]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
Many files:
authorHarlan Stenn <stenn@ntp.org>
Sun, 8 Aug 1999 20:36:15 +0000 (20:36 -0000)
committerHarlan Stenn <stenn@ntp.org>
Sun, 8 Aug 1999 20:36:15 +0000 (20:36 -0000)
  * include/ntp.h: Y2KFixes
  * libparse/parse.c: Ditto
  * ntpd/Makefile.am (check_PROGRAMS): Ditto
  * ntpd/refclock_acts.c: Ditto
  * ntpd/refclock_arc.c (arc_receive): Ditto
  * ntpd/refclock_heath.c: Ditto
  * ntpd/refclock_hpgps.c: Ditto
  * parseutil/Makefile.am (check-local): Ditto
  * parseutil/dcfd.c (check_y2k): Ditto
  * NOTES.y2kfixes: Ditto
  * readme.y2kfixes: Ditto
  * results.y2kfixes: Ditto
  * ntpd/check_y2k.c: Ditto
  From: y2k@y2k.labs.att.com

bk: 37adea3fVeCkp-P5ccAMpsuBz_L8UQ

14 files changed:
ChangeLog
NOTES.y2kfixes [new file with mode: 0644]
include/ntp.h
libparse/parse.c
ntpd/Makefile.am
ntpd/Makefile.in
ntpd/check_y2k.c [new file with mode: 0644]
ntpd/refclock_acts.c
ntpd/refclock_arc.c
ntpd/refclock_heath.c
ntpd/refclock_hpgps.c
parseutil/dcfd.c
readme.y2kfixes [new file with mode: 0644]
results.y2kfixes [new file with mode: 0644]

index 4016d79d9ad8b7f2f7ae9386559bce5a037f34f4..fd65d14aa34fe5695fa87bc87b3d5829c62d50b1 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+1999-08-08  Harlan Stenn  <stenn@whimsy.udel.edu>
+
+       * include/ntp.h: Y2KFixes
+       * libparse/parse.c: Ditto
+       * ntpd/Makefile.am (check_PROGRAMS): Ditto
+       * ntpd/refclock_acts.c: Ditto
+       * ntpd/refclock_arc.c (arc_receive): Ditto
+       * ntpd/refclock_heath.c: Ditto
+       * ntpd/refclock_hpgps.c: Ditto
+       * parseutil/Makefile.am (check-local): Ditto
+       * parseutil/dcfd.c (check_y2k): Ditto
+       * NOTES.y2kfixes: Ditto
+       * readme.y2kfixes: Ditto
+       * results.y2kfixes: Ditto
+       * ntpd/check_y2k.c: Ditto
+       From: y2k@y2k.labs.att.com
+
 1999-08-07  Harlan Stenn  <stenn@whimsy.udel.edu>
 
        * configure.in: Look for sys/ppstime.h.
diff --git a/NOTES.y2kfixes b/NOTES.y2kfixes
new file mode 100644 (file)
index 0000000..c3027a1
--- /dev/null
@@ -0,0 +1,104 @@
+Name of the Application: xntp
+
+Version Number:  4.0.91
+
+Download Size: 4541953 bytes
+
+Downloaded from: http://www.eecis.udel.edu/~ntp/
+
+Operating Systems Supported: many
+
+Operating Systems Tested: unix
+
+Testing
+
+Dates tested (CPU clock set)
+
+       1999-12-31
+       2000-01-01
+       2000-02-29
+
+       Critical fragments of code tested with other dates by special
+       algorithms.
+
+Hardware Platform: Sun Sparc
+
+OS: Solaris 2.6
+
+Compiler: gcc
+
+Version: 2.8.1
+
+Repairs:  9
+
+No. of files Repaired: 13
+
+
+Compilation of Patches Required: yes
+
+Results Description:
+
+1)     Tested suspicious code.
+
+2)     Repaired problem code and added documentation to ntp.h.
+
+3)     Verified ntpd works on critical Y2K dates.
+
+
+Comments:
+
+1)     Errors were found in improper use of tm_year within struct tm,
+       calculations that did not support year 2000 as a leap year
+       (it truly is, despite any unchanged comments remaining in 
+       the NTP source), and some incorrect date calculations, while
+       not traditional Y2K errors, would break in the year 2000.
+
+2)     include/ntpd.h
+       Added some definitions and documentation about the right way
+        of doing things.  Definitions used by most, if not all, of
+        the Y2K repairs.
+
+Cautions:
+
+1)     Some of the Y2K repairs were to reference clock drivers that
+       we did not have the local hardware to test.  While I believe
+       the changes are sound, they really need to be tested.
+       This includes:
+
+               refclock_arc.c
+               refclock_heath.c
+               refclock_hpgps.c
+
+       Also, parseutil/dcfd.c is another hardware dependent module that
+       was repaired without live testing.
+
+Non-Y2K Problems Observed:
+
+1)     Inconsistent casts of variables containing time values may
+       make expansion to 64 bit integer values in a portable manner
+       difficult.
+
+2)     libntp/caltontp.c:
+        Has logic I believe will fail starting in year 2100 or so.
+        Left unchanged/untested as it works well beyond basic NTP 2036 
+       limit checked by check_y2k.c.
+        If NTP is implemented on 64-bit machines, this should be fixed
+
+3)     ntpd/refclock_acts.c:
+       ACTS time format has changed somewhat since the code was written.
+       In particular the '*' '#' character switch no longer occurs...
+       only '*' is typed.
+
+      NOTE: Author (falsely) stated Y2K is NOT a leap year when it 
+      really is.
+
+      TRUTH: ACTS will go beyond Y2K: it uses FourDigitYear % 100 values
+      for year so year 2000 will revert to "00".
+
+
+4)     ntpd/refclock_oncore.c
+       Some very strange logic in manipulating year values:
+       1122         instance->pp->year = buf[6]*256+buf[7];
+       Multiply by 256????
+
index ecd4daf43161f364ca42f63774e32dcb43724a94..68922b49ff1f3d3474f4706fe53448622ad96401 100644 (file)
@@ -8,6 +8,55 @@
 #include "ntp_types.h"
 #include <math.h>
 
