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