usrdb.c revision 3125
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
313125Sdg#ifndef LINT
323125Sdgstatic char rcsid[] = "$Id: usrdb.c,v 1.1 1994/03/24 18:42:01 cgd Exp $";
333125Sdg#endif
343125Sdg
353125Sdg#include <sys/types.h>
363125Sdg#include <sys/acct.h>
373125Sdg#include <err.h>
383125Sdg#include <errno.h>
393125Sdg#include <fcntl.h>
403125Sdg#include "extern.h"
413125Sdg#include "pathnames.h"
423125Sdg
433125Sdgstatic int uid_compare __P((const DBT *, const DBT *));
443125Sdg
453125Sdgstatic DB	*usracct_db;
463125Sdg
473125Sdgint
483125Sdgusracct_init()
493125Sdg{
503125Sdg	DB *saved_usracct_db;
513125Sdg	BTREEINFO bti;
523125Sdg	int error;
533125Sdg
543125Sdg	bzero(&bti, sizeof bti);
553125Sdg	bti.compare = uid_compare;
563125Sdg
573125Sdg	usracct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti);
583125Sdg	if (usracct_db == NULL)
593125Sdg		return (-1);
603125Sdg
613125Sdg	error = 0;
623125Sdg	if (!iflag) {
633125Sdg		DBT key, data;
643125Sdg		int serr, nerr;
653125Sdg
663125Sdg		saved_usracct_db = dbopen(_PATH_USRACCT, O_RDONLY, 0, DB_BTREE,
673125Sdg		    &bti);
683125Sdg		if (saved_usracct_db == NULL) {
693125Sdg			error = (errno == ENOENT) ? 0 : -1;
703125Sdg			if (error)
713125Sdg				warn("retrieving user accounting summary");
723125Sdg			goto out;
733125Sdg		}
743125Sdg
753125Sdg		serr = DB_SEQ(saved_usracct_db, &key, &data, R_FIRST);
763125Sdg		if (serr < 0) {
773125Sdg			warn("retrieving user accounting summary");
783125Sdg			error = -1;
793125Sdg			goto closeout;
803125Sdg		}
813125Sdg		while (serr == 0) {
823125Sdg			nerr = DB_PUT(usracct_db, &key, &data, 0);
833125Sdg			if (nerr < 0) {
843125Sdg				warn("initializing user accounting stats");
853125Sdg				error = -1;
863125Sdg				break;
873125Sdg			}
883125Sdg
893125Sdg			serr = DB_SEQ(saved_usracct_db, &key, &data, R_NEXT);
903125Sdg			if (serr < 0) {
913125Sdg				warn("retrieving user accounting summary");
923125Sdg				error = -1;
933125Sdg				break;
943125Sdg			}
953125Sdg		}
963125Sdg
973125Sdgcloseout:
983125Sdg		if (DB_CLOSE(saved_usracct_db) < 0) {
993125Sdg			warn("closing user accounting summary");
1003125Sdg			error = -1;
1013125Sdg		}
1023125Sdg	}
1033125Sdg
1043125Sdgout:
1053125Sdg	if (error != 0)
1063125Sdg		usracct_destroy();
1073125Sdg	return (error);
1083125Sdg}
1093125Sdg
1103125Sdgvoid
1113125Sdgusracct_destroy()
1123125Sdg{
1133125Sdg	if (DB_CLOSE(usracct_db) < 0)
1143125Sdg		warn("destroying user accounting stats");
1153125Sdg}
1163125Sdg
1173125Sdgint
1183125Sdgusracct_add(ci)
1193125Sdg	const struct cmdinfo *ci;
1203125Sdg{
1213125Sdg	DBT key, data;
1223125Sdg	struct userinfo newui;
1233125Sdg	u_long uid;
1243125Sdg	int rv;
1253125Sdg
1263125Sdg	uid = ci->ci_uid;
1273125Sdg	key.data = &uid;
1283125Sdg	key.size = sizeof uid;
1293125Sdg
1303125Sdg	rv = DB_GET(usracct_db, &key, &data, 0);
1313125Sdg	if (rv < 0) {
1323125Sdg		warn("get key %d from user accounting stats", uid);
1333125Sdg		return (-1);
1343125Sdg	} else if (rv == 0) {	/* it's there; copy whole thing */
1353125Sdg		/* add the old data to the new data */
1363125Sdg		bcopy(data.data, &newui, data.size);
1373125Sdg		if (newui.ui_uid != uid) {
1383125Sdg			warnx("key %d != expected record number %d",
1393125Sdg			    newui.ui_uid, uid);
1403125Sdg			warnx("inconsistent user accounting stats");
1413125Sdg			return (-1);
1423125Sdg		}
1433125Sdg	} else {		/* it's not there; zero it and copy the key */
1443125Sdg		bzero(&newui, sizeof newui);
1453125Sdg		newui.ui_uid = ci->ci_uid;
1463125Sdg	}
1473125Sdg
1483125Sdg	newui.ui_calls += ci->ci_calls;
1493125Sdg	newui.ui_utime += ci->ci_utime;
1503125Sdg	newui.ui_stime += ci->ci_stime;
1513125Sdg	newui.ui_mem += ci->ci_mem;
1523125Sdg	newui.ui_io += ci->ci_io;
1533125Sdg
1543125Sdg	data.data = &newui;
1553125Sdg	data.size = sizeof newui;
1563125Sdg	rv = DB_PUT(usracct_db, &key, &data, 0);
1573125Sdg	if (rv < 0) {
1583125Sdg		warn("add key %d to user accounting stats", uid);
1593125Sdg		return (-1);
1603125Sdg	} else if (rv != 0) {
1613125Sdg		warnx("DB_PUT returned 1");
1623125Sdg		return (-1);
1633125Sdg	}
1643125Sdg
1653125Sdg	return (0);
1663125Sdg}
1673125Sdg
1683125Sdgint
1693125Sdgusracct_update()
1703125Sdg{
1713125Sdg	DB *saved_usracct_db;
1723125Sdg	DBT key, data;
1733125Sdg	BTREEINFO bti;
1743125Sdg	u_long uid;
1753125Sdg	int error, serr, nerr;
1763125Sdg
1773125Sdg	bzero(&bti, sizeof bti);
1783125Sdg	bti.compare = uid_compare;
1793125Sdg
1803125Sdg	saved_usracct_db = dbopen(_PATH_USRACCT, O_RDWR|O_CREAT|O_TRUNC, 0644,
1813125Sdg	    DB_BTREE, &bti);
1823125Sdg	if (saved_usracct_db == NULL) {
1833125Sdg		warn("creating user accounting summary");
1843125Sdg		return (-1);
1853125Sdg	}
1863125Sdg
1873125Sdg	error = 0;
1883125Sdg
1893125Sdg	serr = DB_SEQ(usracct_db, &key, &data, R_FIRST);
1903125Sdg	if (serr < 0) {
1913125Sdg		warn("retrieving user accounting stats");
1923125Sdg		error = -1;
1933125Sdg	}
1943125Sdg	while (serr == 0) {
1953125Sdg		nerr = DB_PUT(saved_usracct_db, &key, &data, 0);
1963125Sdg		if (nerr < 0) {
1973125Sdg			warn("saving user accounting summary");
1983125Sdg			error = -1;
1993125Sdg			break;
2003125Sdg		}
2013125Sdg
2023125Sdg		serr = DB_SEQ(usracct_db, &key, &data, R_NEXT);
2033125Sdg		if (serr < 0) {
2043125Sdg			warn("retrieving user accounting stats");
2053125Sdg			error = -1;
2063125Sdg			break;
2073125Sdg		}
2083125Sdg	}
2093125Sdg
2103125Sdg	if (DB_SYNC(saved_usracct_db, 0) < 0) {
2113125Sdg		warn("syncing process accounting summary");
2123125Sdg		error = -1;
2133125Sdg	}
2143125Sdgout:
2153125Sdg	if (DB_CLOSE(saved_usracct_db) < 0) {
2163125Sdg		warn("closing process accounting summary");
2173125Sdg		error = -1;
2183125Sdg	}
2193125Sdg	return error;
2203125Sdg}
2213125Sdg
2223125Sdgvoid
2233125Sdgusracct_print()
2243125Sdg{
2253125Sdg	DBT key, data;
2263125Sdg	struct userinfo *ui;
2273125Sdg	double t;
2283125Sdg	int rv;
2293125Sdg
2303125Sdg	rv = DB_SEQ(usracct_db, &key, &data, R_FIRST);
2313125Sdg	if (rv < 0)
2323125Sdg		warn("retrieving user accounting stats");
2333125Sdg
2343125Sdg	while (rv == 0) {
2353125Sdg		ui = (struct userinfo *) data.data;
2363125Sdg
2373125Sdg		printf("%-8s %9qu ",
2383125Sdg		    user_from_uid(ui->ui_uid, 0), ui->ui_calls);
2393125Sdg
2403125Sdg		t = (double) (ui->ui_utime + ui->ui_stime) /
2413125Sdg		    (double) AHZ;
2423125Sdg		if (t < 0.0001)		/* kill divide by zero */
2433125Sdg			t = 0.0001;
2443125Sdg
2453125Sdg		printf("%12.2lf%s ", t / 60.0, "cpu");
2463125Sdg
2473125Sdg		/* ui->ui_calls is always != 0 */
2483125Sdg		if (dflag)
2493125Sdg			printf("%12qu%s", ui->ui_io / ui->ui_calls, "avio");
2503125Sdg		else
2513125Sdg			printf("%12qu%s", ui->ui_io, "tio");
2523125Sdg
2533125Sdg		/* t is always >= 0.0001; see above */
2543125Sdg		if (kflag)
2553125Sdg			printf("%12qu%s", ui->ui_mem / t, "k");
2563125Sdg		else
2573125Sdg			printf("%12qu%s", ui->ui_mem, "k*sec");
2583125Sdg
2593125Sdg		printf("\n");
2603125Sdg
2613125Sdg		rv = DB_SEQ(usracct_db, &key, &data, R_NEXT);
2623125Sdg		if (rv < 0)
2633125Sdg			warn("retrieving user accounting stats");
2643125Sdg	}
2653125Sdg}
2663125Sdg
2673125Sdgstatic int
2683125Sdguid_compare(k1, k2)
2693125Sdg	const DBT *k1, *k2;
2703125Sdg{
2713125Sdg	u_long d1, d2;
2723125Sdg
2733125Sdg	bcopy(k1->data, &d1, sizeof d1);
2743125Sdg	bcopy(k2->data, &d2, sizeof d2);
2753125Sdg
2763125Sdg	if (d1 < d2)
2773125Sdg		return -1;
2783125Sdg	else if (d1 == d2)
2793125Sdg		return 0;
2803125Sdg	else
2813125Sdg		return 1;
2823125Sdg}
283