xref: /original-bsd/usr.bin/lastcomm/lastcomm.c (revision f238860a)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 char copyright[] =
9 "@(#) Copyright (c) 1980 Regents of the University of California.\n\
10  All rights reserved.\n";
11 #endif not lint
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)lastcomm.c	5.1 (Berkeley) 05/31/85";
15 #endif not lint
16 
17 /*
18  * last command
19  */
20 #include <sys/param.h>
21 #include <sys/acct.h>
22 #include <sys/file.h>
23 
24 #include <stdio.h>
25 #include <pwd.h>
26 #include <sys/stat.h>
27 #include <utmp.h>
28 #include <struct.h>
29 #include <ctype.h>
30 
31 struct	acct buf[DEV_BSIZE / sizeof (struct acct)];
32 
33 time_t	expand();
34 char	*flagbits();
35 char	*getname();
36 char	*getdev();
37 
38 main(argc, argv)
39 	char *argv[];
40 {
41 	register int bn, cc;
42 	register struct acct *acp;
43 	int fd;
44 	struct stat sb;
45 
46 	fd = open("/usr/adm/acct", O_RDONLY);
47 	if (fd < 0) {
48 		perror("/usr/adm/acct");
49 		exit(1);
50 	}
51 	fstat(fd, &sb);
52 	for (bn = btodb(sb.st_size); bn >= 0; bn--) {
53 		lseek(fd, dbtob(bn), L_SET);
54 		cc = read(fd, buf, DEV_BSIZE);
55 		if (cc < 0) {
56 			perror("read");
57 			break;
58 		}
59 		acp = buf + (cc / sizeof (buf[0])) - 1;
60 		for (; acp >= buf; acp--) {
61 			register char *cp;
62 			time_t x;
63 
64 			if (acp->ac_comm[0] == '\0')
65 				strcpy(acp->ac_comm, "?");
66 			for (cp = &acp->ac_comm[0];
67 			     cp < &acp->ac_comm[fldsiz(acct, ac_comm)] && *cp;
68 			     cp++)
69 				if (!isascii(*cp) || iscntrl(*cp))
70 					*cp = '?';
71 			if (argc > 1 && !ok(argc, argv, acp))
72 				continue;
73 			x = expand(acp->ac_utime) + expand(acp->ac_stime);
74 			printf("%-*s %s %-*s %-*s %6.2f secs %.16s\n",
75 				fldsiz(acct, ac_comm), acp->ac_comm,
76 				flagbits(acp->ac_flag),
77 				fldsiz(utmp, ut_name), getname(acp->ac_uid),
78 				fldsiz(utmp, ut_line), getdev(acp->ac_tty),
79 				x / (double)AHZ, ctime(&acp->ac_btime));
80 		}
81 	}
82 }
83 
84 time_t
85 expand (t)
86 	unsigned t;
87 {
88 	register time_t nt;
89 
90 	nt = t & 017777;
91 	t >>= 13;
92 	while (t) {
93 		t--;
94 		nt <<= 3;
95 	}
96 	return (nt);
97 }
98 
99 char *
100 flagbits(f)
101 	register int f;
102 {
103 	register int i = 0;
104 	static char flags[20];
105 
106 #define BIT(flag, ch)	flags[i++] = (f & flag) ? ch : ' '
107 	BIT(ASU, 'S');
108 	BIT(AFORK, 'F');
109 	BIT(ACOMPAT, 'C');
110 	BIT(ACORE, 'D');
111 	BIT(AXSIG, 'X');
112 	flags[i] = '\0';
113 	return (flags);
114 }
115 
116 ok(argc, argv, acp)
117 	register int argc;
118 	register char *argv[];
119 	register struct acct *acp;
120 {
121 	register int j;
122 
123 	for (j = 1; j < argc; j++)
124 		if (strcmp(getname(acp->ac_uid), argv[j]) &&
125 		    strcmp(getdev(acp->ac_tty), argv[j]) &&
126 		    strncmp(acp->ac_comm, argv[j], fldsiz(acct, ac_comm)))
127 			break;
128 	return (j == argc);
129 }
130 
131 /* should be done with nameserver or database */
132 
133 struct	utmp utmp;
134 
135 #define NUID	2048
136 #define	NMAX	(sizeof (utmp.ut_name))
137 
138 char	names[NUID][NMAX+1];
139 char	outrangename[NMAX+1];
140 int	outrangeuid = -1;
141 
142 char *
143 getname(uid)
144 {
145 	register struct passwd *pw;
146 	static init;
147 	struct passwd *getpwent();
148 
149 	if (uid >= 0 && uid < NUID && names[uid][0])
150 		return (&names[uid][0]);
151 	if (uid >= 0 && uid == outrangeuid)
152 		return (outrangename);
153 	if (init == 2) {
154 		if (uid < NUID)
155 			return (0);
156 		setpwent();
157 		while (pw = getpwent()) {
158 			if (pw->pw_uid != uid)
159 				continue;
160 			outrangeuid = pw->pw_uid;
161 			strncpy(outrangename, pw->pw_name, NMAX);
162 			endpwent();
163 			return (outrangename);
164 		}
165 		endpwent();
166 		return (0);
167 	}
168 	if (init == 0)
169 		setpwent(), init = 1;
170 	while (pw = getpwent()) {
171 		if (pw->pw_uid < 0 || pw->pw_uid >= NUID) {
172 			if (pw->pw_uid == uid) {
173 				outrangeuid = pw->pw_uid;
174 				strncpy(outrangename, pw->pw_name, NMAX);
175 				return (outrangename);
176 			}
177 			continue;
178 		}
179 		if (names[pw->pw_uid][0])
180 			continue;
181 		strncpy(names[pw->pw_uid], pw->pw_name, NMAX);
182 		if (pw->pw_uid == uid)
183 			return (&names[uid][0]);
184 	}
185 	init = 2;
186 	endpwent();
187 	return (0);
188 }
189 
190 #include <sys/dir.h>
191 
192 #define N_DEVS		43		/* hash value for device names */
193 #define NDEVS		500		/* max number of file names in /dev */
194 
195 struct	devhash {
196 	dev_t	dev_dev;
197 	char	dev_name [fldsiz(utmp, ut_line) + 1];
198 	struct	devhash * dev_nxt;
199 };
200 struct	devhash *dev_hash[N_DEVS];
201 struct	devhash *dev_chain;
202 #define HASH(d)	(((int) d) % N_DEVS)
203 
204 setupdevs()
205 {
206 	register DIR * fd;
207 	register struct devhash * hashtab;
208 	register ndevs = NDEVS;
209 	struct direct * dp;
210 
211 	if ((fd = opendir("/dev")) == NULL) {
212 		perror("/dev");
213 		return;
214 	}
215 	hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash));
216 	if (hashtab == (struct devhash *)0) {
217 		fprintf(stderr, "No mem for dev table\n");
218 		closedir(fd);
219 		return;
220 	}
221 	while (dp = readdir(fd)) {
222 		if (dp->d_ino == 0)
223 			continue;
224 		if (dp->d_name[0] != 't' && strcmp(dp->d_name, "console"))
225 			continue;
226 		strncpy(hashtab->dev_name, dp->d_name, fldsiz(utmp, ut_line));
227 		hashtab->dev_name[fldsiz(utmp, ut_line)] = 0;
228 		hashtab->dev_nxt = dev_chain;
229 		dev_chain = hashtab;
230 		hashtab++;
231 		if (--ndevs <= 0)
232 			break;
233 	}
234 	closedir(fd);
235 }
236 
237 char *
238 getdev(dev)
239 	dev_t dev;
240 {
241 	register struct devhash *hp, *nhp;
242 	struct stat statb;
243 	char name[fldsiz(devhash, dev_name) + 6];
244 	static dev_t lastdev = (dev_t) -1;
245 	static char *lastname;
246 	static int init = 0;
247 
248 	if (dev == NODEV)
249 		return ("__");
250 	if (dev == lastdev)
251 		return (lastname);
252 	if (!init) {
253 		setupdevs();
254 		init++;
255 	}
256 	for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt)
257 		if (hp->dev_dev == dev) {
258 			lastdev = dev;
259 			return (lastname = hp->dev_name);
260 		}
261 	for (hp = dev_chain; hp; hp = nhp) {
262 		nhp = hp->dev_nxt;
263 		strcpy(name, "/dev/");
264 		strcat(name, hp->dev_name);
265 		if (stat(name, &statb) < 0)	/* name truncated usually */
266 			continue;
267 		if ((statb.st_mode & S_IFMT) != S_IFCHR)
268 			continue;
269 		hp->dev_dev = statb.st_rdev;
270 		hp->dev_nxt = dev_hash[HASH(hp->dev_dev)];
271 		dev_hash[HASH(hp->dev_dev)] = hp;
272 		if (hp->dev_dev == dev) {
273 			dev_chain = nhp;
274 			lastdev = dev;
275 			return (lastname = hp->dev_name);
276 		}
277 	}
278 	dev_chain = (struct devhash *) 0;
279 	return ("??");
280 }
281