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