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