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