1*21563Sdist /* 2*21563Sdist * Copyright (c) 1980 Regents of the University of California. 3*21563Sdist * All rights reserved. The Berkeley software License Agreement 4*21563Sdist * specifies the terms and conditions for redistribution. 5*21563Sdist */ 6*21563Sdist 711839Ssam #ifndef lint 8*21563Sdist char copyright[] = 9*21563Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 10*21563Sdist All rights reserved.\n"; 11*21563Sdist #endif not lint 121037Sbill 13*21563Sdist #ifndef lint 14*21563Sdist static char sccsid[] = "@(#)lastcomm.c 5.1 (Berkeley) 05/31/85"; 15*21563Sdist #endif not lint 16*21563Sdist 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); 7417503Skarels printf("%-*s %s %-*s %-*s %6.2f secs %.16s\n", 7511839Ssam fldsiz(acct, ac_comm), acp->ac_comm, 7611839Ssam flagbits(acp->ac_flag), 7713188Ssam fldsiz(utmp, ut_name), getname(acp->ac_uid), 7813188Ssam fldsiz(utmp, ut_line), getdev(acp->ac_tty), 7917503Skarels x / (double)AHZ, ctime(&acp->ac_btime)); 801037Sbill } 811037Sbill } 821037Sbill } 831037Sbill 841037Sbill time_t 851037Sbill expand (t) 8611839Ssam unsigned t; 871037Sbill { 881037Sbill register time_t nt; 891037Sbill 901037Sbill nt = t & 017777; 911037Sbill t >>= 13; 9211839Ssam while (t) { 931037Sbill t--; 941037Sbill nt <<= 3; 951037Sbill } 961037Sbill return (nt); 971037Sbill } 981037Sbill 997457Skre char * 1007457Skre flagbits(f) 10111839Ssam register int f; 1021037Sbill { 1037457Skre register int i = 0; 1047457Skre static char flags[20]; 1057457Skre 10611839Ssam #define BIT(flag, ch) flags[i++] = (f & flag) ? ch : ' ' 10711839Ssam BIT(ASU, 'S'); 10811839Ssam BIT(AFORK, 'F'); 10911839Ssam BIT(ACOMPAT, 'C'); 11011839Ssam BIT(ACORE, 'D'); 11111839Ssam BIT(AXSIG, 'X'); 1127457Skre flags[i] = '\0'; 11311839Ssam return (flags); 1147457Skre } 1157457Skre 11613188Ssam ok(argc, argv, acp) 11713188Ssam register int argc; 11813188Ssam register char *argv[]; 11913188Ssam register struct acct *acp; 12013188Ssam { 12113188Ssam register int j; 12213188Ssam 12313188Ssam for (j = 1; j < argc; j++) 12413188Ssam if (strcmp(getname(acp->ac_uid), argv[j]) && 12513188Ssam strcmp(getdev(acp->ac_tty), argv[j]) && 12617905Sralph strncmp(acp->ac_comm, argv[j], fldsiz(acct, ac_comm))) 12713188Ssam break; 12813188Ssam return (j == argc); 12913188Ssam } 13013188Ssam 13113188Ssam /* should be done with nameserver or database */ 13213188Ssam 13313188Ssam struct utmp utmp; 13413188Ssam 13513188Ssam #define NUID 2048 13613188Ssam #define NMAX (sizeof (utmp.ut_name)) 13713188Ssam 13813188Ssam char names[NUID][NMAX+1]; 13913188Ssam char outrangename[NMAX+1]; 14013188Ssam int outrangeuid = -1; 14113188Ssam 14213188Ssam char * 14313188Ssam getname(uid) 14413188Ssam { 14513188Ssam register struct passwd *pw; 14613188Ssam static init; 14713188Ssam struct passwd *getpwent(); 14813188Ssam 14913188Ssam if (uid >= 0 && uid < NUID && names[uid][0]) 15013188Ssam return (&names[uid][0]); 15113188Ssam if (uid >= 0 && uid == outrangeuid) 15213188Ssam return (outrangename); 15313188Ssam if (init == 2) { 15413188Ssam if (uid < NUID) 15513188Ssam return (0); 15613188Ssam setpwent(); 15713188Ssam while (pw = getpwent()) { 15813188Ssam if (pw->pw_uid != uid) 15913188Ssam continue; 16013188Ssam outrangeuid = pw->pw_uid; 16114768Ssam strncpy(outrangename, pw->pw_name, NMAX); 16213188Ssam endpwent(); 16313188Ssam return (outrangename); 16413188Ssam } 16513188Ssam endpwent(); 16613188Ssam return (0); 16713188Ssam } 16813188Ssam if (init == 0) 16913188Ssam setpwent(), init = 1; 17013188Ssam while (pw = getpwent()) { 17113188Ssam if (pw->pw_uid < 0 || pw->pw_uid >= NUID) { 17213188Ssam if (pw->pw_uid == uid) { 17313188Ssam outrangeuid = pw->pw_uid; 17414768Ssam strncpy(outrangename, pw->pw_name, NMAX); 17513188Ssam return (outrangename); 17613188Ssam } 17713188Ssam continue; 17813188Ssam } 17913188Ssam if (names[pw->pw_uid][0]) 18013188Ssam continue; 18113188Ssam strncpy(names[pw->pw_uid], pw->pw_name, NMAX); 18213188Ssam if (pw->pw_uid == uid) 18313188Ssam return (&names[uid][0]); 18413188Ssam } 18513188Ssam init = 2; 18613188Ssam endpwent(); 18713188Ssam return (0); 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; 2107457Skre 2117457Skre if ((fd = opendir("/dev")) == NULL) { 2127457Skre perror("/dev"); 2137457Skre return; 2141037Sbill } 21513188Ssam hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash)); 21613188Ssam if (hashtab == (struct devhash *)0) { 2177457Skre fprintf(stderr, "No mem for dev table\n"); 21814925Sralph closedir(fd); 2197457Skre return; 2207457Skre } 2217457Skre while (dp = readdir(fd)) { 2227457Skre if (dp->d_ino == 0) 2237457Skre continue; 2247457Skre if (dp->d_name[0] != 't' && strcmp(dp->d_name, "console")) 2257457Skre continue; 2267457Skre strncpy(hashtab->dev_name, dp->d_name, fldsiz(utmp, ut_line)); 2277457Skre hashtab->dev_name[fldsiz(utmp, ut_line)] = 0; 2287457Skre hashtab->dev_nxt = dev_chain; 2297457Skre dev_chain = hashtab; 2307457Skre hashtab++; 2317457Skre if (--ndevs <= 0) 2327457Skre break; 2337457Skre } 2347457Skre closedir(fd); 2351037Sbill } 2367457Skre 2377457Skre char * 23813188Ssam getdev(dev) 23911839Ssam dev_t dev; 2407457Skre { 2417457Skre register struct devhash *hp, *nhp; 2427457Skre struct stat statb; 24311839Ssam char name[fldsiz(devhash, dev_name) + 6]; 2447457Skre static dev_t lastdev = (dev_t) -1; 2457457Skre static char *lastname; 24614925Sralph static int init = 0; 2477457Skre 2487457Skre if (dev == NODEV) 24911839Ssam return ("__"); 2507457Skre if (dev == lastdev) 25111839Ssam return (lastname); 25213188Ssam if (!init) { 25313188Ssam setupdevs(); 25413188Ssam init++; 25513188Ssam } 2567457Skre for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt) 2577457Skre if (hp->dev_dev == dev) { 2587457Skre lastdev = dev; 25911839Ssam return (lastname = hp->dev_name); 2607457Skre } 2617457Skre for (hp = dev_chain; hp; hp = nhp) { 2627457Skre nhp = hp->dev_nxt; 2637457Skre strcpy(name, "/dev/"); 2647457Skre strcat(name, hp->dev_name); 2657457Skre if (stat(name, &statb) < 0) /* name truncated usually */ 2667457Skre continue; 2677457Skre if ((statb.st_mode & S_IFMT) != S_IFCHR) 2687457Skre continue; 2697457Skre hp->dev_dev = statb.st_rdev; 2707457Skre hp->dev_nxt = dev_hash[HASH(hp->dev_dev)]; 2717457Skre dev_hash[HASH(hp->dev_dev)] = hp; 2727457Skre if (hp->dev_dev == dev) { 2737457Skre dev_chain = nhp; 2747457Skre lastdev = dev; 27511839Ssam return (lastname = hp->dev_name); 2767457Skre } 2777457Skre } 2787457Skre dev_chain = (struct devhash *) 0; 27911839Ssam return ("??"); 2807457Skre } 281