+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.
--- /dev/null
+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????
+
+
#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
#include "ntp_machine.h"
#include "parse.h"
+#include "ntp.h" /* (get Y2KFixes definitions) Y2KFixes */
#ifndef PARSESTREAM
#include <stdio.h>
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;
/*
* 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++)
{
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 \
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@
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)
--- /dev/null
+/* 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 ] */
* 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;
/* 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!");
}
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) {
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? */
* 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);
/*
* 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);
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;
}
}
* 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)
/*
* 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
*/
/*
* 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)
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
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
*/
}
break;
+ case 'Y':
+ errs=check_y2k();
+ exit( errs ? 1 : 0 );
+
default:
fprintf(stderr, "%s: unknown option -%c\n", argv[0], c);
errs=1;
--- /dev/null
+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
+
+
+
+
+
+