Sync usage with man page.
[netbsd-mini2440.git] / dist / ntp / ntpd / check_y2k.c
blob0b0e504017e77827ea0ab35360336c4ef7128575
1 /* $NetBSD$ */
3 /* check_y2k.c -- test ntp code constructs for Y2K correctness Y2KFixes [*/
5 /*
6 Code invoked by `make check`. Not part of ntpd and not to be
7 installed.
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
16 we did.
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
26 a controled order).
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. */
32 #ifdef HAVE_CONFIG_H
33 # include <config.h>
34 #endif
36 #include "ntpd.h"
38 #ifdef HAVE_UNISTD_H
39 # include <unistd.h>
40 #endif
41 #ifdef HAVE_SYS_STAT_H
42 # include <sys/stat.h>
43 #endif
44 #include <stdio.h>
45 #include <errno.h>
46 #ifndef SYS_WINNT
47 # if !defined(VMS) /*wjm*/
48 # include <sys/param.h>
49 # endif /* VMS */
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>
59 # endif /* VMS */
60 #else
61 # include <signal.h>
62 # include <process.h>
63 # include <io.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>
69 # endif
70 # ifdef HAVE_SYS_LOCK_H
71 # include <sys/lock.h>
72 # endif
73 # include <sys/rtprio.h>
74 #else
75 # ifdef HAVE_PLOCK
76 # ifdef HAVE_SYS_LOCK_H
77 # include <sys/lock.h>
78 # endif
79 # endif
80 #endif
81 #if defined(HAVE_SCHED_SETSCHEDULER)
82 # ifdef HAVE_SCHED_H
83 # include <sched.h>
84 # else
85 # ifdef HAVE_SYS_SCHED_H
86 # include <sys/sched.h>
87 # endif
88 # endif
89 #endif
90 #if defined(HAVE_SYS_MMAN_H)
91 # include <sys/mman.h>
92 #endif
94 #ifdef HAVE_TERMIOS_H
95 # include <termios.h>
96 #endif
98 #ifdef SYS_DOMAINOS
99 # include <apollo/base.h>
100 #endif /* SYS_DOMAINOS */
102 /* } end definitions lifted from ntpd.c */
104 #include "ntp_calendar.h"
105 #include "parse.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";
112 long
113 Days ( int Year ) /* return number of days since year "0" */
115 long Return;
116 /* this is a known to be good algorithm */
117 Return = Year * 365; /* first aproximation to the value */
118 if ( Year >= 1 )
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 */
126 return Return;
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
137 **will be dead.) */
138 static time_t Time;
139 static struct tm LocalTime;
141 #define Error(year) if ( (year)>=2036 && LocalTime.tm_year < 110 ) \
142 Warnings++; else Fatals++
145 main( void )
147 int Fatals;
148 int Warnings;
149 int year;
151 Time = time( (time_t *)NULL )
152 #ifdef TESTTIMEOFFSET
153 + test_time_offset
154 #endif
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 */
171 unsigned long days;
173 if ( year0 >= yearend )
175 fprintf( stdout, "year0=%d NOT LESS THAN yearend=%d (span=%d)\n",
176 (int)year0, (int)yearend, (int)year );
177 exit(2);
181 int save_year;
183 save_year = LocalTime.tm_year; /* save current year */
185 year = 1980;
186 LocalTime.tm_year = year - 1900;
187 Fatals = Warnings = 0;
188 Error(year); /* should increment Fatals */
189 if ( Fatals == 0 )
191 fprintf( stdout,
192 "%4d: %s(%d): FATAL DID NOT INCREMENT (Fatals=%d Warnings=%d)\n",
193 (int)year, __FILE__, __LINE__, (int)Fatals, (int)Warnings );
194 exit(2);
197 year = 2100; /* test year > limit but CURRENT year < limit */
198 Fatals = Warnings = 0;
199 Error(year); /* should increment Fatals */
200 if ( Warnings == 0 )
202 fprintf( stdout,
203 "%4d: %s(%d): WARNING DID NOT INCREMENT (Fatals=%d Warnings=%d)\n",
204 (int)year, __FILE__, __LINE__, (int)Fatals, (int)Warnings );
205 exit(2);
207 Fatals = Warnings = 0;
208 LocalTime.tm_year = year - 1900; /* everything > limit */
209 Error(1980); /* should increment Fatals */
210 if ( Fatals == 0 )
212 fprintf( stdout,
213 "%4d: %s(%d): FATALS DID NOT INCREMENT (Fatals=%d Warnings=%d)\n",
214 (int)year, __FILE__, __LINE__, (int)Fatals, (int)Warnings );
215 exit(2);
218 LocalTime.tm_year = save_year;
221 days = 365+1; /* days in year 0 + 1 more day */
222 for ( year = 1; year <= 2500; year++ )
224 long Test;
225 Test = Days( year );
226 if ( days != Test )
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 */
234 if ( days != Test )
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 */
241 days += 365;
242 if ( isleap_4(year) ) days++;
245 if ( isleap_4(1999) )
247 fprintf( stdout, "isleap_4(1999) REPORTED TRUE\n" );
248 exit(2);
250 if ( !isleap_4(2000) )
252 fprintf( stdout, "isleap_4(2000) REPORTED FALSE\n" );
253 exit(2);
255 if ( isleap_4(2001) )
257 fprintf( stdout, "isleap_4(1999) REPORTED TRUE\n" );
258 exit(2);
261 if ( !isleap_tm(2000-1900) )
263 fprintf( stdout, "isleap_tm(100) REPORTED FALSE\n" );
264 exit(2);
268 Fatals = Warnings = 0;
270 puts( " include/ntp.h" );
271 { /* test our new isleap_*() #define "functions" */
273 for ( year = 1400; year <= 2200; year++ )
275 int LeapSw;
276 int IsLeapSw;
278 LeapSw = GoodLeap(year);
279 IsLeapSw = isleap_4(year);
281 if ( !!LeapSw != !!IsLeapSw )
283 Error(year);
284 fprintf( stdout,
285 " %4d %2d %3d *** ERROR\n", year, LeapSw, IsLeapSw );
286 break;
289 IsLeapSw = isleap_tm(year-1900);
291 if ( !!LeapSw != !!IsLeapSw )
293 Error(year);
294 fprintf( stdout,
295 " %4d %2d %3d *** ERROR\n", year, LeapSw, IsLeapSw );
296 break;
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++ )
309 int LeapSw;
311 LeapSw = GoodLeap(year);
313 if ( !(!LeapSw) != !(!is_leapyear(year)) )
315 Error(year);
316 fprintf( stdout,
317 " %4d %2d *** ERROR\n", year, LeapSw );
318 break;
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 */
330 int year;
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++ )
340 int LeapSw;
341 int DayCnt;
343 LeapSw = GoodLeap(year);
344 DayCnt = (int)days_per_year(year);
346 if ( ( LeapSw ? 366 : 365 ) != DayCnt )
348 Error(year);
349 fprintf( stdout,
350 " days_per_year() %4d %2d %3d *** ERROR\n",
351 year, LeapSw, DayCnt );
352 break;
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++ )
362 unsigned long t;
363 long DaysYear ;
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
374 * and fixes? */
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) */
383 #else
384 /* my replacement, based on Days() above */
385 t = julian0(year) - julian0(1970);
386 #endif
388 /* compare result in t against trusted calculations */
389 DaysYear = Days( year ); /* get days to this year */
390 if ( t != DaysYear - Days1970 )
392 Error(year);
393 fprintf( stdout,
394 " %4d 1970=%-8ld %4d=%-8ld %-3ld t=%-8ld *** ERROR ***\n",
395 year, (long)Days1970,
396 year,
397 (long)DaysYear,
398 (long)(DaysYear - Days1970),
399 (long)t );
403 #if 1 /* { */
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) */
409 clocktime_t ct;
410 time_t Observed;
411 time_t Expected;
412 u_long Flag;
413 unsigned long t;
415 ct.day = 1;
416 ct.month = 1;
417 ct.year = year;
418 ct.hour = ct.minute = ct.second = ct.usecond = 0;
419 ct.utcoffset = 0;
420 ct.utctime = 0;
421 ct.flags = 0;
423 Flag = 0;
424 Observed = parse_to_unixtime( &ct, &Flag );
425 if ( ct.year != year )
427 fprintf( stdout,
428 "%04d: parse_to_unixtime(,%d) CORRUPTED ct.year: was %d\n",
429 (int)year, (int)Flag, (int)ct.year );
430 Error(year);
431 break;
433 t = julian0(year) - julian0(1970); /* Julian day from 1970 */
434 Expected = t * 24 * 60 * 60;
435 if ( Observed != Expected || Flag )
436 { /* time difference */
437 fprintf( stdout,
438 "%04d: parse_to_unixtime(,%d) FAILURE: was=%lu s/b=%lu (%ld)\n",
439 year, (int)Flag,
440 (unsigned long)Observed, (unsigned long)Expected,
441 ((long)Observed - (long)Expected) );
442 Error(year);
443 break;
446 if ( year >= YEAR_PIVOT+1900 )
448 /* check year % 100 code we put into parse_to_unixtime() */
449 ct.utctime = 0;
450 ct.year = year % 100;
451 Flag = 0;
453 Observed = parse_to_unixtime( &ct, &Flag );
455 if ( Observed != Expected || Flag )
456 { /* time difference */
457 fprintf( stdout,
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) );
462 Error(year);
463 break;
466 /* check year - 1900 code we put into parse_to_unixtime() */
467 ct.utctime = 0;
468 ct.year = year - 1900;
469 Flag = 0;
471 Observed = parse_to_unixtime( &ct, &Flag );
473 if ( Observed != Expected || Flag )
474 { /* time difference */
475 fprintf( stdout,
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) );
480 Error(year);
481 break;
487 #endif /* } */
491 puts( " libntp/caljulian.c" );
492 { /* test caljulian() */
493 struct calendar ot;
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 */
504 #endif
505 if ( DAY_NTP_STARTS != ntp_time )
507 Error(year);
508 fprintf( stdout,
509 "%04d: DAY_NTP_STARTS (%ld) NOT TRUE VALUE OF %ld (%ld)\n",
510 (int)year0,
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 */
522 if ( ot.year != year
523 || ot.month != 1
524 || ot.monthday != 1 )
526 Error(year);
527 fprintf( stdout, "%lu: EXPECTED %04d-01-01: FOUND %04d-%02d-%02d\n",
528 (unsigned long)ntp_time,
529 year,
530 (int)ot.year, (int)ot.month, (int)ot.monthday );
531 break;
534 ntp_time += (31 + 28-1) * ( 24 * 60 * 60 ); /* advance to 02-28 */
535 caljulian( ntp_time, &ot ); /* convert Feb 28 */
536 if ( ot.year != year
537 || ot.month != 2
538 || ot.monthday != 28 )
540 Error(year);
541 fprintf( stdout, "%lu: EXPECTED %04d-02-28: FOUND %04d-%02d-%02d\n",
542 (unsigned long)ntp_time,
543 year,
544 (int)ot.year, (int)ot.month, (int)ot.monthday );
545 break;
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 */
557 if ( ot.year != year
558 || ot.month != m
559 || ot.monthday != d )
561 Error(year);
562 fprintf( stdout, "%lu: EXPECTED %04d-%02d-%02d: FOUND %04d-%02d-%02d\n",
563 (unsigned long)ntp_time,
564 year, m, d,
565 (int)ot.year, (int)ot.month, (int)ot.monthday );
566 break;
573 puts( " libntp/caltontp.c" );
574 { /* test caltontp() */
575 struct calendar ot;
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++ )
585 u_long ObservedNtp;
587 /* 01-01 for the current year */
588 ot.year = 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 )
598 Error(year);
599 fprintf( stdout, "%d: EXPECTED %lu: FOUND %lu (%ld)\n",
600 (int)year,
601 (unsigned long)ntp_time, (unsigned long)ObservedNtp ,
602 (long)ntp_time - (long)ObservedNtp );
604 break;
607 /* now call caljulian as a type of failsafe supercheck */
608 caljulian( ObservedNtp, &ot ); /* convert January 1 */
609 if ( ot.year != year
610 || ot.month != 1
611 || ot.monthday != 1 )
613 Error(year);
614 fprintf( stdout, "%lu: caljulian FAILSAFE EXPECTED %04d-01-01: FOUND %04d-%02d-%02d\n",
615 (unsigned long)ObservedNtp,
616 year,
617 (int)ot.year, (int)ot.month, (int)ot.monthday );
618 break;
623 if ( Warnings > 0 )
624 fprintf( stdout, "%d WARNINGS\n", Warnings );
625 if ( Fatals > 0 )
626 fprintf( stdout, "%d FATAL ERRORS\n", Fatals );
627 return Fatals ? 1 : 0;
629 /* Y2KFixes ] */