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