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