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 char const *progname = "check_y2k";
110 Days ( int Year ) /* return number of days since year "0" */
113 /* this is a known to be good algorithm */
114 Return = Year * 365; /* first aproximation to the value */
116 { /* see notes in libparse/parse.c if you want a PROPER
117 * **generic algorithm. */
118 Return += (Year+3) / 4; /* add in (too many) leap days */
119 Return -= (Year-1) / 100; /* reduce by (too many) centurys */
120 Return += (Year-1) / 400; /* get final answer */
126 static int year0 = 1900; /* sarting year for NTP time */
127 static int yearend; /* ending year we test for NTP time.
128 * 32-bit systems: through 2036, the
129 **year in which NTP time overflows.
130 * 64-bit systems: a reasonable upper
131 **limit (well, maybe somewhat beyond
132 **reasonable, but well before the
133 **max time, by which time the earth
136 static struct tm LocalTime;
138 #define Error(year) if ( (year)>=2036 && LocalTime.tm_year < 110 ) \
139 Warnings++; else Fatals++
148 Time = time( (time_t *)NULL )
149 #ifdef TESTTIMEOFFSET
153 LocalTime = *localtime( &Time );
155 year = ( sizeof( u_long ) > 4 ) /* save max span using year as temp */
156 ? ( 400 * 3 ) /* three greater gregorian cycles */
157 : ((int)(0x7FFFFFFF / 365.242 / 24/60/60)* 2 ); /*32-bit limit*/
158 /* NOTE: will automacially expand test years on
159 * 64 bit machines.... this may cause some of the
160 * existing ntp logic to fail for years beyond
161 * 2036 (the current 32-bit limit). If all checks
162 * fail ONLY beyond year 2036 you may ignore such
163 * errors, at least for a decade or so. */
164 yearend = year0 + year;
166 puts( " internal self check" );
167 { /* verify our own logic used to verify repairs */
170 if ( year0 >= yearend )
172 fprintf( stdout, "year0=%d NOT LESS THAN yearend=%d (span=%d)\n",
173 (int)year0, (int)yearend, (int)year );
180 save_year = LocalTime.tm_year; /* save current year */
183 LocalTime.tm_year = year - 1900;
184 Fatals = Warnings = 0;
185 Error(year); /* should increment Fatals */
189 "%4d: %s(%d): FATAL DID NOT INCREMENT (Fatals=%d Warnings=%d)\n",
190 (int)year, __FILE__, __LINE__, (int)Fatals, (int)Warnings );
194 year = 2100; /* test year > limit but CURRENT year < limit */
195 Fatals = Warnings = 0;
196 Error(year); /* should increment Fatals */
200 "%4d: %s(%d): WARNING DID NOT INCREMENT (Fatals=%d Warnings=%d)\n",
201 (int)year, __FILE__, __LINE__, (int)Fatals, (int)Warnings );
204 Fatals = Warnings = 0;
205 LocalTime.tm_year = year - 1900; /* everything > limit */
206 Error(1980); /* should increment Fatals */
210 "%4d: %s(%d): FATALS DID NOT INCREMENT (Fatals=%d Warnings=%d)\n",
211 (int)year, __FILE__, __LINE__, (int)Fatals, (int)Warnings );
215 LocalTime.tm_year = save_year;
218 days = 365+1; /* days in year 0 + 1 more day */
219 for ( year = 1; year <= 2500; year++ )
225 fprintf( stdout, "%04d: Days() DAY COUNT ERROR: s/b=%ld was=%ld\n",
226 year, (long)days, (long)Test );
227 exit(2); /* would throw off many other tests */
230 Test = julian0(year); /* compare with julian0() macro */
233 fprintf( stdout, "%04d: julian0() DAY COUNT ERROR: s/b=%ld was=%ld\n",
234 year, (long)days, (long)Test );
235 exit(2); /* would throw off many other tests */
239 if ( isleap_4(year) ) days++;
242 if ( isleap_4(1999) )
244 fprintf( stdout, "isleap_4(1999) REPORTED TRUE\n" );
247 if ( !isleap_4(2000) )
249 fprintf( stdout, "isleap_4(2000) REPORTED FALSE\n" );
252 if ( isleap_4(2001) )
254 fprintf( stdout, "isleap_4(1999) REPORTED TRUE\n" );
258 if ( !isleap_tm(2000-1900) )
260 fprintf( stdout, "isleap_tm(100) REPORTED FALSE\n" );
265 Fatals = Warnings = 0;
267 puts( " include/ntp.h" );
268 { /* test our new isleap_*() #define "functions" */
270 for ( year = 1400; year <= 2200; year++ )
275 LeapSw = GoodLeap(year);
276 IsLeapSw = isleap_4(year);
278 if ( !!LeapSw != !!IsLeapSw )
282 " %4d %2d %3d *** ERROR\n", year, LeapSw, IsLeapSw );
286 IsLeapSw = isleap_tm(year-1900);
288 if ( !!LeapSw != !!IsLeapSw )
292 " %4d %2d %3d *** ERROR\n", year, LeapSw, IsLeapSw );
298 puts( " include/ntp_calendar.h" );
299 { /* I belive this is good, but just to be sure... */
301 /* we are testing this #define */
302 #define is_leapyear(y) (y%4 == 0 && !(y%100 == 0 && !(y%400 == 0)))
304 for ( year = 1400; year <= 2200; year++ )
308 LeapSw = GoodLeap(year);
310 if ( !(!LeapSw) != !(!is_leapyear(year)) )
314 " %4d %2d *** ERROR\n", year, LeapSw );
321 puts( " libparse/parse.c" );
323 long Days1970; /* days from 1900 to 1970 */
325 struct ParseTime /* womp up a test structure to all cut/paste code */
328 } Clock_Time, *clock_time;
330 clock_time = &Clock_Time;
332 /* first test this #define */
333 #define days_per_year(x) ((x) % 4 ? 365 : ((x % 400) ? ((x % 100) ? 366 : 365) : 366))
335 for ( year = 1400; year <= 2200; year++ )
340 LeapSw = GoodLeap(year);
341 DayCnt = (int)days_per_year(year);
343 if ( ( LeapSw ? 366 : 365 ) != DayCnt )
347 " days_per_year() %4d %2d %3d *** ERROR\n",
348 year, LeapSw, DayCnt );
353 /* test (what is now julian0) calculations */
355 Days1970 = Days( 1970 ); /* get days since 1970 using a known good */
357 for ( year = 1970; year < yearend; year++ )
362 clock_time->year = year;
364 /* here is the code we are testing, cut and pasted out of the source */
365 #if 0 /* old BUGGY code that has Y2K (and many other) failures */
366 /* ghealton: this logic FAILED with great frequency when run
367 * over a period of time, including for year 2000. True, it
368 * had more successes than failures, but that's not really good
369 * enough for critical time distribution software.
370 * It is so awful I wonder if it has had a history of failure
372 t = (clock_time->year - 1970) * 365;
373 t += (clock_time->year >> 2) - (1970 >> 2);
374 t -= clock_time->year / 100 - 1970 / 100;
375 t += clock_time->year / 400 - 1970 / 400;
377 /* (immediate feare of rounding errors on integer
378 * **divisions proved well founded) */
381 /* my replacement, based on Days() above */
382 t = julian0(year) - julian0(1970);
385 /* compare result in t against trusted calculations */
386 DaysYear = Days( year ); /* get days to this year */
387 if ( t != DaysYear - Days1970 )
391 " %4d 1970=%-8ld %4d=%-8ld %-3ld t=%-8ld *** ERROR ***\n",
392 year, (long)Days1970,
395 (long)(DaysYear - Days1970),
402 debug = 1; /* enable debugging */
403 for ( year = 1970; year < yearend; year++ )
404 { /* (limited by theory unix 2038 related bug lives by, but
405 * ends in yearend) */
415 ct.hour = ct.minute = ct.second = ct.usecond = 0;
421 Observed = parse_to_unixtime( &ct, &Flag );
422 if ( ct.year != year )
425 "%04d: parse_to_unixtime(,%d) CORRUPTED ct.year: was %d\n",
426 (int)year, (int)Flag, (int)ct.year );
430 t = julian0(year) - julian0(1970); /* Julian day from 1970 */
431 Expected = t * 24 * 60 * 60;
432 if ( Observed != Expected || Flag )
433 { /* time difference */
435 "%04d: parse_to_unixtime(,%d) FAILURE: was=%lu s/b=%lu (%ld)\n",
437 (unsigned long)Observed, (unsigned long)Expected,
438 ((long)Observed - (long)Expected) );
443 if ( year >= YEAR_PIVOT+1900 )
445 /* check year % 100 code we put into parse_to_unixtime() */
447 ct.year = year % 100;
450 Observed = parse_to_unixtime( &ct, &Flag );
452 if ( Observed != Expected || Flag )
453 { /* time difference */
455 "%04d: parse_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu (%ld)\n",
456 year, (int)ct.year, (int)Flag,
457 (unsigned long)Observed, (unsigned long)Expected,
458 ((long)Observed - (long)Expected) );
463 /* check year - 1900 code we put into parse_to_unixtime() */
465 ct.year = year - 1900;
468 Observed = parse_to_unixtime( &ct, &Flag );
470 if ( Observed != Expected || Flag )
471 { /* time difference */
473 "%04d: parse_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu (%ld)\n",
474 year, (int)ct.year, (int)Flag,
475 (unsigned long)Observed, (unsigned long)Expected,
476 ((long)Observed - (long)Expected) );
488 puts( " libntp/caljulian.c" );
489 { /* test caljulian() */
491 u_long ntp_time; /* NTP time */
493 year = year0; /* calculate the basic year */
494 printf( " starting year %04d\n", (int)year0 );
495 printf( " ending year %04d\n", (int)yearend );
498 ntp_time = julian0( year0 ); /* NTP starts in 1900-01-01 */
499 #if DAY_NTP_STARTS == 693596
500 ntp_time -= 365; /* BIAS required for successful test */
502 if ( DAY_NTP_STARTS != ntp_time )
506 "%04d: DAY_NTP_STARTS (%ld) NOT TRUE VALUE OF %ld (%ld)\n",
508 (long)DAY_NTP_STARTS, (long)ntp_time,
509 (long)DAY_NTP_STARTS - (long)ntp_time );
512 for ( ; year < yearend; year++ )
515 /* 01-01 for the current year */
516 ntp_time = Days( year ) - Days( year0 ); /* days into NTP time */
517 ntp_time *= 24 * 60 * 60; /* convert into seconds */
518 caljulian( ntp_time, &ot ); /* convert January 1 */
521 || ot.monthday != 1 )
524 fprintf( stdout, "%lu: EXPECTED %04d-01-01: FOUND %04d-%02d-%02d\n",
525 (unsigned long)ntp_time,
527 (int)ot.year, (int)ot.month, (int)ot.monthday );
531 ntp_time += (31 + 28-1) * ( 24 * 60 * 60 ); /* advance to 02-28 */
532 caljulian( ntp_time, &ot ); /* convert Feb 28 */
535 || ot.monthday != 28 )
538 fprintf( stdout, "%lu: EXPECTED %04d-02-28: FOUND %04d-%02d-%02d\n",
539 (unsigned long)ntp_time,
541 (int)ot.year, (int)ot.month, (int)ot.monthday );
546 int m; /* expected month */
547 int d; /* expected day */
549 m = isleap_4(year) ? 2 : 3;
550 d = isleap_4(year) ? 29 : 1;
552 ntp_time += ( 24 * 60 * 60 ); /* advance to the next day */
553 caljulian( ntp_time, &ot ); /* convert this day */
556 || ot.monthday != d )
559 fprintf( stdout, "%lu: EXPECTED %04d-%02d-%02d: FOUND %04d-%02d-%02d\n",
560 (unsigned long)ntp_time,
562 (int)ot.year, (int)ot.month, (int)ot.monthday );
570 puts( " libntp/caltontp.c" );
571 { /* test caltontp() */
573 u_long ntp_time; /* NTP time */
575 year = year0; /* calculate the basic year */
576 printf( " starting year %04d\n", (int)year0 );
577 printf( " ending year %04d\n", (int)yearend );
580 for ( ; year < yearend; year++ )
584 /* 01-01 for the current year */
586 ot.month = ot.monthday = 1; /* unused, but set anyway JIC */
587 ot.yearday = 1; /* this is the magic value used by caltontp() */
588 ot.hour = ot.minute = ot.second = 0;
590 ntp_time = Days( year ) - Days( year0 ); /* days into NTP time */
591 ntp_time *= 24 * 60 * 60; /* convert into seconds */
592 ObservedNtp = caltontp( &ot );
593 if ( ntp_time != ObservedNtp )
596 fprintf( stdout, "%d: EXPECTED %lu: FOUND %lu (%ld)\n",
598 (unsigned long)ntp_time, (unsigned long)ObservedNtp ,
599 (long)ntp_time - (long)ObservedNtp );
604 /* now call caljulian as a type of failsafe supercheck */
605 caljulian( ObservedNtp, &ot ); /* convert January 1 */
608 || ot.monthday != 1 )
611 fprintf( stdout, "%lu: caljulian FAILSAFE EXPECTED %04d-01-01: FOUND %04d-%02d-%02d\n",
612 (unsigned long)ObservedNtp,
614 (int)ot.year, (int)ot.month, (int)ot.monthday );
621 fprintf( stdout, "%d WARNINGS\n", Warnings );
623 fprintf( stdout, "%d FATAL ERRORS\n", Fatals );
624 return Fatals ? 1 : 0;