usrdb.c revision 13558
1170530Ssam/* 2178354Ssam * Copyright (c) 1994 Christopher G. Demetriou 3170530Ssam * All rights reserved. 4170530Ssam * 5170530Ssam * Redistribution and use in source and binary forms, with or without 6170530Ssam * modification, are permitted provided that the following conditions 7170530Ssam * are met: 8170530Ssam * 1. Redistributions of source code must retain the above copyright 9170530Ssam * notice, this list of conditions and the following disclaimer. 10170530Ssam * 2. Redistributions in binary form must reproduce the above copyright 11170530Ssam * notice, this list of conditions and the following disclaimer in the 12170530Ssam * documentation and/or other materials provided with the distribution. 13170530Ssam * 3. All advertising materials mentioning features or use of this software 14170530Ssam * must display the following acknowledgement: 15170530Ssam * This product includes software developed by Christopher G. Demetriou. 16170530Ssam * 4. The name of the author may not be used to endorse or promote products 17170530Ssam * derived from this software without specific prior written permission 18170530Ssam * 19170530Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20170530Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21170530Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22170530Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23170530Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24170530Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25170530Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26170530Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27170530Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28170530Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29170530Ssam */ 30170530Ssam 31170530Ssam#ifndef LINT 32170530Ssamstatic char rcsid[] = "$Id: usrdb.c,v 1.2 1995/05/30 03:51:42 rgrimes Exp $"; 33170530Ssam#endif 34170530Ssam 35170530Ssam#include <sys/types.h> 36178354Ssam#include <sys/acct.h> 37170530Ssam#include <err.h> 38170530Ssam#include <errno.h> 39170530Ssam#include <fcntl.h> 40170530Ssam#include <stdio.h> 41170530Ssam#include <string.h> 42170530Ssam#include "extern.h" 43170530Ssam#include "pathnames.h" 44170530Ssam 45170530Ssamstatic int uid_compare __P((const DBT *, const DBT *)); 46170530Ssam 47170530Ssamstatic DB *usracct_db; 48170530Ssam 49170530Ssamint 50195377Ssamusracct_init() 51178354Ssam{ 52170530Ssam DB *saved_usracct_db; 53170530Ssam BTREEINFO bti; 54170530Ssam int error; 55170530Ssam 56170530Ssam bzero(&bti, sizeof bti); 57219456Sbschmidt bti.compare = uid_compare; 58219456Sbschmidt 59219456Sbschmidt usracct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti); 60219456Sbschmidt if (usracct_db == NULL) 61219456Sbschmidt return (-1); 62219456Sbschmidt 63219456Sbschmidt error = 0; 64219456Sbschmidt if (!iflag) { 65219456Sbschmidt DBT key, data; 66219456Sbschmidt int serr, nerr; 67219456Sbschmidt 68219456Sbschmidt saved_usracct_db = dbopen(_PATH_USRACCT, O_RDONLY, 0, DB_BTREE, 69219456Sbschmidt &bti); 70219456Sbschmidt if (saved_usracct_db == NULL) { 71219456Sbschmidt error = (errno == ENOENT) ? 0 : -1; 72219456Sbschmidt if (error) 73219456Sbschmidt warn("retrieving user accounting summary"); 74219456Sbschmidt goto out; 75219456Sbschmidt } 76219456Sbschmidt 77219456Sbschmidt serr = DB_SEQ(saved_usracct_db, &key, &data, R_FIRST); 78219456Sbschmidt if (serr < 0) { 79219456Sbschmidt warn("retrieving user accounting summary"); 80219456Sbschmidt error = -1; 81219456Sbschmidt goto closeout; 82219456Sbschmidt } 83219456Sbschmidt while (serr == 0) { 84219456Sbschmidt nerr = DB_PUT(usracct_db, &key, &data, 0); 85219456Sbschmidt if (nerr < 0) { 86219456Sbschmidt warn("initializing user accounting stats"); 87219456Sbschmidt error = -1; 88219456Sbschmidt break; 89219456Sbschmidt } 90219456Sbschmidt 91219456Sbschmidt serr = DB_SEQ(saved_usracct_db, &key, &data, R_NEXT); 92219456Sbschmidt if (serr < 0) { 93219456Sbschmidt warn("retrieving user accounting summary"); 94219456Sbschmidt error = -1; 95219456Sbschmidt break; 96219456Sbschmidt } 97219456Sbschmidt } 98219456Sbschmidt 99219456Sbschmidtcloseout: 100219456Sbschmidt if (DB_CLOSE(saved_usracct_db) < 0) { 101219456Sbschmidt warn("closing user accounting summary"); 102219456Sbschmidt error = -1; 103219456Sbschmidt } 104219456Sbschmidt } 105219456Sbschmidt 106219456Sbschmidtout: 107219456Sbschmidt if (error != 0) 108219456Sbschmidt usracct_destroy(); 109219456Sbschmidt return (error); 110219456Sbschmidt} 111219456Sbschmidt 112219456Sbschmidtvoid 113219456Sbschmidtusracct_destroy() 114219456Sbschmidt{ 115219456Sbschmidt if (DB_CLOSE(usracct_db) < 0) 116219456Sbschmidt warn("destroying user accounting stats"); 117219456Sbschmidt} 118219456Sbschmidt 119219456Sbschmidtint 120219456Sbschmidtusracct_add(ci) 121219456Sbschmidt const struct cmdinfo *ci; 122219456Sbschmidt{ 123219456Sbschmidt DBT key, data; 124219456Sbschmidt struct userinfo newui; 125219456Sbschmidt u_long uid; 126219456Sbschmidt int rv; 127219456Sbschmidt 128219456Sbschmidt uid = ci->ci_uid; 129219456Sbschmidt key.data = &uid; 130219456Sbschmidt key.size = sizeof uid; 131219456Sbschmidt 132219456Sbschmidt rv = DB_GET(usracct_db, &key, &data, 0); 133219456Sbschmidt if (rv < 0) { 134219456Sbschmidt warn("get key %d from user accounting stats", uid); 135170530Ssam return (-1); 136170530Ssam } else if (rv == 0) { /* it's there; copy whole thing */ 137173273Ssam /* add the old data to the new data */ 138193115Ssam bcopy(data.data, &newui, data.size); 139193115Ssam if (newui.ui_uid != uid) { 140193115Ssam warnx("key %d != expected record number %d", 141193115Ssam newui.ui_uid, uid); 142173273Ssam warnx("inconsistent user accounting stats"); 143173273Ssam return (-1); 144193115Ssam } 145193115Ssam } else { /* it's not there; zero it and copy the key */ 146193115Ssam bzero(&newui, sizeof newui); 147193115Ssam newui.ui_uid = ci->ci_uid; 148193115Ssam } 149193115Ssam 150193115Ssam newui.ui_calls += ci->ci_calls; 151193115Ssam newui.ui_utime += ci->ci_utime; 152193115Ssam newui.ui_stime += ci->ci_stime; 153193115Ssam newui.ui_mem += ci->ci_mem; 154193115Ssam newui.ui_io += ci->ci_io; 155193115Ssam 156193115Ssam data.data = &newui; 157193115Ssam data.size = sizeof newui; 158193115Ssam rv = DB_PUT(usracct_db, &key, &data, 0); 159193115Ssam if (rv < 0) { 160193115Ssam warn("add key %d to user accounting stats", uid); 161193115Ssam return (-1); 162193115Ssam } else if (rv != 0) { 163195377Ssam warnx("DB_PUT returned 1"); 164195377Ssam return (-1); 165195377Ssam } 166195377Ssam 167195377Ssam return (0); 168195377Ssam} 169195377Ssam 170195377Ssamint 171195377Ssamusracct_update() 172195377Ssam{ 173178354Ssam DB *saved_usracct_db; 174195377Ssam DBT key, data; 175178354Ssam BTREEINFO bti; 176195377Ssam int error, serr, nerr; 177195377Ssam 178195377Ssam bzero(&bti, sizeof bti); 179178354Ssam bti.compare = uid_compare; 180178354Ssam 181178354Ssam saved_usracct_db = dbopen(_PATH_USRACCT, O_RDWR|O_CREAT|O_TRUNC, 0644, 182178354Ssam DB_BTREE, &bti); 183178354Ssam if (saved_usracct_db == NULL) { 184184280Ssam warn("creating user accounting summary"); 185195377Ssam return (-1); 186195377Ssam } 187195377Ssam 188195377Ssam error = 0; 189195377Ssam 190195377Ssam serr = DB_SEQ(usracct_db, &key, &data, R_FIRST); 191195377Ssam if (serr < 0) { 192195377Ssam warn("retrieving user accounting stats"); 193195377Ssam error = -1; 194195377Ssam } 195195377Ssam while (serr == 0) { 196195377Ssam nerr = DB_PUT(saved_usracct_db, &key, &data, 0); 197195377Ssam if (nerr < 0) { 198195377Ssam warn("saving user accounting summary"); 199195377Ssam error = -1; 200195377Ssam break; 201195377Ssam } 202195377Ssam 203195377Ssam serr = DB_SEQ(usracct_db, &key, &data, R_NEXT); 204195377Ssam if (serr < 0) { 205195377Ssam warn("retrieving user accounting stats"); 206195377Ssam error = -1; 207178354Ssam break; 208195377Ssam } 209170530Ssam } 210178354Ssam 211178354Ssam if (DB_SYNC(saved_usracct_db, 0) < 0) { 212170530Ssam warn("syncing process accounting summary"); 213170530Ssam error = -1; 214170530Ssam } 215170530Ssam if (DB_CLOSE(saved_usracct_db) < 0) { 216170530Ssam warn("closing process accounting summary"); 217170530Ssam error = -1; 218170530Ssam } 219170530Ssam return error; 220223331Sadrian} 221223331Sadrian 222223331Sadrianvoid 223184280Ssamusracct_print() 224184280Ssam{ 225184280Ssam DBT key, data; 226184280Ssam struct userinfo *ui; 227191552Ssam double t; 228191552Ssam int rv; 229191552Ssam 230170530Ssam rv = DB_SEQ(usracct_db, &key, &data, R_FIRST); 231170530Ssam if (rv < 0) 232170530Ssam warn("retrieving user accounting stats"); 233170530Ssam 234170530Ssam while (rv == 0) { 235195377Ssam ui = (struct userinfo *) data.data; 236170530Ssam 237178354Ssam printf("%-8s %9qu ", 238170530Ssam user_from_uid(ui->ui_uid, 0), ui->ui_calls); 239170530Ssam 240223331Sadrian t = (double) (ui->ui_utime + ui->ui_stime) / 241170530Ssam (double) AHZ; 242184280Ssam if (t < 0.0001) /* kill divide by zero */ 243191552Ssam t = 0.0001; 244191552Ssam 245170530Ssam printf("%12.2f%s ", t / 60.0, "cpu"); 246173273Ssam 247173273Ssam /* ui->ui_calls is always != 0 */ 248178354Ssam if (dflag) 249173273Ssam printf("%12qu%s", ui->ui_io / ui->ui_calls, "avio"); 250178354Ssam else 251178354Ssam printf("%12qu%s", ui->ui_io, "tio"); 252178354Ssam 253178354Ssam /* t is always >= 0.0001; see above */ 254173273Ssam if (kflag) 255178354Ssam printf("%12qu%s", ui->ui_mem / t, "k"); 256178354Ssam else 257178354Ssam printf("%12qu%s", ui->ui_mem, "k*sec"); 258178354Ssam 259178354Ssam printf("\n"); 260178354Ssam 261178354Ssam rv = DB_SEQ(usracct_db, &key, &data, R_NEXT); 262178354Ssam if (rv < 0) 263178354Ssam warn("retrieving user accounting stats"); 264178354Ssam } 265178354Ssam} 266178354Ssam 267178354Ssamstatic int 268178354Ssamuid_compare(k1, k2) 269178354Ssam const DBT *k1, *k2; 270178354Ssam{ 271170530Ssam u_long d1, d2; 272173273Ssam 273173273Ssam bcopy(k1->data, &d1, sizeof d1); 274170530Ssam bcopy(k2->data, &d2, sizeof d2); 275170530Ssam 276193655Ssam if (d1 < d2) 277193655Ssam return -1; 278193655Ssam else if (d1 == d2) 279178354Ssam return 0; 280193655Ssam else 281173273Ssam return 1; 282178354Ssam} 283193655Ssam