[comp.protocols.time.ntp] Tools for NTP users with software reference clocks only.

billd@fps.com (Bill Davidson) (05/21/91)

Below is the README file and a shar file which contains some tools
for manipulating software clocks used as NTP servers.  I find them
handy.  If you do, great.  If you don't, I don't care.  If you
like them let me know.  If you don't, send it to /dev/null.

**************************************************************************

These programs are crude hacks but they make working with a software
reference clock with no good hardware reference clock available a
little easier.

I try to synchronize my time with the phone company time recording.  To
do this, I first run "tclock" which stands for "text clock" which
prints out the current time constantly in the form "\rHH:MM:SS.FF".  I
currently have it set to print out every 0.1 seconds.  I figure I can
see the difference between times that are about .2 off from each other
so this is about as good as it gets when doing this stuff by hand.
Anyway, I call the "time" number and watch the running tclock and try
to guess how far off it is from the phone company time.

After making a guess I then want to adjust it.  "date(1)" is a pain.
There is a variable delay between the time you hit return and the time
that the clock is actually set.  So I've written a program called
"adjtime" which is simply a shell level access program to the
adjtime(2) system call.  It takes as it's parameter a single floating
point number of the amount of seconds to adjust by.  If you have your
tickadj variable set to a small value (as ntp documentation always
recomends), it will take a hell of a long time to make up differences
large enough for humans to distinguish.  For that reason, I've made a
script called "doadj" which does a tickadj to make tickadj 10% of tick
(normal default) while it runs adjtime.  It then waits an appropriate
amount of time for the tickadj to finish and runs "tickadj -A" to set
things back to normal.  You may not want to have (x)ntpd running when
you do this since it might do it's own adjtime and wipe you out.  If
you leave it running and the time doesn't get adjusted, that's probably
what happened.  Just do it again.

READ AND UNDERSTAND THE doadj SCRIPT BEFORE YOU RUN IT!
It may need modification for your system.

Now you can run tclock again and call the "time" number again to see
how close you are.  You may need to adjust again.

This stuff was written on and is used on BSD systems.  I don't know if
tclock will run on System V since I don't know if System V has
setitimer(2) or some of the signal stuff.  I don't care to port it and
I won't support it.  You're on your own.

Usual disclaimers: Run this stuff at your own risk.  Neither I nor my
company are willing to take repsonsibility for this and in fact this
whole posting could be a forgery made it look like it came from
billd@fps.com so you'll have a hell of a time proving that I posted
it.  So there.

--Bill Davidson billd@fps.com 5/20/91

