121563Sdist /* 221563Sdist * Copyright (c) 1980 Regents of the University of California. 321563Sdist * All rights reserved. The Berkeley software License Agreement 421563Sdist * specifies the terms and conditions for redistribution. 521563Sdist */ 621563Sdist 711839Ssam #ifndef lint 821563Sdist char copyright[] = 921563Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 1021563Sdist All rights reserved.\n"; 1121563Sdist #endif not lint 121037Sbill 1321563Sdist #ifndef lint 14*31126Sbostic static char sccsid[] = "@(#)lastcomm.c 5.3 (Berkeley) 05/15/87"; 1521563Sdist #endif not lint 1621563Sdist 171037Sbill /* 181037Sbill * last command 191037Sbill */ 2011839Ssam #include <sys/param.h> 2111839Ssam #include <sys/acct.h> 2213188Ssam #include <sys/file.h> 2313188Ssam 2413188Ssam #include <stdio.h> 2511839Ssam #include <pwd.h> 2613541Ssam #include <sys/stat.h> 2711839Ssam #include <utmp.h> 2811839Ssam #include <struct.h> 2911839Ssam #include <ctype.h> 301037Sbill 3113188Ssam struct acct buf[DEV_BSIZE / sizeof (struct acct)]; 321037Sbill 3313188Ssam time_t expand(); 3411839Ssam char *flagbits(); 3513188Ssam char *getname(); 3613188Ssam char *getdev(); 371037Sbill 3811839Ssam main(argc, argv) 3911839Ssam char *argv[]; 401037Sbill { 4113188Ssam register int bn, cc; 4211839Ssam register struct acct *acp; 4313188Ssam int fd; 4413188Ssam struct stat sb; 45*31126Sbostic long lseek(); 46*31126Sbostic char *strcpy(), *ctime(); 471037Sbill 4813188Ssam fd = open("/usr/adm/acct", O_RDONLY); 4913188Ssam if (fd < 0) { 5011839Ssam perror("/usr/adm/acct"); 5111839Ssam exit(1); 521037Sbill } 5313188Ssam fstat(fd, &sb); 5415634Sralph for (bn = btodb(sb.st_size); bn >= 0; bn--) { 55*31126Sbostic (void)lseek(fd, (off_t)dbtob(bn), L_SET); 5613188Ssam cc = read(fd, buf, DEV_BSIZE); 5713188Ssam if (cc < 0) { 5813188Ssam perror("read"); 5913188Ssam break; 6013188Ssam } 6113188Ssam acp = buf + (cc / sizeof (buf[0])) - 1; 6213188Ssam for (; acp >= buf; acp--) { 6313188Ssam register char *cp; 6417764Sralph time_t x; 651037Sbill 6617905Sralph if (acp->ac_comm[0] == '\0') 6711839Ssam strcpy(acp->ac_comm, "?"); 6817905Sralph for (cp = &acp->ac_comm[0]; 6917905Sralph cp < &acp->ac_comm[fldsiz(acct, ac_comm)] && *cp; 7017905Sralph cp++) 7117905Sralph if (!isascii(*cp) || iscntrl(*cp)) 7213188Ssam *cp = '?'; 7317764Sralph if (argc > 1 && !ok(argc, argv, acp)) 7411839Ssam continue; 7517764Sralph x = expand(acp->ac_utime) + expand(acp->ac_stime); 7627699Slepreau printf("%-*.*s %s %-*s %-*s %6.2f secs %.16s\n", 77*31126Sbostic fldsiz(acct, ac_comm), 78*31126Sbostic fldsiz(acct, ac_comm), 79*31126Sbostic acp->ac_comm, flagbits(acp->ac_flag), 80*31126Sbostic fldsiz(utmp, ut_name), 81*31126Sbostic (cp = getname(acp->ac_uid)) ? cp : "", 8213188Ssam fldsiz(utmp, ut_line), getdev(acp->ac_tty), 8317503Skarels x / (double)AHZ, ctime(&acp->ac_btime)); 841037Sbill } 851037Sbill } 861037Sbill } 871037Sbill 881037Sbill time_t 891037Sbill expand (t) 9011839Ssam unsigned t; 911037Sbill { 921037Sbill register time_t nt; 931037Sbill 941037Sbill nt = t & 017777; 951037Sbill t >>= 13; 9611839Ssam while (t) { 971037Sbill t--; 981037Sbill nt <<= 3; 991037Sbill } 1001037Sbill return (nt); 1011037Sbill } 1021037Sbill 1037457Skre char * 1047457Skre flagbits(f) 10511839Ssam register int f; 1061037Sbill { 1077457Skre register int i = 0; 1087457Skre static char flags[20]; 1097457Skre 11011839Ssam #define BIT(flag, ch) flags[i++] = (f & flag) ? ch : ' ' 11111839Ssam BIT(ASU, 'S'); 11211839Ssam BIT(AFORK, 'F'); 11311839Ssam BIT(ACOMPAT, 'C'); 11411839Ssam BIT(ACORE, 'D'); 11511839Ssam BIT(AXSIG, 'X'); 1167457Skre flags[i] = '\0'; 11711839Ssam return (flags); 1187457Skre } 1197457Skre 12013188Ssam ok(argc, argv, acp) 12113188Ssam register int argc; 12213188Ssam register char *argv[]; 12313188Ssam register struct acct *acp; 12413188Ssam { 12513188Ssam register int j; 126*31126Sbostic register char *cp; 12713188Ssam 12813188Ssam for (j = 1; j < argc; j++) 129*31126Sbostic if ((!(cp = getname(acp->ac_uid)) || strcmp(cp, argv[j])) && 130*31126Sbostic (!(cp = getdev(acp->ac_tty)) || strcmp(cp, argv[j])) && 13117905Sralph strncmp(acp->ac_comm, argv[j], fldsiz(acct, ac_comm))) 13213188Ssam break; 13313188Ssam return (j == argc); 13413188Ssam } 13513188Ssam 13613188Ssam /* should be done with nameserver or database */ 13713188Ssam 13813188Ssam struct utmp utmp; 13913188Ssam 14013188Ssam #define NUID 2048 14113188Ssam #define NMAX (sizeof (utmp.ut_name)) 14213188Ssam 14313188Ssam char names[NUID][NMAX+1]; 14413188Ssam char outrangename[NMAX+1]; 14513188Ssam int outrangeuid = -1; 14613188Ssam 14713188Ssam char * 14813188Ssam getname(uid) 149*31126Sbostic uid_t uid; 15013188Ssam { 15113188Ssam register struct passwd *pw; 15213188Ssam static init; 15313188Ssam struct passwd *getpwent(); 15413188Ssam 155*31126Sbostic if (uid < NUID && names[uid][0]) 15613188Ssam return (&names[uid][0]); 157*31126Sbostic if (uid == outrangeuid) 15813188Ssam return (outrangename); 15913188Ssam if (init == 2) { 16013188Ssam if (uid < NUID) 16113188Ssam return (0); 16213188Ssam setpwent(); 16313188Ssam while (pw = getpwent()) { 16413188Ssam if (pw->pw_uid != uid) 16513188Ssam continue; 16613188Ssam outrangeuid = pw->pw_uid; 16714768Ssam strncpy(outrangename, pw->pw_name, NMAX); 16813188Ssam endpwent(); 16913188Ssam return (outrangename); 17013188Ssam } 17113188Ssam endpwent(); 17213188Ssam return (0); 17313188Ssam } 17413188Ssam if (init == 0) 17513188Ssam setpwent(), init = 1; 17613188Ssam while (pw = getpwent()) { 17713188Ssam if (pw->pw_uid < 0 || pw->pw_uid >= NUID) { 17813188Ssam if (pw->pw_uid == uid) { 17913188Ssam outrangeuid = pw->pw_uid; 18014768Ssam strncpy(outrangename, pw->pw_name, NMAX); 18113188Ssam return (outrangename); 18213188Ssam } 18313188Ssam continue; 18413188Ssam } 18513188Ssam if (names[pw->pw_uid][0]) 18613188Ssam continue; 18713188Ssam strncpy(names[pw->pw_uid], pw->pw_name, NMAX); 18813188Ssam if (pw->pw_uid == uid) 18913188Ssam return (&names[uid][0]); 19013188Ssam } 19113188Ssam init = 2; 19213188Ssam endpwent(); 19313188Ssam return (0); 19413188Ssam } 19513188Ssam 19613188Ssam #include <sys/dir.h> 19713188Ssam 19813188Ssam #define N_DEVS 43 /* hash value for device names */ 19913188Ssam #define NDEVS 500 /* max number of file names in /dev */ 20013188Ssam 20113188Ssam struct devhash { 20213188Ssam dev_t dev_dev; 20313188Ssam char dev_name [fldsiz(utmp, ut_line) + 1]; 20413188Ssam struct devhash * dev_nxt; 20513188Ssam }; 20613188Ssam struct devhash *dev_hash[N_DEVS]; 20713188Ssam struct devhash *dev_chain; 20813188Ssam #define HASH(d) (((int) d) % N_DEVS) 20913188Ssam 2107457Skre setupdevs() 2117457Skre { 2127457Skre register DIR * fd; 2137457Skre register struct devhash * hashtab; 2147457Skre register ndevs = NDEVS; 2157457Skre struct direct * dp; 216*31126Sbostic char *malloc(); 2177457Skre 218*31126Sbostic /*NOSTRICT*/ 219*31126Sbostic hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash)); 220*31126Sbostic if (hashtab == (struct devhash *)0) { 221*31126Sbostic fputs("No mem for dev table\n", stderr); 222*31126Sbostic return; 223*31126Sbostic } 2247457Skre if ((fd = opendir("/dev")) == NULL) { 2257457Skre perror("/dev"); 2267457Skre return; 2271037Sbill } 2287457Skre while (dp = readdir(fd)) { 2297457Skre if (dp->d_ino == 0) 2307457Skre continue; 2317457Skre if (dp->d_name[0] != 't' && strcmp(dp->d_name, "console")) 2327457Skre continue; 2337457Skre strncpy(hashtab->dev_name, dp->d_name, fldsiz(utmp, ut_line)); 2347457Skre hashtab->dev_name[fldsiz(utmp, ut_line)] = 0; 2357457Skre hashtab->dev_nxt = dev_chain; 2367457Skre dev_chain = hashtab; 2377457Skre hashtab++; 2387457Skre if (--ndevs <= 0) 2397457Skre break; 2407457Skre } 2417457Skre closedir(fd); 2421037Sbill } 2437457Skre 2447457Skre char * 24513188Ssam getdev(dev) 24611839Ssam dev_t dev; 2477457Skre { 2487457Skre register struct devhash *hp, *nhp; 2497457Skre struct stat statb; 25011839Ssam char name[fldsiz(devhash, dev_name) + 6]; 2517457Skre static dev_t lastdev = (dev_t) -1; 2527457Skre static char *lastname; 25314925Sralph static int init = 0; 254*31126Sbostic char *strcpy(), *strcat(); 2557457Skre 2567457Skre if (dev == NODEV) 25711839Ssam return ("__"); 2587457Skre if (dev == lastdev) 25911839Ssam return (lastname); 26013188Ssam if (!init) { 26113188Ssam setupdevs(); 26213188Ssam init++; 26313188Ssam } 2647457Skre for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt) 2657457Skre if (hp->dev_dev == dev) { 2667457Skre lastdev = dev; 26711839Ssam return (lastname = hp->dev_name); 2687457Skre } 2697457Skre for (hp = dev_chain; hp; hp = nhp) { 2707457Skre nhp = hp->dev_nxt; 2717457Skre strcpy(name, "/dev/"); 2727457Skre strcat(name, hp->dev_name); 2737457Skre if (stat(name, &statb) < 0) /* name truncated usually */ 2747457Skre continue; 2757457Skre if ((statb.st_mode & S_IFMT) != S_IFCHR) 2767457Skre continue; 2777457Skre hp->dev_dev = statb.st_rdev; 2787457Skre hp->dev_nxt = dev_hash[HASH(hp->dev_dev)]; 2797457Skre dev_hash[HASH(hp->dev_dev)] = hp; 2807457Skre if (hp->dev_dev == dev) { 2817457Skre dev_chain = nhp; 2827457Skre lastdev = dev; 28311839Ssam return (lastname = hp->dev_name); 2847457Skre } 2857457Skre } 2867457Skre dev_chain = (struct devhash *) 0; 28711839Ssam return ("??"); 2887457Skre } 289