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