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 # include <sys/signal.h>
49 # ifdef HAVE_SYS_IOCTL_H
50 # include <sys/ioctl.h>
51 # endif /* HAVE_SYS_IOCTL_H */
52 # if !defined(VMS) /*wjm*/
53 # include <sys/resource.h>
59 # include "../libntp/log.h"
60 #endif /* SYS_WINNT */
61 #if defined(HAVE_RTPRIO)
62 # ifdef HAVE_SYS_RESOURCE_H
63 # include <sys/resource.h>
65 # ifdef HAVE_SYS_LOCK_H
66 # include <sys/lock.h>
68 # include <sys/rtprio.h>
71 # ifdef HAVE_SYS_LOCK_H
72 # include <sys/lock.h>
76 #if defined(HAVE_SCHED_SETSCHEDULER)
80 # ifdef HAVE_SYS_SCHED_H
81 # include <sys/sched.h>
85 #if defined(HAVE_SYS_MMAN_H)
86 # include <sys/mman.h>
94 # include <apollo/base.h>
95 #endif /* SYS_DOMAINOS */
97 /* } end definitions lifted from ntpd.c */
99 #include "ntp_calendar.h"
102 #define GoodLeap(Year) (((Year)%4 || (!((Year)%100) && (Year)%400)) ? 0 : 13 )
104 volatile int debug = 0; /* debugging requests for parse stuff */
105 char const *progname = "check_y2k";
108 Days ( int Year ) /* return number of days since year "0" */
111 /* this is a known to be good algorithm */
112 Return = Year * 365; /* first aproximation to the value */
114 { /* see notes in libparse/parse.c if you want a PROPER
115 * **generic algorithm. */
116 Return += (Year+3) / 4; /* add in (too many) leap days */
117 Return -= (Year-1) / 100; /* reduce by (too many) centurys */
118 Return += (Year-1) / 400; /* get final answer */
124 static int year0 = 1900; /* sarting year for NTP time */
125 static int yearend; /* ending year we test for NTP time.
126 * 32-bit systems: through 2036, the
127 **year in which NTP time overflows.
128 * 64-bit systems: a reasonable upper
129 **limit (well, maybe somewhat beyond
130 **reasonable, but well before the
131 **max time, by which time the earth
134 static struct tm LocalTime;
136 #define Error(year) if ( (year)>=2036 && LocalTime.tm_year < 110 ) \
137 Warnings++; else Fatals++
146 Time = time( (time_t *)NULL )
147 #ifdef TESTTIMEOFFSET
151 LocalTime = *localtime( &Time );
153 year = ( sizeof( u_long ) > 4 ) /* save max span using year as temp */
154 ? ( 400 * 3 ) /* three greater gregorian cycles */
155 : ((int)(0x7FFFFFFF / 365.242 / 24/60/60)* 2 ); /*32-bit limit*/
156 /* NOTE: will automacially expand test years on
157 * 64 bit machines.... this may cause some of the
158 * existing ntp logic to fail for years beyond
159 * 2036 (the current 32-bit limit). If all checks
160 * fail ONLY beyond year 2036 you may ignore such
161 * errors, at least for a decade or so. */
162 yearend = year0 + year;
164 puts( " internal self check" );
165 { /* verify our own logic used to verify repairs */
168 if ( year0 >= yearend )
170 fprintf( stdout, "year0=%d NOT LESS THAN yearend=%d (span=%d)\n",
171 (int)year0, (int)yearend, (int)year );
178 save_year = LocalTime.tm_year; /* save current year */
181 LocalTime.tm_year = year - 1900;
182 Fatals = Warnings = 0;
183 Error(year); /* should increment Fatals */
187 "%4d: %s(%d): FATAL DID NOT INCREMENT (Fatals=%d Warnings=%d)\n",
188 (int)year, __FILE__, __LINE__, (int)Fatals, (int)Warnings );
192 year = 2100; /* test year > limit but CURRENT year < limit */
193 Fatals = Warnings = 0;
194 Error(year); /* should increment Fatals */
198 "%4d: %s(%d): WARNING DID NOT INCREMENT (Fatals=%d Warnings=%d)\n",
199 (int)year, __FILE__, __LINE__, (int)Fatals, (int)Warnings );
202 Fatals = Warnings = 0;
203 LocalTime.tm_year = year - 1900; /* everything > limit */
204 Error(1980); /* should increment Fatals */
208 "%4d: %s(%d): FATALS DID NOT INCREMENT (Fatals=%d Warnings=%d)\n",
209 (int)year, __FILE__, __LINE__, (int)Fatals, (int)Warnings );
213 LocalTime.tm_year = save_year;
216 days = 365+1; /* days in year 0 + 1 more day */
217 for ( year = 1; year <= 2500; year++ )
223 fprintf( stdout, "%04d: Days() DAY COUNT ERROR: s/b=%ld was=%ld\n",
224 year, (long)days, (long)Test );
225 exit(2); /* would throw off many other tests */
228 Test = julian0(year); /* compare with julian0() macro */
231 fprintf( stdout, "%04d: julian0() DAY COUNT ERROR: s/b=%ld was=%ld\n",
232 year, (long)days, (long)Test );
233 exit(2); /* would throw off many other tests */
237 if ( isleap_4(year) ) days++;
240 if ( isleap_4(1999) )
242 fprintf( stdout, "isleap_4(1999) REPORTED TRUE\n" );
245 if ( !isleap_4(2000) )
247 fprintf( stdout, "isleap_4(2000) REPORTED FALSE\n" );
250 if ( isleap_4(2001) )
252 fprintf( stdout, "isleap_4(1999) REPORTED TRUE\n" );
256 if ( !isleap_tm(2000-1900) )
258 fprintf( stdout, "isleap_tm(100) REPORTED FALSE\n" );
263 Fatals = Warnings = 0;
265 puts( " include/ntp.h" );
266 { /* test our new isleap_*() #define "functions" */
268 for ( year = 1400; year <= 2200; year++ )
273 LeapSw = GoodLeap(year);
274 IsLeapSw = isleap_4(year);
276 if ( !!LeapSw != !!IsLeapSw )
280 " %4d %2d %3d *** ERROR\n", year, LeapSw, IsLeapSw );
284 IsLeapSw = isleap_tm(year-1900);
286 if ( !!LeapSw != !!IsLeapSw )
290 " %4d %2d %3d *** ERROR\n", year, LeapSw, IsLeapSw );
296 puts( " include/ntp_calendar.h" );
297 { /* I belive this is good, but just to be sure... */
299 /* we are testing this #define */
300 #define is_leapyear(y) (y%4 == 0 && !(y%100 == 0 && !(y%400 == 0)))
302 for ( year = 1400; year <= 2200; year++ )
306 LeapSw = GoodLeap(year);
308 if ( !(!LeapSw) != !(!is_leapyear(year)) )
312 " %4d %2d *** ERROR\n", year, LeapSw );
319 puts( " libparse/parse.c" );
321 long Days1970; /* days from 1900 to 1970 */
323 struct ParseTime /* womp up a test structure to all cut/paste code */
326 } Clock_Time, *clock_time;
328 clock_time = &Clock_Time;
330 /* first test this #define */
331 #define days_per_year(x) ((x) % 4 ? 365 : ((x % 400) ? ((x % 100) ? 366 : 365) : 366))
333 for ( year = 1400; year <= 2200; year++ )
338 LeapSw = GoodLeap(year);
339 DayCnt = (int)days_per_year(year);
341 if ( ( LeapSw ? 366 : 365 ) != DayCnt )
345 " days_per_year() %4d %2d %3d *** ERROR\n",
346 year, LeapSw, DayCnt );
351 /* test (what is now julian0) calculations */
353 Days1970 = Days( 1970 ); /* get days since 1970 using a known good */
355 for ( year = 1970; year < yearend; year++ )
360 clock_time->year = year;
362 /* here is the code we are testing, cut and pasted out of the source */
363 #if 0 /* old BUGGY code that has Y2K (and many other) failures */
364 /* ghealton: this logic FAILED with great frequency when run
365 * over a period of time, including for year 2000. True, it
366 * had more successes than failures, but that's not really good
367 * enough for critical time distribution software.
368 * It is so awful I wonder if it has had a history of failure
370 t = (clock_time->year - 1970) * 365;
371 t += (clock_time->year >> 2) - (1970 >> 2);
372 t -= clock_time->year / 100 - 1970 / 100;
373 t += clock_time->year / 400 - 1970 / 400;
375 /* (immediate feare of rounding errors on integer
376 * **divisions proved well founded) */
379 /* my replacement, based on Days() above */
380 t = julian0(year) - julian0(1970);
383 /* compare result in t against trusted calculations */
384 DaysYear = Days( year ); /* get days to this year */
385 if ( t != DaysYear - Days1970 )
389 " %4d 1970=%-8ld %4d=%-8ld %-3ld t=%-8ld *** ERROR ***\n",
390 year, (long)Days1970,
393 (long)(DaysYear - Days1970),
400 debug = 1; /* enable debugging */
401 for ( year = 1970; year < yearend; year++ )
402 { /* (limited by theory unix 2038 related bug lives by, but
403 * ends in yearend) */
413 ct.hour = ct.minute = ct.second = ct.usecond = 0;
419 Observed = parse_to_unixtime( &ct, &Flag );
420 if ( ct.year != year )
423 "%04d: parse_to_unixtime(,%d) CORRUPTED ct.year: was %d\n",
424 (int)year, (int)Flag, (int)ct.year );
428 t = julian0(year) - julian0(1970); /* Julian day from 1970 */
429 Expected = t * 24 * 60 * 60;
430 if ( Observed != Expected || Flag )
431 { /* time difference */
433 "%04d: parse_to_unixtime(,%d) FAILURE: was=%lu s/b=%lu (%ld)\n",
435 (unsigned long)Observed, (unsigned long)Expected,
436 ((long)Observed - (long)Expected) );
441 if ( year >= YEAR_PIVOT+1900 )
443 /* check year % 100 code we put into parse_to_unixtime() */
445 ct.year = year % 100;
448 Observed = parse_to_unixtime( &ct, &Flag );
450 if ( Observed != Expected || Flag )
451 { /* time difference */
453 "%04d: parse_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu (%ld)\n",
454 year, (int)ct.year, (int)Flag,
455 (unsigned long)Observed, (unsigned long)Expected,
456 ((long)Observed - (long)Expected) );
461 /* check year - 1900 code we put into parse_to_unixtime() */
463 ct.year = year - 1900;
466 Observed = parse_to_unixtime( &ct, &Flag );
468 if ( Observed != Expected || Flag )
469 { /* time difference */
471 "%04d: parse_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu (%ld)\n",
472 year, (int)ct.year, (int)Flag,
473 (unsigned long)Observed, (unsigned long)Expected,
474 ((long)Observed - (long)Expected) );
486 puts( " libntp/caljulian.c" );
487 { /* test caljulian() */
489 u_long ntp_time; /* NTP time */
491 year = year0; /* calculate the basic year */
492 printf( " starting year %04d\n", (int)year0 );
493 printf( " ending year %04d\n", (int)yearend );
496 ntp_time = julian0( year0 ); /* NTP starts in 1900-01-01 */
497 #if DAY_NTP_STARTS == 693596
498 ntp_time -= 365; /* BIAS required for successful test */
500 if ( DAY_NTP_STARTS != ntp_time )
504 "%04d: DAY_NTP_STARTS (%ld) NOT TRUE VALUE OF %ld (%ld)\n",
506 (long)DAY_NTP_STARTS, (long)ntp_time,
507 (long)DAY_NTP_STARTS - (long)ntp_time );
510 for ( ; year < yearend; year++ )
513 /* 01-01 for the current year */
514 ntp_time = Days( year ) - Days( year0 ); /* days into NTP time */
515 ntp_time *= 24 * 60 * 60; /* convert into seconds */
516 caljulian( ntp_time, &ot ); /* convert January 1 */
519 || ot.monthday != 1 )
522 fprintf( stdout, "%lu: EXPECTED %04d-01-01: FOUND %04d-%02d-%02d\n",
523 (unsigned long)ntp_time,
525 (int)ot.year, (int)ot.month, (int)ot.monthday );
529 ntp_time += (31 + 28-1) * ( 24 * 60 * 60 ); /* advance to 02-28 */
530 caljulian( ntp_time, &ot ); /* convert Feb 28 */
533 || ot.monthday != 28 )
536 fprintf( stdout, "%lu: EXPECTED %04d-02-28: FOUND %04d-%02d-%02d\n",
537 (unsigned long)ntp_time,
539 (int)ot.year, (int)ot.month, (int)ot.monthday );
544 int m; /* expected month */
545 int d; /* expected day */
547 m = isleap_4(year) ? 2 : 3;
548 d = isleap_4(year) ? 29 : 1;
550 ntp_time += ( 24 * 60 * 60 ); /* advance to the next day */
551 caljulian( ntp_time, &ot ); /* convert this day */
554 || ot.monthday != d )
557 fprintf( stdout, "%lu: EXPECTED %04d-%02d-%02d: FOUND %04d-%02d-%02d\n",
558 (unsigned long)ntp_time,
560 (int)ot.year, (int)ot.month, (int)ot.monthday );
568 puts( " libntp/caltontp.c" );
569 { /* test caltontp() */
571 u_long ntp_time; /* NTP time */
573 year = year0; /* calculate the basic year */
574 printf( " starting year %04d\n", (int)year0 );
575 printf( " ending year %04d\n", (int)yearend );
578 for ( ; year < yearend; year++ )
582 /* 01-01 for the current year */
584 ot.month = ot.monthday = 1; /* unused, but set anyway JIC */
585 ot.yearday = 1; /* this is the magic value used by caltontp() */
586 ot.hour = ot.minute = ot.second = 0;
588 ntp_time = Days( year ) - Days( year0 ); /* days into NTP time */
589 ntp_time *= 24 * 60 * 60; /* convert into seconds */
590 ObservedNtp = caltontp( &ot );
591 if ( ntp_time != ObservedNtp )
594 fprintf( stdout, "%d: EXPECTED %lu: FOUND %lu (%ld)\n",
596 (unsigned long)ntp_time, (unsigned long)ObservedNtp ,
597 (long)ntp_time - (long)ObservedNtp );
602 /* now call caljulian as a type of failsafe supercheck */
603 caljulian( ObservedNtp, &ot ); /* convert January 1 */
606 || ot.monthday != 1 )
609 fprintf( stdout, "%lu: caljulian FAILSAFE EXPECTED %04d-01-01: FOUND %04d-%02d-%02d\n",
610 (unsigned long)ObservedNtp,
612 (int)ot.year, (int)ot.month, (int)ot.monthday );
619 fprintf( stdout, "%d WARNINGS\n", Warnings );
621 fprintf( stdout, "%d FATAL ERRORS\n", Fatals );
622 return Fatals ? 1 : 0;