1 /* 2 * Copyright (c) 1980, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 static const char copyright[] = 36 "@(#) Copyright (c) 1980, 1993\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38 #endif /* not lint */ 39 40 #ifndef lint 41 #if 0 42 static char sccsid[] = "@(#)lastcomm.c 8.1 (Berkeley) 6/6/93"; 43 #endif 44 #endif /* not lint */ 45 #include <sys/cdefs.h> 46 __FBSDID("$FreeBSD$"); 47 48 #include <sys/param.h> 49 #include <sys/stat.h> 50 #include <sys/acct.h> 51 52 #include <ctype.h> 53 #include <err.h> 54 #include <fcntl.h> 55 #include <grp.h> 56 #include <pwd.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <unistd.h> 61 #include <utmp.h> 62 #include "pathnames.h" 63 64 /*XXX*/#include <inttypes.h> 65 66 time_t expand(u_int); 67 char *flagbits(int); 68 const char *getdev(dev_t); 69 int requested(char *[], struct acct *); 70 static void usage(void); 71 72 #define AC_UTIME 1 /* user */ 73 #define AC_STIME 2 /* system */ 74 #define AC_ETIME 4 /* elapsed */ 75 #define AC_CTIME 8 /* user + system time, default */ 76 77 #define AC_BTIME 16 /* starting time */ 78 #define AC_FTIME 32 /* exit time (starting time + elapsed time )*/ 79 80 #define AC_HZ ((double)AHZ) 81 82 int 83 main(int argc, char *argv[]) 84 { 85 char *p; 86 struct acct ab; 87 struct stat sb; 88 FILE *fp; 89 off_t size; 90 time_t t; 91 int ch; 92 const char *acctfile; 93 int flags = 0; 94 95 acctfile = _PATH_ACCT; 96 while ((ch = getopt(argc, argv, "f:usecSE")) != -1) 97 switch((char)ch) { 98 case 'f': 99 acctfile = optarg; 100 break; 101 102 case 'u': 103 flags |= AC_UTIME; /* user time */ 104 break; 105 case 's': 106 flags |= AC_STIME; /* system time */ 107 break; 108 case 'e': 109 flags |= AC_ETIME; /* elapsed time */ 110 break; 111 case 'c': 112 flags |= AC_CTIME; /* user + system time */ 113 break; 114 115 case 'S': 116 flags |= AC_BTIME; /* starting time */ 117 break; 118 case 'E': 119 /* exit time (starting time + elapsed time )*/ 120 flags |= AC_FTIME; 121 break; 122 123 case '?': 124 default: 125 usage(); 126 } 127 128 /* default user + system time and starting time */ 129 if (!flags) { 130 flags = AC_CTIME | AC_BTIME; 131 } 132 133 argc -= optind; 134 argv += optind; 135 136 if (strcmp(acctfile, "-") == 0) { 137 fp = stdin; 138 size = sizeof(struct acct); /* Always one more to read. */ 139 } else { 140 /* Open the file. */ 141 if ((fp = fopen(acctfile, "r")) == NULL || 142 fstat(fileno(fp), &sb)) 143 err(1, "could not open %s", acctfile); 144 145 /* 146 * Round off to integral number of accounting records, 147 * probably not necessary, but it doesn't hurt. 148 */ 149 size = sb.st_size - sb.st_size % sizeof(struct acct); 150 151 /* Check if any records to display. */ 152 if ((unsigned)size < sizeof(struct acct)) 153 exit(0); 154 } 155 156 do { 157 int rv; 158 159 if (fp != stdin) { 160 size -= sizeof(struct acct); 161 if (fseeko(fp, size, SEEK_SET) == -1) 162 err(1, "seek %s failed", acctfile); 163 } 164 165 if ((rv = fread(&ab, sizeof(struct acct), 1, fp)) != 1) { 166 if (feof(fp)) 167 break; 168 else 169 err(1, "read %s returned %d", acctfile, rv); 170 } 171 172 if (ab.ac_comm[0] == '\0') { 173 ab.ac_comm[0] = '?'; 174 ab.ac_comm[1] = '\0'; 175 } else 176 for (p = &ab.ac_comm[0]; 177 p < &ab.ac_comm[AC_COMM_LEN] && *p; ++p) 178 if (!isprint(*p)) 179 *p = '?'; 180 if (*argv && !requested(argv, &ab)) 181 continue; 182 183 (void)printf("%-*.*s %-7s %-*s %-*s", 184 AC_COMM_LEN, AC_COMM_LEN, ab.ac_comm, 185 flagbits(ab.ac_flag), 186 UT_NAMESIZE, user_from_uid(ab.ac_uid, 0), 187 UT_LINESIZE, getdev(ab.ac_tty)); 188 189 190 /* user + system time */ 191 if (flags & AC_CTIME) { 192 (void)printf(" %6.2f secs", 193 (expand(ab.ac_utime) + 194 expand(ab.ac_stime))/AC_HZ); 195 } 196 197 /* usr time */ 198 if (flags & AC_UTIME) { 199 (void)printf(" %6.2f us", expand(ab.ac_utime)/AC_HZ); 200 } 201 202 /* system time */ 203 if (flags & AC_STIME) { 204 (void)printf(" %6.2f sy", expand(ab.ac_stime)/AC_HZ); 205 } 206 207 /* elapsed time */ 208 if (flags & AC_ETIME) { 209 (void)printf(" %8.2f es", expand(ab.ac_etime)/AC_HZ); 210 } 211 212 /* starting time */ 213 if (flags & AC_BTIME) { 214 (void)printf(" %.16s", ctime(&ab.ac_btime)); 215 } 216 217 /* exit time (starting time + elapsed time )*/ 218 if (flags & AC_FTIME) { 219 t = ab.ac_btime; 220 t += (time_t)(expand(ab.ac_etime)/AC_HZ); 221 (void)printf(" %.16s", ctime(&t)); 222 } 223 printf("\n"); 224 225 } while (size > 0); 226 if (fflush(stdout)) 227 err(1, "stdout"); 228 exit(0); 229 } 230 231 time_t 232 expand(u_int t) 233 { 234 time_t nt; 235 236 nt = t & 017777; 237 t >>= 13; 238 while (t) { 239 t--; 240 nt <<= 3; 241 } 242 return (nt); 243 } 244 245 char * 246 flagbits(int f) 247 { 248 static char flags[20] = "-"; 249 char *p; 250 251 #define BIT(flag, ch) if (f & flag) *p++ = ch 252 253 p = flags + 1; 254 BIT(ASU, 'S'); 255 BIT(AFORK, 'F'); 256 BIT(ACOMPAT, 'C'); 257 BIT(ACORE, 'D'); 258 BIT(AXSIG, 'X'); 259 *p = '\0'; 260 return (flags); 261 } 262 263 int 264 requested(char *argv[], struct acct *acp) 265 { 266 const char *p; 267 268 do { 269 p = user_from_uid(acp->ac_uid, 0); 270 if (!strcmp(p, *argv)) 271 return (1); 272 if ((p = getdev(acp->ac_tty)) && !strcmp(p, *argv)) 273 return (1); 274 if (!strncmp(acp->ac_comm, *argv, AC_COMM_LEN)) 275 return (1); 276 } while (*++argv); 277 return (0); 278 } 279 280 const char * 281 getdev(dev_t dev) 282 { 283 static dev_t lastdev = (dev_t)-1; 284 static const char *lastname; 285 286 if (dev == NODEV) /* Special case. */ 287 return ("__"); 288 if (dev == lastdev) /* One-element cache. */ 289 return (lastname); 290 lastdev = dev; 291 lastname = devname(dev, S_IFCHR); 292 return (lastname); 293 } 294 295 static void 296 usage(void) 297 { 298 (void)fprintf(stderr, 299 "usage: lastcomm [-EScesu] [-f file] [command ...] [user ...] [terminal ...]\n"); 300 exit(1); 301 } 302