4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 #pragma ident "%Z%%M% %I% %E% SMI"
36 #include <sys/types.h>
37 #include <sys/param.h>
48 char command_name
[16];
50 static char time_buf
[50];
64 extern int daylight
; /* daylight savings time if set */
88 unkid
, /*user doesn't have login on this machine*/
99 dev_t linedev
= 0xffff; /* changed from -1, as dev_t is now ushort */
101 dev_t linedev
= (dev_t
)-1;
105 char *cname
= NULL
; /* command name pattern to match*/
107 struct passwd
*getpwnam(), *getpwuid(), *pw
;
108 struct group
*getgrnam(),*grp
;
123 void doexit(int) __NORETURN
;
125 void fatal(char *, char *);
133 main(int argc
, char **argv
)
137 (void)setlocale(LC_ALL
, "");
139 while((c
= getopt(argc
, argv
,
140 "C:E:H:I:O:S:abe:fg:hikl:mn:o:qrs:tu:v")) != EOF
) {
143 sscanf(optarg
,"%lf",&cpucut
);
146 sscanf(optarg
,"%lf",&syscut
);
149 sscanf(optarg
,"%lf",&hogcut
);
152 sscanf(optarg
,"%lf",&iocut
);
161 if(sscanf(optarg
,"%ld",&gidval
) == 1) {
162 if (getgrgid(gidval
) == NULL
)
163 fatal("Unknown group", optarg
);
164 } else if((grp
=getgrnam(optarg
)) == NULL
)
165 fatal("Unknown group", optarg
);
195 linedev
= lintodev(optarg
);
208 if((pw
= getpwnam(optarg
)) == NULL
) {
209 uidval
= (uid_t
)atoi(optarg
);
210 /* atoi will return 0 in abnormal situation */
211 if (uidval
== 0 && strcmp(optarg
, "0") != 0) {
212 fprintf(stderr
, "%s: Unknown user %s\n", argv
[0], optarg
);
215 if ((pw
= getpwuid(uidval
)) == NULL
) {
216 fprintf(stderr
, "%s: Unknown user %s\n", argv
[0], optarg
);
232 tend_a
= convtime(optarg
);
236 tstrt_a
= convtime(optarg
);
243 tstrt_b
= convtime(optarg
);
247 tend_b
= convtime(optarg
);
252 if((ostrm
= fopen(ofile
, "w")) == NULL
) {
253 perror("open error on output file");
269 argv
= &argv
[optind
];
270 while(optind
++ < argc
) {
271 dofile(*argv
++); /* change from *argv */
276 if(isatty(0) || isdevnull())
280 backward
= offset
= 0;
291 struct acct
*a
= &ab
;
300 int ver
; /* version of acct structure */
301 int dst_secs
; /* number of seconds to adjust
302 for daylight savings time */
305 if(freopen(fname
, "r", stdin
) == NULL
) {
306 fprintf(stderr
, "acctcom: cannot open %s\n", fname
);
310 if (fread((char *)&ab
, sizeof(struct acct
), 1, stdin
) != 1)
312 else if (ab
.ac_flag
& AEXPND
)
313 ver
= 2; /* 4.0 acct structure */
315 ver
= 1; /* 3.x acct structure */
322 nsize
= sizeof(struct acct
); /* make sure offset is signed */
324 nsize
= sizeof(struct o_acct
); /* make sure offset is signed */
325 fseek(stdin
, (long)(-nsize
), 2);
328 daydiff
= a
->ac_btime
- (a
->ac_btime
% SECSINDAY
);
330 t
= localtime(&curtime
);
331 if (daydiff
< (curtime
- (curtime
% SECSINDAY
))) {
334 * it is older than today
336 t
= (time_t)a
->ac_btime
;
337 cftime(time_buf
, DATE_FMT
, &t
);
338 fprintf(stdout
, "\nACCOUNTING RECORDS FROM: %s", time_buf
);
341 /* adjust time by one hour for daylight savings time */
342 if (daylight
&& t
->tm_isdst
!= 0)
346 daystart
= (a
->ac_btime
- timezone
+ dst_secs
) -
347 ((a
->ac_btime
- timezone
+ dst_secs
) % SECSINDAY
);
349 ts_a
= tstrt_a
+ daystart
- dst_secs
;
350 cftime(time_buf
, DATE_FMT
, &ts_a
);
351 fprintf(stdout
, "START AFT: %s", time_buf
);
354 ts_b
= tstrt_b
+ daystart
- dst_secs
;
355 cftime(time_buf
, DATE_FMT
, &ts_b
);
356 fprintf(stdout
, "START BEF: %s", time_buf
);
359 te_a
= tend_a
+ daystart
- dst_secs
;
360 cftime(time_buf
, DATE_FMT
, &te_a
);
361 fprintf(stdout
, "END AFTER: %s", time_buf
);
364 te_b
= tend_b
+ daystart
- dst_secs
;
365 cftime(time_buf
, DATE_FMT
, &te_b
);
366 fprintf(stdout
, "END BEFOR: %s", time_buf
);
369 if (te_b
&& ts_a
> te_b
) te_b
+= SECSINDAY
;
372 while(aread(ver
) != 0) {
373 elapsed
= expand(a
->ac_etime
);
374 etime
= (ulong_t
)a
->ac_btime
+ (ulong_t
)SECS(elapsed
);
375 if(ts_a
|| ts_b
|| te_a
|| te_b
) {
377 if(te_a
&& (etime
< te_a
)) {
381 if(te_b
&& (etime
> te_b
)) {
382 if(backward
) continue;
385 if(ts_a
&& (a
->ac_btime
< ts_a
))
387 if(ts_b
&& (a
->ac_btime
> ts_b
))
390 if(!MYKIND(a
->ac_flag
))
392 if(su_user
&& !SU(a
->ac_flag
))
394 sys
= expand(a
->ac_stime
);
395 user
= expand(a
->ac_utime
);
399 mem
= expand(a
->ac_mem
);
400 (void) strncpy(command_name
, a
->ac_comm
, 8);
403 if(cpucut
&& cpucut
>= SECS(cpu
))
405 if(syscut
&& syscut
>= SECS(sys
))
408 if(linedev
!= 0xffff && a
->ac_tty
!= linedev
)
411 if(linedev
!= (dev_t
)-1 && a
->ac_tty
!= linedev
)
414 if(uidflag
&& a
->ac_uid
!= uidval
)
416 if(gidflag
&& a
->ac_gid
!= gidval
)
418 if(cname
&& !cmatch(a
->ac_comm
,cname
))
420 if(iocut
&& iocut
> io
)
422 if(unkid
&& uidtonam(a
->ac_uid
)[0] != '?')
424 if(verbose
&& (fileout
== 0)) {
430 if(hogcut
&& hogcut
>= (double)cpu
/(double)elapsed
)
433 fwrite(&ab
, sizeof(ab
), 1, ostrm
);
438 realtot
+= (double)elapsed
;
439 usertot
+= (double)user
;
440 systot
+= (double)sys
;
441 kcoretot
+= (double)mem
;
456 if ((ret
= fread((char *)&oab
, sizeof(struct o_acct
), 1, stdin
)) == 1){
457 /* copy SVR3 acct struct to SVR4 acct struct */
458 ab
.ac_flag
= oab
.ac_flag
| AEXPND
;
459 ab
.ac_stat
= oab
.ac_stat
;
460 ab
.ac_uid
= (uid_t
) oab
.ac_uid
;
461 ab
.ac_gid
= (gid_t
) oab
.ac_gid
;
462 ab
.ac_tty
= (dev_t
) oab
.ac_tty
;
463 ab
.ac_btime
= oab
.ac_btime
;
464 ab
.ac_utime
= oab
.ac_utime
;
465 ab
.ac_stime
= oab
.ac_stime
;
466 ab
.ac_mem
= oab
.ac_mem
;
467 ab
.ac_io
= oab
.ac_io
;
468 ab
.ac_rw
= oab
.ac_rw
;
469 strcpy(ab
.ac_comm
, oab
.ac_comm
);
472 ret
= fread((char *)&ab
, sizeof(struct acct
), 1, stdin
);
478 (long)(offset
*(ver
== 2 ? sizeof(struct acct
) :
479 sizeof(struct o_acct
))), 1) != 0) {
481 rewind(stdin
); /* get 1st record */
487 return(ret
!= 1 ? 0 : 1);
493 fprintf(stdout
, "COMMAND START END REAL");
501 if(option
& CPUFACTOR
)
503 if(option
& HOGFACTOR
)
505 if(!option
|| (option
& MEANSIZE
))
507 if(option
& KCOREMIN
)
509 fprintf(stdout
, "\n");
510 fprintf(stdout
, "NAME USER TTYNAME TIME TIME (SECS)");
511 if(option
& SEPTIME
) {
520 if(option
& CPUFACTOR
)
522 if(option
& HOGFACTOR
)
524 if(!option
|| (option
& MEANSIZE
))
526 if(option
& KCOREMIN
)
529 fprintf(stdout
, " F STAT");
530 fprintf(stdout
, "\n");
538 struct acct
*a
= &ab
;
544 strcpy(name
,command_name
);
547 strcat(name
,command_name
);
549 fprintf(stdout
, "%-*.*s", (OUTPUT_NSZ
+ 1),
550 (OUTPUT_NSZ
+ 1), name
);
551 strcpy(name
,uidtonam(a
->ac_uid
));
553 fprintf(stdout
, " %-*.*s", (OUTPUT_NSZ
+ 1),
554 (OUTPUT_NSZ
+ 1), name
);
556 fprintf(stdout
, " %-9d",a
->ac_uid
);
558 fprintf(stdout
, " %-*.*s", OUTPUT_LSZ
, OUTPUT_LSZ
,
559 a
->ac_tty
!= 0xffff? devtolin(a
->ac_tty
):"?");
561 fprintf(stdout
, " %-*.*s", OUTPUT_LSZ
, OUTPUT_LSZ
,
562 a
->ac_tty
!= (dev_t
)-1? devtolin(a
->ac_tty
):"?");
565 cftime(time_buf
, DATE_FMT1
, &t
);
566 fprintf(stdout
, "%.9s", time_buf
);
567 cftime(time_buf
, DATE_FMT1
, (time_t *)&etime
);
568 fprintf(stdout
, "%.9s ", time_buf
);
569 pf((double)SECS(elapsed
));
570 if(option
& SEPTIME
) {
571 pf((double)sys
/ HZ
);
572 pf((double)user
/ HZ
);
574 pf((double)cpu
/ HZ
);
576 fprintf(stdout
, io
< 100000000 ? "%8ld%8ld" : "%12ld%8ld",io
,rw
);
577 if(option
& CPUFACTOR
)
578 pf((double)user
/ cpu
);
579 if(option
& HOGFACTOR
)
580 pf((double)cpu
/ elapsed
);
581 if(!option
|| (option
& MEANSIZE
))
582 pf(KCORE(mem
/ cpu
));
583 if(option
& KCOREMIN
)
584 pf(MINT(KCORE(mem
)));
586 fprintf(stdout
, " %1o %3o", (unsigned char) a
->ac_flag
,
587 (unsigned char) a
->ac_stat
);
588 fprintf(stdout
, "\n");
592 * convtime converts time arg to internal value
593 * arg has form hr:min:sec, min or sec are assumed to be 0 if omitted
603 if(sscanf(str
, "%ld:%ld:%ld", &hr
, &min
, &sec
) < 1) {
604 fatal("acctcom: bad time:", str
);
609 return(sec
+ timezone
);
613 cmatch(char *comm
, char *cstr
)
620 if(comm
[i
]==' '||comm
[i
]=='\0')
626 return (regex(cstr
,xcomm
) ? 1 : 0);
633 if((pattern
=(char *)regcmp(pattern
,(char *)0))==NULL
){
634 fatal("pattern syntax", NULL
);
646 fprintf(stdout
, "cmds=%ld ",cmdcount
);
647 fprintf(stdout
, "Real=%-6.2f ",SECS(realtot
)/cmdcount
);
648 cputot
= systot
+ usertot
;
649 fprintf(stdout
, "CPU=%-6.2f ",SECS(cputot
)/cmdcount
);
650 fprintf(stdout
, "USER=%-6.2f ",SECS(usertot
)/cmdcount
);
651 fprintf(stdout
, "SYS=%-6.2f ",SECS(systot
)/cmdcount
);
652 fprintf(stdout
, "CHAR=%-8.2f ",iotot
/cmdcount
);
653 fprintf(stdout
, "BLK=%-8.2f ",rwtot
/cmdcount
);
654 fprintf(stdout
, "USR/TOT=%-4.2f ",usertot
/cputot
);
655 fprintf(stdout
, "HOG=%-4.2f ",cputot
/realtot
);
656 fprintf(stdout
, "\n");
659 fprintf(stdout
, "\nNo commands matched\n");
669 if(fstat(0,&filearg
) == -1) {
670 fprintf(stderr
,"acctcom: cannot stat stdin\n");
673 if(stat("/dev/null",&devnull
) == -1) {
674 fprintf(stderr
,"acctcom: cannot stat /dev/null\n");
678 if (filearg
.st_rdev
== devnull
.st_rdev
)
685 fatal(char *s1
, char *s2
)
687 fprintf(stderr
,"acctcom: %s %s\n", s1
, (s2
? s2
: ""));
694 fprintf(stderr
, "Usage: acctcom [options] [files]\n");
695 fprintf(stderr
, "\nWhere options can be:\n");
696 diag("-b read backwards through file");
697 diag("-f print the fork/exec flag and exit status");
698 diag("-h print hog factor (total-CPU-time/elapsed-time)");
699 diag("-i print I/O counts");
700 diag("-k show total Kcore minutes instead of memory size");
701 diag("-m show mean memory size");
702 diag("-r show CPU factor (user-time/(sys-time + user-time))");
703 diag("-t show separate system and user CPU times");
704 diag("-v don't print column headings");
705 diag("-a print average statistics of selected commands");
706 diag("-q print average statistics only");
707 diag("-l line \tshow processes belonging to terminal /dev/line");
708 diag("-u user \tshow processes belonging to user name or user ID");
709 diag("-u # \tshow processes executed by super-user");
710 diag("-u ? \tshow processes executed by unknown UID's");
711 diag("-g group show processes belonging to group name of group ID");
712 diag("-s time \tshow processes ending after time (hh[:mm[:ss]])");
713 diag("-e time \tshow processes starting before time");
714 diag("-S time \tshow processes starting after time");
715 diag("-E time \tshow processes ending before time");
716 diag("-n regex select commands matching the ed(1) regular expression");
717 diag("-o file \tdo not print, put selected pacct records into file");
718 diag("-H factor show processes that exceed hog factor");
719 diag("-O sec \tshow processes that exceed CPU system time sec");
720 diag("-C sec \tshow processes that exceed total CPU time sec");
721 diag("-I chars show processes that transfer more than char chars");