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