lastcomm.c revision 92920
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1980, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes 341590Srgrimes#ifndef lint 3578859Sddstatic const char copyright[] = 361590Srgrimes"@(#) Copyright (c) 1980, 1993\n\ 371590Srgrimes The Regents of the University of California. All rights reserved.\n"; 381590Srgrimes#endif /* not lint */ 391590Srgrimes 401590Srgrimes#ifndef lint 4127571Scharnier#if 0 421590Srgrimesstatic char sccsid[] = "@(#)lastcomm.c 8.1 (Berkeley) 6/6/93"; 4327571Scharnier#endif 4427571Scharnierstatic const char rcsid[] = 4550477Speter "$FreeBSD: head/usr.bin/lastcomm/lastcomm.c 92920 2002-03-22 01:22:50Z imp $"; 461590Srgrimes#endif /* not lint */ 471590Srgrimes 481590Srgrimes#include <sys/param.h> 491590Srgrimes#include <sys/stat.h> 501590Srgrimes#include <sys/acct.h> 511590Srgrimes 521590Srgrimes#include <ctype.h> 531590Srgrimes#include <err.h> 541590Srgrimes#include <fcntl.h> 5590878Simp#include <pwd.h> 561590Srgrimes#include <stdio.h> 571590Srgrimes#include <stdlib.h> 581590Srgrimes#include <string.h> 591590Srgrimes#include <unistd.h> 601590Srgrimes#include <utmp.h> 611590Srgrimes#include "pathnames.h" 621590Srgrimes 6392920Simptime_t expand(u_int); 6492920Simpchar *flagbits(int); 6592920Simpconst char *getdev(dev_t); 6692920Simpint requested(char *[], struct acct *); 6792920Simpstatic void usage(void); 681590Srgrimes 6916849Swosch#define AC_UTIME 1 /* user */ 7016849Swosch#define AC_STIME 2 /* system */ 7116849Swosch#define AC_ETIME 4 /* elapsed */ 7216849Swosch#define AC_CTIME 8 /* user + system time, default */ 7316849Swosch 7416849Swosch#define AC_BTIME 16 /* starting time */ 7516849Swosch#define AC_FTIME 32 /* exit time (starting time + elapsed time )*/ 7616849Swosch 7716849Swosch#define AC_HZ ((double)AHZ) 7816849Swosch 791590Srgrimesint 801590Srgrimesmain(argc, argv) 811590Srgrimes int argc; 821590Srgrimes char *argv[]; 831590Srgrimes{ 8478859Sdd char *p; 851590Srgrimes struct acct ab; 861590Srgrimes struct stat sb; 871590Srgrimes FILE *fp; 881590Srgrimes off_t size; 891590Srgrimes time_t t; 901590Srgrimes int ch; 9178859Sdd const char *acctfile; 9278859Sdd int flags = 0; 931590Srgrimes 941590Srgrimes acctfile = _PATH_ACCT; 9524360Simp while ((ch = getopt(argc, argv, "f:usecSE")) != -1) 961590Srgrimes switch((char)ch) { 971590Srgrimes case 'f': 981590Srgrimes acctfile = optarg; 991590Srgrimes break; 10016849Swosch 10116849Swosch case 'u': 10278859Sdd flags |= AC_UTIME; /* user time */ 10316849Swosch break; 10416849Swosch case 's': 10578859Sdd flags |= AC_STIME; /* system time */ 10616849Swosch break; 10716849Swosch case 'e': 10878859Sdd flags |= AC_ETIME; /* elapsed time */ 10916849Swosch break; 11016849Swosch case 'c': 11178859Sdd flags |= AC_CTIME; /* user + system time */ 11216849Swosch break; 11316849Swosch 11416849Swosch case 'S': 11578859Sdd flags |= AC_BTIME; /* starting time */ 11616849Swosch break; 11716849Swosch case 'E': 11816849Swosch /* exit time (starting time + elapsed time )*/ 11978859Sdd flags |= AC_FTIME; 12016849Swosch break; 12116849Swosch 1221590Srgrimes case '?': 1231590Srgrimes default: 1241590Srgrimes usage(); 1251590Srgrimes } 12616849Swosch 12716849Swosch /* default user + system time and starting time */ 12878859Sdd if (!flags) { 12978859Sdd flags = AC_CTIME | AC_BTIME; 13016849Swosch } 13116849Swosch 1321590Srgrimes argc -= optind; 1331590Srgrimes argv += optind; 1341590Srgrimes 1351590Srgrimes /* Open the file. */ 1361590Srgrimes if ((fp = fopen(acctfile, "r")) == NULL || fstat(fileno(fp), &sb)) 1371590Srgrimes err(1, "%s", acctfile); 1381590Srgrimes 1391590Srgrimes /* 1401590Srgrimes * Round off to integral number of accounting records, probably 1411590Srgrimes * not necessary, but it doesn't hurt. 1421590Srgrimes */ 1431590Srgrimes size = sb.st_size - sb.st_size % sizeof(struct acct); 1441590Srgrimes 1451590Srgrimes /* Check if any records to display. */ 14678859Sdd if ((unsigned)size < sizeof(struct acct)) 1471590Srgrimes exit(0); 1481590Srgrimes 1491590Srgrimes /* 1501590Srgrimes * Seek to before the last entry in the file; use lseek(2) in case 1511590Srgrimes * the file is bigger than a "long". 1521590Srgrimes */ 1531590Srgrimes size -= sizeof(struct acct); 1541590Srgrimes if (lseek(fileno(fp), size, SEEK_SET) == -1) 1551590Srgrimes err(1, "%s", acctfile); 1561590Srgrimes 1571590Srgrimes for (;;) { 1581590Srgrimes if (fread(&ab, sizeof(struct acct), 1, fp) != 1) 1591590Srgrimes err(1, "%s", acctfile); 1601590Srgrimes 1611590Srgrimes if (fseek(fp, 2 * -(long)sizeof(struct acct), SEEK_CUR) == -1) 1621590Srgrimes err(1, "%s", acctfile); 1631590Srgrimes 1641590Srgrimes if (size == 0) 1651590Srgrimes break; 1661590Srgrimes size -= sizeof(struct acct); 1671590Srgrimes 1681590Srgrimes if (ab.ac_comm[0] == '\0') { 1691590Srgrimes ab.ac_comm[0] = '?'; 1701590Srgrimes ab.ac_comm[1] = '\0'; 1711590Srgrimes } else 1721590Srgrimes for (p = &ab.ac_comm[0]; 17367443Sphk p < &ab.ac_comm[AC_COMM_LEN] && *p; ++p) 1741590Srgrimes if (!isprint(*p)) 1751590Srgrimes *p = '?'; 1761590Srgrimes if (*argv && !requested(argv, &ab)) 1771590Srgrimes continue; 1781590Srgrimes 17978341Smikeh (void)printf("%-*.*s %-7s %-*s %-*s", 18067443Sphk AC_COMM_LEN, AC_COMM_LEN, ab.ac_comm, 18116849Swosch flagbits(ab.ac_flag), 18216849Swosch UT_NAMESIZE, user_from_uid(ab.ac_uid, 0), 18316849Swosch UT_LINESIZE, getdev(ab.ac_tty)); 18416849Swosch 18516849Swosch 18616849Swosch /* user + system time */ 18778859Sdd if (flags & AC_CTIME) { 18878341Smikeh (void)printf(" %6.2f secs", 18916849Swosch (expand(ab.ac_utime) + 19016849Swosch expand(ab.ac_stime))/AC_HZ); 19116849Swosch } 19216849Swosch 19316849Swosch /* usr time */ 19478859Sdd if (flags & AC_UTIME) { 19578341Smikeh (void)printf(" %6.2f us", expand(ab.ac_utime)/AC_HZ); 19616849Swosch } 19716849Swosch 19816849Swosch /* system time */ 19978859Sdd if (flags & AC_STIME) { 20078341Smikeh (void)printf(" %6.2f sy", expand(ab.ac_stime)/AC_HZ); 20116849Swosch } 20216849Swosch 20316849Swosch /* elapsed time */ 20478859Sdd if (flags & AC_ETIME) { 20578341Smikeh (void)printf(" %8.2f es", expand(ab.ac_etime)/AC_HZ); 20616849Swosch } 20716849Swosch 20816849Swosch /* starting time */ 20978859Sdd if (flags & AC_BTIME) { 21078341Smikeh (void)printf(" %.16s", ctime(&ab.ac_btime)); 21116849Swosch } 21216849Swosch 21316849Swosch /* exit time (starting time + elapsed time )*/ 21478859Sdd if (flags & AC_FTIME) { 21516849Swosch t = ab.ac_btime; 21616849Swosch t += (time_t)(expand(ab.ac_etime)/AC_HZ); 21778341Smikeh (void)printf(" %.16s", ctime(&t)); 21816849Swosch } 21916849Swosch printf("\n"); 22016849Swosch } 22116849Swosch exit(0); 2221590Srgrimes} 2231590Srgrimes 2241590Srgrimestime_t 2251590Srgrimesexpand(t) 2261590Srgrimes u_int t; 2271590Srgrimes{ 22878859Sdd time_t nt; 2291590Srgrimes 2301590Srgrimes nt = t & 017777; 2311590Srgrimes t >>= 13; 2321590Srgrimes while (t) { 2331590Srgrimes t--; 2341590Srgrimes nt <<= 3; 2351590Srgrimes } 2361590Srgrimes return (nt); 2371590Srgrimes} 2381590Srgrimes 2391590Srgrimeschar * 2401590Srgrimesflagbits(f) 24178859Sdd int f; 2421590Srgrimes{ 2431590Srgrimes static char flags[20] = "-"; 2441590Srgrimes char *p; 2451590Srgrimes 2461590Srgrimes#define BIT(flag, ch) if (f & flag) *p++ = ch 2471590Srgrimes 2481590Srgrimes p = flags + 1; 2491590Srgrimes BIT(ASU, 'S'); 2501590Srgrimes BIT(AFORK, 'F'); 2511590Srgrimes BIT(ACOMPAT, 'C'); 2521590Srgrimes BIT(ACORE, 'D'); 2531590Srgrimes BIT(AXSIG, 'X'); 2541590Srgrimes *p = '\0'; 2551590Srgrimes return (flags); 2561590Srgrimes} 2571590Srgrimes 2581590Srgrimesint 2591590Srgrimesrequested(argv, acp) 26078859Sdd char *argv[]; 26178859Sdd struct acct *acp; 2621590Srgrimes{ 26378859Sdd const char *p; 2641590Srgrimes 2651590Srgrimes do { 2661590Srgrimes p = user_from_uid(acp->ac_uid, 0); 2678874Srgrimes if (!strcmp(p, *argv)) 2681590Srgrimes return (1); 2691590Srgrimes if ((p = getdev(acp->ac_tty)) && !strcmp(p, *argv)) 2701590Srgrimes return (1); 27167443Sphk if (!strncmp(acp->ac_comm, *argv, AC_COMM_LEN)) 2721590Srgrimes return (1); 2731590Srgrimes } while (*++argv); 2741590Srgrimes return (0); 2751590Srgrimes} 2761590Srgrimes 27778859Sddconst char * 2781590Srgrimesgetdev(dev) 2791590Srgrimes dev_t dev; 2801590Srgrimes{ 2811590Srgrimes static dev_t lastdev = (dev_t)-1; 28278859Sdd static const char *lastname; 2831590Srgrimes 2841590Srgrimes if (dev == NODEV) /* Special case. */ 2851590Srgrimes return ("__"); 2861590Srgrimes if (dev == lastdev) /* One-element cache. */ 2871590Srgrimes return (lastname); 2881590Srgrimes lastdev = dev; 2891590Srgrimes lastname = devname(dev, S_IFCHR); 2901590Srgrimes return (lastname); 2911590Srgrimes} 2921590Srgrimes 29327571Scharnierstatic void 2941590Srgrimesusage() 2951590Srgrimes{ 2961590Srgrimes (void)fprintf(stderr, 29727571Scharnier"usage: lastcomm [-EScesu] [ -f file ] [command ...] [user ...] [tty ...]\n"); 2981590Srgrimes exit(1); 2991590Srgrimes} 300