pdb.c revision 3125
11592Srgrimes/*
21592Srgrimes * Copyright (c) 1994 Christopher G. Demetriou
31592Srgrimes * All rights reserved.
41592Srgrimes *
51592Srgrimes * Redistribution and use in source and binary forms, with or without
61592Srgrimes * modification, are permitted provided that the following conditions
71592Srgrimes * are met:
81592Srgrimes * 1. Redistributions of source code must retain the above copyright
91592Srgrimes *    notice, this list of conditions and the following disclaimer.
101592Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111592Srgrimes *    notice, this list of conditions and the following disclaimer in the
121592Srgrimes *    documentation and/or other materials provided with the distribution.
131592Srgrimes * 3. All advertising materials mentioning features or use of this software
141592Srgrimes *    must display the following acknowledgement:
151592Srgrimes *      This product includes software developed by Christopher G. Demetriou.
161592Srgrimes * 4. The name of the author may not be used to endorse or promote products
171592Srgrimes *    derived from this software without specific prior written permission
181592Srgrimes *
191592Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
201592Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
211592Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
221592Srgrimes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
231592Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
241592Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
251592Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
261592Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
271592Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
281592Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
291592Srgrimes */
301592Srgrimes
311592Srgrimes#ifndef LINT
321592Srgrimesstatic char rcsid[] = "$Id: pdb.c,v 1.1 1994/03/24 18:41:54 cgd Exp $";
331592Srgrimes#endif
341592Srgrimes
351592Srgrimes#include <sys/types.h>
361592Srgrimes#include <sys/acct.h>
371592Srgrimes#include <err.h>
381592Srgrimes#include <errno.h>
391592Srgrimes#include <fcntl.h>
401592Srgrimes#include <stdio.h>
411592Srgrimes#include "extern.h"
421592Srgrimes#include "pathnames.h"
431592Srgrimes
441592Srgrimesstatic int check_junk __P((struct cmdinfo *));
451592Srgrimesstatic void add_ci __P((const struct cmdinfo *, struct cmdinfo *));
461592Srgrimesstatic void print_ci __P((const struct cmdinfo *, const struct cmdinfo *));
471592Srgrimes
481592Srgrimesstatic DB	*pacct_db;
491592Srgrimes
501592Srgrimesint
511592Srgrimespacct_init()
521592Srgrimes{
531592Srgrimes	DB *saved_pacct_db;
541592Srgrimes	int error;
551592Srgrimes
561592Srgrimes	pacct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL);
571592Srgrimes	if (pacct_db == NULL)
581592Srgrimes		return (-1);
591592Srgrimes
601592Srgrimes	error = 0;
611592Srgrimes	if (!iflag) {
621592Srgrimes		DBT key, data;
631592Srgrimes		int serr, nerr;
641592Srgrimes
651592Srgrimes		saved_pacct_db = dbopen(_PATH_SAVACCT, O_RDONLY, 0, DB_BTREE,
661592Srgrimes		    NULL);
671592Srgrimes		if (saved_pacct_db == NULL) {
681592Srgrimes			error = errno == ENOENT ? 0 : -1;
691592Srgrimes			if (error)
701592Srgrimes				warn("retrieving process accounting summary");
711592Srgrimes			goto out;
721592Srgrimes		}
731592Srgrimes
741592Srgrimes		serr = DB_SEQ(saved_pacct_db, &key, &data, R_FIRST);
751592Srgrimes		if (serr < 0) {
761592Srgrimes			warn("retrieving process accounting summary");
771592Srgrimes			error = -1;
781592Srgrimes			goto closeout;
791592Srgrimes		}
801592Srgrimes		while (serr == 0) {
811592Srgrimes			nerr = DB_PUT(pacct_db, &key, &data, 0);
821592Srgrimes			if (nerr < 0) {
831592Srgrimes				warn("initializing process accounting stats");
841592Srgrimes				error = -1;
851592Srgrimes				break;
861592Srgrimes			}
871592Srgrimes
881592Srgrimes			serr = DB_SEQ(saved_pacct_db, &key, &data, R_NEXT);
891592Srgrimes			if (serr < 0) {
901592Srgrimes				warn("retrieving process accounting summary");
911592Srgrimes				error = -1;
921592Srgrimes				break;
931592Srgrimes			}
941592Srgrimes		}
951592Srgrimes
961592Srgrimescloseout:	if (DB_CLOSE(saved_pacct_db) < 0) {
971592Srgrimes			warn("closing process accounting summary");
981592Srgrimes			error = -1;
991592Srgrimes		}
1001592Srgrimes	}
1011592Srgrimes
1021592Srgrimesout:	if (error != 0)
1031592Srgrimes		pacct_destroy();
1041592Srgrimes	return (error);
1051592Srgrimes}
1061592Srgrimes
1071592Srgrimesvoid
1081592Srgrimespacct_destroy()
1091592Srgrimes{
1101592Srgrimes	if (DB_CLOSE(pacct_db) < 0)
1111592Srgrimes		warn("destroying process accounting stats");
1121592Srgrimes}
1131592Srgrimes
1141592Srgrimesint
1151592Srgrimespacct_add(ci)
1161592Srgrimes	const struct cmdinfo *ci;
1171592Srgrimes{
1181592Srgrimes	DBT key, data;
1191592Srgrimes	struct cmdinfo newci;
1201592Srgrimes	char keydata[sizeof ci->ci_comm];
1211592Srgrimes	int rv;
1221592Srgrimes
1231592Srgrimes	bcopy(ci->ci_comm, &keydata, sizeof keydata);
1241592Srgrimes	key.data = &keydata;
1251592Srgrimes	key.size = strlen(keydata);
1261592Srgrimes
1271592Srgrimes	rv = DB_GET(pacct_db, &key, &data, 0);
1281592Srgrimes	if (rv < 0) {
1291592Srgrimes		warn("get key %s from process accounting stats", ci->ci_comm);
1301592Srgrimes		return (-1);
1311592Srgrimes	} else if (rv == 0) {	/* it's there; copy whole thing */
1321592Srgrimes		/* XXX compare size if paranoid */
1331592Srgrimes		/* add the old data to the new data */
1341592Srgrimes		bcopy(data.data, &newci, data.size);
1351592Srgrimes	} else {		/* it's not there; zero it and copy the key */
1361592Srgrimes		bzero(&newci, sizeof newci);
1371592Srgrimes		bcopy(key.data, newci.ci_comm, key.size);
1381592Srgrimes	}
1391592Srgrimes
1401592Srgrimes	add_ci(ci, &newci);
1411592Srgrimes
1421592Srgrimes	data.data = &newci;
1431592Srgrimes	data.size = sizeof newci;
1441592Srgrimes	rv = DB_PUT(pacct_db, &key, &data, 0);
1451592Srgrimes	if (rv < 0) {
1461592Srgrimes		warn("add key %s to process accounting stats", ci->ci_comm);
1471592Srgrimes		return (-1);
1481592Srgrimes	} else if (rv == 1) {
1491592Srgrimes		warnx("duplicate key %s in process accounting stats",
1501592Srgrimes		    ci->ci_comm);
1511592Srgrimes		return (-1);
1521592Srgrimes	}
1531592Srgrimes
1541592Srgrimes	return (0);
1551592Srgrimes}
1561592Srgrimes
1571592Srgrimesint
1581592Srgrimespacct_update()
1591592Srgrimes{
1601592Srgrimes	DB *saved_pacct_db;
1611592Srgrimes	DBT key, data;
1621592Srgrimes	int error, serr, nerr;
1631592Srgrimes
1641592Srgrimes	saved_pacct_db = dbopen(_PATH_SAVACCT, O_RDWR|O_CREAT|O_TRUNC, 0644,
1651592Srgrimes	    DB_BTREE, NULL);
1661592Srgrimes	if (saved_pacct_db == NULL) {
1671592Srgrimes		warn("creating process accounting summary");
1681592Srgrimes		return (-1);
1691592Srgrimes	}
1701592Srgrimes
1711592Srgrimes	error = 0;
1721592Srgrimes
1731592Srgrimes	serr = DB_SEQ(pacct_db, &key, &data, R_FIRST);
1741592Srgrimes	if (serr < 0) {
1751592Srgrimes		warn("retrieving process accounting stats");
1761592Srgrimes		error = -1;
1771592Srgrimes	}
1781592Srgrimes	while (serr == 0) {
1791592Srgrimes		nerr = DB_PUT(saved_pacct_db, &key, &data, 0);
1801592Srgrimes		if (nerr < 0) {
1811592Srgrimes			warn("saving process accounting summary");
1821592Srgrimes			error = -1;
1831592Srgrimes			break;
1841592Srgrimes		}
1851592Srgrimes
1861592Srgrimes		serr = DB_SEQ(pacct_db, &key, &data, R_NEXT);
1871592Srgrimes		if (serr < 0) {
1881592Srgrimes			warn("retrieving process accounting stats");
1891592Srgrimes			error = -1;
1901592Srgrimes			break;
1911592Srgrimes		}
1921592Srgrimes	}
1931592Srgrimes
1941592Srgrimes	if (DB_SYNC(saved_pacct_db, 0) < 0) {
1951592Srgrimes		warn("syncing process accounting summary");
1961592Srgrimes		error = -1;
1971592Srgrimes	}
1981592Srgrimes	if (DB_CLOSE(saved_pacct_db) < 0) {
1991592Srgrimes		warn("closing process accounting summary");
2001592Srgrimes		error = -1;
2011592Srgrimes	}
2021592Srgrimes	return error;
2031592Srgrimes}
2041592Srgrimes
2051592Srgrimesvoid
2061592Srgrimespacct_print()
2071592Srgrimes{
2081592Srgrimes	BTREEINFO bti;
2091592Srgrimes	DBT key, data, ndata;
2101592Srgrimes	DB *output_pacct_db;
2111592Srgrimes	struct cmdinfo *cip, ci, ci_total, ci_other, ci_junk;
2121592Srgrimes	int rv;
2131592Srgrimes
2141592Srgrimes	bzero(&ci_total, sizeof ci_total);
2151592Srgrimes	strcpy(ci_total.ci_comm, "");
2161592Srgrimes	bzero(&ci_other, sizeof ci_other);
2171592Srgrimes	strcpy(ci_other.ci_comm, "***other");
2181592Srgrimes	bzero(&ci_junk, sizeof ci_junk);
2191592Srgrimes	strcpy(ci_junk.ci_comm, "**junk**");
2201592Srgrimes
2211592Srgrimes	/*
2221592Srgrimes	 * Retrieve them into new DB, sorted by appropriate key.
2231592Srgrimes	 * At the same time, cull 'other' and 'junk'
2241592Srgrimes	 */
2251592Srgrimes	bzero(&bti, sizeof bti);
2261592Srgrimes	bti.compare = sa_cmp;
2271592Srgrimes	output_pacct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti);
2281592Srgrimes	if (output_pacct_db == NULL) {
2291592Srgrimes		warn("couldn't sort process accounting stats");
2301592Srgrimes		return;
2311592Srgrimes	}
2321592Srgrimes
2331592Srgrimes	ndata.data = NULL;
2341592Srgrimes	ndata.size = 0;
2351592Srgrimes	rv = DB_SEQ(pacct_db, &key, &data, R_FIRST);
2361592Srgrimes	if (rv < 0)
2371592Srgrimes		warn("retrieving process accounting stats");
2381592Srgrimes	while (rv == 0) {
2391592Srgrimes		cip = (struct cmdinfo *) data.data;
2401592Srgrimes		bcopy(cip, &ci, sizeof ci);
2411592Srgrimes
2421592Srgrimes		/* add to total */
2431592Srgrimes		add_ci(&ci, &ci_total);
2441592Srgrimes
2451592Srgrimes		if (vflag && ci.ci_calls <= cutoff &&
2461592Srgrimes		    (fflag || check_junk(&ci))) {
2471592Srgrimes			/* put it into **junk** */
2481592Srgrimes			add_ci(&ci, &ci_junk);
2491592Srgrimes			goto next;
2501592Srgrimes		}
2511592Srgrimes		if (!aflag &&
2521592Srgrimes		    ((ci.ci_flags & CI_UNPRINTABLE) != 0 || ci.ci_calls <= 1)) {
2531592Srgrimes			/* put into ***other */
2541592Srgrimes			add_ci(&ci, &ci_other);
2551592Srgrimes			goto next;
2561592Srgrimes		}
2571592Srgrimes		rv = DB_PUT(output_pacct_db, &data, &ndata, 0);
2581592Srgrimes		if (rv < 0)
2591592Srgrimes			warn("sorting process accounting stats");
2601592Srgrimes
2611592Srgrimesnext:		rv = DB_SEQ(pacct_db, &key, &data, R_NEXT);
2621592Srgrimes		if (rv < 0)
2631592Srgrimes			warn("retrieving process accounting stats");
2641592Srgrimes	}
2651592Srgrimes
2661592Srgrimes	/* insert **junk** and ***other */
2671592Srgrimes	if (ci_junk.ci_calls != 0) {
2681592Srgrimes		data.data = &ci_junk;
2691592Srgrimes		data.size = sizeof ci_junk;
2701592Srgrimes		rv = DB_PUT(output_pacct_db, &data, &ndata, 0);
2711592Srgrimes		if (rv < 0)
2721592Srgrimes			warn("sorting process accounting stats");
2731592Srgrimes	}
2741592Srgrimes	if (ci_other.ci_calls != 0) {
2751592Srgrimes		data.data = &ci_other;
2761592Srgrimes		data.size = sizeof ci_other;
2771592Srgrimes		rv = DB_PUT(output_pacct_db, &data, &ndata, 0);
2781592Srgrimes		if (rv < 0)
2791592Srgrimes			warn("sorting process accounting stats");
2801592Srgrimes	}
2811592Srgrimes
2821592Srgrimes	/* print out the total */
2831592Srgrimes	print_ci(&ci_total, &ci_total);
2841592Srgrimes
2851592Srgrimes	/* print out; if reversed, print first (smallest) first */
2861592Srgrimes	rv = DB_SEQ(output_pacct_db, &data, &ndata, rflag ? R_FIRST : R_LAST);
2871592Srgrimes	if (rv < 0)
2881592Srgrimes		warn("retrieving process accounting report");
2891592Srgrimes	while (rv == 0) {
2901592Srgrimes		cip = (struct cmdinfo *) data.data;
2911592Srgrimes		bcopy(cip, &ci, sizeof ci);
2921592Srgrimes
2931592Srgrimes		print_ci(&ci, &ci_total);
2941592Srgrimes
2951592Srgrimes		rv = DB_SEQ(output_pacct_db, &data, &ndata,
2961592Srgrimes		    rflag ? R_NEXT : R_PREV);
2971592Srgrimes		if (rv < 0)
2981592Srgrimes			warn("retrieving process accounting report");
2991592Srgrimes	}
3001592Srgrimes	DB_CLOSE(output_pacct_db);
3011592Srgrimes}
3021592Srgrimes
3031592Srgrimesstatic int
3041592Srgrimescheck_junk(cip)
3051592Srgrimes	struct cmdinfo *cip;
3061592Srgrimes{
3071592Srgrimes	char *cp;
3081592Srgrimes	size_t len;
3091592Srgrimes
3101592Srgrimes	fprintf(stderr, "%s (%qu) -- ", cip->ci_comm, cip->ci_calls);
3111592Srgrimes	cp = fgetln(stdin, &len);
3121592Srgrimes
3131592Srgrimes	return (cp && (cp[0] == 'y' || cp[0] == 'Y')) ? 1 : 0;
3141592Srgrimes}
3151592Srgrimes
3161592Srgrimesstatic void
3171592Srgrimesadd_ci(fromcip, tocip)
3181592Srgrimes	const struct cmdinfo *fromcip;
3191592Srgrimes	struct cmdinfo *tocip;
3201592Srgrimes{
3211592Srgrimes	tocip->ci_calls += fromcip->ci_calls;
3221592Srgrimes	tocip->ci_etime += fromcip->ci_etime;
3231592Srgrimes	tocip->ci_utime += fromcip->ci_utime;
3241592Srgrimes	tocip->ci_stime += fromcip->ci_stime;
3251592Srgrimes	tocip->ci_mem += fromcip->ci_mem;
3261592Srgrimes	tocip->ci_io += fromcip->ci_io;
3271592Srgrimes}
3281592Srgrimes
3291592Srgrimesstatic void
3301592Srgrimesprint_ci(cip, totalcip)
3311592Srgrimes	const struct cmdinfo *cip, *totalcip;
3321592Srgrimes{
3331592Srgrimes	double t, c;
3341592Srgrimes	int uflow;
3351592Srgrimes
3361592Srgrimes	c = cip->ci_calls ? cip->ci_calls : 1;
3371592Srgrimes	t = (cip->ci_utime + cip->ci_stime) / (double) AHZ;
3381592Srgrimes	if (t < 0.01) {
3391592Srgrimes		t = 0.01;
3401592Srgrimes		uflow = 1;
3411592Srgrimes	} else
3421592Srgrimes		uflow = 0;
3431592Srgrimes
3441592Srgrimes	printf("%8qu ", cip->ci_calls);
3451592Srgrimes	if (cflag) {
3461592Srgrimes		if (cip != totalcip)
3471592Srgrimes			printf(" %4.2f%%  ",
3481592Srgrimes			    cip->ci_calls / (double) totalcip->ci_calls);
3491592Srgrimes		else
3501592Srgrimes			printf(" %4s   ", "");
3511592Srgrimes	}
3521592Srgrimes
3531592Srgrimes	if (jflag)
3541592Srgrimes		printf("%11.2fre ", cip->ci_etime / (double) (AHZ * c));
3551592Srgrimes	else
3561592Srgrimes		printf("%11.2fre ", cip->ci_etime / (60.0 * AHZ));
3571592Srgrimes	if (cflag) {
3581592Srgrimes		if (cip != totalcip)
3591592Srgrimes			printf(" %4.2f%%  ",
3601592Srgrimes			    cip->ci_etime / (double) totalcip->ci_etime);
3611592Srgrimes		else
3621592Srgrimes			printf(" %4s   ", "");
3631592Srgrimes	}
3641592Srgrimes
3651592Srgrimes	if (!lflag) {
3661592Srgrimes		if (jflag)
3671592Srgrimes			printf("%11.2fcp ", t / (double) cip->ci_calls);
3681592Srgrimes		else
3691592Srgrimes			printf("%11.2fcp ", t / 60.0);
3701592Srgrimes		if (cflag) {
3711592Srgrimes			if (cip != totalcip)
3721592Srgrimes				printf(" %4.2f%%  ",
3731592Srgrimes				    (cip->ci_utime + cip->ci_stime) / (double)
3741592Srgrimes				    (totalcip->ci_utime + totalcip->ci_stime));
3751592Srgrimes			else
3761592Srgrimes				printf(" %4s   ", "");
3771592Srgrimes		}
3781592Srgrimes	} else {
3791592Srgrimes		if (jflag)
3801592Srgrimes			printf("%11.2fu ", cip->ci_utime / (double) (AHZ * c));
3811592Srgrimes		else
3821592Srgrimes			printf("%11.2fu ", cip->ci_utime / (60.0 * AHZ));
3831592Srgrimes		if (cflag) {
3841592Srgrimes			if (cip != totalcip)
3851592Srgrimes				printf(" %4.2f%%  ", cip->ci_utime / (double) totalcip->ci_utime);
3861592Srgrimes			else
3871592Srgrimes				printf(" %4s   ", "");
3881592Srgrimes		}
3891592Srgrimes		if (jflag)
3901592Srgrimes			printf("%11.2fs ", cip->ci_stime / (double) (AHZ * c));
3911592Srgrimes		else
3921592Srgrimes			printf("%11.2fs ", cip->ci_stime / (60.0 * AHZ));
3931592Srgrimes		if (cflag) {
3941592Srgrimes			if (cip != totalcip)
3951592Srgrimes				printf(" %4.2f%%  ", cip->ci_stime / (double) totalcip->ci_stime);
3961592Srgrimes			else
3971592Srgrimes				printf(" %4s   ", "");
3981592Srgrimes		}
3991592Srgrimes	}
4001592Srgrimes
4011592Srgrimes	if (tflag)
4021592Srgrimes		if (!uflow)
4031592Srgrimes			printf("%8.2fre/cp ", cip->ci_etime / (double) (cip->ci_utime + cip->ci_stime));
4041592Srgrimes		else
4051592Srgrimes			printf("%8 ", "*ignore*");
4061592Srgrimes
4071592Srgrimes	if (Dflag)
4081592Srgrimes		printf("%10qutio ", cip->ci_io);
4091592Srgrimes	else
4101592Srgrimes		printf("%8.0favio ", cip->ci_io / c);
4111592Srgrimes
4121592Srgrimes	if (Kflag)
4131592Srgrimes		printf("%10quk*sec ", cip->ci_mem);
4141592Srgrimes	else
4151592Srgrimes		printf("%8.0fk ", cip->ci_mem / t);
4161592Srgrimes
4171592Srgrimes	printf("  %s\n", cip->ci_comm);
4181592Srgrimes}
4191592Srgrimes