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