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