[unix-pc.sources] program to set system clock on UNIX-PC

rick@kimbal.UUCP (Rick Kimball) (11/20/88)

#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./usnotime.6`
then
echo "writting ./usnotime.6"
cat > ./usnotime.6 << '\Rogue\Monster\'
.TH USNOTIME 6L 20-Nov-88
.SH NAME
usnotime \- Synchronize system clock according to USNO Master Clock (UNIX-PC only)
.SH SYNOPSIS
.I usnotime
.SH DESCRIPTION
.I Usnotime
sets the sytem clock on a UNIX-PC using the ascii time provide by the
United States Naval Observatory ((202) 653-0351 1200 baud).  It
places the call, reads the time for five successive seconds, decides
how far the system clock is off, then resets the clock with the
appropriate correction.  It writes the clock difference to stdout,
allowing you to keep track of the drift in your system's clock.
.sp
.I Usnotime
assumes that the system clock is set to the correct day and year.  It will
not reset the system time if the time difference is greater than one day.
.sp
According to the Naval Observatory, the time signal provided on this number
is slow by 1.7ms +-.4ms, not counting phone-line delay. It is generated by
special hardware driven by the Master Clock, not a computer.
.sp
.I Usnotime
is intended to be run from a cron entry.
You must be able to set the system clock, that is: you must be super-user.
.SH OPTIONS
NONE
.SH AUTHOR
Rick Kimball <rick@kimbal> with thanks to
.sp
Fred Blonder <fred@mimsy.umd.edu>
.SH FILES
/usr/adm/clocklog \- Usual file to record corrections to the system clock.
.SH DIAGNOSTICS
.SH BUGS
\Rogue\Monster\
else
  echo "will not over write ./usnotime.6"
fi
if `test ! -s ./usnotime.c`
then
echo "writting ./usnotime.c"
cat > ./usnotime.c << '\Rogue\Monster\'
/*+
**--------------------------------------------------------------------
**
**  NAME:   usnotime - set system clock to US Naval Observatory Time.
**
**  SYNOPSIS:   usnotime
**
**  DESCRIPTION:
**          This program sets the system clock to the time
**          maintained by United States Naval Observatory.
**          It assumes that the system clock is currently set
**          to the correct day and year.
**
**  AUTHOR: Rick Kimball
**          UUCP: rick@kimbal
**          Sun Nov  6 18:17:57 EST 1988
**  NOTES:
**          This program is based on a program written by
**          <fred@mimsy.umd.edu> called "navclock".  The
**          original required a 'cu' look-a-like called 'x'
**          to handle all the dialing.  The original
**          "navclock" also expected to read its input from
**          stdin.  All I wanted was a small simple program
**          to set the clock and tell me how much difference
**          there was between the system clock and the master
**          clock.  I didn't want to spend the time to get
**          'x' running on the UNIX-PC.  So I added the
**          dialing capability to the program and removed
**          many of the options from "navclock". The result
**          is this program.  Many thanks to the original author
**          Fred Blonder.
**
**--------------------------------------------------------------------
-*/

#include <stdio.h>
#include <dial.h>
#include <time.h>

#define MODEM "/dev/ph1"
#define BAUDRATE 1200
#define USNO_TELNO "12026530351"

#define SECONDS 1
#define MINUTES 60
#define HOURS   (60*MINUTES)
#define DAYS    (24*HOURS)


main()
{
    int modem;          /* file descriptor for modem line */
    long newTime;       /* Universal Marine Time seconds */
    long GetUMT();      /* function returns a long */

    /*
    ** Dial the US Naval Observatory
    */
    modem = CallUSNO();

    /*
    ** Read their output and compute the
    ** number of seconds since 1970.
    */
    newTime = GetUMT(modem);

    /*
    ** Set the system clock on this machine.
    */
    SetLocalTime(newTime);

    /*
    ** Drop the telephone line
    */
    HangUp(modem);
}

