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*33688Sbostic static char sccsid[] = "@(#)lastcomm.c 5.4 (Berkeley) 03/08/88"; 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) 39*33688Sbostic int argc; 4011839Ssam char *argv[]; 411037Sbill { 42*33688Sbostic extern int optind; 43*33688Sbostic extern char *optarg; 44*33688Sbostic register struct acct *acp; 4513188Ssam register int bn, cc; 4613188Ssam struct stat sb; 47*33688Sbostic int ch, fd; 48*33688Sbostic char *acctfile, *strcpy(), *ctime(); 4931126Sbostic long lseek(); 501037Sbill 51*33688Sbostic acctfile = NULL; 52*33688Sbostic while ((ch = getopt(argc, argv, "f:")) != EOF) 53*33688Sbostic switch((char)ch) { 54*33688Sbostic case 'f': 55*33688Sbostic acctfile = optarg; 56*33688Sbostic break; 57*33688Sbostic case '?': 58*33688Sbostic default: 59*33688Sbostic fputs("lastcomm [ -f file ]\n", stderr); 60*33688Sbostic exit(1); 61*33688Sbostic } 62*33688Sbostic argv += optind; 63*33688Sbostic if (!acctfile) 64*33688Sbostic acctfile = "/usr/adm/acct"; 65*33688Sbostic fd = open(acctfile, O_RDONLY); 6613188Ssam if (fd < 0) { 67*33688Sbostic perror(acctfile); 6811839Ssam exit(1); 691037Sbill } 70*33688Sbostic (void)fstat(fd, &sb); 7115634Sralph for (bn = btodb(sb.st_size); bn >= 0; bn--) { 7231126Sbostic (void)lseek(fd, (off_t)dbtob(bn), L_SET); 7313188Ssam cc = read(fd, buf, DEV_BSIZE); 7413188Ssam if (cc < 0) { 7513188Ssam perror("read"); 7613188Ssam break; 7713188Ssam } 7813188Ssam acp = buf + (cc / sizeof (buf[0])) - 1; 7913188Ssam for (; acp >= buf; acp--) { 8013188Ssam register char *cp; 8117764Sralph time_t x; 821037Sbill 8317905Sralph if (acp->ac_comm[0] == '\0') 84*33688Sbostic (void)strcpy(acp->ac_comm, "?"); 8517905Sralph for (cp = &acp->ac_comm[0]; 8617905Sralph cp < &acp->ac_comm[fldsiz(acct, ac_comm)] && *cp; 8717905Sralph cp++) 8817905Sralph if (!isascii(*cp) || iscntrl(*cp)) 8913188Ssam *cp = '?'; 90*33688Sbostic if (*argv && !ok(argv, acp)) 9111839Ssam continue; 9217764Sralph x = expand(acp->ac_utime) + expand(acp->ac_stime); 9327699Slepreau printf("%-*.*s %s %-*s %-*s %6.2f secs %.16s\n", 9431126Sbostic fldsiz(acct, ac_comm), 9531126Sbostic fldsiz(acct, ac_comm), 9631126Sbostic acp->ac_comm, flagbits(acp->ac_flag), 9731126Sbostic fldsiz(utmp, ut_name), 9831126Sbostic (cp = getname(acp->ac_uid)) ? cp : "", 9913188Ssam fldsiz(utmp, ut_line), getdev(acp->ac_tty), 10017503Skarels x / (double)AHZ, ctime(&acp->ac_btime)); 1011037Sbill } 1021037Sbill } 1031037Sbill } 1041037Sbill 1051037Sbill time_t 1061037Sbill expand (t) 10711839Ssam unsigned t; 1081037Sbill { 1091037Sbill register time_t nt; 1101037Sbill 1111037Sbill nt = t & 017777; 1121037Sbill t >>= 13; 11311839Ssam while (t) { 1141037Sbill t--; 1151037Sbill nt <<= 3; 1161037Sbill } 1171037Sbill return (nt); 1181037Sbill } 1191037Sbill 1207457Skre char * 1217457Skre flagbits(f) 12211839Ssam register int f; 1231037Sbill { 1247457Skre register int i = 0; 1257457Skre static char flags[20]; 1267457Skre 12711839Ssam #define BIT(flag, ch) flags[i++] = (f & flag) ? ch : ' ' 12811839Ssam BIT(ASU, 'S'); 12911839Ssam BIT(AFORK, 'F'); 13011839Ssam BIT(ACOMPAT, 'C'); 13111839Ssam BIT(ACORE, 'D'); 13211839Ssam BIT(AXSIG, 'X'); 1337457Skre flags[i] = '\0'; 13411839Ssam return (flags); 1357457Skre } 1367457Skre 137*33688Sbostic ok(argv, acp) 13813188Ssam register char *argv[]; 13913188Ssam register struct acct *acp; 14013188Ssam { 14131126Sbostic register char *cp; 14213188Ssam 143*33688Sbostic do { 144*33688Sbostic if ((cp = getname(acp->ac_uid)) && !strcmp(cp, *argv) || 145*33688Sbostic (cp = getdev(acp->ac_tty)) && !strcmp(cp, *argv) || 146*33688Sbostic !strncmp(acp->ac_comm, *argv, fldsiz(acct, ac_comm))) 147*33688Sbostic return(1); 148*33688Sbostic } while (*++argv); 149*33688Sbostic return(0); 15013188Ssam } 15113188Ssam 15213188Ssam /* should be done with nameserver or database */ 15313188Ssam 15413188Ssam struct utmp utmp; 15513188Ssam 15613188Ssam #define NUID 2048 15713188Ssam #define NMAX (sizeof (utmp.ut_name)) 15813188Ssam 15913188Ssam char names[NUID][NMAX+1]; 16013188Ssam char outrangename[NMAX+1]; 16113188Ssam int outrangeuid = -1; 16213188Ssam 16313188Ssam char * 16413188Ssam getname(uid) 16531126Sbostic uid_t uid; 16613188Ssam { 16713188Ssam register struct passwd *pw; 16813188Ssam static init; 16913188Ssam struct passwd *getpwent(); 17013188Ssam 17131126Sbostic if (uid < NUID && names[uid][0]) 17213188Ssam return (&names[uid][0]); 17331126Sbostic if (uid == outrangeuid) 17413188Ssam return (outrangename); 17513188Ssam if (init == 2) { 17613188Ssam if (uid < NUID) 17713188Ssam return (0); 17813188Ssam setpwent(); 17913188Ssam while (pw = getpwent()) { 18013188Ssam if (pw->pw_uid != uid) 18113188Ssam continue; 18213188Ssam outrangeuid = pw->pw_uid; 18314768Ssam strncpy(outrangename, pw->pw_name, NMAX); 18413188Ssam endpwent(); 18513188Ssam return (outrangename); 18613188Ssam } 18713188Ssam endpwent(); 18813188Ssam return (0); 18913188Ssam } 19013188Ssam if (init == 0) 19113188Ssam setpwent(), init = 1; 19213188Ssam while (pw = getpwent()) { 19313188Ssam if (pw->pw_uid < 0 || pw->pw_uid >= NUID) { 19413188Ssam if (pw->pw_uid == uid) { 19513188Ssam outrangeuid = pw->pw_uid; 19614768Ssam strncpy(outrangename, pw->pw_name, NMAX); 19713188Ssam return (outrangename); 19813188Ssam } 19913188Ssam continue; 20013188Ssam } 20113188Ssam if (names[pw->pw_uid][0]) 20213188Ssam continue; 20313188Ssam strncpy(names[pw->pw_uid], pw->pw_name, NMAX); 20413188Ssam if (pw->pw_uid == uid) 20513188Ssam return (&names[uid][0]); 20613188Ssam } 20713188Ssam init = 2; 20813188Ssam endpwent(); 20913188Ssam return (0); 21013188Ssam } 21113188Ssam 21213188Ssam #include <sys/dir.h> 21313188Ssam 21413188Ssam #define N_DEVS 43 /* hash value for device names */ 21513188Ssam #define NDEVS 500 /* max number of file names in /dev */ 21613188Ssam 21713188Ssam struct devhash { 21813188Ssam dev_t dev_dev; 21913188Ssam char dev_name [fldsiz(utmp, ut_line) + 1]; 22013188Ssam struct devhash * dev_nxt; 22113188Ssam }; 22213188Ssam struct devhash *dev_hash[N_DEVS]; 22313188Ssam struct devhash *dev_chain; 22413188Ssam #define HASH(d) (((int) d) % N_DEVS) 22513188Ssam 2267457Skre setupdevs() 2277457Skre { 2287457Skre register DIR * fd; 2297457Skre register struct devhash * hashtab; 2307457Skre register ndevs = NDEVS; 2317457Skre struct direct * dp; 23231126Sbostic char *malloc(); 2337457Skre 23431126Sbostic /*NOSTRICT*/ 23531126Sbostic hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash)); 23631126Sbostic if (hashtab == (struct devhash *)0) { 23731126Sbostic fputs("No mem for dev table\n", stderr); 23831126Sbostic return; 23931126Sbostic } 2407457Skre if ((fd = opendir("/dev")) == NULL) { 2417457Skre perror("/dev"); 2427457Skre return; 2431037Sbill } 2447457Skre while (dp = readdir(fd)) { 2457457Skre if (dp->d_ino == 0) 2467457Skre continue; 2477457Skre if (dp->d_name[0] != 't' && strcmp(dp->d_name, "console")) 2487457Skre continue; 2497457Skre strncpy(hashtab->dev_name, dp->d_name, fldsiz(utmp, ut_line)); 2507457Skre hashtab->dev_name[fldsiz(utmp, ut_line)] = 0; 2517457Skre hashtab->dev_nxt = dev_chain; 2527457Skre dev_chain = hashtab; 2537457Skre hashtab++; 2547457Skre if (--ndevs <= 0) 2557457Skre break; 2567457Skre } 2577457Skre closedir(fd); 2581037Sbill } 2597457Skre 2607457Skre char * 26113188Ssam getdev(dev) 26211839Ssam dev_t dev; 2637457Skre { 2647457Skre register struct devhash *hp, *nhp; 2657457Skre struct stat statb; 26611839Ssam char name[fldsiz(devhash, dev_name) + 6]; 2677457Skre static dev_t lastdev = (dev_t) -1; 2687457Skre static char *lastname; 26914925Sralph static int init = 0; 27031126Sbostic char *strcpy(), *strcat(); 2717457Skre 2727457Skre if (dev == NODEV) 27311839Ssam return ("__"); 2747457Skre if (dev == lastdev) 27511839Ssam return (lastname); 27613188Ssam if (!init) { 27713188Ssam setupdevs(); 27813188Ssam init++; 27913188Ssam } 2807457Skre for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt) 2817457Skre if (hp->dev_dev == dev) { 2827457Skre lastdev = dev; 28311839Ssam return (lastname = hp->dev_name); 2847457Skre } 2857457Skre for (hp = dev_chain; hp; hp = nhp) { 2867457Skre nhp = hp->dev_nxt; 2877457Skre strcpy(name, "/dev/"); 2887457Skre strcat(name, hp->dev_name); 2897457Skre if (stat(name, &statb) < 0) /* name truncated usually */ 2907457Skre continue; 2917457Skre if ((statb.st_mode & S_IFMT) != S_IFCHR) 2927457Skre continue; 2937457Skre hp->dev_dev = statb.st_rdev; 2947457Skre hp->dev_nxt = dev_hash[HASH(hp->dev_dev)]; 2957457Skre dev_hash[HASH(hp->dev_dev)] = hp; 2967457Skre if (hp->dev_dev == dev) { 2977457Skre dev_chain = nhp; 2987457Skre lastdev = dev; 29911839Ssam return (lastname = hp->dev_name); 3007457Skre } 3017457Skre } 3027457Skre dev_chain = (struct devhash *) 0; 30311839Ssam return ("??"); 3047457Skre } 305