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