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