4.1cBSD/usr/src/ucb/lastcomm.c

Compare this file to the similar file:
Show the results in this format:

static char *sccsid = "@(#)lastcomm.c	4.4 (Berkeley) 82/07/17";

/*
 * last command
 */

# include <stdio.h>
# include <sys/param.h>
# include <sys/acct.h>
# include <sys/dir.h>
# include <signal.h>
# include <pwd.h>
# include <stat.h>
# include <utmp.h>
# include <struct.h>

# define N_USER		4000		/* highest alloc user # */
# define N_DEVS		43		/* hash value for device names */
# define NDEVS		500		/* max number of file names in /dev */

struct acct	acct_buff [BUFSIZ / sizeof (struct acct)];

char	user_list [N_USER][fldsiz(utmp, ut_name) + 1];

struct	devhash {
	dev_t	dev_dev;
	char	dev_name [fldsiz(utmp, ut_line) + 1];
	struct	devhash * dev_nxt;
}
	* dev_hash [ N_DEVS ],
	* dev_chain ;
# define HASH(d)	(((int) d) % N_DEVS)

time_t	expand ();
char	* flagbits();
char	* tername();

struct passwd
	*passwd,
	*getpwent ();

struct stat stat_buff;

# define equal(a, b)		(strcmp(a, b) == 0)

main (argc, argv)
char **argv;
{
	char	acct_desc,
		*p;

	long	i,
		j,
		i_block,
		n_blocks,
		n_byte,
		n_entry;

	float	x;

/*
 * set up user names
 */
	while (passwd = getpwent ())
	{
		if (user_list[passwd->pw_uid][0]==0)
			move (passwd->pw_name, user_list [passwd->pw_uid]);
	}

 /*
  * find dev numbers corresponding to names in /dev
  */
	setupdevs();

	acct_desc = open ("/usr/adm/acct", 0);
	if (acct_desc < 0)
	{
		perror ("/usr/adm/acct");
		return;
	}
	fstat (acct_desc, &stat_buff);
	n_blocks = (stat_buff.st_size + BUFSIZ - 1) / BUFSIZ;

	/*
	 * read one block's worth
	 */
	for (i_block = n_blocks - 1; i_block >= 0; i_block--)
	{
		lseek (acct_desc, i_block * BUFSIZ, 0);
		n_byte = read (acct_desc, acct_buff, BUFSIZ);
		n_entry = n_byte / sizeof acct_buff [0];
		for (i = n_entry - 1; i >= 0; i--)
		{
			if (!*user_list [acct_buff [i].ac_uid])
				continue;
			/*
			 * get the times
			 */
			x =	expand (acct_buff [i].ac_utime)
				+
				expand (acct_buff [i].ac_stime);
			/*
			 * null terminate the command name
			 */
			acct_buff [i].ac_comm [10] = 0;
			/*
			 * replace missing command names with question marks
			 */
			if (!*acct_buff [i].ac_comm)
			{
				move ("?", acct_buff [i].ac_comm);
			}
			/*
			 * replace control characters with question marks
			 */
			for (p = acct_buff [i].ac_comm; *p; p++)
			{
				if (*p < '!' || '~' < *p)
					*p = '?';
			}
			for (j = 1; j < argc; j++)
			{
				if
				(
					equal (acct_buff [i].ac_comm, argv [j])
					||
					equal
					(
						user_list[acct_buff[i].ac_uid],
						argv [j]
					)
					||
					equal
					(
						tername(acct_buff[i].ac_tty),
						argv[j]
					)
				)
				{
					break;
				}
			}
			if (argc == 1 || j != argc)
			{
				printf
				(
					"%-*s %s %-*s %-*s %6.2f     %.16s\n"
					, fldsiz(acct, ac_comm)
					, acct_buff [i].ac_comm
					, flagbits(acct_buff [i].ac_flag)
					, fldsiz(utmp, ut_name)
					, user_list [acct_buff [i].ac_uid]
					, fldsiz(utmp, ut_line)
					, tername(acct_buff [i].ac_tty)
					, x / 60.0
					, ctime (&acct_buff [i].ac_btime)
				);
			}
		}
	}
}

time_t
expand (t)
unsigned t;
{
	register time_t nt;

	nt = t & 017777;
	t >>= 13;
	while (t)
	{
		t--;
		nt <<= 3;
	}
	return (nt);
}

move (a, b)
char *a, *b;
{
	while (*b++ = *a++)
		;
}

char *
flagbits(f)
register int f;
{
	register int i = 0;
	static char flags[20];

# define BIT(flag, ch)	flags[i++] = ( f & flag ) ? ch : ' '

	BIT( ASU,	'S');
	BIT( AFORK,	'F');
	BIT( ACOMPAT,	'C');
	BIT( ACORE,	'D');
	BIT( AXSIG,	'X');

	flags[i] = '\0';

	return(flags);
}

setupdevs()
{
	register DIR * fd;
	register struct devhash * hashtab;
	register ndevs = NDEVS;
	struct direct * dp;

	if ((fd = opendir("/dev")) == NULL) {
		perror("/dev");
		return;
	}

	if ((hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash)))
	    == (struct devhash *) 0) {
		fprintf(stderr, "No mem for dev table\n");
		return;
	}

	while (dp = readdir(fd)) {
		if (dp->d_ino == 0)
			continue;
#ifdef	MELB
		if (dp->d_name[0] != 't' && strcmp(dp->d_name, "console"))
			continue;
#endif
		strncpy(hashtab->dev_name, dp->d_name, fldsiz(utmp, ut_line));
		hashtab->dev_name[fldsiz(utmp, ut_line)] = 0;
		hashtab->dev_nxt = dev_chain;
		dev_chain = hashtab;
		hashtab++;
		if (--ndevs <= 0)
			break;
	}
	closedir(fd);
}

char *
tername(dev)
dev_t dev;
{
	register struct devhash *hp, *nhp;
	struct stat statb;
	char name [fldsiz(devhash, dev_name) + 6];
	static dev_t lastdev = (dev_t) -1;
	static char *lastname;

	if (dev == NODEV)
		return("__");

	if (dev == lastdev)
		return(lastname);
	
	for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt)
		if (hp->dev_dev == dev) {
			lastdev = dev;
			return(lastname = hp->dev_name);
		}

	for (hp = dev_chain; hp; hp = nhp) {
		nhp = hp->dev_nxt;
		strcpy(name, "/dev/");
		strcat(name, hp->dev_name);
		if (stat(name, &statb) < 0)	/* name truncated usually */
			continue;
		if ((statb.st_mode & S_IFMT) != S_IFCHR)
			continue;
		hp->dev_dev = statb.st_rdev;
		hp->dev_nxt = dev_hash[HASH(hp->dev_dev)];
		dev_hash[HASH(hp->dev_dev)] = hp;
		if (hp->dev_dev == dev) {
			dev_chain = nhp;
			lastdev = dev;
			return(lastname = hp->dev_name);
		}
	}

	dev_chain = (struct devhash *) 0;
	return("??");
}