AUSAM/source/S/ac4.c

#
/*
 *	various subroutines in alphabetical order
 */

#include	<local-system>
#include	"ac.h"
#include	<passwd.h>



/*
 *	bycpu		return reverse order of two user cpu times
 *	=====
 */

int bycpu( p1, p2 )
  struct u_ent **p1, **p2;
{
  if ( (*p1)->ue_cputime < (*p2)->ue_cputime )
	return( 1 );
  return( -1 );
}



/*
 *	bylog		return reverse order of two user logged times
 *	=====
 */

int bylog( p1, p2 )
  struct u_ent **p1, **p2;
{
  if ( (*p1)->ue_logtime < (*p2)->ue_logtime )
	return( 1 );
  return( -1 );
}



/*
 *	bylogons	return reverse order of two user logon counts
 *	========
 */

int bylogons( p1, p2 )
  struct u_ent **p1, **p2;
{
  if ( (*p1)->ue_logons < (*p2)->ue_logons )
	return( 1 );
  return( -1 );
}



/*
 *	byname		return order of two user names
 *	======
 */

int byname( p1, p2 )
  struct u_ent **p1, **p2;
{
	register char	*s1 = (*p1)->ue_namep;
	register char	*s2 = (*p2)->ue_namep;
	register	c;

  while ( c = (*s2++|040) )
	if ( c != (*s1++|040) )
		if ( c > (*--s1|040) )
			return( -1 );	/* 1 < 2 */
		else
			return( c );	/* 1 > 2 */

  return( *s1 );	/* 1 >= 2 */
}



/*
 *	byuid		return order of two user ids
 *	=====
 */

int byuid( p1, p2 )
  struct u_ent **p1, **p2;
{
  if ( (*p1)->ue_uid > (*p2)->ue_uid )
	return( 1 );
  return( -1 );
}



/*
 *	chime	keep trace of time changes - hour-day-month
 *	=====
 */

chime( dp, date_change )
  register struct dtmp *dp;
  register date_change;
{
  do
  {
	{
		register struct tty *ttyp = ttys;

		do
		{
			ttyp->t_flags =& ~NEWHR;

			if ( !date_change && ttyp->t_userp )
				if ( ttyp->t_logintime < lasthour )
				{
					hourp->c_ttys++;
					hourp->c_logtime =+ HOUR;
					if ( working_day )
					{
						hourp->c_wd_ttys++;
						hourp->c_wd_lgtime =+ HOUR;
						ttyp->t_wd_time =+ HOUR;
					}
				}
				else
				{
					hourp->c_logtime =+ hour - ttyp->t_logintime;
					if ( working_day )
					{
						hourp->c_wd_lgtime =+ hour - ttyp->t_logintime;
						ttyp->t_wd_time =+ hour - ttyp->t_logintime;
					}
				}
		}
		while
			( ++ttyp < LAST_TTY );
	}

	if ( !date_change )
	{
		register struct tty_profil	*ttpp;

		for ( ttpp = &ttyprofil[ttylcount-1] ; ttpp >= ttyprofil ; ttpp-- )
		{
			long		uptime = hour - ttpp->tp_ontime;

			ttpp->tp_realtime =+ uptime;
			if ( working_day )
				ttpp->tp_wd_realtime =+ uptime;
			ttpp->tp_ontime = hour;
		}
	}

	if ( !date_change )	/* && sys.st_boottime >= lasthour && sys.st_boottime < hour ) */
	{
		sys.st_uptime =+ hour - sys.st_boottime;
		if ( working_day )
			sys.st_wd_uptime =+ hour - sys.st_boottime;
		sys.st_boottime = hour;
#		ifdef	DEBUG
		if ( flg.y )
		{
			char	s[PTIMSIZ];

			syswarn( "chime: uptime %s\n", ptime( sys.st_uptime, s ) );
		}
#		endif
	}

	lasthour = hour;
	hour =+ HOUR;
	if ( hour > midnight )
	{
		if ( !date_change )
		{
			register struct tty	*ttyp = ttys;
			long			last_day = midnight - DAY;

			do
				if ( ttyp->t_userp )
				{
					if ( ttyp->t_logintime < last_day )
						dayp->d_logtime =+ DAY;
					else
						dayp->d_logtime =+ midnight - ttyp->t_logintime;
					dayp->d_sessions++;
				}
			while
				( ++ttyp < LAST_TTY );
		}

		if ( flg.d )
			print( midnight );
		if ( hour > month )
		{
			if ( !flg.d )
				print( month );
			nextmonth();
#ifdef	DEBUG
			if ( flg.y )
				syswarn( "chime - midnight: %s", ctime( midnight ) );
#endif
		}
		midnight =+ DAY;
		hourp = clock;
		if ( hour > week )
		{
			week =+ WEEK;
			dayp = sennight;
		}
		else
			dayp++;

		dayp->d_weeks++;
#		ifdef	DAY_TRACE

		printf( "DAY %d = %d\n", dayp-sennight, dayp->d_weeks );
#		endif	DAY_TRACE
#		ifdef	TIME_TRACE

		print_times( "chime", TT_HOUR );
#		endif	TIME_TRACE
	}
	else
		hourp++;

	if ( hourp >= &clock[W_HOUR_IN] && hourp < &clock[W_HOUR_OUT]
	    && dayp >= &sennight[W_DAY_IN-1] && dayp < &sennight[W_DAY_OUT-1]
	   )
		working_day = 1;
	else
		working_day = 0;
  }
  while
	( hour <= dp->d_newtime );
}



