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