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