xref: /netbsd-src/usr.bin/lastcomm/lastcomm.c (revision cda4f8f6ee55684e8d311b86c99ea59191e6b74f)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * 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 char copyright[] =
36 "@(#) Copyright (c) 1980 Regents of the University of California.\n\
37  All rights reserved.\n";
38 #endif /* not lint */
39 
40 #ifndef lint
41 static char sccsid[] = "@(#)lastcomm.c	5.11 (Berkeley) 6/1/90";
42 #endif /* not lint */
43 
44 /*
45  * last command
46  */
47 #include <sys/param.h>
48 #include <sys/acct.h>
49 #include <sys/file.h>
50 #include <sys/stat.h>
51 #include <utmp.h>
52 #include <struct.h>
53 #include <ctype.h>
54 #include <stdio.h>
55 #include "pathnames.h"
56 
57 struct	acct buf[DEV_BSIZE / sizeof (struct acct)];
58 
59 time_t	expand();
60 char	*flagbits();
61 char	*getdev();
62 
63 main(argc, argv)
64 	int argc;
65 	char *argv[];
66 {
67 	extern int optind;
68 	extern char *optarg;
69 	register struct acct *acp;
70 	register int bn, cc;
71 	struct stat sb;
72 	int ch, fd;
73 	char *acctfile, *ctime(), *strcpy(), *user_from_uid();
74 	long lseek();
75 
76 	acctfile = _PATH_ACCT;
77 	while ((ch = getopt(argc, argv, "f:")) != EOF)
78 		switch((char)ch) {
79 		case 'f':
80 			acctfile = optarg;
81 			break;
82 		case '?':
83 		default:
84 			fputs("lastcomm [ -f file ]\n", stderr);
85 			exit(1);
86 		}
87 	argv += optind;
88 
89 	fd = open(acctfile, O_RDONLY);
90 	if (fd < 0) {
91 		perror(acctfile);
92 		exit(1);
93 	}
94 	(void)fstat(fd, &sb);
95 	setpassent(1);
96 	for (bn = btodb(sb.st_size); bn >= 0; bn--) {
97 		(void)lseek(fd, (off_t)dbtob(bn), L_SET);
98 		cc = read(fd, buf, DEV_BSIZE);
99 		if (cc < 0) {
100 			perror("read");
101 			break;
102 		}
103 		acp = buf + (cc / sizeof (buf[0])) - 1;
104 		for (; acp >= buf; acp--) {
105 			register char *cp;
106 			time_t x;
107 
108 			if (acp->ac_comm[0] == '\0')
109 				(void)strcpy(acp->ac_comm, "?");
110 			for (cp = &acp->ac_comm[0];
111 			     cp < &acp->ac_comm[fldsiz(acct, ac_comm)] && *cp;
112 			     cp++)
113 				if (!isascii(*cp) || iscntrl(*cp))
114 					*cp = '?';
115 			if (*argv && !ok(argv, acp))
116 				continue;
117 			x = expand(acp->ac_utime) + expand(acp->ac_stime);
118 			printf("%-*.*s %s %-*s %-*s %6.2f secs %.16s\n",
119 				fldsiz(acct, ac_comm), fldsiz(acct, ac_comm),
120 				acp->ac_comm, flagbits(acp->ac_flag),
121 				UT_NAMESIZE, user_from_uid(acp->ac_uid, 0),
122 				UT_LINESIZE, getdev(acp->ac_tty),
123 				x / (double)AHZ, ctime(&acp->ac_btime));
124 		}
125 	}
126 }
127 
128 time_t
129 expand (t)
130 	unsigned t;
131 {
132 	register time_t nt;
133 
134 	nt = t & 017777;
135 	t >>= 13;
136 	while (t) {
137 		t--;
138 		nt <<= 3;
139 	}
140 	return (nt);
141 }
142 
143 char *
144 flagbits(f)
145 	register int f;
146 {
147 	static char flags[20];
148 	char *p, *strcpy();
149 
150 #define	BIT(flag, ch)	if (f & flag) *p++ = ch;
151 	p = strcpy(flags, "-    ");
152 	BIT(ASU, 'S');
153 	BIT(AFORK, 'F');
154 	BIT(ACOMPAT, 'C');
155 	BIT(ACORE, 'D');
156 	BIT(AXSIG, 'X');
157 	return (flags);
158 }
159 
160 ok(argv, acp)
161 	register char *argv[];
162 	register struct acct *acp;
163 {
164 	register char *cp;
165 	char *user_from_uid();
166 
167 	do {
168 		cp = user_from_uid(acp->ac_uid, 0);
169 		if (!strcmp(cp, *argv))
170 			return(1);
171 		if ((cp = getdev(acp->ac_tty)) && !strcmp(cp, *argv))
172 			return(1);
173 		if (!strncmp(acp->ac_comm, *argv, fldsiz(acct, ac_comm)))
174 			return(1);
175 	} while (*++argv);
176 	return(0);
177 }
178 
179 #include <sys/dir.h>
180 
181 #define N_DEVS		43		/* hash value for device names */
182 #define NDEVS		500		/* max number of file names in /dev */
183 
184 struct	devhash {
185 	dev_t	dev_dev;
186 	char	dev_name [UT_LINESIZE + 1];
187 	struct	devhash * dev_nxt;
188 };
189 struct	devhash *dev_hash[N_DEVS];
190 struct	devhash *dev_chain;
191 #define HASH(d)	(((int) d) % N_DEVS)
192 
193 setupdevs()
194 {
195 	register DIR * fd;
196 	register struct devhash * hashtab;
197 	register ndevs = NDEVS;
198 	struct direct * dp;
199 	char *malloc();
200 
201 	/*NOSTRICT*/
202 	hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash));
203 	if (hashtab == (struct devhash *)0) {
204 		fputs("No mem for dev table\n", stderr);
205 		return;
206 	}
207 	if ((fd = opendir(_PATH_DEV)) == NULL) {
208 		perror(_PATH_DEV);
209 		return;
210 	}
211 	while (dp = readdir(fd)) {
212 		if (dp->d_ino == 0)
213 			continue;
214 		if (dp->d_name[0] != 't' && /* XXX (cgd) followin is a hack! */
215 		    (strcmp(dp->d_name, "console") && strcmp(dp->d_name, "vga")))
216 			continue;
217 		(void)strncpy(hashtab->dev_name, dp->d_name, UT_LINESIZE);
218 		hashtab->dev_name[UT_LINESIZE] = 0;
219 		hashtab->dev_nxt = dev_chain;
220 		dev_chain = hashtab;
221 		hashtab++;
222 		if (--ndevs <= 0)
223 			break;
224 	}
225 	closedir(fd);
226 }
227 
228 char *
229 getdev(dev)
230 	dev_t dev;
231 {
232 	register struct devhash *hp, *nhp;
233 	struct stat statb;
234 	char name[fldsiz(devhash, dev_name) + 6];
235 	static dev_t lastdev = (dev_t) -1;
236 	static char *lastname;
237 	static int init = 0;
238 	char *strcpy(), *strcat();
239 
240 	if (dev == NODEV)
241 		return ("__");
242 	if (dev == lastdev)
243 		return (lastname);
244 	if (!init) {
245 		setupdevs();
246 		init++;
247 	}
248 	for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt)
249 		if (hp->dev_dev == dev) {
250 			lastdev = dev;
251 			return (lastname = hp->dev_name);
252 		}
253 	for (hp = dev_chain; hp; hp = nhp) {
254 		nhp = hp->dev_nxt;
255 		(void)strcpy(name, _PATH_DEV);
256 		strcat(name, hp->dev_name);
257 		if (stat(name, &statb) < 0)	/* name truncated usually */
258 			continue;
259 		if ((statb.st_mode & S_IFMT) != S_IFCHR)
260 			continue;
261 		hp->dev_dev = statb.st_rdev;
262 		hp->dev_nxt = dev_hash[HASH(hp->dev_dev)];
263 		dev_hash[HASH(hp->dev_dev)] = hp;
264 		if (hp->dev_dev == dev) {
265 			dev_chain = nhp;
266 			lastdev = dev;
267 			return (lastname = hp->dev_name);
268 		}
269 	}
270 	dev_chain = (struct devhash *) 0;
271 	return ("??");
272 }
273