1 /* $NetBSD: lastcomm.c,v 1.23 2012/01/31 21:53:42 wiz 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 40 static char sccsid[] = "@(#)lastcomm.c 8.2 (Berkeley) 4/29/95"; 41 #endif 42 __RCSID("$NetBSD: lastcomm.c,v 1.23 2012/01/31 21:53:42 wiz 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 64 static time_t expand(u_int); 65 static char *flagbits(int); 66 static const char *getdev(dev_t); 67 static int requested(char *[], const struct acct *); 68 static void usage(void) __dead; 69 70 int 71 main(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 164 static time_t 165 expand(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 178 static char * 179 flagbits(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 196 static int 197 requested(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 210 static const char * 211 getdev(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 225 static void 226 usage(void) 227 { 228 (void)fprintf(stderr, 229 "Usage: %s [-w] [-f file] [command ...] [user ...] [terminal ...]\n", 230 getprogname()); 231 exit(1); 232 } 233