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