1 /* $NetBSD: usrdb.c,v 1.10 2001/01/05 03:27:28 lukem 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.10 2001/01/05 03:27:28 lukem 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 int ndups = 0; 64 65 memset(&bti, 0, sizeof(bti)); 66 bti.compare = uid_compare; 67 68 usracct_db = dbopen(NULL, O_RDWR|O_CREAT|O_TRUNC, 0644, DB_BTREE, &bti); 69 if (usracct_db == NULL) 70 return (-1); 71 72 error = 0; 73 if (!iflag) { 74 DBT key, data; 75 int serr, nerr; 76 77 saved_usracct_db = dbopen(_PATH_USRACCT, O_RDONLY, 0, DB_BTREE, 78 &bti); 79 if (saved_usracct_db == NULL) { 80 error = (errno == ENOENT) ? 0 : -1; 81 if (error) 82 warn("retrieving user accounting summary"); 83 goto out; 84 } 85 86 serr = DB_SEQ(saved_usracct_db, &key, &data, R_FIRST); 87 if (serr < 0) { 88 warn("retrieving user accounting summary"); 89 error = -1; 90 goto closeout; 91 } 92 while (serr == 0) { 93 nerr = DB_PUT(usracct_db, &key, &data, R_NOOVERWRITE); 94 if (nerr < 0) { 95 warn("initializing user accounting stats"); 96 error = -1; 97 break; 98 } 99 if (nerr == 1) { 100 warnx("duplicate key in `%s': %s", 101 _PATH_USRACCT, fmt(&key)); 102 if (ndups++ == 5) { 103 warnx("too many duplicate keys;" 104 " `%s' possibly corrupted.", 105 _PATH_USRACCT); 106 error = -1; 107 break; 108 } 109 } 110 111 serr = DB_SEQ(saved_usracct_db, &key, &data, R_NEXT); 112 if (serr < 0) { 113 warn("retrieving user accounting summary"); 114 error = -1; 115 break; 116 } 117 } 118 119 closeout: 120 if (DB_CLOSE(saved_usracct_db) < 0) { 121 warn("closing user accounting summary"); 122 error = -1; 123 } 124 } 125 126 out: 127 if (error != 0) 128 usracct_destroy(); 129 return (error); 130 } 131 132 void 133 usracct_destroy() 134 { 135 if (DB_CLOSE(usracct_db) < 0) 136 warn("destroying user accounting stats"); 137 } 138 139 int 140 usracct_add(ci) 141 const struct cmdinfo *ci; 142 { 143 DBT key, data; 144 struct userinfo newui; 145 uid_t uid; 146 int rv; 147 148 uid = ci->ci_uid; 149 key.data = &uid; 150 key.size = sizeof(uid); 151 152 rv = DB_GET(usracct_db, &key, &data, 0); 153 if (rv < 0) { 154 warn("get key %d from user accounting stats", uid); 155 return (-1); 156 } else if (rv == 0) { /* it's there; copy whole thing */ 157 /* add the old data to the new data */ 158 memcpy(&newui, data.data, data.size); 159 if (newui.ui_uid != uid) { 160 warnx("key %d != expected record number %d", 161 newui.ui_uid, uid); 162 warnx("inconsistent user accounting stats"); 163 return (-1); 164 } 165 } else { /* it's not there; zero it and copy the key */ 166 memset(&newui, 0, sizeof(newui)); 167 newui.ui_uid = ci->ci_uid; 168 } 169 170 newui.ui_calls += ci->ci_calls; 171 newui.ui_utime += ci->ci_utime; 172 newui.ui_stime += ci->ci_stime; 173 newui.ui_mem += ci->ci_mem; 174 newui.ui_io += ci->ci_io; 175 176 data.data = &newui; 177 data.size = sizeof(newui); 178 rv = DB_PUT(usracct_db, &key, &data, 0); 179 if (rv < 0) { 180 warn("add key %d to user accounting stats", uid); 181 return (-1); 182 } else if (rv != 0) { 183 warnx("DB_PUT returned 1"); 184 return (-1); 185 } 186 187 return (0); 188 } 189 190 int 191 usracct_update() 192 { 193 DB *saved_usracct_db; 194 DBT key, data; 195 BTREEINFO bti; 196 int error, serr, nerr; 197 198 memset(&bti, 0, sizeof(bti)); 199 bti.compare = uid_compare; 200 201 saved_usracct_db = dbopen(_PATH_USRACCT, O_RDWR|O_CREAT|O_TRUNC, 0644, 202 DB_BTREE, &bti); 203 if (saved_usracct_db == NULL) { 204 warn("creating user accounting summary"); 205 return (-1); 206 } 207 208 error = 0; 209 210 serr = DB_SEQ(usracct_db, &key, &data, R_FIRST); 211 if (serr < 0) { 212 warn("retrieving user accounting stats"); 213 error = -1; 214 } 215 while (serr == 0) { 216 nerr = DB_PUT(saved_usracct_db, &key, &data, 0); 217 if (nerr < 0) { 218 warn("saving user accounting summary"); 219 error = -1; 220 break; 221 } 222 223 serr = DB_SEQ(usracct_db, &key, &data, R_NEXT); 224 if (serr < 0) { 225 warn("retrieving user accounting stats"); 226 error = -1; 227 break; 228 } 229 } 230 231 if (DB_SYNC(saved_usracct_db, 0) < 0) { 232 warn("syncing process accounting summary"); 233 error = -1; 234 } 235 if (DB_CLOSE(saved_usracct_db) < 0) { 236 warn("closing process accounting summary"); 237 error = -1; 238 } 239 return error; 240 } 241 242 void 243 usracct_print() 244 { 245 DBT key, data; 246 struct userinfo uistore, *ui = &uistore; 247 double t; 248 int rv; 249 250 rv = DB_SEQ(usracct_db, &key, &data, R_FIRST); 251 if (rv < 0) 252 warn("retrieving user accounting stats"); 253 254 while (rv == 0) { 255 memcpy(ui, data.data, sizeof(struct userinfo)); 256 257 printf("%-8s %9llu ", 258 user_from_uid(ui->ui_uid, 0), 259 (unsigned long long)ui->ui_calls); 260 261 t = (double) (ui->ui_utime + ui->ui_stime) / 262 (double) AHZ; 263 if (t < 0.0001) /* kill divide by zero */ 264 t = 0.0001; 265 266 printf("%12.2f%s ", t / 60.0, "cpu"); 267 268 /* ui->ui_calls is always != 0 */ 269 if (dflag) 270 printf("%12llu%s", 271 (unsigned long long)(ui->ui_io / ui->ui_calls), 272 "avio"); 273 else 274 printf("%12llu%s", 275 (unsigned long long)ui->ui_io, "tio"); 276 277 /* t is always >= 0.0001; see above */ 278 if (kflag) 279 printf("%12llu%s", (unsigned long long)(ui->ui_mem / t), 280 "k"); 281 else 282 printf("%12llu%s", (unsigned long long)ui->ui_mem, 283 "k*sec"); 284 285 printf("\n"); 286 287 rv = DB_SEQ(usracct_db, &key, &data, R_NEXT); 288 if (rv < 0) 289 warn("retrieving user accounting stats"); 290 } 291 } 292 293 static int 294 uid_compare(k1, k2) 295 const DBT *k1, *k2; 296 { 297 u_long d1, d2; 298 299 memcpy(&d1, k1->data, sizeof(d1)); 300 memcpy(&d2, k2->data, sizeof(d2)); 301 302 if (d1 < d2) 303 return -1; 304 else if (d1 == d2) 305 return 0; 306 else 307 return 1; 308 } 309