CallUSNO()
{
    int fd;                         /* file descriptor for modem */
    static struct termio Termio;    /* terminal io structure */
    static CALL info =              /* dial() structure */
    {
        &Termio,                    /* terminal io structure */
        BAUDRATE,                   /* I think the UNSO only works at 1200 */
        BAUDRATE,
        MODEM,                      /* OBM modem device name */
        USNO_TELNO,                 /* their telephone number */
        0                           /* no local modem control */
    };

    /*
    ** Set ioctl values for modem
    */

    Termio.c_iflag = IGNBRK | IGNPAR | ISTRIP | IXOFF ;
    Termio.c_oflag = 0;
    Termio.c_cflag |= HUPCL;
    Termio.c_lflag = ICANON | ECHOK;
    Termio.c_cc[VINTR] = 127;
    Termio.c_cc[VQUIT] = 4;
    Termio.c_cc[VMIN]  = 0;
    Termio.c_cc[VTIME] = 0;

    if ((fd = dial ( info )) < 0)
    {
        fprintf (stderr, "usnotime: Error %d trying to dial\n", fd);
        exit(1);
    }
    else
    {
        return (fd);
    }
}

/*
**
    the USNO output looks like this and it keeps coming for ~15 seconds

--- start of sample Naval Observatory output --
*
47471 311 194519 UTC
--- end of sample output --
^     ^   ^ ^ ^
Julian Date
      Julian Day
          GMT Hour
            GMT Minute
              GMT Second
*/

long
GetUMT(modem)
{
    int noOfSamples = 0;    /* count of the number of times sampled */
    char buffer[80];        /* buffer to hold USNO data */
    long notUsed;           /* actually the julian year ??? */
    long day;               /* buffer for julian day 1-366 */
    long hour;              /* buffer for hour 00 - 23 */
    long minute;            /* buffer for minute 00 - 59 */
    long second;            /* buffer for second 00 - 59 */
    FILE *modemFP;          /* FILE pointer to make easy reading */
    long ComputeSeconds();  /* function returns a long seconds */
    extern int errno;       /* UNIX error number */

    if ( (modemFP = fdopen(modem,"r")) == NULL )
    {
        fprintf( stderr, "usnotime: unix error [%d] problem opening modem\n",
            errno );
        return ( 0L );
    }

    /*
    **  Take 5 samples; that should be enough to get rid of any line noise
    */

    while ( noOfSamples < 5 )
    {
        fgets(buffer, 80, modemFP);
        if ( buffer[0] != '*' )
        {
            noOfSamples++;
        }
    }

    sscanf(buffer, "%d %d %2d%2d%2d", &notUsed, &day, &hour, &minute, &second);

    return( ComputeSeconds( day, hour, minute, second ) );
}

long
ComputeSeconds( day, hour, minute, second )
long day;
long hour;
long minute;
long second;
{
    int i;
    int year;
    long daysSince1970;
    long oldTime;
    long seconds;
    struct tm *tp, *gmtime();

    time(&oldTime);

    tp = gmtime(&oldTime);

    year = tp->tm_year + 1900;

    for (daysSince1970 = 0, i = 1970; i < year; i++)
        daysSince1970 += DaysInYr(i);

    seconds =   (daysSince1970 + day - 1) * DAYS
                + hour * HOURS
                + minute * MINUTES
                + second * SECONDS;

    return ( seconds );
}

DaysInYr(year)
int year;
{
    if ( ( year % 4) == 0 )
    {
        if ( year == 2000 )
            return 365;
        else
            return 366;
    }
    else
    {
        return 365;
    }
}

SetLocalTime(newTime)
long newTime;
{
    long oldTime;
    int diff;
    char slow;

    time(&oldTime);

    diff = abs((int)(oldTime - newTime));

    if ( oldTime < newTime )
        slow = 1 /* TRUE  */;
    else
        slow = 0 /* FALSE */;

    fprintf(stderr, "usnotime: the system clock is %d seconds %s\n",
                    diff, slow ? "slow": "fast" );

    if ( diff > DAYS )
    {
        fprintf(stderr,
           "usnotime: Warning! clock not set; difference greater than 1 day\n");
    }
    else
    {
        if ( stime(&newTime) < 0 )
        {
            fprintf(stderr,
                "usnotime: Warning! clock not set; you must be root\n");
        }
    }
}

HangUp(fd)
int fd;
{
    undial(fd);
}
\Rogue\Monster\
else
  echo "will not over write ./usnotime.c"
fi
echo "Finished archive 1 of 1"
exit
-- 
Rick Kimball                                   Mac Source BBS
UUCP: rick@kimbal                              Altamonte Springs, FL      
      ..!gatech!fabscal!kimbal!rick
      ..!ucf-cs!sdgsun!kimbal!rick             DATA (407) 862-6214