xref: /csrg-svn/usr.bin/lastcomm/lastcomm.c (revision 31126)
121563Sdist /*
221563Sdist  * Copyright (c) 1980 Regents of the University of California.
321563Sdist  * All rights reserved.  The Berkeley software License Agreement
421563Sdist  * specifies the terms and conditions for redistribution.
521563Sdist  */
621563Sdist 
711839Ssam #ifndef lint
821563Sdist char copyright[] =
921563Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\
1021563Sdist  All rights reserved.\n";
1121563Sdist #endif not lint
121037Sbill 
1321563Sdist #ifndef lint
14*31126Sbostic static char sccsid[] = "@(#)lastcomm.c	5.3 (Berkeley) 05/15/87";
1521563Sdist #endif not lint
1621563Sdist 
171037Sbill /*
181037Sbill  * last command
191037Sbill  */
2011839Ssam #include <sys/param.h>
2111839Ssam #include <sys/acct.h>
2213188Ssam #include <sys/file.h>
2313188Ssam 
2413188Ssam #include <stdio.h>
2511839Ssam #include <pwd.h>
2613541Ssam #include <sys/stat.h>
2711839Ssam #include <utmp.h>
2811839Ssam #include <struct.h>
2911839Ssam #include <ctype.h>
301037Sbill 
3113188Ssam struct	acct buf[DEV_BSIZE / sizeof (struct acct)];
321037Sbill 
3313188Ssam time_t	expand();
3411839Ssam char	*flagbits();
3513188Ssam char	*getname();
3613188Ssam char	*getdev();
371037Sbill 
3811839Ssam main(argc, argv)
3911839Ssam 	char *argv[];
401037Sbill {
4113188Ssam 	register int bn, cc;
4211839Ssam 	register struct acct *acp;
4313188Ssam 	int fd;
4413188Ssam 	struct stat sb;
45*31126Sbostic 	long lseek();
46*31126Sbostic 	char *strcpy(), *ctime();
471037Sbill 
4813188Ssam 	fd = open("/usr/adm/acct", O_RDONLY);
4913188Ssam 	if (fd < 0) {
5011839Ssam 		perror("/usr/adm/acct");
5111839Ssam 		exit(1);
521037Sbill 	}
5313188Ssam 	fstat(fd, &sb);
5415634Sralph 	for (bn = btodb(sb.st_size); bn >= 0; bn--) {
55*31126Sbostic 		(void)lseek(fd, (off_t)dbtob(bn), L_SET);
5613188Ssam 		cc = read(fd, buf, DEV_BSIZE);
5713188Ssam 		if (cc < 0) {
5813188Ssam 			perror("read");
5913188Ssam 			break;
6013188Ssam 		}
6113188Ssam 		acp = buf + (cc / sizeof (buf[0])) - 1;
6213188Ssam 		for (; acp >= buf; acp--) {
6313188Ssam 			register char *cp;
6417764Sralph 			time_t x;
651037Sbill 
6617905Sralph 			if (acp->ac_comm[0] == '\0')
6711839Ssam 				strcpy(acp->ac_comm, "?");
6817905Sralph 			for (cp = &acp->ac_comm[0];
6917905Sralph 			     cp < &acp->ac_comm[fldsiz(acct, ac_comm)] && *cp;
7017905Sralph 			     cp++)
7117905Sralph 				if (!isascii(*cp) || iscntrl(*cp))
7213188Ssam 					*cp = '?';
7317764Sralph 			if (argc > 1 && !ok(argc, argv, acp))
7411839Ssam 				continue;
7517764Sralph 			x = expand(acp->ac_utime) + expand(acp->ac_stime);
7627699Slepreau 			printf("%-*.*s %s %-*s %-*s %6.2f secs %.16s\n",
77*31126Sbostic 				fldsiz(acct, ac_comm),
78*31126Sbostic 				fldsiz(acct, ac_comm),
79*31126Sbostic 				acp->ac_comm, flagbits(acp->ac_flag),
80*31126Sbostic 				fldsiz(utmp, ut_name),
81*31126Sbostic 				(cp = getname(acp->ac_uid)) ? cp : "",
8213188Ssam 				fldsiz(utmp, ut_line), getdev(acp->ac_tty),
8317503Skarels 				x / (double)AHZ, ctime(&acp->ac_btime));
841037Sbill 		}
851037Sbill 	}
861037Sbill }
871037Sbill 
881037Sbill time_t
891037Sbill expand (t)
9011839Ssam 	unsigned t;
911037Sbill {
921037Sbill 	register time_t nt;
931037Sbill 
941037Sbill 	nt = t & 017777;
951037Sbill 	t >>= 13;
9611839Ssam 	while (t) {
971037Sbill 		t--;
981037Sbill 		nt <<= 3;
991037Sbill 	}
1001037Sbill 	return (nt);
1011037Sbill }
1021037Sbill 
1037457Skre char *
1047457Skre flagbits(f)
10511839Ssam 	register int f;
1061037Sbill {
1077457Skre 	register int i = 0;
1087457Skre 	static char flags[20];
1097457Skre 
11011839Ssam #define BIT(flag, ch)	flags[i++] = (f & flag) ? ch : ' '
11111839Ssam 	BIT(ASU, 'S');
11211839Ssam 	BIT(AFORK, 'F');
11311839Ssam 	BIT(ACOMPAT, 'C');
11411839Ssam 	BIT(ACORE, 'D');
11511839Ssam 	BIT(AXSIG, 'X');
1167457Skre 	flags[i] = '\0';
11711839Ssam 	return (flags);
1187457Skre }
1197457Skre 
12013188Ssam ok(argc, argv, acp)
12113188Ssam 	register int argc;
12213188Ssam 	register char *argv[];
12313188Ssam 	register struct acct *acp;
12413188Ssam {
12513188Ssam 	register int j;
126*31126Sbostic 	register char *cp;
12713188Ssam 
12813188Ssam 	for (j = 1; j < argc; j++)
129*31126Sbostic 		if ((!(cp = getname(acp->ac_uid)) || strcmp(cp, argv[j])) &&
130*31126Sbostic 		    (!(cp = getdev(acp->ac_tty)) || strcmp(cp, argv[j])) &&
13117905Sralph 		    strncmp(acp->ac_comm, argv[j], fldsiz(acct, ac_comm)))
13213188Ssam 			break;
13313188Ssam 	return (j == argc);
13413188Ssam }
13513188Ssam 
13613188Ssam /* should be done with nameserver or database */
13713188Ssam 
13813188Ssam struct	utmp utmp;
13913188Ssam 
14013188Ssam #define NUID	2048
14113188Ssam #define	NMAX	(sizeof (utmp.ut_name))
14213188Ssam 
14313188Ssam char	names[NUID][NMAX+1];
14413188Ssam char	outrangename[NMAX+1];
14513188Ssam int	outrangeuid = -1;
14613188Ssam 
14713188Ssam char *
14813188Ssam getname(uid)
149*31126Sbostic 	uid_t uid;
15013188Ssam {
15113188Ssam 	register struct passwd *pw;
15213188Ssam 	static init;
15313188Ssam 	struct passwd *getpwent();
15413188Ssam 
155*31126Sbostic 	if (uid < NUID && names[uid][0])
15613188Ssam 		return (&names[uid][0]);
157*31126Sbostic 	if (uid == outrangeuid)
15813188Ssam 		return (outrangename);
15913188Ssam 	if (init == 2) {
16013188Ssam 		if (uid < NUID)
16113188Ssam 			return (0);
16213188Ssam 		setpwent();
16313188Ssam 		while (pw = getpwent()) {
16413188Ssam 			if (pw->pw_uid != uid)
16513188Ssam 				continue;
16613188Ssam 			outrangeuid = pw->pw_uid;
16714768Ssam 			strncpy(outrangename, pw->pw_name, NMAX);
16813188Ssam 			endpwent();
16913188Ssam 			return (outrangename);
17013188Ssam 		}
17113188Ssam 		endpwent();
17213188Ssam 		return (0);
17313188Ssam 	}
17413188Ssam 	if (init == 0)
17513188Ssam 		setpwent(), init = 1;
17613188Ssam 	while (pw = getpwent()) {
17713188Ssam 		if (pw->pw_uid < 0 || pw->pw_uid >= NUID) {
17813188Ssam 			if (pw->pw_uid == uid) {
17913188Ssam 				outrangeuid = pw->pw_uid;
18014768Ssam 				strncpy(outrangename, pw->pw_name, NMAX);
18113188Ssam 				return (outrangename);
18213188Ssam 			}
18313188Ssam 			continue;
18413188Ssam 		}
18513188Ssam 		if (names[pw->pw_uid][0])
18613188Ssam 			continue;
18713188Ssam 		strncpy(names[pw->pw_uid], pw->pw_name, NMAX);
18813188Ssam 		if (pw->pw_uid == uid)
18913188Ssam 			return (&names[uid][0]);
19013188Ssam 	}
19113188Ssam 	init = 2;
19213188Ssam 	endpwent();
19313188Ssam 	return (0);
19413188Ssam }
19513188Ssam 
19613188Ssam #include <sys/dir.h>
19713188Ssam 
19813188Ssam #define N_DEVS		43		/* hash value for device names */
19913188Ssam #define NDEVS		500		/* max number of file names in /dev */
20013188Ssam 
20113188Ssam struct	devhash {
20213188Ssam 	dev_t	dev_dev;
20313188Ssam 	char	dev_name [fldsiz(utmp, ut_line) + 1];
20413188Ssam 	struct	devhash * dev_nxt;
20513188Ssam };
20613188Ssam struct	devhash *dev_hash[N_DEVS];
20713188Ssam struct	devhash *dev_chain;
20813188Ssam #define HASH(d)	(((int) d) % N_DEVS)
20913188Ssam 
2107457Skre setupdevs()
2117457Skre {
2127457Skre 	register DIR * fd;
2137457Skre 	register struct devhash * hashtab;
2147457Skre 	register ndevs = NDEVS;
2157457Skre 	struct direct * dp;
216*31126Sbostic 	char *malloc();
2177457Skre 
218*31126Sbostic 	/*NOSTRICT*/
219*31126Sbostic 	hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash));
220*31126Sbostic 	if (hashtab == (struct devhash *)0) {
221*31126Sbostic 		fputs("No mem for dev table\n", stderr);
222*31126Sbostic 		return;
223*31126Sbostic 	}
2247457Skre 	if ((fd = opendir("/dev")) == NULL) {
2257457Skre 		perror("/dev");
2267457Skre 		return;
2271037Sbill 	}
2287457Skre 	while (dp = readdir(fd)) {
2297457Skre 		if (dp->d_ino == 0)
2307457Skre 			continue;
2317457Skre 		if (dp->d_name[0] != 't' && strcmp(dp->d_name, "console"))
2327457Skre 			continue;
2337457Skre 		strncpy(hashtab->dev_name, dp->d_name, fldsiz(utmp, ut_line));
2347457Skre 		hashtab->dev_name[fldsiz(utmp, ut_line)] = 0;
2357457Skre 		hashtab->dev_nxt = dev_chain;
2367457Skre 		dev_chain = hashtab;
2377457Skre 		hashtab++;
2387457Skre 		if (--ndevs <= 0)
2397457Skre 			break;
2407457Skre 	}
2417457Skre 	closedir(fd);
2421037Sbill }
2437457Skre 
2447457Skre char *
24513188Ssam getdev(dev)
24611839Ssam 	dev_t dev;
2477457Skre {
2487457Skre 	register struct devhash *hp, *nhp;
2497457Skre 	struct stat statb;
25011839Ssam 	char name[fldsiz(devhash, dev_name) + 6];
2517457Skre 	static dev_t lastdev = (dev_t) -1;
2527457Skre 	static char *lastname;
25314925Sralph 	static int init = 0;
254*31126Sbostic 	char *strcpy(), *strcat();
2557457Skre 
2567457Skre 	if (dev == NODEV)
25711839Ssam 		return ("__");
2587457Skre 	if (dev == lastdev)
25911839Ssam 		return (lastname);
26013188Ssam 	if (!init) {
26113188Ssam 		setupdevs();
26213188Ssam 		init++;
26313188Ssam 	}
2647457Skre 	for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt)
2657457Skre 		if (hp->dev_dev == dev) {
2667457Skre 			lastdev = dev;
26711839Ssam 			return (lastname = hp->dev_name);
2687457Skre 		}
2697457Skre 	for (hp = dev_chain; hp; hp = nhp) {
2707457Skre 		nhp = hp->dev_nxt;
2717457Skre 		strcpy(name, "/dev/");
2727457Skre 		strcat(name, hp->dev_name);
2737457Skre 		if (stat(name, &statb) < 0)	/* name truncated usually */
2747457Skre 			continue;
2757457Skre 		if ((statb.st_mode & S_IFMT) != S_IFCHR)
2767457Skre 			continue;
2777457Skre 		hp->dev_dev = statb.st_rdev;
2787457Skre 		hp->dev_nxt = dev_hash[HASH(hp->dev_dev)];
2797457Skre 		dev_hash[HASH(hp->dev_dev)] = hp;
2807457Skre 		if (hp->dev_dev == dev) {
2817457Skre 			dev_chain = nhp;
2827457Skre 			lastdev = dev;
28311839Ssam 			return (lastname = hp->dev_name);
2847457Skre 		}
2857457Skre 	}
2867457Skre 	dev_chain = (struct devhash *) 0;
28711839Ssam 	return ("??");
2887457Skre }
289