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*40480Sbostic static char sccsid[] = "@(#)lastcomm.c 5.10 (Berkeley) 03/13/90"; 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> 3937848Sbostic #include "pathnames.h" 401037Sbill 4113188Ssam struct acct buf[DEV_BSIZE / sizeof (struct acct)]; 421037Sbill 4313188Ssam time_t expand(); 4411839Ssam char *flagbits(); 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; 5740266Sbostic char *acctfile, *ctime(), *strcpy(), *user_from_uid(); 5831126Sbostic long lseek(); 591037Sbill 6037848Sbostic acctfile = _PATH_ACCT; 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; 7237848Sbostic 7333688Sbostic fd = open(acctfile, O_RDONLY); 7413188Ssam if (fd < 0) { 7533688Sbostic perror(acctfile); 7611839Ssam exit(1); 771037Sbill } 7833688Sbostic (void)fstat(fd, &sb); 7937076Sbostic setpassent(1); 8015634Sralph for (bn = btodb(sb.st_size); bn >= 0; bn--) { 8131126Sbostic (void)lseek(fd, (off_t)dbtob(bn), L_SET); 8213188Ssam cc = read(fd, buf, DEV_BSIZE); 8313188Ssam if (cc < 0) { 8413188Ssam perror("read"); 8513188Ssam break; 8613188Ssam } 8713188Ssam acp = buf + (cc / sizeof (buf[0])) - 1; 8813188Ssam for (; acp >= buf; acp--) { 8913188Ssam register char *cp; 9017764Sralph time_t x; 911037Sbill 9217905Sralph if (acp->ac_comm[0] == '\0') 9333688Sbostic (void)strcpy(acp->ac_comm, "?"); 9417905Sralph for (cp = &acp->ac_comm[0]; 9517905Sralph cp < &acp->ac_comm[fldsiz(acct, ac_comm)] && *cp; 9617905Sralph cp++) 9717905Sralph if (!isascii(*cp) || iscntrl(*cp)) 9813188Ssam *cp = '?'; 9933688Sbostic if (*argv && !ok(argv, acp)) 10011839Ssam continue; 10117764Sralph x = expand(acp->ac_utime) + expand(acp->ac_stime); 10227699Slepreau printf("%-*.*s %s %-*s %-*s %6.2f secs %.16s\n", 10340266Sbostic fldsiz(acct, ac_comm), fldsiz(acct, ac_comm), 10431126Sbostic acp->ac_comm, flagbits(acp->ac_flag), 105*40480Sbostic UT_NAMESIZE, user_from_uid(acp->ac_uid, 0), 10640266Sbostic UT_LINESIZE, getdev(acp->ac_tty), 10717503Skarels x / (double)AHZ, ctime(&acp->ac_btime)); 1081037Sbill } 1091037Sbill } 1101037Sbill } 1111037Sbill 1121037Sbill time_t 1131037Sbill expand (t) 11411839Ssam unsigned t; 1151037Sbill { 1161037Sbill register time_t nt; 1171037Sbill 1181037Sbill nt = t & 017777; 1191037Sbill t >>= 13; 12011839Ssam while (t) { 1211037Sbill t--; 1221037Sbill nt <<= 3; 1231037Sbill } 1241037Sbill return (nt); 1251037Sbill } 1261037Sbill 1277457Skre char * 1287457Skre flagbits(f) 12911839Ssam register int f; 1301037Sbill { 1317457Skre static char flags[20]; 13234033Sbostic char *p, *strcpy(); 1337457Skre 13434033Sbostic #define BIT(flag, ch) if (f & flag) *p++ = ch; 13534033Sbostic p = strcpy(flags, "- "); 13611839Ssam BIT(ASU, 'S'); 13711839Ssam BIT(AFORK, 'F'); 13811839Ssam BIT(ACOMPAT, 'C'); 13911839Ssam BIT(ACORE, 'D'); 14011839Ssam BIT(AXSIG, 'X'); 14111839Ssam return (flags); 1427457Skre } 1437457Skre 14433688Sbostic ok(argv, acp) 14513188Ssam register char *argv[]; 14613188Ssam register struct acct *acp; 14713188Ssam { 14831126Sbostic register char *cp; 14940266Sbostic char *user_from_uid(); 15013188Ssam 15133688Sbostic do { 152*40480Sbostic cp = user_from_uid(acp->ac_uid, 0); 15340266Sbostic if (!strcmp(cp, *argv)) 15433688Sbostic return(1); 15540266Sbostic if ((cp = getdev(acp->ac_tty)) && !strcmp(cp, *argv)) 15640266Sbostic return(1); 15740266Sbostic if (!strncmp(acp->ac_comm, *argv, fldsiz(acct, ac_comm))) 15840266Sbostic return(1); 15933688Sbostic } while (*++argv); 16033688Sbostic return(0); 16113188Ssam } 16213188Ssam 16313188Ssam #include <sys/dir.h> 16413188Ssam 16513188Ssam #define N_DEVS 43 /* hash value for device names */ 16613188Ssam #define NDEVS 500 /* max number of file names in /dev */ 16713188Ssam 16813188Ssam struct devhash { 16913188Ssam dev_t dev_dev; 17040266Sbostic char dev_name [UT_LINESIZE + 1]; 17113188Ssam struct devhash * dev_nxt; 17213188Ssam }; 17313188Ssam struct devhash *dev_hash[N_DEVS]; 17413188Ssam struct devhash *dev_chain; 17513188Ssam #define HASH(d) (((int) d) % N_DEVS) 17613188Ssam 1777457Skre setupdevs() 1787457Skre { 1797457Skre register DIR * fd; 1807457Skre register struct devhash * hashtab; 1817457Skre register ndevs = NDEVS; 1827457Skre struct direct * dp; 18331126Sbostic char *malloc(); 1847457Skre 18531126Sbostic /*NOSTRICT*/ 18631126Sbostic hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash)); 18731126Sbostic if (hashtab == (struct devhash *)0) { 18831126Sbostic fputs("No mem for dev table\n", stderr); 18931126Sbostic return; 19031126Sbostic } 19137848Sbostic if ((fd = opendir(_PATH_DEV)) == NULL) { 19237848Sbostic perror(_PATH_DEV); 1937457Skre return; 1941037Sbill } 1957457Skre while (dp = readdir(fd)) { 1967457Skre if (dp->d_ino == 0) 1977457Skre continue; 1987457Skre if (dp->d_name[0] != 't' && strcmp(dp->d_name, "console")) 1997457Skre continue; 20040266Sbostic (void)strncpy(hashtab->dev_name, dp->d_name, UT_LINESIZE); 20140266Sbostic hashtab->dev_name[UT_LINESIZE] = 0; 2027457Skre hashtab->dev_nxt = dev_chain; 2037457Skre dev_chain = hashtab; 2047457Skre hashtab++; 2057457Skre if (--ndevs <= 0) 2067457Skre break; 2077457Skre } 2087457Skre closedir(fd); 2091037Sbill } 2107457Skre 2117457Skre char * 21213188Ssam getdev(dev) 21311839Ssam dev_t dev; 2147457Skre { 2157457Skre register struct devhash *hp, *nhp; 2167457Skre struct stat statb; 21711839Ssam char name[fldsiz(devhash, dev_name) + 6]; 2187457Skre static dev_t lastdev = (dev_t) -1; 2197457Skre static char *lastname; 22014925Sralph static int init = 0; 22131126Sbostic char *strcpy(), *strcat(); 2227457Skre 2237457Skre if (dev == NODEV) 22411839Ssam return ("__"); 2257457Skre if (dev == lastdev) 22611839Ssam return (lastname); 22713188Ssam if (!init) { 22813188Ssam setupdevs(); 22913188Ssam init++; 23013188Ssam } 2317457Skre for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt) 2327457Skre if (hp->dev_dev == dev) { 2337457Skre lastdev = dev; 23411839Ssam return (lastname = hp->dev_name); 2357457Skre } 2367457Skre for (hp = dev_chain; hp; hp = nhp) { 2377457Skre nhp = hp->dev_nxt; 23840266Sbostic (void)strcpy(name, _PATH_DEV); 2397457Skre strcat(name, hp->dev_name); 2407457Skre if (stat(name, &statb) < 0) /* name truncated usually */ 2417457Skre continue; 2427457Skre if ((statb.st_mode & S_IFMT) != S_IFCHR) 2437457Skre continue; 2447457Skre hp->dev_dev = statb.st_rdev; 2457457Skre hp->dev_nxt = dev_hash[HASH(hp->dev_dev)]; 2467457Skre dev_hash[HASH(hp->dev_dev)] = hp; 2477457Skre if (hp->dev_dev == dev) { 2487457Skre dev_chain = nhp; 2497457Skre lastdev = dev; 25011839Ssam return (lastname = hp->dev_name); 2517457Skre } 2527457Skre } 2537457Skre dev_chain = (struct devhash *) 0; 25411839Ssam return ("??"); 2557457Skre } 256