xref: /csrg-svn/usr.bin/lastcomm/lastcomm.c (revision 34033)
121563Sdist /*
221563Sdist  * Copyright (c) 1980 Regents of the University of California.
3*34033Sbostic  * All rights reserved.
4*34033Sbostic  *
5*34033Sbostic  * Redistribution and use in source and binary forms are permitted
6*34033Sbostic  * provided that this notice is preserved and that due credit is given
7*34033Sbostic  * to the University of California at Berkeley. The name of the University
8*34033Sbostic  * may not be used to endorse or promote products derived from this
9*34033Sbostic  * software without specific prior written permission. This software
10*34033Sbostic  * is provided ``as is'' without express or implied warranty.
1121563Sdist  */
1221563Sdist 
1311839Ssam #ifndef lint
1421563Sdist char copyright[] =
1521563Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\
1621563Sdist  All rights reserved.\n";
17*34033Sbostic #endif /* not lint */
181037Sbill 
1921563Sdist #ifndef lint
20*34033Sbostic static char sccsid[] = "@(#)lastcomm.c	5.5 (Berkeley) 04/20/88";
21*34033Sbostic #endif /* not lint */
2221563Sdist 
231037Sbill /*
241037Sbill  * last command
251037Sbill  */
2611839Ssam #include <sys/param.h>
2711839Ssam #include <sys/acct.h>
2813188Ssam #include <sys/file.h>
2913541Ssam #include <sys/stat.h>
3011839Ssam #include <utmp.h>
3111839Ssam #include <struct.h>
3211839Ssam #include <ctype.h>
33*34033Sbostic #include <stdio.h>
341037Sbill 
3513188Ssam struct	acct buf[DEV_BSIZE / sizeof (struct acct)];
361037Sbill 
3713188Ssam time_t	expand();
3811839Ssam char	*flagbits();
3913188Ssam char	*getname();
4013188Ssam char	*getdev();
411037Sbill 
4211839Ssam main(argc, argv)
4333688Sbostic 	int argc;
4411839Ssam 	char *argv[];
451037Sbill {
4633688Sbostic 	extern int optind;
4733688Sbostic 	extern char *optarg;
4833688Sbostic 	register struct acct *acp;
4913188Ssam 	register int bn, cc;
5013188Ssam 	struct stat sb;
5133688Sbostic 	int ch, fd;
5233688Sbostic 	char *acctfile, *strcpy(), *ctime();
5331126Sbostic 	long lseek();
541037Sbill 
5533688Sbostic 	acctfile = NULL;
5633688Sbostic 	while ((ch = getopt(argc, argv, "f:")) != EOF)
5733688Sbostic 		switch((char)ch) {
5833688Sbostic 		case 'f':
5933688Sbostic 			acctfile = optarg;
6033688Sbostic 			break;
6133688Sbostic 		case '?':
6233688Sbostic 		default:
6333688Sbostic 			fputs("lastcomm [ -f file ]\n", stderr);
6433688Sbostic 			exit(1);
6533688Sbostic 		}
6633688Sbostic 	argv += optind;
6733688Sbostic 	if (!acctfile)
6833688Sbostic 		acctfile = "/usr/adm/acct";
6933688Sbostic 	fd = open(acctfile, O_RDONLY);
7013188Ssam 	if (fd < 0) {
7133688Sbostic 		perror(acctfile);
7211839Ssam 		exit(1);
731037Sbill 	}
7433688Sbostic 	(void)fstat(fd, &sb);
7515634Sralph 	for (bn = btodb(sb.st_size); bn >= 0; bn--) {
7631126Sbostic 		(void)lseek(fd, (off_t)dbtob(bn), L_SET);
7713188Ssam 		cc = read(fd, buf, DEV_BSIZE);
7813188Ssam 		if (cc < 0) {
7913188Ssam 			perror("read");
8013188Ssam 			break;
8113188Ssam 		}
8213188Ssam 		acp = buf + (cc / sizeof (buf[0])) - 1;
8313188Ssam 		for (; acp >= buf; acp--) {
8413188Ssam 			register char *cp;
8517764Sralph 			time_t x;
861037Sbill 
8717905Sralph 			if (acp->ac_comm[0] == '\0')
8833688Sbostic 				(void)strcpy(acp->ac_comm, "?");
8917905Sralph 			for (cp = &acp->ac_comm[0];
9017905Sralph 			     cp < &acp->ac_comm[fldsiz(acct, ac_comm)] && *cp;
9117905Sralph 			     cp++)
9217905Sralph 				if (!isascii(*cp) || iscntrl(*cp))
9313188Ssam 					*cp = '?';
9433688Sbostic 			if (*argv && !ok(argv, acp))
9511839Ssam 				continue;
9617764Sralph 			x = expand(acp->ac_utime) + expand(acp->ac_stime);
9727699Slepreau 			printf("%-*.*s %s %-*s %-*s %6.2f secs %.16s\n",
9831126Sbostic 				fldsiz(acct, ac_comm),
9931126Sbostic 				fldsiz(acct, ac_comm),
10031126Sbostic 				acp->ac_comm, flagbits(acp->ac_flag),
10131126Sbostic 				fldsiz(utmp, ut_name),
10231126Sbostic 				(cp = getname(acp->ac_uid)) ? cp : "",
10313188Ssam 				fldsiz(utmp, ut_line), getdev(acp->ac_tty),
10417503Skarels 				x / (double)AHZ, ctime(&acp->ac_btime));
1051037Sbill 		}
1061037Sbill 	}
1071037Sbill }
1081037Sbill 
1091037Sbill time_t
1101037Sbill expand (t)
11111839Ssam 	unsigned t;
1121037Sbill {
1131037Sbill 	register time_t nt;
1141037Sbill 
1151037Sbill 	nt = t & 017777;
1161037Sbill 	t >>= 13;
11711839Ssam 	while (t) {
1181037Sbill 		t--;
1191037Sbill 		nt <<= 3;
1201037Sbill 	}
1211037Sbill 	return (nt);
1221037Sbill }
1231037Sbill 
1247457Skre char *
1257457Skre flagbits(f)
12611839Ssam 	register int f;
1271037Sbill {
1287457Skre 	static char flags[20];
129*34033Sbostic 	char *p, *strcpy();
1307457Skre 
131*34033Sbostic #define	BIT(flag, ch)	if (f & flag) *p++ = ch;
132*34033Sbostic 	p = strcpy(flags, "-    ");
13311839Ssam 	BIT(ASU, 'S');
13411839Ssam 	BIT(AFORK, 'F');
13511839Ssam 	BIT(ACOMPAT, 'C');
13611839Ssam 	BIT(ACORE, 'D');
13711839Ssam 	BIT(AXSIG, 'X');
13811839Ssam 	return (flags);
1397457Skre }
1407457Skre 
14133688Sbostic ok(argv, acp)
14213188Ssam 	register char *argv[];
14313188Ssam 	register struct acct *acp;
14413188Ssam {
14531126Sbostic 	register char *cp;
14613188Ssam 
14733688Sbostic 	do {
14833688Sbostic 		if ((cp = getname(acp->ac_uid)) && !strcmp(cp, *argv) ||
14933688Sbostic 		    (cp = getdev(acp->ac_tty)) && !strcmp(cp, *argv) ||
15033688Sbostic 		    !strncmp(acp->ac_comm, *argv, fldsiz(acct, ac_comm)))
15133688Sbostic 			return(1);
15233688Sbostic 	} while (*++argv);
15333688Sbostic 	return(0);
15413188Ssam }
15513188Ssam 
15613188Ssam /* should be done with nameserver or database */
15713188Ssam 
158*34033Sbostic #include <pwd.h>
159*34033Sbostic 
16013188Ssam struct	utmp utmp;
16113188Ssam #define	NMAX	(sizeof (utmp.ut_name))
162*34033Sbostic #define SCPYN(a, b)	strncpy(a, b, NMAX)
16313188Ssam 
164*34033Sbostic #define NCACHE	64		/* power of 2 */
165*34033Sbostic #define CAMASK	NCACHE - 1
16613188Ssam 
16713188Ssam char *
16813188Ssam getname(uid)
16931126Sbostic 	uid_t uid;
17013188Ssam {
171*34033Sbostic 	extern int _pw_stayopen;
172*34033Sbostic 	static struct ncache {
173*34033Sbostic 		uid_t	uid;
174*34033Sbostic 		char	name[NMAX+1];
175*34033Sbostic 	} c_uid[NCACHE];
17613188Ssam 	register struct passwd *pw;
177*34033Sbostic 	register struct ncache *cp;
17813188Ssam 
179*34033Sbostic 	_pw_stayopen = 1;
180*34033Sbostic 	cp = c_uid + (uid & CAMASK);
181*34033Sbostic 	if (cp->uid == uid && *cp->name)
182*34033Sbostic 		return(cp->name);
183*34033Sbostic 	if (!(pw = getpwuid(uid)))
184*34033Sbostic 		return((char *)0);
185*34033Sbostic 	cp->uid = uid;
186*34033Sbostic 	SCPYN(cp->name, pw->pw_name);
187*34033Sbostic 	return(cp->name);
18813188Ssam }
18913188Ssam 
19013188Ssam #include <sys/dir.h>
19113188Ssam 
19213188Ssam #define N_DEVS		43		/* hash value for device names */
19313188Ssam #define NDEVS		500		/* max number of file names in /dev */
19413188Ssam 
19513188Ssam struct	devhash {
19613188Ssam 	dev_t	dev_dev;
19713188Ssam 	char	dev_name [fldsiz(utmp, ut_line) + 1];
19813188Ssam 	struct	devhash * dev_nxt;
19913188Ssam };
20013188Ssam struct	devhash *dev_hash[N_DEVS];
20113188Ssam struct	devhash *dev_chain;
20213188Ssam #define HASH(d)	(((int) d) % N_DEVS)
20313188Ssam 
2047457Skre setupdevs()
2057457Skre {
2067457Skre 	register DIR * fd;
2077457Skre 	register struct devhash * hashtab;
2087457Skre 	register ndevs = NDEVS;
2097457Skre 	struct direct * dp;
21031126Sbostic 	char *malloc();
2117457Skre 
21231126Sbostic 	/*NOSTRICT*/
21331126Sbostic 	hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash));
21431126Sbostic 	if (hashtab == (struct devhash *)0) {
21531126Sbostic 		fputs("No mem for dev table\n", stderr);
21631126Sbostic 		return;
21731126Sbostic 	}
2187457Skre 	if ((fd = opendir("/dev")) == NULL) {
2197457Skre 		perror("/dev");
2207457Skre 		return;
2211037Sbill 	}
2227457Skre 	while (dp = readdir(fd)) {
2237457Skre 		if (dp->d_ino == 0)
2247457Skre 			continue;
2257457Skre 		if (dp->d_name[0] != 't' && strcmp(dp->d_name, "console"))
2267457Skre 			continue;
2277457Skre 		strncpy(hashtab->dev_name, dp->d_name, fldsiz(utmp, ut_line));
2287457Skre 		hashtab->dev_name[fldsiz(utmp, ut_line)] = 0;
2297457Skre 		hashtab->dev_nxt = dev_chain;
2307457Skre 		dev_chain = hashtab;
2317457Skre 		hashtab++;
2327457Skre 		if (--ndevs <= 0)
2337457Skre 			break;
2347457Skre 	}
2357457Skre 	closedir(fd);
2361037Sbill }
2377457Skre 
2387457Skre char *
23913188Ssam getdev(dev)
24011839Ssam 	dev_t dev;
2417457Skre {
2427457Skre 	register struct devhash *hp, *nhp;
2437457Skre 	struct stat statb;
24411839Ssam 	char name[fldsiz(devhash, dev_name) + 6];
2457457Skre 	static dev_t lastdev = (dev_t) -1;
2467457Skre 	static char *lastname;
24714925Sralph 	static int init = 0;
24831126Sbostic 	char *strcpy(), *strcat();
2497457Skre 
2507457Skre 	if (dev == NODEV)
25111839Ssam 		return ("__");
2527457Skre 	if (dev == lastdev)
25311839Ssam 		return (lastname);
25413188Ssam 	if (!init) {
25513188Ssam 		setupdevs();
25613188Ssam 		init++;
25713188Ssam 	}
2587457Skre 	for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt)
2597457Skre 		if (hp->dev_dev == dev) {
2607457Skre 			lastdev = dev;
26111839Ssam 			return (lastname = hp->dev_name);
2627457Skre 		}
2637457Skre 	for (hp = dev_chain; hp; hp = nhp) {
2647457Skre 		nhp = hp->dev_nxt;
2657457Skre 		strcpy(name, "/dev/");
2667457Skre 		strcat(name, hp->dev_name);
2677457Skre 		if (stat(name, &statb) < 0)	/* name truncated usually */
2687457Skre 			continue;
2697457Skre 		if ((statb.st_mode & S_IFMT) != S_IFCHR)
2707457Skre 			continue;
2717457Skre 		hp->dev_dev = statb.st_rdev;
2727457Skre 		hp->dev_nxt = dev_hash[HASH(hp->dev_dev)];
2737457Skre 		dev_hash[HASH(hp->dev_dev)] = hp;
2747457Skre 		if (hp->dev_dev == dev) {
2757457Skre 			dev_chain = nhp;
2767457Skre 			lastdev = dev;
27711839Ssam 			return (lastname = hp->dev_name);
2787457Skre 		}
2797457Skre 	}
2807457Skre 	dev_chain = (struct devhash *) 0;
28111839Ssam 	return ("??");
2827457Skre }
283