/*
Date: Thu, 12 Feb 87 16:34:30 GMT
From: zzkj@ukc.ac.uk
To: mg@ukc.ac.uk
Subject: The wtmp program
Status: O

I might as well mail it to you to save you going root and grubbling it out.

						Zareh

*/
#ifndef lint
static char *sccsid = "@(#)wtmpprog.c	1.1 (UKC) 7/2/87";
#endif  lint

/* System usage display program. Graphically displays the number of users
   versus time and prints the peak number of users for the previous day.
   The information is obtained from /usr/adm/wtmp.

	Author	Z.Z.K. Johannes		University of Kent.
*/

#include<stdio.h>
#include<sys/time.h>
#include<sys/file.h>
#include<utmp.h>
#include<strings.h>

#define	MAX		100		/* Maximum number of users and tty's */
#define MINS		(24*60)		/* Number of minutes in a day */
#define SECS		(MINS*60)	/* Number of seconds in a day */

char	times[MINS];		/* Counters for users/minute */
int	users[MAX];		/* Counters for time at each user level */
char	ttys[MAX];		/* Flags for tty usage */
int	now;			/* Current time position */
int	maxusers;		/* Peak of number of users */

void	extraout();		/* Some forward declarations */
void	store();

main()

{
	int	n,i,yesterday,day,curtime,numusers;
	int	wtmp,err;		/* File pointer and error status */
	struct utmp	entry;		/* Entry pointer for input */
	int	utmpsize;		/* Set to sizeof(struct utmp) */
	char	*ttyname;		/* Name of tty */
	int	ttynum;			/* Number of tty */
	long	yesterlong;		/* Used to get ascii for yesterday */
	char	hostname[256];		/* Used to get the hostname */
	char	*chartime;		/* Used to get ascii for time */
	int	yesteryear;		/* Used to store year of yesterday */
	float	total;			/* Used in the graph routine */
	int	averages[MINS/15];	/*		"		*/
	char	outputstr[MINS/15];	/*		"		*/
	int	starat;			/*		"		*/

	wtmp=open("/usr/adm/wtmp",O_RDONLY);	/* open the wtmp file */
	if (wtmp<0) {
		perror("/usr/adm/wtmp");
		exit(1);
	}

	for (n=0;n<=MINS;n++) {		/* Clear the counters and flags */
		times[n]=0;
		if (n<=MAX) {
			users[n]=0;
			ttys[n]=0;
		}
	}

	yesterlong=time(0)-SECS;
	yesterday=getday(yesterlong);	/* The value of yesterday */
	now=0;		/* 12.00 am */
	day=0;		/* Clear current day */
	numusers=0;	/* Clear users counter */
	maxusers=0;	/* Clear the peak usage counter */

	utmpsize=sizeof(struct utmp);

	/* main loop */
	for (;;) {	/* loop is exited when EOF or today */

		err=read(wtmp,&entry,utmpsize);	/* Read in the entry */
		if (err<0) {
			perror("/usr/adm/wtmp");
			exit(1);
		}

		if (err=0) {	/* handle eof */
			store(MINS,numusers);
			break;
		}

		day=getday(entry.ut_time);	/* Get current day */

		if (day>yesterday) {	/* Today, so update and exit loop */
			store(MINS,numusers);
			break;
		}

		curtime=(day==yesterday ? getmin() : -1);
				/* If yesterday then calculate minute of day,
					else prevent storage */

		ttyname=entry.ut_line;

		if (ttyname[0]=='~' && ttyname[1]=='\0') { /* handle reboots */
			store(curtime,numusers);
			numusers=0;
			for (n=0;n<=MAX;ttys[n++]=0);
			continue;
		}

		if (strlen(ttyname)!=5 || strncmp(ttyname,"tty",3)!=0) continue;
				/* Ignore opr and other console logins */

		ttynum=atoi(&ttyname[3]);	/* get the number of the tty */

		if (entry.ut_name[0]=='\0') {	/* Handle logouts */
			if (ttys[ttynum]==0) extraout(curtime);
			else {
				store(curtime,numusers);
				numusers--;
				ttys[ttynum]=0;
			}
		}
		else {		/* Handle logins */
			store(curtime,numusers);
			numusers++;
			ttys[ttynum]=1;
		}
	}

	/* Now print out the results */

	(void)	gethostname(hostname,256);	/* Print the host and date */
	chartime=ctime(&yesterlong);
	chartime[10]='\0';
	yesteryear=gmtime(&yesterlong)->tm_year+1900;
	printf("\n%s usage for %s %d.\n\n",hostname,chartime,yesteryear);

	printf("The peak number of users was %d.\n\n",maxusers);

	printf("Number of users,Proportion of day\n");
	printf("=================================\n");
	for (n=0;n<=maxusers;n++)	/* Print the day proportions */
		printf("%2d\t\t%6.2f%%\n",n,(float)users[n]*100/MINS);

	for (n=0;n<MINS/15;n++) {	/* Calculate the graph values */
		total=0;
		for (i=0;i<15;total+=times[n*15+i++]);
		averages[n]=total/15;
	}

	printf("\nGraph of number of users versus time\n");
	printf("====================================\n\n");

	for (n=maxusers;n>=0;n--) {	/* Print the graph */
		starat=-1;
		for (i=0;i<MINS/15;i++)
			outputstr[i] = (n==averages[i] ? starat=i,'*' : ' ');
		outputstr[starat+1]='\0';
		printf("%2d |%s\n",n,outputstr);
	}
	printf("    ");			/* Label the x axis */
	for (n=0;n<MINS/15;n++) putchar('-');
	printf("\n ");
	for (n=0;n<MINS/15/4;n++) printf("   |");
	printf("\n ");
	for (n=0;n<24;n++) printf("%4d",n);
	putchar('\n');

	exit(0);			/* Program finished */

}

void	extraout(curtime)		/* Handles a logout without a login */

int	curtime;

{
	int	n;

	if (curtime<now) return;		/* Return if before yesterday */
	for (n=0;n<curtime;times[n++]++);	/*Increment the time counters*/
	for (n=MAX;n>0;n--) users[n]=users[n-1];/* Shift the user level log */
	users[0]=0;
	maxusers++;		/* Increment the maximum number of users */
	now=curtime;
	return;
}

void	store(curtime,numusers)	/* Updates the counters */

int	curtime,numusers;

{
	int	n;
	if (curtime<=now) return;	/* Return if time is not late enough */

	for (n=now;n<curtime;times[n++]=numusers);/* Store the users count */
	users[numusers]+=curtime-now;	/* Store time at userlevel */
	now=curtime;
	if (numusers>maxusers) maxusers=numusers;
	return;
}


struct tm	*timepntr;	/* Structure used by getday and getmin */

getday(timenum)		/* Get the day from the long timenum */

long	timenum;

{
	timepntr=gmtime(&timenum);
	return(timepntr->tm_yday+timepntr->tm_year*366);
}


getmin()		/*Get the minute. getday must be called first*/

{
	return(timepntr->tm_min+timepntr->tm_hour*60);
}
