1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28*0Sstevel@tonic-gate /*	  All Rights Reserved  	*/
29*0Sstevel@tonic-gate 
30*0Sstevel@tonic-gate 
31*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.37 */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <time.h>
34*0Sstevel@tonic-gate #include <string.h>
35*0Sstevel@tonic-gate #include <stdio.h>
36*0Sstevel@tonic-gate #include <sys/types.h>
37*0Sstevel@tonic-gate #include <sys/param.h>
38*0Sstevel@tonic-gate #include "acctdef.h"
39*0Sstevel@tonic-gate #include <grp.h>
40*0Sstevel@tonic-gate #include <sys/acct.h>
41*0Sstevel@tonic-gate #include <pwd.h>
42*0Sstevel@tonic-gate #include <sys/stat.h>
43*0Sstevel@tonic-gate #include <locale.h>
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate struct	acct ab;
46*0Sstevel@tonic-gate char	command_name[16];
47*0Sstevel@tonic-gate char	obuf[BUFSIZ];
48*0Sstevel@tonic-gate static char	time_buf[50];
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate double	cpucut,
51*0Sstevel@tonic-gate 	syscut,
52*0Sstevel@tonic-gate 	hogcut,
53*0Sstevel@tonic-gate 	iocut,
54*0Sstevel@tonic-gate 	realtot,
55*0Sstevel@tonic-gate 	cputot,
56*0Sstevel@tonic-gate 	usertot,
57*0Sstevel@tonic-gate 	systot,
58*0Sstevel@tonic-gate 	kcoretot,
59*0Sstevel@tonic-gate 	iotot,
60*0Sstevel@tonic-gate 	rwtot;
61*0Sstevel@tonic-gate extern long	timezone;
62*0Sstevel@tonic-gate extern int	daylight;	/* daylight savings time if set */
63*0Sstevel@tonic-gate long	daydiff,
64*0Sstevel@tonic-gate 	offset = -2,
65*0Sstevel@tonic-gate 	cmdcount;
66*0Sstevel@tonic-gate ulong_t	elapsed,
67*0Sstevel@tonic-gate 	sys,
68*0Sstevel@tonic-gate 	user,
69*0Sstevel@tonic-gate 	cpu,
70*0Sstevel@tonic-gate 	io,
71*0Sstevel@tonic-gate 	rw,
72*0Sstevel@tonic-gate 	mem,
73*0Sstevel@tonic-gate 	etime;
74*0Sstevel@tonic-gate time_t	tstrt_b,
75*0Sstevel@tonic-gate 	tstrt_a,
76*0Sstevel@tonic-gate 	tend_b,
77*0Sstevel@tonic-gate 	tend_a;
78*0Sstevel@tonic-gate int	backward,
79*0Sstevel@tonic-gate 	flag_field,
80*0Sstevel@tonic-gate 	average,
81*0Sstevel@tonic-gate 	quiet,
82*0Sstevel@tonic-gate 	option,
83*0Sstevel@tonic-gate 	verbose = 1,
84*0Sstevel@tonic-gate 	uidflag,
85*0Sstevel@tonic-gate 	gidflag,
86*0Sstevel@tonic-gate 	unkid,	/*user doesn't have login on this machine*/
87*0Sstevel@tonic-gate 	errflg,
88*0Sstevel@tonic-gate 	su_user,
89*0Sstevel@tonic-gate 	fileout = 0,
90*0Sstevel@tonic-gate 	stdinflg,
91*0Sstevel@tonic-gate 	nfiles;
92*0Sstevel@tonic-gate static int	eflg = 0,
93*0Sstevel@tonic-gate 	Eflg = 0,
94*0Sstevel@tonic-gate 	sflg = 0,
95*0Sstevel@tonic-gate 	Sflg = 0;
96*0Sstevel@tonic-gate #ifdef uts
97*0Sstevel@tonic-gate dev_t   linedev = 0xffff;  /* changed from -1, as dev_t is now ushort */
98*0Sstevel@tonic-gate #else
99*0Sstevel@tonic-gate dev_t	linedev = (dev_t)-1;
100*0Sstevel@tonic-gate #endif
101*0Sstevel@tonic-gate uid_t	uidval;
102*0Sstevel@tonic-gate gid_t	gidval;
103*0Sstevel@tonic-gate char	*cname = NULL; /* command name pattern to match*/
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate struct passwd *getpwnam(), *getpwuid(), *pw;
106*0Sstevel@tonic-gate struct group *getgrnam(),*grp;
107*0Sstevel@tonic-gate long	convtime();
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate #ifdef uts
110*0Sstevel@tonic-gate float   expand();
111*0Sstevel@tonic-gate #else
112*0Sstevel@tonic-gate ulong_t	expand();
113*0Sstevel@tonic-gate #endif
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate char	*ofile,
116*0Sstevel@tonic-gate 	*devtolin(),
117*0Sstevel@tonic-gate 	*uidtonam();
118*0Sstevel@tonic-gate dev_t	lintodev();
119*0Sstevel@tonic-gate FILE	*ostrm;
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate main(argc, argv)
122*0Sstevel@tonic-gate char **argv;
123*0Sstevel@tonic-gate {
124*0Sstevel@tonic-gate 	register int	c;
125*0Sstevel@tonic-gate 	extern int	optind;
126*0Sstevel@tonic-gate 	extern char	*optarg;
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate 	(void)setlocale(LC_ALL, "");
129*0Sstevel@tonic-gate 	setbuf(stdout,obuf);
130*0Sstevel@tonic-gate 	while((c = getopt(argc, argv,
131*0Sstevel@tonic-gate 		"C:E:H:I:O:S:abe:fg:hikl:mn:o:qrs:tu:v")) != EOF) {
132*0Sstevel@tonic-gate 		switch(c) {
133*0Sstevel@tonic-gate 		case 'C':
134*0Sstevel@tonic-gate 			sscanf(optarg,"%lf",&cpucut);
135*0Sstevel@tonic-gate 			continue;
136*0Sstevel@tonic-gate 		case 'O':
137*0Sstevel@tonic-gate 			sscanf(optarg,"%lf",&syscut);
138*0Sstevel@tonic-gate 			continue;
139*0Sstevel@tonic-gate 		case 'H':
140*0Sstevel@tonic-gate 			sscanf(optarg,"%lf",&hogcut);
141*0Sstevel@tonic-gate 			continue;
142*0Sstevel@tonic-gate 		case 'I':
143*0Sstevel@tonic-gate 			sscanf(optarg,"%lf",&iocut);
144*0Sstevel@tonic-gate 			continue;
145*0Sstevel@tonic-gate 		case 'a':
146*0Sstevel@tonic-gate 			average++;
147*0Sstevel@tonic-gate 			continue;
148*0Sstevel@tonic-gate 		case 'b':
149*0Sstevel@tonic-gate 			backward++;
150*0Sstevel@tonic-gate 			continue;
151*0Sstevel@tonic-gate 		case 'g':
152*0Sstevel@tonic-gate 			if(sscanf(optarg,"%ld",&gidval) == 1) {
153*0Sstevel@tonic-gate 				if (getgrgid(gidval) == NULL)
154*0Sstevel@tonic-gate 					fatal("Unknown group", optarg);
155*0Sstevel@tonic-gate 			} else if((grp=getgrnam(optarg)) == NULL)
156*0Sstevel@tonic-gate 				fatal("Unknown group", optarg);
157*0Sstevel@tonic-gate 			else
158*0Sstevel@tonic-gate 				gidval=grp->gr_gid;
159*0Sstevel@tonic-gate 			gidflag++;
160*0Sstevel@tonic-gate 			continue;
161*0Sstevel@tonic-gate 		case 'h':
162*0Sstevel@tonic-gate 			option |= HOGFACTOR;
163*0Sstevel@tonic-gate 			continue;
164*0Sstevel@tonic-gate 		case 'i':
165*0Sstevel@tonic-gate 			option |= IORW;
166*0Sstevel@tonic-gate 			continue;
167*0Sstevel@tonic-gate 		case 'k':
168*0Sstevel@tonic-gate 			option |= KCOREMIN;
169*0Sstevel@tonic-gate 			continue;
170*0Sstevel@tonic-gate 		case 'm':
171*0Sstevel@tonic-gate 			option |= MEANSIZE;
172*0Sstevel@tonic-gate 			continue;
173*0Sstevel@tonic-gate 		case 'n':
174*0Sstevel@tonic-gate 			cname=(char *)cmset(optarg);
175*0Sstevel@tonic-gate 			continue;
176*0Sstevel@tonic-gate 		case 't':
177*0Sstevel@tonic-gate 			option |= SEPTIME;
178*0Sstevel@tonic-gate 			continue;
179*0Sstevel@tonic-gate 		case 'r':
180*0Sstevel@tonic-gate 			option |= CPUFACTOR;
181*0Sstevel@tonic-gate 			continue;
182*0Sstevel@tonic-gate 		case 'v':
183*0Sstevel@tonic-gate 			verbose=0;
184*0Sstevel@tonic-gate 			continue;
185*0Sstevel@tonic-gate 		case 'l':
186*0Sstevel@tonic-gate 			linedev = lintodev(optarg);
187*0Sstevel@tonic-gate 			continue;
188*0Sstevel@tonic-gate 		case 'u':
189*0Sstevel@tonic-gate 			if(*optarg == '?') {
190*0Sstevel@tonic-gate 				unkid++;
191*0Sstevel@tonic-gate 				continue;
192*0Sstevel@tonic-gate 			}
193*0Sstevel@tonic-gate 			if(*optarg == '#') {
194*0Sstevel@tonic-gate 				su_user++;
195*0Sstevel@tonic-gate 				uidval = 0;
196*0Sstevel@tonic-gate 				uidflag++;
197*0Sstevel@tonic-gate 				continue;
198*0Sstevel@tonic-gate 			}
199*0Sstevel@tonic-gate 			if((pw = getpwnam(optarg)) == NULL) {
200*0Sstevel@tonic-gate 				uidval = (uid_t)atoi(optarg);
201*0Sstevel@tonic-gate 				/* atoi will return 0 in abnormal situation */
202*0Sstevel@tonic-gate 				if (uidval == 0 && strcmp(optarg, "0") != 0) {
203*0Sstevel@tonic-gate 					fprintf(stderr, "%s: Unknown user %s\n", argv[0], optarg);
204*0Sstevel@tonic-gate 					exit(1);
205*0Sstevel@tonic-gate 				}
206*0Sstevel@tonic-gate  				if ((pw = getpwuid(uidval)) == NULL) {
207*0Sstevel@tonic-gate 					fprintf(stderr, "%s: Unknown user %s\n", argv[0], optarg);
208*0Sstevel@tonic-gate 					exit(1);
209*0Sstevel@tonic-gate 				}
210*0Sstevel@tonic-gate 				uidflag++;
211*0Sstevel@tonic-gate 			} else {
212*0Sstevel@tonic-gate 				uidval = pw->pw_uid;
213*0Sstevel@tonic-gate 				uidflag++;
214*0Sstevel@tonic-gate 			}
215*0Sstevel@tonic-gate 			continue;
216*0Sstevel@tonic-gate 		case 'q':
217*0Sstevel@tonic-gate 			quiet++;
218*0Sstevel@tonic-gate 			verbose=0;
219*0Sstevel@tonic-gate 			average++;
220*0Sstevel@tonic-gate 			continue;
221*0Sstevel@tonic-gate 		case 's':
222*0Sstevel@tonic-gate 			sflg = 1;
223*0Sstevel@tonic-gate 			tend_a = convtime(optarg);
224*0Sstevel@tonic-gate 			continue;
225*0Sstevel@tonic-gate 		case 'S':
226*0Sstevel@tonic-gate 			Sflg = 1;
227*0Sstevel@tonic-gate 			tstrt_a = convtime(optarg);
228*0Sstevel@tonic-gate 			continue;
229*0Sstevel@tonic-gate 		case 'f':
230*0Sstevel@tonic-gate 			flag_field++;
231*0Sstevel@tonic-gate 			continue;
232*0Sstevel@tonic-gate 		case 'e':
233*0Sstevel@tonic-gate 			eflg = 1;
234*0Sstevel@tonic-gate 			tstrt_b = convtime(optarg);
235*0Sstevel@tonic-gate 			continue;
236*0Sstevel@tonic-gate 		case 'E':
237*0Sstevel@tonic-gate 			Eflg = 1;
238*0Sstevel@tonic-gate 			tend_b = convtime(optarg);
239*0Sstevel@tonic-gate 			continue;
240*0Sstevel@tonic-gate 		case 'o':
241*0Sstevel@tonic-gate 			ofile = optarg;
242*0Sstevel@tonic-gate 			fileout++;
243*0Sstevel@tonic-gate 			if((ostrm = fopen(ofile, "w")) == NULL) {
244*0Sstevel@tonic-gate 				perror("open error on output file");
245*0Sstevel@tonic-gate 				errflg++;
246*0Sstevel@tonic-gate 			}
247*0Sstevel@tonic-gate 			continue;
248*0Sstevel@tonic-gate 		case '?':
249*0Sstevel@tonic-gate 			errflg++;
250*0Sstevel@tonic-gate 			continue;
251*0Sstevel@tonic-gate 		}
252*0Sstevel@tonic-gate 	}
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate 	if(errflg) {
255*0Sstevel@tonic-gate 		usage();
256*0Sstevel@tonic-gate 		exit(1);
257*0Sstevel@tonic-gate 	}
258*0Sstevel@tonic-gate 
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate 	argv = &argv[optind];
261*0Sstevel@tonic-gate 	while(optind++ < argc) {
262*0Sstevel@tonic-gate 		dofile(*argv++);    /* change from *argv */
263*0Sstevel@tonic-gate 		nfiles++;
264*0Sstevel@tonic-gate 	}
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate 	if(nfiles==0) {
267*0Sstevel@tonic-gate 		if(isatty(0) || isdevnull())
268*0Sstevel@tonic-gate 			dofile(PACCT);
269*0Sstevel@tonic-gate 		else {
270*0Sstevel@tonic-gate 			stdinflg = 1;
271*0Sstevel@tonic-gate 			backward = offset = 0;
272*0Sstevel@tonic-gate 			dofile(NULL);
273*0Sstevel@tonic-gate 		}
274*0Sstevel@tonic-gate 	}
275*0Sstevel@tonic-gate 	doexit(0);
276*0Sstevel@tonic-gate }
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate dofile(fname)
279*0Sstevel@tonic-gate char *fname;
280*0Sstevel@tonic-gate {
281*0Sstevel@tonic-gate 	register struct acct *a = &ab;
282*0Sstevel@tonic-gate 	struct tm *t;
283*0Sstevel@tonic-gate 	time_t curtime;
284*0Sstevel@tonic-gate 	time_t	ts_a = 0,
285*0Sstevel@tonic-gate 		ts_b = 0,
286*0Sstevel@tonic-gate 		te_a = 0,
287*0Sstevel@tonic-gate 		te_b = 0;
288*0Sstevel@tonic-gate 	long	daystart;
289*0Sstevel@tonic-gate 	long	nsize;
290*0Sstevel@tonic-gate 	int	ver;	/* version of acct structure */
291*0Sstevel@tonic-gate 	int	dst_secs;	/* number of seconds to adjust
292*0Sstevel@tonic-gate 				   for daylight savings time */
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate 	if(fname != NULL)
295*0Sstevel@tonic-gate 		if(freopen(fname, "r", stdin) == NULL) {
296*0Sstevel@tonic-gate 			fprintf(stderr, "acctcom: cannot open %s\n", fname);
297*0Sstevel@tonic-gate 			return;
298*0Sstevel@tonic-gate 		}
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate 	if (fread((char *)&ab, sizeof(struct acct), 1, stdin) != 1)
301*0Sstevel@tonic-gate 		return;
302*0Sstevel@tonic-gate 	else if (ab.ac_flag & AEXPND)
303*0Sstevel@tonic-gate 		ver = 2;	/* 4.0 acct structure */
304*0Sstevel@tonic-gate 	else
305*0Sstevel@tonic-gate 		ver = 1;	/* 3.x acct structure */
306*0Sstevel@tonic-gate 
307*0Sstevel@tonic-gate 	rewind(stdin);
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 
310*0Sstevel@tonic-gate 	if(backward) {
311*0Sstevel@tonic-gate 		if (ver == 2)
312*0Sstevel@tonic-gate 			nsize = sizeof(struct acct);	/* make sure offset is signed */
313*0Sstevel@tonic-gate 		else
314*0Sstevel@tonic-gate 			nsize = sizeof(struct o_acct);	/* make sure offset is signed */
315*0Sstevel@tonic-gate 		fseek(stdin, (long)(-nsize), 2);
316*0Sstevel@tonic-gate 	}
317*0Sstevel@tonic-gate 	tzset();
318*0Sstevel@tonic-gate 	daydiff = a->ac_btime - (a->ac_btime % SECSINDAY);
319*0Sstevel@tonic-gate 	time(&curtime);
320*0Sstevel@tonic-gate 	t = localtime(&curtime);
321*0Sstevel@tonic-gate 	if (daydiff < (curtime - (curtime % SECSINDAY))) {
322*0Sstevel@tonic-gate 		time_t t;
323*0Sstevel@tonic-gate 		/*
324*0Sstevel@tonic-gate 		 * it is older than today
325*0Sstevel@tonic-gate 		 */
326*0Sstevel@tonic-gate 		t = (time_t)a->ac_btime;
327*0Sstevel@tonic-gate 		cftime(time_buf, DATE_FMT, &t);
328*0Sstevel@tonic-gate 		fprintf(stdout, "\nACCOUNTING RECORDS FROM:  %s", time_buf);
329*0Sstevel@tonic-gate 	}
330*0Sstevel@tonic-gate 
331*0Sstevel@tonic-gate 	/* adjust time by one hour for daylight savings time */
332*0Sstevel@tonic-gate 	if (daylight && t->tm_isdst != 0)
333*0Sstevel@tonic-gate 		dst_secs = 3600;
334*0Sstevel@tonic-gate 	else
335*0Sstevel@tonic-gate 		dst_secs = 0;
336*0Sstevel@tonic-gate 	daystart = (a->ac_btime - timezone + dst_secs) -
337*0Sstevel@tonic-gate 	    ((a->ac_btime - timezone + dst_secs) % SECSINDAY);
338*0Sstevel@tonic-gate 	if (Sflg) {
339*0Sstevel@tonic-gate 		ts_a = tstrt_a + daystart - dst_secs;
340*0Sstevel@tonic-gate 		cftime(time_buf, DATE_FMT, &ts_a);
341*0Sstevel@tonic-gate 		fprintf(stdout, "START AFT: %s", time_buf);
342*0Sstevel@tonic-gate 	}
343*0Sstevel@tonic-gate 	if (eflg) {
344*0Sstevel@tonic-gate 		ts_b = tstrt_b + daystart - dst_secs;
345*0Sstevel@tonic-gate 		cftime(time_buf, DATE_FMT, &ts_b);
346*0Sstevel@tonic-gate 		fprintf(stdout, "START BEF: %s", time_buf);
347*0Sstevel@tonic-gate 	}
348*0Sstevel@tonic-gate 	if (sflg) {
349*0Sstevel@tonic-gate 		te_a = tend_a + daystart - dst_secs;
350*0Sstevel@tonic-gate 		cftime(time_buf, DATE_FMT, &te_a);
351*0Sstevel@tonic-gate 		fprintf(stdout, "END AFTER: %s", time_buf);
352*0Sstevel@tonic-gate 	}
353*0Sstevel@tonic-gate 	if (Eflg) {
354*0Sstevel@tonic-gate 		te_b = tend_b + daystart - dst_secs;
355*0Sstevel@tonic-gate 		cftime(time_buf, DATE_FMT, &te_b);
356*0Sstevel@tonic-gate 		fprintf(stdout, "END BEFOR: %s", time_buf);
357*0Sstevel@tonic-gate 	}
358*0Sstevel@tonic-gate 	if(ts_a) {
359*0Sstevel@tonic-gate 		if (te_b && ts_a > te_b) te_b += SECSINDAY;
360*0Sstevel@tonic-gate 	}
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate 	while(aread(ver) != 0) {
363*0Sstevel@tonic-gate 		elapsed = expand(a->ac_etime);
364*0Sstevel@tonic-gate 		etime = (ulong_t)a->ac_btime + (ulong_t)SECS(elapsed);
365*0Sstevel@tonic-gate 		if(ts_a || ts_b || te_a || te_b) {
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 			if(te_a && (etime < te_a)) {
368*0Sstevel@tonic-gate 				if(backward) return;
369*0Sstevel@tonic-gate 				else continue;
370*0Sstevel@tonic-gate 			}
371*0Sstevel@tonic-gate 			if(te_b && (etime > te_b)) {
372*0Sstevel@tonic-gate 				if(backward) continue;
373*0Sstevel@tonic-gate 				else return;
374*0Sstevel@tonic-gate 			}
375*0Sstevel@tonic-gate 			if(ts_a && (a->ac_btime < ts_a))
376*0Sstevel@tonic-gate 				continue;
377*0Sstevel@tonic-gate 			if(ts_b && (a->ac_btime > ts_b))
378*0Sstevel@tonic-gate 				continue;
379*0Sstevel@tonic-gate 		}
380*0Sstevel@tonic-gate 		if(!MYKIND(a->ac_flag))
381*0Sstevel@tonic-gate 			continue;
382*0Sstevel@tonic-gate 		if(su_user && !SU(a->ac_flag))
383*0Sstevel@tonic-gate 			continue;
384*0Sstevel@tonic-gate 		sys = expand(a->ac_stime);
385*0Sstevel@tonic-gate 		user = expand(a->ac_utime);
386*0Sstevel@tonic-gate 		cpu = sys + user;
387*0Sstevel@tonic-gate 		if(cpu == 0)
388*0Sstevel@tonic-gate 			cpu = 1;
389*0Sstevel@tonic-gate 		mem = expand(a->ac_mem);
390*0Sstevel@tonic-gate 		(void) strncpy(command_name, a->ac_comm, 8);
391*0Sstevel@tonic-gate 		io=expand(a->ac_io);
392*0Sstevel@tonic-gate 		rw=expand(a->ac_rw);
393*0Sstevel@tonic-gate 		if(cpucut && cpucut >= SECS(cpu))
394*0Sstevel@tonic-gate 			continue;
395*0Sstevel@tonic-gate 		if(syscut && syscut >= SECS(sys))
396*0Sstevel@tonic-gate 			continue;
397*0Sstevel@tonic-gate #ifdef uts
398*0Sstevel@tonic-gate 		if(linedev != 0xffff && a->ac_tty != linedev)
399*0Sstevel@tonic-gate 			continue;
400*0Sstevel@tonic-gate #else
401*0Sstevel@tonic-gate 		if(linedev != (dev_t)-1 && a->ac_tty != linedev)
402*0Sstevel@tonic-gate 			continue;
403*0Sstevel@tonic-gate #endif
404*0Sstevel@tonic-gate 		if(uidflag && a->ac_uid != uidval)
405*0Sstevel@tonic-gate 			continue;
406*0Sstevel@tonic-gate 		if(gidflag && a->ac_gid != gidval)
407*0Sstevel@tonic-gate 			continue;
408*0Sstevel@tonic-gate 		if(cname && !cmatch(a->ac_comm,cname))
409*0Sstevel@tonic-gate 			continue;
410*0Sstevel@tonic-gate 		if(iocut && iocut > io)
411*0Sstevel@tonic-gate 			continue;
412*0Sstevel@tonic-gate 		if(unkid && uidtonam(a->ac_uid)[0] != '?')
413*0Sstevel@tonic-gate 			continue;
414*0Sstevel@tonic-gate 		if(verbose && (fileout == 0)) {
415*0Sstevel@tonic-gate 			printhd();
416*0Sstevel@tonic-gate 			verbose = 0;
417*0Sstevel@tonic-gate 		}
418*0Sstevel@tonic-gate 		if(elapsed == 0)
419*0Sstevel@tonic-gate 			elapsed++;
420*0Sstevel@tonic-gate 		if(hogcut && hogcut >= (double)cpu/(double)elapsed)
421*0Sstevel@tonic-gate 			continue;
422*0Sstevel@tonic-gate 		if(fileout)
423*0Sstevel@tonic-gate 			fwrite(&ab, sizeof(ab), 1, ostrm);
424*0Sstevel@tonic-gate 		else
425*0Sstevel@tonic-gate 			println();
426*0Sstevel@tonic-gate 		if(average) {
427*0Sstevel@tonic-gate 			cmdcount++;
428*0Sstevel@tonic-gate 			realtot += (double)elapsed;
429*0Sstevel@tonic-gate 			usertot += (double)user;
430*0Sstevel@tonic-gate 			systot += (double)sys;
431*0Sstevel@tonic-gate 			kcoretot += (double)mem;
432*0Sstevel@tonic-gate 			iotot += (double)io;
433*0Sstevel@tonic-gate 			rwtot += (double)rw;
434*0Sstevel@tonic-gate 		};
435*0Sstevel@tonic-gate 	}
436*0Sstevel@tonic-gate }
437*0Sstevel@tonic-gate 
438*0Sstevel@tonic-gate aread(ver)
439*0Sstevel@tonic-gate int ver;
440*0Sstevel@tonic-gate {
441*0Sstevel@tonic-gate 	static	 ok = 1;
442*0Sstevel@tonic-gate 	struct o_acct oab;
443*0Sstevel@tonic-gate 	int ret;
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 	if (ver != 2) {
446*0Sstevel@tonic-gate 		if ((ret = fread((char *)&oab, sizeof(struct o_acct), 1, stdin)) == 1){
447*0Sstevel@tonic-gate 			/* copy SVR3 acct struct to SVR4 acct struct */
448*0Sstevel@tonic-gate 			ab.ac_flag = oab.ac_flag | AEXPND;
449*0Sstevel@tonic-gate 			ab.ac_stat = oab.ac_stat;
450*0Sstevel@tonic-gate 			ab.ac_uid = (uid_t) oab.ac_uid;
451*0Sstevel@tonic-gate 			ab.ac_gid = (gid_t) oab.ac_gid;
452*0Sstevel@tonic-gate 			ab.ac_tty = (dev_t) oab.ac_tty;
453*0Sstevel@tonic-gate 			ab.ac_btime = oab.ac_btime;
454*0Sstevel@tonic-gate 			ab.ac_utime = oab.ac_utime;
455*0Sstevel@tonic-gate 			ab.ac_stime = oab.ac_stime;
456*0Sstevel@tonic-gate 			ab.ac_mem = oab.ac_mem;
457*0Sstevel@tonic-gate 			ab.ac_io = oab.ac_io;
458*0Sstevel@tonic-gate 			ab.ac_rw = oab.ac_rw;
459*0Sstevel@tonic-gate 			strcpy(ab.ac_comm, oab.ac_comm);
460*0Sstevel@tonic-gate 		}
461*0Sstevel@tonic-gate 	} else
462*0Sstevel@tonic-gate 		ret = fread((char *)&ab, sizeof(struct acct), 1, stdin);
463*0Sstevel@tonic-gate 
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate 	if(backward) {
466*0Sstevel@tonic-gate 		if(ok) {
467*0Sstevel@tonic-gate 			if(fseek(stdin,
468*0Sstevel@tonic-gate 				(long)(offset*(ver == 2 ? sizeof(struct acct) :
469*0Sstevel@tonic-gate 					sizeof(struct o_acct))), 1) != 0) {
470*0Sstevel@tonic-gate 
471*0Sstevel@tonic-gate 					rewind(stdin);	/* get 1st record */
472*0Sstevel@tonic-gate 					ok = 0;
473*0Sstevel@tonic-gate 			}
474*0Sstevel@tonic-gate 		} else
475*0Sstevel@tonic-gate 			ret = 0;
476*0Sstevel@tonic-gate 	}
477*0Sstevel@tonic-gate 	return(ret != 1 ? 0 : 1);
478*0Sstevel@tonic-gate }
479*0Sstevel@tonic-gate 
480*0Sstevel@tonic-gate printhd()
481*0Sstevel@tonic-gate {
482*0Sstevel@tonic-gate 	fprintf(stdout, "COMMAND                           START    END          REAL");
483*0Sstevel@tonic-gate 	ps("CPU");
484*0Sstevel@tonic-gate 	if(option & SEPTIME)
485*0Sstevel@tonic-gate 		ps("(SECS)");
486*0Sstevel@tonic-gate 	if(option & IORW){
487*0Sstevel@tonic-gate 		ps("CHARS");
488*0Sstevel@tonic-gate 		ps("BLOCKS");
489*0Sstevel@tonic-gate 	}
490*0Sstevel@tonic-gate 	if(option & CPUFACTOR)
491*0Sstevel@tonic-gate 		ps("CPU");
492*0Sstevel@tonic-gate 	if(option & HOGFACTOR)
493*0Sstevel@tonic-gate 		ps("HOG");
494*0Sstevel@tonic-gate 	if(!option || (option & MEANSIZE))
495*0Sstevel@tonic-gate 		ps("MEAN");
496*0Sstevel@tonic-gate 	if(option & KCOREMIN)
497*0Sstevel@tonic-gate 		ps("KCORE");
498*0Sstevel@tonic-gate 	fprintf(stdout, "\n");
499*0Sstevel@tonic-gate 	fprintf(stdout, "NAME       USER     TTYNAME       TIME     TIME       (SECS)");
500*0Sstevel@tonic-gate 	if(option & SEPTIME) {
501*0Sstevel@tonic-gate 		ps("SYS");
502*0Sstevel@tonic-gate 		ps("USER");
503*0Sstevel@tonic-gate 	} else
504*0Sstevel@tonic-gate 		ps("(SECS)");
505*0Sstevel@tonic-gate 	if(option & IORW) {
506*0Sstevel@tonic-gate 		ps("TRNSFD");
507*0Sstevel@tonic-gate 		ps("READ");
508*0Sstevel@tonic-gate 	}
509*0Sstevel@tonic-gate 	if(option & CPUFACTOR)
510*0Sstevel@tonic-gate 		ps("FACTOR");
511*0Sstevel@tonic-gate 	if(option & HOGFACTOR)
512*0Sstevel@tonic-gate 		ps("FACTOR");
513*0Sstevel@tonic-gate 	if(!option || (option & MEANSIZE))
514*0Sstevel@tonic-gate 		ps("SIZE(K)");
515*0Sstevel@tonic-gate 	if(option & KCOREMIN)
516*0Sstevel@tonic-gate 		ps("MIN");
517*0Sstevel@tonic-gate 	if(flag_field)
518*0Sstevel@tonic-gate 		fprintf(stdout, "  F STAT");
519*0Sstevel@tonic-gate 	fprintf(stdout, "\n");
520*0Sstevel@tonic-gate 	fflush(stdout);
521*0Sstevel@tonic-gate }
522*0Sstevel@tonic-gate 
523*0Sstevel@tonic-gate println()
524*0Sstevel@tonic-gate {
525*0Sstevel@tonic-gate 	char name[32];
526*0Sstevel@tonic-gate 	register struct acct *a = &ab;
527*0Sstevel@tonic-gate 	time_t t;
528*0Sstevel@tonic-gate 
529*0Sstevel@tonic-gate 	if(quiet)
530*0Sstevel@tonic-gate 		return;
531*0Sstevel@tonic-gate 	if(!SU(a->ac_flag))
532*0Sstevel@tonic-gate 		strcpy(name,command_name);
533*0Sstevel@tonic-gate 	else {
534*0Sstevel@tonic-gate 		strcpy(name,"#");
535*0Sstevel@tonic-gate 		strcat(name,command_name);
536*0Sstevel@tonic-gate 	}
537*0Sstevel@tonic-gate 	fprintf(stdout, "%-*.*s", (OUTPUT_NSZ + 1),
538*0Sstevel@tonic-gate 	    (OUTPUT_NSZ + 1), name);
539*0Sstevel@tonic-gate 	strcpy(name,uidtonam(a->ac_uid));
540*0Sstevel@tonic-gate 	if(*name != '?')
541*0Sstevel@tonic-gate 		fprintf(stdout, "  %-*.*s", (OUTPUT_NSZ + 1),
542*0Sstevel@tonic-gate 		    (OUTPUT_NSZ + 1), name);
543*0Sstevel@tonic-gate 	else
544*0Sstevel@tonic-gate 		fprintf(stdout, "  %-9d",a->ac_uid);
545*0Sstevel@tonic-gate #ifdef uts
546*0Sstevel@tonic-gate 	fprintf(stdout, " %-*.*s", OUTPUT_LSZ, OUTPUT_LSZ,
547*0Sstevel@tonic-gate 	    a->ac_tty != 0xffff? devtolin(a->ac_tty):"?");
548*0Sstevel@tonic-gate #else
549*0Sstevel@tonic-gate 	fprintf(stdout, " %-*.*s", OUTPUT_LSZ, OUTPUT_LSZ,
550*0Sstevel@tonic-gate 	    a->ac_tty != (dev_t)-1? devtolin(a->ac_tty):"?");
551*0Sstevel@tonic-gate #endif
552*0Sstevel@tonic-gate 	t = a->ac_btime;
553*0Sstevel@tonic-gate 	cftime(time_buf, DATE_FMT1, &t);
554*0Sstevel@tonic-gate 	fprintf(stdout, "%.9s", time_buf);
555*0Sstevel@tonic-gate 	cftime(time_buf, DATE_FMT1, (time_t *)&etime);
556*0Sstevel@tonic-gate 	fprintf(stdout, "%.9s ", time_buf);
557*0Sstevel@tonic-gate 	pf((double)SECS(elapsed));
558*0Sstevel@tonic-gate 	if(option & SEPTIME) {
559*0Sstevel@tonic-gate 		pf((double)sys / HZ);
560*0Sstevel@tonic-gate 		pf((double)user / HZ);
561*0Sstevel@tonic-gate 	} else
562*0Sstevel@tonic-gate 		pf((double)cpu / HZ);
563*0Sstevel@tonic-gate 	if(option & IORW)
564*0Sstevel@tonic-gate 		fprintf(stdout, io < 100000000 ? "%8ld%8ld" : "%12ld%8ld",io,rw);
565*0Sstevel@tonic-gate 	if(option & CPUFACTOR)
566*0Sstevel@tonic-gate 		pf((double)user / cpu);
567*0Sstevel@tonic-gate 	if(option & HOGFACTOR)
568*0Sstevel@tonic-gate 		pf((double)cpu / elapsed);
569*0Sstevel@tonic-gate 	if(!option || (option & MEANSIZE))
570*0Sstevel@tonic-gate 		pf(KCORE(mem / cpu));
571*0Sstevel@tonic-gate 	if(option & KCOREMIN)
572*0Sstevel@tonic-gate 		pf(MINT(KCORE(mem)));
573*0Sstevel@tonic-gate 	if(flag_field)
574*0Sstevel@tonic-gate 		fprintf(stdout, "  %1o %3o", (unsigned char) a->ac_flag,
575*0Sstevel@tonic-gate 						(unsigned char) a->ac_stat);
576*0Sstevel@tonic-gate 	fprintf(stdout, "\n");
577*0Sstevel@tonic-gate }
578*0Sstevel@tonic-gate 
579*0Sstevel@tonic-gate /*
580*0Sstevel@tonic-gate  * convtime converts time arg to internal value
581*0Sstevel@tonic-gate  * arg has form hr:min:sec, min or sec are assumed to be 0 if omitted
582*0Sstevel@tonic-gate  */
583*0Sstevel@tonic-gate long
584*0Sstevel@tonic-gate convtime(str)
585*0Sstevel@tonic-gate char *str;
586*0Sstevel@tonic-gate {
587*0Sstevel@tonic-gate 	long	hr, min, sec;
588*0Sstevel@tonic-gate 
589*0Sstevel@tonic-gate 	min = sec = 0;
590*0Sstevel@tonic-gate 
591*0Sstevel@tonic-gate 	if(sscanf(str, "%ld:%ld:%ld", &hr, &min, &sec) < 1) {
592*0Sstevel@tonic-gate 		fatal("acctcom: bad time:", str);
593*0Sstevel@tonic-gate 	}
594*0Sstevel@tonic-gate 	tzset();
595*0Sstevel@tonic-gate 	sec += (min*60);
596*0Sstevel@tonic-gate 	sec += (hr*3600);
597*0Sstevel@tonic-gate 	return(sec + timezone);
598*0Sstevel@tonic-gate }
599*0Sstevel@tonic-gate 
600*0Sstevel@tonic-gate cmatch(comm, cstr)
601*0Sstevel@tonic-gate register char	*comm, *cstr;
602*0Sstevel@tonic-gate {
603*0Sstevel@tonic-gate 
604*0Sstevel@tonic-gate 	char	xcomm[9];
605*0Sstevel@tonic-gate 	register i;
606*0Sstevel@tonic-gate 
607*0Sstevel@tonic-gate 	for(i=0;i<8;i++){
608*0Sstevel@tonic-gate 		if(comm[i]==' '||comm[i]=='\0')
609*0Sstevel@tonic-gate 			break;
610*0Sstevel@tonic-gate 		xcomm[i] = comm[i];
611*0Sstevel@tonic-gate 	}
612*0Sstevel@tonic-gate 	xcomm[i] = '\0';
613*0Sstevel@tonic-gate 
614*0Sstevel@tonic-gate 	return(regex(cstr,xcomm));
615*0Sstevel@tonic-gate }
616*0Sstevel@tonic-gate 
617*0Sstevel@tonic-gate cmset(pattern)
618*0Sstevel@tonic-gate register char	*pattern;
619*0Sstevel@tonic-gate {
620*0Sstevel@tonic-gate 
621*0Sstevel@tonic-gate 	if((pattern=(char *)regcmp(pattern,(char *)0))==NULL){
622*0Sstevel@tonic-gate 		fatal("pattern syntax", NULL);
623*0Sstevel@tonic-gate 	}
624*0Sstevel@tonic-gate 
625*0Sstevel@tonic-gate 	return((unsigned)pattern);
626*0Sstevel@tonic-gate }
627*0Sstevel@tonic-gate 
628*0Sstevel@tonic-gate doexit(status)
629*0Sstevel@tonic-gate {
630*0Sstevel@tonic-gate 	if(!average)
631*0Sstevel@tonic-gate 		exit(status);
632*0Sstevel@tonic-gate 	if(cmdcount) {
633*0Sstevel@tonic-gate 		fprintf(stdout, "cmds=%ld ",cmdcount);
634*0Sstevel@tonic-gate 		fprintf(stdout, "Real=%-6.2f ",SECS(realtot)/cmdcount);
635*0Sstevel@tonic-gate 		cputot = systot + usertot;
636*0Sstevel@tonic-gate 		fprintf(stdout, "CPU=%-6.2f ",SECS(cputot)/cmdcount);
637*0Sstevel@tonic-gate 		fprintf(stdout, "USER=%-6.2f ",SECS(usertot)/cmdcount);
638*0Sstevel@tonic-gate 		fprintf(stdout, "SYS=%-6.2f ",SECS(systot)/cmdcount);
639*0Sstevel@tonic-gate 		fprintf(stdout, "CHAR=%-8.2f ",iotot/cmdcount);
640*0Sstevel@tonic-gate 		fprintf(stdout, "BLK=%-8.2f ",rwtot/cmdcount);
641*0Sstevel@tonic-gate 		fprintf(stdout, "USR/TOT=%-4.2f ",usertot/cputot);
642*0Sstevel@tonic-gate 		fprintf(stdout, "HOG=%-4.2f ",cputot/realtot);
643*0Sstevel@tonic-gate 		fprintf(stdout, "\n");
644*0Sstevel@tonic-gate 	}
645*0Sstevel@tonic-gate 	else
646*0Sstevel@tonic-gate 		fprintf(stdout, "\nNo commands matched\n");
647*0Sstevel@tonic-gate 	exit(status);
648*0Sstevel@tonic-gate }
649*0Sstevel@tonic-gate isdevnull()
650*0Sstevel@tonic-gate {
651*0Sstevel@tonic-gate 	struct stat	filearg;
652*0Sstevel@tonic-gate 	struct stat	devnull;
653*0Sstevel@tonic-gate 
654*0Sstevel@tonic-gate 	if(fstat(0,&filearg) == -1) {
655*0Sstevel@tonic-gate 		fprintf(stderr,"acctcom: cannot stat stdin\n");
656*0Sstevel@tonic-gate 		return(NULL);
657*0Sstevel@tonic-gate 	}
658*0Sstevel@tonic-gate 	if(stat("/dev/null",&devnull) == -1) {
659*0Sstevel@tonic-gate 		fprintf(stderr,"acctcom: cannot stat /dev/null\n");
660*0Sstevel@tonic-gate 		return(NULL);
661*0Sstevel@tonic-gate 	}
662*0Sstevel@tonic-gate 
663*0Sstevel@tonic-gate 	if(filearg.st_rdev == devnull.st_rdev) return(1);
664*0Sstevel@tonic-gate 	else return(NULL);
665*0Sstevel@tonic-gate }
666*0Sstevel@tonic-gate 
667*0Sstevel@tonic-gate fatal(s1, s2)
668*0Sstevel@tonic-gate char *s1, *s2;
669*0Sstevel@tonic-gate {
670*0Sstevel@tonic-gate 	fprintf(stderr,"acctcom: %s %s\n", s1, (s2 ? s2 : ""));
671*0Sstevel@tonic-gate 	exit(1);
672*0Sstevel@tonic-gate }
673*0Sstevel@tonic-gate 
674*0Sstevel@tonic-gate usage()
675*0Sstevel@tonic-gate {
676*0Sstevel@tonic-gate 	fprintf(stderr, "Usage: acctcom [options] [files]\n");
677*0Sstevel@tonic-gate 	fprintf(stderr, "\nWhere options can be:\n");
678*0Sstevel@tonic-gate 	diag("-b	read backwards through file");
679*0Sstevel@tonic-gate 	diag("-f	print the fork/exec flag and exit status");
680*0Sstevel@tonic-gate 	diag("-h	print hog factor (total-CPU-time/elapsed-time)");
681*0Sstevel@tonic-gate 	diag("-i	print I/O counts");
682*0Sstevel@tonic-gate 	diag("-k	show total Kcore minutes instead of memory size");
683*0Sstevel@tonic-gate 	diag("-m	show mean memory size");
684*0Sstevel@tonic-gate 	diag("-r	show CPU factor (user-time/(sys-time + user-time))");
685*0Sstevel@tonic-gate 	diag("-t	show separate system and user CPU times");
686*0Sstevel@tonic-gate 	diag("-v	don't print column headings");
687*0Sstevel@tonic-gate 	diag("-a	print average statistics of selected commands");
688*0Sstevel@tonic-gate 	diag("-q	print average statistics only");
689*0Sstevel@tonic-gate 	diag("-l line	\tshow processes belonging to terminal /dev/line");
690*0Sstevel@tonic-gate 	diag("-u user	\tshow processes belonging to user name or user ID");
691*0Sstevel@tonic-gate 	diag("-u #	\tshow processes executed by super-user");
692*0Sstevel@tonic-gate 	diag("-u ?	\tshow processes executed by unknown UID's");
693*0Sstevel@tonic-gate 	diag("-g group	show processes belonging to group name of group ID");
694*0Sstevel@tonic-gate 	diag("-s time	\tshow processes ending after time (hh[:mm[:ss]])");
695*0Sstevel@tonic-gate 	diag("-e time	\tshow processes starting before time");
696*0Sstevel@tonic-gate 	diag("-S time	\tshow processes starting after time");
697*0Sstevel@tonic-gate 	diag("-E time	\tshow processes ending before time");
698*0Sstevel@tonic-gate 	diag("-n regex	select commands matching the ed(1) regular expression");
699*0Sstevel@tonic-gate 	diag("-o file	\tdo not print, put selected pacct records into file");
700*0Sstevel@tonic-gate 	diag("-H factor	show processes that exceed hog factor");
701*0Sstevel@tonic-gate 	diag("-O sec	\tshow processes that exceed CPU system time sec");
702*0Sstevel@tonic-gate 	diag("-C sec	\tshow processes that exceed total CPU time sec");
703*0Sstevel@tonic-gate 	diag("-I chars	show processes that transfer more than char chars");
704*0Sstevel@tonic-gate }
705