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