xref: /illumos-gate/usr/src/cmd/lastcomm/lc_exacct.c (revision 2a8bcb4efb45d99ac41c94a75c396b362c414f7f)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
28*7c478bd9Sstevel@tonic-gate #include <errno.h>
29*7c478bd9Sstevel@tonic-gate #include "lastcomm.h"
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate /* ARGSUSED1 */
32*7c478bd9Sstevel@tonic-gate static void
skip_group(ea_file_t * ef,uint_t nobjs)33*7c478bd9Sstevel@tonic-gate skip_group(ea_file_t *ef, uint_t nobjs)
34*7c478bd9Sstevel@tonic-gate {
35*7c478bd9Sstevel@tonic-gate 	ea_object_t curr_obj;
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate 	if (ea_previous_object(ef, &curr_obj) == -1) {
38*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("lastcomm: "
39*7c478bd9Sstevel@tonic-gate 		    "corrupted exacct file\n"));
40*7c478bd9Sstevel@tonic-gate 		exit(1);
41*7c478bd9Sstevel@tonic-gate 	}
42*7c478bd9Sstevel@tonic-gate }
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate static int
ok(int argc,char * argv[],int index,uid_t uid,dev_t tty,char * command)45*7c478bd9Sstevel@tonic-gate ok(int argc, char *argv[], int index, uid_t uid, dev_t tty, char *command)
46*7c478bd9Sstevel@tonic-gate {
47*7c478bd9Sstevel@tonic-gate 	int j;
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate 	for (j = index; j < argc; j++)
50*7c478bd9Sstevel@tonic-gate 		if (strcmp(getname(uid), argv[j]) &&
51*7c478bd9Sstevel@tonic-gate 		    strcmp(getdev(tty), argv[j]) &&
52*7c478bd9Sstevel@tonic-gate 		    strncmp(command, argv[j], fldsiz(acct, ac_comm)))
53*7c478bd9Sstevel@tonic-gate 			break;
54*7c478bd9Sstevel@tonic-gate 	return (j == argc);
55*7c478bd9Sstevel@tonic-gate }
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate static void
disp_group(ea_file_t * ef,uint_t nobjs,int argc,char * argv[],int index)58*7c478bd9Sstevel@tonic-gate disp_group(ea_file_t *ef, uint_t nobjs, int argc, char *argv[], int index)
59*7c478bd9Sstevel@tonic-gate {
60*7c478bd9Sstevel@tonic-gate 	uint_t i;
61*7c478bd9Sstevel@tonic-gate 	char *command = NULL;
62*7c478bd9Sstevel@tonic-gate 	double cpu_usr_secs = 0.;
63*7c478bd9Sstevel@tonic-gate 	double cpu_usr_nsecs = 0.;
64*7c478bd9Sstevel@tonic-gate 	double cpu_sys_secs = 0.;
65*7c478bd9Sstevel@tonic-gate 	double cpu_sys_nsecs = 0.;
66*7c478bd9Sstevel@tonic-gate 	double totalsecs;
67*7c478bd9Sstevel@tonic-gate 	dev_t tty = 0;
68*7c478bd9Sstevel@tonic-gate 	major_t tty_major = 0;
69*7c478bd9Sstevel@tonic-gate 	minor_t tty_minor = 0;
70*7c478bd9Sstevel@tonic-gate 	uid_t uid = 0;
71*7c478bd9Sstevel@tonic-gate 	time_t time = 0;
72*7c478bd9Sstevel@tonic-gate 	uint32_t flag = 0;
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < nobjs; i++) {
75*7c478bd9Sstevel@tonic-gate 		ea_object_t curr_obj;
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate 		if (ea_get_object(ef, &curr_obj) == -1) {
78*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("lastcomm: "
79*7c478bd9Sstevel@tonic-gate 			    "corrupted exacct file\n"));
80*7c478bd9Sstevel@tonic-gate 			exit(1);
81*7c478bd9Sstevel@tonic-gate 		}
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate 		switch (curr_obj.eo_catalog) {
84*7c478bd9Sstevel@tonic-gate 			case EXT_STRING | EXC_DEFAULT | EXD_PROC_COMMAND:
85*7c478bd9Sstevel@tonic-gate 				command = curr_obj.eo_item.ei_string;
86*7c478bd9Sstevel@tonic-gate 				break;
87*7c478bd9Sstevel@tonic-gate 			case EXT_UINT32 | EXC_DEFAULT | EXD_PROC_UID:
88*7c478bd9Sstevel@tonic-gate 				uid = curr_obj.eo_item.ei_uint32;
89*7c478bd9Sstevel@tonic-gate 				break;
90*7c478bd9Sstevel@tonic-gate 			case EXT_UINT64 | EXC_DEFAULT | EXD_PROC_CPU_SYS_SEC:
91*7c478bd9Sstevel@tonic-gate 				cpu_sys_secs = curr_obj.eo_item.ei_uint64;
92*7c478bd9Sstevel@tonic-gate 				break;
93*7c478bd9Sstevel@tonic-gate 			case EXT_UINT64 | EXC_DEFAULT | EXD_PROC_CPU_USER_SEC:
94*7c478bd9Sstevel@tonic-gate 				cpu_usr_secs = curr_obj.eo_item.ei_uint64;
95*7c478bd9Sstevel@tonic-gate 				break;
96*7c478bd9Sstevel@tonic-gate 			case EXT_UINT64 | EXC_DEFAULT | EXD_PROC_CPU_SYS_NSEC:
97*7c478bd9Sstevel@tonic-gate 				cpu_sys_nsecs = curr_obj.eo_item.ei_uint64;
98*7c478bd9Sstevel@tonic-gate 				break;
99*7c478bd9Sstevel@tonic-gate 			case EXT_UINT64 | EXC_DEFAULT | EXD_PROC_CPU_USER_NSEC:
100*7c478bd9Sstevel@tonic-gate 				cpu_usr_nsecs = curr_obj.eo_item.ei_uint64;
101*7c478bd9Sstevel@tonic-gate 				break;
102*7c478bd9Sstevel@tonic-gate 			case EXT_UINT32 | EXC_DEFAULT | EXD_PROC_TTY_MAJOR:
103*7c478bd9Sstevel@tonic-gate 				tty_major = curr_obj.eo_item.ei_uint32;
104*7c478bd9Sstevel@tonic-gate 				break;
105*7c478bd9Sstevel@tonic-gate 			case EXT_UINT32 | EXC_DEFAULT | EXD_PROC_TTY_MINOR:
106*7c478bd9Sstevel@tonic-gate 				tty_minor = curr_obj.eo_item.ei_uint32;
107*7c478bd9Sstevel@tonic-gate 				break;
108*7c478bd9Sstevel@tonic-gate 			case EXT_UINT32 | EXC_DEFAULT | EXD_PROC_ACCT_FLAGS:
109*7c478bd9Sstevel@tonic-gate 				flag = curr_obj.eo_item.ei_uint32;
110*7c478bd9Sstevel@tonic-gate 				break;
111*7c478bd9Sstevel@tonic-gate 			case EXT_UINT64 | EXC_DEFAULT | EXD_PROC_START_SEC:
112*7c478bd9Sstevel@tonic-gate 				time = (uint32_t)curr_obj.eo_item.ei_uint64;
113*7c478bd9Sstevel@tonic-gate 				break;
114*7c478bd9Sstevel@tonic-gate 			default:
115*7c478bd9Sstevel@tonic-gate 				break;
116*7c478bd9Sstevel@tonic-gate 		}
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate 		if (curr_obj.eo_type == EO_GROUP)
119*7c478bd9Sstevel@tonic-gate 			disp_group(ef, curr_obj.eo_group.eg_nobjs,
120*7c478bd9Sstevel@tonic-gate 			    argc, argv, index);
121*7c478bd9Sstevel@tonic-gate 	}
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate 	if (command == NULL) {
124*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("lastcomm: "
125*7c478bd9Sstevel@tonic-gate 		    "corrupted exacct file\n"));
126*7c478bd9Sstevel@tonic-gate 		exit(1);
127*7c478bd9Sstevel@tonic-gate 	}
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate 	/*
130*7c478bd9Sstevel@tonic-gate 	 * If a 64-bit kernel returns a major or minor value that would exceed
131*7c478bd9Sstevel@tonic-gate 	 * the capacity of a 32-bit dev_t (and these also become visible in the
132*7c478bd9Sstevel@tonic-gate 	 * filesystem), then the 32-bit makedev may be inaccurate and return
133*7c478bd9Sstevel@tonic-gate 	 * NODEV.  When this occurs, we can remedy the problem by providing
134*7c478bd9Sstevel@tonic-gate 	 * either a function which returns "dev64_t"'s or by providing an LP64
135*7c478bd9Sstevel@tonic-gate 	 * version of lastcomm.
136*7c478bd9Sstevel@tonic-gate 	 */
137*7c478bd9Sstevel@tonic-gate 	tty = makedev(tty_major, tty_minor);
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate 	/*
140*7c478bd9Sstevel@tonic-gate 	 * If this record doesn't match the optional arguments, go on to the
141*7c478bd9Sstevel@tonic-gate 	 * next record.
142*7c478bd9Sstevel@tonic-gate 	 */
143*7c478bd9Sstevel@tonic-gate 	if (argc > index && !ok(argc, argv, index, uid, tty, command))
144*7c478bd9Sstevel@tonic-gate 		return;
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate 	totalsecs =
147*7c478bd9Sstevel@tonic-gate 	    cpu_usr_secs + cpu_usr_nsecs / NANOSEC +
148*7c478bd9Sstevel@tonic-gate 	    cpu_sys_secs + cpu_sys_nsecs / NANOSEC;
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 	(void) printf("%-*.*s %s %-*s %-*s %6.2f secs %.16s\n",
151*7c478bd9Sstevel@tonic-gate 	    fldsiz(acct, ac_comm), fldsiz(acct, ac_comm), command,
152*7c478bd9Sstevel@tonic-gate 	    flagbits(flag), NMAX, getname(uid), LMAX, getdev(tty),
153*7c478bd9Sstevel@tonic-gate 	    totalsecs, ctime(&time));
154*7c478bd9Sstevel@tonic-gate }
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate int
lc_exacct(char * filename,int argc,char * argv[],int index)157*7c478bd9Sstevel@tonic-gate lc_exacct(char *filename, int argc, char *argv[], int index)
158*7c478bd9Sstevel@tonic-gate {
159*7c478bd9Sstevel@tonic-gate 	ea_file_t ef;
160*7c478bd9Sstevel@tonic-gate 	ea_object_t curr_obj;
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 	if (ea_open(&ef, filename, EXACCT_CREATOR,
163*7c478bd9Sstevel@tonic-gate 		    EO_TAIL | EO_VALID_HDR, O_RDONLY, 0) < 0) {
164*7c478bd9Sstevel@tonic-gate 		switch (ea_error()) {
165*7c478bd9Sstevel@tonic-gate 			case EXR_CORRUPT_FILE:
166*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext("lastcomm: "
167*7c478bd9Sstevel@tonic-gate 				    "exacct file corrupted\n"));
168*7c478bd9Sstevel@tonic-gate 				break;
169*7c478bd9Sstevel@tonic-gate 			case EXR_SYSCALL_FAIL:
170*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext("lastcomm: "
171*7c478bd9Sstevel@tonic-gate 				    "cannot open %s: %s\n"), filename,
172*7c478bd9Sstevel@tonic-gate 				    strerror(errno));
173*7c478bd9Sstevel@tonic-gate 				break;
174*7c478bd9Sstevel@tonic-gate 			default:
175*7c478bd9Sstevel@tonic-gate 				break;
176*7c478bd9Sstevel@tonic-gate 		}
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate 		return (1);
179*7c478bd9Sstevel@tonic-gate 	}
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 	while (ea_previous_object(&ef, &curr_obj) != -1) {
182*7c478bd9Sstevel@tonic-gate 		if (ea_get_object(&ef, &curr_obj) == -1) {
183*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("lastcomm: "
184*7c478bd9Sstevel@tonic-gate 			    "exacct file corrupted\n"));
185*7c478bd9Sstevel@tonic-gate 			exit(1);
186*7c478bd9Sstevel@tonic-gate 		}
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate 		/*
189*7c478bd9Sstevel@tonic-gate 		 * lc_exacct(), in parsing the extended process accounting file,
190*7c478bd9Sstevel@tonic-gate 		 * has knowledge of the fact that process records are top-level
191*7c478bd9Sstevel@tonic-gate 		 * records.
192*7c478bd9Sstevel@tonic-gate 		 */
193*7c478bd9Sstevel@tonic-gate 		if ((curr_obj.eo_catalog & EXT_TYPE_MASK) == EXT_GROUP) {
194*7c478bd9Sstevel@tonic-gate 			if (curr_obj.eo_catalog ==
195*7c478bd9Sstevel@tonic-gate 			    (EXT_GROUP | EXC_DEFAULT | EXD_GROUP_PROC))
196*7c478bd9Sstevel@tonic-gate 				disp_group(&ef, curr_obj.eo_group.eg_nobjs,
197*7c478bd9Sstevel@tonic-gate 				    argc, argv, index);
198*7c478bd9Sstevel@tonic-gate 			else
199*7c478bd9Sstevel@tonic-gate 				skip_group(&ef, curr_obj.eo_group.eg_nobjs);
200*7c478bd9Sstevel@tonic-gate 		}
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate 		/*
203*7c478bd9Sstevel@tonic-gate 		 * Back up to the head of the object we just consumed.
204*7c478bd9Sstevel@tonic-gate 		 */
205*7c478bd9Sstevel@tonic-gate 		if (ea_previous_object(&ef, &curr_obj) == -1) {
206*7c478bd9Sstevel@tonic-gate 			if (ea_error() == EXR_EOF)
207*7c478bd9Sstevel@tonic-gate 				break;
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("lastcomm: "
210*7c478bd9Sstevel@tonic-gate 			    "exacct file corrupted\n"));
211*7c478bd9Sstevel@tonic-gate 			exit(1);
212*7c478bd9Sstevel@tonic-gate 		}
213*7c478bd9Sstevel@tonic-gate 	}
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate 	if (ea_error() != EXR_EOF) {
216*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("lastcomm: "
217*7c478bd9Sstevel@tonic-gate 		    "exacct file corrupted\n"));
218*7c478bd9Sstevel@tonic-gate 		exit(1);
219*7c478bd9Sstevel@tonic-gate 	}
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 	(void) ea_close(&ef);
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate 	return (0);
224*7c478bd9Sstevel@tonic-gate }
225