121563Sdist /* 2*62049Sbostic * Copyright (c) 1980, 1993 3*62049Sbostic * The Regents of the University of California. All rights reserved. 434033Sbostic * 542735Sbostic * %sccs.include.redist.c% 621563Sdist */ 721563Sdist 811839Ssam #ifndef lint 9*62049Sbostic static char copyright[] = 10*62049Sbostic "@(#) Copyright (c) 1980, 1993\n\ 11*62049Sbostic The Regents of the University of California. All rights reserved.\n"; 1234033Sbostic #endif /* not lint */ 131037Sbill 1421563Sdist #ifndef lint 15*62049Sbostic static char sccsid[] = "@(#)lastcomm.c 8.1 (Berkeley) 06/06/93"; 1634033Sbostic #endif /* not lint */ 1721563Sdist 1811839Ssam #include <sys/param.h> 1955085Sbostic #include <sys/stat.h> 2011839Ssam #include <sys/acct.h> 2155085Sbostic 2260102Storek #include <ctype.h> 2360102Storek #include <err.h> 2455085Sbostic #include <fcntl.h> 2560102Storek #include <stdio.h> 2660102Storek #include <stdlib.h> 2760102Storek #include <string.h> 2811839Ssam #include <struct.h> 2955085Sbostic #include <unistd.h> 3060102Storek #include <utmp.h> 3137848Sbostic #include "pathnames.h" 321037Sbill 3355085Sbostic time_t expand __P((u_int)); 3455085Sbostic char *flagbits __P((int)); 3555085Sbostic char *getdev __P((dev_t)); 3655085Sbostic int requested __P((char *[], struct acct *)); 3755085Sbostic void usage __P((void)); 3855085Sbostic char *user_from_uid(); 391037Sbill 4055085Sbostic int 4111839Ssam main(argc, argv) 4233688Sbostic int argc; 4311839Ssam char *argv[]; 441037Sbill { 4555085Sbostic register char *p; 4655085Sbostic struct acct ab; 4713188Ssam struct stat sb; 4855085Sbostic FILE *fp; 4955085Sbostic off_t size; 5055085Sbostic time_t t; 5155085Sbostic int ch; 5255085Sbostic char *acctfile; 531037Sbill 5437848Sbostic acctfile = _PATH_ACCT; 5533688Sbostic while ((ch = getopt(argc, argv, "f:")) != EOF) 5633688Sbostic switch((char)ch) { 5733688Sbostic case 'f': 5833688Sbostic acctfile = optarg; 5933688Sbostic break; 6033688Sbostic case '?': 6133688Sbostic default: 6255085Sbostic usage(); 6333688Sbostic } 6455085Sbostic argc -= optind; 6533688Sbostic argv += optind; 6637848Sbostic 6755085Sbostic /* Open the file. */ 6855085Sbostic if ((fp = fopen(acctfile, "r")) == NULL || fstat(fileno(fp), &sb)) 6960102Storek err(1, "%s", acctfile); 7055085Sbostic 7155085Sbostic /* 7255085Sbostic * Round off to integral number of accounting records, probably 7355085Sbostic * not necessary, but it doesn't hurt. 7455085Sbostic */ 7555085Sbostic size = sb.st_size - sb.st_size % sizeof(struct acct); 7655085Sbostic 7755085Sbostic /* Check if any records to display. */ 7855085Sbostic if (size < sizeof(struct acct)) 7955085Sbostic exit(0); 8055085Sbostic 8155085Sbostic /* 8255085Sbostic * Seek to before the last entry in the file; use lseek(2) in case 8355085Sbostic * the file is bigger than a "long". 8455085Sbostic */ 8555085Sbostic size -= sizeof(struct acct); 8655085Sbostic if (lseek(fileno(fp), size, SEEK_SET) == -1) 8760102Storek err(1, "%s", acctfile); 8855085Sbostic 8955085Sbostic for (;;) { 9055085Sbostic if (fread(&ab, sizeof(struct acct), 1, fp) != 1) 9160102Storek err(1, "%s", acctfile); 9255085Sbostic 9355085Sbostic if (fseek(fp, 2 * -(long)sizeof(struct acct), SEEK_CUR) == -1) 9460102Storek err(1, "%s", acctfile); 9555085Sbostic 9655085Sbostic if (size == 0) 9713188Ssam break; 9855085Sbostic size -= sizeof(struct acct); 991037Sbill 10055085Sbostic if (ab.ac_comm[0] == '\0') { 10155085Sbostic ab.ac_comm[0] = '?'; 10255085Sbostic ab.ac_comm[1] = '\0'; 10355085Sbostic } else 10455085Sbostic for (p = &ab.ac_comm[0]; 10555085Sbostic p < &ab.ac_comm[fldsiz(acct, ac_comm)] && *p; ++p) 10655085Sbostic if (!isprint(*p)) 10755085Sbostic *p = '?'; 10855085Sbostic if (*argv && !requested(argv, &ab)) 10955085Sbostic continue; 11055085Sbostic 11155085Sbostic t = expand(ab.ac_utime) + expand(ab.ac_stime); 11255085Sbostic (void)printf("%-*s %-7s %-*s %-*s %6.2f secs %.16s\n", 11355085Sbostic fldsiz(acct, ac_comm), ab.ac_comm, flagbits(ab.ac_flag), 11455085Sbostic UT_NAMESIZE, user_from_uid(ab.ac_uid, 0), 11555085Sbostic UT_LINESIZE, getdev(ab.ac_tty), 11655085Sbostic t / (double)AHZ, ctime(&ab.ac_btime)); 1171037Sbill } 11855085Sbostic exit(0); 1191037Sbill } 1201037Sbill 1211037Sbill time_t 12255085Sbostic expand(t) 12355085Sbostic u_int t; 1241037Sbill { 1251037Sbill register time_t nt; 1261037Sbill 1271037Sbill nt = t & 017777; 1281037Sbill t >>= 13; 12911839Ssam while (t) { 1301037Sbill t--; 1311037Sbill nt <<= 3; 1321037Sbill } 1331037Sbill return (nt); 1341037Sbill } 1351037Sbill 1367457Skre char * 1377457Skre flagbits(f) 13811839Ssam register int f; 1391037Sbill { 14055085Sbostic static char flags[20] = "-"; 14155085Sbostic char *p; 1427457Skre 14355085Sbostic #define BIT(flag, ch) if (f & flag) *p++ = ch 14455085Sbostic 14555085Sbostic p = flags + 1; 14611839Ssam BIT(ASU, 'S'); 14711839Ssam BIT(AFORK, 'F'); 14811839Ssam BIT(ACOMPAT, 'C'); 14911839Ssam BIT(ACORE, 'D'); 15011839Ssam BIT(AXSIG, 'X'); 15155085Sbostic *p = '\0'; 15211839Ssam return (flags); 1537457Skre } 1547457Skre 15555085Sbostic int 15655085Sbostic requested(argv, acp) 15713188Ssam register char *argv[]; 15813188Ssam register struct acct *acp; 15913188Ssam { 16055085Sbostic register char *p; 16113188Ssam 16233688Sbostic do { 16355085Sbostic p = user_from_uid(acp->ac_uid, 0); 16455085Sbostic if (!strcmp(p, *argv)) 16555085Sbostic return (1); 16655085Sbostic if ((p = getdev(acp->ac_tty)) && !strcmp(p, *argv)) 16755085Sbostic return (1); 16840266Sbostic if (!strncmp(acp->ac_comm, *argv, fldsiz(acct, ac_comm))) 16955085Sbostic return (1); 17033688Sbostic } while (*++argv); 17155085Sbostic return (0); 17213188Ssam } 17313188Ssam 1747457Skre char * 17513188Ssam getdev(dev) 17611839Ssam dev_t dev; 1777457Skre { 17855085Sbostic static dev_t lastdev = (dev_t)-1; 1797457Skre static char *lastname; 1807457Skre 18155085Sbostic if (dev == NODEV) /* Special case. */ 18211839Ssam return ("__"); 18355085Sbostic if (dev == lastdev) /* One-element cache. */ 18411839Ssam return (lastname); 18555085Sbostic lastdev = dev; 18655085Sbostic lastname = devname(dev, S_IFCHR); 18755085Sbostic return (lastname); 1887457Skre } 18955085Sbostic 19055085Sbostic void 19155085Sbostic usage() 19255085Sbostic { 19355085Sbostic (void)fprintf(stderr, 19455085Sbostic "lastcomm [ -f file ] [command ...] [user ...] [tty ...]\n"); 19555085Sbostic exit(1); 19655085Sbostic } 197