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