Annotation of embedaddon/ntp/ntpd/check_y2k.c, revision 1.1
1.1 ! misho 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>