=========================================================================
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  README Makefile adjtime.c tclock.c doadj.sh
# Wrapped by billd@celit on Mon May 20 20:26:18 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(2559 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X
XThese programs are crude hacks but they make working with a software
Xreference clock with no good hardware reference clock available a
Xlittle easier.
X
XI try to synchronize my time with the phone company time recording.  To
Xdo this, I first run "tclock" which stands for "text clock" which
Xprints out the current time constantly in the form "\rHH:MM:SS.FF".  I
Xcurrently have it set to print out every 0.1 seconds.  I figure I can
Xsee the difference between times that are about .2 off from each other
Xso this is about as good as it gets when doing this stuff by hand.
XAnyway, I call the "time" number and watch the running tclock and try
Xto guess how far off it is from the phone company time.
X
XAfter making a guess I then want to adjust it.  "date(1)" is a pain.
XThere is a variable delay between the time you hit return and the time
Xthat the clock is actually set.  So I've written a program called
X"adjtime" which is simply a shell level access program to the
Xadjtime(2) system call.  It takes as it's parameter a single floating
Xpoint number of the amount of seconds to adjust by.  If you have your
Xtickadj variable set to a small value (as ntp documentation always
Xrecomends), it will take a hell of a long time to make up differences
Xlarge enough for humans to distinguish.  For that reason, I've made a
Xscript called "doadj" which does a tickadj to make tickadj 10% of tick
X(normal default) while it runs adjtime.  It then waits an appropriate
Xamount of time for the tickadj to finish and runs "tickadj -A" to set
Xthings back to normal.  You may not want to have (x)ntpd running when
Xyou do this since it might do it's own adjtime and wipe you out.  If
Xyou leave it running and the time doesn't get adjusted, that's probably
Xwhat happened.  Just do it again.
X
XREAD AND UNDERSTAND THE doadj SCRIPT BEFORE YOU RUN IT!
XIt may need modification for your system.
X
XNow you can run tclock again and call the "time" number again to see
Xhow close you are.  You may need to adjust again.
X
XThis stuff was written on and is used on BSD systems.  I don't know if
Xtclock will run on System V since I don't know if System V has
Xsetitimer(2) or some of the signal stuff.  I don't care to port it and
XI won't support it.  You're on your own.
X
XUsual disclaimers: Run this stuff at your own risk.  Neither I nor my
Xcompany are willing to take repsonsibility for this and in fact this
Xwhole posting could be a forgery made it look like it came from
Xbilld@fps.com so you'll have a hell of a time proving that I posted
Xit.  So there.
X
X--Bill Davidson billd@fps.com 5/20/91
END_OF_FILE
if test 2559 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(368 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X#
X# quick hack Makefile
X#
X
XCFLAGS=		-O
XPROGRAMS=	adjtime tclock doadj
XFILES=		README Makefile adjtime.c tclock.c doadj.sh
X
Xall: $(PROGRAMS)
X
Xadjtime: adjtime.o
X	$(CC) $(CFLAGS) -o $@ $@.o
X
Xtclock: tclock.o
X	$(CC) $(CFLAGS) -o $@ $@.o
X
Xdoadj: doadj.sh
X	cp $@.sh $@
X	chmod +x $@
X
Xclean:
X	rm -f $(PROGRAMS) *.o
X
Xsoftclock.shar: $(FILES)
X	shar -o softclock.shar $(FILES)
X
END_OF_FILE
if test 368 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'adjtime.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'adjtime.c'\"
else
echo shar: Extracting \"'adjtime.c'\" \(1799 characters\)
sed "s/^X//" >'adjtime.c' <<'END_OF_FILE'
X/******************************************************************************
X*
X*	ADJTIME - Apply the adjtime call with the value on the command
X*	line.  Reports value of pending adjtime which you just wiped
X*	out (see adjtime(2)).  Takes only one parameter: a floating
X*	point number which is the number of seconds to adjust by.
X*	Positive numbers speed up the clock, negative numbers slow
X*	it down.
X*
X*	This program must be run by root to have any effect.
X*
X*	You probably want to have tickadj set to a large value, say
X*	tick/10 (normal value).  If you have a small value for ntp,
X*	you may want to temporarily run "tickadj -a 1000" before
X*	running adjtime and "tickadj -A" after running adjtime and
X*	after the clock has come into the value you want.
X*
X*	This program makes it a little easier to get the system clock
X*	set to the proper time in the face of delays running date(1).
X*
X******************************************************************************/
X
X#include <stdio.h>
X#include <ctype.h>
X#include <sys/time.h>
X
Xdouble atof();
Xvoid doadjtime();
X
X#define issign(x)	(((x)=='-')||((x)=='+'))
X
Xvoid main( argc, argv )
Xint	argc;
Xchar	*argv[];
X{
X    double diff;
X    char *val;
X
X    if ( argc < 2 )
X	usage();
X    val = argv[1];
X    if ( isdigit(val[0]) || ( isdigit(val[1]) && issign(val[0]) ) ){
X	diff = atof(argv[1]);
X	doadjtime(diff);
X    }else
X	usage();
X}
X
Xint usage()
X{
X    fprintf(stderr,"usage: adjtime seconds\n");
X    exit(-1);
X}
X
Xvoid doadjtime(diff)
Xdouble	diff;
X{
X    struct timeval tp, otp;
X
X    tp.tv_sec = (long)diff;
X    tp.tv_usec = (long)(1000000 * (diff - tp.tv_sec));
X    printf("adjusting %ld seconds, %ld useconds\n",tp.tv_sec,tp.tv_usec);
X    if ( adjtime( &tp, &otp ) ){
X	perror("adjtime");
X	exit(-1);
X    }else
X	printf("%ld %ld\n",otp.tv_sec,otp.tv_usec);
X}
X
END_OF_FILE
if test 1799 -ne `wc -c <'adjtime.c'`; then
    echo shar: \"'adjtime.c'\" unpacked with wrong size!
fi
# end of 'adjtime.c'
fi
if test -f 'tclock.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'tclock.c'\"
else
echo shar: Extracting \"'tclock.c'\" \(2924 characters\)
sed "s/^X//" >'tclock.c' <<'END_OF_FILE'
X/******************************************************************************
X*
X*	TCLOCK - This program prints a text clock.  It tries to do it
X*	ten times per second.  It prints out accurate to 1/100th of
X*	a second.  Quit with SIGINT (usually control-C).
X*
X*	Needed Library Routines:
X*
X*		gettimeofday(2)
X*		setitimer(2)
X*		sigpause(2)
X*		sigsetmask(2)
X*
X*		exit(3)
X*		fflush(3)
X*		localtime(3)
X*		printf(3)
X*		signal(3)
X*
X******************************************************************************/
X
X#include <stdio.h>
X#include <sys/time.h>
X#include <sys/signal.h>
X
X/* set FREQ to the number of microseconds to sleep between printouts
X   I try to get it so that it prints out every 0.1 seconds.  Due to
X   program overhead and resource sharing, this is usually a bit less
X   than 100000 microseconds (=0.1 seconds).  If you get it right, the
X   hundredths place will stay constant. */
X
X#define	FREQ	99990
X
Xvoid fsleep();
X
X/* cheap signal handler */
Xint
Xhandler()
X{
X    printf("\n");
X    exit(0);
X}
X
X/******************************************************************************
X*
X*	Main program.
X*		Just an infinite loop getting and printing out the time.
X*		Sets up a signal handler to abort on SIGINT or SIGTERM.
X*
X*	Library routines:
X*		gettimeofday(2)
X*		fflush(3)
X*		localtime(3)
X*		printf(3)
X*		signal(3)
X*
X******************************************************************************/
Xvoid
Xmain()
X{
X    struct tm *tp;
X    struct timeval tv;
X    struct timezone tz;
X
X    signal( SIGINT, handler );
X    signal( SIGTERM, handler );
X    while ( 1 ){
X	gettimeofday( &tv, &tz );
X	tp = localtime(&tv.tv_sec);
X	printf("\r%02d:%02d:%02d.%02d", tp->tm_hour, tp->tm_min, tp->tm_sec,
X							tv.tv_usec/10000 );
X	fflush(stdout);
X	fsleep( (unsigned long)0, (unsigned long)FREQ );
X    }
X}
X
Xstatic void
Xfsleeptrap()
X{
X	/* Zen function */
X}
X
X/******************************************************************************
X*
X*	FSLEEP - Fine sleep function; sleeps at resolution of the
X*	interval timer (see setitimer(2)) or microseconds; whichever
X*	is worse.
X*
X*	Library routines:
X*		setitimer(2)
X*		sigpause(2)
X*		sigsetmask(2)
X*		signal(3)
X*
X******************************************************************************/
Xvoid
Xfsleep( secs, usecs )
Xunsigned long secs, usecs;
X{
X    int  omask, (*osig)();
X    struct itimerval tval[2];
X
X	/* setup */
X    osig = signal( SIGALRM, fsleeptrap );
X
X    if ( usecs >= 1000000L ){
X	secs += usecs / 1000000L;
X	usecs %= 1000000L;
X    }
X    tval[1].it_interval.tv_sec = 0L;
X    tval[1].it_interval.tv_usec = 0L;
X    tval[1].it_value.tv_sec = secs;
X    tval[1].it_value.tv_usec = usecs;
X
X	/* more setup */
X    omask = sigsetmask( ( 1 << (SIGALRM-1) ) );
X    setitimer( ITIMER_REAL, &tval[1], &tval[0] );
X
X	/* wait for interrupt */
X    sigpause( 0 );
X
X	/* cleanup */
X    signal( SIGALRM, osig );
X    setitimer( ITIMER_REAL, &tval[0], &tval[1] );
X    sigsetmask( omask );
X
X    return;
X}
END_OF_FILE
if test 2924 -ne `wc -c <'tclock.c'`; then
    echo shar: \"'tclock.c'\" unpacked with wrong size!
fi
# end of 'tclock.c'
fi
if test -f 'doadj.sh' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'doadj.sh'\"
else
echo shar: Extracting \"'doadj.sh'\" \(698 characters\)
sed "s/^X//" >'doadj.sh' <<'END_OF_FILE'
X#!/bin/sh -x
X#
X# This script temporarily changes tickadj and runs adjtime to fix your
X# system time.  It's only parameter is the amount of time to adjust by
X# which is passed to adjtime.
X#
X# set path so that you can find tickadj and adjtime
X#
XPATH="$PATH:/usr/local/etc"
X#
X# find tick/10 so you can make large adjustments with adjtime.
X#
Xticka=`echo tick/D |adb -k /vmunix /dev/mem |grep tick |awk '{printf("%d\n",$2/10)}'`
X#
X# set tickadj to a large value and do the adjtime.
X#
Xtickadj -a $ticka
Xadjtime $1
X#
X# sleep long enough for the adjtime to finish.
X#
Xtim=`echo $1 | awk '{s=$1;if(s<0){s=-1*s};printf("%d\n",((10*s)+0.5))}'`
Xsleep $tim
X#
X# Restore tickadj to it's proper value.
X#
Xtickadj -A
END_OF_FILE
if test 698 -ne `wc -c <'doadj.sh'`; then
    echo shar: \"'doadj.sh'\" unpacked with wrong size!
fi
# end of 'doadj.sh'
fi
echo shar: End of shell archive.
exit 0