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 ] */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>