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