1*11839Ssam #ifndef lint 2*11839Ssam static char *sccsid = "@(#)lastcomm.c 4.5 (Berkeley) 83/04/04"; 3*11839Ssam #endif 41037Sbill 51037Sbill /* 61037Sbill * last command 71037Sbill */ 8*11839Ssam #include <stdio.h> 9*11839Ssam #include <sys/param.h> 10*11839Ssam #include <sys/acct.h> 11*11839Ssam #include <sys/dir.h> 12*11839Ssam #include <signal.h> 13*11839Ssam #include <pwd.h> 14*11839Ssam #include <stat.h> 15*11839Ssam #include <utmp.h> 16*11839Ssam #include <struct.h> 17*11839Ssam #include <ctype.h> 181037Sbill 19*11839Ssam #define N_USER 4000 /* highest alloc user # */ 20*11839Ssam #define N_DEVS 43 /* hash value for device names */ 21*11839Ssam #define NDEVS 500 /* max number of file names in /dev */ 221037Sbill 23*11839Ssam struct acct acct_buff[BUFSIZ / sizeof (struct acct)]; 24*11839Ssam char user_list[N_USER][fldsiz(utmp, ut_name) + 1]; 251037Sbill 267457Skre struct devhash { 277457Skre dev_t dev_dev; 287457Skre char dev_name [fldsiz(utmp, ut_line) + 1]; 297457Skre struct devhash * dev_nxt; 30*11839Ssam }; 31*11839Ssam struct devhash *dev_hash[N_DEVS]; 32*11839Ssam struct devhash *dev_chain ; 33*11839Ssam #define HASH(d) (((int) d) % N_DEVS) 341037Sbill 351037Sbill time_t expand (); 36*11839Ssam char *flagbits(); 37*11839Ssam char *ttyname(); 381037Sbill 39*11839Ssam struct passwd *passwd, *getpwent (); 401037Sbill struct stat stat_buff; 411037Sbill 42*11839Ssam main(argc, argv) 43*11839Ssam char *argv[]; 441037Sbill { 45*11839Ssam char acct_desc, *p; 46*11839Ssam long i, j, i_block, n_blocks, n_byte, n_entry, x; 47*11839Ssam register struct acct *acp; 481037Sbill 49*11839Ssam /* 50*11839Ssam * Set up user names 51*11839Ssam */ 52*11839Ssam while (passwd = getpwent()) 53*11839Ssam if (user_list[passwd->pw_uid][0] == 0) 54*11839Ssam strcpy(user_list[passwd->pw_uid], passwd->pw_name); 55*11839Ssam /* 56*11839Ssam * Find dev numbers corresponding to names in /dev 57*11839Ssam */ 587457Skre setupdevs(); 59*11839Ssam acct_desc = open("/usr/adm/acct", 0); 60*11839Ssam if (acct_desc < 0) { 61*11839Ssam perror("/usr/adm/acct"); 62*11839Ssam exit(1); 631037Sbill } 64*11839Ssam fstat(acct_desc, &stat_buff); 651037Sbill n_blocks = (stat_buff.st_size + BUFSIZ - 1) / BUFSIZ; 661037Sbill 671037Sbill /* 68*11839Ssam * Read one block's worth 691037Sbill */ 70*11839Ssam for (i_block = n_blocks - 1; i_block >= 0; i_block--) { 71*11839Ssam lseek(acct_desc, i_block * BUFSIZ, 0); 72*11839Ssam n_byte = read(acct_desc, acct_buff, BUFSIZ); 73*11839Ssam n_entry = n_byte / sizeof acct_buff[0]; 74*11839Ssam for (acp = acct_buff + n_entry - 1; acp >= acct_buff; acp--) { 75*11839Ssam if (*user_list[acp->ac_uid] == '\0') 767457Skre continue; 77*11839Ssam x = expand(acp->ac_utime) + expand(acp->ac_stime); 78*11839Ssam acp->ac_comm[10] = '\0'; 79*11839Ssam if (*acp->ac_comm == '\0') 80*11839Ssam strcpy(acp->ac_comm, "?"); 81*11839Ssam for (p = acp->ac_comm; *p; p++) 82*11839Ssam if (iscntrl(*p)) 837457Skre *p = '?'; 84*11839Ssam if (!ok(argc, argv, acp) && argc != 1) 85*11839Ssam continue; 86*11839Ssam printf("%-*s %s %-*s %-*s %4d sec%s %.16s\n", 87*11839Ssam fldsiz(acct, ac_comm), acp->ac_comm, 88*11839Ssam flagbits(acp->ac_flag), 89*11839Ssam fldsiz(utmp, ut_name), user_list[acp->ac_uid], 90*11839Ssam fldsiz(utmp, ut_line), ttyname(acp->ac_tty), 91*11839Ssam x, x > 1 || x == 0 ? "s" : " ", 92*11839Ssam ctime(&acp->ac_btime)); 931037Sbill } 941037Sbill } 951037Sbill } 961037Sbill 971037Sbill time_t 981037Sbill expand (t) 99*11839Ssam unsigned t; 1001037Sbill { 1011037Sbill register time_t nt; 1021037Sbill 1031037Sbill nt = t & 017777; 1041037Sbill t >>= 13; 105*11839Ssam while (t) { 1061037Sbill t--; 1071037Sbill nt <<= 3; 1081037Sbill } 1091037Sbill return (nt); 1101037Sbill } 1111037Sbill 1127457Skre char * 1137457Skre flagbits(f) 114*11839Ssam register int f; 1151037Sbill { 1167457Skre register int i = 0; 1177457Skre static char flags[20]; 1187457Skre 119*11839Ssam #define BIT(flag, ch) flags[i++] = (f & flag) ? ch : ' ' 120*11839Ssam BIT(ASU, 'S'); 121*11839Ssam BIT(AFORK, 'F'); 122*11839Ssam BIT(ACOMPAT, 'C'); 123*11839Ssam BIT(ACORE, 'D'); 124*11839Ssam BIT(AXSIG, 'X'); 1257457Skre flags[i] = '\0'; 126*11839Ssam return (flags); 1277457Skre } 1287457Skre 1297457Skre setupdevs() 1307457Skre { 1317457Skre register DIR * fd; 1327457Skre register struct devhash * hashtab; 1337457Skre register ndevs = NDEVS; 1347457Skre struct direct * dp; 1357457Skre 1367457Skre if ((fd = opendir("/dev")) == NULL) { 1377457Skre perror("/dev"); 1387457Skre return; 1391037Sbill } 1407457Skre if ((hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash))) 1417457Skre == (struct devhash *) 0) { 1427457Skre fprintf(stderr, "No mem for dev table\n"); 1437457Skre return; 1447457Skre } 1457457Skre while (dp = readdir(fd)) { 1467457Skre if (dp->d_ino == 0) 1477457Skre continue; 1487457Skre #ifdef MELB 1497457Skre if (dp->d_name[0] != 't' && strcmp(dp->d_name, "console")) 1507457Skre continue; 1517457Skre #endif 1527457Skre strncpy(hashtab->dev_name, dp->d_name, fldsiz(utmp, ut_line)); 1537457Skre hashtab->dev_name[fldsiz(utmp, ut_line)] = 0; 1547457Skre hashtab->dev_nxt = dev_chain; 1557457Skre dev_chain = hashtab; 1567457Skre hashtab++; 1577457Skre if (--ndevs <= 0) 1587457Skre break; 1597457Skre } 1607457Skre closedir(fd); 1611037Sbill } 1627457Skre 1637457Skre char * 164*11839Ssam ttyname(dev) 165*11839Ssam dev_t dev; 1667457Skre { 1677457Skre register struct devhash *hp, *nhp; 1687457Skre struct stat statb; 169*11839Ssam char name[fldsiz(devhash, dev_name) + 6]; 1707457Skre static dev_t lastdev = (dev_t) -1; 1717457Skre static char *lastname; 1727457Skre 1737457Skre if (dev == NODEV) 174*11839Ssam return ("__"); 1757457Skre if (dev == lastdev) 176*11839Ssam return (lastname); 1777457Skre for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt) 1787457Skre if (hp->dev_dev == dev) { 1797457Skre lastdev = dev; 180*11839Ssam return (lastname = hp->dev_name); 1817457Skre } 1827457Skre for (hp = dev_chain; hp; hp = nhp) { 1837457Skre nhp = hp->dev_nxt; 1847457Skre strcpy(name, "/dev/"); 1857457Skre strcat(name, hp->dev_name); 1867457Skre if (stat(name, &statb) < 0) /* name truncated usually */ 1877457Skre continue; 1887457Skre if ((statb.st_mode & S_IFMT) != S_IFCHR) 1897457Skre continue; 1907457Skre hp->dev_dev = statb.st_rdev; 1917457Skre hp->dev_nxt = dev_hash[HASH(hp->dev_dev)]; 1927457Skre dev_hash[HASH(hp->dev_dev)] = hp; 1937457Skre if (hp->dev_dev == dev) { 1947457Skre dev_chain = nhp; 1957457Skre lastdev = dev; 196*11839Ssam return (lastname = hp->dev_name); 1977457Skre } 1987457Skre } 1997457Skre dev_chain = (struct devhash *) 0; 200*11839Ssam return ("??"); 2017457Skre } 202*11839Ssam 203*11839Ssam ok(argc, argv, acp) 204*11839Ssam register int argc; 205*11839Ssam register char *argv[]; 206*11839Ssam register struct acct *acp; 207*11839Ssam { 208*11839Ssam register int j; 209*11839Ssam 210*11839Ssam for (j = 1; j < argc; j++) 211*11839Ssam if (strcmp(user_list[acp->ac_uid], argv[j]) && 212*11839Ssam strcmp(ttyname(acp->ac_tty), argv[j]) && 213*11839Ssam strcmp(acp->ac_comm, argv[j])) 214*11839Ssam break; 215*11839Ssam return (j == argc); 216*11839Ssam } 217