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