+       /* common definitions for Y2K repairs                   [ Y2KFixes */
+
+               /* (this might better be put in ntp_calendar.h) */
+#define YEAR_BREAK 500         /* assume years < this are tm_year values: */
+                                   /*    Break < AnyFourDigitYear
+                                      && Break > Anytm_yearYear */
+#define YEAR_PIVOT 98          /* 97/98: assume years < this are year 2000+ */
+       /* FYI: official UNIX pivot year is 68/69 */
+
+  /* Number of Days since (mythical) 1.BC Gregorian to 1 January of given year*/
+#define julian0(year) \
+       (       \
+         ( (year) * 365 ) + ( (year) > 0       \
+               ? ( ((year)+3) / 4 - ((year-1) / 100) + ((year-1) / 400) )  \
+               : 0 ) \
+       )
+
+  /* Number of days since start of NTP time to 1 January of given year */
+#define ntp0(year)  ( julian0(year) - julian0(1900) )
+
+  /* Number of days since start of UNIX time to 1 January of given year */
+#define unix0(year)  ( julian0(year) - julian0(1970) )
+
+  /* LEAP YEAR test for full 4-digit years (e.g, 1999, 2010) */
+#define isleap_4(y)     /* a TRUE and PROPER leap year test */ \
+                  ((y)%4 == 0 && !((y)%100 == 0 && !(y%400 == 0)))
+           /* NOTE: year 2000 TRULY IS A LEAP YEAR!!! */
+
+  /* LEAP YEAR test for tm_year (struct tm) years (e.g, 99, 110) */
+#define isleap_tm(y)     /* a TRUE and PROPER leap year test */ \
+                  ((y)%4 == 0 && !((y)%100 == 0 && !(((y)+1900)%400 == 0)))
+
+  /* to convert simple two-digit years to tm_year style years:
+       if ( year < YEAR_PIVOT ) year += 100;
+
+   * to convert either two-digit OR tm_year years to four-digit years:
+       if ( year < YEAR_PIVOT ) year += 100;
+       if ( year < YEAR_BREAK ) year += 1900;
+
+ CALL TO STANDARD:
+   * As the Internet is an INTERNATIONAL network, it makes SENSE to use
+     the international standard ISO 8601 to format dates and times.
+     Basically this is yyyy-mm-dd for years and hh:mm:ss for times
+     (joining the two togeather in computer readable media calls for
+     yyyy-mm-ddThh:mm:ss, though yyyy-mm-dd hh:mm:ss is often used
+     for human readable forms even though it is not not strictly
+     valid ISO 8601). Standard time-zone offsets ([+-]hh:mm) are allowed.
+                                       ghealton                 ] Y2KFixes */
+
 /*
  * How to get signed characters.  On machines where signed char works,
  * use it.  On machines where signed char doesn't work, char had better
index 727a32b70494bbe68a3ac05d3330b0852f0bfea2..cb59a397d7db751a8deaf234b6a3ef7fb65e9dd1 100644 (file)
@@ -54,6 +54,7 @@ static char rcsid[] = "parse.c,v 4.13 1999/02/28 11:50:20 kardel RELEASE_1999022
 #include "ntp_machine.h"
 
 #include "parse.h"
+#include "ntp.h"               /* (get Y2KFixes definitions)   Y2KFixes */
 
 #ifndef PARSESTREAM
 #include <stdio.h>
