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