xref: /csrg-svn/usr.bin/lastcomm/lastcomm.c (revision 11839)
1*11839Ssam #ifndef lint
2*11839Ssam static char *sccsid = "@(#)lastcomm.c	4.5 (Berkeley) 83/04/04";
3*11839Ssam #endif
41037Sbill 
51037Sbill /*
61037Sbill  * last command
71037Sbill  */
8*11839Ssam #include <stdio.h>
9*11839Ssam #include <sys/param.h>
10*11839Ssam #include <sys/acct.h>
11*11839Ssam #include <sys/dir.h>
12*11839Ssam #include <signal.h>
13*11839Ssam #include <pwd.h>
14*11839Ssam #include <stat.h>
15*11839Ssam #include <utmp.h>
16*11839Ssam #include <struct.h>
17*11839Ssam #include <ctype.h>
181037Sbill 
19*11839Ssam #define N_USER		4000		/* highest alloc user # */
20*11839Ssam #define N_DEVS		43		/* hash value for device names */
21*11839Ssam #define NDEVS		500		/* max number of file names in /dev */
221037Sbill 
23*11839Ssam struct	acct acct_buff[BUFSIZ / sizeof (struct acct)];
24*11839Ssam char	user_list[N_USER][fldsiz(utmp, ut_name) + 1];
251037Sbill 
267457Skre struct	devhash {
277457Skre 	dev_t	dev_dev;
287457Skre 	char	dev_name [fldsiz(utmp, ut_line) + 1];
297457Skre 	struct	devhash * dev_nxt;
30*11839Ssam };
31*11839Ssam struct	devhash *dev_hash[N_DEVS];
32*11839Ssam struct	devhash *dev_chain ;
33*11839Ssam #define HASH(d)	(((int) d) % N_DEVS)
341037Sbill 
351037Sbill time_t	expand ();
36*11839Ssam char	*flagbits();
37*11839Ssam char	*ttyname();
381037Sbill 
39*11839Ssam struct	passwd *passwd, *getpwent ();
401037Sbill struct stat stat_buff;
411037Sbill 
42*11839Ssam main(argc, argv)
43*11839Ssam 	char *argv[];
441037Sbill {
45*11839Ssam 	char acct_desc, *p;
46*11839Ssam 	long i, j, i_block, n_blocks, n_byte, n_entry, x;
47*11839Ssam 	register struct acct *acp;
481037Sbill 
49*11839Ssam 	/*
50*11839Ssam 	 * Set up user names
51*11839Ssam 	 */
52*11839Ssam 	while (passwd = getpwent())
53*11839Ssam 		if (user_list[passwd->pw_uid][0] == 0)
54*11839Ssam 			strcpy(user_list[passwd->pw_uid], passwd->pw_name);
55*11839Ssam 	/*
56*11839Ssam 	 * Find dev numbers corresponding to names in /dev
57*11839Ssam 	 */
587457Skre 	setupdevs();
59*11839Ssam 	acct_desc = open("/usr/adm/acct", 0);
60*11839Ssam 	if (acct_desc < 0) {
61*11839Ssam 		perror("/usr/adm/acct");
62*11839Ssam 		exit(1);
631037Sbill 	}
64*11839Ssam 	fstat(acct_desc, &stat_buff);
651037Sbill 	n_blocks = (stat_buff.st_size + BUFSIZ - 1) / BUFSIZ;
661037Sbill 
671037Sbill 	/*
68*11839Ssam 	 * Read one block's worth
691037Sbill 	 */
70*11839Ssam 	for (i_block = n_blocks - 1; i_block >= 0; i_block--) {
71*11839Ssam 		lseek(acct_desc, i_block * BUFSIZ, 0);
72*11839Ssam 		n_byte = read(acct_desc, acct_buff, BUFSIZ);
73*11839Ssam 		n_entry = n_byte / sizeof acct_buff[0];
74*11839Ssam 		for (acp = acct_buff + n_entry - 1; acp >= acct_buff; acp--) {
75*11839Ssam 			if (*user_list[acp->ac_uid] == '\0')
767457Skre 				continue;
77*11839Ssam 			x = expand(acp->ac_utime) + expand(acp->ac_stime);
78*11839Ssam 			acp->ac_comm[10] = '\0';
79*11839Ssam 			if (*acp->ac_comm == '\0')
80*11839Ssam 				strcpy(acp->ac_comm, "?");
81*11839Ssam 			for (p = acp->ac_comm; *p; p++)
82*11839Ssam 				if (iscntrl(*p))
837457Skre 					*p = '?';
84*11839Ssam 			if (!ok(argc, argv, acp) && argc != 1)
85*11839Ssam 				continue;
86*11839Ssam 			printf("%-*s %s %-*s %-*s %4d sec%s %.16s\n",
87*11839Ssam 				fldsiz(acct, ac_comm), acp->ac_comm,
88*11839Ssam 				flagbits(acp->ac_flag),
89*11839Ssam 				fldsiz(utmp, ut_name), user_list[acp->ac_uid],
90*11839Ssam 				fldsiz(utmp, ut_line), ttyname(acp->ac_tty),
91*11839Ssam 				x, x > 1 || x == 0 ? "s" : " ",
92*11839Ssam 				ctime(&acp->ac_btime));
931037Sbill 		}
941037Sbill 	}
951037Sbill }
961037Sbill 
971037Sbill time_t
981037Sbill expand (t)
99*11839Ssam 	unsigned t;
1001037Sbill {
1011037Sbill 	register time_t nt;
1021037Sbill 
1031037Sbill 	nt = t & 017777;
1041037Sbill 	t >>= 13;
105*11839Ssam 	while (t) {
1061037Sbill 		t--;
1071037Sbill 		nt <<= 3;
1081037Sbill 	}
1091037Sbill 	return (nt);
1101037Sbill }
1111037Sbill 
1127457Skre char *
1137457Skre flagbits(f)
114*11839Ssam 	register int f;
1151037Sbill {
1167457Skre 	register int i = 0;
1177457Skre 	static char flags[20];
1187457Skre 
119*11839Ssam #define BIT(flag, ch)	flags[i++] = (f & flag) ? ch : ' '
120*11839Ssam 	BIT(ASU, 'S');
121*11839Ssam 	BIT(AFORK, 'F');
122*11839Ssam 	BIT(ACOMPAT, 'C');
123*11839Ssam 	BIT(ACORE, 'D');
124*11839Ssam 	BIT(AXSIG, 'X');
1257457Skre 	flags[i] = '\0';
126*11839Ssam 	return (flags);
1277457Skre }
1287457Skre 
1297457Skre setupdevs()
1307457Skre {
1317457Skre 	register DIR * fd;
1327457Skre 	register struct devhash * hashtab;
1337457Skre 	register ndevs = NDEVS;
1347457Skre 	struct direct * dp;
1357457Skre 
1367457Skre 	if ((fd = opendir("/dev")) == NULL) {
1377457Skre 		perror("/dev");
1387457Skre 		return;
1391037Sbill 	}
1407457Skre 	if ((hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash)))
1417457Skre 	    == (struct devhash *) 0) {
1427457Skre 		fprintf(stderr, "No mem for dev table\n");
1437457Skre 		return;
1447457Skre 	}
1457457Skre 	while (dp = readdir(fd)) {
1467457Skre 		if (dp->d_ino == 0)
1477457Skre 			continue;
1487457Skre #ifdef	MELB
1497457Skre 		if (dp->d_name[0] != 't' && strcmp(dp->d_name, "console"))
1507457Skre 			continue;
1517457Skre #endif
1527457Skre 		strncpy(hashtab->dev_name, dp->d_name, fldsiz(utmp, ut_line));
1537457Skre 		hashtab->dev_name[fldsiz(utmp, ut_line)] = 0;
1547457Skre 		hashtab->dev_nxt = dev_chain;
1557457Skre 		dev_chain = hashtab;
1567457Skre 		hashtab++;
1577457Skre 		if (--ndevs <= 0)
1587457Skre 			break;
1597457Skre 	}
1607457Skre 	closedir(fd);
1611037Sbill }
1627457Skre 
1637457Skre char *
164*11839Ssam ttyname(dev)
165*11839Ssam 	dev_t dev;
1667457Skre {
1677457Skre 	register struct devhash *hp, *nhp;
1687457Skre 	struct stat statb;
169*11839Ssam 	char name[fldsiz(devhash, dev_name) + 6];
1707457Skre 	static dev_t lastdev = (dev_t) -1;
1717457Skre 	static char *lastname;
1727457Skre 
1737457Skre 	if (dev == NODEV)
174*11839Ssam 		return ("__");
1757457Skre 	if (dev == lastdev)
176*11839Ssam 		return (lastname);
1777457Skre 	for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt)
1787457Skre 		if (hp->dev_dev == dev) {
1797457Skre 			lastdev = dev;
180*11839Ssam 			return (lastname = hp->dev_name);
1817457Skre 		}
1827457Skre 	for (hp = dev_chain; hp; hp = nhp) {
1837457Skre 		nhp = hp->dev_nxt;
1847457Skre 		strcpy(name, "/dev/");
1857457Skre 		strcat(name, hp->dev_name);
1867457Skre 		if (stat(name, &statb) < 0)	/* name truncated usually */
1877457Skre 			continue;
1887457Skre 		if ((statb.st_mode & S_IFMT) != S_IFCHR)
1897457Skre 			continue;
1907457Skre 		hp->dev_dev = statb.st_rdev;
1917457Skre 		hp->dev_nxt = dev_hash[HASH(hp->dev_dev)];
1927457Skre 		dev_hash[HASH(hp->dev_dev)] = hp;
1937457Skre 		if (hp->dev_dev == dev) {
1947457Skre 			dev_chain = nhp;
1957457Skre 			lastdev = dev;
196*11839Ssam 			return (lastname = hp->dev_name);
1977457Skre 		}
1987457Skre 	}
1997457Skre 	dev_chain = (struct devhash *) 0;
200*11839Ssam 	return ("??");
2017457Skre }
202*11839Ssam 
203*11839Ssam ok(argc, argv, acp)
204*11839Ssam 	register int argc;
205*11839Ssam 	register char *argv[];
206*11839Ssam 	register struct acct *acp;
207*11839Ssam {
208*11839Ssam 	register int j;
209*11839Ssam 
210*11839Ssam 	for (j = 1; j < argc; j++)
211*11839Ssam 		if (strcmp(user_list[acp->ac_uid], argv[j]) &&
212*11839Ssam 		    strcmp(ttyname(acp->ac_tty), argv[j]) &&
213*11839Ssam 		    strcmp(acp->ac_comm, argv[j]))
214*11839Ssam 			break;
215*11839Ssam 	return (j == argc);
216*11839Ssam }
217