usrdb.c revision 30425
1/*
2 * Copyright (c) 1994 Christopher G. Demetriou
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *      This product includes software developed by Christopher G. Demetriou.
16 * 4. The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#ifndef lint
32static const char rcsid[] =
33	"$Id$";
34#endif /* not lint */
35
36#include <sys/types.h>
37#include <sys/acct.h>
38#include <err.h>
39#include <errno.h>
40#include <fcntl.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include "extern.h"
45#include "pathnames.h"
46
47static int uid_compare __P((const DBT *, const DBT *));
48
49static DB	*usracct_db;
50
51int
52usracct_init()
53{
54	DB *saved_usracct_db;
55	BTREEINFO bti;
56	int error;
57
58	bzero(&bti, sizeof bti);
59	bti.compare = uid_compare;
60
61	usracct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti);
62	if (usracct_db == NULL)
63		return (-1);
64
65	error = 0;
66	if (!iflag) {
67		DBT key, data;
68		int serr, nerr;
69
70		saved_usracct_db = dbopen(_PATH_USRACCT, O_RDONLY, 0, DB_BTREE,
71		    &bti);
72		if (saved_usracct_db == NULL) {
73			error = (errno == ENOENT) ? 0 : -1;
74			if (error)
75				warn("retrieving user accounting summary");
76			goto out;
77		}
78
79		serr = DB_SEQ(saved_usracct_db, &key, &data, R_FIRST);
80		if (serr < 0) {
81			warn("retrieving user accounting summary");
82			error = -1;
83			goto closeout;
84		}
85		while (serr == 0) {
86			nerr = DB_PUT(usracct_db, &key, &data, 0);
87			if (nerr < 0) {
88				warn("initializing user accounting stats");
89				error = -1;
90				break;
91			}
92
93			serr = DB_SEQ(saved_usracct_db, &key, &data, R_NEXT);
94			if (serr < 0) {
95				warn("retrieving user accounting summary");
96				error = -1;
97				break;
98			}
99		}
100
101closeout:
102		if (DB_CLOSE(saved_usracct_db) < 0) {
103			warn("closing user accounting summary");
104			error = -1;
105		}
106	}
107
108out:
109	if (error != 0)
110		usracct_destroy();
111	return (error);
112}
113
114void
115usracct_destroy()
116{
117	if (DB_CLOSE(usracct_db) < 0)
118		warn("destroying user accounting stats");
119}
120
121int
122usracct_add(ci)
123	const struct cmdinfo *ci;
124{
125	DBT key, data;
126	struct userinfo newui;
127	u_long uid;
128	int rv;
129
130	uid = ci->ci_uid;
131	key.data = &uid;
132	key.size = sizeof uid;
133
134	rv = DB_GET(usracct_db, &key, &data, 0);
135	if (rv < 0) {
136		warn("get key %d from user accounting stats", uid);
137		return (-1);
138	} else if (rv == 0) {	/* it's there; copy whole thing */
139		/* add the old data to the new data */
140		bcopy(data.data, &newui, data.size);
141		if (newui.ui_uid != uid) {
142			warnx("key %d != expected record number %d",
143			    newui.ui_uid, uid);
144			warnx("inconsistent user accounting stats");
145			return (-1);
146		}
147	} else {		/* it's not there; zero it and copy the key */
148		bzero(&newui, sizeof newui);
149		newui.ui_uid = ci->ci_uid;
150	}
151
152	newui.ui_calls += ci->ci_calls;
153	newui.ui_utime += ci->ci_utime;
154	newui.ui_stime += ci->ci_stime;
155	newui.ui_mem += ci->ci_mem;
156	newui.ui_io += ci->ci_io;
157
158	data.data = &newui;
159	data.size = sizeof newui;
160	rv = DB_PUT(usracct_db, &key, &data, 0);
161	if (rv < 0) {
162		warn("add key %d to user accounting stats", uid);
163		return (-1);
164	} else if (rv != 0) {
165		warnx("DB_PUT returned 1");
166		return (-1);
167	}
168
169	return (0);
170}
171
172int
173usracct_update()
174{
175	DB *saved_usracct_db;
176	DBT key, data;
177	BTREEINFO bti;
178	int error, serr, nerr;
179
180	bzero(&bti, sizeof bti);
181	bti.compare = uid_compare;
182
183	saved_usracct_db = dbopen(_PATH_USRACCT, O_RDWR|O_CREAT|O_TRUNC, 0644,
184	    DB_BTREE, &bti);
185	if (saved_usracct_db == NULL) {
186		warn("creating user accounting summary");
187		return (-1);
188	}
189
190	error = 0;
191
192	serr = DB_SEQ(usracct_db, &key, &data, R_FIRST);
193	if (serr < 0) {
194		warn("retrieving user accounting stats");
195		error = -1;
196	}
197	while (serr == 0) {
198		nerr = DB_PUT(saved_usracct_db, &key, &data, 0);
199		if (nerr < 0) {
200			warn("saving user accounting summary");
201			error = -1;
202			break;
203		}
204
205		serr = DB_SEQ(usracct_db, &key, &data, R_NEXT);
206		if (serr < 0) {
207			warn("retrieving user accounting stats");
208			error = -1;
209			break;
210		}
211	}
212
213	if (DB_SYNC(saved_usracct_db, 0) < 0) {
214		warn("syncing process accounting summary");
215		error = -1;
216	}
217	if (DB_CLOSE(saved_usracct_db) < 0) {
218		warn("closing process accounting summary");
219		error = -1;
220	}
221	return error;
222}
223
224void
225usracct_print()
226{
227	DBT key, data;
228	struct userinfo *ui;
229	double t;
230	int rv;
231
232	rv = DB_SEQ(usracct_db, &key, &data, R_FIRST);
233	if (rv < 0)
234		warn("retrieving user accounting stats");
235
236	while (rv == 0) {
237		ui = (struct userinfo *) data.data;
238
239		printf("%-8s %9qu ",
240		    user_from_uid(ui->ui_uid, 0), ui->ui_calls);
241
242		t = (double) (ui->ui_utime + ui->ui_stime) /
243		    (double) AHZ;
244		if (t < 0.0001)		/* kill divide by zero */
245			t = 0.0001;
246
247		printf("%12.2f%s ", t / 60.0, "cpu");
248
249		/* ui->ui_calls is always != 0 */
250		if (dflag)
251			printf("%12qu%s", ui->ui_io / ui->ui_calls, "avio");
252		else
253			printf("%12qu%s", ui->ui_io, "tio");
254
255		/* t is always >= 0.0001; see above */
256		if (kflag)
257			printf("%12qu%s", ui->ui_mem / t, "k");
258		else
259			printf("%12qu%s", ui->ui_mem, "k*sec");
260
261		printf("\n");
262
263		rv = DB_SEQ(usracct_db, &key, &data, R_NEXT);
264		if (rv < 0)
265			warn("retrieving user accounting stats");
266	}
267}
268
269static int
270uid_compare(k1, k2)
271	const DBT *k1, *k2;
272{
273	u_long d1, d2;
274
275	bcopy(k1->data, &d1, sizeof d1);
276	bcopy(k2->data, &d2, sizeof d2);
277
278	if (d1 < d2)
279		return -1;
280	else if (d1 == d2)
281		return 0;
282	else
283		return 1;
284}
285