xref: /csrg-svn/usr.bin/lastcomm/lastcomm.c (revision 55085)
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*55085Sbostic static char sccsid[] = "@(#)lastcomm.c	5.12 (Berkeley) 07/12/92";
1634033Sbostic #endif /* not lint */
1721563Sdist 
1811839Ssam #include <sys/param.h>
19*55085Sbostic #include <sys/stat.h>
2011839Ssam #include <sys/acct.h>
21*55085Sbostic 
22*55085Sbostic #include <fcntl.h>
2311839Ssam #include <utmp.h>
2411839Ssam #include <struct.h>
25*55085Sbostic #include <errno.h>
26*55085Sbostic #include <unistd.h>
27*55085Sbostic #include <stdlib.h>
28*55085Sbostic #include <stdio.h>
2911839Ssam #include <ctype.h>
30*55085Sbostic #include <string.h>
3137848Sbostic #include "pathnames.h"
321037Sbill 
33*55085Sbostic char	*devname __P((dev_t, mode_t));
34*55085Sbostic void	 err __P((const char *, ...));
35*55085Sbostic time_t	 expand __P((u_int));
36*55085Sbostic char	*flagbits __P((int));
37*55085Sbostic char	*getdev __P((dev_t));
38*55085Sbostic int	 requested __P((char *[], struct acct *));
39*55085Sbostic void	 usage __P((void));
40*55085Sbostic char	*user_from_uid();
411037Sbill 
42*55085Sbostic int
4311839Ssam main(argc, argv)
4433688Sbostic 	int argc;
4511839Ssam 	char *argv[];
461037Sbill {
47*55085Sbostic 	register char *p;
48*55085Sbostic 	struct acct ab;
4913188Ssam 	struct stat sb;
50*55085Sbostic 	FILE *fp;
51*55085Sbostic 	off_t size;
52*55085Sbostic 	time_t t;
53*55085Sbostic 	int ch;
54*55085Sbostic 	char *acctfile;
551037Sbill 
5637848Sbostic 	acctfile = _PATH_ACCT;
5733688Sbostic 	while ((ch = getopt(argc, argv, "f:")) != EOF)
5833688Sbostic 		switch((char)ch) {
5933688Sbostic 		case 'f':
6033688Sbostic 			acctfile = optarg;
6133688Sbostic 			break;
6233688Sbostic 		case '?':
6333688Sbostic 		default:
64*55085Sbostic 			usage();
6533688Sbostic 		}
66*55085Sbostic 	argc -= optind;
6733688Sbostic 	argv += optind;
6837848Sbostic 
69*55085Sbostic 	/* Open the file. */
70*55085Sbostic 	if ((fp = fopen(acctfile, "r")) == NULL || fstat(fileno(fp), &sb))
71*55085Sbostic 		err("%s: %s\n", acctfile, strerror(errno));
72*55085Sbostic 
73*55085Sbostic 	/*
74*55085Sbostic 	 * Round off to integral number of accounting records, probably
75*55085Sbostic 	 * not necessary, but it doesn't hurt.
76*55085Sbostic 	 */
77*55085Sbostic 	size = sb.st_size - sb.st_size % sizeof(struct acct);
78*55085Sbostic 
79*55085Sbostic 	/* Check if any records to display. */
80*55085Sbostic 	if (size < sizeof(struct acct))
81*55085Sbostic 		exit(0);
82*55085Sbostic 
83*55085Sbostic 	/*
84*55085Sbostic 	 * Seek to before the last entry in the file; use lseek(2) in case
85*55085Sbostic 	 * the file is bigger than a "long".
86*55085Sbostic 	 */
87*55085Sbostic 	size -= sizeof(struct acct);
88*55085Sbostic 	if (lseek(fileno(fp), size, SEEK_SET) == -1)
89*55085Sbostic 		err("%s: %s\n", acctfile, strerror(errno));
90*55085Sbostic 
91*55085Sbostic 	for (;;) {
92*55085Sbostic 		if (fread(&ab, sizeof(struct acct), 1, fp) != 1)
93*55085Sbostic 			err("%s: %s\n", acctfile, strerror(errno));
94*55085Sbostic 
95*55085Sbostic 		if (fseek(fp, 2 * -(long)sizeof(struct acct), SEEK_CUR) == -1)
96*55085Sbostic 			err("%s: %s\n", acctfile, strerror(errno));
97*55085Sbostic 
98*55085Sbostic 		if (size == 0)
9913188Ssam 			break;
100*55085Sbostic 		size -= sizeof(struct acct);
1011037Sbill 
102*55085Sbostic 		if (ab.ac_comm[0] == '\0') {
103*55085Sbostic 			ab.ac_comm[0] = '?';
104*55085Sbostic 			ab.ac_comm[1] = '\0';
105*55085Sbostic 		} else
106*55085Sbostic 			for (p = &ab.ac_comm[0];
107*55085Sbostic 			    p < &ab.ac_comm[fldsiz(acct, ac_comm)] && *p; ++p)
108*55085Sbostic 				if (!isprint(*p))
109*55085Sbostic 					*p = '?';
110*55085Sbostic 		if (*argv && !requested(argv, &ab))
111*55085Sbostic 			continue;
112*55085Sbostic 
113*55085Sbostic 		t = expand(ab.ac_utime) + expand(ab.ac_stime);
114*55085Sbostic 		(void)printf("%-*s %-7s %-*s %-*s %6.2f secs %.16s\n",
115*55085Sbostic 			fldsiz(acct, ac_comm), ab.ac_comm, flagbits(ab.ac_flag),
116*55085Sbostic 			UT_NAMESIZE, user_from_uid(ab.ac_uid, 0),
117*55085Sbostic 			UT_LINESIZE, getdev(ab.ac_tty),
118*55085Sbostic 			t / (double)AHZ, ctime(&ab.ac_btime));
1191037Sbill 	}
120*55085Sbostic 	exit(0);
1211037Sbill }
1221037Sbill 
1231037Sbill time_t
124*55085Sbostic expand(t)
125*55085Sbostic 	u_int t;
1261037Sbill {
1271037Sbill 	register time_t nt;
1281037Sbill 
1291037Sbill 	nt = t & 017777;
1301037Sbill 	t >>= 13;
13111839Ssam 	while (t) {
1321037Sbill 		t--;
1331037Sbill 		nt <<= 3;
1341037Sbill 	}
1351037Sbill 	return (nt);
1361037Sbill }
1371037Sbill 
1387457Skre char *
1397457Skre flagbits(f)
14011839Ssam 	register int f;
1411037Sbill {
142*55085Sbostic 	static char flags[20] = "-";
143*55085Sbostic 	char *p;
1447457Skre 
145*55085Sbostic #define	BIT(flag, ch)	if (f & flag) *p++ = ch
146*55085Sbostic 
147*55085Sbostic 	p = flags + 1;
14811839Ssam 	BIT(ASU, 'S');
14911839Ssam 	BIT(AFORK, 'F');
15011839Ssam 	BIT(ACOMPAT, 'C');
15111839Ssam 	BIT(ACORE, 'D');
15211839Ssam 	BIT(AXSIG, 'X');
153*55085Sbostic 	*p = '\0';
15411839Ssam 	return (flags);
1557457Skre }
1567457Skre 
157*55085Sbostic int
158*55085Sbostic requested(argv, acp)
15913188Ssam 	register char *argv[];
16013188Ssam 	register struct acct *acp;
16113188Ssam {
162*55085Sbostic 	register char *p;
16313188Ssam 
16433688Sbostic 	do {
165*55085Sbostic 		p = user_from_uid(acp->ac_uid, 0);
166*55085Sbostic 		if (!strcmp(p, *argv))
167*55085Sbostic 			return (1);
168*55085Sbostic 		if ((p = getdev(acp->ac_tty)) && !strcmp(p, *argv))
169*55085Sbostic 			return (1);
17040266Sbostic 		if (!strncmp(acp->ac_comm, *argv, fldsiz(acct, ac_comm)))
171*55085Sbostic 			return (1);
17233688Sbostic 	} while (*++argv);
173*55085Sbostic 	return (0);
17413188Ssam }
17513188Ssam 
1767457Skre char *
17713188Ssam getdev(dev)
17811839Ssam 	dev_t dev;
1797457Skre {
180*55085Sbostic 	static dev_t lastdev = (dev_t)-1;
1817457Skre 	static char *lastname;
1827457Skre 
183*55085Sbostic 	if (dev == NODEV)			/* Special case. */
18411839Ssam 		return ("__");
185*55085Sbostic 	if (dev == lastdev)			/* One-element cache. */
18611839Ssam 		return (lastname);
187*55085Sbostic 	lastdev = dev;
188*55085Sbostic 	lastname = devname(dev, S_IFCHR);
189*55085Sbostic 	return (lastname);
1907457Skre }
191*55085Sbostic 
192*55085Sbostic void
193*55085Sbostic usage()
194*55085Sbostic {
195*55085Sbostic 	(void)fprintf(stderr,
196*55085Sbostic 	    "lastcomm [ -f file ] [command ...] [user ...] [tty ...]\n");
197*55085Sbostic 	exit(1);
198*55085Sbostic }
199*55085Sbostic 
200*55085Sbostic #if __STDC__
201*55085Sbostic #include <stdarg.h>
202*55085Sbostic #else
203*55085Sbostic #include <varargs.h>
204*55085Sbostic #endif
205*55085Sbostic 
206*55085Sbostic void
207*55085Sbostic #if __STDC__
208*55085Sbostic err(const char *fmt, ...)
209*55085Sbostic #else
210*55085Sbostic err(fmt, va_alist)
211*55085Sbostic 	char *fmt;
212*55085Sbostic         va_dcl
213*55085Sbostic #endif
214*55085Sbostic {
215*55085Sbostic 	va_list ap;
216*55085Sbostic #if __STDC__
217*55085Sbostic 	va_start(ap, fmt);
218*55085Sbostic #else
219*55085Sbostic 	va_start(ap);
220*55085Sbostic #endif
221*55085Sbostic 	(void)fprintf(stderr, "lastcomm: ");
222*55085Sbostic 	(void)vfprintf(stderr, fmt, ap);
223*55085Sbostic 	va_end(ap);
224*55085Sbostic 	(void)fprintf(stderr, "\n");
225*55085Sbostic 	exit(1);
226*55085Sbostic 	/* NOTREACHED */
227*55085Sbostic }
228