/*
 *	copystring	allocate new string area and copy string into it
 *	==========
 */

char *copystring( string )
  char *string;
{
	register char	*s, *ns;
	register	i;
	char		*new;
	extern char	*ualloc();

  for ( i = 1 , s = string ; *s++ && (!flg.o || i <= 8) ; i++ );

  new = ns = ualloc( i );

  for ( s = string ; i-- ; )
	*ns++ = *s++;
  if ( flg.o )
	*--ns = 0;

  return( new );
}



/*
 *	cputimes	update system cputimes and return total
 *	========
 */

long cputimes( op )
  register struct otmp *op;
{
	long	t;

  if ( !flg.o )
  {
	sys.st_syscpu =+ op->o_systime;
	sys.st_usercpu =+ op->o_usertime;
	t = op->o_systime + op->o_usertime;
	if ( working_day )
	{
		sys.st_wd_syscpu =+ op->o_systime;
		sys.st_wd_usercpu =+ op->o_usertime;
		hourp->c_wd_cputime =+ t;
	}
	hourp->c_cputime =+ t;
	dayp->d_cputime =+ t;
	return( t );
  }
  else
	return( 0 );
}



/*
 *	fixuptime	bring time variables up to date
 *	=========
 */

fixuptime( dp )
  register struct dtmp *dp;
{
# ifdef	TIME_TRACE
  print_times( "fixuptime", TT_ALL );

# endif	TIME_TRACE
  while ( midnight <= dp->d_newtime )
	midnight =+ DAY;

  hour = midnight - DAY;
  lasthour = hour - HOUR;
  hourp = &clock[-1];

  set_week();
  chime( dp, 1 );
  nextmonth();
# ifdef	TIME_TRACE

  print_times( "fixuptime", TT_ALL );
# endif	TIME_TRACE
}



/*
 *	getuser		if user can't be found in hash table,
 *	=======		allocate a new user structure, and enter it in the table
 */

struct u_ent *getuser( up )
  register struct utmp *up;
{
	register struct u_ent	*ep;
	register		hashval = uhash( up->u_u_id );
	struct pwent		pen;
	char			sbuf[SSIZ];
	extern char		*ualloc(), *copystring();

  if ( !flg.p )
  {
	static struct u_ent	everyman;

	return( &everyman );
  }

  if ( ep = uhasht[hashval] )
  do
	if ( up->u_u_id == ep->ue_uid )
		return( ep );
  while
	( ep = ep->ue_next );

  nu_ents++;
  ep = ualloc( sizeof *ep );

  /*
   *	initialise structure elements in order of declaration
   */

  ep->ue_next = uhasht[hashval];
  uhasht[hashval] = ep;

  pen.pw_uid = ep->ue_uid = up->u_u_id;
  ep->ue_flags = 0;
  ep->ue_logins = 0;
  ep->ue_multilogins = 0;
  ep->ue_logons = 0;

  if ( ( !flg.o && getpwlog( &pen, sbuf, SSIZ ) < 0 )
      || ( flg.o && ( !up->u_u_name[0] || up->u_type != U_TYPE ) )
     )
  {
	warn( "unrecognised user", up );
	ep->ue_namep = copystring( "????????" );
  }
  else
  if ( flg.p )
  {
	ep->ue_namep = copystring( flg.o ? up->u_u_name : pen.pw_strings[LNAME] );
#	ifdef	USER_NAMES
	if ( !flg.o )
	{
		ep->ue_firstname = copystring( pen.pw_strings[FIRSTNAME] );
		ep->ue_lastname = copystring( pen.pw_strings[LASTNAME] );
	}
#	endif	USER_NAMES
  }

  ep->ue_asynctime = 0;
  ep->ue_cputime = 0;
  ep->ue_logtime = 0;

  return( ep );
}



