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