11590Srgrimes/*
21590Srgrimes * Copyright (c) 1980, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 4. Neither the name of the University nor the names of its contributors
141590Srgrimes *    may be used to endorse or promote products derived from this software
151590Srgrimes *    without specific prior written permission.
161590Srgrimes *
171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271590Srgrimes * SUCH DAMAGE.
281590Srgrimes */
291590Srgrimes
301590Srgrimes#ifndef lint
3178859Sddstatic const char copyright[] =
321590Srgrimes"@(#) Copyright (c) 1980, 1993\n\
331590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
341590Srgrimes#endif /* not lint */
351590Srgrimes
361590Srgrimes#ifndef lint
3727571Scharnier#if 0
381590Srgrimesstatic char sccsid[] = "@(#)lastcomm.c	8.1 (Berkeley) 6/6/93";
3927571Scharnier#endif
401590Srgrimes#endif /* not lint */
4199112Sobrien#include <sys/cdefs.h>
4299112Sobrien__FBSDID("$FreeBSD$");
431590Srgrimes
441590Srgrimes#include <sys/param.h>
451590Srgrimes#include <sys/stat.h>
461590Srgrimes#include <sys/acct.h>
471590Srgrimes
481590Srgrimes#include <ctype.h>
491590Srgrimes#include <err.h>
50200462Sdelphij#include <errno.h>
5190878Simp#include <pwd.h>
521590Srgrimes#include <stdio.h>
531590Srgrimes#include <stdlib.h>
541590Srgrimes#include <string.h>
55235541Skib#include <time.h>
561590Srgrimes#include <unistd.h>
571590Srgrimes#include "pathnames.h"
581590Srgrimes
59109943Sfenner/*XXX*/#include <inttypes.h>
60109943Sfenner
6192920Simptime_t	 expand(u_int);
6292920Simpchar	*flagbits(int);
6392920Simpconst	 char *getdev(dev_t);
64169857Sddsint	 readrec_forward(FILE *f, struct acctv2 *av2);
65169857Sddsint	 readrec_backward(FILE *f, struct acctv2 *av2);
66169857Sddsint	 requested(char *[], struct acctv2 *);
6792920Simpstatic	 void usage(void);
681590Srgrimes
6916849Swosch#define AC_UTIME 1 /* user */
7016849Swosch#define AC_STIME 2 /* system */
7116849Swosch#define AC_ETIME 4 /* elapsed */
7216849Swosch#define AC_CTIME 8 /* user + system time, default */
7316849Swosch
7416849Swosch#define AC_BTIME 16 /* starting time */
7516849Swosch#define AC_FTIME 32 /* exit time (starting time + elapsed time )*/
7616849Swosch
771590Srgrimesint
78102944Sdwmalonemain(int argc, char *argv[])
791590Srgrimes{
80169857Sdds	struct acctv2 ab;
8178859Sdd	char *p;
821590Srgrimes	FILE *fp;
83169857Sdds	int (*readrec)(FILE *f, struct acctv2 *av2);
841590Srgrimes	time_t t;
85169857Sdds	int ch, rv;
86235541Skib	const char *acctfile, *format;
87235541Skib	char buf[1024];
8878859Sdd	int flags = 0;
891590Srgrimes
901590Srgrimes	acctfile = _PATH_ACCT;
91235541Skib	format = NULL;
92169549Sdds	while ((ch = getopt(argc, argv, "f:usecSE")) != -1)
931590Srgrimes		switch((char)ch) {
941590Srgrimes		case 'f':
951590Srgrimes			acctfile = optarg;
961590Srgrimes			break;
97169549Sdds
9816849Swosch		case 'u':
9978859Sdd			flags |= AC_UTIME; /* user time */
10016849Swosch			break;
10116849Swosch		case 's':
10278859Sdd			flags |= AC_STIME; /* system time */
10316849Swosch			break;
10416849Swosch		case 'e':
10578859Sdd			flags |= AC_ETIME; /* elapsed time */
10616849Swosch			break;
10716849Swosch        	case 'c':
10878859Sdd                        flags |= AC_CTIME; /* user + system time */
10916849Swosch			break;
11016849Swosch
11116849Swosch        	case 'S':
11278859Sdd                        flags |= AC_BTIME; /* starting time */
11316849Swosch			break;
11416849Swosch        	case 'E':
11516849Swosch			/* exit time (starting time + elapsed time )*/
11678859Sdd                        flags |= AC_FTIME;
11716849Swosch			break;
11816849Swosch
1191590Srgrimes		case '?':
1201590Srgrimes		default:
1211590Srgrimes			usage();
1221590Srgrimes		}
12316849Swosch
12416849Swosch	/* default user + system time and starting time */
125169549Sdds	if (!flags) {
12678859Sdd	    flags = AC_CTIME | AC_BTIME;
127169549Sdds	}
12816849Swosch
1291590Srgrimes	argc -= optind;
1301590Srgrimes	argv += optind;
1311590Srgrimes
132235541Skib	if (argc > 0 && **argv == '+') {
133235541Skib		format = *argv + 1; /* skip + */
134235541Skib		argc--;
135235541Skib		argv++;
136235541Skib	}
137235541Skib
138169235Sdwmalone	if (strcmp(acctfile, "-") == 0) {
139168367Sdds		fp = stdin;
140169857Sdds		readrec = readrec_forward;
141169235Sdwmalone	} else {
142168367Sdds		/* Open the file. */
143169857Sdds		if ((fp = fopen(acctfile, "r")) == NULL)
144168367Sdds			err(1, "could not open %s", acctfile);
145169857Sdds		if (fseek(fp, 0l, SEEK_END) == -1)
146169857Sdds			err(1, "seek to end of %s failed", acctfile);
147169857Sdds		readrec = readrec_backward;
148168367Sdds	}
1491590Srgrimes
150169857Sdds	while ((rv = readrec(fp, &ab)) == 1) {
151169857Sdds		for (p = &ab.ac_comm[0];
152169857Sdds		    p < &ab.ac_comm[AC_COMM_LEN] && *p; ++p)
153169857Sdds			if (!isprint(*p))
154169857Sdds				*p = '?';
1551590Srgrimes
1561590Srgrimes		if (*argv && !requested(argv, &ab))
1571590Srgrimes			continue;
1581590Srgrimes
159202049Sed		(void)printf("%-*.*s %-7s %-*s %-8s",
16067443Sphk			     AC_COMM_LEN, AC_COMM_LEN, ab.ac_comm,
161169857Sdds			     flagbits(ab.ac_flagx),
162202049Sed			     MAXLOGNAME - 1, user_from_uid(ab.ac_uid, 0),
163202049Sed			     getdev(ab.ac_tty));
16416849Swosch
16516849Swosch
16616849Swosch		/* user + system time */
16778859Sdd		if (flags & AC_CTIME) {
168169857Sdds			(void)printf(" %6.3f secs",
169169857Sdds			    (ab.ac_utime + ab.ac_stime) / 1000000);
17016849Swosch		}
17116849Swosch
17216849Swosch		/* usr time */
17378859Sdd		if (flags & AC_UTIME) {
174169857Sdds			(void)printf(" %6.3f us", ab.ac_utime / 1000000);
17516849Swosch		}
17616849Swosch
17716849Swosch		/* system time */
17878859Sdd		if (flags & AC_STIME) {
179169857Sdds			(void)printf(" %6.3f sy", ab.ac_stime / 1000000);
18016849Swosch		}
18116849Swosch
18216849Swosch		/* elapsed time */
18378859Sdd		if (flags & AC_ETIME) {
184169857Sdds			(void)printf(" %8.3f es", ab.ac_etime / 1000000);
18516849Swosch		}
18616849Swosch
18716849Swosch		/* starting time */
18878859Sdd		if (flags & AC_BTIME) {
189235541Skib			if (format != NULL) {
190235541Skib				(void)strftime(buf, sizeof(buf), format,
191235541Skib				    localtime(&ab.ac_btime));
192235541Skib				(void)printf(" %s", buf);
193235541Skib			} else
194235541Skib				(void)printf(" %.16s", ctime(&ab.ac_btime));
19516849Swosch		}
19616849Swosch
19716849Swosch		/* exit time (starting time + elapsed time )*/
19878859Sdd		if (flags & AC_FTIME) {
19916849Swosch			t = ab.ac_btime;
200169857Sdds			t += (time_t)(ab.ac_etime / 1000000);
201235541Skib			if (format != NULL) {
202235541Skib				(void)strftime(buf, sizeof(buf), format,
203235541Skib				    localtime(&t));
204235541Skib				(void)printf(" %s", buf);
205235541Skib			} else
206235541Skib				(void)printf(" %.16s", ctime(&t));
20716849Swosch		}
20816849Swosch		printf("\n");
209169857Sdds 	}
210169857Sdds	if (rv == EOF)
211169857Sdds		err(1, "read record from %s failed", acctfile);
212109943Sfenner
213168836Sdds	if (fflush(stdout))
214168836Sdds		err(1, "stdout");
21516849Swosch 	exit(0);
2161590Srgrimes}
2171590Srgrimes
2181590Srgrimeschar *
219102944Sdwmaloneflagbits(int f)
2201590Srgrimes{
2211590Srgrimes	static char flags[20] = "-";
2221590Srgrimes	char *p;
2231590Srgrimes
2241590Srgrimes#define	BIT(flag, ch)	if (f & flag) *p++ = ch
2251590Srgrimes
2261590Srgrimes	p = flags + 1;
2271590Srgrimes	BIT(ASU, 'S');
2281590Srgrimes	BIT(AFORK, 'F');
2291590Srgrimes	BIT(ACOMPAT, 'C');
2301590Srgrimes	BIT(ACORE, 'D');
2311590Srgrimes	BIT(AXSIG, 'X');
2321590Srgrimes	*p = '\0';
2331590Srgrimes	return (flags);
2341590Srgrimes}
2351590Srgrimes
2361590Srgrimesint
237169857Sddsrequested(char *argv[], struct acctv2 *acp)
2381590Srgrimes{
23978859Sdd	const char *p;
2401590Srgrimes
2411590Srgrimes	do {
2421590Srgrimes		p = user_from_uid(acp->ac_uid, 0);
2438874Srgrimes		if (!strcmp(p, *argv))
2441590Srgrimes			return (1);
2451590Srgrimes		if ((p = getdev(acp->ac_tty)) && !strcmp(p, *argv))
2461590Srgrimes			return (1);
24767443Sphk		if (!strncmp(acp->ac_comm, *argv, AC_COMM_LEN))
2481590Srgrimes			return (1);
2491590Srgrimes	} while (*++argv);
2501590Srgrimes	return (0);
2511590Srgrimes}
2521590Srgrimes
25378859Sddconst char *
254102944Sdwmalonegetdev(dev_t dev)
2551590Srgrimes{
2561590Srgrimes	static dev_t lastdev = (dev_t)-1;
25778859Sdd	static const char *lastname;
2581590Srgrimes
2591590Srgrimes	if (dev == NODEV)			/* Special case. */
2601590Srgrimes		return ("__");
2611590Srgrimes	if (dev == lastdev)			/* One-element cache. */
2621590Srgrimes		return (lastname);
2631590Srgrimes	lastdev = dev;
2641590Srgrimes	lastname = devname(dev, S_IFCHR);
2651590Srgrimes	return (lastname);
2661590Srgrimes}
2671590Srgrimes
26827571Scharnierstatic void
269102944Sdwmaloneusage(void)
2701590Srgrimes{
2711590Srgrimes	(void)fprintf(stderr,
272235541Skib	    "usage: lastcomm [-EScesu] [-f file] [+format] [command ...] "
273235541Skib	    "[user ...] [terminal ...]\n");
2741590Srgrimes	exit(1);
2751590Srgrimes}
276