@@ -417,13 +418,12 @@ parse_to_unixtime(
        if (clock_time->utctime)
            return clock_time->utctime; /* if the conversion routine gets it right away - why not */
 
-       if (clock_time->year < 100)
+       if ( clock_time->year < YEAR_PIVOT )                    /* Y2KFixes [ */
+           clock_time->year += 100;    /* convert 20xx%100 to 20xx-1900 */
+       if ( clock_time->year < YEAR_BREAK )    /* expand to full four-digits */
            clock_time->year += 1900;
 
-       if (clock_time->year < 1998)
-           clock_time->year += 100;            /* XXX this will do it till <2098 */
-
-       if (clock_time->year < 1998)
+       if (clock_time->year < 1970 )                           /* Y2KFixes ] */
        {
                SETRTC(CVT_FAIL|CVT_BADDATE);
                return -1;
@@ -432,20 +432,22 @@ parse_to_unixtime(
        /*
         * sorry, slow section here - but it's not time critical anyway
         */
-       t =  (clock_time->year - 1970) * 365;
-       t += (clock_time->year >> 2) - (1970 >> 2);
-       t -= clock_time->year / 100 - 1970 / 100;
-       t += clock_time->year / 400 - 1970 / 400;
-
+       t = julian0(clock_time->year) - julian0(1970);          /* Y2kFixes */
                                /* month */
        if (clock_time->month <= 0 || clock_time->month > 12)
        {
                SETRTC(CVT_FAIL|CVT_BADDATE);
                return -1;              /* bad month */
        }
+
+#if 0                                                          /* Y2KFixes */
                                /* adjust leap year */
        if (clock_time->month < 3 && days_per_year(clock_time->year) == 366)
            t--;
+#else                                                          /* Y2KFixes [ */
+       if ( clock_time->month >= 3  &&  isleap_4(clock_time->year) )
+           t++;                /* add one more if within leap year */
+#endif                                                         /* Y2KFixes ] */
 
        for (i = 1; i < clock_time->month; i++)
        {
index 83e024b62da6f21387949f9e9b9881eb634c49ba..6947061c42cfa9b7c29e36d1b4aa8b89ca9199d0 100644 (file)
@@ -8,6 +8,8 @@ ntpd_LDADD = $(LDADD) -lm
 DISTCLEANFILES = .version version.c
 #EXTRA_DIST = ntpd.mak
 ETAGS_ARGS = Makefile.am
+###                                                    Y2Kfixes
+check_PROGRAMS = check_y2k
 
 ntpd_SOURCES = map_vme.c ntp_config.c ntp_control.c ntp_io.c \
        ntp_loopfilter.c ntp_monitor.c ntp_peer.c ntp_proto.c \
index 9a5d8bb6535821962b12a91fd2becf96eaa453f6..dfdb643204243ee3dbd14f9dd04d15f368783872 100644 (file)
@@ -98,6 +98,8 @@ VERSION = @VERSION@
 
 AUTOMAKE_OPTIONS = ../util/ansi2knr
 bin_PROGRAMS = ntpd
+                                                       #       Y2Kfixes
+check_PROGRAMS = check_y2k
 INCLUDES = -I$(top_srcdir)/include
 # LDADD might need RESLIB and ADJLIB
 LDADD = version.o @LIBPARSE@ ../libntp/libntp.a @LIBRSAREF@
@@ -292,6 +294,16 @@ refclock_oncore$U.o:
 refclock_chronolog$U.o:
 refclock_dumbclock$U.o:
 
+                                                               #Y2Kfixes [
+check_y2k.o: Makefile check_y2k.c ../config.h \
+           ../include/ntp.h ../include/ntpd.h ../include/ntp_calendar.h
+       $(COMPILE) -o check_y2k.o -c check_y2k.c
+
+check_y2k: check_y2k.o 
+       @if [ -f check_y2k ]; then rm -f check_y2k; fi
+       $(LINK) $(ntpd_LDFLAGS) check_y2k.o $(ntpd_LDADD) $(LIBS)
+                                                               #Y2Kfixes ]
+
 ntpd: $(ntpd_OBJECTS) $(ntpd_DEPENDENCIES)
        @rm -f ntpd
        $(LINK) $(ntpd_LDFLAGS) $(ntpd_OBJECTS) $(ntpd_LDADD) $(LIBS)
diff --git a/ntpd/check_y2k.c b/ntpd/check_y2k.c
new file mode 100644 (file)
index 0000000..3cc05fc
--- /dev/null
@@ -0,0 +1,624 @@
+/* check_y2k.c -- test ntp code constructs for Y2K correctness         Y2KFixes [*/
+
+  /*
+       Code invoked by `make check`. Not part of ntpd and not to be
+       installed.
+
+       On any code I even wonder about, I've cut and pasted the code
+       here and ran it as a test case just to be sure.
+
+       For code not in "ntpd" proper, we have tried to call most 
+       repaired functions from herein to properly test them
+       (something never done before!). This has found several bugs,
+       not normal Y2K bugs, that will strike in Y2K so repair them
+       we did.
+
+       Program exits with 0 on success, 1 on Y2K failure (stdout messages).
+       Exit of 2 indicates internal logic bug detected OR failure of
+       what should be our correct formulas.
+
+       While "make check" should only check logic for source within that
+       specific directory, this check goes outside the scope of the local
+       directory.  It's not a perfect world (besides, there is a lot of
+       interdependence here, and it really needs to be tested in
+       a controled order).
+   */
+
+/* { definitions lifted from ntpd.c to allow us to complie with 
+     "#include ntp.h".  I have not taken the time to reduce the clutter. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#include <stdio.h>
+#include <errno.h>
+#ifndef SYS_WINNT
+# if !defined(VMS)     /*wjm*/
+#  include <sys/param.h>
+# endif /* VMS */
+# include <sys/signal.h>
+# ifdef HAVE_SYS_IOCTL_H
+#  include <sys/ioctl.h>
+# endif /* HAVE_SYS_IOCTL_H */
+# include <sys/time.h>
+# if !defined(VMS)     /*wjm*/
+#  include <sys/resource.h>
+# endif /* VMS */
+#else
+# include <signal.h>
+# include <process.h>
+# include <io.h>
+# include "../libntp/log.h"
+#endif /* SYS_WINNT */
+#if defined(HAVE_RTPRIO)
+# ifdef HAVE_SYS_RESOURCE_H
+#  include <sys/resource.h>
+# endif
+# ifdef HAVE_SYS_LOCK_H
+#  include <sys/lock.h>
+# endif
+# include <sys/rtprio.h>
+#else
+# ifdef HAVE_PLOCK
+#  ifdef HAVE_SYS_LOCK_H
+#      include <sys/lock.h>
+#  endif
+# endif
+#endif
+#if defined(HAVE_SCHED_SETSCHEDULER)
+# ifdef HAVE_SCHED_H
+#  include <sched.h>
+# else
+#  ifdef HAVE_SYS_SCHED_H
+#   include <sys/sched.h>
+#  endif
+# endif
+#endif
+#if defined(HAVE_SYS_MMAN_H)
+# include <sys/mman.h>
+#endif
+
+#ifdef HAVE_TERMIOS_H
+# include <termios.h>
+#endif
+
+#ifdef SYS_DOMAINOS
+# include <apollo/base.h>
+#endif /* SYS_DOMAINOS */
+
+#include "ntpd.h"
+
+/* } end definitions lifted from ntpd.c */
+
+#include "ntp_calendar.h"
+#include "parse.h"
+
+#define GoodLeap(Year) (((Year)%4 || (!((Year)%100) && (Year)%400)) ? 0 : 13 )
+
+int debug = 0;                 /* debugging requests for parse stuff */
+char const *progname = "check_y2k";
+
+long Days ( int Year )         /* return number of days since year "0" */
+{
+    long  Return;
+               /* this is a known to be good algorithm */
+    Return = Year * 365;       /* first aproximation to the value */
+    if ( Year >= 1 )
+    {          /* see notes in libparse/parse.c if you want a PROPER
+                * **generic algorithm. */
+       Return += (Year+3) / 4;         /* add in (too many) leap days */
+       Return -= (Year-1) / 100;       /* reduce by (too many) centurys */
+       Return += (Year-1) / 400;       /* get final answer */
+    }
+
+    return Return;
+}
+
+static int  year0 = 1900;      /* sarting year for NTP time */
+static int  yearend;           /* ending year we test for NTP time.
+                                   * 32-bit systems: through 2036, the
+                                     **year in which NTP time overflows.
+                                   * 64-bit systems: a reasonable upper
+                                     **limit (well, maybe somewhat beyond
+                                     **reasonable, but well before the
+                                     **max time, by which time the earth
+                                     **will be dead.) */
+static time_t Time;
+static struct tm LocalTime;
+
+#define Error(year) if ( (year)>=2036 && LocalTime.tm_year < 110 ) \
+       Warnings++; else Fatals++
+
+int main( void )
+{
+    int Fatals;
+    int Warnings;
+    int  year;
+
+    Time = time( (time_t *)NULL )
+#ifdef TESTTIMEOFFSET
+               + test_time_offset
+#endif
+       ;
+    LocalTime = *localtime( &Time );
+
+    year = ( sizeof( u_long ) > 4 )    /* save max span using year as temp */
+               ? ( 400 * 3 )           /* three greater gregorian cycles */
+               : ((int)(0x7FFFFFFF / 365.242 / 24/60/60)* 2 ); /*32-bit limit*/
+                       /* NOTE: will automacially expand test years on
+                        * 64 bit machines.... this may cause some of the
+                        * existing ntp logic to fail for years beyond
+                        * 2036 (the current 32-bit limit). If all checks
+                        * fail ONLY beyond year 2036 you may ignore such
+                        * errors, at least for a decade or so. */
+    yearend = year0 + year;
+
+    puts( " internal self check" );
+  {            /* verify our own logic used to verify repairs */
+    unsigned long days;
+
+    if ( year0 >= yearend )
+    {
+       fprintf( stdout, "year0=%d NOT LESS THAN yearend=%d  (span=%d)\n",
+               (int)year0, (int)yearend, (int)year );
+       exit(2);
+    }
+
+   {
+    int  save_year;
+
+    save_year = LocalTime.tm_year;     /* save current year */
+
+    year = 1980;
+    LocalTime.tm_year = year - 1900;
+    Fatals = Warnings = 0;
+    Error(year);               /* should increment Fatals */
+    if ( Fatals == 0 ) 
+    {
+       fprintf( stdout, 
+           "%4d: %s(%d): FATAL DID NOT INCREMENT  (Fatals=%d Warnings=%d)\n",
+           (int)year, __FILE__, __LINE__, (int)Fatals, (int)Warnings );
+       exit(2);
+    }
+
+    year = 2100;               /* test year > limit but CURRENT year < limit */
+    Fatals = Warnings = 0;
+    Error(year);               /* should increment Fatals */
+    if ( Warnings == 0 ) 
+    {
+       fprintf( stdout, 
+           "%4d: %s(%d): WARNING DID NOT INCREMENT  (Fatals=%d Warnings=%d)\n",
+           (int)year, __FILE__, __LINE__, (int)Fatals, (int)Warnings );
+       exit(2);
+    }
+    Fatals = Warnings = 0;
+    LocalTime.tm_year = year - 1900;   /* everything > limit */
+    Error(1980);               /* should increment Fatals */
+    if ( Fatals == 0 ) 
+    {
+       fprintf( stdout, 
+           "%4d: %s(%d): FATALS DID NOT INCREMENT  (Fatals=%d Warnings=%d)\n",
+           (int)year, __FILE__, __LINE__, (int)Fatals, (int)Warnings );
+       exit(2);
+    }
+
+    LocalTime.tm_year = save_year;
+   }
+
+    days = 365+1;              /* days in year 0 + 1 more day */
+    for ( year = 1; year <= 2500; year++ )
+    {
+       long   Test;
+       Test = Days( year );
+       if ( days != Test )
+       {
+           fprintf( stdout, "%04d: Days() DAY COUNT ERROR: s/b=%ld was=%ld\n", 
+               year, (long)days, (long)Test );
+           exit(2);            /* would throw off many other tests */
+       }
+
+       Test = julian0(year);           /* compare with julian0() macro */
+       if ( days != Test )
+       {
+           fprintf( stdout, "%04d: julian0() DAY COUNT ERROR: s/b=%ld was=%ld\n", 
+               year, (long)days, (long)Test );
+           exit(2);            /* would throw off many other tests */
+       }
+
+       days += 365;
+       if ( isleap_4(year) ) days++;
+    }
+
+    if ( isleap_4(1999) )
+    {
+       fprintf( stdout, "isleap_4(1999) REPORTED TRUE\n" );
+       exit(2);
+    }
+    if ( !isleap_4(2000) )
+    {
+       fprintf( stdout, "isleap_4(2000) REPORTED FALSE\n" );
+       exit(2);
+    }
+    if ( isleap_4(2001) )
+    {
+       fprintf( stdout, "isleap_4(1999) REPORTED TRUE\n" );
+       exit(2);
+    }
+
+    if ( !isleap_tm(2000-1900) )
+    {
+       fprintf( stdout, "isleap_tm(100) REPORTED FALSE\n" );
+       exit(2);
+    }
+  }
+
+    Fatals = Warnings = 0;
+
+    puts( " include/ntp.h" );
+  {            /* test our new isleap_*() #define "functions" */
+    
+    for ( year = 1400; year <= 2200; year++ )
+    {
+       int  LeapSw;
+       int  IsLeapSw;
+
+       LeapSw = GoodLeap(year);
+       IsLeapSw = isleap_4(year);
+
+       if ( !!LeapSw != !!IsLeapSw )
+       {
+           Error(year);
+           fprintf( stdout, 
+               "  %4d %2d %3d *** ERROR\n", year, LeapSw, IsLeapSw );
+           break;
+       }
+
+       IsLeapSw = isleap_tm(year-1900);
+
+       if ( !!LeapSw != !!IsLeapSw )
+       {
+           Error(year);
+           fprintf( stdout, 
+               "  %4d %2d %3d *** ERROR\n", year, LeapSw, IsLeapSw );
+           break;
+       }
+    }
+  }
+
+    puts( " include/ntp_calendar.h" );
+  {            /* I belive this is good, but just to be sure... */
+
+       /* we are testing this #define */
+#define is_leapyear(y) (y%4 == 0 && !(y%100 == 0 && !(y%400 == 0)))
+
+    for ( year = 1400; year <= 2200; year++ )
+    {
+       int  LeapSw;
+
+       LeapSw = GoodLeap(year);
+
+       if ( !(!LeapSw) != !(!is_leapyear(year)) )
+       {
+           Error(year);
+           fprintf( stdout, 
+               "  %4d %2d *** ERROR\n", year, LeapSw );
+           break;
+       }
+    }
+  }   
+
+
+    puts( " libparse/parse.c" );
+  { 
+    long Days1970;     /* days from 1900 to 1970 */
+
+    struct ParseTime   /* womp up a test structure to all cut/paste code */
+    {
+       int   year;
+    } Clock_Time, *clock_time;
+
+    clock_time = &Clock_Time;
+
+       /* first test this #define */
+#define days_per_year(x)  ((x) % 4 ? 365 : ((x % 400) ? ((x % 100) ? 366 : 365) : 366))
+
+    for ( year = 1400; year <= 2200; year++ )
+    {
+       int  LeapSw;
+       int  DayCnt;
+
+       LeapSw = GoodLeap(year);
+       DayCnt = (int)days_per_year(year);
+
+       if ( ( LeapSw ? 366 : 365 ) != DayCnt )
+       {
+           Error(year);
+           fprintf( stdout, 
+                   "  days_per_year() %4d %2d %3d *** ERROR\n", 
+                   year, LeapSw, DayCnt );
+           break;
+       }
+    }
+
+    /* test (what is now julian0) calculations */
+
+    Days1970 = Days( 1970 );   /* get days since 1970 using a known good */
+
+    for ( year = 1970; year < yearend; year++ )
+    {                          
+       unsigned long t;
+       long DaysYear ;
+
+       clock_time->year = year;
+
+       /* here is the code we are testing, cut and pasted out of the source */
+#if 0          /* old BUGGY code that has Y2K (and many other) failures */
+           /* ghealton: this logic FAILED with great frequency when run
+            * over a period of time, including for year 2000. True, it
+            * had more successes than failures, but that's not really good
+            * enough for critical time distribution software.
+            * It is so awful I wonder if it has had a history of failure 
+            * and fixes? */
+        t =  (clock_time->year - 1970) * 365;
+        t += (clock_time->year >> 2) - (1970 >> 2);
+        t -= clock_time->year / 100 - 1970 / 100;
+        t += clock_time->year / 400 - 1970 / 400;
+
+               /* (immediate feare of rounding errors on integer
+                * **divisions proved well founded) */
+
+#else
+       /* my replacement, based on Days() above */
+       t = julian0(year) - julian0(1970);
+#endif
+
+       /* compare result in t against trusted calculations */
+       DaysYear = Days( year );        /* get days to this year */
+       if ( t != DaysYear - Days1970 )
+       {
+           Error(year);
+           fprintf( stdout, 
+               "  %4d 1970=%-8ld %4d=%-8ld %-3ld  t=%-8ld  *** ERROR ***\n",
+                 year,      (long)Days1970,
+                                year,
+                                    (long)DaysYear,
+                                          (long)(DaysYear - Days1970),
+                                                  (long)t );
+       }
+    }
+
+#if 1          /* { */
+   {
+    debug = 1;                 /* enable debugging */
+    for ( year = 1970; year < yearend; year++ )
+    {          /* (limited by theory unix 2038 related bug lives by, but
+                * ends in yearend) */
+       clocktime_t  ct;
+       time_t       Observed;
+       time_t       Expected;
+       u_long       Flag;
+       unsigned long t;
+
+       ct.day = 1;
+       ct.month = 1;
+       ct.year = year;
+       ct.hour = ct.minute = ct.second = ct.usecond = 0;
+       ct.utcoffset = 0;
+       ct.utctime = 0;
+       ct.flags = 0;
+
+       Flag = 0;
+       Observed = parse_to_unixtime( &ct, &Flag );
+       if ( ct.year != year )
+       {
+           fprintf( stdout, 
+              "%04d: parse_to_unixtime(,%d) CORRUPTED ct.year: was %d\n",
+              (int)year, (int)Flag, (int)ct.year );
+           Error(year);
+           break;
+       }
+       t = julian0(year) - julian0(1970);      /* Julian day from 1970 */
+       Expected = t * 24 * 60 * 60;
+       if ( Observed != Expected  ||  Flag )
+       {   /* time difference */
+           fprintf( stdout, 
+              "%04d: parse_to_unixtime(,%d) FAILURE: was=%lu s/b=%lu  (%ld)\n",
+              year, (int)Flag, 
+              (unsigned long)Observed, (unsigned long)Expected,
+              ((long)Observed - (long)Expected) );
+           Error(year);
+           break;
+       }
+
+       if ( year >= YEAR_PIVOT+1900 )
+       {
+           /* check year % 100 code we put into parse_to_unixtime() */
+           ct.utctime = 0;
+           ct.year = year % 100;
+           Flag = 0;
+
+           Observed = parse_to_unixtime( &ct, &Flag );
+
+           if ( Observed != Expected  ||  Flag )
+           {   /* time difference */
+               fprintf( stdout, 
+"%04d: parse_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu  (%ld)\n",
+                  year, (int)ct.year, (int)Flag, 
+                  (unsigned long)Observed, (unsigned long)Expected,
+                  ((long)Observed - (long)Expected) );
+               Error(year);
+               break;
+           }
+
+           /* check year - 1900 code we put into parse_to_unixtime() */
+           ct.utctime = 0;
+           ct.year = year - 1900;
+           Flag = 0;
+
+           Observed = parse_to_unixtime( &ct, &Flag );
+
+           if ( Observed != Expected  ||  Flag )
+           {   /* time difference */
+               fprintf( stdout, 
+"%04d: parse_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu  (%ld)\n",
+                  year, (int)ct.year, (int)Flag, 
+                  (unsigned long)Observed, (unsigned long)Expected,
+                  ((long)Observed - (long)Expected) );
+               Error(year);
+               break;
+           }
+
+
+       }
+    }
+#endif         /* } */
+   }
+  }
+
+    puts( " libntp/caljulian.c" );
+  {            /* test caljulian() */
+    struct     calendar  ot;
+    u_long ntp_time;           /* NTP time */
+
+    year = year0;              /* calculate the basic year */
+    printf( "  starting year %04d\n", (int)year0 );
+    printf( "  ending year   %04d\n", (int)yearend );
+
+
+    ntp_time = julian0( year0 );               /* NTP starts in 1900-01-01 */
+#if DAY_NTP_STARTS == 693596
+    ntp_time -= 365;           /* BIAS required for successful test */
+#endif
+    if ( DAY_NTP_STARTS != ntp_time )
+    {
+       Error(year);
+       fprintf( stdout, 
+               "%04d: DAY_NTP_STARTS (%ld) NOT TRUE VALUE OF %ld (%ld)\n",
+               (int)year0,
+               (long)DAY_NTP_STARTS,  (long)ntp_time,
+               (long)DAY_NTP_STARTS - (long)ntp_time );
+    }
+
+    for ( ; year < yearend; year++ )
+    {
+       
+       /* 01-01 for the current year */
+       ntp_time = Days( year ) - Days( year0 );  /* days into NTP time */
+       ntp_time *= 24 * 60 * 60;       /* convert into seconds */
+       caljulian( ntp_time, &ot );     /* convert January 1 */
+       if ( ot.year  != year
+         || ot.month != 1
+         || ot.monthday != 1 )
+       {
+           Error(year);
+           fprintf( stdout, "%lu: EXPECTED %04d-01-01: FOUND %04d-%02d-%02d\n",
+                       (unsigned long)ntp_time,
+                       year, 
+                       (int)ot.year, (int)ot.month, (int)ot.monthday );
+           break;
+       }
+
+       ntp_time += (31 + 28-1) * ( 24 * 60 * 60 );     /* advance to 02-28 */
+       caljulian( ntp_time, &ot );     /* convert Feb 28 */
+       if ( ot.year  != year
+         || ot.month != 2
+         || ot.monthday != 28 )
+       {
+           Error(year);
+           fprintf( stdout, "%lu: EXPECTED %04d-02-28: FOUND %04d-%02d-%02d\n",
+                       (unsigned long)ntp_time,
+                       year, 
+                       (int)ot.year, (int)ot.month, (int)ot.monthday );
+           break;
+       }
+
+      {
+       int    m;               /* expected month */
+       int    d;               /* expected day */
+
+       m = isleap_4(year) ?  2 : 3;
+       d = isleap_4(year) ? 29 : 1;
+
+       ntp_time += ( 24 * 60 * 60 );   /* advance to the next day */
+       caljulian( ntp_time, &ot );     /* convert this day */
+       if ( ot.year  != year
+         || ot.month != m
+         || ot.monthday != d )
+       {
+           Error(year);
+           fprintf( stdout, "%lu: EXPECTED %04d-%02d-%02d: FOUND %04d-%02d-%02d\n",
+                       (unsigned long)ntp_time,
+                       year, m, d, 
+                       (int)ot.year, (int)ot.month, (int)ot.monthday );
+           break;
+       }
+
+      }
+    }
+  }
+
+    puts( " libntp/caltontp.c" );
+  {            /* test caltontp() */
+    struct     calendar  ot;
+    u_long      ntp_time;              /* NTP time */
+
+    year = year0;              /* calculate the basic year */
+    printf( "  starting year %04d\n", (int)year0 );
+    printf( "  ending year   %04d\n", (int)yearend );
+
+
+    for ( ; year < yearend; year++ )
+    {
+       u_long  ObservedNtp;
+       
+       /* 01-01 for the current year */
+       ot.year = year;
+       ot.month = ot.monthday = 1;     /* unused, but set anyway JIC */
+       ot.yearday = 1;         /* this is the magic value used by caltontp() */
+       ot.hour = ot.minute = ot.second = 0;
+
+       ntp_time = Days( year ) - Days( year0 );  /* days into NTP time */
+       ntp_time *= 24 * 60 * 60;       /* convert into seconds */
+       ObservedNtp = caltontp( &ot );
+       if ( ntp_time != ObservedNtp )
+       {
+           Error(year);
+           fprintf( stdout, "%d: EXPECTED %lu: FOUND %lu (%ld)\n",
+                       (int)year,
+                       (unsigned long)ntp_time, (unsigned long)ObservedNtp ,
+                       (long)ntp_time - (long)ObservedNtp );
+
+           break;
+       }
+
+       /* now call caljulian as a type of failsafe supercheck */
+       caljulian( ObservedNtp, &ot );  /* convert January 1 */
+       if ( ot.year  != year
+         || ot.month != 1
+         || ot.monthday != 1 )
+       {
+           Error(year);
+           fprintf( stdout, "%lu: caljulian FAILSAFE EXPECTED %04d-01-01: FOUND %04d-%02d-%02d\n",
+                       (unsigned long)ObservedNtp,
+                       year, 
+                       (int)ot.year, (int)ot.month, (int)ot.monthday );
+           break;
+       }
+    }
+  }
+
+   if ( Warnings > 0 )
+       fprintf( stdout, "%d WARNINGS\n",  Warnings );
+   if ( Fatals > 0 )
+       fprintf( stdout, "%d FATAL ERRORS\n",  Fatals );
+   return Fatals ? 1 : 0;
+}
+                                                       /* Y2KFixes ] */
index c0a2739234ad65d1f9f9b172919ecb799d64dc28..54f117826cf49c6101b8fffc0b04d2790a871fbf 100644 (file)
@@ -660,12 +660,14 @@ acts_receive (
         * short. Would only the timecode mavens resist the urge to
         * express months of the year and days of the month in favor of
         * days of the year.
+        *      NOTE: year 2000 IS a leap year!!!  ghealton     Y2KFixes
         */
        if (month < 1 || month > 12 || day < 1) {
                refclock_report(peer, CEVNT_BADTIME);
                return;
        }
-       if (pp->year % 4) {
+       if ( pp->year <= YEAR_PIVOT ) pp->year += 100;          /* Y2KFixes */
+       if ( !isleap_tm(pp->year) ) {                           /* Y2KFixes */
                if (day > day1tab[month - 1]) {
                        refclock_report(peer, CEVNT_BADTIME);
                        return;
index 36f3f4b77f6fb7dc60dacaee2a68afe1bbf4976e..92fa8cc330ad8cac238125a08af1fadb1557cced 100644 (file)
@@ -1079,15 +1079,15 @@ arc_receive(
 
        /* Year-2000 alert! */
        /* Attempt to wrap 2-digit date into sensible window. */
-       /* This code was written in 1997, so that is the window start. */
-       if(pp->year < 97) { pp->year += 2000; }
-       else /* if(pp->year < 100) */ { pp->year += 1900; }
+       if(pp->year < YEAR_PIVOT) { pp->year += 100; }          /* Y2KFixes */
+       pp->year += 1900;       /* use full four-digit year     /* Y2KFixes */
        /*
          Attempt to do the right thing by screaming that the code will
          soon break when we get to the end of its useful life.  What a
          hero I am...  PLEASE FIX LEAP-YEAR AND WRAP CODE IN 209X!
        */
-       if(pp->year >= 2090) {          /* This should get attention B^> */
+       if(pp->year >= YEAR_PIVOT+2000-2 ) {                    /* Y2KFixes */
+               /*This should get attention B^> */
                msyslog(LOG_NOTICE,
                       "ARCRON: fix me!  EITHER YOUR DATE IS BADLY WRONG or else I will break soon!");
        }
@@ -1124,8 +1124,7 @@ arc_receive(
 
        pp->day += moff[month - 1];
 
-       /* Good 'til 1st March 2100 */
-       if(((pp->year % 4) == 0) && month > 2) { pp->day++; }
+       if(isleap_4(pp->year) && month > 2) { pp->day++; }      /* Y2KFixes */
 
        /* Convert to UTC if required */
        if(bst & 2) {
index 84817a7178a0a4aa127ea2a09a365bc837f43b62..57740f850ab59021f3fc8306f638560b5b648387 100644 (file)
@@ -361,6 +361,7 @@ heath_receive(
                t.tm_mday = day; /* not converted to yday yet */
                t.tm_mon = month-1; /* ditto */
                t.tm_year = pp->year;
+               if ( t.tm_year < YEAR_PIVOT ) t.tm_year += 100; /* Y2KFixes */
 
                t.tm_wday = -1; /* who knows? */
                t.tm_yday = -1; /* who knows? */
@@ -399,6 +400,7 @@ heath_receive(
         * Yes, I know this code incorrectly thinks that 2000 is a leap
         * year; but, the latest year that can be set by the DIPswitches
         * is 1997 anyay. Life is short.
+        *      Hey! Year 2000 IS a leap year!                     Y2KFixes
         */
        if (month < 1 || month > 12 || day < 1) {
                refclock_report(peer, CEVNT_BADTIME);
index 37a9f015829bd4d2f0b60f01c10c522ee20d27dd..30aa49406842d52fa38d1f099d813dc1622c702d 100644 (file)
@@ -444,13 +444,13 @@ hpgps_receive(
 
        /* 
         * Compute the day of year from the yyyymmdd format.
-        * Exception noted for year 2000.
         */
        if (month < 1 || month > 12 || day < 1) {
                refclock_report(peer, CEVNT_BADTIME);
                return;
        }
-       if ((pp->year % 4) || (pp->year == 2000)) {
+
+       if ( ! isleap_4(pp->year) ) {                           /* Y2KFixes */
                /* not a leap year */
                if (day > day1tab[month - 1]) {
                        refclock_report(peer, CEVNT_BADTIME);
@@ -490,10 +490,10 @@ hpgps_receive(
                day--;
                if (day < 1) {
                        pp->year--;
-                       if ((pp->year % 4) || (pp->year % 400))
-                           day = 365;
-                       else
+                       if ( isleap_4(pp->year) )               /* Y2KFixes */
                            day = 366;
+                       else
+                           day = 365;
                }
        }
 
index 0d0ae0aa625aa949fe085d1fb419d86b689b11bf..98bfd81f8b526273473080e793edf5d9bff00b0f 100644 (file)
@@ -42,6 +42,7 @@
  * NTP compilation environment
  */
 #include "ntp_stdlib.h"
+#include "ntpd.h"   /* indirectly include ntp.h to get YEAR_PIVOT   Y2KFixes */
 
 /*
  * select which terminal handling to use (currently only SysV variants)
@@ -744,25 +745,20 @@ dcf_to_unixtime(
        /*
         * map 2 digit years to 19xx (DCF77 is a 20th century item)
         */
-       if (clock_time->year < 100)
-           clock_time->year += 1900;
-
-       /*
-        * assume that we convert timecode within the unix/UTC epoch -
-        * prolonges validity of 2 digit years
-        */
-       if (clock_time->year < 1998)
-           clock_time->year += 100;            /* XXX this will do it till <2098 */
+       if ( clock_time->year < YEAR_PIVOT )    /* in case of      Y2KFixes [ */
+               clock_time->year += 100;        /* *year%100, make tm_year */
+                                               /* *(do we need this?) */
+       if ( clock_time->year < YEAR_BREAK )    /* (failsafe if) */
+           clock_time->year += 1900;                           /* Y2KFixes ] */
 
        /*
         * must have been a really bad year code - drop it
         */
-       if (clock_time->year < 1998)
+       if (clock_time->year < (YEAR_PIVOT + 1900) )            /* Y2KFixes */
        {
                SETRTC(CVT_FAIL|CVT_BADDATE);
                return -1;
        }
-  
        /*
         * sorry, slow section here - but it's not time critical anyway
         */
@@ -770,10 +766,7 @@ dcf_to_unixtime(
        /*
         * calculate days since 1970 (watching leap years)
         */
-       t =  (clock_time->year - 1970) * 365;
-       t += (clock_time->year >> 2) - (1970 >> 2);
-       t -= clock_time->year / 100 - 1970 / 100;
-       t += clock_time->year / 400 - 1970 / 400;
+       t = julian0( clock_time->year ) - julian0( 1970 );
 
                                /* month */
        if (clock_time->month <= 0 || clock_time->month > 12)
@@ -782,8 +775,10 @@ dcf_to_unixtime(
                return -1;              /* bad month */
        }
                                /* adjust current leap year */
+#if 0
        if (clock_time->month < 3 && days_per_year(clock_time->year) == 366)
            t--;
+#endif
 
        /*
         * collect days from months excluding the current one
@@ -1213,10 +1208,137 @@ usage(
        fprintf(stderr, "\t-f              print all databits (includes PTB private data)\n");
        fprintf(stderr, "\t-l              print loop filter debug information\n");
        fprintf(stderr, "\t-o              print offet average for current minute\n");
+       fprintf(stderr, "\t-Y              make internal Y2K checks then exit\n");      /* Y2KFixes */
        fprintf(stderr, "\t-d <drift_file> specify alternate drift file\n");
        fprintf(stderr, "\t-D <input delay>specify delay from input edge to processing in micro seconds\n");
 }
 
+/*-----------------------------------------------------------------------
+ * check_y2k() - internal check of Y2K logic
+ *     (a lot of this logic lifted from ../ntpd/check_y2k.c)
+ */
+int
+check_y2k( void )
+{ 
+    int  year;                 /* current working year */
+    int  year0 = 1900;         /* sarting year for NTP time */
+    int  yearend;              /* ending year we test for NTP time.
+                                   * 32-bit systems: through 2036, the
+                                     **year in which NTP time overflows.
+                                   * 64-bit systems: a reasonable upper
+                                     **limit (well, maybe somewhat beyond
+                                     **reasonable, but well before the
+                                     **max time, by which time the earth
+                                     **will be dead.) */
+    time_t Time;
+    struct tm LocalTime;
+
+    int Fatals, Warnings;
+#define Error(year) if ( (year)>=2036 && LocalTime.tm_year < 110 ) \
+       Warnings++; else Fatals++
+
+    Fatals = Warnings = 0;
+
+    Time = time( (time_t *)NULL );
+    LocalTime = *localtime( &Time );
+
+    year = ( sizeof( u_long ) > 4 )    /* save max span using year as temp */
+               ? ( 400 * 3 )           /* three greater gregorian cycles */
+               : ((int)(0x7FFFFFFF / 365.242 / 24/60/60)* 2 ); /*32-bit limit*/
+                       /* NOTE: will automacially expand test years on
+                        * 64 bit machines.... this may cause some of the
+                        * existing ntp logic to fail for years beyond
+                        * 2036 (the current 32-bit limit). If all checks
+                        * fail ONLY beyond year 2036 you may ignore such
+                        * errors, at least for a decade or so. */
+    yearend = year0 + year;
+
+    year = 1900+YEAR_PIVOT;
+    printf( "  starting year %04d\n", (int) year );
+    printf( "  ending year   %04d\n", (int) yearend );
+
+    for ( ; year < yearend; year++ )
+    {
+       clocktime_t  ct;
+       time_t       Observed;
+       time_t       Expected;
+       unsigned     Flag;
+       unsigned long t;
+
+       ct.day = 1;
+       ct.month = 1;
+       ct.year = year;
+       ct.hour = ct.minute = ct.second = ct.usecond = 0;
+       ct.utcoffset = 0;
+       ct.flags = 0;
+
+       Flag = 0;
+       Observed = dcf_to_unixtime( &ct, &Flag );
+               /* seems to be a clone of parse_to_unixtime() with
+                * *a minor difference to arg2 type */
+       if ( ct.year != year )
+       {
+           fprintf( stdout, 
+              "%04d: dcf_to_unixtime(,%d) CORRUPTED ct.year: was %d\n",
+              (int)year, (int)Flag, (int)ct.year );
+           Error(year);
+           break;
+       }
+       t = julian0(year) - julian0(1970);      /* Julian day from 1970 */
+       Expected = t * 24 * 60 * 60;
+       if ( Observed != Expected  ||  Flag )
+       {   /* time difference */
+           fprintf( stdout, 
+              "%04d: dcf_to_unixtime(,%d) FAILURE: was=%lu s/b=%lu  (%ld)\n",
+              year, (int)Flag, 
+              (unsigned long)Observed, (unsigned long)Expected,
+              ((long)Observed - (long)Expected) );
+           Error(year);
+           break;
+       }
+
+       if ( year >= YEAR_PIVOT+1900 )
+       {
+           /* check year % 100 code we put into dcf_to_unixtime() */
+           ct.year = year % 100;
+           Flag = 0;
+
+           Observed = dcf_to_unixtime( &ct, &Flag );
+
+           if ( Observed != Expected  ||  Flag )
+           {   /* time difference */
+               fprintf( stdout, 
+"%04d: dcf_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu  (%ld)\n",
+                  year, (int)ct.year, (int)Flag, 
+                  (unsigned long)Observed, (unsigned long)Expected,
+                  ((long)Observed - (long)Expected) );
+               Error(year);
+               break;
+           }
+
+           /* check year - 1900 code we put into dcf_to_unixtime() */
+           ct.year = year - 1900;
+           Flag = 0;
+
+           Observed = dcf_to_unixtime( &ct, &Flag );
+
+           if ( Observed != Expected  ||  Flag ) {   /* time difference */
+                   fprintf( stdout, 
+                            "%04d: dcf_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu  (%ld)\n",
+                            year, (int)ct.year, (int)Flag, 
+                            (unsigned long)Observed, (unsigned long)Expected,
+                            ((long)Observed - (long)Expected) );
+                   Error(year);
+               break;
+           }
+
+
+       }
+    }
+
+    return ( Fatals );
+}
+
 /*--------------------------------------------------
  * rawdcf_init - set up modem lines for RAWDCF receivers
  */
@@ -1339,6 +1461,10 @@ main(
                                }
                                break;
              
+                           case 'Y':   
+                               errs=check_y2k();
+                               exit( errs ? 1 : 0 );
+
                            default:
                                fprintf(stderr, "%s: unknown option -%c\n", argv[0], c);
                                errs=1;
diff --git a/readme.y2kfixes b/readme.y2kfixes
new file mode 100644 (file)
index 0000000..e9a63c1
Binary files /dev/null and b/readme.y2kfixes differ
diff --git a/results.y2kfixes b/results.y2kfixes
new file mode 100644 (file)
index 0000000..32f42cf
--- /dev/null
@@ -0,0 +1,76 @@
+Script started on Sat Jan  1 04:14:09 2000
+[root@timetest ntpdate]# date
+Sat Jan  1 04:14:11 EST 2000
+[root@timetest ntpdate]# ./ntpdate -b timelord.att.com
+14 Jul 13:44:39 ntpdate[11723]: step time server 135.16.xxxx.xxxx offset -14740193.210537 sec
+[root@timetest ntpdate]# date
+Wed Jul 14 13:44:42 EST 1999
+[root@timetest ntpdate]# cd ../ntptrace
+[root@timetest ntptrace]# ./ntptrace timelord.att.com
+timelord.att.com: stratum 2, offset -0.000879, synch distance 0.07207
+timemaster.att.com: stratum 1, offset -0.004876, synch distance 0.03485, refid 'GPS'
+[root@timetest ntptrace]# cd -
+[root@timetest ntpdate]# date
+Mon Feb 28 01:00:04 EST 2000
+[root@timetest ntpdate]# ./ntpdate -b timelord.att.com
+14 Jul 13:49:01 ntpdate[11760]: step time server 135.16.xxxx.xxxx offset -19739467.533126 sec
+[root@timetest ntpdate]# date
+Wed Jul 14 13:49:03 EST 1999
+[root@timetest ntpdate]# cd -
+[root@timetest ntptrace]# ./ntptrace timelord.att.com
+timelord.att.com: stratum 2, offset 0.001383, synch distance 0.05644
+timemaster.att.com: stratum 1, offset -0.006355, synch distance 0.04178, refid 'GPS'
+[root@timetest ntptrace]# cd -
+[root@timetest ntpdate]# date
+Tue Feb 29 01:00:05 EST 2000
+[root@timetest ntpdate]# ./ntpdate -b timelord.att.com
+14 Jul 13:57:41 ntpdate[12423]: step time server 135.16.xxxx.xxxx offset -19825349.396585 sec
+[root@timetest ntpdate]# date
+Wed Jul 14 13:57:43 EST 1999
+[root@timetest ntpdate]# cd -
+[root@timetest ntptrace]# ./ntptrace timelord.att.com
+timelord.att.com: stratum 2, offset -0.000094, synch distance 0.06522
+timemaster.att.com: stratum 1, offset -0.010803, synch distance 0.03078, refid 'GPS'
+[root@timetest ntptrace]# cd -
+[root@timetest ntpdate]# date 
+Wed Mar  1 01:00:03 EST 2000
+[root@timetest ntpdate]# ./ntpdate -b timelord.att.com
+14 Jul 13:58:10 ntpdate[12525]: step time server 135.16.xxxx.xxxx offset -19911719.766061 sec
+[root@timetest ntpdate]# date
+Wed Jul 14 13:58:12 EST 1999
+[root@timetest ntpdate]# cd -
+[root@timetest ntptrace]# ./ntptrace timelord.att.com
+timelord.att.com: stratum 2, offset -0.000719, synch distance 0.06561
+timemaster.att.com: stratum 1, offset -0.013598, synch distance 0.03116, refid 'GPS'
+
+Script done on Wed Jul 14 13:58:28 1999
+
+RESULTS OK.
+--------------------END OF TEST1-------------------- 
+
+
+### freeware test configuration
+server 127.127.1.0 prefer
+fudge 127.127.1.0 stratum 0
+driftfile drift.log
+
+
+ntpdate timelord.att.com
+server 135.16.xxxx.xxxx stratum 1, offset 0.000033, delay 0.02975
+31 Dec 23:58:59 ntpdate[83551]: adjust time server 135.16.74.3 offset 0.039057 s
+ec
+
+ntpdate timelord.att.com
+server 135.16.xxxx.xxxx stratum 1, offset 0.000019, delay 0.02504
+01 Jan 00:01:05 ntpdate[8352]: adjust time server 135.16.74.3 offset 0.039057 s
+ec
+
+ntpdate timelord.att.com
+server 135.25.xxxx.xxxx, stratum 1, offset -0.000023, delay 0.02731
+29 Feb 00:02:15 ntpdate[8353]: adjust time server 135.25.xxxx.xxxx offset -0.000023 sec
+
+
+
+
+
+