lastcomm.c revision 1.29
1100894Srwatson/* $OpenBSD: lastcomm.c,v 1.29 2019/09/09 20:02:27 bluhm Exp $ */ 2100894Srwatson/* $NetBSD: lastcomm.c,v 1.9 1995/10/22 01:43:42 ghudson Exp $ */ 3100894Srwatson 4100894Srwatson/* 5100894Srwatson * Copyright (c) 1980, 1993 6100894Srwatson * The Regents of the University of California. All rights reserved. 7100894Srwatson * 8100894Srwatson * Redistribution and use in source and binary forms, with or without 9100894Srwatson * modification, are permitted provided that the following conditions 10100894Srwatson * are met: 11100894Srwatson * 1. Redistributions of source code must retain the above copyright 12100894Srwatson * notice, this list of conditions and the following disclaimer. 13100894Srwatson * 2. Redistributions in binary form must reproduce the above copyright 14100894Srwatson * notice, this list of conditions and the following disclaimer in the 15100894Srwatson * documentation and/or other materials provided with the distribution. 16100894Srwatson * 3. Neither the name of the University nor the names of its contributors 17100894Srwatson * may be used to endorse or promote products derived from this software 18100894Srwatson * without specific prior written permission. 19100894Srwatson * 20100894Srwatson * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21100894Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22100894Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23100894Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24100894Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25100894Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26100894Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27100894Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28100894Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29100894Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30100894Srwatson * SUCH DAMAGE. 31100894Srwatson */ 32100894Srwatson 33100894Srwatson#include <sys/param.h> /* NODEV */ 34100894Srwatson#include <sys/stat.h> 35100894Srwatson#include <sys/acct.h> 36100894Srwatson 37100894Srwatson#include <ctype.h> 38100894Srwatson#include <err.h> 39100894Srwatson#include <fcntl.h> 40100894Srwatson#include <math.h> 41100894Srwatson#include <stdio.h> 42100894Srwatson#include <stdlib.h> 43100894Srwatson#include <string.h> 44100894Srwatson#include <unistd.h> 45100894Srwatson#include <utmp.h> 46100894Srwatson#include <pwd.h> 47100894Srwatson#include "pathnames.h" 48100894Srwatson 49101173Srwatsontime_t expand(u_int); 50100894Srwatsonchar *flagbits(int); 51100979Srwatsonchar *getdev(dev_t); 52100979Srwatsonint requested(char *[], struct acct *); 53100979Srwatsonvoid usage(void); 54100979Srwatson 55100979Srwatson#define SECSPERMIN (60) 56100979Srwatson#define SECSPERHOUR (60 * 60) 57101712Srwatson 58100979Srwatsonint 59100979Srwatsonmain(int argc, char *argv[]) 60100894Srwatson{ 61100894Srwatson char *p; 62100979Srwatson struct acct ab; 63100979Srwatson struct stat sb; 64100979Srwatson FILE *fp; 65100979Srwatson off_t size; 66100979Srwatson time_t t; 67100979Srwatson double delta; 68100979Srwatson int ch; 69100979Srwatson char *acctfile; 70100979Srwatson 71100894Srwatson if (pledge("stdio rpath getpw", NULL) == -1) 72100979Srwatson err(1, "pledge"); 73100979Srwatson 74100979Srwatson acctfile = _PATH_ACCT; 75100979Srwatson while ((ch = getopt(argc, argv, "f:")) != -1) 76100979Srwatson switch(ch) { 77100979Srwatson case 'f': 78100979Srwatson acctfile = optarg; 79100979Srwatson break; 80100979Srwatson case '?': 81100979Srwatson default: 82100979Srwatson usage(); 83100979Srwatson } 84100979Srwatson argc -= optind; 85100979Srwatson argv += optind; 86100979Srwatson 87100979Srwatson /* Open the file. */ 88100979Srwatson if ((fp = fopen(acctfile, "r")) == NULL || fstat(fileno(fp), &sb)) 89100979Srwatson err(1, "%s", acctfile); 90100979Srwatson 91101712Srwatson /* 92101712Srwatson * Round off to integral number of accounting records, probably 93101712Srwatson * not necessary, but it doesn't hurt. 94101712Srwatson */ 95101712Srwatson size = sb.st_size - sb.st_size % sizeof(struct acct); 96101712Srwatson 97101712Srwatson /* Check if any records to display. */ 98100979Srwatson if (size < sizeof(struct acct)) 99100979Srwatson exit(0); 100100979Srwatson 101100979Srwatson /* 102100979Srwatson * Seek to before the last entry in the file; use lseek(2) in case 103100979Srwatson * the file is bigger than a "long". 104100979Srwatson */ 105100979Srwatson size -= sizeof(struct acct); 106100979Srwatson if (lseek(fileno(fp), size, SEEK_SET) == -1) 107100979Srwatson err(1, "%s", acctfile); 108100979Srwatson 109100979Srwatson for (;;) { 110100979Srwatson if (fread(&ab, sizeof(struct acct), 1, fp) != 1) 111100979Srwatson err(1, "%s", acctfile); 112100979Srwatson 113100979Srwatson if (ab.ac_comm[0] == '\0') { 114100979Srwatson ab.ac_comm[0] = '?'; 115100979Srwatson ab.ac_comm[1] = '\0'; 116100979Srwatson } else 117100979Srwatson for (p = &ab.ac_comm[0]; 118100979Srwatson p < &ab.ac_comm[sizeof ab.ac_comm] && *p; ++p) 119100979Srwatson if (!isprint((unsigned char)*p)) 120100979Srwatson *p = '?'; 121100979Srwatson if (!*argv || requested(argv, &ab)) 122100979Srwatson { 123100979Srwatson t = expand(ab.ac_utime) + expand(ab.ac_stime); 124100979Srwatson (void)printf("%-*.*s %-7s %-*.*s %-*.*s %6.2f secs %.16s", 125100979Srwatson (int)sizeof ab.ac_comm, 126100979Srwatson (int)sizeof ab.ac_comm, 127100979Srwatson ab.ac_comm, flagbits(ab.ac_flag), UT_NAMESIZE, 128100979Srwatson UT_NAMESIZE, user_from_uid(ab.ac_uid, 0), 129100979Srwatson UT_LINESIZE, UT_LINESIZE, getdev(ab.ac_tty), 130100979Srwatson t / (double)AHZ, ctime(&ab.ac_btime)); 131100979Srwatson delta = expand(ab.ac_etime) / (double)AHZ; 132100979Srwatson printf(" (%1.0f:%02.0f:%05.2f)\n", 133100979Srwatson delta / SECSPERHOUR, 134100979Srwatson fmod(delta, (double)SECSPERHOUR) / SECSPERMIN, 135100979Srwatson fmod(delta, (double)SECSPERMIN)); 136100979Srwatson } 137100979Srwatson 138100979Srwatson if (size == 0) 139100979Srwatson break; 140100979Srwatson /* seek to previous entry */ 141100979Srwatson if (fseek(fp, 2 * -(long)sizeof(struct acct), SEEK_CUR) == -1) 142100979Srwatson err(1, "%s", acctfile); 143100979Srwatson size -= sizeof(struct acct); 144100979Srwatson } 145100979Srwatson exit(0); 146100979Srwatson} 147100979Srwatson 148100979Srwatsontime_t 149100979Srwatsonexpand(u_int t) 150100979Srwatson{ 151100979Srwatson time_t nt; 152100979Srwatson 153100979Srwatson nt = t & 017777; 154100979Srwatson t >>= 13; 155100979Srwatson while (t) { 156100979Srwatson t--; 157100979Srwatson nt <<= 3; 158100979Srwatson } 159100979Srwatson return (nt); 160100979Srwatson} 161100979Srwatson 162100979Srwatsonchar * 163100979Srwatsonflagbits(int f) 164100979Srwatson{ 165101892Srwatson static char flags[20] = "-"; 166100979Srwatson char *p; 167100979Srwatson 168100979Srwatson#define BIT(flag, ch) if (f & flag) *p++ = ch 169100979Srwatson 170101988Srwatson p = flags + 1; 171100979Srwatson BIT(AFORK, 'F'); 172100979Srwatson BIT(AMAP, 'M'); 173100979Srwatson BIT(ACORE, 'D'); 174100979Srwatson BIT(AXSIG, 'X'); 175100979Srwatson BIT(APLEDGE, 'P'); 176100979Srwatson BIT(ATRAP, 'T'); 177100979Srwatson BIT(AUNVEIL, 'U'); 178100979Srwatson *p = '\0'; 179100979Srwatson return (flags); 180100979Srwatson} 181100979Srwatson 182100979Srwatsonint 183100979Srwatsonrequested(char *argv[], struct acct *acp) 184100979Srwatson{ 185100979Srwatson do { 186100979Srwatson if (!strcmp(user_from_uid(acp->ac_uid, 0), *argv)) 187100979Srwatson return (1); 188100979Srwatson if (!strcmp(getdev(acp->ac_tty), *argv)) 189100979Srwatson return (1); 190100979Srwatson if (!strncmp(acp->ac_comm, *argv, sizeof acp->ac_comm)) 191100979Srwatson return (1); 192100979Srwatson } while (*++argv); 193100979Srwatson return (0); 194100979Srwatson} 195100979Srwatson 196101988Srwatsonchar * 197100979Srwatsongetdev(dev_t dev) 198100979Srwatson{ 199100979Srwatson static dev_t lastdev = (dev_t)-1; 200100979Srwatson static char *lastname; 201100979Srwatson 202100979Srwatson if (dev == NODEV) /* Special case. */ 203100979Srwatson return ("__"); 204100979Srwatson if (dev == lastdev) /* One-element cache. */ 205100979Srwatson return (lastname); 206100979Srwatson lastdev = dev; 207100979Srwatson if ((lastname = devname(dev, S_IFCHR)) == NULL) 208100979Srwatson lastname = "??"; 209100979Srwatson return (lastname); 210100979Srwatson} 211100979Srwatson 212100979Srwatsonvoid 213100979Srwatsonusage(void) 214100979Srwatson{ 215100979Srwatson (void)fprintf(stderr, 216100979Srwatson "usage: lastcomm [-f file] [command ...] [user ...] [terminal ...]\n"); 217100979Srwatson exit(1); 218100979Srwatson} 219100979Srwatson