3 /* check_y2k.c -- test ntp code constructs for Y2K correctness Y2KFixes [*/
6 Code invoked by `make check`. Not part of ntpd and not to be
9 On any code I even wonder about, I've cut and pasted the code
10 here and ran it as a test case just to be sure.
12 For code not in "ntpd" proper, we have tried to call most
13 repaired functions from herein to properly test them
14 (something never done before!). This has found several bugs,
15 not normal Y2K bugs, that will strike in Y2K so repair them
18 Program exits with 0 on success, 1 on Y2K failure (stdout messages).
19 Exit of 2 indicates internal logic bug detected OR failure of
20 what should be our correct formulas.
22 While "make check" should only check logic for source within that
23 specific directory, this check goes outside the scope of the local
24 directory. It's not a perfect world (besides, there is a lot of
25 interdependence here, and it really needs to be tested in
29 /* { definitions lifted from ntpd.c to allow us to complie with
30 "#include ntp.h". I have not taken the time to reduce the clutter. */
41 #ifdef HAVE_SYS_STAT_H
42 # include <sys/stat.h>
47 # if !defined(VMS) /*wjm*/
48 # include <sys/param.h>
50 # if HAVE_SYS_SIGNAL_H
51 # include <sys/signal.h>
52 # endif /* HAVE_SYS_SIGNAL_H */
53 # include <sys/signal.h>
54 # ifdef HAVE_SYS_IOCTL_H
55 # include <sys/ioctl.h>
56 # endif /* HAVE_SYS_IOCTL_H */
57 # if !defined(VMS) /*wjm*/
58 # include <sys/resource.h>
64 # include "../libntp/log.h"
65 #endif /* SYS_WINNT */
66 #if defined(HAVE_RTPRIO)
67 # ifdef HAVE_SYS_RESOURCE_H
68 # include <sys/resource.h>
70 # ifdef HAVE_SYS_LOCK_H
71 # include <sys/lock.h>
73 # include <sys/rtprio.h>
76 # ifdef HAVE_SYS_LOCK_H
77 # include <sys/lock.h>
81 #if defined(HAVE_SCHED_SETSCHEDULER)
85 # ifdef HAVE_SYS_SCHED_H
86 # include <sys/sched.h>
90 #if defined(HAVE_SYS_MMAN_H)
91 # include <sys/mman.h>
99 # include <apollo/base.h>
100 #endif /* SYS_DOMAINOS */
102 /* } end definitions lifted from ntpd.c */
104 #include "ntp_calendar.h"
107 #define GoodLeap(Year) (((Year)%4 || (!((Year)%100) && (Year)%400)) ? 0 : 13 )
109 volatile int debug
= 0; /* debugging requests for parse stuff */
110 char const *progname
= "check_y2k";
113 Days ( int Year
) /* return number of days since year "0" */
116 /* this is a known to be good algorithm */
117 Return
= Year
* 365; /* first aproximation to the value */
119 { /* see notes in libparse/parse.c if you want a PROPER
120 * **generic algorithm. */
121 Return
+= (Year
+3) / 4; /* add in (too many) leap days */
122 Return
-= (Year
-1) / 100; /* reduce by (too many) centurys */
123 Return
+= (Year
-1) / 400; /* get final answer */
129 static int year0
= 1900; /* sarting year for NTP time */
130 static int yearend
; /* ending year we test for NTP time.
131 * 32-bit systems: through 2036, the
132 **year in which NTP time overflows.
133 * 64-bit systems: a reasonable upper
134 **limit (well, maybe somewhat beyond
135 **reasonable, but well before the
136 **max time, by which time the earth
139 static struct tm LocalTime
;
141 #define Error(year) if ( (year)>=2036 && LocalTime.tm_year < 110 ) \
142 Warnings++; else Fatals++
151 Time
= time( (time_t *)NULL
)
152 #ifdef TESTTIMEOFFSET
156 LocalTime
= *localtime( &Time
);
158 year
= ( sizeof( u_long
) > 4 ) /* save max span using year as temp */
159 ? ( 400 * 3 ) /* three greater gregorian cycles */
160 : ((int)(0x7FFFFFFF / 365.242 / 24/60/60)* 2 ); /*32-bit limit*/
161 /* NOTE: will automacially expand test years on
162 * 64 bit machines.... this may cause some of the
163 * existing ntp logic to fail for years beyond
164 * 2036 (the current 32-bit limit). If all checks
165 * fail ONLY beyond year 2036 you may ignore such
166 * errors, at least for a decade or so. */
167 yearend
= year0
+ year
;
169 puts( " internal self check" );
170 { /* verify our own logic used to verify repairs */
173 if ( year0
>= yearend
)
175 fprintf( stdout
, "year0=%d NOT LESS THAN yearend=%d (span=%d)\n",
176 (int)year0
, (int)yearend
, (int)year
);
183 save_year
= LocalTime
.tm_year
; /* save current year */
186 LocalTime
.tm_year
= year
- 1900;
187 Fatals
= Warnings
= 0;
188 Error(year
); /* should increment Fatals */
192 "%4d: %s(%d): FATAL DID NOT INCREMENT (Fatals=%d Warnings=%d)\n",
193 (int)year
, __FILE__
, __LINE__
, (int)Fatals
, (int)Warnings
);
197 year
= 2100; /* test year > limit but CURRENT year < limit */
198 Fatals
= Warnings
= 0;
199 Error(year
); /* should increment Fatals */
203 "%4d: %s(%d): WARNING DID NOT INCREMENT (Fatals=%d Warnings=%d)\n",
204 (int)year
, __FILE__
, __LINE__
, (int)Fatals
, (int)Warnings
);
207 Fatals
= Warnings
= 0;
208 LocalTime
.tm_year
= year
- 1900; /* everything > limit */
209 Error(1980); /* should increment Fatals */
213 "%4d: %s(%d): FATALS DID NOT INCREMENT (Fatals=%d Warnings=%d)\n",
214 (int)year
, __FILE__
, __LINE__
, (int)Fatals
, (int)Warnings
);
218 LocalTime
.tm_year
= save_year
;
221 days
= 365+1; /* days in year 0 + 1 more day */
222 for ( year
= 1; year
<= 2500; year
++ )
228 fprintf( stdout
, "%04d: Days() DAY COUNT ERROR: s/b=%ld was=%ld\n",
229 year
, (long)days
, (long)Test
);
230 exit(2); /* would throw off many other tests */
233 Test
= julian0(year
); /* compare with julian0() macro */
236 fprintf( stdout
, "%04d: julian0() DAY COUNT ERROR: s/b=%ld was=%ld\n",
237 year
, (long)days
, (long)Test
);
238 exit(2); /* would throw off many other tests */
242 if ( isleap_4(year
) ) days
++;
245 if ( isleap_4(1999) )
247 fprintf( stdout
, "isleap_4(1999) REPORTED TRUE\n" );
250 if ( !isleap_4(2000) )
252 fprintf( stdout
, "isleap_4(2000) REPORTED FALSE\n" );
255 if ( isleap_4(2001) )
257 fprintf( stdout
, "isleap_4(1999) REPORTED TRUE\n" );
261 if ( !isleap_tm(2000-1900) )
263 fprintf( stdout
, "isleap_tm(100) REPORTED FALSE\n" );
268 Fatals
= Warnings
= 0;
270 puts( " include/ntp.h" );
271 { /* test our new isleap_*() #define "functions" */
273 for ( year
= 1400; year
<= 2200; year
++ )
278 LeapSw
= GoodLeap(year
);
279 IsLeapSw
= isleap_4(year
);
281 if ( !!LeapSw
!= !!IsLeapSw
)
285 " %4d %2d %3d *** ERROR\n", year
, LeapSw
, IsLeapSw
);
289 IsLeapSw
= isleap_tm(year
-1900);
291 if ( !!LeapSw
!= !!IsLeapSw
)
295 " %4d %2d %3d *** ERROR\n", year
, LeapSw
, IsLeapSw
);
301 puts( " include/ntp_calendar.h" );
302 { /* I belive this is good, but just to be sure... */
304 /* we are testing this #define */
305 #define is_leapyear(y) (y%4 == 0 && !(y%100 == 0 && !(y%400 == 0)))
307 for ( year
= 1400; year
<= 2200; year
++ )
311 LeapSw
= GoodLeap(year
);
313 if ( !(!LeapSw
) != !(!is_leapyear(year
)) )
317 " %4d %2d *** ERROR\n", year
, LeapSw
);
324 puts( " libparse/parse.c" );
326 long Days1970
; /* days from 1900 to 1970 */
328 struct ParseTime
/* womp up a test structure to all cut/paste code */
331 } Clock_Time
, *clock_time
;
333 clock_time
= &Clock_Time
;
335 /* first test this #define */
336 #define days_per_year(x) ((x) % 4 ? 365 : ((x % 400) ? ((x % 100) ? 366 : 365) : 366))
338 for ( year
= 1400; year
<= 2200; year
++ )
343 LeapSw
= GoodLeap(year
);
344 DayCnt
= (int)days_per_year(year
);
346 if ( ( LeapSw
? 366 : 365 ) != DayCnt
)
350 " days_per_year() %4d %2d %3d *** ERROR\n",
351 year
, LeapSw
, DayCnt
);
356 /* test (what is now julian0) calculations */
358 Days1970
= Days( 1970 ); /* get days since 1970 using a known good */
360 for ( year
= 1970; year
< yearend
; year
++ )
365 clock_time
->year
= year
;
367 /* here is the code we are testing, cut and pasted out of the source */
368 #if 0 /* old BUGGY code that has Y2K (and many other) failures */
369 /* ghealton: this logic FAILED with great frequency when run
370 * over a period of time, including for year 2000. True, it
371 * had more successes than failures, but that's not really good
372 * enough for critical time distribution software.
373 * It is so awful I wonder if it has had a history of failure
375 t
= (clock_time
->year
- 1970) * 365;
376 t
+= (clock_time
->year
>> 2) - (1970 >> 2);
377 t
-= clock_time
->year
/ 100 - 1970 / 100;
378 t
+= clock_time
->year
/ 400 - 1970 / 400;
380 /* (immediate feare of rounding errors on integer
381 * **divisions proved well founded) */
384 /* my replacement, based on Days() above */
385 t
= julian0(year
) - julian0(1970);
388 /* compare result in t against trusted calculations */
389 DaysYear
= Days( year
); /* get days to this year */
390 if ( t
!= DaysYear
- Days1970
)
394 " %4d 1970=%-8ld %4d=%-8ld %-3ld t=%-8ld *** ERROR ***\n",
395 year
, (long)Days1970
,
398 (long)(DaysYear
- Days1970
),
405 debug
= 1; /* enable debugging */
406 for ( year
= 1970; year
< yearend
; year
++ )
407 { /* (limited by theory unix 2038 related bug lives by, but
408 * ends in yearend) */
418 ct
.hour
= ct
.minute
= ct
.second
= ct
.usecond
= 0;
424 Observed
= parse_to_unixtime( &ct
, &Flag
);
425 if ( ct
.year
!= year
)
428 "%04d: parse_to_unixtime(,%d) CORRUPTED ct.year: was %d\n",
429 (int)year
, (int)Flag
, (int)ct
.year
);
433 t
= julian0(year
) - julian0(1970); /* Julian day from 1970 */
434 Expected
= t
* 24 * 60 * 60;
435 if ( Observed
!= Expected
|| Flag
)
436 { /* time difference */
438 "%04d: parse_to_unixtime(,%d) FAILURE: was=%lu s/b=%lu (%ld)\n",
440 (unsigned long)Observed
, (unsigned long)Expected
,
441 ((long)Observed
- (long)Expected
) );
446 if ( year
>= YEAR_PIVOT
+1900 )
448 /* check year % 100 code we put into parse_to_unixtime() */
450 ct
.year
= year
% 100;
453 Observed
= parse_to_unixtime( &ct
, &Flag
);
455 if ( Observed
!= Expected
|| Flag
)
456 { /* time difference */
458 "%04d: parse_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu (%ld)\n",
459 year
, (int)ct
.year
, (int)Flag
,
460 (unsigned long)Observed
, (unsigned long)Expected
,
461 ((long)Observed
- (long)Expected
) );
466 /* check year - 1900 code we put into parse_to_unixtime() */
468 ct
.year
= year
- 1900;
471 Observed
= parse_to_unixtime( &ct
, &Flag
);
473 if ( Observed
!= Expected
|| Flag
)
474 { /* time difference */
476 "%04d: parse_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu (%ld)\n",
477 year
, (int)ct
.year
, (int)Flag
,
478 (unsigned long)Observed
, (unsigned long)Expected
,
479 ((long)Observed
- (long)Expected
) );
491 puts( " libntp/caljulian.c" );
492 { /* test caljulian() */
494 u_long ntp_time
; /* NTP time */
496 year
= year0
; /* calculate the basic year */
497 printf( " starting year %04d\n", (int)year0
);
498 printf( " ending year %04d\n", (int)yearend
);
501 ntp_time
= julian0( year0
); /* NTP starts in 1900-01-01 */
502 #if DAY_NTP_STARTS == 693596
503 ntp_time
-= 365; /* BIAS required for successful test */
505 if ( DAY_NTP_STARTS
!= ntp_time
)
509 "%04d: DAY_NTP_STARTS (%ld) NOT TRUE VALUE OF %ld (%ld)\n",
511 (long)DAY_NTP_STARTS
, (long)ntp_time
,
512 (long)DAY_NTP_STARTS
- (long)ntp_time
);
515 for ( ; year
< yearend
; year
++ )
518 /* 01-01 for the current year */
519 ntp_time
= Days( year
) - Days( year0
); /* days into NTP time */
520 ntp_time
*= 24 * 60 * 60; /* convert into seconds */
521 caljulian( ntp_time
, &ot
); /* convert January 1 */
524 || ot
.monthday
!= 1 )
527 fprintf( stdout
, "%lu: EXPECTED %04d-01-01: FOUND %04d-%02d-%02d\n",
528 (unsigned long)ntp_time
,
530 (int)ot
.year
, (int)ot
.month
, (int)ot
.monthday
);
534 ntp_time
+= (31 + 28-1) * ( 24 * 60 * 60 ); /* advance to 02-28 */
535 caljulian( ntp_time
, &ot
); /* convert Feb 28 */
538 || ot
.monthday
!= 28 )
541 fprintf( stdout
, "%lu: EXPECTED %04d-02-28: FOUND %04d-%02d-%02d\n",
542 (unsigned long)ntp_time
,
544 (int)ot
.year
, (int)ot
.month
, (int)ot
.monthday
);
549 int m
; /* expected month */
550 int d
; /* expected day */
552 m
= isleap_4(year
) ? 2 : 3;
553 d
= isleap_4(year
) ? 29 : 1;
555 ntp_time
+= ( 24 * 60 * 60 ); /* advance to the next day */
556 caljulian( ntp_time
, &ot
); /* convert this day */
559 || ot
.monthday
!= d
)
562 fprintf( stdout
, "%lu: EXPECTED %04d-%02d-%02d: FOUND %04d-%02d-%02d\n",
563 (unsigned long)ntp_time
,
565 (int)ot
.year
, (int)ot
.month
, (int)ot
.monthday
);
573 puts( " libntp/caltontp.c" );
574 { /* test caltontp() */
576 u_long ntp_time
; /* NTP time */
578 year
= year0
; /* calculate the basic year */
579 printf( " starting year %04d\n", (int)year0
);
580 printf( " ending year %04d\n", (int)yearend
);
583 for ( ; year
< yearend
; year
++ )
587 /* 01-01 for the current year */
589 ot
.month
= ot
.monthday
= 1; /* unused, but set anyway JIC */
590 ot
.yearday
= 1; /* this is the magic value used by caltontp() */
591 ot
.hour
= ot
.minute
= ot
.second
= 0;
593 ntp_time
= Days( year
) - Days( year0
); /* days into NTP time */
594 ntp_time
*= 24 * 60 * 60; /* convert into seconds */
595 ObservedNtp
= caltontp( &ot
);
596 if ( ntp_time
!= ObservedNtp
)
599 fprintf( stdout
, "%d: EXPECTED %lu: FOUND %lu (%ld)\n",
601 (unsigned long)ntp_time
, (unsigned long)ObservedNtp
,
602 (long)ntp_time
- (long)ObservedNtp
);
607 /* now call caljulian as a type of failsafe supercheck */
608 caljulian( ObservedNtp
, &ot
); /* convert January 1 */
611 || ot
.monthday
!= 1 )
614 fprintf( stdout
, "%lu: caljulian FAILSAFE EXPECTED %04d-01-01: FOUND %04d-%02d-%02d\n",
615 (unsigned long)ObservedNtp
,
617 (int)ot
.year
, (int)ot
.month
, (int)ot
.monthday
);
624 fprintf( stdout
, "%d WARNINGS\n", Warnings
);
626 fprintf( stdout
, "%d FATAL ERRORS\n", Fatals
);
627 return Fatals
? 1 : 0;