usrdb.c revision 141638
13125Sdg/* 23125Sdg * Copyright (c) 1994 Christopher G. Demetriou 33125Sdg * All rights reserved. 43125Sdg * 53125Sdg * Redistribution and use in source and binary forms, with or without 63125Sdg * modification, are permitted provided that the following conditions 73125Sdg * are met: 83125Sdg * 1. Redistributions of source code must retain the above copyright 93125Sdg * notice, this list of conditions and the following disclaimer. 103125Sdg * 2. Redistributions in binary form must reproduce the above copyright 113125Sdg * notice, this list of conditions and the following disclaimer in the 123125Sdg * documentation and/or other materials provided with the distribution. 133125Sdg * 3. All advertising materials mentioning features or use of this software 143125Sdg * must display the following acknowledgement: 153125Sdg * This product includes software developed by Christopher G. Demetriou. 163125Sdg * 4. The name of the author may not be used to endorse or promote products 173125Sdg * derived from this software without specific prior written permission 183125Sdg * 193125Sdg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 203125Sdg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 213125Sdg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 223125Sdg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 233125Sdg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 243125Sdg * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 253125Sdg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 263125Sdg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 273125Sdg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 283125Sdg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 293125Sdg */ 303125Sdg 31114601Sobrien#include <sys/cdefs.h> 32114601Sobrien__FBSDID("$FreeBSD: head/usr.sbin/sa/usrdb.c 141638 2005-02-10 12:43:16Z delphij $"); 333125Sdg 3461089Sghelmer#include <sys/param.h> 353125Sdg#include <sys/types.h> 363125Sdg#include <sys/acct.h> 373125Sdg#include <err.h> 383125Sdg#include <errno.h> 393125Sdg#include <fcntl.h> 4090878Simp#include <pwd.h> 41100107Sdes#include <stdint.h> 4213558Smpp#include <stdio.h> 4330425Scharnier#include <stdlib.h> 4413558Smpp#include <string.h> 453125Sdg#include "extern.h" 463125Sdg#include "pathnames.h" 473125Sdg 48141638Sdelphijstatic int uid_compare(const DBT *, const DBT *); 493125Sdg 503125Sdgstatic DB *usracct_db; 513125Sdg 523125Sdgint 533125Sdgusracct_init() 543125Sdg{ 553125Sdg DB *saved_usracct_db; 563125Sdg BTREEINFO bti; 573125Sdg int error; 583125Sdg 593125Sdg bzero(&bti, sizeof bti); 603125Sdg bti.compare = uid_compare; 613125Sdg 623125Sdg usracct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti); 633125Sdg if (usracct_db == NULL) 643125Sdg return (-1); 653125Sdg 663125Sdg error = 0; 673125Sdg if (!iflag) { 683125Sdg DBT key, data; 693125Sdg int serr, nerr; 703125Sdg 713125Sdg saved_usracct_db = dbopen(_PATH_USRACCT, O_RDONLY, 0, DB_BTREE, 723125Sdg &bti); 733125Sdg if (saved_usracct_db == NULL) { 743125Sdg error = (errno == ENOENT) ? 0 : -1; 753125Sdg if (error) 763125Sdg warn("retrieving user accounting summary"); 773125Sdg goto out; 783125Sdg } 793125Sdg 803125Sdg serr = DB_SEQ(saved_usracct_db, &key, &data, R_FIRST); 813125Sdg if (serr < 0) { 823125Sdg warn("retrieving user accounting summary"); 833125Sdg error = -1; 843125Sdg goto closeout; 853125Sdg } 863125Sdg while (serr == 0) { 873125Sdg nerr = DB_PUT(usracct_db, &key, &data, 0); 883125Sdg if (nerr < 0) { 893125Sdg warn("initializing user accounting stats"); 903125Sdg error = -1; 913125Sdg break; 928857Srgrimes } 933125Sdg 943125Sdg serr = DB_SEQ(saved_usracct_db, &key, &data, R_NEXT); 953125Sdg if (serr < 0) { 963125Sdg warn("retrieving user accounting summary"); 973125Sdg error = -1; 983125Sdg break; 993125Sdg } 1003125Sdg } 1013125Sdg 1023125Sdgcloseout: 1033125Sdg if (DB_CLOSE(saved_usracct_db) < 0) { 1043125Sdg warn("closing user accounting summary"); 1053125Sdg error = -1; 1063125Sdg } 1073125Sdg } 1083125Sdg 1093125Sdgout: 1103125Sdg if (error != 0) 1113125Sdg usracct_destroy(); 1123125Sdg return (error); 1133125Sdg} 1143125Sdg 1153125Sdgvoid 1163125Sdgusracct_destroy() 1173125Sdg{ 1183125Sdg if (DB_CLOSE(usracct_db) < 0) 1193125Sdg warn("destroying user accounting stats"); 1203125Sdg} 1213125Sdg 1223125Sdgint 123141638Sdelphijusracct_add(const struct cmdinfo *ci) 1243125Sdg{ 1253125Sdg DBT key, data; 1263125Sdg struct userinfo newui; 1273125Sdg u_long uid; 1283125Sdg int rv; 1293125Sdg 1303125Sdg uid = ci->ci_uid; 1313125Sdg key.data = &uid; 1323125Sdg key.size = sizeof uid; 1333125Sdg 1343125Sdg rv = DB_GET(usracct_db, &key, &data, 0); 1353125Sdg if (rv < 0) { 13649455Sbde warn("get key %lu from user accounting stats", uid); 1373125Sdg return (-1); 1383125Sdg } else if (rv == 0) { /* it's there; copy whole thing */ 1393125Sdg /* add the old data to the new data */ 1403125Sdg bcopy(data.data, &newui, data.size); 1413125Sdg if (newui.ui_uid != uid) { 14249455Sbde warnx("key %lu != expected record number %lu", 1433125Sdg newui.ui_uid, uid); 1443125Sdg warnx("inconsistent user accounting stats"); 1453125Sdg return (-1); 1463125Sdg } 1473125Sdg } else { /* it's not there; zero it and copy the key */ 1483125Sdg bzero(&newui, sizeof newui); 1493125Sdg newui.ui_uid = ci->ci_uid; 1503125Sdg } 1513125Sdg 1523125Sdg newui.ui_calls += ci->ci_calls; 1533125Sdg newui.ui_utime += ci->ci_utime; 1543125Sdg newui.ui_stime += ci->ci_stime; 1553125Sdg newui.ui_mem += ci->ci_mem; 1563125Sdg newui.ui_io += ci->ci_io; 1573125Sdg 1588857Srgrimes data.data = &newui; 1593125Sdg data.size = sizeof newui; 1603125Sdg rv = DB_PUT(usracct_db, &key, &data, 0); 1613125Sdg if (rv < 0) { 16249455Sbde warn("add key %lu to user accounting stats", uid); 1633125Sdg return (-1); 1643125Sdg } else if (rv != 0) { 1653125Sdg warnx("DB_PUT returned 1"); 1663125Sdg return (-1); 1673125Sdg } 1683125Sdg 1693125Sdg return (0); 1703125Sdg} 1713125Sdg 1723125Sdgint 1733125Sdgusracct_update() 1743125Sdg{ 1753125Sdg DB *saved_usracct_db; 1763125Sdg DBT key, data; 1773125Sdg BTREEINFO bti; 1783125Sdg int error, serr, nerr; 1793125Sdg 1803125Sdg bzero(&bti, sizeof bti); 1813125Sdg bti.compare = uid_compare; 1823125Sdg 1833125Sdg saved_usracct_db = dbopen(_PATH_USRACCT, O_RDWR|O_CREAT|O_TRUNC, 0644, 1843125Sdg DB_BTREE, &bti); 1853125Sdg if (saved_usracct_db == NULL) { 1863125Sdg warn("creating user accounting summary"); 1873125Sdg return (-1); 1883125Sdg } 1893125Sdg 1903125Sdg error = 0; 1913125Sdg 1923125Sdg serr = DB_SEQ(usracct_db, &key, &data, R_FIRST); 1933125Sdg if (serr < 0) { 1943125Sdg warn("retrieving user accounting stats"); 1953125Sdg error = -1; 1963125Sdg } 1973125Sdg while (serr == 0) { 1983125Sdg nerr = DB_PUT(saved_usracct_db, &key, &data, 0); 1993125Sdg if (nerr < 0) { 2003125Sdg warn("saving user accounting summary"); 2013125Sdg error = -1; 2023125Sdg break; 2033125Sdg } 2043125Sdg 2053125Sdg serr = DB_SEQ(usracct_db, &key, &data, R_NEXT); 2063125Sdg if (serr < 0) { 2073125Sdg warn("retrieving user accounting stats"); 2083125Sdg error = -1; 2093125Sdg break; 2103125Sdg } 2113125Sdg } 2123125Sdg 2133125Sdg if (DB_SYNC(saved_usracct_db, 0) < 0) { 2143125Sdg warn("syncing process accounting summary"); 2153125Sdg error = -1; 2163125Sdg } 2173125Sdg if (DB_CLOSE(saved_usracct_db) < 0) { 2183125Sdg warn("closing process accounting summary"); 2193125Sdg error = -1; 2203125Sdg } 2213125Sdg return error; 2223125Sdg} 2233125Sdg 2243125Sdgvoid 2253125Sdgusracct_print() 2263125Sdg{ 2273125Sdg DBT key, data; 22867642Sgallatin struct userinfo uistore, *ui = &uistore; 2293125Sdg double t; 2303125Sdg int rv; 2313125Sdg 2323125Sdg rv = DB_SEQ(usracct_db, &key, &data, R_FIRST); 2333125Sdg if (rv < 0) 2343125Sdg warn("retrieving user accounting stats"); 2353125Sdg 2363125Sdg while (rv == 0) { 23767642Sgallatin memcpy(ui, data.data, sizeof(struct userinfo)); 2383125Sdg 239100107Sdes printf("%-*s %9ju ", MAXLOGNAME - 1, 240100107Sdes user_from_uid(ui->ui_uid, 0), (uintmax_t)ui->ui_calls); 2413125Sdg 2423125Sdg t = (double) (ui->ui_utime + ui->ui_stime) / 2433125Sdg (double) AHZ; 2443125Sdg if (t < 0.0001) /* kill divide by zero */ 2453125Sdg t = 0.0001; 2463125Sdg 24713558Smpp printf("%12.2f%s ", t / 60.0, "cpu"); 2483125Sdg 2493125Sdg /* ui->ui_calls is always != 0 */ 2503125Sdg if (dflag) 251100107Sdes printf("%12ju%s", 252100107Sdes (uintmax_t)(ui->ui_io / ui->ui_calls), "avio"); 2533125Sdg else 254100107Sdes printf("%12ju%s", (uintmax_t)ui->ui_io, "tio"); 2553125Sdg 2563125Sdg /* t is always >= 0.0001; see above */ 2573125Sdg if (kflag) 25849455Sbde printf("%12.0f%s", ui->ui_mem / t, "k"); 2593125Sdg else 260100107Sdes printf("%12ju%s", (uintmax_t)ui->ui_mem, "k*sec"); 2613125Sdg 2623125Sdg printf("\n"); 2633125Sdg 2643125Sdg rv = DB_SEQ(usracct_db, &key, &data, R_NEXT); 2653125Sdg if (rv < 0) 2663125Sdg warn("retrieving user accounting stats"); 2673125Sdg } 2683125Sdg} 2693125Sdg 2703125Sdgstatic int 271141638Sdelphijuid_compare(const DBT *k1, const DBT *k2) 2723125Sdg{ 2733125Sdg u_long d1, d2; 2743125Sdg 2753125Sdg bcopy(k1->data, &d1, sizeof d1); 2763125Sdg bcopy(k2->data, &d2, sizeof d2); 2778857Srgrimes 2783125Sdg if (d1 < d2) 2793125Sdg return -1; 2803125Sdg else if (d1 == d2) 2813125Sdg return 0; 2823125Sdg else 2833125Sdg return 1; 2843125Sdg} 285