xref: /freebsd/usr.bin/lastcomm/lastcomm.c (revision 0b8224d1cc9dc6c9778ba04a75b2c8d47e5d7481)
19b50d902SRodney W. Grimes /*
28a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni  *
49b50d902SRodney W. Grimes  * Copyright (c) 1980, 1993
59b50d902SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
69b50d902SRodney W. Grimes  *
79b50d902SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
89b50d902SRodney W. Grimes  * modification, are permitted provided that the following conditions
99b50d902SRodney W. Grimes  * are met:
109b50d902SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
119b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
129b50d902SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
139b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
149b50d902SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
169b50d902SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
179b50d902SRodney W. Grimes  *    without specific prior written permission.
189b50d902SRodney W. Grimes  *
199b50d902SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
209b50d902SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
219b50d902SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
229b50d902SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
239b50d902SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
249b50d902SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
259b50d902SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
269b50d902SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
279b50d902SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
289b50d902SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
299b50d902SRodney W. Grimes  * SUCH DAMAGE.
309b50d902SRodney W. Grimes  */
319b50d902SRodney W. Grimes 
329b50d902SRodney W. Grimes #include <sys/param.h>
339b50d902SRodney W. Grimes #include <sys/stat.h>
349b50d902SRodney W. Grimes #include <sys/acct.h>
359b50d902SRodney W. Grimes 
369b50d902SRodney W. Grimes #include <ctype.h>
379b50d902SRodney W. Grimes #include <err.h>
38821df508SXin LI #include <errno.h>
39576541a9SWarner Losh #include <pwd.h>
409b50d902SRodney W. Grimes #include <stdio.h>
419b50d902SRodney W. Grimes #include <stdlib.h>
429b50d902SRodney W. Grimes #include <string.h>
436fe3ecc3SKonstantin Belousov #include <time.h>
449b50d902SRodney W. Grimes #include <unistd.h>
459b50d902SRodney W. Grimes #include "pathnames.h"
469b50d902SRodney W. Grimes 
476841d8b9SBill Fenner /*XXX*/#include <inttypes.h>
486841d8b9SBill Fenner 
49f1bb2cd2SWarner Losh time_t	 expand(u_int);
50f1bb2cd2SWarner Losh char	*flagbits(int);
51f1bb2cd2SWarner Losh const	 char *getdev(dev_t);
5269921123SKonstantin Belousov int	 readrec_forward(FILE *f, struct acctv3 *av3);
5369921123SKonstantin Belousov int	 readrec_backward(FILE *f, struct acctv3 *av3);
5469921123SKonstantin Belousov int	 requested(char *[], struct acctv3 *);
55f1bb2cd2SWarner Losh static	 void usage(void);
569b50d902SRodney W. Grimes 
570309b92bSWolfram Schneider #define AC_UTIME 1 /* user */
580309b92bSWolfram Schneider #define AC_STIME 2 /* system */
590309b92bSWolfram Schneider #define AC_ETIME 4 /* elapsed */
600309b92bSWolfram Schneider #define AC_CTIME 8 /* user + system time, default */
610309b92bSWolfram Schneider 
620309b92bSWolfram Schneider #define AC_BTIME 16 /* starting time */
630309b92bSWolfram Schneider #define AC_FTIME 32 /* exit time (starting time + elapsed time )*/
640309b92bSWolfram Schneider 
659b50d902SRodney W. Grimes int
main(int argc,char * argv[])66f4ac32deSDavid Malone main(int argc, char *argv[])
679b50d902SRodney W. Grimes {
6869921123SKonstantin Belousov 	struct acctv3 ab;
69fd8879d3SDima Dorfman 	char *p;
709b50d902SRodney W. Grimes 	FILE *fp;
7169921123SKonstantin Belousov 	int (*readrec)(FILE *f, struct acctv3 *av3);
729b50d902SRodney W. Grimes 	time_t t;
73fdbe5babSDiomidis Spinellis 	int ch, rv;
746fe3ecc3SKonstantin Belousov 	const char *acctfile, *format;
756fe3ecc3SKonstantin Belousov 	char buf[1024];
76fd8879d3SDima Dorfman 	int flags = 0;
779b50d902SRodney W. Grimes 
789b50d902SRodney W. Grimes 	acctfile = _PATH_ACCT;
796fe3ecc3SKonstantin Belousov 	format = NULL;
80e91843d4SDiomidis Spinellis 	while ((ch = getopt(argc, argv, "f:usecSE")) != -1)
819b50d902SRodney W. Grimes 		switch((char)ch) {
829b50d902SRodney W. Grimes 		case 'f':
839b50d902SRodney W. Grimes 			acctfile = optarg;
849b50d902SRodney W. Grimes 			break;
85e91843d4SDiomidis Spinellis 
860309b92bSWolfram Schneider 		case 'u':
87fd8879d3SDima Dorfman 			flags |= AC_UTIME; /* user time */
880309b92bSWolfram Schneider 			break;
890309b92bSWolfram Schneider 		case 's':
90fd8879d3SDima Dorfman 			flags |= AC_STIME; /* system time */
910309b92bSWolfram Schneider 			break;
920309b92bSWolfram Schneider 		case 'e':
93fd8879d3SDima Dorfman 			flags |= AC_ETIME; /* elapsed time */
940309b92bSWolfram Schneider 			break;
950309b92bSWolfram Schneider         	case 'c':
96fd8879d3SDima Dorfman                         flags |= AC_CTIME; /* user + system time */
970309b92bSWolfram Schneider 			break;
980309b92bSWolfram Schneider 
990309b92bSWolfram Schneider         	case 'S':
100fd8879d3SDima Dorfman                         flags |= AC_BTIME; /* starting time */
1010309b92bSWolfram Schneider 			break;
1020309b92bSWolfram Schneider         	case 'E':
1030309b92bSWolfram Schneider 			/* exit time (starting time + elapsed time )*/
104fd8879d3SDima Dorfman                         flags |= AC_FTIME;
1050309b92bSWolfram Schneider 			break;
1060309b92bSWolfram Schneider 
1079b50d902SRodney W. Grimes 		case '?':
1089b50d902SRodney W. Grimes 		default:
1099b50d902SRodney W. Grimes 			usage();
1109b50d902SRodney W. Grimes 		}
1110309b92bSWolfram Schneider 
1120309b92bSWolfram Schneider 	/* default user + system time and starting time */
113e91843d4SDiomidis Spinellis 	if (!flags) {
114fd8879d3SDima Dorfman 	    flags = AC_CTIME | AC_BTIME;
115e91843d4SDiomidis Spinellis 	}
1160309b92bSWolfram Schneider 
1179b50d902SRodney W. Grimes 	argc -= optind;
1189b50d902SRodney W. Grimes 	argv += optind;
1199b50d902SRodney W. Grimes 
1206fe3ecc3SKonstantin Belousov 	if (argc > 0 && **argv == '+') {
1216fe3ecc3SKonstantin Belousov 		format = *argv + 1; /* skip + */
1226fe3ecc3SKonstantin Belousov 		argc--;
1236fe3ecc3SKonstantin Belousov 		argv++;
1246fe3ecc3SKonstantin Belousov 	}
1256fe3ecc3SKonstantin Belousov 
12661f31ed6SDavid Malone 	if (strcmp(acctfile, "-") == 0) {
12744c900afSDiomidis Spinellis 		fp = stdin;
128fdbe5babSDiomidis Spinellis 		readrec = readrec_forward;
12961f31ed6SDavid Malone 	} else {
1309b50d902SRodney W. Grimes 		/* Open the file. */
131fdbe5babSDiomidis Spinellis 		if ((fp = fopen(acctfile, "r")) == NULL)
132151e36fcSHiten Pandya 			err(1, "could not open %s", acctfile);
133fdbe5babSDiomidis Spinellis 		if (fseek(fp, 0l, SEEK_END) == -1)
134fdbe5babSDiomidis Spinellis 			err(1, "seek to end of %s failed", acctfile);
135fdbe5babSDiomidis Spinellis 		readrec = readrec_backward;
13644c900afSDiomidis Spinellis 	}
1379b50d902SRodney W. Grimes 
138fdbe5babSDiomidis Spinellis 	while ((rv = readrec(fp, &ab)) == 1) {
1399b50d902SRodney W. Grimes 		for (p = &ab.ac_comm[0];
140f90e81f9SPoul-Henning Kamp 		    p < &ab.ac_comm[AC_COMM_LEN] && *p; ++p)
1419b50d902SRodney W. Grimes 			if (!isprint(*p))
1429b50d902SRodney W. Grimes 				*p = '?';
143fdbe5babSDiomidis Spinellis 
1449b50d902SRodney W. Grimes 		if (*argv && !requested(argv, &ab))
1459b50d902SRodney W. Grimes 			continue;
1469b50d902SRodney W. Grimes 
14785277f13SEd Schouten 		(void)printf("%-*.*s %-7s %-*s %-8s",
148f90e81f9SPoul-Henning Kamp 			     AC_COMM_LEN, AC_COMM_LEN, ab.ac_comm,
149fdbe5babSDiomidis Spinellis 			     flagbits(ab.ac_flagx),
15085277f13SEd Schouten 			     MAXLOGNAME - 1, user_from_uid(ab.ac_uid, 0),
15185277f13SEd Schouten 			     getdev(ab.ac_tty));
1520309b92bSWolfram Schneider 
1530309b92bSWolfram Schneider 
1540309b92bSWolfram Schneider 		/* user + system time */
155fd8879d3SDima Dorfman 		if (flags & AC_CTIME) {
156fdbe5babSDiomidis Spinellis 			(void)printf(" %6.3f secs",
157fdbe5babSDiomidis Spinellis 			    (ab.ac_utime + ab.ac_stime) / 1000000);
1580309b92bSWolfram Schneider 		}
1590309b92bSWolfram Schneider 
1600309b92bSWolfram Schneider 		/* usr time */
161fd8879d3SDima Dorfman 		if (flags & AC_UTIME) {
162fdbe5babSDiomidis Spinellis 			(void)printf(" %6.3f us", ab.ac_utime / 1000000);
1630309b92bSWolfram Schneider 		}
1640309b92bSWolfram Schneider 
1650309b92bSWolfram Schneider 		/* system time */
166fd8879d3SDima Dorfman 		if (flags & AC_STIME) {
167fdbe5babSDiomidis Spinellis 			(void)printf(" %6.3f sy", ab.ac_stime / 1000000);
1680309b92bSWolfram Schneider 		}
1690309b92bSWolfram Schneider 
1700309b92bSWolfram Schneider 		/* elapsed time */
171fd8879d3SDima Dorfman 		if (flags & AC_ETIME) {
172fdbe5babSDiomidis Spinellis 			(void)printf(" %8.3f es", ab.ac_etime / 1000000);
1730309b92bSWolfram Schneider 		}
1740309b92bSWolfram Schneider 
1750309b92bSWolfram Schneider 		/* starting time */
176fd8879d3SDima Dorfman 		if (flags & AC_BTIME) {
1776fe3ecc3SKonstantin Belousov 			if (format != NULL) {
1786fe3ecc3SKonstantin Belousov 				(void)strftime(buf, sizeof(buf), format,
1796fe3ecc3SKonstantin Belousov 				    localtime(&ab.ac_btime));
1806fe3ecc3SKonstantin Belousov 				(void)printf(" %s", buf);
1816fe3ecc3SKonstantin Belousov 			} else
182*6f4ce7e8SMichael Paepcke 				(void)printf(" %.19s", ctime(&ab.ac_btime));
1830309b92bSWolfram Schneider 		}
1840309b92bSWolfram Schneider 
1850309b92bSWolfram Schneider 		/* exit time (starting time + elapsed time )*/
186fd8879d3SDima Dorfman 		if (flags & AC_FTIME) {
1870309b92bSWolfram Schneider 			t = ab.ac_btime;
188fdbe5babSDiomidis Spinellis 			t += (time_t)(ab.ac_etime / 1000000);
1896fe3ecc3SKonstantin Belousov 			if (format != NULL) {
1906fe3ecc3SKonstantin Belousov 				(void)strftime(buf, sizeof(buf), format,
1916fe3ecc3SKonstantin Belousov 				    localtime(&t));
1926fe3ecc3SKonstantin Belousov 				(void)printf(" %s", buf);
1936fe3ecc3SKonstantin Belousov 			} else
194*6f4ce7e8SMichael Paepcke 				(void)printf(" %.19s", ctime(&t));
1950309b92bSWolfram Schneider 		}
1960309b92bSWolfram Schneider 		printf("\n");
197fdbe5babSDiomidis Spinellis  	}
198fdbe5babSDiomidis Spinellis 	if (rv == EOF)
199fdbe5babSDiomidis Spinellis 		err(1, "read record from %s failed", acctfile);
2006841d8b9SBill Fenner 
2013f863a9aSDiomidis Spinellis 	if (fflush(stdout))
2023f863a9aSDiomidis Spinellis 		err(1, "stdout");
2039b50d902SRodney W. Grimes  	exit(0);
2049b50d902SRodney W. Grimes }
2059b50d902SRodney W. Grimes 
2069b50d902SRodney W. Grimes char *
flagbits(int f)207f4ac32deSDavid Malone flagbits(int f)
2089b50d902SRodney W. Grimes {
2099b50d902SRodney W. Grimes 	static char flags[20] = "-";
2109b50d902SRodney W. Grimes 	char *p;
2119b50d902SRodney W. Grimes 
2129b50d902SRodney W. Grimes #define	BIT(flag, ch)	if (f & flag) *p++ = ch
2139b50d902SRodney W. Grimes 
2149b50d902SRodney W. Grimes 	p = flags + 1;
2159b50d902SRodney W. Grimes 	BIT(ASU, 'S');
2169b50d902SRodney W. Grimes 	BIT(AFORK, 'F');
2179b50d902SRodney W. Grimes 	BIT(ACOMPAT, 'C');
2189b50d902SRodney W. Grimes 	BIT(ACORE, 'D');
2199b50d902SRodney W. Grimes 	BIT(AXSIG, 'X');
2209b50d902SRodney W. Grimes 	*p = '\0';
2219b50d902SRodney W. Grimes 	return (flags);
2229b50d902SRodney W. Grimes }
2239b50d902SRodney W. Grimes 
2249b50d902SRodney W. Grimes int
requested(char * argv[],struct acctv3 * acp)22569921123SKonstantin Belousov requested(char *argv[], struct acctv3 *acp)
2269b50d902SRodney W. Grimes {
227fd8879d3SDima Dorfman 	const char *p;
2289b50d902SRodney W. Grimes 
2299b50d902SRodney W. Grimes 	do {
2309b50d902SRodney W. Grimes 		p = user_from_uid(acp->ac_uid, 0);
2319b50d902SRodney W. Grimes 		if (!strcmp(p, *argv))
2329b50d902SRodney W. Grimes 			return (1);
2339b50d902SRodney W. Grimes 		if ((p = getdev(acp->ac_tty)) && !strcmp(p, *argv))
2349b50d902SRodney W. Grimes 			return (1);
235f90e81f9SPoul-Henning Kamp 		if (!strncmp(acp->ac_comm, *argv, AC_COMM_LEN))
2369b50d902SRodney W. Grimes 			return (1);
2379b50d902SRodney W. Grimes 	} while (*++argv);
2389b50d902SRodney W. Grimes 	return (0);
2399b50d902SRodney W. Grimes }
2409b50d902SRodney W. Grimes 
241fd8879d3SDima Dorfman const char *
getdev(dev_t dev)242f4ac32deSDavid Malone getdev(dev_t dev)
2439b50d902SRodney W. Grimes {
2449b50d902SRodney W. Grimes 	static dev_t lastdev = (dev_t)-1;
245fd8879d3SDima Dorfman 	static const char *lastname;
2469b50d902SRodney W. Grimes 
2479b50d902SRodney W. Grimes 	if (dev == NODEV)			/* Special case. */
2489b50d902SRodney W. Grimes 		return ("__");
2499b50d902SRodney W. Grimes 	if (dev == lastdev)			/* One-element cache. */
2509b50d902SRodney W. Grimes 		return (lastname);
2519b50d902SRodney W. Grimes 	lastdev = dev;
2529b50d902SRodney W. Grimes 	lastname = devname(dev, S_IFCHR);
2539b50d902SRodney W. Grimes 	return (lastname);
2549b50d902SRodney W. Grimes }
2559b50d902SRodney W. Grimes 
256342548bfSPhilippe Charnier static void
usage(void)257f4ac32deSDavid Malone usage(void)
2589b50d902SRodney W. Grimes {
2599b50d902SRodney W. Grimes 	(void)fprintf(stderr,
2606fe3ecc3SKonstantin Belousov 	    "usage: lastcomm [-EScesu] [-f file] [+format] [command ...] "
2616fe3ecc3SKonstantin Belousov 	    "[user ...] [terminal ...]\n");
2629b50d902SRodney W. Grimes 	exit(1);
2639b50d902SRodney W. Grimes }
264