xref: /csrg-svn/usr.bin/lastcomm/lastcomm.c (revision 33688)
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*33688Sbostic static char sccsid[] = "@(#)lastcomm.c	5.4 (Berkeley) 03/08/88";
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)
39*33688Sbostic 	int argc;
4011839Ssam 	char *argv[];
411037Sbill {
42*33688Sbostic 	extern int optind;
43*33688Sbostic 	extern char *optarg;
44*33688Sbostic 	register struct acct *acp;
4513188Ssam 	register int bn, cc;
4613188Ssam 	struct stat sb;
47*33688Sbostic 	int ch, fd;
48*33688Sbostic 	char *acctfile, *strcpy(), *ctime();
4931126Sbostic 	long lseek();
501037Sbill 
51*33688Sbostic 	acctfile = NULL;
52*33688Sbostic 	while ((ch = getopt(argc, argv, "f:")) != EOF)
53*33688Sbostic 		switch((char)ch) {
54*33688Sbostic 		case 'f':
55*33688Sbostic 			acctfile = optarg;
56*33688Sbostic 			break;
57*33688Sbostic 		case '?':
58*33688Sbostic 		default:
59*33688Sbostic 			fputs("lastcomm [ -f file ]\n", stderr);
60*33688Sbostic 			exit(1);
61*33688Sbostic 		}
62*33688Sbostic 	argv += optind;
63*33688Sbostic 	if (!acctfile)
64*33688Sbostic 		acctfile = "/usr/adm/acct";
65*33688Sbostic 	fd = open(acctfile, O_RDONLY);
6613188Ssam 	if (fd < 0) {
67*33688Sbostic 		perror(acctfile);
6811839Ssam 		exit(1);
691037Sbill 	}
70*33688Sbostic 	(void)fstat(fd, &sb);
7115634Sralph 	for (bn = btodb(sb.st_size); bn >= 0; bn--) {
7231126Sbostic 		(void)lseek(fd, (off_t)dbtob(bn), L_SET);
7313188Ssam 		cc = read(fd, buf, DEV_BSIZE);
7413188Ssam 		if (cc < 0) {
7513188Ssam 			perror("read");
7613188Ssam 			break;
7713188Ssam 		}
7813188Ssam 		acp = buf + (cc / sizeof (buf[0])) - 1;
7913188Ssam 		for (; acp >= buf; acp--) {
8013188Ssam 			register char *cp;
8117764Sralph 			time_t x;
821037Sbill 
8317905Sralph 			if (acp->ac_comm[0] == '\0')
84*33688Sbostic 				(void)strcpy(acp->ac_comm, "?");
8517905Sralph 			for (cp = &acp->ac_comm[0];
8617905Sralph 			     cp < &acp->ac_comm[fldsiz(acct, ac_comm)] && *cp;
8717905Sralph 			     cp++)
8817905Sralph 				if (!isascii(*cp) || iscntrl(*cp))
8913188Ssam 					*cp = '?';
90*33688Sbostic 			if (*argv && !ok(argv, acp))
9111839Ssam 				continue;
9217764Sralph 			x = expand(acp->ac_utime) + expand(acp->ac_stime);
9327699Slepreau 			printf("%-*.*s %s %-*s %-*s %6.2f secs %.16s\n",
9431126Sbostic 				fldsiz(acct, ac_comm),
9531126Sbostic 				fldsiz(acct, ac_comm),
9631126Sbostic 				acp->ac_comm, flagbits(acp->ac_flag),
9731126Sbostic 				fldsiz(utmp, ut_name),
9831126Sbostic 				(cp = getname(acp->ac_uid)) ? cp : "",
9913188Ssam 				fldsiz(utmp, ut_line), getdev(acp->ac_tty),
10017503Skarels 				x / (double)AHZ, ctime(&acp->ac_btime));
1011037Sbill 		}
1021037Sbill 	}
1031037Sbill }
1041037Sbill 
1051037Sbill time_t
1061037Sbill expand (t)
10711839Ssam 	unsigned t;
1081037Sbill {
1091037Sbill 	register time_t nt;
1101037Sbill 
1111037Sbill 	nt = t & 017777;
1121037Sbill 	t >>= 13;
11311839Ssam 	while (t) {
1141037Sbill 		t--;
1151037Sbill 		nt <<= 3;
1161037Sbill 	}
1171037Sbill 	return (nt);
1181037Sbill }
1191037Sbill 
1207457Skre char *
1217457Skre flagbits(f)
12211839Ssam 	register int f;
1231037Sbill {
1247457Skre 	register int i = 0;
1257457Skre 	static char flags[20];
1267457Skre 
12711839Ssam #define BIT(flag, ch)	flags[i++] = (f & flag) ? ch : ' '
12811839Ssam 	BIT(ASU, 'S');
12911839Ssam 	BIT(AFORK, 'F');
13011839Ssam 	BIT(ACOMPAT, 'C');
13111839Ssam 	BIT(ACORE, 'D');
13211839Ssam 	BIT(AXSIG, 'X');
1337457Skre 	flags[i] = '\0';
13411839Ssam 	return (flags);
1357457Skre }
1367457Skre 
137*33688Sbostic ok(argv, acp)
13813188Ssam 	register char *argv[];
13913188Ssam 	register struct acct *acp;
14013188Ssam {
14131126Sbostic 	register char *cp;
14213188Ssam 
143*33688Sbostic 	do {
144*33688Sbostic 		if ((cp = getname(acp->ac_uid)) && !strcmp(cp, *argv) ||
145*33688Sbostic 		    (cp = getdev(acp->ac_tty)) && !strcmp(cp, *argv) ||
146*33688Sbostic 		    !strncmp(acp->ac_comm, *argv, fldsiz(acct, ac_comm)))
147*33688Sbostic 			return(1);
148*33688Sbostic 	} while (*++argv);
149*33688Sbostic 	return(0);
15013188Ssam }
15113188Ssam 
15213188Ssam /* should be done with nameserver or database */
15313188Ssam 
15413188Ssam struct	utmp utmp;
15513188Ssam 
15613188Ssam #define NUID	2048
15713188Ssam #define	NMAX	(sizeof (utmp.ut_name))
15813188Ssam 
15913188Ssam char	names[NUID][NMAX+1];
16013188Ssam char	outrangename[NMAX+1];
16113188Ssam int	outrangeuid = -1;
16213188Ssam 
16313188Ssam char *
16413188Ssam getname(uid)
16531126Sbostic 	uid_t uid;
16613188Ssam {
16713188Ssam 	register struct passwd *pw;
16813188Ssam 	static init;
16913188Ssam 	struct passwd *getpwent();
17013188Ssam 
17131126Sbostic 	if (uid < NUID && names[uid][0])
17213188Ssam 		return (&names[uid][0]);
17331126Sbostic 	if (uid == outrangeuid)
17413188Ssam 		return (outrangename);
17513188Ssam 	if (init == 2) {
17613188Ssam 		if (uid < NUID)
17713188Ssam 			return (0);
17813188Ssam 		setpwent();
17913188Ssam 		while (pw = getpwent()) {
18013188Ssam 			if (pw->pw_uid != uid)
18113188Ssam 				continue;
18213188Ssam 			outrangeuid = pw->pw_uid;
18314768Ssam 			strncpy(outrangename, pw->pw_name, NMAX);
18413188Ssam 			endpwent();
18513188Ssam 			return (outrangename);
18613188Ssam 		}
18713188Ssam 		endpwent();
18813188Ssam 		return (0);
18913188Ssam 	}
19013188Ssam 	if (init == 0)
19113188Ssam 		setpwent(), init = 1;
19213188Ssam 	while (pw = getpwent()) {
19313188Ssam 		if (pw->pw_uid < 0 || pw->pw_uid >= NUID) {
19413188Ssam 			if (pw->pw_uid == uid) {
19513188Ssam 				outrangeuid = pw->pw_uid;
19614768Ssam 				strncpy(outrangename, pw->pw_name, NMAX);
19713188Ssam 				return (outrangename);
19813188Ssam 			}
19913188Ssam 			continue;
20013188Ssam 		}
20113188Ssam 		if (names[pw->pw_uid][0])
20213188Ssam 			continue;
20313188Ssam 		strncpy(names[pw->pw_uid], pw->pw_name, NMAX);
20413188Ssam 		if (pw->pw_uid == uid)
20513188Ssam 			return (&names[uid][0]);
20613188Ssam 	}
20713188Ssam 	init = 2;
20813188Ssam 	endpwent();
20913188Ssam 	return (0);
21013188Ssam }
21113188Ssam 
21213188Ssam #include <sys/dir.h>
21313188Ssam 
21413188Ssam #define N_DEVS		43		/* hash value for device names */
21513188Ssam #define NDEVS		500		/* max number of file names in /dev */
21613188Ssam 
21713188Ssam struct	devhash {
21813188Ssam 	dev_t	dev_dev;
21913188Ssam 	char	dev_name [fldsiz(utmp, ut_line) + 1];
22013188Ssam 	struct	devhash * dev_nxt;
22113188Ssam };
22213188Ssam struct	devhash *dev_hash[N_DEVS];
22313188Ssam struct	devhash *dev_chain;
22413188Ssam #define HASH(d)	(((int) d) % N_DEVS)
22513188Ssam 
2267457Skre setupdevs()
2277457Skre {
2287457Skre 	register DIR * fd;
2297457Skre 	register struct devhash * hashtab;
2307457Skre 	register ndevs = NDEVS;
2317457Skre 	struct direct * dp;
23231126Sbostic 	char *malloc();
2337457Skre 
23431126Sbostic 	/*NOSTRICT*/
23531126Sbostic 	hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash));
23631126Sbostic 	if (hashtab == (struct devhash *)0) {
23731126Sbostic 		fputs("No mem for dev table\n", stderr);
23831126Sbostic 		return;
23931126Sbostic 	}
2407457Skre 	if ((fd = opendir("/dev")) == NULL) {
2417457Skre 		perror("/dev");
2427457Skre 		return;
2431037Sbill 	}
2447457Skre 	while (dp = readdir(fd)) {
2457457Skre 		if (dp->d_ino == 0)
2467457Skre 			continue;
2477457Skre 		if (dp->d_name[0] != 't' && strcmp(dp->d_name, "console"))
2487457Skre 			continue;
2497457Skre 		strncpy(hashtab->dev_name, dp->d_name, fldsiz(utmp, ut_line));
2507457Skre 		hashtab->dev_name[fldsiz(utmp, ut_line)] = 0;
2517457Skre 		hashtab->dev_nxt = dev_chain;
2527457Skre 		dev_chain = hashtab;
2537457Skre 		hashtab++;
2547457Skre 		if (--ndevs <= 0)
2557457Skre 			break;
2567457Skre 	}
2577457Skre 	closedir(fd);
2581037Sbill }
2597457Skre 
2607457Skre char *
26113188Ssam getdev(dev)
26211839Ssam 	dev_t dev;
2637457Skre {
2647457Skre 	register struct devhash *hp, *nhp;
2657457Skre 	struct stat statb;
26611839Ssam 	char name[fldsiz(devhash, dev_name) + 6];
2677457Skre 	static dev_t lastdev = (dev_t) -1;
2687457Skre 	static char *lastname;
26914925Sralph 	static int init = 0;
27031126Sbostic 	char *strcpy(), *strcat();
2717457Skre 
2727457Skre 	if (dev == NODEV)
27311839Ssam 		return ("__");
2747457Skre 	if (dev == lastdev)
27511839Ssam 		return (lastname);
27613188Ssam 	if (!init) {
27713188Ssam 		setupdevs();
27813188Ssam 		init++;
27913188Ssam 	}
2807457Skre 	for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt)
2817457Skre 		if (hp->dev_dev == dev) {
2827457Skre 			lastdev = dev;
28311839Ssam 			return (lastname = hp->dev_name);
2847457Skre 		}
2857457Skre 	for (hp = dev_chain; hp; hp = nhp) {
2867457Skre 		nhp = hp->dev_nxt;
2877457Skre 		strcpy(name, "/dev/");
2887457Skre 		strcat(name, hp->dev_name);
2897457Skre 		if (stat(name, &statb) < 0)	/* name truncated usually */
2907457Skre 			continue;
2917457Skre 		if ((statb.st_mode & S_IFMT) != S_IFCHR)
2927457Skre 			continue;
2937457Skre 		hp->dev_dev = statb.st_rdev;
2947457Skre 		hp->dev_nxt = dev_hash[HASH(hp->dev_dev)];
2957457Skre 		dev_hash[HASH(hp->dev_dev)] = hp;
2967457Skre 		if (hp->dev_dev == dev) {
2977457Skre 			dev_chain = nhp;
2987457Skre 			lastdev = dev;
29911839Ssam 			return (lastname = hp->dev_name);
3007457Skre 		}
3017457Skre 	}
3027457Skre 	dev_chain = (struct devhash *) 0;
30311839Ssam 	return ("??");
3047457Skre }
305