1 /* $NetBSD: usrdb.c,v 1.14 2010/08/30 02:49:17 dholland 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.14 2010/08/30 02:49:17 dholland 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(const DBT *, const DBT *); 54 55 static DB *usracct_db; 56 57 int 58 usracct_init(void) 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(void) 134 { 135 if (DB_CLOSE(usracct_db) < 0) 136 warn("destroying user accounting stats"); 137 } 138 139 int 140 usracct_add(const struct cmdinfo *ci) 141 { 142 DBT key, data; 143 struct userinfo newui; 144 uid_t uid; 145 int rv; 146 147 uid = ci->ci_uid; 148 key.data = &uid; 149 key.size = sizeof(uid); 150 151 rv = DB_GET(usracct_db, &key, &data, 0); 152 if (rv < 0) { 153 warn("get key %d from user accounting stats", uid); 154 return (-1); 155 } else if (rv == 0) { /* it's there; copy whole thing */ 156 /* add the old data to the new data */ 157 memcpy(&newui, data.data, data.size); 158 if (newui.ui_uid != uid) { 159 warnx("key %d != expected record number %d", 160 newui.ui_uid, uid); 161 warnx("inconsistent user accounting stats"); 162 return (-1); 163 } 164 } else { /* it's not there; zero it and copy the key */ 165 memset(&newui, 0, sizeof(newui)); 166 newui.ui_uid = ci->ci_uid; 167 } 168 169 newui.ui_calls += ci->ci_calls; 170 newui.ui_utime += ci->ci_utime; 171 newui.ui_stime += ci->ci_stime; 172 newui.ui_mem += ci->ci_mem; 173 newui.ui_io += ci->ci_io; 174 175 data.data = &newui; 176 data.size = sizeof(newui); 177 rv = DB_PUT(usracct_db, &key, &data, 0); 178 if (rv < 0) { 179 warn("add key %d to user accounting stats", uid); 180 return (-1); 181 } else if (rv != 0) { 182 warnx("DB_PUT returned 1"); 183 return (-1); 184 } 185 186 return (0); 187 } 188 189 int 190 usracct_update(void) 191 { 192 DB *saved_usracct_db; 193 DBT key, data; 194 BTREEINFO bti; 195 int error, serr, nerr; 196 197 memset(&bti, 0, sizeof(bti)); 198 bti.compare = uid_compare; 199 200 saved_usracct_db = dbopen(_PATH_USRACCT, O_RDWR|O_CREAT|O_TRUNC, 0644, 201 DB_BTREE, &bti); 202 if (saved_usracct_db == NULL) { 203 warn("creating user accounting summary"); 204 return (-1); 205 } 206 207 error = 0; 208 209 serr = DB_SEQ(usracct_db, &key, &data, R_FIRST); 210 if (serr < 0) { 211 warn("retrieving user accounting stats"); 212 error = -1; 213 } 214 while (serr == 0) { 215 nerr = DB_PUT(saved_usracct_db, &key, &data, 0); 216 if (nerr < 0) { 217 warn("saving user accounting summary"); 218 error = -1; 219 break; 220 } 221 222 serr = DB_SEQ(usracct_db, &key, &data, R_NEXT); 223 if (serr < 0) { 224 warn("retrieving user accounting stats"); 225 error = -1; 226 break; 227 } 228 } 229 230 if (DB_SYNC(saved_usracct_db, 0) < 0) { 231 warn("syncing process accounting summary"); 232 error = -1; 233 } 234 if (DB_CLOSE(saved_usracct_db) < 0) { 235 warn("closing process accounting summary"); 236 error = -1; 237 } 238 return error; 239 } 240 241 void 242 usracct_print(void) 243 { 244 DBT key, data; 245 struct userinfo uistore, *ui = &uistore; 246 double t; 247 int rv; 248 249 rv = DB_SEQ(usracct_db, &key, &data, R_FIRST); 250 if (rv < 0) 251 warn("retrieving user accounting stats"); 252 253 while (rv == 0) { 254 memcpy(ui, data.data, sizeof(struct userinfo)); 255 256 printf("%-8s %9llu ", 257 user_from_uid(ui->ui_uid, 0), 258 (unsigned long long)ui->ui_calls); 259 260 t = (double) (ui->ui_utime + ui->ui_stime) / 261 (double) AHZ; 262 if (t < 0.0001) /* kill divide by zero */ 263 t = 0.0001; 264 265 printf("%12.2f%s ", t / 60.0, "cpu"); 266 267 /* ui->ui_calls is always != 0 */ 268 if (dflag) 269 printf("%12llu%s", 270 (unsigned long long)(ui->ui_io / ui->ui_calls), 271 "avio"); 272 else 273 printf("%12llu%s", 274 (unsigned long long)ui->ui_io, "tio"); 275 276 /* t is always >= 0.0001; see above */ 277 if (kflag) 278 printf("%12llu%s", (unsigned long long)(ui->ui_mem / t), 279 "k"); 280 else 281 printf("%12llu%s", (unsigned long long)ui->ui_mem, 282 "k*sec"); 283 284 printf("\n"); 285 286 rv = DB_SEQ(usracct_db, &key, &data, R_NEXT); 287 if (rv < 0) 288 warn("retrieving user accounting stats"); 289 } 290 } 291 292 static int 293 uid_compare(const DBT *k1, const DBT *k2) 294 { 295 uid_t d1, d2; 296 297 memcpy(&d1, k1->data, sizeof(d1)); 298 memcpy(&d2, k2->data, sizeof(d2)); 299 300 if (d1 < d2) 301 return -1; 302 else if (d1 == d2) 303 return 0; 304 else 305 return 1; 306 } 307