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