usrdb.c revision 61089
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  "$FreeBSD: head/usr.sbin/sa/usrdb.c 61089 2000-05-30 13:27:33Z ghelmer $";
34#endif /* not lint */
35
36#include <sys/param.h>
37#include <sys/types.h>
38#include <sys/acct.h>
39#include <err.h>
40#include <errno.h>
41#include <fcntl.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include "extern.h"
46#include "pathnames.h"
47
48static int uid_compare __P((const DBT *, const DBT *));
49
50static DB	*usracct_db;
51
52int
53usracct_init()
54{
55	DB *saved_usracct_db;
56	BTREEINFO bti;
57	int error;
58
59	bzero(&bti, sizeof bti);
60	bti.compare = uid_compare;
61
62	usracct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti);
63	if (usracct_db == NULL)
64		return (-1);
65
66	error = 0;
67	if (!iflag) {
68		DBT key, data;
69		int serr, nerr;
70
71		saved_usracct_db = dbopen(_PATH_USRACCT, O_RDONLY, 0, DB_BTREE,
72		    &bti);
73		if (saved_usracct_db == NULL) {
74			error = (errno == ENOENT) ? 0 : -1;
75			if (error)
76				warn("retrieving user accounting summary");
77			goto out;
78		}
79
80		serr = DB_SEQ(saved_usracct_db, &key, &data, R_FIRST);
81		if (serr < 0) {
82			warn("retrieving user accounting summary");
83			error = -1;
84			goto closeout;
85		}
86		while (serr == 0) {
87			nerr = DB_PUT(usracct_db, &key, &data, 0);
88			if (nerr < 0) {
89				warn("initializing user accounting stats");
90				error = -1;
91				break;
92			}
93
94			serr = DB_SEQ(saved_usracct_db, &key, &data, R_NEXT);
95			if (serr < 0) {
96				warn("retrieving user accounting summary");
97				error = -1;
98				break;
99			}
100		}
101
102closeout:
103		if (DB_CLOSE(saved_usracct_db) < 0) {
104			warn("closing user accounting summary");
105			error = -1;
106		}
107	}
108
109out:
110	if (error != 0)
111		usracct_destroy();
112	return (error);
113}
114
115void
116usracct_destroy()
117{
118	if (DB_CLOSE(usracct_db) < 0)
119		warn("destroying user accounting stats");
120}
121
122int
123usracct_add(ci)
124	const struct cmdinfo *ci;
125{
126	DBT key, data;
127	struct userinfo newui;
128	u_long uid;
129	int rv;
130
131	uid = ci->ci_uid;
132	key.data = &uid;
133	key.size = sizeof uid;
134
135	rv = DB_GET(usracct_db, &key, &data, 0);
136	if (rv < 0) {
137		warn("get key %lu from user accounting stats", uid);
138		return (-1);
139	} else if (rv == 0) {	/* it's there; copy whole thing */
140		/* add the old data to the new data */
141		bcopy(data.data, &newui, data.size);
142		if (newui.ui_uid != uid) {
143			warnx("key %lu != expected record number %lu",
144			    newui.ui_uid, uid);
145			warnx("inconsistent user accounting stats");
146			return (-1);
147		}
148	} else {		/* it's not there; zero it and copy the key */
149		bzero(&newui, sizeof newui);
150		newui.ui_uid = ci->ci_uid;
151	}
152
153	newui.ui_calls += ci->ci_calls;
154	newui.ui_utime += ci->ci_utime;
155	newui.ui_stime += ci->ci_stime;
156	newui.ui_mem += ci->ci_mem;
157	newui.ui_io += ci->ci_io;
158
159	data.data = &newui;
160	data.size = sizeof newui;
161	rv = DB_PUT(usracct_db, &key, &data, 0);
162	if (rv < 0) {
163		warn("add key %lu to user accounting stats", uid);
164		return (-1);
165	} else if (rv != 0) {
166		warnx("DB_PUT returned 1");
167		return (-1);
168	}
169
170	return (0);
171}
172
173int
174usracct_update()
175{
176	DB *saved_usracct_db;
177	DBT key, data;
178	BTREEINFO bti;
179	int error, serr, nerr;
180
181	bzero(&bti, sizeof bti);
182	bti.compare = uid_compare;
183
184	saved_usracct_db = dbopen(_PATH_USRACCT, O_RDWR|O_CREAT|O_TRUNC, 0644,
185	    DB_BTREE, &bti);
186	if (saved_usracct_db == NULL) {
187		warn("creating user accounting summary");
188		return (-1);
189	}
190
191	error = 0;
192
193	serr = DB_SEQ(usracct_db, &key, &data, R_FIRST);
194	if (serr < 0) {
195		warn("retrieving user accounting stats");
196		error = -1;
197	}
198	while (serr == 0) {
199		nerr = DB_PUT(saved_usracct_db, &key, &data, 0);
200		if (nerr < 0) {
201			warn("saving user accounting summary");
202			error = -1;
203			break;
204		}
205
206		serr = DB_SEQ(usracct_db, &key, &data, R_NEXT);
207		if (serr < 0) {
208			warn("retrieving user accounting stats");
209			error = -1;
210			break;
211		}
212	}
213
214	if (DB_SYNC(saved_usracct_db, 0) < 0) {
215		warn("syncing process accounting summary");
216		error = -1;
217	}
218	if (DB_CLOSE(saved_usracct_db) < 0) {
219		warn("closing process accounting summary");
220		error = -1;
221	}
222	return error;
223}
224
225void
226usracct_print()
227{
228	DBT key, data;
229	struct userinfo *ui;
230	double t;
231	int rv;
232
233	rv = DB_SEQ(usracct_db, &key, &data, R_FIRST);
234	if (rv < 0)
235		warn("retrieving user accounting stats");
236
237	while (rv == 0) {
238		ui = (struct userinfo *) data.data;
239
240		printf("%-*s %9qu ", MAXLOGNAME - 1,
241		    user_from_uid(ui->ui_uid, 0), ui->ui_calls);
242
243		t = (double) (ui->ui_utime + ui->ui_stime) /
244		    (double) AHZ;
245		if (t < 0.0001)		/* kill divide by zero */
246			t = 0.0001;
247
248		printf("%12.2f%s ", t / 60.0, "cpu");
249
250		/* ui->ui_calls is always != 0 */
251		if (dflag)
252			printf("%12qu%s", ui->ui_io / ui->ui_calls, "avio");
253		else
254			printf("%12qu%s", ui->ui_io, "tio");
255
256		/* t is always >= 0.0001; see above */
257		if (kflag)
258			printf("%12.0f%s", ui->ui_mem / t, "k");
259		else
260			printf("%12qu%s", ui->ui_mem, "k*sec");
261
262		printf("\n");
263
264		rv = DB_SEQ(usracct_db, &key, &data, R_NEXT);
265		if (rv < 0)
266			warn("retrieving user accounting stats");
267	}
268}
269
270static int
271uid_compare(k1, k2)
272	const DBT *k1, *k2;
273{
274	u_long d1, d2;
275
276	bcopy(k1->data, &d1, sizeof d1);
277	bcopy(k2->data, &d2, sizeof d2);
278
279	if (d1 < d2)
280		return -1;
281	else if (d1 == d2)
282		return 0;
283	else
284		return 1;
285}
286