usrdb.c revision 30425
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
3130425Scharnier#ifndef lint
3230425Scharnierstatic const char rcsid[] =
3330425Scharnier	"$Id$";
3430425Scharnier#endif /* not lint */
353125Sdg
363125Sdg#include <sys/types.h>
373125Sdg#include <sys/acct.h>
383125Sdg#include <err.h>
393125Sdg#include <errno.h>
403125Sdg#include <fcntl.h>
4113558Smpp#include <stdio.h>
4230425Scharnier#include <stdlib.h>
4313558Smpp#include <string.h>
443125Sdg#include "extern.h"
453125Sdg#include "pathnames.h"
463125Sdg
473125Sdgstatic int uid_compare __P((const DBT *, const DBT *));
483125Sdg
493125Sdgstatic DB	*usracct_db;
503125Sdg
513125Sdgint
523125Sdgusracct_init()
533125Sdg{
543125Sdg	DB *saved_usracct_db;
553125Sdg	BTREEINFO bti;
563125Sdg	int error;
573125Sdg
583125Sdg	bzero(&bti, sizeof bti);
593125Sdg	bti.compare = uid_compare;
603125Sdg
613125Sdg	usracct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti);
623125Sdg	if (usracct_db == NULL)
633125Sdg		return (-1);
643125Sdg
653125Sdg	error = 0;
663125Sdg	if (!iflag) {
673125Sdg		DBT key, data;
683125Sdg		int serr, nerr;
693125Sdg
703125Sdg		saved_usracct_db = dbopen(_PATH_USRACCT, O_RDONLY, 0, DB_BTREE,
713125Sdg		    &bti);
723125Sdg		if (saved_usracct_db == NULL) {
733125Sdg			error = (errno == ENOENT) ? 0 : -1;
743125Sdg			if (error)
753125Sdg				warn("retrieving user accounting summary");
763125Sdg			goto out;
773125Sdg		}
783125Sdg
793125Sdg		serr = DB_SEQ(saved_usracct_db, &key, &data, R_FIRST);
803125Sdg		if (serr < 0) {
813125Sdg			warn("retrieving user accounting summary");
823125Sdg			error = -1;
833125Sdg			goto closeout;
843125Sdg		}
853125Sdg		while (serr == 0) {
863125Sdg			nerr = DB_PUT(usracct_db, &key, &data, 0);
873125Sdg			if (nerr < 0) {
883125Sdg				warn("initializing user accounting stats");
893125Sdg				error = -1;
903125Sdg				break;
918857Srgrimes			}
923125Sdg
933125Sdg			serr = DB_SEQ(saved_usracct_db, &key, &data, R_NEXT);
943125Sdg			if (serr < 0) {
953125Sdg				warn("retrieving user accounting summary");
963125Sdg				error = -1;
973125Sdg				break;
983125Sdg			}
993125Sdg		}
1003125Sdg
1013125Sdgcloseout:
1023125Sdg		if (DB_CLOSE(saved_usracct_db) < 0) {
1033125Sdg			warn("closing user accounting summary");
1043125Sdg			error = -1;
1053125Sdg		}
1063125Sdg	}
1073125Sdg
1083125Sdgout:
1093125Sdg	if (error != 0)
1103125Sdg		usracct_destroy();
1113125Sdg	return (error);
1123125Sdg}
1133125Sdg
1143125Sdgvoid
1153125Sdgusracct_destroy()
1163125Sdg{
1173125Sdg	if (DB_CLOSE(usracct_db) < 0)
1183125Sdg		warn("destroying user accounting stats");
1193125Sdg}
1203125Sdg
1213125Sdgint
1223125Sdgusracct_add(ci)
1233125Sdg	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) {
1363125Sdg		warn("get key %d 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) {
1423125Sdg			warnx("key %d != expected record number %d",
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) {
1623125Sdg		warn("add key %d 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;
2283125Sdg	struct userinfo *ui;
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) {
2373125Sdg		ui = (struct userinfo *) data.data;
2383125Sdg
2393125Sdg		printf("%-8s %9qu ",
2403125Sdg		    user_from_uid(ui->ui_uid, 0), 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)
2513125Sdg			printf("%12qu%s", ui->ui_io / ui->ui_calls, "avio");
2523125Sdg		else
2533125Sdg			printf("%12qu%s", ui->ui_io, "tio");
2543125Sdg
2553125Sdg		/* t is always >= 0.0001; see above */
2563125Sdg		if (kflag)
2573125Sdg			printf("%12qu%s", ui->ui_mem / t, "k");
2583125Sdg		else
2593125Sdg			printf("%12qu%s", ui->ui_mem, "k*sec");
2603125Sdg
2613125Sdg		printf("\n");
2623125Sdg
2633125Sdg		rv = DB_SEQ(usracct_db, &key, &data, R_NEXT);
2643125Sdg		if (rv < 0)
2653125Sdg			warn("retrieving user accounting stats");
2663125Sdg	}
2673125Sdg}
2683125Sdg
2693125Sdgstatic int
2703125Sdguid_compare(k1, k2)
2713125Sdg	const DBT *k1, *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