usrdb.c revision 13558
1170530Ssam/*
2178354Ssam * Copyright (c) 1994 Christopher G. Demetriou
3170530Ssam * All rights reserved.
4170530Ssam *
5170530Ssam * Redistribution and use in source and binary forms, with or without
6170530Ssam * modification, are permitted provided that the following conditions
7170530Ssam * are met:
8170530Ssam * 1. Redistributions of source code must retain the above copyright
9170530Ssam *    notice, this list of conditions and the following disclaimer.
10170530Ssam * 2. Redistributions in binary form must reproduce the above copyright
11170530Ssam *    notice, this list of conditions and the following disclaimer in the
12170530Ssam *    documentation and/or other materials provided with the distribution.
13170530Ssam * 3. All advertising materials mentioning features or use of this software
14170530Ssam *    must display the following acknowledgement:
15170530Ssam *      This product includes software developed by Christopher G. Demetriou.
16170530Ssam * 4. The name of the author may not be used to endorse or promote products
17170530Ssam *    derived from this software without specific prior written permission
18170530Ssam *
19170530Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20170530Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21170530Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22170530Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23170530Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24170530Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25170530Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26170530Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27170530Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28170530Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29170530Ssam */
30170530Ssam
31170530Ssam#ifndef LINT
32170530Ssamstatic char rcsid[] = "$Id: usrdb.c,v 1.2 1995/05/30 03:51:42 rgrimes Exp $";
33170530Ssam#endif
34170530Ssam
35170530Ssam#include <sys/types.h>
36178354Ssam#include <sys/acct.h>
37170530Ssam#include <err.h>
38170530Ssam#include <errno.h>
39170530Ssam#include <fcntl.h>
40170530Ssam#include <stdio.h>
41170530Ssam#include <string.h>
42170530Ssam#include "extern.h"
43170530Ssam#include "pathnames.h"
44170530Ssam
45170530Ssamstatic int uid_compare __P((const DBT *, const DBT *));
46170530Ssam
47170530Ssamstatic DB	*usracct_db;
48170530Ssam
49170530Ssamint
50195377Ssamusracct_init()
51178354Ssam{
52170530Ssam	DB *saved_usracct_db;
53170530Ssam	BTREEINFO bti;
54170530Ssam	int error;
55170530Ssam
56170530Ssam	bzero(&bti, sizeof bti);
57219456Sbschmidt	bti.compare = uid_compare;
58219456Sbschmidt
59219456Sbschmidt	usracct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti);
60219456Sbschmidt	if (usracct_db == NULL)
61219456Sbschmidt		return (-1);
62219456Sbschmidt
63219456Sbschmidt	error = 0;
64219456Sbschmidt	if (!iflag) {
65219456Sbschmidt		DBT key, data;
66219456Sbschmidt		int serr, nerr;
67219456Sbschmidt
68219456Sbschmidt		saved_usracct_db = dbopen(_PATH_USRACCT, O_RDONLY, 0, DB_BTREE,
69219456Sbschmidt		    &bti);
70219456Sbschmidt		if (saved_usracct_db == NULL) {
71219456Sbschmidt			error = (errno == ENOENT) ? 0 : -1;
72219456Sbschmidt			if (error)
73219456Sbschmidt				warn("retrieving user accounting summary");
74219456Sbschmidt			goto out;
75219456Sbschmidt		}
76219456Sbschmidt
77219456Sbschmidt		serr = DB_SEQ(saved_usracct_db, &key, &data, R_FIRST);
78219456Sbschmidt		if (serr < 0) {
79219456Sbschmidt			warn("retrieving user accounting summary");
80219456Sbschmidt			error = -1;
81219456Sbschmidt			goto closeout;
82219456Sbschmidt		}
83219456Sbschmidt		while (serr == 0) {
84219456Sbschmidt			nerr = DB_PUT(usracct_db, &key, &data, 0);
85219456Sbschmidt			if (nerr < 0) {
86219456Sbschmidt				warn("initializing user accounting stats");
87219456Sbschmidt				error = -1;
88219456Sbschmidt				break;
89219456Sbschmidt			}
90219456Sbschmidt
91219456Sbschmidt			serr = DB_SEQ(saved_usracct_db, &key, &data, R_NEXT);
92219456Sbschmidt			if (serr < 0) {
93219456Sbschmidt				warn("retrieving user accounting summary");
94219456Sbschmidt				error = -1;
95219456Sbschmidt				break;
96219456Sbschmidt			}
97219456Sbschmidt		}
98219456Sbschmidt
99219456Sbschmidtcloseout:
100219456Sbschmidt		if (DB_CLOSE(saved_usracct_db) < 0) {
101219456Sbschmidt			warn("closing user accounting summary");
102219456Sbschmidt			error = -1;
103219456Sbschmidt		}
104219456Sbschmidt	}
105219456Sbschmidt
106219456Sbschmidtout:
107219456Sbschmidt	if (error != 0)
108219456Sbschmidt		usracct_destroy();
109219456Sbschmidt	return (error);
110219456Sbschmidt}
111219456Sbschmidt
112219456Sbschmidtvoid
113219456Sbschmidtusracct_destroy()
114219456Sbschmidt{
115219456Sbschmidt	if (DB_CLOSE(usracct_db) < 0)
116219456Sbschmidt		warn("destroying user accounting stats");
117219456Sbschmidt}
118219456Sbschmidt
119219456Sbschmidtint
120219456Sbschmidtusracct_add(ci)
121219456Sbschmidt	const struct cmdinfo *ci;
122219456Sbschmidt{
123219456Sbschmidt	DBT key, data;
124219456Sbschmidt	struct userinfo newui;
125219456Sbschmidt	u_long uid;
126219456Sbschmidt	int rv;
127219456Sbschmidt
128219456Sbschmidt	uid = ci->ci_uid;
129219456Sbschmidt	key.data = &uid;
130219456Sbschmidt	key.size = sizeof uid;
131219456Sbschmidt
132219456Sbschmidt	rv = DB_GET(usracct_db, &key, &data, 0);
133219456Sbschmidt	if (rv < 0) {
134219456Sbschmidt		warn("get key %d from user accounting stats", uid);
135170530Ssam		return (-1);
136170530Ssam	} else if (rv == 0) {	/* it's there; copy whole thing */
137173273Ssam		/* add the old data to the new data */
138193115Ssam		bcopy(data.data, &newui, data.size);
139193115Ssam		if (newui.ui_uid != uid) {
140193115Ssam			warnx("key %d != expected record number %d",
141193115Ssam			    newui.ui_uid, uid);
142173273Ssam			warnx("inconsistent user accounting stats");
143173273Ssam			return (-1);
144193115Ssam		}
145193115Ssam	} else {		/* it's not there; zero it and copy the key */
146193115Ssam		bzero(&newui, sizeof newui);
147193115Ssam		newui.ui_uid = ci->ci_uid;
148193115Ssam	}
149193115Ssam
150193115Ssam	newui.ui_calls += ci->ci_calls;
151193115Ssam	newui.ui_utime += ci->ci_utime;
152193115Ssam	newui.ui_stime += ci->ci_stime;
153193115Ssam	newui.ui_mem += ci->ci_mem;
154193115Ssam	newui.ui_io += ci->ci_io;
155193115Ssam
156193115Ssam	data.data = &newui;
157193115Ssam	data.size = sizeof newui;
158193115Ssam	rv = DB_PUT(usracct_db, &key, &data, 0);
159193115Ssam	if (rv < 0) {
160193115Ssam		warn("add key %d to user accounting stats", uid);
161193115Ssam		return (-1);
162193115Ssam	} else if (rv != 0) {
163195377Ssam		warnx("DB_PUT returned 1");
164195377Ssam		return (-1);
165195377Ssam	}
166195377Ssam
167195377Ssam	return (0);
168195377Ssam}
169195377Ssam
170195377Ssamint
171195377Ssamusracct_update()
172195377Ssam{
173178354Ssam	DB *saved_usracct_db;
174195377Ssam	DBT key, data;
175178354Ssam	BTREEINFO bti;
176195377Ssam	int error, serr, nerr;
177195377Ssam
178195377Ssam	bzero(&bti, sizeof bti);
179178354Ssam	bti.compare = uid_compare;
180178354Ssam
181178354Ssam	saved_usracct_db = dbopen(_PATH_USRACCT, O_RDWR|O_CREAT|O_TRUNC, 0644,
182178354Ssam	    DB_BTREE, &bti);
183178354Ssam	if (saved_usracct_db == NULL) {
184184280Ssam		warn("creating user accounting summary");
185195377Ssam		return (-1);
186195377Ssam	}
187195377Ssam
188195377Ssam	error = 0;
189195377Ssam
190195377Ssam	serr = DB_SEQ(usracct_db, &key, &data, R_FIRST);
191195377Ssam	if (serr < 0) {
192195377Ssam		warn("retrieving user accounting stats");
193195377Ssam		error = -1;
194195377Ssam	}
195195377Ssam	while (serr == 0) {
196195377Ssam		nerr = DB_PUT(saved_usracct_db, &key, &data, 0);
197195377Ssam		if (nerr < 0) {
198195377Ssam			warn("saving user accounting summary");
199195377Ssam			error = -1;
200195377Ssam			break;
201195377Ssam		}
202195377Ssam
203195377Ssam		serr = DB_SEQ(usracct_db, &key, &data, R_NEXT);
204195377Ssam		if (serr < 0) {
205195377Ssam			warn("retrieving user accounting stats");
206195377Ssam			error = -1;
207178354Ssam			break;
208195377Ssam		}
209170530Ssam	}
210178354Ssam
211178354Ssam	if (DB_SYNC(saved_usracct_db, 0) < 0) {
212170530Ssam		warn("syncing process accounting summary");
213170530Ssam		error = -1;
214170530Ssam	}
215170530Ssam	if (DB_CLOSE(saved_usracct_db) < 0) {
216170530Ssam		warn("closing process accounting summary");
217170530Ssam		error = -1;
218170530Ssam	}
219170530Ssam	return error;
220223331Sadrian}
221223331Sadrian
222223331Sadrianvoid
223184280Ssamusracct_print()
224184280Ssam{
225184280Ssam	DBT key, data;
226184280Ssam	struct userinfo *ui;
227191552Ssam	double t;
228191552Ssam	int rv;
229191552Ssam
230170530Ssam	rv = DB_SEQ(usracct_db, &key, &data, R_FIRST);
231170530Ssam	if (rv < 0)
232170530Ssam		warn("retrieving user accounting stats");
233170530Ssam
234170530Ssam	while (rv == 0) {
235195377Ssam		ui = (struct userinfo *) data.data;
236170530Ssam
237178354Ssam		printf("%-8s %9qu ",
238170530Ssam		    user_from_uid(ui->ui_uid, 0), ui->ui_calls);
239170530Ssam
240223331Sadrian		t = (double) (ui->ui_utime + ui->ui_stime) /
241170530Ssam		    (double) AHZ;
242184280Ssam		if (t < 0.0001)		/* kill divide by zero */
243191552Ssam			t = 0.0001;
244191552Ssam
245170530Ssam		printf("%12.2f%s ", t / 60.0, "cpu");
246173273Ssam
247173273Ssam		/* ui->ui_calls is always != 0 */
248178354Ssam		if (dflag)
249173273Ssam			printf("%12qu%s", ui->ui_io / ui->ui_calls, "avio");
250178354Ssam		else
251178354Ssam			printf("%12qu%s", ui->ui_io, "tio");
252178354Ssam
253178354Ssam		/* t is always >= 0.0001; see above */
254173273Ssam		if (kflag)
255178354Ssam			printf("%12qu%s", ui->ui_mem / t, "k");
256178354Ssam		else
257178354Ssam			printf("%12qu%s", ui->ui_mem, "k*sec");
258178354Ssam
259178354Ssam		printf("\n");
260178354Ssam
261178354Ssam		rv = DB_SEQ(usracct_db, &key, &data, R_NEXT);
262178354Ssam		if (rv < 0)
263178354Ssam			warn("retrieving user accounting stats");
264178354Ssam	}
265178354Ssam}
266178354Ssam
267178354Ssamstatic int
268178354Ssamuid_compare(k1, k2)
269178354Ssam	const DBT *k1, *k2;
270178354Ssam{
271170530Ssam	u_long d1, d2;
272173273Ssam
273173273Ssam	bcopy(k1->data, &d1, sizeof d1);
274170530Ssam	bcopy(k2->data, &d2, sizeof d2);
275170530Ssam
276193655Ssam	if (d1 < d2)
277193655Ssam		return -1;
278193655Ssam	else if (d1 == d2)
279178354Ssam		return 0;
280193655Ssam	else
281173273Ssam		return 1;
282178354Ssam}
283193655Ssam