usrdb.c revision 100107
1171939Sdes/* 2222176Suqs * Copyright (c) 1994 Christopher G. Demetriou 3171939Sdes * All rights reserved. 4171939Sdes * 5171939Sdes * Redistribution and use in source and binary forms, with or without 6171939Sdes * modification, are permitted provided that the following conditions 7171939Sdes * are met: 8171939Sdes * 1. Redistributions of source code must retain the above copyright 9171939Sdes * notice, this list of conditions and the following disclaimer. 10171939Sdes * 2. Redistributions in binary form must reproduce the above copyright 11171939Sdes * notice, this list of conditions and the following disclaimer in the 12171939Sdes * documentation and/or other materials provided with the distribution. 13171939Sdes * 3. All advertising materials mentioning features or use of this software 14171939Sdes * must display the following acknowledgement: 15171939Sdes * This product includes software developed by Christopher G. Demetriou. 16171939Sdes * 4. The name of the author may not be used to endorse or promote products 17171939Sdes * derived from this software without specific prior written permission 18171939Sdes * 19171939Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20171939Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21171939Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22171939Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23171939Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24171939Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25171939Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26171939Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27171939Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28181967Srpaulo * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29171939Sdes */ 30171939Sdes 31171939Sdes#ifndef lint 32171939Sdesstatic const char rcsid[] = 33171939Sdes "$FreeBSD: head/usr.sbin/sa/usrdb.c 100107 2002-07-15 16:05:15Z des $"; 34171939Sdes#endif /* not lint */ 35171939Sdes 36171939Sdes#include <sys/param.h> 37171939Sdes#include <sys/types.h> 38171939Sdes#include <sys/acct.h> 39171939Sdes#include <err.h> 40171939Sdes#include <errno.h> 41171939Sdes#include <fcntl.h> 42171939Sdes#include <pwd.h> 43171939Sdes#include <stdint.h> 44171939Sdes#include <stdio.h> 45171939Sdes#include <stdlib.h> 46171939Sdes#include <string.h> 47171939Sdes#include "extern.h" 48171939Sdes#include "pathnames.h" 49171939Sdes 50171939Sdesstatic int uid_compare __P((const DBT *, const DBT *)); 51171939Sdes 52171939Sdesstatic DB *usracct_db; 53181967Srpaulo 54181967Srpauloint 55181967Srpaulousracct_init() 56181967Srpaulo{ 57181967Srpaulo DB *saved_usracct_db; 58181967Srpaulo BTREEINFO bti; 59181967Srpaulo int error; 60181967Srpaulo 61181967Srpaulo bzero(&bti, sizeof bti); 62181967Srpaulo bti.compare = uid_compare; 63181967Srpaulo 64181967Srpaulo usracct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti); 65181967Srpaulo if (usracct_db == NULL) 66171939Sdes return (-1); 67171939Sdes 68171939Sdes error = 0; 69198288Savg if (!iflag) { 70181967Srpaulo DBT key, data; 71181967Srpaulo int serr, nerr; 72181967Srpaulo 73181967Srpaulo saved_usracct_db = dbopen(_PATH_USRACCT, O_RDONLY, 0, DB_BTREE, 74181967Srpaulo &bti); 75181967Srpaulo if (saved_usracct_db == NULL) { 76171939Sdes error = (errno == ENOENT) ? 0 : -1; 77171939Sdes if (error) 78171939Sdes warn("retrieving user accounting summary"); 79171939Sdes goto out; 80171939Sdes } 81171939Sdes 82171939Sdes serr = DB_SEQ(saved_usracct_db, &key, &data, R_FIRST); 83171939Sdes if (serr < 0) { 84171939Sdes warn("retrieving user accounting summary"); 85181967Srpaulo error = -1; 86267938Sbapt goto closeout; 87181967Srpaulo } 88267938Sbapt while (serr == 0) { 89171939Sdes nerr = DB_PUT(usracct_db, &key, &data, 0); 90267938Sbapt if (nerr < 0) { 91 warn("initializing user accounting stats"); 92 error = -1; 93 break; 94 } 95 96 serr = DB_SEQ(saved_usracct_db, &key, &data, R_NEXT); 97 if (serr < 0) { 98 warn("retrieving user accounting summary"); 99 error = -1; 100 break; 101 } 102 } 103 104closeout: 105 if (DB_CLOSE(saved_usracct_db) < 0) { 106 warn("closing user accounting summary"); 107 error = -1; 108 } 109 } 110 111out: 112 if (error != 0) 113 usracct_destroy(); 114 return (error); 115} 116 117void 118usracct_destroy() 119{ 120 if (DB_CLOSE(usracct_db) < 0) 121 warn("destroying user accounting stats"); 122} 123 124int 125usracct_add(ci) 126 const struct cmdinfo *ci; 127{ 128 DBT key, data; 129 struct userinfo newui; 130 u_long uid; 131 int rv; 132 133 uid = ci->ci_uid; 134 key.data = &uid; 135 key.size = sizeof uid; 136 137 rv = DB_GET(usracct_db, &key, &data, 0); 138 if (rv < 0) { 139 warn("get key %lu from user accounting stats", uid); 140 return (-1); 141 } else if (rv == 0) { /* it's there; copy whole thing */ 142 /* add the old data to the new data */ 143 bcopy(data.data, &newui, data.size); 144 if (newui.ui_uid != uid) { 145 warnx("key %lu != expected record number %lu", 146 newui.ui_uid, uid); 147 warnx("inconsistent user accounting stats"); 148 return (-1); 149 } 150 } else { /* it's not there; zero it and copy the key */ 151 bzero(&newui, sizeof newui); 152 newui.ui_uid = ci->ci_uid; 153 } 154 155 newui.ui_calls += ci->ci_calls; 156 newui.ui_utime += ci->ci_utime; 157 newui.ui_stime += ci->ci_stime; 158 newui.ui_mem += ci->ci_mem; 159 newui.ui_io += ci->ci_io; 160 161 data.data = &newui; 162 data.size = sizeof newui; 163 rv = DB_PUT(usracct_db, &key, &data, 0); 164 if (rv < 0) { 165 warn("add key %lu to user accounting stats", uid); 166 return (-1); 167 } else if (rv != 0) { 168 warnx("DB_PUT returned 1"); 169 return (-1); 170 } 171 172 return (0); 173} 174 175int 176usracct_update() 177{ 178 DB *saved_usracct_db; 179 DBT key, data; 180 BTREEINFO bti; 181 int error, serr, nerr; 182 183 bzero(&bti, sizeof bti); 184 bti.compare = uid_compare; 185 186 saved_usracct_db = dbopen(_PATH_USRACCT, O_RDWR|O_CREAT|O_TRUNC, 0644, 187 DB_BTREE, &bti); 188 if (saved_usracct_db == NULL) { 189 warn("creating user accounting summary"); 190 return (-1); 191 } 192 193 error = 0; 194 195 serr = DB_SEQ(usracct_db, &key, &data, R_FIRST); 196 if (serr < 0) { 197 warn("retrieving user accounting stats"); 198 error = -1; 199 } 200 while (serr == 0) { 201 nerr = DB_PUT(saved_usracct_db, &key, &data, 0); 202 if (nerr < 0) { 203 warn("saving user accounting summary"); 204 error = -1; 205 break; 206 } 207 208 serr = DB_SEQ(usracct_db, &key, &data, R_NEXT); 209 if (serr < 0) { 210 warn("retrieving user accounting stats"); 211 error = -1; 212 break; 213 } 214 } 215 216 if (DB_SYNC(saved_usracct_db, 0) < 0) { 217 warn("syncing process accounting summary"); 218 error = -1; 219 } 220 if (DB_CLOSE(saved_usracct_db) < 0) { 221 warn("closing process accounting summary"); 222 error = -1; 223 } 224 return error; 225} 226 227void 228usracct_print() 229{ 230 DBT key, data; 231 struct userinfo uistore, *ui = &uistore; 232 double t; 233 int rv; 234 235 rv = DB_SEQ(usracct_db, &key, &data, R_FIRST); 236 if (rv < 0) 237 warn("retrieving user accounting stats"); 238 239 while (rv == 0) { 240 memcpy(ui, data.data, sizeof(struct userinfo)); 241 242 printf("%-*s %9ju ", MAXLOGNAME - 1, 243 user_from_uid(ui->ui_uid, 0), (uintmax_t)ui->ui_calls); 244 245 t = (double) (ui->ui_utime + ui->ui_stime) / 246 (double) AHZ; 247 if (t < 0.0001) /* kill divide by zero */ 248 t = 0.0001; 249 250 printf("%12.2f%s ", t / 60.0, "cpu"); 251 252 /* ui->ui_calls is always != 0 */ 253 if (dflag) 254 printf("%12ju%s", 255 (uintmax_t)(ui->ui_io / ui->ui_calls), "avio"); 256 else 257 printf("%12ju%s", (uintmax_t)ui->ui_io, "tio"); 258 259 /* t is always >= 0.0001; see above */ 260 if (kflag) 261 printf("%12.0f%s", ui->ui_mem / t, "k"); 262 else 263 printf("%12ju%s", (uintmax_t)ui->ui_mem, "k*sec"); 264 265 printf("\n"); 266 267 rv = DB_SEQ(usracct_db, &key, &data, R_NEXT); 268 if (rv < 0) 269 warn("retrieving user accounting stats"); 270 } 271} 272 273static int 274uid_compare(k1, k2) 275 const DBT *k1, *k2; 276{ 277 u_long d1, d2; 278 279 bcopy(k1->data, &d1, sizeof d1); 280 bcopy(k2->data, &d2, sizeof d2); 281 282 if (d1 < d2) 283 return -1; 284 else if (d1 == d2) 285 return 0; 286 else 287 return 1; 288} 289