[comp.unix.questions] Time sync on Suns

earle@jplopto.uucp (Gregory Earle (40876)) (05/11/87)

An easy workaround for not having `timed' on Suns, that has worked quite
well for me for some time:

For each machine in your network, call the UTC number, (303) 499-7111 I
believe, and set its clock by it.  Do this on a Friday.  Then, on Monday,
call it again and see which machine is still closest to the correct time.
Assume that is your best clock machine.  Call this machine `goodclock'.
Then, write a little script, which does simply
	for i in [names of your hosts here]
(If you use YP, you can replace a static list by 
`ypcat hosts.byname | awk '{ print $1}'` or something equivalent)
	do
		rsh $i rdate goodclock
	done

I toss this into /usr/adm, and run it every 6 hours out of crontab.
Obviously it loses if one of the machines happens to be down (`goodclock'
will be left with a few processes hanging around, like `sh' and `rsh'),
but in general this is a minor nuisance.  This way, you get pretty
reasonable clock sync across your network, and then you merely need call
UTC every week or two to keep `goodclock' in sync.

It may not be as clean as `timed' but *I* certainly never worried about
clock sync problems using this method ...

chris@mimsy.UUCP (Chris Torek) (05/11/87)

In article <3734@elroy.Jpl.Nasa.Gov> earle@jplopto.uucp (Gregory
Earle (40876)) writes:
>... call the UTC number, (303) 499-7111 I believe, and set its clock
>by it.

There must be several UTC clocks.  There is a machine readable UTC
clock at the U.S. Naval Observatory in Washington, D.C.; the number
is (correct this time!) 202 653 0351.  (The voice number is 202
653 1800.) Below is a program that reads the values printed by this
clock.  I did not write this code and am not responsible for all
the obvious bugs in it.

#ifndef lint
static char sccsid[] = "@(#)navclock.c	(U of Maryland) FLB 15-May-1986";
static char RCSid[] = "$Header: navclock.c,v 1.1 86/05/15 23:23:25 bin Exp $";
#endif lint

/*
 * navclock - read Naval Observatory clock to set system clock
 *
 % cc -s -O navclock.c -o navclock
 *
 * $Log:	navclock.c,v $
 * Revision 1.1  86/05/15  23:23:25  bin
 * Initial revision
 * 
 */

#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
#include <ctype.h>
#include <sysexits.h>

#define PHONE_DELAY	1700

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

#define	N_SAMP_DFL	3

#define	ADJTIME 1

#define	CLOCK_LOG "/usr/adm/clock_log"

int silent_flag = 0;
struct timeval correction, min_correction = { 259200, 0},
	corr_threshhold = { 0, 50000}, threshhold = { 600, 0},
	timeout = { 8, 500 };

/****************************************************************************/

struct timeval
get_correction()
{
struct timeval system_time, naval_time, correction;
struct timezone time_zone;
long julian_date, day_of_year, hour, minute, second, days, year;
char buff[BUFSIZ], c;
register char *cp;

nice(-40);
nice(20);
nice(0);
nice(-10);

alarm(40);

do {
	if (fgets(buff, sizeof(buff), stdin) == NULL) {
		if (!silent_flag)
			fprintf(stderr, "unexpected EOF on input\n\r");
		exit(EX_NOINPUT);
		}

	for (cp = buff; cp < &buff[sizeof(buff)] && *cp; cp++)
		*cp &= 0177;
	*--cp = (char)0;
	} while (sscanf(buff, "%d %d %2d%2d%2d", &julian_date, &day_of_year,
				&hour, &minute, &second) < 5);

do {
	if (read(0, &c, 1) < 1) {
		if (!silent_flag)
			perror("Read error");
		exit(EX_NOINPUT);
		}
	c &= 0177;
	if (!silent_flag)
		fputc(c, stderr);
	} while (c != '*');
if (!silent_flag)
	fputc('\n', stderr);
fflush(stderr);

if (gettimeofday(&system_time, &time_zone) < 0) {
	if (!silent_flag)
		perror("gettimeofday");
	exit(EX_OSERR);
	}

alarm(0);

nice(-40);
nice(20);
nice(0);

{
long t;
struct tm *localtime();
register struct tm *tp;

time(&t);
tp = localtime(&t);
year = tp->tm_year;
if (year < 100)
	year += 1900;
}

{
register int i;

for (days = 0, i = 1970; i < year; i++)
	days += dysize(i);
}

naval_time.tv_sec = (days+day_of_year-1)*DAYS + hour*HOURS + minute*MINUTES
		+ second*SECONDS;
naval_time.tv_usec = 0;

correction.tv_sec  = naval_time.tv_sec  - system_time.tv_sec;
correction.tv_usec = naval_time.tv_usec - system_time.tv_usec;

correction.tv_usec += PHONE_DELAY;

normalize(&correction);

return correction;
}

