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