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*27699Slepreau static char sccsid[] = "@(#)lastcomm.c 5.2 (Berkeley) 05/04/86"; 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; 451037Sbill 4613188Ssam fd = open("/usr/adm/acct", O_RDONLY); 4713188Ssam if (fd < 0) { 4811839Ssam perror("/usr/adm/acct"); 4911839Ssam exit(1); 501037Sbill } 5113188Ssam fstat(fd, &sb); 5215634Sralph for (bn = btodb(sb.st_size); bn >= 0; bn--) { 5315634Sralph lseek(fd, dbtob(bn), L_SET); 5413188Ssam cc = read(fd, buf, DEV_BSIZE); 5513188Ssam if (cc < 0) { 5613188Ssam perror("read"); 5713188Ssam break; 5813188Ssam } 5913188Ssam acp = buf + (cc / sizeof (buf[0])) - 1; 6013188Ssam for (; acp >= buf; acp--) { 6113188Ssam register char *cp; 6217764Sralph time_t x; 631037Sbill 6417905Sralph if (acp->ac_comm[0] == '\0') 6511839Ssam strcpy(acp->ac_comm, "?"); 6617905Sralph for (cp = &acp->ac_comm[0]; 6717905Sralph cp < &acp->ac_comm[fldsiz(acct, ac_comm)] && *cp; 6817905Sralph cp++) 6917905Sralph if (!isascii(*cp) || iscntrl(*cp)) 7013188Ssam *cp = '?'; 7117764Sralph if (argc > 1 && !ok(argc, argv, acp)) 7211839Ssam continue; 7317764Sralph x = expand(acp->ac_utime) + expand(acp->ac_stime); 74*27699Slepreau printf("%-*.*s %s %-*s %-*s %6.2f secs %.16s\n", 75*27699Slepreau fldsiz(acct, ac_comm), fldsiz(acct, ac_comm), 76*27699Slepreau acp->ac_comm, 7711839Ssam flagbits(acp->ac_flag), 7813188Ssam fldsiz(utmp, ut_name), getname(acp->ac_uid), 7913188Ssam fldsiz(utmp, ut_line), getdev(acp->ac_tty), 8017503Skarels x / (double)AHZ, ctime(&acp->ac_btime)); 811037Sbill } 821037Sbill } 831037Sbill } 841037Sbill 851037Sbill time_t 861037Sbill expand (t) 8711839Ssam unsigned t; 881037Sbill { 891037Sbill register time_t nt; 901037Sbill 911037Sbill nt = t & 017777; 921037Sbill t >>= 13; 9311839Ssam while (t) { 941037Sbill t--; 951037Sbill nt <<= 3; 961037Sbill } 971037Sbill return (nt); 981037Sbill } 991037Sbill 1007457Skre char * 1017457Skre flagbits(f) 10211839Ssam register int f; 1031037Sbill { 1047457Skre register int i = 0; 1057457Skre static char flags[20]; 1067457Skre 10711839Ssam #define BIT(flag, ch) flags[i++] = (f & flag) ? ch : ' ' 10811839Ssam BIT(ASU, 'S'); 10911839Ssam BIT(AFORK, 'F'); 11011839Ssam BIT(ACOMPAT, 'C'); 11111839Ssam BIT(ACORE, 'D'); 11211839Ssam BIT(AXSIG, 'X'); 1137457Skre flags[i] = '\0'; 11411839Ssam return (flags); 1157457Skre } 1167457Skre 11713188Ssam ok(argc, argv, acp) 11813188Ssam register int argc; 11913188Ssam register char *argv[]; 12013188Ssam register struct acct *acp; 12113188Ssam { 12213188Ssam register int j; 12313188Ssam 12413188Ssam for (j = 1; j < argc; j++) 12513188Ssam if (strcmp(getname(acp->ac_uid), argv[j]) && 12613188Ssam strcmp(getdev(acp->ac_tty), argv[j]) && 12717905Sralph strncmp(acp->ac_comm, argv[j], fldsiz(acct, ac_comm))) 12813188Ssam break; 12913188Ssam return (j == argc); 13013188Ssam } 13113188Ssam 13213188Ssam /* should be done with nameserver or database */ 13313188Ssam 13413188Ssam struct utmp utmp; 13513188Ssam 13613188Ssam #define NUID 2048 13713188Ssam #define NMAX (sizeof (utmp.ut_name)) 13813188Ssam 13913188Ssam char names[NUID][NMAX+1]; 14013188Ssam char outrangename[NMAX+1]; 14113188Ssam int outrangeuid = -1; 14213188Ssam 14313188Ssam char * 14413188Ssam getname(uid) 14513188Ssam { 14613188Ssam register struct passwd *pw; 14713188Ssam static init; 14813188Ssam struct passwd *getpwent(); 14913188Ssam 15013188Ssam if (uid >= 0 && uid < NUID && names[uid][0]) 15113188Ssam return (&names[uid][0]); 15213188Ssam if (uid >= 0 && uid == outrangeuid) 15313188Ssam return (outrangename); 15413188Ssam if (init == 2) { 15513188Ssam if (uid < NUID) 15613188Ssam return (0); 15713188Ssam setpwent(); 15813188Ssam while (pw = getpwent()) { 15913188Ssam if (pw->pw_uid != uid) 16013188Ssam continue; 16113188Ssam outrangeuid = pw->pw_uid; 16214768Ssam strncpy(outrangename, pw->pw_name, NMAX); 16313188Ssam endpwent(); 16413188Ssam return (outrangename); 16513188Ssam } 16613188Ssam endpwent(); 16713188Ssam return (0); 16813188Ssam } 16913188Ssam if (init == 0) 17013188Ssam setpwent(), init = 1; 17113188Ssam while (pw = getpwent()) { 17213188Ssam if (pw->pw_uid < 0 || pw->pw_uid >= NUID) { 17313188Ssam if (pw->pw_uid == uid) { 17413188Ssam outrangeuid = pw->pw_uid; 17514768Ssam strncpy(outrangename, pw->pw_name, NMAX); 17613188Ssam return (outrangename); 17713188Ssam } 17813188Ssam continue; 17913188Ssam } 18013188Ssam if (names[pw->pw_uid][0]) 18113188Ssam continue; 18213188Ssam strncpy(names[pw->pw_uid], pw->pw_name, NMAX); 18313188Ssam if (pw->pw_uid == uid) 18413188Ssam return (&names[uid][0]); 18513188Ssam } 18613188Ssam init = 2; 18713188Ssam endpwent(); 18813188Ssam return (0); 18913188Ssam } 19013188Ssam 19113188Ssam #include <sys/dir.h> 19213188Ssam 19313188Ssam #define N_DEVS 43 /* hash value for device names */ 19413188Ssam #define NDEVS 500 /* max number of file names in /dev */ 19513188Ssam 19613188Ssam struct devhash { 19713188Ssam dev_t dev_dev; 19813188Ssam char dev_name [fldsiz(utmp, ut_line) + 1]; 19913188Ssam struct devhash * dev_nxt; 20013188Ssam }; 20113188Ssam struct devhash *dev_hash[N_DEVS]; 20213188Ssam struct devhash *dev_chain; 20313188Ssam #define HASH(d) (((int) d) % N_DEVS) 20413188Ssam 2057457Skre setupdevs() 2067457Skre { 2077457Skre register DIR * fd; 2087457Skre register struct devhash * hashtab; 2097457Skre register ndevs = NDEVS; 2107457Skre struct direct * dp; 2117457Skre 2127457Skre if ((fd = opendir("/dev")) == NULL) { 2137457Skre perror("/dev"); 2147457Skre return; 2151037Sbill } 21613188Ssam hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash)); 21713188Ssam if (hashtab == (struct devhash *)0) { 2187457Skre fprintf(stderr, "No mem for dev table\n"); 21914925Sralph closedir(fd); 2207457Skre return; 2217457Skre } 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; 2487457Skre 2497457Skre if (dev == NODEV) 25011839Ssam return ("__"); 2517457Skre if (dev == lastdev) 25211839Ssam return (lastname); 25313188Ssam if (!init) { 25413188Ssam setupdevs(); 25513188Ssam init++; 25613188Ssam } 2577457Skre for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt) 2587457Skre if (hp->dev_dev == dev) { 2597457Skre lastdev = dev; 26011839Ssam return (lastname = hp->dev_name); 2617457Skre } 2627457Skre for (hp = dev_chain; hp; hp = nhp) { 2637457Skre nhp = hp->dev_nxt; 2647457Skre strcpy(name, "/dev/"); 2657457Skre strcat(name, hp->dev_name); 2667457Skre if (stat(name, &statb) < 0) /* name truncated usually */ 2677457Skre continue; 2687457Skre if ((statb.st_mode & S_IFMT) != S_IFCHR) 2697457Skre continue; 2707457Skre hp->dev_dev = statb.st_rdev; 2717457Skre hp->dev_nxt = dev_hash[HASH(hp->dev_dev)]; 2727457Skre dev_hash[HASH(hp->dev_dev)] = hp; 2737457Skre if (hp->dev_dev == dev) { 2747457Skre dev_chain = nhp; 2757457Skre lastdev = dev; 27611839Ssam return (lastname = hp->dev_name); 2777457Skre } 2787457Skre } 2797457Skre dev_chain = (struct devhash *) 0; 28011839Ssam return ("??"); 2817457Skre } 282