/****************************************************************************/

struct timeval *
abs_val(tp)
struct timeval *tp;
{
register struct timeval *abs;

if (tp->tv_sec < 0) {
	abs = (struct timeval *)malloc(sizeof(struct timeval));
	abs->tv_sec  = -tp->tv_sec;
	abs->tv_usec = -tp->tv_usec;
	}
else
	*abs = *tp;

return abs;
}

/****************************************************************************/

main(argc, argv)
int argc;
char *argv[];
{
int n_samp = N_SAMP_DFL;

signal(SIGALRM, SIG_DFL);

for (argc--, argv++; argc > 0; argc--, argv++) {
	register char *cp;

	for (cp = *argv; *cp;)
		switch (*cp) {
			case 'm':
				threshhold.tv_sec = atoi(++cp);
				while (*cp && isascii(*cp) && isdigit(*cp))
					cp++;
				break;

			case 's':
				silent_flag++;
				cp++;
				break;

			case 'n':
				n_samp = atoi(++cp);
				while (*cp && isascii(*cp) && isdigit(*cp))
					cp++;

			default:
				fprintf(stderr, "navclock: bad flag: %c\n\r",
									*cp);

			case '-':
				cp++;
			}
	}

while (n_samp-- > 0) {
	correction = get_correction();

	if (timercmp(abs_val(&correction), abs_val(&min_correction), <))
		min_correction = correction;
	}

if (timercmp(abs_val(&correction), &corr_threshhold, <)) {
	if (!silent_flag)
		fprintf(stderr, "no correction\r\n");
	correction.tv_sec = correction.tv_usec = 0;
	}

if (!silent_flag)
	fprintf(stderr, "correction %f seconds\r\n",
			(double)correction.tv_sec +
			((double)correction.tv_usec/1000000.0));

if (timercmp(abs_val(&correction), &threshhold, >)) {
	if (!silent_flag)
		fprintf(stderr,
			"navclock: correction greater than %d seconds.\n",
							threshhold);
	exit(EX_DATAERR);
	}

#ifdef	CLOCK_LOG
log_it(&correction);
#endif	CLOCK_LOG

if (correction.tv_sec == 0 && correction.tv_usec == 0)
	exit(EX_OK);

#ifdef ADJTIME

if (adjtime(&correction, (struct timeval *)0) < 0) {
        if (!silent_flag)
                perror("adjtime");
        exit(EX_NOPERM);
        }
#else ADJTIME
if (gettimeofday(&system_time, &time_zone) < 0) {
	if (!silent_flag)
		perror("gettimeofday");
	exit(EX_OSERR);
	}

system_time.tv_sec  += correction.tv_sec;
system_time.tv_usec += correction.tv_usec;
normalize(&system_time);

if (settimeofday(&system_time, &time_zone) < 0) {
	if (!silent_flag)
		perror("settimeofday");
	exit(EX_NOPERM);
	}
#endif ADJTIME

exit (EX_OK);
}

/****************************************************************************/

normalize(timestruct)
register struct timeval *timestruct;
{

if (timestruct->tv_sec >= 0) {
	if (timestruct->tv_usec >= 1000000) {
		timestruct->tv_sec++;
		timestruct->tv_usec -= 1000000;
		}
	if (timestruct->tv_usec < 0) {
		timestruct->tv_sec--;
		timestruct->tv_usec += 1000000;
		}
	}
else {
	if (timestruct->tv_usec <= -1000000) {
		timestruct->tv_sec--;
		timestruct->tv_usec += 1000000;
		}
	if (timestruct->tv_usec > 0) {
		timestruct->tv_sec++;
		timestruct->tv_usec -= 1000000;
		}
	}
}

/****************************************************************************/

#ifdef CLOCK_LOG

log_it(corr)
struct timeval *corr;
{
register FILE *log;
char *ctime();
long time(), tim;

if ((log = fopen(CLOCK_LOG, "a")) == NULL) {
	perror(CLOCK_LOG);
	return;
	}

time(&tim);
fprintf(log, "%24.24s %f\n", ctime(&tim), (double)corr->tv_sec +
	((double)corr->tv_usec/1000000.0));

fclose(log);
}

#endif CLOCK_LOG
/****************************************************************************/
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
Domain:	chris@mimsy.umd.edu	Path:	seismo!mimsy!chris