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