pdb.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: pdb.c,v 1.1 1994/03/24 18:41:54 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 <stdio.h>
413125Sdg#include "extern.h"
423125Sdg#include "pathnames.h"
433125Sdg
443125Sdgstatic int check_junk __P((struct cmdinfo *));
453125Sdgstatic void add_ci __P((const struct cmdinfo *, struct cmdinfo *));
463125Sdgstatic void print_ci __P((const struct cmdinfo *, const struct cmdinfo *));
473125Sdg
483125Sdgstatic DB	*pacct_db;
493125Sdg
503125Sdgint
513125Sdgpacct_init()
523125Sdg{
533125Sdg	DB *saved_pacct_db;
543125Sdg	int error;
553125Sdg
563125Sdg	pacct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL);
573125Sdg	if (pacct_db == NULL)
583125Sdg		return (-1);
593125Sdg
603125Sdg	error = 0;
613125Sdg	if (!iflag) {
623125Sdg		DBT key, data;
633125Sdg		int serr, nerr;
643125Sdg
653125Sdg		saved_pacct_db = dbopen(_PATH_SAVACCT, O_RDONLY, 0, DB_BTREE,
663125Sdg		    NULL);
673125Sdg		if (saved_pacct_db == NULL) {
683125Sdg			error = errno == ENOENT ? 0 : -1;
693125Sdg			if (error)
703125Sdg				warn("retrieving process accounting summary");
713125Sdg			goto out;
723125Sdg		}
733125Sdg
743125Sdg		serr = DB_SEQ(saved_pacct_db, &key, &data, R_FIRST);
753125Sdg		if (serr < 0) {
763125Sdg			warn("retrieving process accounting summary");
773125Sdg			error = -1;
783125Sdg			goto closeout;
793125Sdg		}
803125Sdg		while (serr == 0) {
813125Sdg			nerr = DB_PUT(pacct_db, &key, &data, 0);
823125Sdg			if (nerr < 0) {
833125Sdg				warn("initializing process accounting stats");
843125Sdg				error = -1;
853125Sdg				break;
863125Sdg			}
873125Sdg
883125Sdg			serr = DB_SEQ(saved_pacct_db, &key, &data, R_NEXT);
893125Sdg			if (serr < 0) {
903125Sdg				warn("retrieving process accounting summary");
913125Sdg				error = -1;
923125Sdg				break;
933125Sdg			}
943125Sdg		}
953125Sdg
963125Sdgcloseout:	if (DB_CLOSE(saved_pacct_db) < 0) {
973125Sdg			warn("closing process accounting summary");
983125Sdg			error = -1;
993125Sdg		}
1003125Sdg	}
1013125Sdg
1023125Sdgout:	if (error != 0)
1033125Sdg		pacct_destroy();
1043125Sdg	return (error);
1053125Sdg}
1063125Sdg
1073125Sdgvoid
1083125Sdgpacct_destroy()
1093125Sdg{
1103125Sdg	if (DB_CLOSE(pacct_db) < 0)
1113125Sdg		warn("destroying process accounting stats");
1123125Sdg}
1133125Sdg
1143125Sdgint
1153125Sdgpacct_add(ci)
1163125Sdg	const struct cmdinfo *ci;
1173125Sdg{
1183125Sdg	DBT key, data;
1193125Sdg	struct cmdinfo newci;
1203125Sdg	char keydata[sizeof ci->ci_comm];
1213125Sdg	int rv;
1223125Sdg
1233125Sdg	bcopy(ci->ci_comm, &keydata, sizeof keydata);
1243125Sdg	key.data = &keydata;
1253125Sdg	key.size = strlen(keydata);
1263125Sdg
1273125Sdg	rv = DB_GET(pacct_db, &key, &data, 0);
1283125Sdg	if (rv < 0) {
1293125Sdg		warn("get key %s from process accounting stats", ci->ci_comm);
1303125Sdg		return (-1);
1313125Sdg	} else if (rv == 0) {	/* it's there; copy whole thing */
1323125Sdg		/* XXX compare size if paranoid */
1333125Sdg		/* add the old data to the new data */
1343125Sdg		bcopy(data.data, &newci, data.size);
1353125Sdg	} else {		/* it's not there; zero it and copy the key */
1363125Sdg		bzero(&newci, sizeof newci);
1373125Sdg		bcopy(key.data, newci.ci_comm, key.size);
1383125Sdg	}
1393125Sdg
1403125Sdg	add_ci(ci, &newci);
1413125Sdg
1423125Sdg	data.data = &newci;
1433125Sdg	data.size = sizeof newci;
1443125Sdg	rv = DB_PUT(pacct_db, &key, &data, 0);
1453125Sdg	if (rv < 0) {
1463125Sdg		warn("add key %s to process accounting stats", ci->ci_comm);
1473125Sdg		return (-1);
1483125Sdg	} else if (rv == 1) {
1493125Sdg		warnx("duplicate key %s in process accounting stats",
1503125Sdg		    ci->ci_comm);
1513125Sdg		return (-1);
1523125Sdg	}
1533125Sdg
1543125Sdg	return (0);
1553125Sdg}
1563125Sdg
1573125Sdgint
1583125Sdgpacct_update()
1593125Sdg{
1603125Sdg	DB *saved_pacct_db;
1613125Sdg	DBT key, data;
1623125Sdg	int error, serr, nerr;
1633125Sdg
1643125Sdg	saved_pacct_db = dbopen(_PATH_SAVACCT, O_RDWR|O_CREAT|O_TRUNC, 0644,
1653125Sdg	    DB_BTREE, NULL);
1663125Sdg	if (saved_pacct_db == NULL) {
1673125Sdg		warn("creating process accounting summary");
1683125Sdg		return (-1);
1693125Sdg	}
1703125Sdg
1713125Sdg	error = 0;
1723125Sdg
1733125Sdg	serr = DB_SEQ(pacct_db, &key, &data, R_FIRST);
1743125Sdg	if (serr < 0) {
1753125Sdg		warn("retrieving process accounting stats");
1763125Sdg		error = -1;
1773125Sdg	}
1783125Sdg	while (serr == 0) {
1793125Sdg		nerr = DB_PUT(saved_pacct_db, &key, &data, 0);
1803125Sdg		if (nerr < 0) {
1813125Sdg			warn("saving process accounting summary");
1823125Sdg			error = -1;
1833125Sdg			break;
1843125Sdg		}
1853125Sdg
1863125Sdg		serr = DB_SEQ(pacct_db, &key, &data, R_NEXT);
1873125Sdg		if (serr < 0) {
1883125Sdg			warn("retrieving process accounting stats");
1893125Sdg			error = -1;
1903125Sdg			break;
1913125Sdg		}
1923125Sdg	}
1933125Sdg
1943125Sdg	if (DB_SYNC(saved_pacct_db, 0) < 0) {
1953125Sdg		warn("syncing process accounting summary");
1963125Sdg		error = -1;
1973125Sdg	}
1983125Sdg	if (DB_CLOSE(saved_pacct_db) < 0) {
1993125Sdg		warn("closing process accounting summary");
2003125Sdg		error = -1;
2013125Sdg	}
2023125Sdg	return error;
2033125Sdg}
2043125Sdg
2053125Sdgvoid
2063125Sdgpacct_print()
2073125Sdg{
2083125Sdg	BTREEINFO bti;
2093125Sdg	DBT key, data, ndata;
2103125Sdg	DB *output_pacct_db;
2113125Sdg	struct cmdinfo *cip, ci, ci_total, ci_other, ci_junk;
2123125Sdg	int rv;
2133125Sdg
2143125Sdg	bzero(&ci_total, sizeof ci_total);
2153125Sdg	strcpy(ci_total.ci_comm, "");
2163125Sdg	bzero(&ci_other, sizeof ci_other);
2173125Sdg	strcpy(ci_other.ci_comm, "***other");
2183125Sdg	bzero(&ci_junk, sizeof ci_junk);
2193125Sdg	strcpy(ci_junk.ci_comm, "**junk**");
2203125Sdg
2213125Sdg	/*
2223125Sdg	 * Retrieve them into new DB, sorted by appropriate key.
2233125Sdg	 * At the same time, cull 'other' and 'junk'
2243125Sdg	 */
2253125Sdg	bzero(&bti, sizeof bti);
2263125Sdg	bti.compare = sa_cmp;
2273125Sdg	output_pacct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti);
2283125Sdg	if (output_pacct_db == NULL) {
2293125Sdg		warn("couldn't sort process accounting stats");
2303125Sdg		return;
2313125Sdg	}
2323125Sdg
2333125Sdg	ndata.data = NULL;
2343125Sdg	ndata.size = 0;
2353125Sdg	rv = DB_SEQ(pacct_db, &key, &data, R_FIRST);
2363125Sdg	if (rv < 0)
2373125Sdg		warn("retrieving process accounting stats");
2383125Sdg	while (rv == 0) {
2393125Sdg		cip = (struct cmdinfo *) data.data;
2403125Sdg		bcopy(cip, &ci, sizeof ci);
2413125Sdg
2423125Sdg		/* add to total */
2433125Sdg		add_ci(&ci, &ci_total);
2443125Sdg
2453125Sdg		if (vflag && ci.ci_calls <= cutoff &&
2463125Sdg		    (fflag || check_junk(&ci))) {
2473125Sdg			/* put it into **junk** */
2483125Sdg			add_ci(&ci, &ci_junk);
2493125Sdg			goto next;
2503125Sdg		}
2513125Sdg		if (!aflag &&
2523125Sdg		    ((ci.ci_flags & CI_UNPRINTABLE) != 0 || ci.ci_calls <= 1)) {
2533125Sdg			/* put into ***other */
2543125Sdg			add_ci(&ci, &ci_other);
2553125Sdg			goto next;
2563125Sdg		}
2573125Sdg		rv = DB_PUT(output_pacct_db, &data, &ndata, 0);
2583125Sdg		if (rv < 0)
2593125Sdg			warn("sorting process accounting stats");
2603125Sdg
2613125Sdgnext:		rv = DB_SEQ(pacct_db, &key, &data, R_NEXT);
2623125Sdg		if (rv < 0)
2633125Sdg			warn("retrieving process accounting stats");
2643125Sdg	}
2653125Sdg
2663125Sdg	/* insert **junk** and ***other */
2673125Sdg	if (ci_junk.ci_calls != 0) {
2683125Sdg		data.data = &ci_junk;
2693125Sdg		data.size = sizeof ci_junk;
2703125Sdg		rv = DB_PUT(output_pacct_db, &data, &ndata, 0);
2713125Sdg		if (rv < 0)
2723125Sdg			warn("sorting process accounting stats");
2733125Sdg	}
2743125Sdg	if (ci_other.ci_calls != 0) {
2753125Sdg		data.data = &ci_other;
2763125Sdg		data.size = sizeof ci_other;
2773125Sdg		rv = DB_PUT(output_pacct_db, &data, &ndata, 0);
2783125Sdg		if (rv < 0)
2793125Sdg			warn("sorting process accounting stats");
2803125Sdg	}
2813125Sdg
2823125Sdg	/* print out the total */
2833125Sdg	print_ci(&ci_total, &ci_total);
2843125Sdg
2853125Sdg	/* print out; if reversed, print first (smallest) first */
2863125Sdg	rv = DB_SEQ(output_pacct_db, &data, &ndata, rflag ? R_FIRST : R_LAST);
2873125Sdg	if (rv < 0)
2883125Sdg		warn("retrieving process accounting report");
2893125Sdg	while (rv == 0) {
2903125Sdg		cip = (struct cmdinfo *) data.data;
2913125Sdg		bcopy(cip, &ci, sizeof ci);
2923125Sdg
2933125Sdg		print_ci(&ci, &ci_total);
2943125Sdg
2953125Sdg		rv = DB_SEQ(output_pacct_db, &data, &ndata,
2963125Sdg		    rflag ? R_NEXT : R_PREV);
2973125Sdg		if (rv < 0)
2983125Sdg			warn("retrieving process accounting report");
2993125Sdg	}
3003125Sdg	DB_CLOSE(output_pacct_db);
3013125Sdg}
3023125Sdg
3033125Sdgstatic int
3043125Sdgcheck_junk(cip)
3053125Sdg	struct cmdinfo *cip;
3063125Sdg{
3073125Sdg	char *cp;
3083125Sdg	size_t len;
3093125Sdg
3103125Sdg	fprintf(stderr, "%s (%qu) -- ", cip->ci_comm, cip->ci_calls);
3113125Sdg	cp = fgetln(stdin, &len);
3123125Sdg
3133125Sdg	return (cp && (cp[0] == 'y' || cp[0] == 'Y')) ? 1 : 0;
3143125Sdg}
3153125Sdg
3163125Sdgstatic void
3173125Sdgadd_ci(fromcip, tocip)
3183125Sdg	const struct cmdinfo *fromcip;
3193125Sdg	struct cmdinfo *tocip;
3203125Sdg{
3213125Sdg	tocip->ci_calls += fromcip->ci_calls;
3223125Sdg	tocip->ci_etime += fromcip->ci_etime;
3233125Sdg	tocip->ci_utime += fromcip->ci_utime;
3243125Sdg	tocip->ci_stime += fromcip->ci_stime;
3253125Sdg	tocip->ci_mem += fromcip->ci_mem;
3263125Sdg	tocip->ci_io += fromcip->ci_io;
3273125Sdg}
3283125Sdg
3293125Sdgstatic void
3303125Sdgprint_ci(cip, totalcip)
3313125Sdg	const struct cmdinfo *cip, *totalcip;
3323125Sdg{
3333125Sdg	double t, c;
3343125Sdg	int uflow;
3353125Sdg
3363125Sdg	c = cip->ci_calls ? cip->ci_calls : 1;
3373125Sdg	t = (cip->ci_utime + cip->ci_stime) / (double) AHZ;
3383125Sdg	if (t < 0.01) {
3393125Sdg		t = 0.01;
3403125Sdg		uflow = 1;
3413125Sdg	} else
3423125Sdg		uflow = 0;
3433125Sdg
3443125Sdg	printf("%8qu ", cip->ci_calls);
3453125Sdg	if (cflag) {
3463125Sdg		if (cip != totalcip)
3473125Sdg			printf(" %4.2f%%  ",
3483125Sdg			    cip->ci_calls / (double) totalcip->ci_calls);
3493125Sdg		else
3503125Sdg			printf(" %4s   ", "");
3513125Sdg	}
3523125Sdg
3533125Sdg	if (jflag)
3543125Sdg		printf("%11.2fre ", cip->ci_etime / (double) (AHZ * c));
3553125Sdg	else
3563125Sdg		printf("%11.2fre ", cip->ci_etime / (60.0 * AHZ));
3573125Sdg	if (cflag) {
3583125Sdg		if (cip != totalcip)
3593125Sdg			printf(" %4.2f%%  ",
3603125Sdg			    cip->ci_etime / (double) totalcip->ci_etime);
3613125Sdg		else
3623125Sdg			printf(" %4s   ", "");
3633125Sdg	}
3643125Sdg
3653125Sdg	if (!lflag) {
3663125Sdg		if (jflag)
3673125Sdg			printf("%11.2fcp ", t / (double) cip->ci_calls);
3683125Sdg		else
3693125Sdg			printf("%11.2fcp ", t / 60.0);
3703125Sdg		if (cflag) {
3713125Sdg			if (cip != totalcip)
3723125Sdg				printf(" %4.2f%%  ",
3733125Sdg				    (cip->ci_utime + cip->ci_stime) / (double)
3743125Sdg				    (totalcip->ci_utime + totalcip->ci_stime));
3753125Sdg			else
3763125Sdg				printf(" %4s   ", "");
3773125Sdg		}
3783125Sdg	} else {
3793125Sdg		if (jflag)
3803125Sdg			printf("%11.2fu ", cip->ci_utime / (double) (AHZ * c));
3813125Sdg		else
3823125Sdg			printf("%11.2fu ", cip->ci_utime / (60.0 * AHZ));
3833125Sdg		if (cflag) {
3843125Sdg			if (cip != totalcip)
3853125Sdg				printf(" %4.2f%%  ", cip->ci_utime / (double) totalcip->ci_utime);
3863125Sdg			else
3873125Sdg				printf(" %4s   ", "");
3883125Sdg		}
3893125Sdg		if (jflag)
3903125Sdg			printf("%11.2fs ", cip->ci_stime / (double) (AHZ * c));
3913125Sdg		else
3923125Sdg			printf("%11.2fs ", cip->ci_stime / (60.0 * AHZ));
3933125Sdg		if (cflag) {
3943125Sdg			if (cip != totalcip)
3953125Sdg				printf(" %4.2f%%  ", cip->ci_stime / (double) totalcip->ci_stime);
3963125Sdg			else
3973125Sdg				printf(" %4s   ", "");
3983125Sdg		}
3993125Sdg	}
4003125Sdg
4013125Sdg	if (tflag)
4023125Sdg		if (!uflow)
4033125Sdg			printf("%8.2fre/cp ", cip->ci_etime / (double) (cip->ci_utime + cip->ci_stime));
4043125Sdg		else
4053125Sdg			printf("%8 ", "*ignore*");
4063125Sdg
4073125Sdg	if (Dflag)
4083125Sdg		printf("%10qutio ", cip->ci_io);
4093125Sdg	else
4103125Sdg		printf("%8.0favio ", cip->ci_io / c);
4113125Sdg
4123125Sdg	if (Kflag)
4133125Sdg		printf("%10quk*sec ", cip->ci_mem);
4143125Sdg	else
4153125Sdg		printf("%8.0fk ", cip->ci_mem / t);
4163125Sdg
4173125Sdg	printf("  %s\n", cip->ci_comm);
4183125Sdg}
419