xref: /onnv-gate/usr/src/cmd/acct/acctcom.c (revision 428:a261479c3dbd)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
280Sstevel@tonic-gate /*	  All Rights Reserved  	*/
290Sstevel@tonic-gate 
300Sstevel@tonic-gate 
31*428Ssl108498 #pragma ident	"%Z%%M%	%I%	%E% SMI"
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include <time.h>
340Sstevel@tonic-gate #include <string.h>
350Sstevel@tonic-gate #include <stdio.h>
360Sstevel@tonic-gate #include <sys/types.h>
370Sstevel@tonic-gate #include <sys/param.h>
380Sstevel@tonic-gate #include "acctdef.h"
390Sstevel@tonic-gate #include <grp.h>
400Sstevel@tonic-gate #include <sys/acct.h>
410Sstevel@tonic-gate #include <pwd.h>
420Sstevel@tonic-gate #include <sys/stat.h>
430Sstevel@tonic-gate #include <locale.h>
44*428Ssl108498 #include <stdlib.h>
45*428Ssl108498 #include <libgen.h>
460Sstevel@tonic-gate 
470Sstevel@tonic-gate struct	acct ab;
480Sstevel@tonic-gate char	command_name[16];
490Sstevel@tonic-gate char	obuf[BUFSIZ];
500Sstevel@tonic-gate static char	time_buf[50];
510Sstevel@tonic-gate 
520Sstevel@tonic-gate double	cpucut,
530Sstevel@tonic-gate 	syscut,
540Sstevel@tonic-gate 	hogcut,
550Sstevel@tonic-gate 	iocut,
560Sstevel@tonic-gate 	realtot,
570Sstevel@tonic-gate 	cputot,
580Sstevel@tonic-gate 	usertot,
590Sstevel@tonic-gate 	systot,
600Sstevel@tonic-gate 	kcoretot,
610Sstevel@tonic-gate 	iotot,
620Sstevel@tonic-gate 	rwtot;
630Sstevel@tonic-gate extern long	timezone;
640Sstevel@tonic-gate extern int	daylight;	/* daylight savings time if set */
650Sstevel@tonic-gate long	daydiff,
660Sstevel@tonic-gate 	offset = -2,
670Sstevel@tonic-gate 	cmdcount;
680Sstevel@tonic-gate ulong_t	elapsed,
690Sstevel@tonic-gate 	sys,
700Sstevel@tonic-gate 	user,
710Sstevel@tonic-gate 	cpu,
720Sstevel@tonic-gate 	io,
730Sstevel@tonic-gate 	rw,
740Sstevel@tonic-gate 	mem,
750Sstevel@tonic-gate 	etime;
760Sstevel@tonic-gate time_t	tstrt_b,
770Sstevel@tonic-gate 	tstrt_a,
780Sstevel@tonic-gate 	tend_b,
790Sstevel@tonic-gate 	tend_a;
800Sstevel@tonic-gate int	backward,
810Sstevel@tonic-gate 	flag_field,
820Sstevel@tonic-gate 	average,
830Sstevel@tonic-gate 	quiet,
840Sstevel@tonic-gate 	option,
850Sstevel@tonic-gate 	verbose = 1,
860Sstevel@tonic-gate 	uidflag,
870Sstevel@tonic-gate 	gidflag,
880Sstevel@tonic-gate 	unkid,	/*user doesn't have login on this machine*/
890Sstevel@tonic-gate 	errflg,
900Sstevel@tonic-gate 	su_user,
910Sstevel@tonic-gate 	fileout = 0,
920Sstevel@tonic-gate 	stdinflg,
930Sstevel@tonic-gate 	nfiles;
940Sstevel@tonic-gate static int	eflg = 0,
950Sstevel@tonic-gate 	Eflg = 0,
960Sstevel@tonic-gate 	sflg = 0,
970Sstevel@tonic-gate 	Sflg = 0;
980Sstevel@tonic-gate #ifdef uts
990Sstevel@tonic-gate dev_t   linedev = 0xffff;  /* changed from -1, as dev_t is now ushort */
1000Sstevel@tonic-gate #else
1010Sstevel@tonic-gate dev_t	linedev = (dev_t)-1;
1020Sstevel@tonic-gate #endif
1030Sstevel@tonic-gate uid_t	uidval;
1040Sstevel@tonic-gate gid_t	gidval;
1050Sstevel@tonic-gate char	*cname = NULL; /* command name pattern to match*/
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate struct passwd *getpwnam(), *getpwuid(), *pw;
1080Sstevel@tonic-gate struct group *getgrnam(),*grp;
1090Sstevel@tonic-gate long	convtime();
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate #ifdef uts
1120Sstevel@tonic-gate float   expand();
1130Sstevel@tonic-gate #else
1140Sstevel@tonic-gate ulong_t	expand();
1150Sstevel@tonic-gate #endif
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate char	*ofile,
1180Sstevel@tonic-gate 	*devtolin(),
1190Sstevel@tonic-gate 	*uidtonam();
1200Sstevel@tonic-gate dev_t	lintodev();
121*428Ssl108498 
122*428Ssl108498 void dofile(char *);
123*428Ssl108498 void doexit(int) __NORETURN;
124*428Ssl108498 void usage(void);
125*428Ssl108498 void fatal(char *, char *);
126*428Ssl108498 void println(void);
127*428Ssl108498 void printhd(void);
128*428Ssl108498 char *cmset(char *);
129*428Ssl108498 
1300Sstevel@tonic-gate FILE	*ostrm;
1310Sstevel@tonic-gate 
132*428Ssl108498 int
main(int argc,char ** argv)133*428Ssl108498 main(int argc, char **argv)
1340Sstevel@tonic-gate {
135*428Ssl108498 	int	c;
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 	(void)setlocale(LC_ALL, "");
1380Sstevel@tonic-gate 	setbuf(stdout,obuf);
1390Sstevel@tonic-gate 	while((c = getopt(argc, argv,
1400Sstevel@tonic-gate 		"C:E:H:I:O:S:abe:fg:hikl:mn:o:qrs:tu:v")) != EOF) {
1410Sstevel@tonic-gate 		switch(c) {
1420Sstevel@tonic-gate 		case 'C':
1430Sstevel@tonic-gate 			sscanf(optarg,"%lf",&cpucut);
1440Sstevel@tonic-gate 			continue;
1450Sstevel@tonic-gate 		case 'O':
1460Sstevel@tonic-gate 			sscanf(optarg,"%lf",&syscut);
1470Sstevel@tonic-gate 			continue;
1480Sstevel@tonic-gate 		case 'H':
1490Sstevel@tonic-gate 			sscanf(optarg,"%lf",&hogcut);
1500Sstevel@tonic-gate 			continue;
1510Sstevel@tonic-gate 		case 'I':
1520Sstevel@tonic-gate 			sscanf(optarg,"%lf",&iocut);
1530Sstevel@tonic-gate 			continue;
1540Sstevel@tonic-gate 		case 'a':
1550Sstevel@tonic-gate 			average++;
1560Sstevel@tonic-gate 			continue;
1570Sstevel@tonic-gate 		case 'b':
1580Sstevel@tonic-gate 			backward++;
1590Sstevel@tonic-gate 			continue;
1600Sstevel@tonic-gate 		case 'g':
1610Sstevel@tonic-gate 			if(sscanf(optarg,"%ld",&gidval) == 1) {
1620Sstevel@tonic-gate 				if (getgrgid(gidval) == NULL)
1630Sstevel@tonic-gate 					fatal("Unknown group", optarg);
1640Sstevel@tonic-gate 			} else if((grp=getgrnam(optarg)) == NULL)
1650Sstevel@tonic-gate 				fatal("Unknown group", optarg);
1660Sstevel@tonic-gate 			else
1670Sstevel@tonic-gate 				gidval=grp->gr_gid;
1680Sstevel@tonic-gate 			gidflag++;
1690Sstevel@tonic-gate 			continue;
1700Sstevel@tonic-gate 		case 'h':
1710Sstevel@tonic-gate 			option |= HOGFACTOR;
1720Sstevel@tonic-gate 			continue;
1730Sstevel@tonic-gate 		case 'i':
1740Sstevel@tonic-gate 			option |= IORW;
1750Sstevel@tonic-gate 			continue;
1760Sstevel@tonic-gate 		case 'k':
1770Sstevel@tonic-gate 			option |= KCOREMIN;
1780Sstevel@tonic-gate 			continue;
1790Sstevel@tonic-gate 		case 'm':
1800Sstevel@tonic-gate 			option |= MEANSIZE;
1810Sstevel@tonic-gate 			continue;
1820Sstevel@tonic-gate 		case 'n':
183*428Ssl108498 			cname=cmset(optarg);
1840Sstevel@tonic-gate 			continue;
1850Sstevel@tonic-gate 		case 't':
1860Sstevel@tonic-gate 			option |= SEPTIME;
1870Sstevel@tonic-gate 			continue;
1880Sstevel@tonic-gate 		case 'r':
1890Sstevel@tonic-gate 			option |= CPUFACTOR;
1900Sstevel@tonic-gate 			continue;
1910Sstevel@tonic-gate 		case 'v':
1920Sstevel@tonic-gate 			verbose=0;
1930Sstevel@tonic-gate 			continue;
1940Sstevel@tonic-gate 		case 'l':
1950Sstevel@tonic-gate 			linedev = lintodev(optarg);
1960Sstevel@tonic-gate 			continue;
1970Sstevel@tonic-gate 		case 'u':
1980Sstevel@tonic-gate 			if(*optarg == '?') {
1990Sstevel@tonic-gate 				unkid++;
2000Sstevel@tonic-gate 				continue;
2010Sstevel@tonic-gate 			}
2020Sstevel@tonic-gate 			if(*optarg == '#') {
2030Sstevel@tonic-gate 				su_user++;
2040Sstevel@tonic-gate 				uidval = 0;
2050Sstevel@tonic-gate 				uidflag++;
2060Sstevel@tonic-gate 				continue;
2070Sstevel@tonic-gate 			}
2080Sstevel@tonic-gate 			if((pw = getpwnam(optarg)) == NULL) {
2090Sstevel@tonic-gate 				uidval = (uid_t)atoi(optarg);
2100Sstevel@tonic-gate 				/* atoi will return 0 in abnormal situation */
2110Sstevel@tonic-gate 				if (uidval == 0 && strcmp(optarg, "0") != 0) {
2120Sstevel@tonic-gate 					fprintf(stderr, "%s: Unknown user %s\n", argv[0], optarg);
2130Sstevel@tonic-gate 					exit(1);
2140Sstevel@tonic-gate 				}
2150Sstevel@tonic-gate  				if ((pw = getpwuid(uidval)) == NULL) {
2160Sstevel@tonic-gate 					fprintf(stderr, "%s: Unknown user %s\n", argv[0], optarg);
2170Sstevel@tonic-gate 					exit(1);
2180Sstevel@tonic-gate 				}
2190Sstevel@tonic-gate 				uidflag++;
2200Sstevel@tonic-gate 			} else {
2210Sstevel@tonic-gate 				uidval = pw->pw_uid;
2220Sstevel@tonic-gate 				uidflag++;
2230Sstevel@tonic-gate 			}
2240Sstevel@tonic-gate 			continue;
2250Sstevel@tonic-gate 		case 'q':
2260Sstevel@tonic-gate 			quiet++;
2270Sstevel@tonic-gate 			verbose=0;
2280Sstevel@tonic-gate 			average++;
2290Sstevel@tonic-gate 			continue;
2300Sstevel@tonic-gate 		case 's':
2310Sstevel@tonic-gate 			sflg = 1;
2320Sstevel@tonic-gate 			tend_a = convtime(optarg);
2330Sstevel@tonic-gate 			continue;
2340Sstevel@tonic-gate 		case 'S':
2350Sstevel@tonic-gate 			Sflg = 1;
2360Sstevel@tonic-gate 			tstrt_a = convtime(optarg);
2370Sstevel@tonic-gate 			continue;
2380Sstevel@tonic-gate 		case 'f':
2390Sstevel@tonic-gate 			flag_field++;
2400Sstevel@tonic-gate 			continue;
2410Sstevel@tonic-gate 		case 'e':
2420Sstevel@tonic-gate 			eflg = 1;
2430Sstevel@tonic-gate 			tstrt_b = convtime(optarg);
2440Sstevel@tonic-gate 			continue;
2450Sstevel@tonic-gate 		case 'E':
2460Sstevel@tonic-gate 			Eflg = 1;
2470Sstevel@tonic-gate 			tend_b = convtime(optarg);
2480Sstevel@tonic-gate 			continue;
2490Sstevel@tonic-gate 		case 'o':
2500Sstevel@tonic-gate 			ofile = optarg;
2510Sstevel@tonic-gate 			fileout++;
2520Sstevel@tonic-gate 			if((ostrm = fopen(ofile, "w")) == NULL) {
2530Sstevel@tonic-gate 				perror("open error on output file");
2540Sstevel@tonic-gate 				errflg++;
2550Sstevel@tonic-gate 			}
2560Sstevel@tonic-gate 			continue;
2570Sstevel@tonic-gate 		case '?':
2580Sstevel@tonic-gate 			errflg++;
2590Sstevel@tonic-gate 			continue;
2600Sstevel@tonic-gate 		}
2610Sstevel@tonic-gate 	}
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 	if(errflg) {
2640Sstevel@tonic-gate 		usage();
2650Sstevel@tonic-gate 		exit(1);
2660Sstevel@tonic-gate 	}
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	argv = &argv[optind];
2700Sstevel@tonic-gate 	while(optind++ < argc) {
2710Sstevel@tonic-gate 		dofile(*argv++);    /* change from *argv */
2720Sstevel@tonic-gate 		nfiles++;
2730Sstevel@tonic-gate 	}
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	if(nfiles==0) {
2760Sstevel@tonic-gate 		if(isatty(0) || isdevnull())
2770Sstevel@tonic-gate 			dofile(PACCT);
2780Sstevel@tonic-gate 		else {
2790Sstevel@tonic-gate 			stdinflg = 1;
2800Sstevel@tonic-gate 			backward = offset = 0;
2810Sstevel@tonic-gate 			dofile(NULL);
2820Sstevel@tonic-gate 		}
2830Sstevel@tonic-gate 	}
2840Sstevel@tonic-gate 	doexit(0);
285*428Ssl108498 	/* NOTREACHED */
2860Sstevel@tonic-gate }
2870Sstevel@tonic-gate 
288*428Ssl108498 void
dofile(char * fname)289*428Ssl108498 dofile(char *fname)
2900Sstevel@tonic-gate {
291*428Ssl108498 	struct acct *a = &ab;
2920Sstevel@tonic-gate 	struct tm *t;
2930Sstevel@tonic-gate 	time_t curtime;
2940Sstevel@tonic-gate 	time_t	ts_a = 0,
2950Sstevel@tonic-gate 		ts_b = 0,
2960Sstevel@tonic-gate 		te_a = 0,
2970Sstevel@tonic-gate 		te_b = 0;
2980Sstevel@tonic-gate 	long	daystart;
2990Sstevel@tonic-gate 	long	nsize;
3000Sstevel@tonic-gate 	int	ver;	/* version of acct structure */
3010Sstevel@tonic-gate 	int	dst_secs;	/* number of seconds to adjust
3020Sstevel@tonic-gate 				   for daylight savings time */
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	if(fname != NULL)
3050Sstevel@tonic-gate 		if(freopen(fname, "r", stdin) == NULL) {
3060Sstevel@tonic-gate 			fprintf(stderr, "acctcom: cannot open %s\n", fname);
3070Sstevel@tonic-gate 			return;
3080Sstevel@tonic-gate 		}
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	if (fread((char *)&ab, sizeof(struct acct), 1, stdin) != 1)
3110Sstevel@tonic-gate 		return;
3120Sstevel@tonic-gate 	else if (ab.ac_flag & AEXPND)
3130Sstevel@tonic-gate 		ver = 2;	/* 4.0 acct structure */
3140Sstevel@tonic-gate 	else
3150Sstevel@tonic-gate 		ver = 1;	/* 3.x acct structure */
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	rewind(stdin);
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 	if(backward) {
3210Sstevel@tonic-gate 		if (ver == 2)
3220Sstevel@tonic-gate 			nsize = sizeof(struct acct);	/* make sure offset is signed */
3230Sstevel@tonic-gate 		else
3240Sstevel@tonic-gate 			nsize = sizeof(struct o_acct);	/* make sure offset is signed */
3250Sstevel@tonic-gate 		fseek(stdin, (long)(-nsize), 2);
3260Sstevel@tonic-gate 	}
3270Sstevel@tonic-gate 	tzset();
3280Sstevel@tonic-gate 	daydiff = a->ac_btime - (a->ac_btime % SECSINDAY);
3290Sstevel@tonic-gate 	time(&curtime);
3300Sstevel@tonic-gate 	t = localtime(&curtime);
3310Sstevel@tonic-gate 	if (daydiff < (curtime - (curtime % SECSINDAY))) {
3320Sstevel@tonic-gate 		time_t t;
3330Sstevel@tonic-gate 		/*
3340Sstevel@tonic-gate 		 * it is older than today
3350Sstevel@tonic-gate 		 */
3360Sstevel@tonic-gate 		t = (time_t)a->ac_btime;
3370Sstevel@tonic-gate 		cftime(time_buf, DATE_FMT, &t);
3380Sstevel@tonic-gate 		fprintf(stdout, "\nACCOUNTING RECORDS FROM:  %s", time_buf);
3390Sstevel@tonic-gate 	}
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	/* adjust time by one hour for daylight savings time */
3420Sstevel@tonic-gate 	if (daylight && t->tm_isdst != 0)
3430Sstevel@tonic-gate 		dst_secs = 3600;
3440Sstevel@tonic-gate 	else
3450Sstevel@tonic-gate 		dst_secs = 0;
3460Sstevel@tonic-gate 	daystart = (a->ac_btime - timezone + dst_secs) -
3470Sstevel@tonic-gate 	    ((a->ac_btime - timezone + dst_secs) % SECSINDAY);
3480Sstevel@tonic-gate 	if (Sflg) {
3490Sstevel@tonic-gate 		ts_a = tstrt_a + daystart - dst_secs;
3500Sstevel@tonic-gate 		cftime(time_buf, DATE_FMT, &ts_a);
3510Sstevel@tonic-gate 		fprintf(stdout, "START AFT: %s", time_buf);
3520Sstevel@tonic-gate 	}
3530Sstevel@tonic-gate 	if (eflg) {
3540Sstevel@tonic-gate 		ts_b = tstrt_b + daystart - dst_secs;
3550Sstevel@tonic-gate 		cftime(time_buf, DATE_FMT, &ts_b);
3560Sstevel@tonic-gate 		fprintf(stdout, "START BEF: %s", time_buf);
3570Sstevel@tonic-gate 	}
3580Sstevel@tonic-gate 	if (sflg) {
3590Sstevel@tonic-gate 		te_a = tend_a + daystart - dst_secs;
3600Sstevel@tonic-gate 		cftime(time_buf, DATE_FMT, &te_a);
3610Sstevel@tonic-gate 		fprintf(stdout, "END AFTER: %s", time_buf);
3620Sstevel@tonic-gate 	}
3630Sstevel@tonic-gate 	if (Eflg) {
3640Sstevel@tonic-gate 		te_b = tend_b + daystart - dst_secs;
3650Sstevel@tonic-gate 		cftime(time_buf, DATE_FMT, &te_b);
3660Sstevel@tonic-gate 		fprintf(stdout, "END BEFOR: %s", time_buf);
3670Sstevel@tonic-gate 	}
3680Sstevel@tonic-gate 	if(ts_a) {
3690Sstevel@tonic-gate 		if (te_b && ts_a > te_b) te_b += SECSINDAY;
3700Sstevel@tonic-gate 	}
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 	while(aread(ver) != 0) {
3730Sstevel@tonic-gate 		elapsed = expand(a->ac_etime);
3740Sstevel@tonic-gate 		etime = (ulong_t)a->ac_btime + (ulong_t)SECS(elapsed);
3750Sstevel@tonic-gate 		if(ts_a || ts_b || te_a || te_b) {
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 			if(te_a && (etime < te_a)) {
3780Sstevel@tonic-gate 				if(backward) return;
3790Sstevel@tonic-gate 				else continue;
3800Sstevel@tonic-gate 			}
3810Sstevel@tonic-gate 			if(te_b && (etime > te_b)) {
3820Sstevel@tonic-gate 				if(backward) continue;
3830Sstevel@tonic-gate 				else return;
3840Sstevel@tonic-gate 			}
3850Sstevel@tonic-gate 			if(ts_a && (a->ac_btime < ts_a))
3860Sstevel@tonic-gate 				continue;
3870Sstevel@tonic-gate 			if(ts_b && (a->ac_btime > ts_b))
3880Sstevel@tonic-gate 				continue;
3890Sstevel@tonic-gate 		}
3900Sstevel@tonic-gate 		if(!MYKIND(a->ac_flag))
3910Sstevel@tonic-gate 			continue;
3920Sstevel@tonic-gate 		if(su_user && !SU(a->ac_flag))
3930Sstevel@tonic-gate 			continue;
3940Sstevel@tonic-gate 		sys = expand(a->ac_stime);
3950Sstevel@tonic-gate 		user = expand(a->ac_utime);
3960Sstevel@tonic-gate 		cpu = sys + user;
3970Sstevel@tonic-gate 		if(cpu == 0)
3980Sstevel@tonic-gate 			cpu = 1;
3990Sstevel@tonic-gate 		mem = expand(a->ac_mem);
4000Sstevel@tonic-gate 		(void) strncpy(command_name, a->ac_comm, 8);
4010Sstevel@tonic-gate 		io=expand(a->ac_io);
4020Sstevel@tonic-gate 		rw=expand(a->ac_rw);
4030Sstevel@tonic-gate 		if(cpucut && cpucut >= SECS(cpu))
4040Sstevel@tonic-gate 			continue;
4050Sstevel@tonic-gate 		if(syscut && syscut >= SECS(sys))
4060Sstevel@tonic-gate 			continue;
4070Sstevel@tonic-gate #ifdef uts
4080Sstevel@tonic-gate 		if(linedev != 0xffff && a->ac_tty != linedev)
4090Sstevel@tonic-gate 			continue;
4100Sstevel@tonic-gate #else
4110Sstevel@tonic-gate 		if(linedev != (dev_t)-1 && a->ac_tty != linedev)
4120Sstevel@tonic-gate 			continue;
4130Sstevel@tonic-gate #endif
4140Sstevel@tonic-gate 		if(uidflag && a->ac_uid != uidval)
4150Sstevel@tonic-gate 			continue;
4160Sstevel@tonic-gate 		if(gidflag && a->ac_gid != gidval)
4170Sstevel@tonic-gate 			continue;
4180Sstevel@tonic-gate 		if(cname && !cmatch(a->ac_comm,cname))
4190Sstevel@tonic-gate 			continue;
4200Sstevel@tonic-gate 		if(iocut && iocut > io)
4210Sstevel@tonic-gate 			continue;
4220Sstevel@tonic-gate 		if(unkid && uidtonam(a->ac_uid)[0] != '?')
4230Sstevel@tonic-gate 			continue;
4240Sstevel@tonic-gate 		if(verbose && (fileout == 0)) {
4250Sstevel@tonic-gate 			printhd();
4260Sstevel@tonic-gate 			verbose = 0;
4270Sstevel@tonic-gate 		}
4280Sstevel@tonic-gate 		if(elapsed == 0)
4290Sstevel@tonic-gate 			elapsed++;
4300Sstevel@tonic-gate 		if(hogcut && hogcut >= (double)cpu/(double)elapsed)
4310Sstevel@tonic-gate 			continue;
4320Sstevel@tonic-gate 		if(fileout)
4330Sstevel@tonic-gate 			fwrite(&ab, sizeof(ab), 1, ostrm);
4340Sstevel@tonic-gate 		else
4350Sstevel@tonic-gate 			println();
4360Sstevel@tonic-gate 		if(average) {
4370Sstevel@tonic-gate 			cmdcount++;
4380Sstevel@tonic-gate 			realtot += (double)elapsed;
4390Sstevel@tonic-gate 			usertot += (double)user;
4400Sstevel@tonic-gate 			systot += (double)sys;
4410Sstevel@tonic-gate 			kcoretot += (double)mem;
4420Sstevel@tonic-gate 			iotot += (double)io;
4430Sstevel@tonic-gate 			rwtot += (double)rw;
4440Sstevel@tonic-gate 		};
4450Sstevel@tonic-gate 	}
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate 
448*428Ssl108498 int
aread(int ver)449*428Ssl108498 aread(int ver)
4500Sstevel@tonic-gate {
451*428Ssl108498 	static int ok = 1;
4520Sstevel@tonic-gate 	struct o_acct oab;
4530Sstevel@tonic-gate 	int ret;
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 	if (ver != 2) {
4560Sstevel@tonic-gate 		if ((ret = fread((char *)&oab, sizeof(struct o_acct), 1, stdin)) == 1){
4570Sstevel@tonic-gate 			/* copy SVR3 acct struct to SVR4 acct struct */
4580Sstevel@tonic-gate 			ab.ac_flag = oab.ac_flag | AEXPND;
4590Sstevel@tonic-gate 			ab.ac_stat = oab.ac_stat;
4600Sstevel@tonic-gate 			ab.ac_uid = (uid_t) oab.ac_uid;
4610Sstevel@tonic-gate 			ab.ac_gid = (gid_t) oab.ac_gid;
4620Sstevel@tonic-gate 			ab.ac_tty = (dev_t) oab.ac_tty;
4630Sstevel@tonic-gate 			ab.ac_btime = oab.ac_btime;
4640Sstevel@tonic-gate 			ab.ac_utime = oab.ac_utime;
4650Sstevel@tonic-gate 			ab.ac_stime = oab.ac_stime;
4660Sstevel@tonic-gate 			ab.ac_mem = oab.ac_mem;
4670Sstevel@tonic-gate 			ab.ac_io = oab.ac_io;
4680Sstevel@tonic-gate 			ab.ac_rw = oab.ac_rw;
4690Sstevel@tonic-gate 			strcpy(ab.ac_comm, oab.ac_comm);
4700Sstevel@tonic-gate 		}
4710Sstevel@tonic-gate 	} else
4720Sstevel@tonic-gate 		ret = fread((char *)&ab, sizeof(struct acct), 1, stdin);
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 	if(backward) {
4760Sstevel@tonic-gate 		if(ok) {
4770Sstevel@tonic-gate 			if(fseek(stdin,
4780Sstevel@tonic-gate 				(long)(offset*(ver == 2 ? sizeof(struct acct) :
4790Sstevel@tonic-gate 					sizeof(struct o_acct))), 1) != 0) {
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 					rewind(stdin);	/* get 1st record */
4820Sstevel@tonic-gate 					ok = 0;
4830Sstevel@tonic-gate 			}
4840Sstevel@tonic-gate 		} else
4850Sstevel@tonic-gate 			ret = 0;
4860Sstevel@tonic-gate 	}
4870Sstevel@tonic-gate 	return(ret != 1 ? 0 : 1);
4880Sstevel@tonic-gate }
4890Sstevel@tonic-gate 
490*428Ssl108498 void
printhd(void)491*428Ssl108498 printhd(void)
4920Sstevel@tonic-gate {
4930Sstevel@tonic-gate 	fprintf(stdout, "COMMAND                           START    END          REAL");
4940Sstevel@tonic-gate 	ps("CPU");
4950Sstevel@tonic-gate 	if(option & SEPTIME)
4960Sstevel@tonic-gate 		ps("(SECS)");
4970Sstevel@tonic-gate 	if(option & IORW){
4980Sstevel@tonic-gate 		ps("CHARS");
4990Sstevel@tonic-gate 		ps("BLOCKS");
5000Sstevel@tonic-gate 	}
5010Sstevel@tonic-gate 	if(option & CPUFACTOR)
5020Sstevel@tonic-gate 		ps("CPU");
5030Sstevel@tonic-gate 	if(option & HOGFACTOR)
5040Sstevel@tonic-gate 		ps("HOG");
5050Sstevel@tonic-gate 	if(!option || (option & MEANSIZE))
5060Sstevel@tonic-gate 		ps("MEAN");
5070Sstevel@tonic-gate 	if(option & KCOREMIN)
5080Sstevel@tonic-gate 		ps("KCORE");
5090Sstevel@tonic-gate 	fprintf(stdout, "\n");
5100Sstevel@tonic-gate 	fprintf(stdout, "NAME       USER     TTYNAME       TIME     TIME       (SECS)");
5110Sstevel@tonic-gate 	if(option & SEPTIME) {
5120Sstevel@tonic-gate 		ps("SYS");
5130Sstevel@tonic-gate 		ps("USER");
5140Sstevel@tonic-gate 	} else
5150Sstevel@tonic-gate 		ps("(SECS)");
5160Sstevel@tonic-gate 	if(option & IORW) {
5170Sstevel@tonic-gate 		ps("TRNSFD");
5180Sstevel@tonic-gate 		ps("READ");
5190Sstevel@tonic-gate 	}
5200Sstevel@tonic-gate 	if(option & CPUFACTOR)
5210Sstevel@tonic-gate 		ps("FACTOR");
5220Sstevel@tonic-gate 	if(option & HOGFACTOR)
5230Sstevel@tonic-gate 		ps("FACTOR");
5240Sstevel@tonic-gate 	if(!option || (option & MEANSIZE))
5250Sstevel@tonic-gate 		ps("SIZE(K)");
5260Sstevel@tonic-gate 	if(option & KCOREMIN)
5270Sstevel@tonic-gate 		ps("MIN");
5280Sstevel@tonic-gate 	if(flag_field)
5290Sstevel@tonic-gate 		fprintf(stdout, "  F STAT");
5300Sstevel@tonic-gate 	fprintf(stdout, "\n");
5310Sstevel@tonic-gate 	fflush(stdout);
5320Sstevel@tonic-gate }
5330Sstevel@tonic-gate 
534*428Ssl108498 void
println(void)535*428Ssl108498 println(void)
5360Sstevel@tonic-gate {
5370Sstevel@tonic-gate 	char name[32];
538*428Ssl108498 	struct acct *a = &ab;
5390Sstevel@tonic-gate 	time_t t;
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 	if(quiet)
5420Sstevel@tonic-gate 		return;
5430Sstevel@tonic-gate 	if(!SU(a->ac_flag))
5440Sstevel@tonic-gate 		strcpy(name,command_name);
5450Sstevel@tonic-gate 	else {
5460Sstevel@tonic-gate 		strcpy(name,"#");
5470Sstevel@tonic-gate 		strcat(name,command_name);
5480Sstevel@tonic-gate 	}
5490Sstevel@tonic-gate 	fprintf(stdout, "%-*.*s", (OUTPUT_NSZ + 1),
5500Sstevel@tonic-gate 	    (OUTPUT_NSZ + 1), name);
5510Sstevel@tonic-gate 	strcpy(name,uidtonam(a->ac_uid));
5520Sstevel@tonic-gate 	if(*name != '?')
5530Sstevel@tonic-gate 		fprintf(stdout, "  %-*.*s", (OUTPUT_NSZ + 1),
5540Sstevel@tonic-gate 		    (OUTPUT_NSZ + 1), name);
5550Sstevel@tonic-gate 	else
5560Sstevel@tonic-gate 		fprintf(stdout, "  %-9d",a->ac_uid);
5570Sstevel@tonic-gate #ifdef uts
5580Sstevel@tonic-gate 	fprintf(stdout, " %-*.*s", OUTPUT_LSZ, OUTPUT_LSZ,
5590Sstevel@tonic-gate 	    a->ac_tty != 0xffff? devtolin(a->ac_tty):"?");
5600Sstevel@tonic-gate #else
5610Sstevel@tonic-gate 	fprintf(stdout, " %-*.*s", OUTPUT_LSZ, OUTPUT_LSZ,
5620Sstevel@tonic-gate 	    a->ac_tty != (dev_t)-1? devtolin(a->ac_tty):"?");
5630Sstevel@tonic-gate #endif
5640Sstevel@tonic-gate 	t = a->ac_btime;
5650Sstevel@tonic-gate 	cftime(time_buf, DATE_FMT1, &t);
5660Sstevel@tonic-gate 	fprintf(stdout, "%.9s", time_buf);
5670Sstevel@tonic-gate 	cftime(time_buf, DATE_FMT1, (time_t *)&etime);
5680Sstevel@tonic-gate 	fprintf(stdout, "%.9s ", time_buf);
5690Sstevel@tonic-gate 	pf((double)SECS(elapsed));
5700Sstevel@tonic-gate 	if(option & SEPTIME) {
5710Sstevel@tonic-gate 		pf((double)sys / HZ);
5720Sstevel@tonic-gate 		pf((double)user / HZ);
5730Sstevel@tonic-gate 	} else
5740Sstevel@tonic-gate 		pf((double)cpu / HZ);
5750Sstevel@tonic-gate 	if(option & IORW)
5760Sstevel@tonic-gate 		fprintf(stdout, io < 100000000 ? "%8ld%8ld" : "%12ld%8ld",io,rw);
5770Sstevel@tonic-gate 	if(option & CPUFACTOR)
5780Sstevel@tonic-gate 		pf((double)user / cpu);
5790Sstevel@tonic-gate 	if(option & HOGFACTOR)
5800Sstevel@tonic-gate 		pf((double)cpu / elapsed);
5810Sstevel@tonic-gate 	if(!option || (option & MEANSIZE))
5820Sstevel@tonic-gate 		pf(KCORE(mem / cpu));
5830Sstevel@tonic-gate 	if(option & KCOREMIN)
5840Sstevel@tonic-gate 		pf(MINT(KCORE(mem)));
5850Sstevel@tonic-gate 	if(flag_field)
5860Sstevel@tonic-gate 		fprintf(stdout, "  %1o %3o", (unsigned char) a->ac_flag,
5870Sstevel@tonic-gate 						(unsigned char) a->ac_stat);
5880Sstevel@tonic-gate 	fprintf(stdout, "\n");
5890Sstevel@tonic-gate }
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate /*
5920Sstevel@tonic-gate  * convtime converts time arg to internal value
5930Sstevel@tonic-gate  * arg has form hr:min:sec, min or sec are assumed to be 0 if omitted
5940Sstevel@tonic-gate  */
5950Sstevel@tonic-gate long
convtime(str)5960Sstevel@tonic-gate convtime(str)
5970Sstevel@tonic-gate char *str;
5980Sstevel@tonic-gate {
5990Sstevel@tonic-gate 	long	hr, min, sec;
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 	min = sec = 0;
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	if(sscanf(str, "%ld:%ld:%ld", &hr, &min, &sec) < 1) {
6040Sstevel@tonic-gate 		fatal("acctcom: bad time:", str);
6050Sstevel@tonic-gate 	}
6060Sstevel@tonic-gate 	tzset();
6070Sstevel@tonic-gate 	sec += (min*60);
6080Sstevel@tonic-gate 	sec += (hr*3600);
6090Sstevel@tonic-gate 	return(sec + timezone);
6100Sstevel@tonic-gate }
6110Sstevel@tonic-gate 
612*428Ssl108498 int
cmatch(char * comm,char * cstr)613*428Ssl108498 cmatch(char *comm, char *cstr)
6140Sstevel@tonic-gate {
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate 	char	xcomm[9];
617*428Ssl108498 	int i;
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	for(i=0;i<8;i++){
6200Sstevel@tonic-gate 		if(comm[i]==' '||comm[i]=='\0')
6210Sstevel@tonic-gate 			break;
6220Sstevel@tonic-gate 		xcomm[i] = comm[i];
6230Sstevel@tonic-gate 	}
6240Sstevel@tonic-gate 	xcomm[i] = '\0';
625*428Ssl108498 
626*428Ssl108498 	return (regex(cstr,xcomm) ? 1 : 0);
6270Sstevel@tonic-gate }
6280Sstevel@tonic-gate 
629*428Ssl108498 char *
cmset(char * pattern)630*428Ssl108498 cmset(char *pattern)
6310Sstevel@tonic-gate {
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	if((pattern=(char *)regcmp(pattern,(char *)0))==NULL){
6340Sstevel@tonic-gate 		fatal("pattern syntax", NULL);
6350Sstevel@tonic-gate 	}
6360Sstevel@tonic-gate 
637*428Ssl108498 	return (pattern);
6380Sstevel@tonic-gate }
6390Sstevel@tonic-gate 
640*428Ssl108498 void
doexit(int status)641*428Ssl108498 doexit(int status)
6420Sstevel@tonic-gate {
6430Sstevel@tonic-gate 	if(!average)
6440Sstevel@tonic-gate 		exit(status);
6450Sstevel@tonic-gate 	if(cmdcount) {
6460Sstevel@tonic-gate 		fprintf(stdout, "cmds=%ld ",cmdcount);
6470Sstevel@tonic-gate 		fprintf(stdout, "Real=%-6.2f ",SECS(realtot)/cmdcount);
6480Sstevel@tonic-gate 		cputot = systot + usertot;
6490Sstevel@tonic-gate 		fprintf(stdout, "CPU=%-6.2f ",SECS(cputot)/cmdcount);
6500Sstevel@tonic-gate 		fprintf(stdout, "USER=%-6.2f ",SECS(usertot)/cmdcount);
6510Sstevel@tonic-gate 		fprintf(stdout, "SYS=%-6.2f ",SECS(systot)/cmdcount);
6520Sstevel@tonic-gate 		fprintf(stdout, "CHAR=%-8.2f ",iotot/cmdcount);
6530Sstevel@tonic-gate 		fprintf(stdout, "BLK=%-8.2f ",rwtot/cmdcount);
6540Sstevel@tonic-gate 		fprintf(stdout, "USR/TOT=%-4.2f ",usertot/cputot);
6550Sstevel@tonic-gate 		fprintf(stdout, "HOG=%-4.2f ",cputot/realtot);
6560Sstevel@tonic-gate 		fprintf(stdout, "\n");
6570Sstevel@tonic-gate 	}
6580Sstevel@tonic-gate 	else
6590Sstevel@tonic-gate 		fprintf(stdout, "\nNo commands matched\n");
6600Sstevel@tonic-gate 	exit(status);
6610Sstevel@tonic-gate }
662*428Ssl108498 
663*428Ssl108498 int
isdevnull(void)664*428Ssl108498 isdevnull(void)
6650Sstevel@tonic-gate {
6660Sstevel@tonic-gate 	struct stat	filearg;
6670Sstevel@tonic-gate 	struct stat	devnull;
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 	if(fstat(0,&filearg) == -1) {
6700Sstevel@tonic-gate 		fprintf(stderr,"acctcom: cannot stat stdin\n");
671*428Ssl108498 		return (0);
6720Sstevel@tonic-gate 	}
6730Sstevel@tonic-gate 	if(stat("/dev/null",&devnull) == -1) {
6740Sstevel@tonic-gate 		fprintf(stderr,"acctcom: cannot stat /dev/null\n");
675*428Ssl108498 		return (0);
6760Sstevel@tonic-gate 	}
6770Sstevel@tonic-gate 
678*428Ssl108498 	if (filearg.st_rdev == devnull.st_rdev)
679*428Ssl108498 		return (1);
680*428Ssl108498 	else
681*428Ssl108498 		return (0);
6820Sstevel@tonic-gate }
6830Sstevel@tonic-gate 
684*428Ssl108498 void
fatal(char * s1,char * s2)685*428Ssl108498 fatal(char *s1, char *s2)
6860Sstevel@tonic-gate {
6870Sstevel@tonic-gate 	fprintf(stderr,"acctcom: %s %s\n", s1, (s2 ? s2 : ""));
6880Sstevel@tonic-gate 	exit(1);
6890Sstevel@tonic-gate }
6900Sstevel@tonic-gate 
691*428Ssl108498 void
usage(void)692*428Ssl108498 usage(void)
6930Sstevel@tonic-gate {
6940Sstevel@tonic-gate 	fprintf(stderr, "Usage: acctcom [options] [files]\n");
6950Sstevel@tonic-gate 	fprintf(stderr, "\nWhere options can be:\n");
6960Sstevel@tonic-gate 	diag("-b	read backwards through file");
6970Sstevel@tonic-gate 	diag("-f	print the fork/exec flag and exit status");
6980Sstevel@tonic-gate 	diag("-h	print hog factor (total-CPU-time/elapsed-time)");
6990Sstevel@tonic-gate 	diag("-i	print I/O counts");
7000Sstevel@tonic-gate 	diag("-k	show total Kcore minutes instead of memory size");
7010Sstevel@tonic-gate 	diag("-m	show mean memory size");
7020Sstevel@tonic-gate 	diag("-r	show CPU factor (user-time/(sys-time + user-time))");
7030Sstevel@tonic-gate 	diag("-t	show separate system and user CPU times");
7040Sstevel@tonic-gate 	diag("-v	don't print column headings");
7050Sstevel@tonic-gate 	diag("-a	print average statistics of selected commands");
7060Sstevel@tonic-gate 	diag("-q	print average statistics only");
7070Sstevel@tonic-gate 	diag("-l line	\tshow processes belonging to terminal /dev/line");
7080Sstevel@tonic-gate 	diag("-u user	\tshow processes belonging to user name or user ID");
7090Sstevel@tonic-gate 	diag("-u #	\tshow processes executed by super-user");
7100Sstevel@tonic-gate 	diag("-u ?	\tshow processes executed by unknown UID's");
7110Sstevel@tonic-gate 	diag("-g group	show processes belonging to group name of group ID");
7120Sstevel@tonic-gate 	diag("-s time	\tshow processes ending after time (hh[:mm[:ss]])");
7130Sstevel@tonic-gate 	diag("-e time	\tshow processes starting before time");
7140Sstevel@tonic-gate 	diag("-S time	\tshow processes starting after time");
7150Sstevel@tonic-gate 	diag("-E time	\tshow processes ending before time");
7160Sstevel@tonic-gate 	diag("-n regex	select commands matching the ed(1) regular expression");
7170Sstevel@tonic-gate 	diag("-o file	\tdo not print, put selected pacct records into file");
7180Sstevel@tonic-gate 	diag("-H factor	show processes that exceed hog factor");
7190Sstevel@tonic-gate 	diag("-O sec	\tshow processes that exceed CPU system time sec");
7200Sstevel@tonic-gate 	diag("-C sec	\tshow processes that exceed total CPU time sec");
7210Sstevel@tonic-gate 	diag("-I chars	show processes that transfer more than char chars");
7220Sstevel@tonic-gate }
723