1 /* check_y2k.c -- test ntp code constructs for Y2K correctness Y2KFixes [*/
4 Code invoked by `make check`. Not part of ntpd and not to be
7 On any code I even wonder about, I've cut and pasted the code
8 here and ran it as a test case just to be sure.
10 For code not in "ntpd" proper, we have tried to call most
11 repaired functions from herein to properly test them
12 (something never done before!). This has found several bugs,
13 not normal Y2K bugs, that will strike in Y2K so repair them
16 Program exits with 0 on success, 1 on Y2K failure (stdout messages).
17 Exit of 2 indicates internal logic bug detected OR failure of
18 what should be our correct formulas.
20 While "make check" should only check logic for source within that
21 specific directory, this check goes outside the scope of the local
22 directory. It's not a perfect world (besides, there is a lot of
23 interdependence here, and it really needs to be tested in
27 /* { definitions lifted from ntpd.c to allow us to complie with
28 "#include ntp.h". I have not taken the time to reduce the clutter. */
39 #ifdef HAVE_SYS_STAT_H
40 # include <sys/stat.h>
45 # if !defined(VMS) /*wjm*/
46 # include <sys/param.h>
48 # if HAVE_SYS_SIGNAL_H
49 # include <sys/signal.h>
50 # endif /* HAVE_SYS_SIGNAL_H */
51 # include <sys/signal.h>
52 # ifdef HAVE_SYS_IOCTL_H
53 # include <sys/ioctl.h>
54 # endif /* HAVE_SYS_IOCTL_H */
55 # if !defined(VMS) /*wjm*/
56 # include <sys/resource.h>
62 # include "../libntp/log.h"
63 #endif /* SYS_WINNT */
64 #if defined(HAVE_RTPRIO)
65 # ifdef HAVE_SYS_RESOURCE_H
66 # include <sys/resource.h>
68 # ifdef HAVE_SYS_LOCK_H
69 # include <sys/lock.h>
71 # include <sys/rtprio.h>
74 # ifdef HAVE_SYS_LOCK_H
75 # include <sys/lock.h>
79 #if defined(HAVE_SCHED_SETSCHEDULER)
83 # ifdef HAVE_SYS_SCHED_H
84 # include <sys/sched.h>
88 #if defined(HAVE_SYS_MMAN_H)
89 # include <sys/mman.h>
97 # include <apollo/base.h>
98 #endif /* SYS_DOMAINOS */
100 /* } end definitions lifted from ntpd.c */
102 #include "ntp_calendar.h"
105 #define GoodLeap(Year) (((Year)%4 || (!((Year)%100) && (Year)%400)) ? 0 : 13 )
107 volatile int debug
= 0; /* debugging requests for parse stuff */
108 char const *progname
= "check_y2k";
111 Days ( int Year
) /* return number of days since year "0" */
114 /* this is a known to be good algorithm */
115 Return
= Year
* 365; /* first aproximation to the value */
117 { /* see notes in libparse/parse.c if you want a PROPER
118 * **generic algorithm. */
119 Return
+= (Year
+3) / 4; /* add in (too many) leap days */
120 Return
-= (Year
-1) / 100; /* reduce by (too many) centurys */
121 Return
+= (Year
-1) / 400; /* get final answer */
127 static int year0
= 1900; /* sarting year for NTP time */
128 static int yearend
; /* ending year we test for NTP time.
129 * 32-bit systems: through 2036, the
130 **year in which NTP time overflows.
131 * 64-bit systems: a reasonable upper
132 **limit (well, maybe somewhat beyond
133 **reasonable, but well before the
134 **max time, by which time the earth
137 static struct tm LocalTime
;
139 #define Error(year) if ( (year)>=2036 && LocalTime.tm_year < 110 ) \
140 Warnings++; else Fatals++
149 Time
= time( (time_t *)NULL
)
150 #ifdef TESTTIMEOFFSET
154 LocalTime
= *localtime( &Time
);
156 year
= ( sizeof( u_long
) > 4 ) /* save max span using year as temp */
157 ? ( 400 * 3 ) /* three greater gregorian cycles */
158 : ((int)(0x7FFFFFFF / 365.242 / 24/60/60)* 2 ); /*32-bit limit*/
159 /* NOTE: will automacially expand test years on
160 * 64 bit machines.... this may cause some of the
161 * existing ntp logic to fail for years beyond
162 * 2036 (the current 32-bit limit). If all checks
163 * fail ONLY beyond year 2036 you may ignore such
164 * errors, at least for a decade or so. */
165 yearend
= year0
+ year
;
167 puts( " internal self check" );
168 { /* verify our own logic used to verify repairs */
171 if ( year0
>= yearend
)
173 fprintf( stdout
, "year0=%d NOT LESS THAN yearend=%d (span=%d)\n",
174 (int)year0
, (int)yearend
, (int)year
);
181 save_year
= LocalTime
.tm_year
; /* save current year */
184 LocalTime
.tm_year
= year
- 1900;
185 Fatals
= Warnings
= 0;
186 Error(year
); /* should increment Fatals */
190 "%4d: %s(%d): FATAL DID NOT INCREMENT (Fatals=%d Warnings=%d)\n",
191 (int)year
, __FILE__
, __LINE__
, (int)Fatals
, (int)Warnings
);
195 year
= 2100; /* test year > limit but CURRENT year < limit */
196 Fatals
= Warnings
= 0;
197 Error(year
); /* should increment Fatals */
201 "%4d: %s(%d): WARNING DID NOT INCREMENT (Fatals=%d Warnings=%d)\n",
202 (int)year
, __FILE__
, __LINE__
, (int)Fatals
, (int)Warnings
);
205 Fatals
= Warnings
= 0;
206 LocalTime
.tm_year
= year
- 1900; /* everything > limit */
207 Error(1980); /* should increment Fatals */
211 "%4d: %s(%d): FATALS DID NOT INCREMENT (Fatals=%d Warnings=%d)\n",
212 (int)year
, __FILE__
, __LINE__
, (int)Fatals
, (int)Warnings
);
216 LocalTime
.tm_year
= save_year
;
219 days
= 365+1; /* days in year 0 + 1 more day */
220 for ( year
= 1; year
<= 2500; year
++ )
226 fprintf( stdout
, "%04d: Days() DAY COUNT ERROR: s/b=%ld was=%ld\n",
227 year
, (long)days
, (long)Test
);
228 exit(2); /* would throw off many other tests */
231 Test
= julian0(year
); /* compare with julian0() macro */
234 fprintf( stdout
, "%04d: julian0() DAY COUNT ERROR: s/b=%ld was=%ld\n",
235 year
, (long)days
, (long)Test
);
236 exit(2); /* would throw off many other tests */
240 if ( isleap_4(year
) ) days
++;
243 if ( isleap_4(1999) )
245 fprintf( stdout
, "isleap_4(1999) REPORTED TRUE\n" );
248 if ( !isleap_4(2000) )
250 fprintf( stdout
, "isleap_4(2000) REPORTED FALSE\n" );
253 if ( isleap_4(2001) )
255 fprintf( stdout
, "isleap_4(1999) REPORTED TRUE\n" );
259 if ( !isleap_tm(2000-1900) )
261 fprintf( stdout
, "isleap_tm(100) REPORTED FALSE\n" );
266 Fatals
= Warnings
= 0;
268 puts( " include/ntp.h" );
269 { /* test our new isleap_*() #define "functions" */
271 for ( year
= 1400; year
<= 2200; year
++ )
276 LeapSw
= GoodLeap(year
);
277 IsLeapSw
= isleap_4(year
);
279 if ( !!LeapSw
!= !!IsLeapSw
)
283 " %4d %2d %3d *** ERROR\n", year
, LeapSw
, IsLeapSw
);
287 IsLeapSw
= isleap_tm(year
-1900);
289 if ( !!LeapSw
!= !!IsLeapSw
)
293 " %4d %2d %3d *** ERROR\n", year
, LeapSw
, IsLeapSw
);
299 puts( " include/ntp_calendar.h" );
300 { /* I belive this is good, but just to be sure... */
302 /* we are testing this #define */
303 #define is_leapyear(y) (y%4 == 0 && !(y%100 == 0 && !(y%400 == 0)))
305 for ( year
= 1400; year
<= 2200; year
++ )
309 LeapSw
= GoodLeap(year
);
311 if ( !(!LeapSw
) != !(!is_leapyear(year
)) )
315 " %4d %2d *** ERROR\n", year
, LeapSw
);
322 puts( " libparse/parse.c" );
324 long Days1970
; /* days from 1900 to 1970 */
326 struct ParseTime
/* womp up a test structure to all cut/paste code */
329 } Clock_Time
, *clock_time
;
331 clock_time
= &Clock_Time
;
333 /* first test this #define */
334 #define days_per_year(x) ((x) % 4 ? 365 : ((x % 400) ? ((x % 100) ? 366 : 365) : 366))
336 for ( year
= 1400; year
<= 2200; year
++ )
341 LeapSw
= GoodLeap(year
);
342 DayCnt
= (int)days_per_year(year
);
344 if ( ( LeapSw
? 366 : 365 ) != DayCnt
)
348 " days_per_year() %4d %2d %3d *** ERROR\n",
349 year
, LeapSw
, DayCnt
);
354 /* test (what is now julian0) calculations */
356 Days1970
= Days( 1970 ); /* get days since 1970 using a known good */
358 for ( year
= 1970; year
< yearend
; year
++ )
363 clock_time
->year
= year
;
365 /* here is the code we are testing, cut and pasted out of the source */
366 #if 0 /* old BUGGY code that has Y2K (and many other) failures */
367 /* ghealton: this logic FAILED with great frequency when run
368 * over a period of time, including for year 2000. True, it
369 * had more successes than failures, but that's not really good
370 * enough for critical time distribution software.
371 * It is so awful I wonder if it has had a history of failure
373 t
= (clock_time
->year
- 1970) * 365;
374 t
+= (clock_time
->year
>> 2) - (1970 >> 2);
375 t
-= clock_time
->year
/ 100 - 1970 / 100;
376 t
+= clock_time
->year
/ 400 - 1970 / 400;
378 /* (immediate feare of rounding errors on integer
379 * **divisions proved well founded) */
382 /* my replacement, based on Days() above */
383 t
= julian0(year
) - julian0(1970);
386 /* compare result in t against trusted calculations */
387 DaysYear
= Days( year
); /* get days to this year */
388 if ( t
!= DaysYear
- Days1970
)
392 " %4d 1970=%-8ld %4d=%-8ld %-3ld t=%-8ld *** ERROR ***\n",
393 year
, (long)Days1970
,
396 (long)(DaysYear
- Days1970
),
403 debug
= 1; /* enable debugging */
404 for ( year
= 1970; year
< yearend
; year
++ )
405 { /* (limited by theory unix 2038 related bug lives by, but
406 * ends in yearend) */
416 ct
.hour
= ct
.minute
= ct
.second
= ct
.usecond
= 0;
422 Observed
= parse_to_unixtime( &ct
, &Flag
);
423 if ( ct
.year
!= year
)
426 "%04d: parse_to_unixtime(,%d) CORRUPTED ct.year: was %d\n",
427 (int)year
, (int)Flag
, (int)ct
.year
);
431 t
= julian0(year
) - julian0(1970); /* Julian day from 1970 */
432 Expected
= t
* 24 * 60 * 60;
433 if ( Observed
!= Expected
|| Flag
)
434 { /* time difference */
436 "%04d: parse_to_unixtime(,%d) FAILURE: was=%lu s/b=%lu (%ld)\n",
438 (unsigned long)Observed
, (unsigned long)Expected
,
439 ((long)Observed
- (long)Expected
) );
444 if ( year
>= YEAR_PIVOT
+1900 )
446 /* check year % 100 code we put into parse_to_unixtime() */
448 ct
.year
= year
% 100;
451 Observed
= parse_to_unixtime( &ct
, &Flag
);
453 if ( Observed
!= Expected
|| Flag
)
454 { /* time difference */
456 "%04d: parse_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu (%ld)\n",
457 year
, (int)ct
.year
, (int)Flag
,
458 (unsigned long)Observed
, (unsigned long)Expected
,
459 ((long)Observed
- (long)Expected
) );
464 /* check year - 1900 code we put into parse_to_unixtime() */
466 ct
.year
= year
- 1900;
469 Observed
= parse_to_unixtime( &ct
, &Flag
);
471 if ( Observed
!= Expected
|| Flag
)
472 { /* time difference */
474 "%04d: parse_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu (%ld)\n",
475 year
, (int)ct
.year
, (int)Flag
,
476 (unsigned long)Observed
, (unsigned long)Expected
,
477 ((long)Observed
- (long)Expected
) );
489 puts( " libntp/caljulian.c" );
490 { /* test caljulian() */
492 u_long ntp_time
; /* NTP time */
494 year
= year0
; /* calculate the basic year */
495 printf( " starting year %04d\n", (int)year0
);
496 printf( " ending year %04d\n", (int)yearend
);
499 ntp_time
= julian0( year0
); /* NTP starts in 1900-01-01 */
500 #if DAY_NTP_STARTS == 693596
501 ntp_time
-= 365; /* BIAS required for successful test */
503 if ( DAY_NTP_STARTS
!= ntp_time
)
507 "%04d: DAY_NTP_STARTS (%ld) NOT TRUE VALUE OF %ld (%ld)\n",
509 (long)DAY_NTP_STARTS
, (long)ntp_time
,
510 (long)DAY_NTP_STARTS
- (long)ntp_time
);
513 for ( ; year
< yearend
; year
++ )
516 /* 01-01 for the current year */
517 ntp_time
= Days( year
) - Days( year0
); /* days into NTP time */
518 ntp_time
*= 24 * 60 * 60; /* convert into seconds */
519 caljulian( ntp_time
, &ot
); /* convert January 1 */
522 || ot
.monthday
!= 1 )
525 fprintf( stdout
, "%lu: EXPECTED %04d-01-01: FOUND %04d-%02d-%02d\n",
526 (unsigned long)ntp_time
,
528 (int)ot
.year
, (int)ot
.month
, (int)ot
.monthday
);
532 ntp_time
+= (31 + 28-1) * ( 24 * 60 * 60 ); /* advance to 02-28 */
533 caljulian( ntp_time
, &ot
); /* convert Feb 28 */
536 || ot
.monthday
!= 28 )
539 fprintf( stdout
, "%lu: EXPECTED %04d-02-28: FOUND %04d-%02d-%02d\n",
540 (unsigned long)ntp_time
,
542 (int)ot
.year
, (int)ot
.month
, (int)ot
.monthday
);
547 int m
; /* expected month */
548 int d
; /* expected day */
550 m
= isleap_4(year
) ? 2 : 3;
551 d
= isleap_4(year
) ? 29 : 1;
553 ntp_time
+= ( 24 * 60 * 60 ); /* advance to the next day */
554 caljulian( ntp_time
, &ot
); /* convert this day */
557 || ot
.monthday
!= d
)
560 fprintf( stdout
, "%lu: EXPECTED %04d-%02d-%02d: FOUND %04d-%02d-%02d\n",
561 (unsigned long)ntp_time
,
563 (int)ot
.year
, (int)ot
.month
, (int)ot
.monthday
);
571 puts( " libntp/caltontp.c" );
572 { /* test caltontp() */
574 u_long ntp_time
; /* NTP time */
576 year
= year0
; /* calculate the basic year */
577 printf( " starting year %04d\n", (int)year0
);
578 printf( " ending year %04d\n", (int)yearend
);
581 for ( ; year
< yearend
; year
++ )
585 /* 01-01 for the current year */
587 ot
.month
= ot
.monthday
= 1; /* unused, but set anyway JIC */
588 ot
.yearday
= 1; /* this is the magic value used by caltontp() */
589 ot
.hour
= ot
.minute
= ot
.second
= 0;
591 ntp_time
= Days( year
) - Days( year0
); /* days into NTP time */
592 ntp_time
*= 24 * 60 * 60; /* convert into seconds */
593 ObservedNtp
= caltontp( &ot
);
594 if ( ntp_time
!= ObservedNtp
)
597 fprintf( stdout
, "%d: EXPECTED %lu: FOUND %lu (%ld)\n",
599 (unsigned long)ntp_time
, (unsigned long)ObservedNtp
,
600 (long)ntp_time
- (long)ObservedNtp
);
605 /* now call caljulian as a type of failsafe supercheck */
606 caljulian( ObservedNtp
, &ot
); /* convert January 1 */
609 || ot
.monthday
!= 1 )
612 fprintf( stdout
, "%lu: caljulian FAILSAFE EXPECTED %04d-01-01: FOUND %04d-%02d-%02d\n",
613 (unsigned long)ObservedNtp
,
615 (int)ot
.year
, (int)ot
.month
, (int)ot
.monthday
);
622 fprintf( stdout
, "%d WARNINGS\n", Warnings
);
624 fprintf( stdout
, "%d FATAL ERRORS\n", Fatals
);
625 return Fatals
? 1 : 0;