Merge from vendor branch CVS:
[dragonfly.git] / contrib / ntp / ntpd / check_y2k.c
1 /* check_y2k.c -- test ntp code constructs for Y2K correctness  Y2KFixes [*/
2
3   /*
4         Code invoked by `make check`. Not part of ntpd and not to be
5         installed.
6
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.
9
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
14         we did.
15
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.
19
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
24         a controled order).
25    */
26
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. */
29
30 #ifdef HAVE_CONFIG_H
31 # include <config.h>
32 #endif
33
34 #include "ntpd.h"
35
36 #ifdef HAVE_UNISTD_H
37 # include <unistd.h>
38 #endif
39 #ifdef HAVE_SYS_STAT_H
40 # include <sys/stat.h>
41 #endif
42 #include <stdio.h>
43 #include <errno.h>
44 #ifndef SYS_WINNT
45 # if !defined(VMS)      /*wjm*/
46 #  include <sys/param.h>
47 # endif /* VMS */
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>
54 # endif /* VMS */
55 #else
56 # include <signal.h>
57 # include <process.h>
58 # include <io.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>
64 # endif
65 # ifdef HAVE_SYS_LOCK_H
66 #  include <sys/lock.h>
67 # endif
68 # include <sys/rtprio.h>
69 #else
70 # ifdef HAVE_PLOCK
71 #  ifdef HAVE_SYS_LOCK_H
72 #       include <sys/lock.h>
73 #  endif
74 # endif
75 #endif
76 #if defined(HAVE_SCHED_SETSCHEDULER)
77 # ifdef HAVE_SCHED_H
78 #  include <sched.h>
79 # else
80 #  ifdef HAVE_SYS_SCHED_H
81 #   include <sys/sched.h>
82 #  endif
83 # endif
84 #endif
85 #if defined(HAVE_SYS_MMAN_H)
86 # include <sys/mman.h>
87 #endif
88
89 #ifdef HAVE_TERMIOS_H
90 # include <termios.h>
91 #endif
92
93 #ifdef SYS_DOMAINOS
94 # include <apollo/base.h>
95 #endif /* SYS_DOMAINOS */
96
97 /* } end definitions lifted from ntpd.c */
98
99 #include "ntp_calendar.h"
100 #include "parse.h"
101
102 #define GoodLeap(Year) (((Year)%4 || (!((Year)%100) && (Year)%400)) ? 0 : 13 )
103
104 volatile int debug = 0;         /* debugging requests for parse stuff */
105 char const *progname = "check_y2k";
106
107 long
108 Days ( int Year )               /* return number of days since year "0" */
109 {
110     long  Return;
111                 /* this is a known to be good algorithm */
112     Return = Year * 365;        /* first aproximation to the value */
113     if ( Year >= 1 )
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 */
119     }
120
121     return Return;
122 }
123
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
132                                       **will be dead.) */
133 static time_t Time;
134 static struct tm LocalTime;
135
136 #define Error(year) if ( (year)>=2036 && LocalTime.tm_year < 110 ) \
137         Warnings++; else Fatals++
138
139 int
140 main( void )
141 {
142     int Fatals;
143     int Warnings;
144     int  year;
145
146     Time = time( (time_t *)NULL )
147 #ifdef TESTTIMEOFFSET
148                 + test_time_offset
149 #endif
150         ;
151     LocalTime = *localtime( &Time );
152
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;
163
164     puts( " internal self check" );
165   {             /* verify our own logic used to verify repairs */
166     unsigned long days;
167
168     if ( year0 >= yearend )
169     {
170         fprintf( stdout, "year0=%d NOT LESS THAN yearend=%d  (span=%d)\n",
171                 (int)year0, (int)yearend, (int)year );
172         exit(2);
173     }
174
175    {
176     int  save_year;
177
178     save_year = LocalTime.tm_year;      /* save current year */
179
180     year = 1980;
181     LocalTime.tm_year = year - 1900;
182     Fatals = Warnings = 0;
183     Error(year);                /* should increment Fatals */
184     if ( Fatals == 0 ) 
185     {
186         fprintf( stdout, 
187             "%4d: %s(%d): FATAL DID NOT INCREMENT  (Fatals=%d Warnings=%d)\n",
188             (int)year, __FILE__, __LINE__, (int)Fatals, (int)Warnings );
189         exit(2);
190     }
191
192     year = 2100;                /* test year > limit but CURRENT year < limit */
193     Fatals = Warnings = 0;
194     Error(year);                /* should increment Fatals */
195     if ( Warnings == 0 ) 
196     {
197         fprintf( stdout, 
198             "%4d: %s(%d): WARNING DID NOT INCREMENT  (Fatals=%d Warnings=%d)\n",
199             (int)year, __FILE__, __LINE__, (int)Fatals, (int)Warnings );
200         exit(2);
201     }
202     Fatals = Warnings = 0;
203     LocalTime.tm_year = year - 1900;    /* everything > limit */
204     Error(1980);                /* should increment Fatals */
205     if ( Fatals == 0 ) 
206     {
207         fprintf( stdout, 
208             "%4d: %s(%d): FATALS DID NOT INCREMENT  (Fatals=%d Warnings=%d)\n",
209             (int)year, __FILE__, __LINE__, (int)Fatals, (int)Warnings );
210         exit(2);
211     }
212
213     LocalTime.tm_year = save_year;
214    }
215
216     days = 365+1;               /* days in year 0 + 1 more day */
217     for ( year = 1; year <= 2500; year++ )
218     {
219         long   Test;
220         Test = Days( year );
221         if ( days != Test )
222         {
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 */
226         }
227
228         Test = julian0(year);           /* compare with julian0() macro */
229         if ( days != Test )
230         {
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 */
234         }
235
236         days += 365;
237         if ( isleap_4(year) ) days++;
238     }
239
240     if ( isleap_4(1999) )
241     {
242         fprintf( stdout, "isleap_4(1999) REPORTED TRUE\n" );
243         exit(2);
244     }
245     if ( !isleap_4(2000) )
246     {
247         fprintf( stdout, "isleap_4(2000) REPORTED FALSE\n" );
248         exit(2);
249     }
250     if ( isleap_4(2001) )
251     {
252         fprintf( stdout, "isleap_4(1999) REPORTED TRUE\n" );
253         exit(2);
254     }
255
256     if ( !isleap_tm(2000-1900) )
257     {
258         fprintf( stdout, "isleap_tm(100) REPORTED FALSE\n" );
259         exit(2);
260     }
261   }
262
263     Fatals = Warnings = 0;
264
265     puts( " include/ntp.h" );
266   {             /* test our new isleap_*() #define "functions" */
267     
268     for ( year = 1400; year <= 2200; year++ )
269     {
270         int  LeapSw;
271         int  IsLeapSw;
272
273         LeapSw = GoodLeap(year);
274         IsLeapSw = isleap_4(year);
275
276         if ( !!LeapSw != !!IsLeapSw )
277         {
278             Error(year);
279             fprintf( stdout, 
280                 "  %4d %2d %3d *** ERROR\n", year, LeapSw, IsLeapSw );
281             break;
282         }
283
284         IsLeapSw = isleap_tm(year-1900);
285
286         if ( !!LeapSw != !!IsLeapSw )
287         {
288             Error(year);
289             fprintf( stdout, 
290                 "  %4d %2d %3d *** ERROR\n", year, LeapSw, IsLeapSw );
291             break;
292         }
293     }
294   }
295
296     puts( " include/ntp_calendar.h" );
297   {             /* I belive this is good, but just to be sure... */
298
299         /* we are testing this #define */
300 #define is_leapyear(y) (y%4 == 0 && !(y%100 == 0 && !(y%400 == 0)))
301
302     for ( year = 1400; year <= 2200; year++ )
303     {
304         int  LeapSw;
305
306         LeapSw = GoodLeap(year);
307
308         if ( !(!LeapSw) != !(!is_leapyear(year)) )
309         {
310             Error(year);
311             fprintf( stdout, 
312                 "  %4d %2d *** ERROR\n", year, LeapSw );
313             break;
314         }
315     }
316   }   
317
318
319     puts( " libparse/parse.c" );
320   { 
321     long Days1970;      /* days from 1900 to 1970 */
322
323     struct ParseTime    /* womp up a test structure to all cut/paste code */
324     {
325        int   year;
326     } Clock_Time, *clock_time;
327
328     clock_time = &Clock_Time;
329
330         /* first test this #define */
331 #define days_per_year(x)  ((x) % 4 ? 365 : ((x % 400) ? ((x % 100) ? 366 : 365) : 366))
332
333     for ( year = 1400; year <= 2200; year++ )
334     {
335         int  LeapSw;
336         int  DayCnt;
337
338         LeapSw = GoodLeap(year);
339         DayCnt = (int)days_per_year(year);
340
341         if ( ( LeapSw ? 366 : 365 ) != DayCnt )
342         {
343             Error(year);
344             fprintf( stdout, 
345                     "  days_per_year() %4d %2d %3d *** ERROR\n", 
346                     year, LeapSw, DayCnt );
347             break;
348         }
349     }
350
351     /* test (what is now julian0) calculations */
352
353     Days1970 = Days( 1970 );    /* get days since 1970 using a known good */
354
355     for ( year = 1970; year < yearend; year++ )
356     {                           
357         unsigned long t;
358         long DaysYear ;
359
360         clock_time->year = year;
361
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 
369              * and fixes? */
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;
374
375                 /* (immediate feare of rounding errors on integer
376                  * **divisions proved well founded) */
377
378 #else
379         /* my replacement, based on Days() above */
380         t = julian0(year) - julian0(1970);
381 #endif
382
383         /* compare result in t against trusted calculations */
384         DaysYear = Days( year );        /* get days to this year */
385         if ( t != DaysYear - Days1970 )
386         {
387             Error(year);
388             fprintf( stdout, 
389                 "  %4d 1970=%-8ld %4d=%-8ld %-3ld  t=%-8ld  *** ERROR ***\n",
390                   year,      (long)Days1970,
391                                  year,
392                                      (long)DaysYear,
393                                            (long)(DaysYear - Days1970),
394                                                    (long)t );
395         }
396     }
397
398 #if 1           /* { */
399    {
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) */
404         clocktime_t  ct;
405         time_t       Observed;
406         time_t       Expected;
407         u_long       Flag;
408         unsigned long t;
409
410         ct.day = 1;
411         ct.month = 1;
412         ct.year = year;
413         ct.hour = ct.minute = ct.second = ct.usecond = 0;
414         ct.utcoffset = 0;
415         ct.utctime = 0;
416         ct.flags = 0;
417
418         Flag = 0;
419         Observed = parse_to_unixtime( &ct, &Flag );
420         if ( ct.year != year )
421         {
422             fprintf( stdout, 
423                "%04d: parse_to_unixtime(,%d) CORRUPTED ct.year: was %d\n",
424                (int)year, (int)Flag, (int)ct.year );
425             Error(year);
426             break;
427         }
428         t = julian0(year) - julian0(1970);      /* Julian day from 1970 */
429         Expected = t * 24 * 60 * 60;
430         if ( Observed != Expected  ||  Flag )
431         {   /* time difference */
432             fprintf( stdout, 
433                "%04d: parse_to_unixtime(,%d) FAILURE: was=%lu s/b=%lu  (%ld)\n",
434                year, (int)Flag, 
435                (unsigned long)Observed, (unsigned long)Expected,
436                ((long)Observed - (long)Expected) );
437             Error(year);
438             break;
439         }
440
441         if ( year >= YEAR_PIVOT+1900 )
442         {
443             /* check year % 100 code we put into parse_to_unixtime() */
444             ct.utctime = 0;
445             ct.year = year % 100;
446             Flag = 0;
447
448             Observed = parse_to_unixtime( &ct, &Flag );
449
450             if ( Observed != Expected  ||  Flag )
451             {   /* time difference */
452                 fprintf( stdout, 
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) );
457                 Error(year);
458                 break;
459             }
460
461             /* check year - 1900 code we put into parse_to_unixtime() */
462             ct.utctime = 0;
463             ct.year = year - 1900;
464             Flag = 0;
465
466             Observed = parse_to_unixtime( &ct, &Flag );
467
468             if ( Observed != Expected  ||  Flag )
469             {   /* time difference */
470                 fprintf( stdout, 
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) );
475                 Error(year);
476                 break;
477             }
478
479
480         }
481     }
482 #endif          /* } */
483    }
484   }
485
486     puts( " libntp/caljulian.c" );
487   {             /* test caljulian() */
488     struct      calendar  ot;
489     u_long ntp_time;            /* NTP time */
490
491     year = year0;               /* calculate the basic year */
492     printf( "  starting year %04d\n", (int)year0 );
493     printf( "  ending year   %04d\n", (int)yearend );
494
495
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 */
499 #endif
500     if ( DAY_NTP_STARTS != ntp_time )
501     {
502         Error(year);
503         fprintf( stdout, 
504                 "%04d: DAY_NTP_STARTS (%ld) NOT TRUE VALUE OF %ld (%ld)\n",
505                 (int)year0,
506                 (long)DAY_NTP_STARTS,  (long)ntp_time,
507                 (long)DAY_NTP_STARTS - (long)ntp_time );
508     }
509
510     for ( ; year < yearend; year++ )
511     {
512         
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 */
517         if ( ot.year  != year
518           || ot.month != 1
519           || ot.monthday != 1 )
520         {
521             Error(year);
522             fprintf( stdout, "%lu: EXPECTED %04d-01-01: FOUND %04d-%02d-%02d\n",
523                         (unsigned long)ntp_time,
524                         year, 
525                         (int)ot.year, (int)ot.month, (int)ot.monthday );
526             break;
527         }
528
529         ntp_time += (31 + 28-1) * ( 24 * 60 * 60 );     /* advance to 02-28 */
530         caljulian( ntp_time, &ot );     /* convert Feb 28 */
531         if ( ot.year  != year
532           || ot.month != 2
533           || ot.monthday != 28 )
534         {
535             Error(year);
536             fprintf( stdout, "%lu: EXPECTED %04d-02-28: FOUND %04d-%02d-%02d\n",
537                         (unsigned long)ntp_time,
538                         year, 
539                         (int)ot.year, (int)ot.month, (int)ot.monthday );
540             break;
541         }
542
543       {
544         int    m;               /* expected month */
545         int    d;               /* expected day */
546
547         m = isleap_4(year) ?  2 : 3;
548         d = isleap_4(year) ? 29 : 1;
549
550         ntp_time += ( 24 * 60 * 60 );   /* advance to the next day */
551         caljulian( ntp_time, &ot );     /* convert this day */
552         if ( ot.year  != year
553           || ot.month != m
554           || ot.monthday != d )
555         {
556             Error(year);
557             fprintf( stdout, "%lu: EXPECTED %04d-%02d-%02d: FOUND %04d-%02d-%02d\n",
558                         (unsigned long)ntp_time,
559                         year, m, d, 
560                         (int)ot.year, (int)ot.month, (int)ot.monthday );
561             break;
562         }
563
564       }
565     }
566   }
567
568     puts( " libntp/caltontp.c" );
569   {             /* test caltontp() */
570     struct      calendar  ot;
571     u_long      ntp_time;               /* NTP time */
572
573     year = year0;               /* calculate the basic year */
574     printf( "  starting year %04d\n", (int)year0 );
575     printf( "  ending year   %04d\n", (int)yearend );
576
577
578     for ( ; year < yearend; year++ )
579     {
580         u_long  ObservedNtp;
581         
582         /* 01-01 for the current year */
583         ot.year = 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;
587
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 )
592         {
593             Error(year);
594             fprintf( stdout, "%d: EXPECTED %lu: FOUND %lu (%ld)\n",
595                         (int)year,
596                         (unsigned long)ntp_time, (unsigned long)ObservedNtp ,
597                         (long)ntp_time - (long)ObservedNtp );
598
599             break;
600         }
601
602         /* now call caljulian as a type of failsafe supercheck */
603         caljulian( ObservedNtp, &ot );  /* convert January 1 */
604         if ( ot.year  != year
605           || ot.month != 1
606           || ot.monthday != 1 )
607         {
608             Error(year);
609             fprintf( stdout, "%lu: caljulian FAILSAFE EXPECTED %04d-01-01: FOUND %04d-%02d-%02d\n",
610                         (unsigned long)ObservedNtp,
611                         year, 
612                         (int)ot.year, (int)ot.month, (int)ot.monthday );
613             break;
614         }
615     }
616   }
617
618    if ( Warnings > 0 )
619        fprintf( stdout, "%d WARNINGS\n",  Warnings );
620    if ( Fatals > 0 )
621        fprintf( stdout, "%d FATAL ERRORS\n",  Fatals );
622    return Fatals ? 1 : 0;
623 }
624                                                         /* Y2KFixes ] */