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.11 (Berkeley) 06/01/90"; 16 #endif /* not lint */ 17 18 /* 19 * last command 20 */ 21 #include <sys/param.h> 22 #include <sys/acct.h> 23 #include <sys/file.h> 24 #include <sys/stat.h> 25 #include <utmp.h> 26 #include <struct.h> 27 #include <ctype.h> 28 #include <stdio.h> 29 #include "pathnames.h" 30 31 struct acct buf[DEV_BSIZE / sizeof (struct acct)]; 32 33 time_t expand(); 34 char *flagbits(); 35 char *getdev(); 36 37 main(argc, argv) 38 int argc; 39 char *argv[]; 40 { 41 extern int optind; 42 extern char *optarg; 43 register struct acct *acp; 44 register int bn, cc; 45 struct stat sb; 46 int ch, fd; 47 char *acctfile, *ctime(), *strcpy(), *user_from_uid(); 48 long lseek(); 49 50 acctfile = _PATH_ACCT; 51 while ((ch = getopt(argc, argv, "f:")) != EOF) 52 switch((char)ch) { 53 case 'f': 54 acctfile = optarg; 55 break; 56 case '?': 57 default: 58 fputs("lastcomm [ -f file ]\n", stderr); 59 exit(1); 60 } 61 argv += optind; 62 63 fd = open(acctfile, O_RDONLY); 64 if (fd < 0) { 65 perror(acctfile); 66 exit(1); 67 } 68 (void)fstat(fd, &sb); 69 setpassent(1); 70 for (bn = btodb(sb.st_size); bn >= 0; bn--) { 71 (void)lseek(fd, (off_t)dbtob(bn), L_SET); 72 cc = read(fd, buf, DEV_BSIZE); 73 if (cc < 0) { 74 perror("read"); 75 break; 76 } 77 acp = buf + (cc / sizeof (buf[0])) - 1; 78 for (; acp >= buf; acp--) { 79 register char *cp; 80 time_t x; 81 82 if (acp->ac_comm[0] == '\0') 83 (void)strcpy(acp->ac_comm, "?"); 84 for (cp = &acp->ac_comm[0]; 85 cp < &acp->ac_comm[fldsiz(acct, ac_comm)] && *cp; 86 cp++) 87 if (!isascii(*cp) || iscntrl(*cp)) 88 *cp = '?'; 89 if (*argv && !ok(argv, acp)) 90 continue; 91 x = expand(acp->ac_utime) + expand(acp->ac_stime); 92 printf("%-*.*s %s %-*s %-*s %6.2f secs %.16s\n", 93 fldsiz(acct, ac_comm), fldsiz(acct, ac_comm), 94 acp->ac_comm, flagbits(acp->ac_flag), 95 UT_NAMESIZE, user_from_uid(acp->ac_uid, 0), 96 UT_LINESIZE, getdev(acp->ac_tty), 97 x / (double)AHZ, ctime(&acp->ac_btime)); 98 } 99 } 100 } 101 102 time_t 103 expand (t) 104 unsigned t; 105 { 106 register time_t nt; 107 108 nt = t & 017777; 109 t >>= 13; 110 while (t) { 111 t--; 112 nt <<= 3; 113 } 114 return (nt); 115 } 116 117 char * 118 flagbits(f) 119 register int f; 120 { 121 static char flags[20]; 122 char *p, *strcpy(); 123 124 #define BIT(flag, ch) if (f & flag) *p++ = ch; 125 p = strcpy(flags, "- "); 126 BIT(ASU, 'S'); 127 BIT(AFORK, 'F'); 128 BIT(ACOMPAT, 'C'); 129 BIT(ACORE, 'D'); 130 BIT(AXSIG, 'X'); 131 return (flags); 132 } 133 134 ok(argv, acp) 135 register char *argv[]; 136 register struct acct *acp; 137 { 138 register char *cp; 139 char *user_from_uid(); 140 141 do { 142 cp = user_from_uid(acp->ac_uid, 0); 143 if (!strcmp(cp, *argv)) 144 return(1); 145 if ((cp = getdev(acp->ac_tty)) && !strcmp(cp, *argv)) 146 return(1); 147 if (!strncmp(acp->ac_comm, *argv, fldsiz(acct, ac_comm))) 148 return(1); 149 } while (*++argv); 150 return(0); 151 } 152 153 #include <sys/dir.h> 154 155 #define N_DEVS 43 /* hash value for device names */ 156 #define NDEVS 500 /* max number of file names in /dev */ 157 158 struct devhash { 159 dev_t dev_dev; 160 char dev_name [UT_LINESIZE + 1]; 161 struct devhash * dev_nxt; 162 }; 163 struct devhash *dev_hash[N_DEVS]; 164 struct devhash *dev_chain; 165 #define HASH(d) (((int) d) % N_DEVS) 166 167 setupdevs() 168 { 169 register DIR * fd; 170 register struct devhash * hashtab; 171 register ndevs = NDEVS; 172 struct direct * dp; 173 char *malloc(); 174 175 /*NOSTRICT*/ 176 hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash)); 177 if (hashtab == (struct devhash *)0) { 178 fputs("No mem for dev table\n", stderr); 179 return; 180 } 181 if ((fd = opendir(_PATH_DEV)) == NULL) { 182 perror(_PATH_DEV); 183 return; 184 } 185 while (dp = readdir(fd)) { 186 if (dp->d_ino == 0) 187 continue; 188 if (dp->d_name[0] != 't' && strcmp(dp->d_name, "console")) 189 continue; 190 (void)strncpy(hashtab->dev_name, dp->d_name, UT_LINESIZE); 191 hashtab->dev_name[UT_LINESIZE] = 0; 192 hashtab->dev_nxt = dev_chain; 193 dev_chain = hashtab; 194 hashtab++; 195 if (--ndevs <= 0) 196 break; 197 } 198 closedir(fd); 199 } 200 201 char * 202 getdev(dev) 203 dev_t dev; 204 { 205 register struct devhash *hp, *nhp; 206 struct stat statb; 207 char name[fldsiz(devhash, dev_name) + 6]; 208 static dev_t lastdev = (dev_t) -1; 209 static char *lastname; 210 static int init = 0; 211 char *strcpy(), *strcat(); 212 213 if (dev == NODEV) 214 return ("__"); 215 if (dev == lastdev) 216 return (lastname); 217 if (!init) { 218 setupdevs(); 219 init++; 220 } 221 for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt) 222 if (hp->dev_dev == dev) { 223 lastdev = dev; 224 return (lastname = hp->dev_name); 225 } 226 for (hp = dev_chain; hp; hp = nhp) { 227 nhp = hp->dev_nxt; 228 (void)strcpy(name, _PATH_DEV); 229 strcat(name, hp->dev_name); 230 if (stat(name, &statb) < 0) /* name truncated usually */ 231 continue; 232 if ((statb.st_mode & S_IFMT) != S_IFCHR) 233 continue; 234 hp->dev_dev = statb.st_rdev; 235 hp->dev_nxt = dev_hash[HASH(hp->dev_dev)]; 236 dev_hash[HASH(hp->dev_dev)] = hp; 237 if (hp->dev_dev == dev) { 238 dev_chain = nhp; 239 lastdev = dev; 240 return (lastname = hp->dev_name); 241 } 242 } 243 dev_chain = (struct devhash *) 0; 244 return ("??"); 245 } 246