usrdb.c revision 61089
1205354Simp/* 2205354Simp * Copyright (c) 1994 Christopher G. Demetriou 3205354Simp * All rights reserved. 4205354Simp * 5205354Simp * Redistribution and use in source and binary forms, with or without 6205354Simp * modification, are permitted provided that the following conditions 7205354Simp * are met: 8205354Simp * 1. Redistributions of source code must retain the above copyright 9205354Simp * notice, this list of conditions and the following disclaimer. 10205354Simp * 2. Redistributions in binary form must reproduce the above copyright 11205354Simp * notice, this list of conditions and the following disclaimer in the 12205354Simp * documentation and/or other materials provided with the distribution. 13205354Simp * 3. All advertising materials mentioning features or use of this software 14205354Simp * must display the following acknowledgement: 15205354Simp * This product includes software developed by Christopher G. Demetriou. 16205354Simp * 4. The name of the author may not be used to endorse or promote products 17205354Simp * derived from this software without specific prior written permission 18205354Simp * 19205354Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20205354Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21205354Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22205354Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23205354Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24205354Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25205354Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26205354Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27205354Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28205354Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29205354Simp */ 30205354Simp 31205354Simp#ifndef lint 32205354Simpstatic const char rcsid[] = 33205354Simp "$FreeBSD: head/usr.sbin/sa/usrdb.c 61089 2000-05-30 13:27:33Z ghelmer $"; 34205354Simp#endif /* not lint */ 35205354Simp 36205354Simp#include <sys/param.h> 37205354Simp#include <sys/types.h> 38205354Simp#include <sys/acct.h> 39205354Simp#include <err.h> 40205354Simp#include <errno.h> 41205354Simp#include <fcntl.h> 42205354Simp#include <stdio.h> 43205354Simp#include <stdlib.h> 44205354Simp#include <string.h> 45205354Simp#include "extern.h" 46205354Simp#include "pathnames.h" 47205354Simp 48205354Simpstatic int uid_compare __P((const DBT *, const DBT *)); 49205354Simp 50205354Simpstatic DB *usracct_db; 51205354Simp 52205354Simpint 53205354Simpusracct_init() 54205354Simp{ 55205354Simp DB *saved_usracct_db; 56205354Simp BTREEINFO bti; 57205354Simp int error; 58205354Simp 59205354Simp bzero(&bti, sizeof bti); 60205354Simp bti.compare = uid_compare; 61205354Simp 62205354Simp usracct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti); 63205354Simp if (usracct_db == NULL) 64205354Simp return (-1); 65205354Simp 66205354Simp error = 0; 67205354Simp if (!iflag) { 68205354Simp DBT key, data; 69205354Simp int serr, nerr; 70205354Simp 71205354Simp saved_usracct_db = dbopen(_PATH_USRACCT, O_RDONLY, 0, DB_BTREE, 72205354Simp &bti); 73205354Simp if (saved_usracct_db == NULL) { 74205354Simp error = (errno == ENOENT) ? 0 : -1; 75205354Simp if (error) 76205354Simp warn("retrieving user accounting summary"); 77205354Simp goto out; 78205354Simp } 79205354Simp 80205354Simp serr = DB_SEQ(saved_usracct_db, &key, &data, R_FIRST); 81205354Simp if (serr < 0) { 82205354Simp warn("retrieving user accounting summary"); 83205354Simp error = -1; 84205354Simp goto closeout; 85205354Simp } 86205354Simp while (serr == 0) { 87205354Simp nerr = DB_PUT(usracct_db, &key, &data, 0); 88205354Simp if (nerr < 0) { 89205354Simp warn("initializing user accounting stats"); 90205354Simp error = -1; 91205354Simp break; 92205354Simp } 93205354Simp 94205354Simp serr = DB_SEQ(saved_usracct_db, &key, &data, R_NEXT); 95205354Simp if (serr < 0) { 96205354Simp warn("retrieving user accounting summary"); 97205354Simp error = -1; 98205354Simp break; 99205354Simp } 100205354Simp } 101205354Simp 102205354Simpcloseout: 103205354Simp if (DB_CLOSE(saved_usracct_db) < 0) { 104205354Simp warn("closing user accounting summary"); 105205354Simp error = -1; 106205354Simp } 107205354Simp } 108205354Simp 109205354Simpout: 110205354Simp if (error != 0) 111205354Simp usracct_destroy(); 112205354Simp return (error); 113205354Simp} 114205354Simp 115205354Simpvoid 116205354Simpusracct_destroy() 117205354Simp{ 118205354Simp if (DB_CLOSE(usracct_db) < 0) 119205354Simp warn("destroying user accounting stats"); 120205354Simp} 121205354Simp 122205354Simpint 123205354Simpusracct_add(ci) 124205354Simp const struct cmdinfo *ci; 125205354Simp{ 126205354Simp DBT key, data; 127205354Simp struct userinfo newui; 128205354Simp u_long uid; 129205354Simp int rv; 130205354Simp 131205354Simp uid = ci->ci_uid; 132205354Simp key.data = &uid; 133205354Simp key.size = sizeof uid; 134205354Simp 135205354Simp rv = DB_GET(usracct_db, &key, &data, 0); 136205354Simp if (rv < 0) { 137205354Simp warn("get key %lu from user accounting stats", uid); 138205354Simp return (-1); 139205354Simp } else if (rv == 0) { /* it's there; copy whole thing */ 140205354Simp /* add the old data to the new data */ 141205354Simp bcopy(data.data, &newui, data.size); 142205354Simp if (newui.ui_uid != uid) { 143205354Simp warnx("key %lu != expected record number %lu", 144205354Simp newui.ui_uid, uid); 145205354Simp warnx("inconsistent user accounting stats"); 146205354Simp return (-1); 147205354Simp } 148205354Simp } else { /* it's not there; zero it and copy the key */ 149205354Simp bzero(&newui, sizeof newui); 150205354Simp newui.ui_uid = ci->ci_uid; 151205354Simp } 152205354Simp 153205354Simp newui.ui_calls += ci->ci_calls; 154205354Simp newui.ui_utime += ci->ci_utime; 155205354Simp newui.ui_stime += ci->ci_stime; 156205354Simp newui.ui_mem += ci->ci_mem; 157205354Simp newui.ui_io += ci->ci_io; 158205354Simp 159227849Shselasky data.data = &newui; 160205354Simp data.size = sizeof newui; 161205354Simp rv = DB_PUT(usracct_db, &key, &data, 0); 162205354Simp if (rv < 0) { 163205354Simp warn("add key %lu to user accounting stats", uid); 164205354Simp return (-1); 165205354Simp } else if (rv != 0) { 166205354Simp warnx("DB_PUT returned 1"); 167205354Simp return (-1); 168205354Simp } 169205354Simp 170205354Simp return (0); 171205354Simp} 172205354Simp 173205354Simpint 174205354Simpusracct_update() 175205354Simp{ 176205354Simp DB *saved_usracct_db; 177205354Simp DBT key, data; 178205354Simp BTREEINFO bti; 179205354Simp int error, serr, nerr; 180205354Simp 181205354Simp bzero(&bti, sizeof bti); 182205354Simp bti.compare = uid_compare; 183205354Simp 184205354Simp saved_usracct_db = dbopen(_PATH_USRACCT, O_RDWR|O_CREAT|O_TRUNC, 0644, 185205354Simp DB_BTREE, &bti); 186205354Simp if (saved_usracct_db == NULL) { 187205354Simp warn("creating user accounting summary"); 188205354Simp return (-1); 189205354Simp } 190205354Simp 191205354Simp error = 0; 192205354Simp 193205354Simp serr = DB_SEQ(usracct_db, &key, &data, R_FIRST); 194205354Simp if (serr < 0) { 195205354Simp warn("retrieving user accounting stats"); 196205354Simp error = -1; 197205354Simp } 198205354Simp while (serr == 0) { 199205354Simp nerr = DB_PUT(saved_usracct_db, &key, &data, 0); 200205354Simp if (nerr < 0) { 201228483Shselasky warn("saving user accounting summary"); 202228483Shselasky error = -1; 203205354Simp break; 204205354Simp } 205227843Smarius 206205354Simp serr = DB_SEQ(usracct_db, &key, &data, R_NEXT); 207205354Simp if (serr < 0) { 208205354Simp warn("retrieving user accounting stats"); 209228483Shselasky error = -1; 210228483Shselasky break; 211228483Shselasky } 212205354Simp } 213205354Simp 214205354Simp if (DB_SYNC(saved_usracct_db, 0) < 0) { 215205354Simp warn("syncing process accounting summary"); 216205354Simp error = -1; 217205354Simp } 218 if (DB_CLOSE(saved_usracct_db) < 0) { 219 warn("closing process accounting summary"); 220 error = -1; 221 } 222 return error; 223} 224 225void 226usracct_print() 227{ 228 DBT key, data; 229 struct userinfo *ui; 230 double t; 231 int rv; 232 233 rv = DB_SEQ(usracct_db, &key, &data, R_FIRST); 234 if (rv < 0) 235 warn("retrieving user accounting stats"); 236 237 while (rv == 0) { 238 ui = (struct userinfo *) data.data; 239 240 printf("%-*s %9qu ", MAXLOGNAME - 1, 241 user_from_uid(ui->ui_uid, 0), ui->ui_calls); 242 243 t = (double) (ui->ui_utime + ui->ui_stime) / 244 (double) AHZ; 245 if (t < 0.0001) /* kill divide by zero */ 246 t = 0.0001; 247 248 printf("%12.2f%s ", t / 60.0, "cpu"); 249 250 /* ui->ui_calls is always != 0 */ 251 if (dflag) 252 printf("%12qu%s", ui->ui_io / ui->ui_calls, "avio"); 253 else 254 printf("%12qu%s", ui->ui_io, "tio"); 255 256 /* t is always >= 0.0001; see above */ 257 if (kflag) 258 printf("%12.0f%s", ui->ui_mem / t, "k"); 259 else 260 printf("%12qu%s", ui->ui_mem, "k*sec"); 261 262 printf("\n"); 263 264 rv = DB_SEQ(usracct_db, &key, &data, R_NEXT); 265 if (rv < 0) 266 warn("retrieving user accounting stats"); 267 } 268} 269 270static int 271uid_compare(k1, k2) 272 const DBT *k1, *k2; 273{ 274 u_long d1, d2; 275 276 bcopy(k1->data, &d1, sizeof d1); 277 bcopy(k2->data, &d2, sizeof d2); 278 279 if (d1 < d2) 280 return -1; 281 else if (d1 == d2) 282 return 0; 283 else 284 return 1; 285} 286