xref: /csrg-svn/usr.bin/lastcomm/lastcomm.c (revision 60102)
121563Sdist /*
221563Sdist  * Copyright (c) 1980 Regents of the University of California.
334033Sbostic  * All rights reserved.
434033Sbostic  *
542735Sbostic  * %sccs.include.redist.c%
621563Sdist  */
721563Sdist 
811839Ssam #ifndef lint
921563Sdist char copyright[] =
1021563Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\
1121563Sdist  All rights reserved.\n";
1234033Sbostic #endif /* not lint */
131037Sbill 
1421563Sdist #ifndef lint
15*60102Storek static char sccsid[] = "@(#)lastcomm.c	5.13 (Berkeley) 05/17/93";
1634033Sbostic #endif /* not lint */
1721563Sdist 
1811839Ssam #include <sys/param.h>
1955085Sbostic #include <sys/stat.h>
2011839Ssam #include <sys/acct.h>
2155085Sbostic 
22*60102Storek #include <ctype.h>
23*60102Storek #include <err.h>
2455085Sbostic #include <fcntl.h>
25*60102Storek #include <stdio.h>
26*60102Storek #include <stdlib.h>
27*60102Storek #include <string.h>
2811839Ssam #include <struct.h>
2955085Sbostic #include <unistd.h>
30*60102Storek #include <utmp.h>
3137848Sbostic #include "pathnames.h"
321037Sbill 
3355085Sbostic char	*devname __P((dev_t, mode_t));
3455085Sbostic time_t	 expand __P((u_int));
3555085Sbostic char	*flagbits __P((int));
3655085Sbostic char	*getdev __P((dev_t));
3755085Sbostic int	 requested __P((char *[], struct acct *));
3855085Sbostic void	 usage __P((void));
3955085Sbostic char	*user_from_uid();
401037Sbill 
4155085Sbostic int
4211839Ssam main(argc, argv)
4333688Sbostic 	int argc;
4411839Ssam 	char *argv[];
451037Sbill {
4655085Sbostic 	register char *p;
4755085Sbostic 	struct acct ab;
4813188Ssam 	struct stat sb;
4955085Sbostic 	FILE *fp;
5055085Sbostic 	off_t size;
5155085Sbostic 	time_t t;
5255085Sbostic 	int ch;
5355085Sbostic 	char *acctfile;
541037Sbill 
5537848Sbostic 	acctfile = _PATH_ACCT;
5633688Sbostic 	while ((ch = getopt(argc, argv, "f:")) != EOF)
5733688Sbostic 		switch((char)ch) {
5833688Sbostic 		case 'f':
5933688Sbostic 			acctfile = optarg;
6033688Sbostic 			break;
6133688Sbostic 		case '?':
6233688Sbostic 		default:
6355085Sbostic 			usage();
6433688Sbostic 		}
6555085Sbostic 	argc -= optind;
6633688Sbostic 	argv += optind;
6737848Sbostic 
6855085Sbostic 	/* Open the file. */
6955085Sbostic 	if ((fp = fopen(acctfile, "r")) == NULL || fstat(fileno(fp), &sb))
70*60102Storek 		err(1, "%s", acctfile);
7155085Sbostic 
7255085Sbostic 	/*
7355085Sbostic 	 * Round off to integral number of accounting records, probably
7455085Sbostic 	 * not necessary, but it doesn't hurt.
7555085Sbostic 	 */
7655085Sbostic 	size = sb.st_size - sb.st_size % sizeof(struct acct);
7755085Sbostic 
7855085Sbostic 	/* Check if any records to display. */
7955085Sbostic 	if (size < sizeof(struct acct))
8055085Sbostic 		exit(0);
8155085Sbostic 
8255085Sbostic 	/*
8355085Sbostic 	 * Seek to before the last entry in the file; use lseek(2) in case
8455085Sbostic 	 * the file is bigger than a "long".
8555085Sbostic 	 */
8655085Sbostic 	size -= sizeof(struct acct);
8755085Sbostic 	if (lseek(fileno(fp), size, SEEK_SET) == -1)
88*60102Storek 		err(1, "%s", acctfile);
8955085Sbostic 
9055085Sbostic 	for (;;) {
9155085Sbostic 		if (fread(&ab, sizeof(struct acct), 1, fp) != 1)
92*60102Storek 			err(1, "%s", acctfile);
9355085Sbostic 
9455085Sbostic 		if (fseek(fp, 2 * -(long)sizeof(struct acct), SEEK_CUR) == -1)
95*60102Storek 			err(1, "%s", acctfile);
9655085Sbostic 
9755085Sbostic 		if (size == 0)
9813188Ssam 			break;
9955085Sbostic 		size -= sizeof(struct acct);
1001037Sbill 
10155085Sbostic 		if (ab.ac_comm[0] == '\0') {
10255085Sbostic 			ab.ac_comm[0] = '?';
10355085Sbostic 			ab.ac_comm[1] = '\0';
10455085Sbostic 		} else
10555085Sbostic 			for (p = &ab.ac_comm[0];
10655085Sbostic 			    p < &ab.ac_comm[fldsiz(acct, ac_comm)] && *p; ++p)
10755085Sbostic 				if (!isprint(*p))
10855085Sbostic 					*p = '?';
10955085Sbostic 		if (*argv && !requested(argv, &ab))
11055085Sbostic 			continue;
11155085Sbostic 
11255085Sbostic 		t = expand(ab.ac_utime) + expand(ab.ac_stime);
11355085Sbostic 		(void)printf("%-*s %-7s %-*s %-*s %6.2f secs %.16s\n",
11455085Sbostic 			fldsiz(acct, ac_comm), ab.ac_comm, flagbits(ab.ac_flag),
11555085Sbostic 			UT_NAMESIZE, user_from_uid(ab.ac_uid, 0),
11655085Sbostic 			UT_LINESIZE, getdev(ab.ac_tty),
11755085Sbostic 			t / (double)AHZ, ctime(&ab.ac_btime));
1181037Sbill 	}
11955085Sbostic 	exit(0);
1201037Sbill }
1211037Sbill 
1221037Sbill time_t
12355085Sbostic expand(t)
12455085Sbostic 	u_int t;
1251037Sbill {
1261037Sbill 	register time_t nt;
1271037Sbill 
1281037Sbill 	nt = t & 017777;
1291037Sbill 	t >>= 13;
13011839Ssam 	while (t) {
1311037Sbill 		t--;
1321037Sbill 		nt <<= 3;
1331037Sbill 	}
1341037Sbill 	return (nt);
1351037Sbill }
1361037Sbill 
1377457Skre char *
1387457Skre flagbits(f)
13911839Ssam 	register int f;
1401037Sbill {
14155085Sbostic 	static char flags[20] = "-";
14255085Sbostic 	char *p;
1437457Skre 
14455085Sbostic #define	BIT(flag, ch)	if (f & flag) *p++ = ch
14555085Sbostic 
14655085Sbostic 	p = flags + 1;
14711839Ssam 	BIT(ASU, 'S');
14811839Ssam 	BIT(AFORK, 'F');
14911839Ssam 	BIT(ACOMPAT, 'C');
15011839Ssam 	BIT(ACORE, 'D');
15111839Ssam 	BIT(AXSIG, 'X');
15255085Sbostic 	*p = '\0';
15311839Ssam 	return (flags);
1547457Skre }
1557457Skre 
15655085Sbostic int
15755085Sbostic requested(argv, acp)
15813188Ssam 	register char *argv[];
15913188Ssam 	register struct acct *acp;
16013188Ssam {
16155085Sbostic 	register char *p;
16213188Ssam 
16333688Sbostic 	do {
16455085Sbostic 		p = user_from_uid(acp->ac_uid, 0);
16555085Sbostic 		if (!strcmp(p, *argv))
16655085Sbostic 			return (1);
16755085Sbostic 		if ((p = getdev(acp->ac_tty)) && !strcmp(p, *argv))
16855085Sbostic 			return (1);
16940266Sbostic 		if (!strncmp(acp->ac_comm, *argv, fldsiz(acct, ac_comm)))
17055085Sbostic 			return (1);
17133688Sbostic 	} while (*++argv);
17255085Sbostic 	return (0);
17313188Ssam }
17413188Ssam 
1757457Skre char *
17613188Ssam getdev(dev)
17711839Ssam 	dev_t dev;
1787457Skre {
17955085Sbostic 	static dev_t lastdev = (dev_t)-1;
1807457Skre 	static char *lastname;
1817457Skre 
18255085Sbostic 	if (dev == NODEV)			/* Special case. */
18311839Ssam 		return ("__");
18455085Sbostic 	if (dev == lastdev)			/* One-element cache. */
18511839Ssam 		return (lastname);
18655085Sbostic 	lastdev = dev;
18755085Sbostic 	lastname = devname(dev, S_IFCHR);
18855085Sbostic 	return (lastname);
1897457Skre }
19055085Sbostic 
19155085Sbostic void
19255085Sbostic usage()
19355085Sbostic {
19455085Sbostic 	(void)fprintf(stderr,
19555085Sbostic 	    "lastcomm [ -f file ] [command ...] [user ...] [tty ...]\n");
19655085Sbostic 	exit(1);
19755085Sbostic }
198