/*
 *	nextmonth	calculate end of current month
 *	=========
 */

nextmonth()
{
	register	i,j;
	register	day = (midnight - 1)/DAY;
	int		f = 0;
	int		mon = 0;
	extern int	dysize(), dmsize[];

# ifdef	TIME_TRACE
  print_times( "nextmonth", TT_MONTH );

# endif	TIME_TRACE
#ifdef	DEBUG
  if ( flg.y )
	syswarn( "nextmonth in hour: %s", ctime( hour ) );

#endif
  for ( i = 1970 ; day >= 0 ; i++ )
  {
	j = dysize( i );
	day =- j;	mon =+ j;
  }
  day =+ j;	mon =- j;

  if ( j == 366 )	/* leap year */
	f++;

  for ( i = 0 ; day >= 0 ; i++ )
  {
	j = dmsize[i];
	if ( f && i == 1 )	/* february */
		j++;
	day =- j;	mon =+ j;
  }

  month = mon*DAY;
#ifdef	DEBUG

  if ( flg.y )
	syswarn( "nextmonth out month: %s", ctime( month ) );
#endif
# ifdef	TIME_TRACE

  print_times( "nextmonth", TT_MONTH );
# endif	TIME_TRACE
}
#ifdef	TIME_TRACE




struct timetable time_table[]
{
  {	"year",		&year		}
 ,{	"month",	&month		}
 ,{	"week",		&week		}
 ,{	"midnight",	&midnight	}
 ,{	"hour",		&hour		}
 ,{	"lasthour",	&lasthour	}
 ,{	"timenow",	&timenow	}
 ,{	"lastprint",	&lastprint	}
 ,{	"boot time",	&sys.st_boottime}
};

#define	NTIMES	((sizeof time_table)/(sizeof time_table[0]))




/*
 *	print_times	print out trace of time values
 *	===========
 */

print_times( s, only )
  char		*s;
  register	only;
{
	register struct timetable	*p;

	if ( flg.y )
	{
		printf( "TIME TRACE in %s:\n", s );

		for ( p = &time_table[only >= NTIMES ? 0 : only] ; p < &time_table[NTIMES] ; p++ )
		{
			printf( "\t%s:%20t%s", p->t_name, ctime( *p->t_timep ) );
			if ( only )
				break;
		}
	}
}
#endif	TIME_TRACE



/*
 *	set_week	calculate end of current week and set "dayp"
 *	========
 */

set_week()
{
	extern int	*localtime();
	register	weekday = localtime( midnight-1 )[6] - 1;

#	ifdef	TIME_TRACE
	print_times( "set_week", TT_WEEK );

#	endif	TIME_TRACE
	if ( weekday < 0 )
		weekday = 6;	/* Sunday */

	dayp = &sennight[weekday];
	dayp->d_weeks++;

	week = midnight + DAY * (6 - weekday);
#	ifdef	TIME_TRACE

	print_times( "set_week", TT_WEEK );
#	endif	TIME_TRACE
}




/*
 *	syswarn		general warning on file 2
 *	=======
 */

syswarn( s, a1, a2, a3, a4, a5 )
{
	register	of;
	extern		fout;

  if ( !flg.n )
  {
	flush();
	of = fout;
	fout = 2;
	printf( s, a1, a2, a3, a4, a5 );
	flush();
	fout = of;
  }
}



