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: #if defined(DOSCCS) && !defined(lint) 8: char copyright[] = 9: "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 10: All rights reserved.\n"; 11: 12: static char sccsid[] = "@(#)lastcomm.c 5.2.4 (2.11BSD GTE) 1997/5/7"; 13: #endif 14: 15: /* 16: * lastcomm command 17: */ 18: #include <sys/param.h> 19: #include <sys/acct.h> 20: #include <sys/file.h> 21: 22: #include <stdio.h> 23: #include <pwd.h> 24: #include <sys/stat.h> 25: #include <utmp.h> 26: #include <struct.h> 27: #include <ctype.h> 28: #include <stdlib.h> 29: 30: struct acct buf[DEV_BSIZE / sizeof (struct acct)]; 31: 32: time_t expand(); 33: char *flagbits(); 34: char *getname(); 35: char *getdev(); 36: 37: main(argc, argv) 38: char *argv[]; 39: { 40: register int bn, cc; 41: register struct acct *acp; 42: int fd, ch; 43: struct stat sb; 44: char *acctfile = "/usr/adm/acct"; 45: 46: while ((ch = getopt(argc, argv, "f:")) != EOF) 47: { 48: switch (ch) 49: { 50: case 'f': 51: acctfile = optarg; 52: break; 53: case '?': 54: default: 55: usage(); 56: } 57: } 58: argc -= optind; 59: argv += optind; 60: 61: fd = open(acctfile, O_RDONLY); 62: if (fd < 0) 63: err(1, "%s", acctfile); 64: 65: fstat(fd, &sb); 66: for (bn = btodb(sb.st_size); bn >= 0; bn--) { 67: lseek(fd, (off_t)dbtob(bn), L_SET); 68: cc = read(fd, buf, DEV_BSIZE); 69: if (cc < 0) { 70: perror("read"); 71: break; 72: } 73: acp = buf + (cc / sizeof (buf[0])) - 1; 74: for (; acp >= buf; acp--) { 75: register char *cp; 76: time_t x; 77: 78: if (acp->ac_comm[0] == '\0') 79: strcpy(acp->ac_comm, "?"); 80: for (cp = &acp->ac_comm[0]; 81: cp < &acp->ac_comm[fldsiz(acct, ac_comm)] && *cp; 82: cp++) 83: if (!isascii(*cp) || iscntrl(*cp)) 84: *cp = '?'; 85: if (*argv && !ok(argv, acp)) 86: continue; 87: x = expand(acp->ac_utime) + expand(acp->ac_stime); 88: printf("%-*.*s %s %-*s %-*s %6.2f secs %.16s\n", 89: fldsiz(acct, ac_comm), fldsiz(acct, ac_comm), 90: acp->ac_comm, 91: flagbits(acp->ac_flag), 92: fldsiz(utmp, ut_name), getname(acp->ac_uid), 93: fldsiz(utmp, ut_line), getdev(acp->ac_tty), 94: x / (double)AHZ, ctime(&acp->ac_btime)); 95: } 96: } 97: } 98: 99: time_t 100: expand (t) 101: unsigned t; 102: { 103: register time_t nt; 104: 105: nt = t & 017777; 106: t >>= 13; 107: while (t) { 108: t--; 109: nt <<= 3; 110: } 111: return (nt); 112: } 113: 114: char * 115: flagbits(f) 116: register int f; 117: { 118: register int i = 0; 119: static char flags[20]; 120: 121: #define BIT(flag, ch) flags[i++] = (f & flag) ? ch : ' ' 122: BIT(ASU, 'S'); 123: BIT(AFORK, 'F'); 124: BIT(ACOMPAT, 'C'); 125: BIT(ACORE, 'D'); 126: BIT(AXSIG, 'X'); 127: flags[i] = '\0'; 128: return (flags); 129: } 130: 131: ok(argv, acp) 132: register char *argv[]; 133: register struct acct *acp; 134: { 135: do { 136: if (!strcmp(getname(acp->ac_uid), *argv)) 137: return(1); 138: if (!strcmp(getdev(acp->ac_tty), *argv)) 139: return(1); 140: if (!strncmp(acp->ac_comm, *argv, fldsiz(acct, ac_comm))) 141: return(1); 142: } while (*++argv); 143: return (0); 144: } 145: 146: /* should be done with nameserver or database */ 147: 148: struct utmp utmp; 149: #define NMAX (sizeof (utmp.ut_name)) 150: #define SCPYN(a, b) strncpy(a, b, NMAX) 151: 152: #define NCACHE 64 /* power of 2 */ 153: #define CAMASK NCACHE - 1 154: 155: char * 156: getname(uid) 157: uid_t uid; 158: { 159: static struct ncache { 160: uid_t uid; 161: char name[NMAX+1]; 162: } c_uid[NCACHE]; 163: register struct passwd *pw; 164: register struct ncache *cp; 165: 166: setpassent(1); 167: cp = c_uid + (uid & CAMASK); 168: if (cp->uid == uid && *cp->name) 169: return(cp->name); 170: if (!(pw = getpwuid(uid))) 171: return((char *)0); 172: cp->uid = uid; 173: SCPYN(cp->name, pw->pw_name); 174: return(cp->name); 175: } 176: 177: char * 178: getdev(dev) 179: dev_t dev; 180: { 181: static dev_t lastdev = (dev_t) -1; 182: static char *lastname; 183: 184: if (dev == NODEV) /* Special case */ 185: return ("__"); 186: if (dev == lastdev) /* One-element cache. */ 187: return (lastname); 188: lastdev = dev; 189: lastname = devname(dev, S_IFCHR); 190: return (lastname); 191: } 192: 193: void 194: usage() 195: { 196: 197: (void)fprintf(stderr, 198: "lastcomm [ -f file ] [ command ...] [ user ...] [ tty ...]\n"); 199: exit(1); 200: }