121563Sdist /* 221563Sdist * Copyright (c) 1980 Regents of the University of California. 334033Sbostic * All rights reserved. 434033Sbostic * 534033Sbostic * Redistribution and use in source and binary forms are permitted 634911Sbostic * provided that the above copyright notice and this paragraph are 734911Sbostic * duplicated in all such forms and that any documentation, 834911Sbostic * advertising materials, and other materials related to such 934911Sbostic * distribution and use acknowledge that the software was developed 1034911Sbostic * by the University of California, Berkeley. The name of the 1134911Sbostic * University may not be used to endorse or promote products derived 1234911Sbostic * from this software without specific prior written permission. 1334911Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434911Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534911Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621563Sdist */ 1721563Sdist 1811839Ssam #ifndef lint 1921563Sdist char copyright[] = 2021563Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 2121563Sdist All rights reserved.\n"; 2234033Sbostic #endif /* not lint */ 231037Sbill 2421563Sdist #ifndef lint 25*37076Sbostic static char sccsid[] = "@(#)lastcomm.c 5.7 (Berkeley) 03/06/89"; 2634033Sbostic #endif /* not lint */ 2721563Sdist 281037Sbill /* 291037Sbill * last command 301037Sbill */ 3111839Ssam #include <sys/param.h> 3211839Ssam #include <sys/acct.h> 3313188Ssam #include <sys/file.h> 3413541Ssam #include <sys/stat.h> 3511839Ssam #include <utmp.h> 3611839Ssam #include <struct.h> 3711839Ssam #include <ctype.h> 3834033Sbostic #include <stdio.h> 391037Sbill 4013188Ssam struct acct buf[DEV_BSIZE / sizeof (struct acct)]; 411037Sbill 4213188Ssam time_t expand(); 4311839Ssam char *flagbits(); 4413188Ssam char *getname(); 4513188Ssam char *getdev(); 461037Sbill 4711839Ssam main(argc, argv) 4833688Sbostic int argc; 4911839Ssam char *argv[]; 501037Sbill { 5133688Sbostic extern int optind; 5233688Sbostic extern char *optarg; 5333688Sbostic register struct acct *acp; 5413188Ssam register int bn, cc; 5513188Ssam struct stat sb; 5633688Sbostic int ch, fd; 5733688Sbostic char *acctfile, *strcpy(), *ctime(); 5831126Sbostic long lseek(); 591037Sbill 6033688Sbostic acctfile = NULL; 6133688Sbostic while ((ch = getopt(argc, argv, "f:")) != EOF) 6233688Sbostic switch((char)ch) { 6333688Sbostic case 'f': 6433688Sbostic acctfile = optarg; 6533688Sbostic break; 6633688Sbostic case '?': 6733688Sbostic default: 6833688Sbostic fputs("lastcomm [ -f file ]\n", stderr); 6933688Sbostic exit(1); 7033688Sbostic } 7133688Sbostic argv += optind; 7233688Sbostic if (!acctfile) 7333688Sbostic acctfile = "/usr/adm/acct"; 7433688Sbostic fd = open(acctfile, O_RDONLY); 7513188Ssam if (fd < 0) { 7633688Sbostic perror(acctfile); 7711839Ssam exit(1); 781037Sbill } 7933688Sbostic (void)fstat(fd, &sb); 80*37076Sbostic setpassent(1); 8115634Sralph for (bn = btodb(sb.st_size); bn >= 0; bn--) { 8231126Sbostic (void)lseek(fd, (off_t)dbtob(bn), L_SET); 8313188Ssam cc = read(fd, buf, DEV_BSIZE); 8413188Ssam if (cc < 0) { 8513188Ssam perror("read"); 8613188Ssam break; 8713188Ssam } 8813188Ssam acp = buf + (cc / sizeof (buf[0])) - 1; 8913188Ssam for (; acp >= buf; acp--) { 9013188Ssam register char *cp; 9117764Sralph time_t x; 921037Sbill 9317905Sralph if (acp->ac_comm[0] == '\0') 9433688Sbostic (void)strcpy(acp->ac_comm, "?"); 9517905Sralph for (cp = &acp->ac_comm[0]; 9617905Sralph cp < &acp->ac_comm[fldsiz(acct, ac_comm)] && *cp; 9717905Sralph cp++) 9817905Sralph if (!isascii(*cp) || iscntrl(*cp)) 9913188Ssam *cp = '?'; 10033688Sbostic if (*argv && !ok(argv, acp)) 10111839Ssam continue; 10217764Sralph x = expand(acp->ac_utime) + expand(acp->ac_stime); 10327699Slepreau printf("%-*.*s %s %-*s %-*s %6.2f secs %.16s\n", 10431126Sbostic fldsiz(acct, ac_comm), 10531126Sbostic fldsiz(acct, ac_comm), 10631126Sbostic acp->ac_comm, flagbits(acp->ac_flag), 10731126Sbostic fldsiz(utmp, ut_name), 10831126Sbostic (cp = getname(acp->ac_uid)) ? cp : "", 10913188Ssam fldsiz(utmp, ut_line), getdev(acp->ac_tty), 11017503Skarels x / (double)AHZ, ctime(&acp->ac_btime)); 1111037Sbill } 1121037Sbill } 1131037Sbill } 1141037Sbill 1151037Sbill time_t 1161037Sbill expand (t) 11711839Ssam unsigned t; 1181037Sbill { 1191037Sbill register time_t nt; 1201037Sbill 1211037Sbill nt = t & 017777; 1221037Sbill t >>= 13; 12311839Ssam while (t) { 1241037Sbill t--; 1251037Sbill nt <<= 3; 1261037Sbill } 1271037Sbill return (nt); 1281037Sbill } 1291037Sbill 1307457Skre char * 1317457Skre flagbits(f) 13211839Ssam register int f; 1331037Sbill { 1347457Skre static char flags[20]; 13534033Sbostic char *p, *strcpy(); 1367457Skre 13734033Sbostic #define BIT(flag, ch) if (f & flag) *p++ = ch; 13834033Sbostic p = strcpy(flags, "- "); 13911839Ssam BIT(ASU, 'S'); 14011839Ssam BIT(AFORK, 'F'); 14111839Ssam BIT(ACOMPAT, 'C'); 14211839Ssam BIT(ACORE, 'D'); 14311839Ssam BIT(AXSIG, 'X'); 14411839Ssam return (flags); 1457457Skre } 1467457Skre 14733688Sbostic ok(argv, acp) 14813188Ssam register char *argv[]; 14913188Ssam register struct acct *acp; 15013188Ssam { 15131126Sbostic register char *cp; 15213188Ssam 15333688Sbostic do { 15433688Sbostic if ((cp = getname(acp->ac_uid)) && !strcmp(cp, *argv) || 15533688Sbostic (cp = getdev(acp->ac_tty)) && !strcmp(cp, *argv) || 15633688Sbostic !strncmp(acp->ac_comm, *argv, fldsiz(acct, ac_comm))) 15733688Sbostic return(1); 15833688Sbostic } while (*++argv); 15933688Sbostic return(0); 16013188Ssam } 16113188Ssam 16213188Ssam /* should be done with nameserver or database */ 16313188Ssam 16434033Sbostic #include <pwd.h> 16534033Sbostic 16613188Ssam struct utmp utmp; 16713188Ssam #define NMAX (sizeof (utmp.ut_name)) 16834033Sbostic #define SCPYN(a, b) strncpy(a, b, NMAX) 16913188Ssam 17034033Sbostic #define NCACHE 64 /* power of 2 */ 17134033Sbostic #define CAMASK NCACHE - 1 17213188Ssam 17313188Ssam char * 17413188Ssam getname(uid) 17531126Sbostic uid_t uid; 17613188Ssam { 17734033Sbostic static struct ncache { 17834033Sbostic uid_t uid; 17934033Sbostic char name[NMAX+1]; 18034033Sbostic } c_uid[NCACHE]; 18113188Ssam register struct passwd *pw; 18234033Sbostic register struct ncache *cp; 18313188Ssam 18434033Sbostic cp = c_uid + (uid & CAMASK); 18534033Sbostic if (cp->uid == uid && *cp->name) 18634033Sbostic return(cp->name); 18734033Sbostic if (!(pw = getpwuid(uid))) 18834033Sbostic return((char *)0); 18934033Sbostic cp->uid = uid; 19034033Sbostic SCPYN(cp->name, pw->pw_name); 19134033Sbostic return(cp->name); 19213188Ssam } 19313188Ssam 19413188Ssam #include <sys/dir.h> 19513188Ssam 19613188Ssam #define N_DEVS 43 /* hash value for device names */ 19713188Ssam #define NDEVS 500 /* max number of file names in /dev */ 19813188Ssam 19913188Ssam struct devhash { 20013188Ssam dev_t dev_dev; 20113188Ssam char dev_name [fldsiz(utmp, ut_line) + 1]; 20213188Ssam struct devhash * dev_nxt; 20313188Ssam }; 20413188Ssam struct devhash *dev_hash[N_DEVS]; 20513188Ssam struct devhash *dev_chain; 20613188Ssam #define HASH(d) (((int) d) % N_DEVS) 20713188Ssam 2087457Skre setupdevs() 2097457Skre { 2107457Skre register DIR * fd; 2117457Skre register struct devhash * hashtab; 2127457Skre register ndevs = NDEVS; 2137457Skre struct direct * dp; 21431126Sbostic char *malloc(); 2157457Skre 21631126Sbostic /*NOSTRICT*/ 21731126Sbostic hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash)); 21831126Sbostic if (hashtab == (struct devhash *)0) { 21931126Sbostic fputs("No mem for dev table\n", stderr); 22031126Sbostic return; 22131126Sbostic } 2227457Skre if ((fd = opendir("/dev")) == NULL) { 2237457Skre perror("/dev"); 2247457Skre return; 2251037Sbill } 2267457Skre while (dp = readdir(fd)) { 2277457Skre if (dp->d_ino == 0) 2287457Skre continue; 2297457Skre if (dp->d_name[0] != 't' && strcmp(dp->d_name, "console")) 2307457Skre continue; 2317457Skre strncpy(hashtab->dev_name, dp->d_name, fldsiz(utmp, ut_line)); 2327457Skre hashtab->dev_name[fldsiz(utmp, ut_line)] = 0; 2337457Skre hashtab->dev_nxt = dev_chain; 2347457Skre dev_chain = hashtab; 2357457Skre hashtab++; 2367457Skre if (--ndevs <= 0) 2377457Skre break; 2387457Skre } 2397457Skre closedir(fd); 2401037Sbill } 2417457Skre 2427457Skre char * 24313188Ssam getdev(dev) 24411839Ssam dev_t dev; 2457457Skre { 2467457Skre register struct devhash *hp, *nhp; 2477457Skre struct stat statb; 24811839Ssam char name[fldsiz(devhash, dev_name) + 6]; 2497457Skre static dev_t lastdev = (dev_t) -1; 2507457Skre static char *lastname; 25114925Sralph static int init = 0; 25231126Sbostic char *strcpy(), *strcat(); 2537457Skre 2547457Skre if (dev == NODEV) 25511839Ssam return ("__"); 2567457Skre if (dev == lastdev) 25711839Ssam return (lastname); 25813188Ssam if (!init) { 25913188Ssam setupdevs(); 26013188Ssam init++; 26113188Ssam } 2627457Skre for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt) 2637457Skre if (hp->dev_dev == dev) { 2647457Skre lastdev = dev; 26511839Ssam return (lastname = hp->dev_name); 2667457Skre } 2677457Skre for (hp = dev_chain; hp; hp = nhp) { 2687457Skre nhp = hp->dev_nxt; 2697457Skre strcpy(name, "/dev/"); 2707457Skre strcat(name, hp->dev_name); 2717457Skre if (stat(name, &statb) < 0) /* name truncated usually */ 2727457Skre continue; 2737457Skre if ((statb.st_mode & S_IFMT) != S_IFCHR) 2747457Skre continue; 2757457Skre hp->dev_dev = statb.st_rdev; 2767457Skre hp->dev_nxt = dev_hash[HASH(hp->dev_dev)]; 2777457Skre dev_hash[HASH(hp->dev_dev)] = hp; 2787457Skre if (hp->dev_dev == dev) { 2797457Skre dev_chain = nhp; 2807457Skre lastdev = dev; 28111839Ssam return (lastname = hp->dev_name); 2827457Skre } 2837457Skre } 2847457Skre dev_chain = (struct devhash *) 0; 28511839Ssam return ("??"); 2867457Skre } 287