1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)lastcomm.c 5.12 (Berkeley) 07/12/92"; 16 #endif /* not lint */ 17 18 #include <sys/param.h> 19 #include <sys/stat.h> 20 #include <sys/acct.h> 21 22 #include <fcntl.h> 23 #include <utmp.h> 24 #include <struct.h> 25 #include <errno.h> 26 #include <unistd.h> 27 #include <stdlib.h> 28 #include <stdio.h> 29 #include <ctype.h> 30 #include <string.h> 31 #include "pathnames.h" 32 33 char *devname __P((dev_t, mode_t)); 34 void err __P((const char *, ...)); 35 time_t expand __P((u_int)); 36 char *flagbits __P((int)); 37 char *getdev __P((dev_t)); 38 int requested __P((char *[], struct acct *)); 39 void usage __P((void)); 40 char *user_from_uid(); 41 42 int 43 main(argc, argv) 44 int argc; 45 char *argv[]; 46 { 47 register char *p; 48 struct acct ab; 49 struct stat sb; 50 FILE *fp; 51 off_t size; 52 time_t t; 53 int ch; 54 char *acctfile; 55 56 acctfile = _PATH_ACCT; 57 while ((ch = getopt(argc, argv, "f:")) != EOF) 58 switch((char)ch) { 59 case 'f': 60 acctfile = optarg; 61 break; 62 case '?': 63 default: 64 usage(); 65 } 66 argc -= optind; 67 argv += optind; 68 69 /* Open the file. */ 70 if ((fp = fopen(acctfile, "r")) == NULL || fstat(fileno(fp), &sb)) 71 err("%s: %s\n", acctfile, strerror(errno)); 72 73 /* 74 * Round off to integral number of accounting records, probably 75 * not necessary, but it doesn't hurt. 76 */ 77 size = sb.st_size - sb.st_size % sizeof(struct acct); 78 79 /* Check if any records to display. */ 80 if (size < sizeof(struct acct)) 81 exit(0); 82 83 /* 84 * Seek to before the last entry in the file; use lseek(2) in case 85 * the file is bigger than a "long". 86 */ 87 size -= sizeof(struct acct); 88 if (lseek(fileno(fp), size, SEEK_SET) == -1) 89 err("%s: %s\n", acctfile, strerror(errno)); 90 91 for (;;) { 92 if (fread(&ab, sizeof(struct acct), 1, fp) != 1) 93 err("%s: %s\n", acctfile, strerror(errno)); 94 95 if (fseek(fp, 2 * -(long)sizeof(struct acct), SEEK_CUR) == -1) 96 err("%s: %s\n", acctfile, strerror(errno)); 97 98 if (size == 0) 99 break; 100 size -= sizeof(struct acct); 101 102 if (ab.ac_comm[0] == '\0') { 103 ab.ac_comm[0] = '?'; 104 ab.ac_comm[1] = '\0'; 105 } else 106 for (p = &ab.ac_comm[0]; 107 p < &ab.ac_comm[fldsiz(acct, ac_comm)] && *p; ++p) 108 if (!isprint(*p)) 109 *p = '?'; 110 if (*argv && !requested(argv, &ab)) 111 continue; 112 113 t = expand(ab.ac_utime) + expand(ab.ac_stime); 114 (void)printf("%-*s %-7s %-*s %-*s %6.2f secs %.16s\n", 115 fldsiz(acct, ac_comm), ab.ac_comm, flagbits(ab.ac_flag), 116 UT_NAMESIZE, user_from_uid(ab.ac_uid, 0), 117 UT_LINESIZE, getdev(ab.ac_tty), 118 t / (double)AHZ, ctime(&ab.ac_btime)); 119 } 120 exit(0); 121 } 122 123 time_t 124 expand(t) 125 u_int t; 126 { 127 register time_t nt; 128 129 nt = t & 017777; 130 t >>= 13; 131 while (t) { 132 t--; 133 nt <<= 3; 134 } 135 return (nt); 136 } 137 138 char * 139 flagbits(f) 140 register int f; 141 { 142 static char flags[20] = "-"; 143 char *p; 144 145 #define BIT(flag, ch) if (f & flag) *p++ = ch 146 147 p = flags + 1; 148 BIT(ASU, 'S'); 149 BIT(AFORK, 'F'); 150 BIT(ACOMPAT, 'C'); 151 BIT(ACORE, 'D'); 152 BIT(AXSIG, 'X'); 153 *p = '\0'; 154 return (flags); 155 } 156 157 int 158 requested(argv, acp) 159 register char *argv[]; 160 register struct acct *acp; 161 { 162 register char *p; 163 164 do { 165 p = user_from_uid(acp->ac_uid, 0); 166 if (!strcmp(p, *argv)) 167 return (1); 168 if ((p = getdev(acp->ac_tty)) && !strcmp(p, *argv)) 169 return (1); 170 if (!strncmp(acp->ac_comm, *argv, fldsiz(acct, ac_comm))) 171 return (1); 172 } while (*++argv); 173 return (0); 174 } 175 176 char * 177 getdev(dev) 178 dev_t dev; 179 { 180 static dev_t lastdev = (dev_t)-1; 181 static char *lastname; 182 183 if (dev == NODEV) /* Special case. */ 184 return ("__"); 185 if (dev == lastdev) /* One-element cache. */ 186 return (lastname); 187 lastdev = dev; 188 lastname = devname(dev, S_IFCHR); 189 return (lastname); 190 } 191 192 void 193 usage() 194 { 195 (void)fprintf(stderr, 196 "lastcomm [ -f file ] [command ...] [user ...] [tty ...]\n"); 197 exit(1); 198 } 199 200 #if __STDC__ 201 #include <stdarg.h> 202 #else 203 #include <varargs.h> 204 #endif 205 206 void 207 #if __STDC__ 208 err(const char *fmt, ...) 209 #else 210 err(fmt, va_alist) 211 char *fmt; 212 va_dcl 213 #endif 214 { 215 va_list ap; 216 #if __STDC__ 217 va_start(ap, fmt); 218 #else 219 va_start(ap); 220 #endif 221 (void)fprintf(stderr, "lastcomm: "); 222 (void)vfprintf(stderr, fmt, ap); 223 va_end(ap); 224 (void)fprintf(stderr, "\n"); 225 exit(1); 226 /* NOTREACHED */ 227 } 228