/*
 *	ttycount	count a tty if first time it has been used in current hour
 *	========
 */

ttycount( ttyp )
  register struct tty *ttyp;
{
  if ( !(ttyp->t_flags & NEWHR) )
  {
	hourp->c_ttys++;
	if ( working_day )
		hourp->c_wd_ttys++;
	ttyp->t_flags =| NEWHR;
  }
}



/*
 *	ualloc		allocate new area, if none left, attempt garbage collection from hash table
 *	======
 */

char *ualloc( n )
{
	char			*s;
	extern char		*alloc();

loop:
  if ( (s = alloc(n)) == -1 )
  {
#	ifdef	GARBAGE_COLLECTION
	register struct u_ent	*ep, **bp, **hp;

	for ( hp = &uhasht[HASHSIZ-1] ; hp >= uhasht ; --hp )
		if ( ep = *hp )
		{
			bp = hp;
			do
				if ( (ep->ue_flags & (LOGIN|UPDATE)) == 0 )
				{
					nu_ents--;
					*bp = ep->ue_next;
					free( ep->ue_namep );
					free( ep );
					goto loop;
				}
			while
				( bp = &ep->ue_next , ep = ep->ue_next );
		}
#	endif	GARBAGE_COLLECTION

	flg.n = 0;
	syswarn( "%s: not enough memory!\n", name );
	exit( -1 );
  }

  return( s );
}



/*
 *	warn		accounting record related warning
 *	====
 */

warn( s, up )
  char *s;
  register struct utmp *up;
{
	register	c;
	register	type;
	extern char	*ctime();

  if ( flg.o && up->u_u_id == 0xffff )
	return;

  switch ( type = up->u_type )
  {
   case U_TYPE:	type = 'U';	break;
   case O_TYPE:	type = 'O';	break;
   case W_TYPE:	type = 'W';	break;
   case S_TYPE:	type = 'S';	break;
   case D_TYPE:	type = 'D';	break;

   default:	switch ( type =+ ' ' )
		{
		 case 'U': case 'O': case 'W': case 'S': case 'D':
			type =| 040;
		}
  }

  syswarn( "Warning: %s;\n\ttype:'%c' tty:'%c' uid:%-5l  %s"
	   ,s
	   ,type
	   ,(c = up->u_ttyid) ? c : '?'
	   ,up->u_u_id
	   ,ctime( up->u_logintime )
	 );
}




/*
 *	wd_elapsed	return working day time during period
 *	==========
 */

long wd_elapsed( time1, time2 )
  long time1, time2;
{
	register	hour;
	register	wd;
	int		timeout;
	int		day;

  time1 =- w_days_lost * DAY;

  {
	register	*tp;
	extern int	*localtime();

	tp = localtime( time1 );
	if ( tp[6] >= W_DAY_IN && tp[6] < W_DAY_OUT )
	{
		wd = 1;
		if ( tp[2] >= W_HOUR_IN && tp[2] < W_HOUR_OUT )
		{
			timeout = tp[1] * 60 + tp[0];
			time1 =- timeout;
		}
		else
			timeout = 0;
	}
	else
	{
		wd = 0;
		timeout = 0;
	}

	timeout =+ w_days_lost * ((W_HOUR_OUT-W_HOUR_IN)*HOUR);

	hour = tp[2];
	day = tp[6];

	tp = localtime( time2-1 );
	if ( tp[6] >= W_DAY_IN && tp[6] < W_DAY_OUT && tp[2] >= W_HOUR_IN && tp[2] < W_HOUR_OUT )
		timeout =+ HOUR - 1 - (tp[1]*60 + tp[0]);
  }
  {
	register	wh = 0;

	for ( ; time1 < time2 ; time1 =+ HOUR )
	{
		if ( hour >= W_HOUR_IN && hour < W_HOUR_OUT && wd )
			wh++;

		if ( hour++ == 23 )
		{
			hour = 0;

			if ( day++ == 7 )	/* Sunday */
				day = 1;	/* Monday */

			if ( day >= W_DAY_IN && day < W_DAY_OUT )
				wd = 1;
			else
				wd = 0;
		}
	}

	return( wh * 3600L - timeout );
  }
}