[comp.os.minix] leave

tholm@uvicctr.UUCP (Terrence W. Holm) (11/09/88)

EFTH MINIX report #56  - November 1988 -  leave(1)


There follows an implementation of leave(1) for MINIX.

----------------------------------------------------------
echo x - leave.1
gres '^X' '' > leave.1 << '/'
XCOMMANDS
X    leave(1)		- informs user when it is time to leave
X
XINVOCATION
X    leave  [ [+] hhmm ]
X
XEXPLANATION
X    The user tells leave(1) when there is something more
X    important than MINIX work to do. Leave(1) will inform
X    the user when the time approaches (five minutes before),
X    and up to ten minutes after the deadline.
X
X    The time may be in a 12 or 24 hour format, for example
X    730 or 1930. If preceded by a "+" then the deadline is
X    relative to the current time, for example +2400 means
X    24 hours from now. A ':' may be inserted between the
X    hour and minute fields.
X
X    The argument string may be empty, in which case leave(1)
X    will prompt for a [+]hhmm string. If only an ENTER is
X    typed then leave(1) terminates. One could use this in
X    a .profile.
X
X    The signals sigint, sigquit and sigterm are all ignored
X    in the background process. Leave(1) will terminate after
X    the user logs out.
/
echo x - leave.c
gres '^X' '' > leave.c << '/'
X/*  leave(1)
X *
X *  Author: Terrence W. Holm          Nov. 1988
X *
X *  Usage:  leave  [ [+] hhmm ]
X */
X
X#include <signal.h>
X#include <stdio.h>
X#include <utmp.h>
X
X#define  Min(a,b)  ((a<b) ? a : b)
X
X#ifndef  WTMP
X#define  WTMP   "/usr/adm/wtmp"
X#endif
X
X#define  BUFFER_SIZE     1024	  /*  Room for wtmp records  */
X#define  MAX_WTMP_COUNT  ( BUFFER_SIZE / sizeof(struct utmp) )
X
Xstruct utmp  wtmp_buffer[ MAX_WTMP_COUNT ];
X
X#define  STRING	   80		/*  Lots of room for an argument  */
X#define  MIN	   60L		/*  Seconds per minute		  */
X#define  HOUR      (60L*60L)	/*  Seconds per hour		  */
X#define  HALF_DAY  (12L*HOUR)	/*  Seconds per half day	  */
X#define  DAY	   (24L*HOUR)	/*  Seconds per day		  */
X
X/*  Set the following to your personal preferences for the	  */
X/*  time and contents of warnings.				  */
X
X#define  INTERVALS 13		/*  Size of intervals[]		  */
X#define  WARNINGS  4		/*  Size of warnings[]		  */
X
Xint intervals[ INTERVALS ] = { -5*MIN, -1*MIN, 0, MIN, 2*MIN, 3*MIN,
X	4*MIN, 5*MIN, 6*MIN, 7*MIN, 8*MIN, 9*MIN, 10*MIN };
X
Xchar *warnings[ WARNINGS ] = {
X	"You have to leave within 5 minutes",
X	"Just one more minute!",
X	"Time to leave!",
X	"You're going to be late!"   /*  For all subsequent warnings */
X	 };
X
X
X#ifdef V7
Xextern long timezone;
X#else
X#ifdef BSD
X#include <time.h>
Xlong timezone;
X#else
Xlong timezone = 0 * HOUR;	/*  Should be in ctime(3)	  */
X#endif
X#endif
X
X
Xlong  time();
Xchar *ttyname();
Xchar *cuserid();
Xchar *ctime();
X
X
Xmain( argc, argv )
X  int   argc;
X  char *argv[];
X
X  {
X  char when[ STRING ];
X  long now = time( 0 );
X  long leave;
X  int  hour, min;
X  int  pid;
X
X
X  /*  Get the argument string "when" either from stdin, or argv  */
X
X  if ( argc <= 1 )
X    {
X    printf( "When do you have to leave? " );
X
X    if ( fgets( when, STRING, stdin ) == NULL  ||  when[0] == '\n' )
X      exit( 0 );
X    }
X  else
X    {
X    strcpy( when, argv[1] );
X
X    if ( argc > 2 )
X      strcat( when, argv[2] );
X    }
X
X
X  /*  Determine the leave time from the current time and "when"  */
X
X
X  if ( when[0] == '+' )
X    {
X    Get_Hour_Min( &when[1], &hour, &min );
X
X    leave = now + hour * HOUR + min * MIN;
X    }
X  else
X    {
X    /*  User entered an absolute time.  */
X
X#ifdef BSD
X    timezone = - localtime(&now)->tm_gmtoff;
X#endif
X
X    Get_Hour_Min( &when[0], &hour, &min );
X
X    if ( hour >= 1  &&  hour <= 12 )
X	{
X	/*  12-hour format: relative to previous midnight or noon.  */
X
X	leave = now - (now - timezone) % HALF_DAY + hour % 12 * HOUR + min * MIN;
X
X	if ( leave < now - HOUR )
X	  leave = leave + HALF_DAY;
X	else if ( leave < now )
X	  {
X	  printf( "That time has already passed!\n" );
X	  exit( 1 );
X	  }
X	}
X    else if ( hour <= 24 )
X	{
X	/*  24-hour format: relative to previous midnight.  */
X
X	leave = now - (now - timezone) % DAY + hour * HOUR + min * MIN;
X
X	if ( leave < now - HOUR )
X	  leave = leave + DAY;
X	else if ( leave < now )
X	  {
X	  printf( "That time has already passed!\n" );
X	  exit( 1 );
X	  }
X	}
X    else
X	Usage();
X    }
X
X
X  printf( "Alarm set for %s", ctime( &leave ) );
X
X  if ( (pid = fork()) == -1 )
X    {
X    fprintf( stderr, "leave: can not fork\n" );
X    exit( 1 );
X    }
X
X  if ( pid != 0 )
X    exit( 0 );
X
X
X  /*  Only the child continues on  */
X
X  {
X  char *user = cuserid( NULL );
X  char *tty  = ttyname( 0 ) + 5;
X  long delta;
X  int  i;
X
X  if ( user == NULL  ||  tty == NULL )
X    {
X    fprintf( stderr, "leave: Can not determine user and terminal name\n" );
X    exit( 1 );
X    }
X
X
X  signal( SIGINT,  SIG_IGN );
X  signal( SIGQUIT, SIG_IGN );
X  signal( SIGTERM, SIG_IGN );
X
X
X  for(;;)
X    {
X    if( ! Still_Logged_On( user, tty ) )
X      exit( 0 );
X
X    /*  How much longer until the leave time?  */
X
X    delta = leave - time( 0 );
X
X    /*  Which interval are we currently in?  */
X
X    for ( i = 0;  i < INTERVALS;  ++i )
X      if ( delta + intervals[i] > 0 )
X	break;
X
X    /*  If we are within intervals[0] then print a warning.  */
X    /*  If there are more intervals than messages, then use  */
X    /*  warnings[WARNINGS-1] for all subsequent messages.    */
X
X    if ( i > 0 )
X      printf( "\007%s\n", warnings[ i > WARNINGS ? WARNINGS-1 : i-1 ] );
X
X    if ( i == INTERVALS )
X      {
X      printf( "That was the last time I'll tell you. Bye.\n" );
X      exit( 0 );
X      }
X
X    /*  Sleep until the next interval. For long periods, wake	*/
X    /*  up every hour to check if the user is still on (also	*/
X    /*  required because 16 bit ints don't allow long waits).	*/
X
X    sleep( (int) Min( delta + intervals[i], HOUR ) );
X    }
X  }
X  }
X
X
X
XGet_Hour_Min( when, hour, min )
X  char *when;
X  int  *hour;
X  int  *min;
X
X  {
X  int hour_min;
X  int just_min = 0;
X
X  switch ( sscanf( when, "%d:%d", &hour_min, &just_min ) )
X    {
X    case 1 :  *hour = hour_min / 100;
X	      *min  = hour_min % 100;
X	      break;
X
X    case 2 :  *hour = hour_min;
X	      *min  = just_min;
X	      break;
X
X    default:  Usage();
X    }
X
X
X  if ( hour_min < 0  ||  just_min < 0  ||  *min > 59 )
X	Usage();
X  }
X
X
X
XStill_Logged_On( user, tty )
X  char *user;
X  char *tty;
X
X  {
X  FILE  *f;
X  long   size;		/*  Number of wtmp records in the file	*/
X  int    wtmp_count;	/*  How many to read into wtmp_buffer	*/
X
X
X  if( (f = fopen( WTMP, "r" )) == NULL )
X    /*  No login/logout records kept  */
X    return( 1 );
X
X  if ( fseek( f, 0L, 2 ) != 0  ||  (size = ftell(f)) % sizeof(struct utmp) != 0  )
X    {
X    fprintf( stderr, "leave: invalid wtmp file\n" );
X    exit( 1 );
X    }
X
X
X  size /= sizeof(struct utmp);	/*  Number of records in wtmp	*/
X
X
X  while( size > 0 )
X    {
X    wtmp_count = (int) Min( size, MAX_WTMP_COUNT );
X
X    size -= (long) wtmp_count;
X
X    fseek( f, size * sizeof(struct utmp), 0 );
X
X    if ( fread( &wtmp_buffer[ 0 ], sizeof(struct utmp), wtmp_count, f ) != wtmp_count )
X	{
X    	fprintf( stderr, "leave: read error on wtmp file\n" );
X    	exit( 1 );
X    	}
X
X
X    while ( --wtmp_count >= 0 )
X	{
X	if ( strcmp( wtmp_buffer[ wtmp_count ].ut_line, "~" ) == 0 )
X	  return( 0 );
X
X	if ( strncmp( wtmp_buffer[ wtmp_count ].ut_line, tty, 8 ) == 0 )
X          if ( strncmp( wtmp_buffer[ wtmp_count ].ut_name, user, 8 ) == 0 )
X	    return( 1 );
X	  else
X	    return( 0 );
X	}
X
X    }  /* end while( size > 0 ) */
X
X  return( 0 );
X  }
X
X
X
XUsage()
X  {
X  fprintf( stderr, "Usage: leave [[+]hhmm]\n" );
X  exit( 1 );
X  }
/
----------------------------------------------------------

		Terrence W. Holm
		  uw-beaver!uvicctr!tholm