1/* $NetBSD: lastcomm.c,v 1.22 2012/01/31 16:30:40 christos Exp $ */ 2 3/* 4 * Copyright (c) 1980, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33#ifndef lint 34__COPYRIGHT("@(#) Copyright (c) 1980, 1993\ 35 The Regents of the University of California. All rights reserved."); 36#endif /* not lint */ 37 38#ifndef lint 39#if 0 40static char sccsid[] = "@(#)lastcomm.c 8.2 (Berkeley) 4/29/95"; 41#endif 42__RCSID("$NetBSD: lastcomm.c,v 1.22 2012/01/31 16:30:40 christos Exp $"); 43#endif /* not lint */ 44 45#include <sys/param.h> 46#include <sys/stat.h> 47#include <sys/acct.h> 48 49#include <ctype.h> 50#include <err.h> 51#include <fcntl.h> 52#include <math.h> 53#include <pwd.h> 54#include <stdio.h> 55#include <stdlib.h> 56#include <string.h> 57#include <struct.h> 58#include <time.h> 59#include <tzfile.h> 60#include <unistd.h> 61#include <utmp.h> 62#include "pathnames.h" 63 64static time_t expand(u_int); 65static char *flagbits(int); 66static const char *getdev(dev_t); 67static int requested(char *[], const struct acct *); 68static void usage(void) __dead; 69 70int 71main(int argc, char *argv[]) 72{ 73 char *p; 74 struct acct ab; 75 struct stat sb; 76 FILE *fp; 77 off_t size; 78 time_t t; 79 double delta; 80 int ch, wflag, lwidth; 81 const char *acctfile = _PATH_ACCT; 82 83 setprogname(argv[0]); 84 wflag = 0; 85 lwidth = -6; 86 87 while ((ch = getopt(argc, argv, "f:w")) != -1) 88 switch((char)ch) { 89 case 'f': 90 acctfile = optarg; 91 break; 92 case 'w': 93 wflag = 1; 94 break; 95 case '?': 96 default: 97 usage(); 98 } 99 argc -= optind; 100 argv += optind; 101 102 /* Open the file. */ 103 if ((fp = fopen(acctfile, "r")) == NULL || fstat(fileno(fp), &sb)) 104 err(1, "%s", acctfile); 105 106 /* 107 * Round off to integral number of accounting records, probably 108 * not necessary, but it doesn't hurt. 109 */ 110 size = sb.st_size - sb.st_size % sizeof(ab); 111 112 /* Check if any records to display. */ 113 if (size < (off_t)sizeof(ab)) 114 return 0; 115 116 size -= sizeof(ab); 117 if (fseeko(fp, size, SEEK_SET) == -1) 118 err(1, "%s", acctfile); 119 120 lwidth = (int)fldsiz(acct, ac_comm) - ((wflag)? 0: 6); 121 for (;;) { 122 if (fread(&ab, sizeof(ab), 1, fp) != 1) 123 err(1, "%s", acctfile); 124 125 if (ab.ac_comm[0] == '\0') { 126 ab.ac_comm[0] = '?'; 127 ab.ac_comm[1] = '\0'; 128 } else 129 for (p = &ab.ac_comm[0]; 130 p < &ab.ac_comm[fldsiz(acct, ac_comm)] && *p; ++p) 131 if (!isprint((unsigned char)*p)) 132 *p = '?'; 133 if (!*argv || requested(argv, &ab)) { 134 135 if (!wflag) 136 ab.ac_comm[10] = '\0'; 137 t = expand(ab.ac_utime) + expand(ab.ac_stime); 138 (void)printf( 139 "%-*.*s %-7s %-*.*s %-*.*s %6.2f secs %.16s", 140 lwidth, lwidth, 141 ab.ac_comm, flagbits(ab.ac_flag), 142 UT_NAMESIZE, UT_NAMESIZE, 143 user_from_uid(ab.ac_uid, 0), UT_LINESIZE, 144 UT_LINESIZE, getdev(ab.ac_tty), 145 t / (double)AHZ, ctime(&ab.ac_btime)); 146 delta = expand(ab.ac_etime) / (double)AHZ; 147 (void)printf(" (%1.0f:%02.0f:%05.2f)\n", 148 floor(delta / SECSPERHOUR), 149 floor(fmod(delta, SECSPERHOUR) / SECSPERMIN), 150 fmod(delta, SECSPERMIN)); 151 } 152 /* are we at the beginning of the file yet? */ 153 if (size == 0) 154 break; 155 /* seek backward over the one we read and the next to read */ 156 if (fseeko(fp, 2 * -(off_t)sizeof(ab), SEEK_CUR) == -1) 157 err(1, "%s", acctfile); 158 /* and account for its size */ 159 size -= sizeof(ab); 160 } 161 return 0; 162} 163 164static time_t 165expand(u_int t) 166{ 167 time_t nt; 168 169 nt = t & 017777; 170 t >>= 13; 171 while (t) { 172 t--; 173 nt <<= 3; 174 } 175 return nt; 176} 177 178static char * 179flagbits(int f) 180{ 181 static char flags[20] = "-"; 182 char *p; 183 184#define BIT(flag, ch) if (f & flag) *p++ = ch 185 186 p = flags + 1; 187 BIT(ASU, 'S'); 188 BIT(AFORK, 'F'); 189 BIT(ACOMPAT, 'C'); 190 BIT(ACORE, 'D'); 191 BIT(AXSIG, 'X'); 192 *p = '\0'; 193 return flags; 194} 195 196static int 197requested(char *argv[], const struct acct *acp) 198{ 199 do { 200 if (!strcmp(user_from_uid(acp->ac_uid, 0), *argv)) 201 return 1; 202 if (!strcmp(getdev(acp->ac_tty), *argv)) 203 return 1; 204 if (!strncmp(acp->ac_comm, *argv, fldsiz(acct, ac_comm))) 205 return 1; 206 } while (*++argv); 207 return 0; 208} 209 210static const char * 211getdev(dev_t dev) 212{ 213 static dev_t lastdev = NODEV; 214 static const char *lastname; 215 216 if (dev == NODEV) /* Special case. */ 217 return "__"; 218 if (dev == lastdev) /* One-element cache. */ 219 return lastname; 220 if ((lastname = devname(dev, S_IFCHR)) != NULL) 221 return lastname; 222 return "??"; 223} 224 225static void 226usage(void) 227{ 228 (void)fprintf(stderr, 229 "Usage: %s [-w] [-f file] [command ...] [user ...] [terminal ...]\n", 230 getprogname()); 231 exit(1); 232} 233