121563Sdist /*
262049Sbostic * Copyright (c) 1980, 1993
362049Sbostic * The Regents of the University of California. All rights reserved.
434033Sbostic *
542735Sbostic * %sccs.include.redist.c%
621563Sdist */
721563Sdist
811839Ssam #ifndef lint
962049Sbostic static char copyright[] =
1062049Sbostic "@(#) Copyright (c) 1980, 1993\n\
1162049Sbostic The Regents of the University of California. All rights reserved.\n";
1234033Sbostic #endif /* not lint */
131037Sbill
1421563Sdist #ifndef lint
15*69122Sbostic static char sccsid[] = "@(#)lastcomm.c 8.2 (Berkeley) 04/29/95";
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
main(argc,argv)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
expand(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 *
flagbits(f)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
requested(argv,acp)15655085Sbostic requested(argv, acp)
15713188Ssam register char *argv[];
15813188Ssam register struct acct *acp;
15913188Ssam {
16033688Sbostic do {
161*69122Sbostic if (!strcmp(user_from_uid(acp->ac_uid, 0), *argv))
16255085Sbostic return (1);
163*69122Sbostic if (!strcmp(getdev(acp->ac_tty), *argv))
16455085Sbostic return (1);
16540266Sbostic if (!strncmp(acp->ac_comm, *argv, fldsiz(acct, ac_comm)))
16655085Sbostic return (1);
16733688Sbostic } while (*++argv);
16855085Sbostic return (0);
16913188Ssam }
17013188Ssam
1717457Skre char *
getdev(dev)17213188Ssam getdev(dev)
17311839Ssam dev_t dev;
1747457Skre {
17555085Sbostic static dev_t lastdev = (dev_t)-1;
1767457Skre static char *lastname;
1777457Skre
17855085Sbostic if (dev == NODEV) /* Special case. */
17911839Ssam return ("__");
18055085Sbostic if (dev == lastdev) /* One-element cache. */
18111839Ssam return (lastname);
18255085Sbostic lastdev = dev;
183*69122Sbostic if ((lastname = devname(dev, S_IFCHR)) == NULL)
184*69122Sbostic lastname = "??";
18555085Sbostic return (lastname);
1867457Skre }
18755085Sbostic
18855085Sbostic void
usage()18955085Sbostic usage()
19055085Sbostic {
19155085Sbostic (void)fprintf(stderr,
19255085Sbostic "lastcomm [ -f file ] [command ...] [user ...] [tty ...]\n");
19355085Sbostic exit(1);
19455085Sbostic }
195