1*7457Skre static char *sccsid = "@(#)lastcomm.c 4.4 (Berkeley) 82/07/17"; 21037Sbill 31037Sbill /* 41037Sbill * last command 51037Sbill */ 61037Sbill 71037Sbill # include <stdio.h> 8*7457Skre # include <sys/param.h> 91037Sbill # include <sys/acct.h> 10*7457Skre # include <sys/dir.h> 111037Sbill # include <signal.h> 121037Sbill # include <pwd.h> 131037Sbill # include <stat.h> 14*7457Skre # include <utmp.h> 15*7457Skre # include <struct.h> 161037Sbill 17*7457Skre # define N_USER 4000 /* highest alloc user # */ 18*7457Skre # define N_DEVS 43 /* hash value for device names */ 19*7457Skre # define NDEVS 500 /* max number of file names in /dev */ 201037Sbill 211037Sbill struct acct acct_buff [BUFSIZ / sizeof (struct acct)]; 221037Sbill 23*7457Skre char user_list [N_USER][fldsiz(utmp, ut_name) + 1]; 241037Sbill 25*7457Skre struct devhash { 26*7457Skre dev_t dev_dev; 27*7457Skre char dev_name [fldsiz(utmp, ut_line) + 1]; 28*7457Skre struct devhash * dev_nxt; 29*7457Skre } 30*7457Skre * dev_hash [ N_DEVS ], 31*7457Skre * dev_chain ; 32*7457Skre # define HASH(d) (((int) d) % N_DEVS) 331037Sbill 341037Sbill time_t expand (); 35*7457Skre char * flagbits(); 36*7457Skre char * tername(); 371037Sbill 381037Sbill struct passwd 391037Sbill *passwd, 401037Sbill *getpwent (); 411037Sbill 421037Sbill struct stat stat_buff; 431037Sbill 44*7457Skre # define equal(a, b) (strcmp(a, b) == 0) 45*7457Skre 461037Sbill main (argc, argv) 471037Sbill char **argv; 481037Sbill { 491037Sbill char acct_desc, 501037Sbill *p; 511037Sbill 521037Sbill long i, 531037Sbill j, 541037Sbill i_block, 551037Sbill n_blocks, 561037Sbill n_byte, 571037Sbill n_entry; 581037Sbill 591037Sbill float x; 601037Sbill 611037Sbill /* 621037Sbill * set up user names 631037Sbill */ 641037Sbill while (passwd = getpwent ()) 651037Sbill { 661887Smark if (user_list[passwd->pw_uid][0]==0) 671886Smark move (passwd->pw_name, user_list [passwd->pw_uid]); 681037Sbill } 691037Sbill 70*7457Skre /* 71*7457Skre * find dev numbers corresponding to names in /dev 72*7457Skre */ 73*7457Skre setupdevs(); 74*7457Skre 751037Sbill acct_desc = open ("/usr/adm/acct", 0); 761037Sbill if (acct_desc < 0) 771037Sbill { 781037Sbill perror ("/usr/adm/acct"); 791037Sbill return; 801037Sbill } 811037Sbill fstat (acct_desc, &stat_buff); 821037Sbill n_blocks = (stat_buff.st_size + BUFSIZ - 1) / BUFSIZ; 831037Sbill 841037Sbill /* 851037Sbill * read one block's worth 861037Sbill */ 871037Sbill for (i_block = n_blocks - 1; i_block >= 0; i_block--) 881037Sbill { 891037Sbill lseek (acct_desc, i_block * BUFSIZ, 0); 901037Sbill n_byte = read (acct_desc, acct_buff, BUFSIZ); 911037Sbill n_entry = n_byte / sizeof acct_buff [0]; 921037Sbill for (i = n_entry - 1; i >= 0; i--) 931037Sbill { 94*7457Skre if (!*user_list [acct_buff [i].ac_uid]) 95*7457Skre continue; 961037Sbill /* 971037Sbill * get the times 981037Sbill */ 991037Sbill x = expand (acct_buff [i].ac_utime) 1001037Sbill + 1011037Sbill expand (acct_buff [i].ac_stime); 1021037Sbill /* 1031037Sbill * null terminate the command name 1041037Sbill */ 1051037Sbill acct_buff [i].ac_comm [10] = 0; 1061037Sbill /* 1071037Sbill * replace missing command names with question marks 1081037Sbill */ 1091037Sbill if (!*acct_buff [i].ac_comm) 1101037Sbill { 1111037Sbill move ("?", acct_buff [i].ac_comm); 1121037Sbill } 1131037Sbill /* 1141037Sbill * replace control characters with question marks 1151037Sbill */ 1161037Sbill for (p = acct_buff [i].ac_comm; *p; p++) 1171037Sbill { 118*7457Skre if (*p < '!' || '~' < *p) 119*7457Skre *p = '?'; 1201037Sbill } 1211037Sbill for (j = 1; j < argc; j++) 1221037Sbill { 1231037Sbill if 1241037Sbill ( 1251037Sbill equal (acct_buff [i].ac_comm, argv [j]) 1261037Sbill || 1271037Sbill equal 1281037Sbill ( 129*7457Skre user_list[acct_buff[i].ac_uid], 1301037Sbill argv [j] 1311037Sbill ) 132*7457Skre || 133*7457Skre equal 134*7457Skre ( 135*7457Skre tername(acct_buff[i].ac_tty), 136*7457Skre argv[j] 137*7457Skre ) 1381037Sbill ) 1391037Sbill { 1401037Sbill break; 1411037Sbill } 1421037Sbill } 1431037Sbill if (argc == 1 || j != argc) 1441037Sbill { 1451037Sbill printf 1461037Sbill ( 147*7457Skre "%-*s %s %-*s %-*s %6.2f %.16s\n" 148*7457Skre , fldsiz(acct, ac_comm) 149*7457Skre , acct_buff [i].ac_comm 150*7457Skre , flagbits(acct_buff [i].ac_flag) 151*7457Skre , fldsiz(utmp, ut_name) 152*7457Skre , user_list [acct_buff [i].ac_uid] 153*7457Skre , fldsiz(utmp, ut_line) 154*7457Skre , tername(acct_buff [i].ac_tty) 155*7457Skre , x / 60.0 156*7457Skre , ctime (&acct_buff [i].ac_btime) 1571037Sbill ); 1581037Sbill } 1591037Sbill } 1601037Sbill } 1611037Sbill } 1621037Sbill 1631037Sbill time_t 1641037Sbill expand (t) 1651037Sbill unsigned t; 1661037Sbill { 1671037Sbill register time_t nt; 1681037Sbill 1691037Sbill nt = t & 017777; 1701037Sbill t >>= 13; 1711037Sbill while (t) 1721037Sbill { 1731037Sbill t--; 1741037Sbill nt <<= 3; 1751037Sbill } 1761037Sbill return (nt); 1771037Sbill } 1781037Sbill 1791037Sbill move (a, b) 1801037Sbill char *a, *b; 1811037Sbill { 182*7457Skre while (*b++ = *a++) 183*7457Skre ; 1841037Sbill } 1851037Sbill 186*7457Skre char * 187*7457Skre flagbits(f) 188*7457Skre register int f; 1891037Sbill { 190*7457Skre register int i = 0; 191*7457Skre static char flags[20]; 192*7457Skre 193*7457Skre # define BIT(flag, ch) flags[i++] = ( f & flag ) ? ch : ' ' 194*7457Skre 195*7457Skre BIT( ASU, 'S'); 196*7457Skre BIT( AFORK, 'F'); 197*7457Skre BIT( ACOMPAT, 'C'); 198*7457Skre BIT( ACORE, 'D'); 199*7457Skre BIT( AXSIG, 'X'); 200*7457Skre 201*7457Skre flags[i] = '\0'; 202*7457Skre 203*7457Skre return(flags); 204*7457Skre } 205*7457Skre 206*7457Skre setupdevs() 207*7457Skre { 208*7457Skre register DIR * fd; 209*7457Skre register struct devhash * hashtab; 210*7457Skre register ndevs = NDEVS; 211*7457Skre struct direct * dp; 212*7457Skre 213*7457Skre if ((fd = opendir("/dev")) == NULL) { 214*7457Skre perror("/dev"); 215*7457Skre return; 2161037Sbill } 217*7457Skre 218*7457Skre if ((hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash))) 219*7457Skre == (struct devhash *) 0) { 220*7457Skre fprintf(stderr, "No mem for dev table\n"); 221*7457Skre return; 222*7457Skre } 223*7457Skre 224*7457Skre while (dp = readdir(fd)) { 225*7457Skre if (dp->d_ino == 0) 226*7457Skre continue; 227*7457Skre #ifdef MELB 228*7457Skre if (dp->d_name[0] != 't' && strcmp(dp->d_name, "console")) 229*7457Skre continue; 230*7457Skre #endif 231*7457Skre strncpy(hashtab->dev_name, dp->d_name, fldsiz(utmp, ut_line)); 232*7457Skre hashtab->dev_name[fldsiz(utmp, ut_line)] = 0; 233*7457Skre hashtab->dev_nxt = dev_chain; 234*7457Skre dev_chain = hashtab; 235*7457Skre hashtab++; 236*7457Skre if (--ndevs <= 0) 237*7457Skre break; 238*7457Skre } 239*7457Skre closedir(fd); 2401037Sbill } 241*7457Skre 242*7457Skre char * 243*7457Skre tername(dev) 244*7457Skre dev_t dev; 245*7457Skre { 246*7457Skre register struct devhash *hp, *nhp; 247*7457Skre struct stat statb; 248*7457Skre char name [fldsiz(devhash, dev_name) + 6]; 249*7457Skre static dev_t lastdev = (dev_t) -1; 250*7457Skre static char *lastname; 251*7457Skre 252*7457Skre if (dev == NODEV) 253*7457Skre return("__"); 254*7457Skre 255*7457Skre if (dev == lastdev) 256*7457Skre return(lastname); 257*7457Skre 258*7457Skre for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt) 259*7457Skre if (hp->dev_dev == dev) { 260*7457Skre lastdev = dev; 261*7457Skre return(lastname = hp->dev_name); 262*7457Skre } 263*7457Skre 264*7457Skre for (hp = dev_chain; hp; hp = nhp) { 265*7457Skre nhp = hp->dev_nxt; 266*7457Skre strcpy(name, "/dev/"); 267*7457Skre strcat(name, hp->dev_name); 268*7457Skre if (stat(name, &statb) < 0) /* name truncated usually */ 269*7457Skre continue; 270*7457Skre if ((statb.st_mode & S_IFMT) != S_IFCHR) 271*7457Skre continue; 272*7457Skre hp->dev_dev = statb.st_rdev; 273*7457Skre hp->dev_nxt = dev_hash[HASH(hp->dev_dev)]; 274*7457Skre dev_hash[HASH(hp->dev_dev)] = hp; 275*7457Skre if (hp->dev_dev == dev) { 276*7457Skre dev_chain = nhp; 277*7457Skre lastdev = dev; 278*7457Skre return(lastname = hp->dev_name); 279*7457Skre } 280*7457Skre } 281*7457Skre 282*7457Skre dev_chain = (struct devhash *) 0; 283*7457Skre return("??"); 284*7457Skre } 285