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