1: /* 2: * Copyright (c) 1980 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #ifndef lint 8: char copyright[] = 9: "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 10: All rights reserved.\n"; 11: #endif not lint 12: 13: #ifndef lint 14: static char sccsid[] = "@(#)lastcomm.c 5.2 (Berkeley) 5/4/86"; 15: #endif not lint 16: 17: /* 18: * last command 19: */ 20: #include <sys/param.h> 21: #include <sys/acct.h> 22: #include <sys/file.h> 23: 24: #include <stdio.h> 25: #include <pwd.h> 26: #include <sys/stat.h> 27: #include <utmp.h> 28: #include <struct.h> 29: #include <ctype.h> 30: 31: struct acct buf[DEV_BSIZE / sizeof (struct acct)]; 32: 33: time_t expand(); 34: char *flagbits(); 35: char *getname(); 36: char *getdev(); 37: 38: main(argc, argv) 39: char *argv[]; 40: { 41: register int bn, cc; 42: register struct acct *acp; 43: int fd; 44: struct stat sb; 45: 46: fd = open("/usr/adm/acct", O_RDONLY); 47: if (fd < 0) { 48: perror("/usr/adm/acct"); 49: exit(1); 50: } 51: fstat(fd, &sb); 52: for (bn = btodb(sb.st_size); bn >= 0; bn--) { 53: lseek(fd, dbtob(bn), L_SET); 54: cc = read(fd, buf, DEV_BSIZE); 55: if (cc < 0) { 56: perror("read"); 57: break; 58: } 59: acp = buf + (cc / sizeof (buf[0])) - 1; 60: for (; acp >= buf; acp--) { 61: register char *cp; 62: time_t x; 63: 64: if (acp->ac_comm[0] == '\0') 65: strcpy(acp->ac_comm, "?"); 66: for (cp = &acp->ac_comm[0]; 67: cp < &acp->ac_comm[fldsiz(acct, ac_comm)] && *cp; 68: cp++) 69: if (!isascii(*cp) || iscntrl(*cp)) 70: *cp = '?'; 71: if (argc > 1 && !ok(argc, argv, acp)) 72: continue; 73: x = expand(acp->ac_utime) + expand(acp->ac_stime); 74: printf("%-*.*s %s %-*s %-*s %6.2f secs %.16s\n", 75: fldsiz(acct, ac_comm), fldsiz(acct, ac_comm), 76: acp->ac_comm, 77: flagbits(acp->ac_flag), 78: fldsiz(utmp, ut_name), getname(acp->ac_uid), 79: fldsiz(utmp, ut_line), getdev(acp->ac_tty), 80: x / (double)AHZ, ctime(&acp->ac_btime)); 81: } 82: } 83: } 84: 85: time_t 86: expand (t) 87: unsigned t; 88: { 89: register time_t nt; 90: 91: nt = t & 017777; 92: t >>= 13; 93: while (t) { 94: t--; 95: nt <<= 3; 96: } 97: return (nt); 98: } 99: 100: char * 101: flagbits(f) 102: register int f; 103: { 104: register int i = 0; 105: static char flags[20]; 106: 107: #define BIT(flag, ch) flags[i++] = (f & flag) ? ch : ' ' 108: BIT(ASU, 'S'); 109: BIT(AFORK, 'F'); 110: BIT(ACOMPAT, 'C'); 111: BIT(ACORE, 'D'); 112: BIT(AXSIG, 'X'); 113: flags[i] = '\0'; 114: return (flags); 115: } 116: 117: ok(argc, argv, acp) 118: register int argc; 119: register char *argv[]; 120: register struct acct *acp; 121: { 122: register int j; 123: 124: for (j = 1; j < argc; j++) 125: if (strcmp(getname(acp->ac_uid), argv[j]) && 126: strcmp(getdev(acp->ac_tty), argv[j]) && 127: strncmp(acp->ac_comm, argv[j], fldsiz(acct, ac_comm))) 128: break; 129: return (j == argc); 130: } 131: 132: /* should be done with nameserver or database */ 133: 134: struct utmp utmp; 135: 136: #define NUID 2048 137: #define NMAX (sizeof (utmp.ut_name)) 138: 139: char names[NUID][NMAX+1]; 140: char outrangename[NMAX+1]; 141: int outrangeuid = -1; 142: 143: char * 144: getname(uid) 145: { 146: register struct passwd *pw; 147: static init; 148: struct passwd *getpwent(); 149: 150: if (uid >= 0 && uid < NUID && names[uid][0]) 151: return (&names[uid][0]); 152: if (uid >= 0 && uid == outrangeuid) 153: return (outrangename); 154: if (init == 2) { 155: if (uid < NUID) 156: return (0); 157: setpwent(); 158: while (pw = getpwent()) { 159: if (pw->pw_uid != uid) 160: continue; 161: outrangeuid = pw->pw_uid; 162: strncpy(outrangename, pw->pw_name, NMAX); 163: endpwent(); 164: return (outrangename); 165: } 166: endpwent(); 167: return (0); 168: } 169: if (init == 0) 170: setpwent(), init = 1; 171: while (pw = getpwent()) { 172: if (pw->pw_uid < 0 || pw->pw_uid >= NUID) { 173: if (pw->pw_uid == uid) { 174: outrangeuid = pw->pw_uid; 175: strncpy(outrangename, pw->pw_name, NMAX); 176: return (outrangename); 177: } 178: continue; 179: } 180: if (names[pw->pw_uid][0]) 181: continue; 182: strncpy(names[pw->pw_uid], pw->pw_name, NMAX); 183: if (pw->pw_uid == uid) 184: return (&names[uid][0]); 185: } 186: init = 2; 187: endpwent(); 188: return (0); 189: } 190: 191: #include <sys/dir.h> 192: 193: #define N_DEVS 43 /* hash value for device names */ 194: #define NDEVS 500 /* max number of file names in /dev */ 195: 196: struct devhash { 197: dev_t dev_dev; 198: char dev_name [fldsiz(utmp, ut_line) + 1]; 199: struct devhash * dev_nxt; 200: }; 201: struct devhash *dev_hash[N_DEVS]; 202: struct devhash *dev_chain; 203: #define HASH(d) (((int) d) % N_DEVS) 204: 205: setupdevs() 206: { 207: register DIR * fd; 208: register struct devhash * hashtab; 209: register ndevs = NDEVS; 210: struct direct * dp; 211: 212: if ((fd = opendir("/dev")) == NULL) { 213: perror("/dev"); 214: return; 215: } 216: hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash)); 217: if (hashtab == (struct devhash *)0) { 218: fprintf(stderr, "No mem for dev table\n"); 219: closedir(fd); 220: return; 221: } 222: while (dp = readdir(fd)) { 223: if (dp->d_ino == 0) 224: continue; 225: if (dp->d_name[0] != 't' && strcmp(dp->d_name, "console")) 226: continue; 227: strncpy(hashtab->dev_name, dp->d_name, fldsiz(utmp, ut_line)); 228: hashtab->dev_name[fldsiz(utmp, ut_line)] = 0; 229: hashtab->dev_nxt = dev_chain; 230: dev_chain = hashtab; 231: hashtab++; 232: if (--ndevs <= 0) 233: break; 234: } 235: closedir(fd); 236: } 237: 238: char * 239: getdev(dev) 240: dev_t dev; 241: { 242: register struct devhash *hp, *nhp; 243: struct stat statb; 244: char name[fldsiz(devhash, dev_name) + 6]; 245: static dev_t lastdev = (dev_t) -1; 246: static char *lastname; 247: static int init = 0; 248: 249: if (dev == NODEV) 250: return ("__"); 251: if (dev == lastdev) 252: return (lastname); 253: if (!init) { 254: setupdevs(); 255: init++; 256: } 257: for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt) 258: if (hp->dev_dev == dev) { 259: lastdev = dev; 260: return (lastname = hp->dev_name); 261: } 262: for (hp = dev_chain; hp; hp = nhp) { 263: nhp = hp->dev_nxt; 264: strcpy(name, "/dev/"); 265: strcat(name, hp->dev_name); 266: if (stat(name, &statb) < 0) /* name truncated usually */ 267: continue; 268: if ((statb.st_mode & S_IFMT) != S_IFCHR) 269: continue; 270: hp->dev_dev = statb.st_rdev; 271: hp->dev_nxt = dev_hash[HASH(hp->dev_dev)]; 272: dev_hash[HASH(hp->dev_dev)] = hp; 273: if (hp->dev_dev == dev) { 274: dev_chain = nhp; 275: lastdev = dev; 276: return (lastname = hp->dev_name); 277: } 278: } 279: dev_chain = (struct devhash *) 0; 280: return ("??"); 281: }