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 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include <sys/param.h> 35 #include <sys/types.h> 36 #include <sys/acct.h> 37 #include <err.h> 38 #include <errno.h> 39 #include <fcntl.h> 40 #include <pwd.h> 41 #include <stdint.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(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(usrdb_file, 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(const struct cmdinfo *ci) 124 { 125 DBT key, data; 126 struct userinfo newui; 127 u_long uid; 128 int rv; 129 130 uid = ci->ci_uid; 131 key.data = &uid; 132 key.size = sizeof uid; 133 134 rv = DB_GET(usracct_db, &key, &data, 0); 135 if (rv < 0) { 136 warn("get key %lu from user accounting stats", uid); 137 return (-1); 138 } else if (rv == 0) { /* it's there; copy whole thing */ 139 /* add the old data to the new data */ 140 bcopy(data.data, &newui, data.size); 141 if (newui.ui_uid != uid) { 142 warnx("key %lu != expected record number %lu", 143 newui.ui_uid, uid); 144 warnx("inconsistent user accounting stats"); 145 return (-1); 146 } 147 } else { /* it's not there; zero it and copy the key */ 148 bzero(&newui, sizeof newui); 149 newui.ui_uid = ci->ci_uid; 150 } 151 152 newui.ui_calls += ci->ci_calls; 153 newui.ui_utime += ci->ci_utime; 154 newui.ui_stime += ci->ci_stime; 155 newui.ui_mem += ci->ci_mem; 156 newui.ui_io += ci->ci_io; 157 158 data.data = &newui; 159 data.size = sizeof newui; 160 rv = DB_PUT(usracct_db, &key, &data, 0); 161 if (rv < 0) { 162 warn("add key %lu to user accounting stats", uid); 163 return (-1); 164 } else if (rv != 0) { 165 warnx("DB_PUT returned 1"); 166 return (-1); 167 } 168 169 return (0); 170 } 171 172 int 173 usracct_update() 174 { 175 DB *saved_usracct_db; 176 DBT key, data; 177 BTREEINFO bti; 178 int error, serr, nerr; 179 180 bzero(&bti, sizeof bti); 181 bti.compare = uid_compare; 182 183 saved_usracct_db = dbopen(usrdb_file, O_RDWR|O_CREAT|O_TRUNC, 0644, 184 DB_BTREE, &bti); 185 if (saved_usracct_db == NULL) { 186 warn("creating user accounting summary"); 187 return (-1); 188 } 189 190 error = 0; 191 192 serr = DB_SEQ(usracct_db, &key, &data, R_FIRST); 193 if (serr < 0) { 194 warn("retrieving user accounting stats"); 195 error = -1; 196 } 197 while (serr == 0) { 198 nerr = DB_PUT(saved_usracct_db, &key, &data, 0); 199 if (nerr < 0) { 200 warn("saving user accounting summary"); 201 error = -1; 202 break; 203 } 204 205 serr = DB_SEQ(usracct_db, &key, &data, R_NEXT); 206 if (serr < 0) { 207 warn("retrieving user accounting stats"); 208 error = -1; 209 break; 210 } 211 } 212 213 if (DB_SYNC(saved_usracct_db, 0) < 0) { 214 warn("syncing process accounting summary"); 215 error = -1; 216 } 217 if (DB_CLOSE(saved_usracct_db) < 0) { 218 warn("closing process accounting summary"); 219 error = -1; 220 } 221 return error; 222 } 223 224 void 225 usracct_print() 226 { 227 DBT key, data; 228 struct userinfo uistore, *ui = &uistore; 229 double t; 230 int rv; 231 232 rv = DB_SEQ(usracct_db, &key, &data, R_FIRST); 233 if (rv < 0) 234 warn("retrieving user accounting stats"); 235 236 while (rv == 0) { 237 memcpy(ui, data.data, sizeof(struct userinfo)); 238 239 printf("%-*s %9ju ", MAXLOGNAME - 1, 240 user_from_uid(ui->ui_uid, 0), (uintmax_t)ui->ui_calls); 241 242 t = (double) (ui->ui_utime + ui->ui_stime) / 243 (double) AHZ; 244 if (t < 0.0001) /* kill divide by zero */ 245 t = 0.0001; 246 247 printf("%12.2f%s ", t / 60.0, "cpu"); 248 249 /* ui->ui_calls is always != 0 */ 250 if (dflag) 251 printf("%12ju%s", 252 (uintmax_t)(ui->ui_io / ui->ui_calls), "avio"); 253 else 254 printf("%12ju%s", (uintmax_t)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("%12ju%s", (uintmax_t)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(const DBT *k1, const DBT *k2) 272 { 273 u_long d1, d2; 274 275 bcopy(k1->data, &d1, sizeof d1); 276 bcopy(k2->data, &d2, sizeof d2); 277 278 if (d1 < d2) 279 return -1; 280 else if (d1 == d2) 281 return 0; 282 else 283 return 1; 284 } 285