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