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 const char rcsid[] = 33 "$FreeBSD$"; 34 #endif /* not lint */ 35 36 #include <sys/param.h> 37 #include <sys/types.h> 38 #include <sys/acct.h> 39 #include <err.h> 40 #include <errno.h> 41 #include <fcntl.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include "extern.h" 46 #include "pathnames.h" 47 48 static int uid_compare __P((const DBT *, const DBT *)); 49 50 static DB *usracct_db; 51 52 int 53 usracct_init() 54 { 55 DB *saved_usracct_db; 56 BTREEINFO bti; 57 int error; 58 59 bzero(&bti, sizeof bti); 60 bti.compare = uid_compare; 61 62 usracct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti); 63 if (usracct_db == NULL) 64 return (-1); 65 66 error = 0; 67 if (!iflag) { 68 DBT key, data; 69 int serr, nerr; 70 71 saved_usracct_db = dbopen(_PATH_USRACCT, O_RDONLY, 0, DB_BTREE, 72 &bti); 73 if (saved_usracct_db == NULL) { 74 error = (errno == ENOENT) ? 0 : -1; 75 if (error) 76 warn("retrieving user accounting summary"); 77 goto out; 78 } 79 80 serr = DB_SEQ(saved_usracct_db, &key, &data, R_FIRST); 81 if (serr < 0) { 82 warn("retrieving user accounting summary"); 83 error = -1; 84 goto closeout; 85 } 86 while (serr == 0) { 87 nerr = DB_PUT(usracct_db, &key, &data, 0); 88 if (nerr < 0) { 89 warn("initializing user accounting stats"); 90 error = -1; 91 break; 92 } 93 94 serr = DB_SEQ(saved_usracct_db, &key, &data, R_NEXT); 95 if (serr < 0) { 96 warn("retrieving user accounting summary"); 97 error = -1; 98 break; 99 } 100 } 101 102 closeout: 103 if (DB_CLOSE(saved_usracct_db) < 0) { 104 warn("closing user accounting summary"); 105 error = -1; 106 } 107 } 108 109 out: 110 if (error != 0) 111 usracct_destroy(); 112 return (error); 113 } 114 115 void 116 usracct_destroy() 117 { 118 if (DB_CLOSE(usracct_db) < 0) 119 warn("destroying user accounting stats"); 120 } 121 122 int 123 usracct_add(ci) 124 const struct cmdinfo *ci; 125 { 126 DBT key, data; 127 struct userinfo newui; 128 u_long uid; 129 int rv; 130 131 uid = ci->ci_uid; 132 key.data = &uid; 133 key.size = sizeof uid; 134 135 rv = DB_GET(usracct_db, &key, &data, 0); 136 if (rv < 0) { 137 warn("get key %lu from user accounting stats", uid); 138 return (-1); 139 } else if (rv == 0) { /* it's there; copy whole thing */ 140 /* add the old data to the new data */ 141 bcopy(data.data, &newui, data.size); 142 if (newui.ui_uid != uid) { 143 warnx("key %lu != expected record number %lu", 144 newui.ui_uid, uid); 145 warnx("inconsistent user accounting stats"); 146 return (-1); 147 } 148 } else { /* it's not there; zero it and copy the key */ 149 bzero(&newui, sizeof newui); 150 newui.ui_uid = ci->ci_uid; 151 } 152 153 newui.ui_calls += ci->ci_calls; 154 newui.ui_utime += ci->ci_utime; 155 newui.ui_stime += ci->ci_stime; 156 newui.ui_mem += ci->ci_mem; 157 newui.ui_io += ci->ci_io; 158 159 data.data = &newui; 160 data.size = sizeof newui; 161 rv = DB_PUT(usracct_db, &key, &data, 0); 162 if (rv < 0) { 163 warn("add key %lu to user accounting stats", uid); 164 return (-1); 165 } else if (rv != 0) { 166 warnx("DB_PUT returned 1"); 167 return (-1); 168 } 169 170 return (0); 171 } 172 173 int 174 usracct_update() 175 { 176 DB *saved_usracct_db; 177 DBT key, data; 178 BTREEINFO bti; 179 int error, serr, nerr; 180 181 bzero(&bti, sizeof bti); 182 bti.compare = uid_compare; 183 184 saved_usracct_db = dbopen(_PATH_USRACCT, O_RDWR|O_CREAT|O_TRUNC, 0644, 185 DB_BTREE, &bti); 186 if (saved_usracct_db == NULL) { 187 warn("creating user accounting summary"); 188 return (-1); 189 } 190 191 error = 0; 192 193 serr = DB_SEQ(usracct_db, &key, &data, R_FIRST); 194 if (serr < 0) { 195 warn("retrieving user accounting stats"); 196 error = -1; 197 } 198 while (serr == 0) { 199 nerr = DB_PUT(saved_usracct_db, &key, &data, 0); 200 if (nerr < 0) { 201 warn("saving user accounting summary"); 202 error = -1; 203 break; 204 } 205 206 serr = DB_SEQ(usracct_db, &key, &data, R_NEXT); 207 if (serr < 0) { 208 warn("retrieving user accounting stats"); 209 error = -1; 210 break; 211 } 212 } 213 214 if (DB_SYNC(saved_usracct_db, 0) < 0) { 215 warn("syncing process accounting summary"); 216 error = -1; 217 } 218 if (DB_CLOSE(saved_usracct_db) < 0) { 219 warn("closing process accounting summary"); 220 error = -1; 221 } 222 return error; 223 } 224 225 void 226 usracct_print() 227 { 228 DBT key, data; 229 struct userinfo uistore, *ui = &uistore; 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 memcpy(ui, data.data, sizeof(struct userinfo)); 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 270 static int 271 uid_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