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