xref: /csrg-svn/usr.bin/lastcomm/lastcomm.c (revision 69122)
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