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
skip_group(ea_file_t * ef,uint_t nobjs)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
ok(int argc,char * argv[],int index,uid_t uid,dev_t tty,char * command)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
disp_group(ea_file_t * ef,uint_t nobjs,int argc,char * argv[],int index)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
lc_exacct(char * filename,int argc,char * argv[],int index)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