1*7457Skre static char *sccsid = "@(#)lastcomm.c	4.4 (Berkeley) 82/07/17";
21037Sbill 
31037Sbill /*
41037Sbill  * last command
51037Sbill  */
61037Sbill 
71037Sbill # include <stdio.h>
8*7457Skre # include <sys/param.h>
91037Sbill # include <sys/acct.h>
10*7457Skre # include <sys/dir.h>
111037Sbill # include <signal.h>
121037Sbill # include <pwd.h>
131037Sbill # include <stat.h>
14*7457Skre # include <utmp.h>
15*7457Skre # include <struct.h>
161037Sbill 
17*7457Skre # define N_USER		4000		/* highest alloc user # */
18*7457Skre # define N_DEVS		43		/* hash value for device names */
19*7457Skre # define NDEVS		500		/* max number of file names in /dev */
201037Sbill 
211037Sbill struct acct	acct_buff [BUFSIZ / sizeof (struct acct)];
221037Sbill 
23*7457Skre char	user_list [N_USER][fldsiz(utmp, ut_name) + 1];
241037Sbill 
25*7457Skre struct	devhash {
26*7457Skre 	dev_t	dev_dev;
27*7457Skre 	char	dev_name [fldsiz(utmp, ut_line) + 1];
28*7457Skre 	struct	devhash * dev_nxt;
29*7457Skre }
30*7457Skre 	* dev_hash [ N_DEVS ],
31*7457Skre 	* dev_chain ;
32*7457Skre # define HASH(d)	(((int) d) % N_DEVS)
331037Sbill 
341037Sbill time_t	expand ();
35*7457Skre char	* flagbits();
36*7457Skre char	* tername();
371037Sbill 
381037Sbill struct passwd
391037Sbill 	*passwd,
401037Sbill 	*getpwent ();
411037Sbill 
421037Sbill struct stat stat_buff;
431037Sbill 
44*7457Skre # define equal(a, b)		(strcmp(a, b) == 0)
45*7457Skre 
461037Sbill main (argc, argv)
471037Sbill char **argv;
481037Sbill {
491037Sbill 	char	acct_desc,
501037Sbill 		*p;
511037Sbill 
521037Sbill 	long	i,
531037Sbill 		j,
541037Sbill 		i_block,
551037Sbill 		n_blocks,
561037Sbill 		n_byte,
571037Sbill 		n_entry;
581037Sbill 
591037Sbill 	float	x;
601037Sbill 
611037Sbill /*
621037Sbill  * set up user names
631037Sbill  */
641037Sbill 	while (passwd = getpwent ())
651037Sbill 	{
661887Smark 		if (user_list[passwd->pw_uid][0]==0)
671886Smark 			move (passwd->pw_name, user_list [passwd->pw_uid]);
681037Sbill 	}
691037Sbill 
70*7457Skre  /*
71*7457Skre   * find dev numbers corresponding to names in /dev
72*7457Skre   */
73*7457Skre 	setupdevs();
74*7457Skre 
751037Sbill 	acct_desc = open ("/usr/adm/acct", 0);
761037Sbill 	if (acct_desc < 0)
771037Sbill 	{
781037Sbill 		perror ("/usr/adm/acct");
791037Sbill 		return;
801037Sbill 	}
811037Sbill 	fstat (acct_desc, &stat_buff);
821037Sbill 	n_blocks = (stat_buff.st_size + BUFSIZ - 1) / BUFSIZ;
831037Sbill 
841037Sbill 	/*
851037Sbill 	 * read one block's worth
861037Sbill 	 */
871037Sbill 	for (i_block = n_blocks - 1; i_block >= 0; i_block--)
881037Sbill 	{
891037Sbill 		lseek (acct_desc, i_block * BUFSIZ, 0);
901037Sbill 		n_byte = read (acct_desc, acct_buff, BUFSIZ);
911037Sbill 		n_entry = n_byte / sizeof acct_buff [0];
921037Sbill 		for (i = n_entry - 1; i >= 0; i--)
931037Sbill 		{
94*7457Skre 			if (!*user_list [acct_buff [i].ac_uid])
95*7457Skre 				continue;
961037Sbill 			/*
971037Sbill 			 * get the times
981037Sbill 			 */
991037Sbill 			x =	expand (acct_buff [i].ac_utime)
1001037Sbill 				+
1011037Sbill 				expand (acct_buff [i].ac_stime);
1021037Sbill 			/*
1031037Sbill 			 * null terminate the command name
1041037Sbill 			 */
1051037Sbill 			acct_buff [i].ac_comm [10] = 0;
1061037Sbill 			/*
1071037Sbill 			 * replace missing command names with question marks
1081037Sbill 			 */
1091037Sbill 			if (!*acct_buff [i].ac_comm)
1101037Sbill 			{
1111037Sbill 				move ("?", acct_buff [i].ac_comm);
1121037Sbill 			}
1131037Sbill 			/*
1141037Sbill 			 * replace control characters with question marks
1151037Sbill 			 */
1161037Sbill 			for (p = acct_buff [i].ac_comm; *p; p++)
1171037Sbill 			{
118*7457Skre 				if (*p < '!' || '~' < *p)
119*7457Skre 					*p = '?';
1201037Sbill 			}
1211037Sbill 			for (j = 1; j < argc; j++)
1221037Sbill 			{
1231037Sbill 				if
1241037Sbill 				(
1251037Sbill 					equal (acct_buff [i].ac_comm, argv [j])
1261037Sbill 					||
1271037Sbill 					equal
1281037Sbill 					(
129*7457Skre 						user_list[acct_buff[i].ac_uid],
1301037Sbill 						argv [j]
1311037Sbill 					)
132*7457Skre 					||
133*7457Skre 					equal
134*7457Skre 					(
135*7457Skre 						tername(acct_buff[i].ac_tty),
136*7457Skre 						argv[j]
137*7457Skre 					)
1381037Sbill 				)
1391037Sbill 				{
1401037Sbill 					break;
1411037Sbill 				}
1421037Sbill 			}
1431037Sbill 			if (argc == 1 || j != argc)
1441037Sbill 			{
1451037Sbill 				printf
1461037Sbill 				(
147*7457Skre 					"%-*s %s %-*s %-*s %6.2f     %.16s\n"
148*7457Skre 					, fldsiz(acct, ac_comm)
149*7457Skre 					, acct_buff [i].ac_comm
150*7457Skre 					, flagbits(acct_buff [i].ac_flag)
151*7457Skre 					, fldsiz(utmp, ut_name)
152*7457Skre 					, user_list [acct_buff [i].ac_uid]
153*7457Skre 					, fldsiz(utmp, ut_line)
154*7457Skre 					, tername(acct_buff [i].ac_tty)
155*7457Skre 					, x / 60.0
156*7457Skre 					, ctime (&acct_buff [i].ac_btime)
1571037Sbill 				);
1581037Sbill 			}
1591037Sbill 		}
1601037Sbill 	}
1611037Sbill }
1621037Sbill 
1631037Sbill time_t
1641037Sbill expand (t)
1651037Sbill unsigned t;
1661037Sbill {
1671037Sbill 	register time_t nt;
1681037Sbill 
1691037Sbill 	nt = t & 017777;
1701037Sbill 	t >>= 13;
1711037Sbill 	while (t)
1721037Sbill 	{
1731037Sbill 		t--;
1741037Sbill 		nt <<= 3;
1751037Sbill 	}
1761037Sbill 	return (nt);
1771037Sbill }
1781037Sbill 
1791037Sbill move (a, b)
1801037Sbill char *a, *b;
1811037Sbill {
182*7457Skre 	while (*b++ = *a++)
183*7457Skre 		;
1841037Sbill }
1851037Sbill 
186*7457Skre char *
187*7457Skre flagbits(f)
188*7457Skre register int f;
1891037Sbill {
190*7457Skre 	register int i = 0;
191*7457Skre 	static char flags[20];
192*7457Skre 
193*7457Skre # define BIT(flag, ch)	flags[i++] = ( f & flag ) ? ch : ' '
194*7457Skre 
195*7457Skre 	BIT( ASU,	'S');
196*7457Skre 	BIT( AFORK,	'F');
197*7457Skre 	BIT( ACOMPAT,	'C');
198*7457Skre 	BIT( ACORE,	'D');
199*7457Skre 	BIT( AXSIG,	'X');
200*7457Skre 
201*7457Skre 	flags[i] = '\0';
202*7457Skre 
203*7457Skre 	return(flags);
204*7457Skre }
205*7457Skre 
206*7457Skre setupdevs()
207*7457Skre {
208*7457Skre 	register DIR * fd;
209*7457Skre 	register struct devhash * hashtab;
210*7457Skre 	register ndevs = NDEVS;
211*7457Skre 	struct direct * dp;
212*7457Skre 
213*7457Skre 	if ((fd = opendir("/dev")) == NULL) {
214*7457Skre 		perror("/dev");
215*7457Skre 		return;
2161037Sbill 	}
217*7457Skre 
218*7457Skre 	if ((hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash)))
219*7457Skre 	    == (struct devhash *) 0) {
220*7457Skre 		fprintf(stderr, "No mem for dev table\n");
221*7457Skre 		return;
222*7457Skre 	}
223*7457Skre 
224*7457Skre 	while (dp = readdir(fd)) {
225*7457Skre 		if (dp->d_ino == 0)
226*7457Skre 			continue;
227*7457Skre #ifdef	MELB
228*7457Skre 		if (dp->d_name[0] != 't' && strcmp(dp->d_name, "console"))
229*7457Skre 			continue;
230*7457Skre #endif
231*7457Skre 		strncpy(hashtab->dev_name, dp->d_name, fldsiz(utmp, ut_line));
232*7457Skre 		hashtab->dev_name[fldsiz(utmp, ut_line)] = 0;
233*7457Skre 		hashtab->dev_nxt = dev_chain;
234*7457Skre 		dev_chain = hashtab;
235*7457Skre 		hashtab++;
236*7457Skre 		if (--ndevs <= 0)
237*7457Skre 			break;
238*7457Skre 	}
239*7457Skre 	closedir(fd);
2401037Sbill }
241*7457Skre 
242*7457Skre char *
243*7457Skre tername(dev)
244*7457Skre dev_t dev;
245*7457Skre {
246*7457Skre 	register struct devhash *hp, *nhp;
247*7457Skre 	struct stat statb;
248*7457Skre 	char name [fldsiz(devhash, dev_name) + 6];
249*7457Skre 	static dev_t lastdev = (dev_t) -1;
250*7457Skre 	static char *lastname;
251*7457Skre 
252*7457Skre 	if (dev == NODEV)
253*7457Skre 		return("__");
254*7457Skre 
255*7457Skre 	if (dev == lastdev)
256*7457Skre 		return(lastname);
257*7457Skre 
258*7457Skre 	for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt)
259*7457Skre 		if (hp->dev_dev == dev) {
260*7457Skre 			lastdev = dev;
261*7457Skre 			return(lastname = hp->dev_name);
262*7457Skre 		}
263*7457Skre 
264*7457Skre 	for (hp = dev_chain; hp; hp = nhp) {
265*7457Skre 		nhp = hp->dev_nxt;
266*7457Skre 		strcpy(name, "/dev/");
267*7457Skre 		strcat(name, hp->dev_name);
268*7457Skre 		if (stat(name, &statb) < 0)	/* name truncated usually */
269*7457Skre 			continue;
270*7457Skre 		if ((statb.st_mode & S_IFMT) != S_IFCHR)
271*7457Skre 			continue;
272*7457Skre 		hp->dev_dev = statb.st_rdev;
273*7457Skre 		hp->dev_nxt = dev_hash[HASH(hp->dev_dev)];
274*7457Skre 		dev_hash[HASH(hp->dev_dev)] = hp;
275*7457Skre 		if (hp->dev_dev == dev) {
276*7457Skre 			dev_chain = nhp;
277*7457Skre 			lastdev = dev;
278*7457Skre 			return(lastname = hp->dev_name);
279*7457Skre 		}
280*7457Skre 	}
281*7457Skre 
282*7457Skre 	dev_chain = (struct devhash *) 0;
283*7457Skre 	return("??");
284*7457Skre }
285