121563Sdist /* 221563Sdist * Copyright (c) 1980 Regents of the University of California. 3*34033Sbostic * All rights reserved. 4*34033Sbostic * 5*34033Sbostic * Redistribution and use in source and binary forms are permitted 6*34033Sbostic * provided that this notice is preserved and that due credit is given 7*34033Sbostic * to the University of California at Berkeley. The name of the University 8*34033Sbostic * may not be used to endorse or promote products derived from this 9*34033Sbostic * software without specific prior written permission. This software 10*34033Sbostic * is provided ``as is'' without express or implied warranty. 1121563Sdist */ 1221563Sdist 1311839Ssam #ifndef lint 1421563Sdist char copyright[] = 1521563Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 1621563Sdist All rights reserved.\n"; 17*34033Sbostic #endif /* not lint */ 181037Sbill 1921563Sdist #ifndef lint 20*34033Sbostic static char sccsid[] = "@(#)lastcomm.c 5.5 (Berkeley) 04/20/88"; 21*34033Sbostic #endif /* not lint */ 2221563Sdist 231037Sbill /* 241037Sbill * last command 251037Sbill */ 2611839Ssam #include <sys/param.h> 2711839Ssam #include <sys/acct.h> 2813188Ssam #include <sys/file.h> 2913541Ssam #include <sys/stat.h> 3011839Ssam #include <utmp.h> 3111839Ssam #include <struct.h> 3211839Ssam #include <ctype.h> 33*34033Sbostic #include <stdio.h> 341037Sbill 3513188Ssam struct acct buf[DEV_BSIZE / sizeof (struct acct)]; 361037Sbill 3713188Ssam time_t expand(); 3811839Ssam char *flagbits(); 3913188Ssam char *getname(); 4013188Ssam char *getdev(); 411037Sbill 4211839Ssam main(argc, argv) 4333688Sbostic int argc; 4411839Ssam char *argv[]; 451037Sbill { 4633688Sbostic extern int optind; 4733688Sbostic extern char *optarg; 4833688Sbostic register struct acct *acp; 4913188Ssam register int bn, cc; 5013188Ssam struct stat sb; 5133688Sbostic int ch, fd; 5233688Sbostic char *acctfile, *strcpy(), *ctime(); 5331126Sbostic long lseek(); 541037Sbill 5533688Sbostic acctfile = NULL; 5633688Sbostic while ((ch = getopt(argc, argv, "f:")) != EOF) 5733688Sbostic switch((char)ch) { 5833688Sbostic case 'f': 5933688Sbostic acctfile = optarg; 6033688Sbostic break; 6133688Sbostic case '?': 6233688Sbostic default: 6333688Sbostic fputs("lastcomm [ -f file ]\n", stderr); 6433688Sbostic exit(1); 6533688Sbostic } 6633688Sbostic argv += optind; 6733688Sbostic if (!acctfile) 6833688Sbostic acctfile = "/usr/adm/acct"; 6933688Sbostic fd = open(acctfile, O_RDONLY); 7013188Ssam if (fd < 0) { 7133688Sbostic perror(acctfile); 7211839Ssam exit(1); 731037Sbill } 7433688Sbostic (void)fstat(fd, &sb); 7515634Sralph for (bn = btodb(sb.st_size); bn >= 0; bn--) { 7631126Sbostic (void)lseek(fd, (off_t)dbtob(bn), L_SET); 7713188Ssam cc = read(fd, buf, DEV_BSIZE); 7813188Ssam if (cc < 0) { 7913188Ssam perror("read"); 8013188Ssam break; 8113188Ssam } 8213188Ssam acp = buf + (cc / sizeof (buf[0])) - 1; 8313188Ssam for (; acp >= buf; acp--) { 8413188Ssam register char *cp; 8517764Sralph time_t x; 861037Sbill 8717905Sralph if (acp->ac_comm[0] == '\0') 8833688Sbostic (void)strcpy(acp->ac_comm, "?"); 8917905Sralph for (cp = &acp->ac_comm[0]; 9017905Sralph cp < &acp->ac_comm[fldsiz(acct, ac_comm)] && *cp; 9117905Sralph cp++) 9217905Sralph if (!isascii(*cp) || iscntrl(*cp)) 9313188Ssam *cp = '?'; 9433688Sbostic if (*argv && !ok(argv, acp)) 9511839Ssam continue; 9617764Sralph x = expand(acp->ac_utime) + expand(acp->ac_stime); 9727699Slepreau printf("%-*.*s %s %-*s %-*s %6.2f secs %.16s\n", 9831126Sbostic fldsiz(acct, ac_comm), 9931126Sbostic fldsiz(acct, ac_comm), 10031126Sbostic acp->ac_comm, flagbits(acp->ac_flag), 10131126Sbostic fldsiz(utmp, ut_name), 10231126Sbostic (cp = getname(acp->ac_uid)) ? cp : "", 10313188Ssam fldsiz(utmp, ut_line), getdev(acp->ac_tty), 10417503Skarels x / (double)AHZ, ctime(&acp->ac_btime)); 1051037Sbill } 1061037Sbill } 1071037Sbill } 1081037Sbill 1091037Sbill time_t 1101037Sbill expand (t) 11111839Ssam unsigned t; 1121037Sbill { 1131037Sbill register time_t nt; 1141037Sbill 1151037Sbill nt = t & 017777; 1161037Sbill t >>= 13; 11711839Ssam while (t) { 1181037Sbill t--; 1191037Sbill nt <<= 3; 1201037Sbill } 1211037Sbill return (nt); 1221037Sbill } 1231037Sbill 1247457Skre char * 1257457Skre flagbits(f) 12611839Ssam register int f; 1271037Sbill { 1287457Skre static char flags[20]; 129*34033Sbostic char *p, *strcpy(); 1307457Skre 131*34033Sbostic #define BIT(flag, ch) if (f & flag) *p++ = ch; 132*34033Sbostic p = strcpy(flags, "- "); 13311839Ssam BIT(ASU, 'S'); 13411839Ssam BIT(AFORK, 'F'); 13511839Ssam BIT(ACOMPAT, 'C'); 13611839Ssam BIT(ACORE, 'D'); 13711839Ssam BIT(AXSIG, 'X'); 13811839Ssam return (flags); 1397457Skre } 1407457Skre 14133688Sbostic ok(argv, acp) 14213188Ssam register char *argv[]; 14313188Ssam register struct acct *acp; 14413188Ssam { 14531126Sbostic register char *cp; 14613188Ssam 14733688Sbostic do { 14833688Sbostic if ((cp = getname(acp->ac_uid)) && !strcmp(cp, *argv) || 14933688Sbostic (cp = getdev(acp->ac_tty)) && !strcmp(cp, *argv) || 15033688Sbostic !strncmp(acp->ac_comm, *argv, fldsiz(acct, ac_comm))) 15133688Sbostic return(1); 15233688Sbostic } while (*++argv); 15333688Sbostic return(0); 15413188Ssam } 15513188Ssam 15613188Ssam /* should be done with nameserver or database */ 15713188Ssam 158*34033Sbostic #include <pwd.h> 159*34033Sbostic 16013188Ssam struct utmp utmp; 16113188Ssam #define NMAX (sizeof (utmp.ut_name)) 162*34033Sbostic #define SCPYN(a, b) strncpy(a, b, NMAX) 16313188Ssam 164*34033Sbostic #define NCACHE 64 /* power of 2 */ 165*34033Sbostic #define CAMASK NCACHE - 1 16613188Ssam 16713188Ssam char * 16813188Ssam getname(uid) 16931126Sbostic uid_t uid; 17013188Ssam { 171*34033Sbostic extern int _pw_stayopen; 172*34033Sbostic static struct ncache { 173*34033Sbostic uid_t uid; 174*34033Sbostic char name[NMAX+1]; 175*34033Sbostic } c_uid[NCACHE]; 17613188Ssam register struct passwd *pw; 177*34033Sbostic register struct ncache *cp; 17813188Ssam 179*34033Sbostic _pw_stayopen = 1; 180*34033Sbostic cp = c_uid + (uid & CAMASK); 181*34033Sbostic if (cp->uid == uid && *cp->name) 182*34033Sbostic return(cp->name); 183*34033Sbostic if (!(pw = getpwuid(uid))) 184*34033Sbostic return((char *)0); 185*34033Sbostic cp->uid = uid; 186*34033Sbostic SCPYN(cp->name, pw->pw_name); 187*34033Sbostic return(cp->name); 18813188Ssam } 18913188Ssam 19013188Ssam #include <sys/dir.h> 19113188Ssam 19213188Ssam #define N_DEVS 43 /* hash value for device names */ 19313188Ssam #define NDEVS 500 /* max number of file names in /dev */ 19413188Ssam 19513188Ssam struct devhash { 19613188Ssam dev_t dev_dev; 19713188Ssam char dev_name [fldsiz(utmp, ut_line) + 1]; 19813188Ssam struct devhash * dev_nxt; 19913188Ssam }; 20013188Ssam struct devhash *dev_hash[N_DEVS]; 20113188Ssam struct devhash *dev_chain; 20213188Ssam #define HASH(d) (((int) d) % N_DEVS) 20313188Ssam 2047457Skre setupdevs() 2057457Skre { 2067457Skre register DIR * fd; 2077457Skre register struct devhash * hashtab; 2087457Skre register ndevs = NDEVS; 2097457Skre struct direct * dp; 21031126Sbostic char *malloc(); 2117457Skre 21231126Sbostic /*NOSTRICT*/ 21331126Sbostic hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash)); 21431126Sbostic if (hashtab == (struct devhash *)0) { 21531126Sbostic fputs("No mem for dev table\n", stderr); 21631126Sbostic return; 21731126Sbostic } 2187457Skre if ((fd = opendir("/dev")) == NULL) { 2197457Skre perror("/dev"); 2207457Skre return; 2211037Sbill } 2227457Skre while (dp = readdir(fd)) { 2237457Skre if (dp->d_ino == 0) 2247457Skre continue; 2257457Skre if (dp->d_name[0] != 't' && strcmp(dp->d_name, "console")) 2267457Skre continue; 2277457Skre strncpy(hashtab->dev_name, dp->d_name, fldsiz(utmp, ut_line)); 2287457Skre hashtab->dev_name[fldsiz(utmp, ut_line)] = 0; 2297457Skre hashtab->dev_nxt = dev_chain; 2307457Skre dev_chain = hashtab; 2317457Skre hashtab++; 2327457Skre if (--ndevs <= 0) 2337457Skre break; 2347457Skre } 2357457Skre closedir(fd); 2361037Sbill } 2377457Skre 2387457Skre char * 23913188Ssam getdev(dev) 24011839Ssam dev_t dev; 2417457Skre { 2427457Skre register struct devhash *hp, *nhp; 2437457Skre struct stat statb; 24411839Ssam char name[fldsiz(devhash, dev_name) + 6]; 2457457Skre static dev_t lastdev = (dev_t) -1; 2467457Skre static char *lastname; 24714925Sralph static int init = 0; 24831126Sbostic char *strcpy(), *strcat(); 2497457Skre 2507457Skre if (dev == NODEV) 25111839Ssam return ("__"); 2527457Skre if (dev == lastdev) 25311839Ssam return (lastname); 25413188Ssam if (!init) { 25513188Ssam setupdevs(); 25613188Ssam init++; 25713188Ssam } 2587457Skre for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt) 2597457Skre if (hp->dev_dev == dev) { 2607457Skre lastdev = dev; 26111839Ssam return (lastname = hp->dev_name); 2627457Skre } 2637457Skre for (hp = dev_chain; hp; hp = nhp) { 2647457Skre nhp = hp->dev_nxt; 2657457Skre strcpy(name, "/dev/"); 2667457Skre strcat(name, hp->dev_name); 2677457Skre if (stat(name, &statb) < 0) /* name truncated usually */ 2687457Skre continue; 2697457Skre if ((statb.st_mode & S_IFMT) != S_IFCHR) 2707457Skre continue; 2717457Skre hp->dev_dev = statb.st_rdev; 2727457Skre hp->dev_nxt = dev_hash[HASH(hp->dev_dev)]; 2737457Skre dev_hash[HASH(hp->dev_dev)] = hp; 2747457Skre if (hp->dev_dev == dev) { 2757457Skre dev_chain = nhp; 2767457Skre lastdev = dev; 27711839Ssam return (lastname = hp->dev_name); 2787457Skre } 2797457Skre } 2807457Skre dev_chain = (struct devhash *) 0; 28111839Ssam return ("??"); 2827457Skre } 283