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