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