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