1 /* $OpenBSD: usrdb.c,v 1.10 2016/08/14 22:29:01 krw Exp $ */ 2 /* 3 * Copyright (c) 1994 Christopher G. Demetriou 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Christopher G. Demetriou. 17 * 4. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/types.h> 33 #include <sys/acct.h> 34 #include <err.h> 35 #include <errno.h> 36 #include <fcntl.h> 37 #include <pwd.h> 38 #include <stdio.h> 39 #include <string.h> 40 #include "extern.h" 41 #include "pathnames.h" 42 43 static int uid_compare(const DBT *, const DBT *); 44 45 static DB *usracct_db; 46 47 int 48 usracct_init(void) 49 { 50 DB *saved_usracct_db; 51 BTREEINFO bti; 52 int error; 53 54 memset(&bti, 0, sizeof(bti)); 55 bti.compare = uid_compare; 56 57 usracct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti); 58 if (usracct_db == NULL) 59 return (-1); 60 61 error = 0; 62 if (!iflag) { 63 DBT key, data; 64 int serr, nerr; 65 66 saved_usracct_db = dbopen(_PATH_USRACCT, O_RDONLY, 0, DB_BTREE, 67 &bti); 68 if (saved_usracct_db == NULL) { 69 error = (errno == ENOENT) ? 0 : -1; 70 if (error) 71 warn("retrieving user accounting summary"); 72 goto out; 73 } 74 75 serr = DB_SEQ(saved_usracct_db, &key, &data, R_FIRST); 76 if (serr < 0) { 77 warn("retrieving user accounting summary"); 78 error = -1; 79 goto closeout; 80 } 81 while (serr == 0) { 82 nerr = DB_PUT(usracct_db, &key, &data, 0); 83 if (nerr < 0) { 84 warn("initializing user accounting stats"); 85 error = -1; 86 break; 87 } 88 89 serr = DB_SEQ(saved_usracct_db, &key, &data, R_NEXT); 90 if (serr < 0) { 91 warn("retrieving user accounting summary"); 92 error = -1; 93 break; 94 } 95 } 96 97 closeout: 98 if (DB_CLOSE(saved_usracct_db) < 0) { 99 warn("closing user accounting summary"); 100 error = -1; 101 } 102 } 103 104 out: 105 if (error != 0) 106 usracct_destroy(); 107 return (error); 108 } 109 110 void 111 usracct_destroy(void) 112 { 113 if (DB_CLOSE(usracct_db) < 0) 114 warn("destroying user accounting stats"); 115 } 116 117 int 118 usracct_add(const struct cmdinfo *ci) 119 { 120 DBT key, data; 121 struct userinfo newui; 122 uid_t uid; 123 int rv; 124 125 uid = ci->ci_uid; 126 key.data = &uid; 127 key.size = sizeof(uid); 128 129 rv = DB_GET(usracct_db, &key, &data, 0); 130 if (rv < 0) { 131 warn("get key %u from user accounting stats", uid); 132 return (-1); 133 } else if (rv == 0) { /* it's there; copy whole thing */ 134 /* add the old data to the new data */ 135 memcpy(&newui, data.data, data.size); 136 if (newui.ui_uid != uid) { 137 warnx("key %u != expected record number %u", 138 newui.ui_uid, uid); 139 warnx("inconsistent user accounting stats"); 140 return (-1); 141 } 142 } else { /* it's not there; zero it and copy the key */ 143 memset(&newui, 0, sizeof(newui)); 144 newui.ui_uid = ci->ci_uid; 145 } 146 147 newui.ui_calls += ci->ci_calls; 148 newui.ui_utime += ci->ci_utime; 149 newui.ui_stime += ci->ci_stime; 150 newui.ui_mem += ci->ci_mem; 151 newui.ui_io += ci->ci_io; 152 153 data.data = &newui; 154 data.size = sizeof(newui); 155 rv = DB_PUT(usracct_db, &key, &data, 0); 156 if (rv < 0) { 157 warn("add key %u to user accounting stats", uid); 158 return (-1); 159 } else if (rv != 0) { 160 warnx("DB_PUT returned 1"); 161 return (-1); 162 } 163 164 return (0); 165 } 166 167 int 168 usracct_update(void) 169 { 170 DB *saved_usracct_db; 171 DBT key, data; 172 BTREEINFO bti; 173 int error, serr, nerr; 174 175 memset(&bti, 0, sizeof(bti)); 176 bti.compare = uid_compare; 177 178 saved_usracct_db = dbopen(_PATH_USRACCT, O_RDWR|O_CREAT|O_TRUNC, 0644, 179 DB_BTREE, &bti); 180 if (saved_usracct_db == NULL) { 181 warn("creating user accounting summary"); 182 return (-1); 183 } 184 185 error = 0; 186 187 serr = DB_SEQ(usracct_db, &key, &data, R_FIRST); 188 if (serr < 0) { 189 warn("retrieving user accounting stats"); 190 error = -1; 191 } 192 while (serr == 0) { 193 nerr = DB_PUT(saved_usracct_db, &key, &data, 0); 194 if (nerr < 0) { 195 warn("saving user accounting summary"); 196 error = -1; 197 break; 198 } 199 200 serr = DB_SEQ(usracct_db, &key, &data, R_NEXT); 201 if (serr < 0) { 202 warn("retrieving user accounting stats"); 203 error = -1; 204 break; 205 } 206 } 207 208 if (DB_SYNC(saved_usracct_db, 0) < 0) { 209 warn("syncing process accounting summary"); 210 error = -1; 211 } 212 if (DB_CLOSE(saved_usracct_db) < 0) { 213 warn("closing process accounting summary"); 214 error = -1; 215 } 216 return error; 217 } 218 219 void 220 usracct_print(void) 221 { 222 DBT key, data; 223 struct userinfo uistore, *ui = &uistore; 224 double t; 225 int rv; 226 227 rv = DB_SEQ(usracct_db, &key, &data, R_FIRST); 228 if (rv < 0) 229 warn("retrieving user accounting stats"); 230 231 while (rv == 0) { 232 memcpy(ui, data.data, sizeof(struct userinfo)); 233 234 printf("%-8s %9llu ", 235 user_from_uid(ui->ui_uid, 0), ui->ui_calls); 236 237 t = (double) (ui->ui_utime + ui->ui_stime) / 238 (double) AHZ; 239 if (t < 0.0001) /* kill divide by zero */ 240 t = 0.0001; 241 242 printf("%12.2f%s ", t / 60.0, "cpu"); 243 244 /* ui->ui_calls is always != 0 */ 245 if (dflag) 246 printf("%12llu%s", ui->ui_io / ui->ui_calls, "avio"); 247 else 248 printf("%12llu%s", ui->ui_io, "tio"); 249 250 /* t is always >= 0.0001; see above */ 251 if (kflag) 252 printf("%12.0f%s", ui->ui_mem / t, "k"); 253 else 254 printf("%12llu%s", ui->ui_mem, "k*sec"); 255 256 printf("\n"); 257 258 rv = DB_SEQ(usracct_db, &key, &data, R_NEXT); 259 if (rv < 0) 260 warn("retrieving user accounting stats"); 261 } 262 } 263 264 static int 265 uid_compare(const DBT *k1, const DBT *k2) 266 { 267 uid_t d1, d2; 268 269 memcpy(&d1, k1->data, sizeof(d1)); 270 memcpy(&d2, k2->data, sizeof(d2)); 271 272 if (d1 < d2) 273 return -1; 274 else if (d1 == d2) 275 return 0; 276 else 277 return 1; 278 } 279