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