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 6*34911Sbostic * provided that the above copyright notice and this paragraph are 7*34911Sbostic * duplicated in all such forms and that any documentation, 8*34911Sbostic * advertising materials, and other materials related to such 9*34911Sbostic * distribution and use acknowledge that the software was developed 10*34911Sbostic * by the University of California, Berkeley. The name of the 11*34911Sbostic * University may not be used to endorse or promote products derived 12*34911Sbostic * from this software without specific prior written permission. 13*34911Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*34911Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*34911Sbostic * 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*34911Sbostic static char sccsid[] = "@(#)lastcomm.c 5.6 (Berkeley) 06/29/88"; 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); 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", 10331126Sbostic fldsiz(acct, ac_comm), 10431126Sbostic fldsiz(acct, ac_comm), 10531126Sbostic acp->ac_comm, flagbits(acp->ac_flag), 10631126Sbostic fldsiz(utmp, ut_name), 10731126Sbostic (cp = getname(acp->ac_uid)) ? cp : "", 10813188Ssam fldsiz(utmp, ut_line), getdev(acp->ac_tty), 10917503Skarels x / (double)AHZ, ctime(&acp->ac_btime)); 1101037Sbill } 1111037Sbill } 1121037Sbill } 1131037Sbill 1141037Sbill time_t 1151037Sbill expand (t) 11611839Ssam unsigned t; 1171037Sbill { 1181037Sbill register time_t nt; 1191037Sbill 1201037Sbill nt = t & 017777; 1211037Sbill t >>= 13; 12211839Ssam while (t) { 1231037Sbill t--; 1241037Sbill nt <<= 3; 1251037Sbill } 1261037Sbill return (nt); 1271037Sbill } 1281037Sbill 1297457Skre char * 1307457Skre flagbits(f) 13111839Ssam register int f; 1321037Sbill { 1337457Skre static char flags[20]; 13434033Sbostic char *p, *strcpy(); 1357457Skre 13634033Sbostic #define BIT(flag, ch) if (f & flag) *p++ = ch; 13734033Sbostic p = strcpy(flags, "- "); 13811839Ssam BIT(ASU, 'S'); 13911839Ssam BIT(AFORK, 'F'); 14011839Ssam BIT(ACOMPAT, 'C'); 14111839Ssam BIT(ACORE, 'D'); 14211839Ssam BIT(AXSIG, 'X'); 14311839Ssam return (flags); 1447457Skre } 1457457Skre 14633688Sbostic ok(argv, acp) 14713188Ssam register char *argv[]; 14813188Ssam register struct acct *acp; 14913188Ssam { 15031126Sbostic register char *cp; 15113188Ssam 15233688Sbostic do { 15333688Sbostic if ((cp = getname(acp->ac_uid)) && !strcmp(cp, *argv) || 15433688Sbostic (cp = getdev(acp->ac_tty)) && !strcmp(cp, *argv) || 15533688Sbostic !strncmp(acp->ac_comm, *argv, fldsiz(acct, ac_comm))) 15633688Sbostic return(1); 15733688Sbostic } while (*++argv); 15833688Sbostic return(0); 15913188Ssam } 16013188Ssam 16113188Ssam /* should be done with nameserver or database */ 16213188Ssam 16334033Sbostic #include <pwd.h> 16434033Sbostic 16513188Ssam struct utmp utmp; 16613188Ssam #define NMAX (sizeof (utmp.ut_name)) 16734033Sbostic #define SCPYN(a, b) strncpy(a, b, NMAX) 16813188Ssam 16934033Sbostic #define NCACHE 64 /* power of 2 */ 17034033Sbostic #define CAMASK NCACHE - 1 17113188Ssam 17213188Ssam char * 17313188Ssam getname(uid) 17431126Sbostic uid_t uid; 17513188Ssam { 17634033Sbostic extern int _pw_stayopen; 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 _pw_stayopen = 1; 18534033Sbostic cp = c_uid + (uid & CAMASK); 18634033Sbostic if (cp->uid == uid && *cp->name) 18734033Sbostic return(cp->name); 18834033Sbostic if (!(pw = getpwuid(uid))) 18934033Sbostic return((char *)0); 19034033Sbostic cp->uid = uid; 19134033Sbostic SCPYN(cp->name, pw->pw_name); 19234033Sbostic return(cp->name); 19313188Ssam } 19413188Ssam 19513188Ssam #include <sys/dir.h> 19613188Ssam 19713188Ssam #define N_DEVS 43 /* hash value for device names */ 19813188Ssam #define NDEVS 500 /* max number of file names in /dev */ 19913188Ssam 20013188Ssam struct devhash { 20113188Ssam dev_t dev_dev; 20213188Ssam char dev_name [fldsiz(utmp, ut_line) + 1]; 20313188Ssam struct devhash * dev_nxt; 20413188Ssam }; 20513188Ssam struct devhash *dev_hash[N_DEVS]; 20613188Ssam struct devhash *dev_chain; 20713188Ssam #define HASH(d) (((int) d) % N_DEVS) 20813188Ssam 2097457Skre setupdevs() 2107457Skre { 2117457Skre register DIR * fd; 2127457Skre register struct devhash * hashtab; 2137457Skre register ndevs = NDEVS; 2147457Skre struct direct * dp; 21531126Sbostic char *malloc(); 2167457Skre 21731126Sbostic /*NOSTRICT*/ 21831126Sbostic hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash)); 21931126Sbostic if (hashtab == (struct devhash *)0) { 22031126Sbostic fputs("No mem for dev table\n", stderr); 22131126Sbostic return; 22231126Sbostic } 2237457Skre if ((fd = opendir("/dev")) == NULL) { 2247457Skre perror("/dev"); 2257457Skre return; 2261037Sbill } 2277457Skre while (dp = readdir(fd)) { 2287457Skre if (dp->d_ino == 0) 2297457Skre continue; 2307457Skre if (dp->d_name[0] != 't' && strcmp(dp->d_name, "console")) 2317457Skre continue; 2327457Skre strncpy(hashtab->dev_name, dp->d_name, fldsiz(utmp, ut_line)); 2337457Skre hashtab->dev_name[fldsiz(utmp, ut_line)] = 0; 2347457Skre hashtab->dev_nxt = dev_chain; 2357457Skre dev_chain = hashtab; 2367457Skre hashtab++; 2377457Skre if (--ndevs <= 0) 2387457Skre break; 2397457Skre } 2407457Skre closedir(fd); 2411037Sbill } 2427457Skre 2437457Skre char * 24413188Ssam getdev(dev) 24511839Ssam dev_t dev; 2467457Skre { 2477457Skre register struct devhash *hp, *nhp; 2487457Skre struct stat statb; 24911839Ssam char name[fldsiz(devhash, dev_name) + 6]; 2507457Skre static dev_t lastdev = (dev_t) -1; 2517457Skre static char *lastname; 25214925Sralph static int init = 0; 25331126Sbostic char *strcpy(), *strcat(); 2547457Skre 2557457Skre if (dev == NODEV) 25611839Ssam return ("__"); 2577457Skre if (dev == lastdev) 25811839Ssam return (lastname); 25913188Ssam if (!init) { 26013188Ssam setupdevs(); 26113188Ssam init++; 26213188Ssam } 2637457Skre for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt) 2647457Skre if (hp->dev_dev == dev) { 2657457Skre lastdev = dev; 26611839Ssam return (lastname = hp->dev_name); 2677457Skre } 2687457Skre for (hp = dev_chain; hp; hp = nhp) { 2697457Skre nhp = hp->dev_nxt; 2707457Skre strcpy(name, "/dev/"); 2717457Skre strcat(name, hp->dev_name); 2727457Skre if (stat(name, &statb) < 0) /* name truncated usually */ 2737457Skre continue; 2747457Skre if ((statb.st_mode & S_IFMT) != S_IFCHR) 2757457Skre continue; 2767457Skre hp->dev_dev = statb.st_rdev; 2777457Skre hp->dev_nxt = dev_hash[HASH(hp->dev_dev)]; 2787457Skre dev_hash[HASH(hp->dev_dev)] = hp; 2797457Skre if (hp->dev_dev == dev) { 2807457Skre dev_chain = nhp; 2817457Skre lastdev = dev; 28211839Ssam return (lastname = hp->dev_name); 2837457Skre } 2847457Skre } 2857457Skre dev_chain = (struct devhash *) 0; 28611839Ssam return ("??"); 2877457Skre } 288