/contrib/ntp/ntpd/check_y2k.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 627 lines · 475 code · 89 blank · 63 comment · 91 complexity · 0da9007ca3cc32286e9d5f759a9bc24d MD5 · raw file

  1. /* check_y2k.c -- test ntp code constructs for Y2K correctness Y2KFixes [*/
  2. /*
  3. Code invoked by `make check`. Not part of ntpd and not to be
  4. installed.
  5. On any code I even wonder about, I've cut and pasted the code
  6. here and ran it as a test case just to be sure.
  7. For code not in "ntpd" proper, we have tried to call most
  8. repaired functions from herein to properly test them
  9. (something never done before!). This has found several bugs,
  10. not normal Y2K bugs, that will strike in Y2K so repair them
  11. we did.
  12. Program exits with 0 on success, 1 on Y2K failure (stdout messages).
  13. Exit of 2 indicates internal logic bug detected OR failure of
  14. what should be our correct formulas.
  15. While "make check" should only check logic for source within that
  16. specific directory, this check goes outside the scope of the local
  17. directory. It's not a perfect world (besides, there is a lot of
  18. interdependence here, and it really needs to be tested in
  19. a controled order).
  20. */
  21. /* { definitions lifted from ntpd.c to allow us to complie with
  22. "#include ntp.h". I have not taken the time to reduce the clutter. */
  23. #ifdef HAVE_CONFIG_H
  24. # include <config.h>
  25. #endif
  26. #include "ntpd.h"
  27. #ifdef HAVE_UNISTD_H
  28. # include <unistd.h>
  29. #endif
  30. #ifdef HAVE_SYS_STAT_H
  31. # include <sys/stat.h>
  32. #endif
  33. #include <stdio.h>
  34. #include <errno.h>
  35. #ifndef SYS_WINNT
  36. # if !defined(VMS) /*wjm*/
  37. # include <sys/param.h>
  38. # endif /* VMS */
  39. # if HAVE_SYS_SIGNAL_H
  40. # include <sys/signal.h>
  41. # endif /* HAVE_SYS_SIGNAL_H */
  42. # include <sys/signal.h>
  43. # ifdef HAVE_SYS_IOCTL_H
  44. # include <sys/ioctl.h>
  45. # endif /* HAVE_SYS_IOCTL_H */
  46. # if !defined(VMS) /*wjm*/
  47. # include <sys/resource.h>
  48. # endif /* VMS */
  49. #else
  50. # include <signal.h>
  51. # include <process.h>
  52. # include <io.h>
  53. # include "../libntp/log.h"
  54. #endif /* SYS_WINNT */
  55. #if defined(HAVE_RTPRIO)
  56. # ifdef HAVE_SYS_RESOURCE_H
  57. # include <sys/resource.h>
  58. # endif
  59. # ifdef HAVE_SYS_LOCK_H
  60. # include <sys/lock.h>
  61. # endif
  62. # include <sys/rtprio.h>
  63. #else
  64. # ifdef HAVE_PLOCK
  65. # ifdef HAVE_SYS_LOCK_H
  66. # include <sys/lock.h>
  67. # endif
  68. # endif
  69. #endif
  70. #if defined(HAVE_SCHED_SETSCHEDULER)
  71. # ifdef HAVE_SCHED_H
  72. # include <sched.h>
  73. # else
  74. # ifdef HAVE_SYS_SCHED_H
  75. # include <sys/sched.h>
  76. # endif
  77. # endif
  78. #endif
  79. #if defined(HAVE_SYS_MMAN_H)
  80. # include <sys/mman.h>
  81. #endif
  82. #ifdef HAVE_TERMIOS_H
  83. # include <termios.h>
  84. #endif
  85. #ifdef SYS_DOMAINOS
  86. # include <apollo/base.h>
  87. #endif /* SYS_DOMAINOS */
  88. /* } end definitions lifted from ntpd.c */
  89. #include "ntp_calendar.h"
  90. #include "parse.h"
  91. #define GoodLeap(Year) (((Year)%4 || (!((Year)%100) && (Year)%400)) ? 0 : 13 )
  92. volatile int debug = 0; /* debugging requests for parse stuff */
  93. char const *progname = "check_y2k";
  94. long
  95. Days ( int Year ) /* return number of days since year "0" */
  96. {
  97. long Return;
  98. /* this is a known to be good algorithm */
  99. Return = Year * 365; /* first aproximation to the value */
  100. if ( Year >= 1 )
  101. { /* see notes in libparse/parse.c if you want a PROPER
  102. * **generic algorithm. */
  103. Return += (Year+3) / 4; /* add in (too many) leap days */
  104. Return -= (Year-1) / 100; /* reduce by (too many) centurys */
  105. Return += (Year-1) / 400; /* get final answer */
  106. }
  107. return Return;
  108. }
  109. static int year0 = 1900; /* sarting year for NTP time */
  110. static int yearend; /* ending year we test for NTP time.
  111. * 32-bit systems: through 2036, the
  112. **year in which NTP time overflows.
  113. * 64-bit systems: a reasonable upper
  114. **limit (well, maybe somewhat beyond
  115. **reasonable, but well before the
  116. **max time, by which time the earth
  117. **will be dead.) */
  118. static time_t Time;
  119. static struct tm LocalTime;
  120. #define Error(year) if ( (year)>=2036 && LocalTime.tm_year < 110 ) \
  121. Warnings++; else Fatals++
  122. int
  123. main( void )
  124. {
  125. int Fatals;
  126. int Warnings;
  127. int year;
  128. Time = time( (time_t *)NULL )
  129. #ifdef TESTTIMEOFFSET
  130. + test_time_offset
  131. #endif
  132. ;
  133. LocalTime = *localtime( &Time );
  134. year = ( sizeof( u_long ) > 4 ) /* save max span using year as temp */
  135. ? ( 400 * 3 ) /* three greater gregorian cycles */
  136. : ((int)(0x7FFFFFFF / 365.242 / 24/60/60)* 2 ); /*32-bit limit*/
  137. /* NOTE: will automacially expand test years on
  138. * 64 bit machines.... this may cause some of the
  139. * existing ntp logic to fail for years beyond
  140. * 2036 (the current 32-bit limit). If all checks
  141. * fail ONLY beyond year 2036 you may ignore such
  142. * errors, at least for a decade or so. */
  143. yearend = year0 + year;
  144. puts( " internal self check" );
  145. { /* verify our own logic used to verify repairs */
  146. unsigned long days;
  147. if ( year0 >= yearend )
  148. {
  149. fprintf( stdout, "year0=%d NOT LESS THAN yearend=%d (span=%d)\n",
  150. (int)year0, (int)yearend, (int)year );
  151. exit(2);
  152. }
  153. {
  154. int save_year;
  155. save_year = LocalTime.tm_year; /* save current year */
  156. year = 1980;
  157. LocalTime.tm_year = year - 1900;
  158. Fatals = Warnings = 0;
  159. Error(year); /* should increment Fatals */
  160. if ( Fatals == 0 )
  161. {
  162. fprintf( stdout,
  163. "%4d: %s(%d): FATAL DID NOT INCREMENT (Fatals=%d Warnings=%d)\n",
  164. (int)year, __FILE__, __LINE__, (int)Fatals, (int)Warnings );
  165. exit(2);
  166. }
  167. year = 2100; /* test year > limit but CURRENT year < limit */
  168. Fatals = Warnings = 0;
  169. Error(year); /* should increment Fatals */
  170. if ( Warnings == 0 )
  171. {
  172. fprintf( stdout,
  173. "%4d: %s(%d): WARNING DID NOT INCREMENT (Fatals=%d Warnings=%d)\n",
  174. (int)year, __FILE__, __LINE__, (int)Fatals, (int)Warnings );
  175. exit(2);
  176. }
  177. Fatals = Warnings = 0;
  178. LocalTime.tm_year = year - 1900; /* everything > limit */
  179. Error(1980); /* should increment Fatals */
  180. if ( Fatals == 0 )
  181. {
  182. fprintf( stdout,
  183. "%4d: %s(%d): FATALS DID NOT INCREMENT (Fatals=%d Warnings=%d)\n",
  184. (int)year, __FILE__, __LINE__, (int)Fatals, (int)Warnings );
  185. exit(2);
  186. }
  187. LocalTime.tm_year = save_year;
  188. }
  189. days = 365+1; /* days in year 0 + 1 more day */
  190. for ( year = 1; year <= 2500; year++ )
  191. {
  192. long Test;
  193. Test = Days( year );
  194. if ( days != Test )
  195. {
  196. fprintf( stdout, "%04d: Days() DAY COUNT ERROR: s/b=%ld was=%ld\n",
  197. year, (long)days, (long)Test );
  198. exit(2); /* would throw off many other tests */
  199. }
  200. Test = julian0(year); /* compare with julian0() macro */
  201. if ( days != Test )
  202. {
  203. fprintf( stdout, "%04d: julian0() DAY COUNT ERROR: s/b=%ld was=%ld\n",
  204. year, (long)days, (long)Test );
  205. exit(2); /* would throw off many other tests */
  206. }
  207. days += 365;
  208. if ( isleap_4(year) ) days++;
  209. }
  210. if ( isleap_4(1999) )
  211. {
  212. fprintf( stdout, "isleap_4(1999) REPORTED TRUE\n" );
  213. exit(2);
  214. }
  215. if ( !isleap_4(2000) )
  216. {
  217. fprintf( stdout, "isleap_4(2000) REPORTED FALSE\n" );
  218. exit(2);
  219. }
  220. if ( isleap_4(2001) )
  221. {
  222. fprintf( stdout, "isleap_4(1999) REPORTED TRUE\n" );
  223. exit(2);
  224. }
  225. if ( !isleap_tm(2000-1900) )
  226. {
  227. fprintf( stdout, "isleap_tm(100) REPORTED FALSE\n" );
  228. exit(2);
  229. }
  230. }
  231. Fatals = Warnings = 0;
  232. puts( " include/ntp.h" );
  233. { /* test our new isleap_*() #define "functions" */
  234. for ( year = 1400; year <= 2200; year++ )
  235. {
  236. int LeapSw;
  237. int IsLeapSw;
  238. LeapSw = GoodLeap(year);
  239. IsLeapSw = isleap_4(year);
  240. if ( !!LeapSw != !!IsLeapSw )
  241. {
  242. Error(year);
  243. fprintf( stdout,
  244. " %4d %2d %3d *** ERROR\n", year, LeapSw, IsLeapSw );
  245. break;
  246. }
  247. IsLeapSw = isleap_tm(year-1900);
  248. if ( !!LeapSw != !!IsLeapSw )
  249. {
  250. Error(year);
  251. fprintf( stdout,
  252. " %4d %2d %3d *** ERROR\n", year, LeapSw, IsLeapSw );
  253. break;
  254. }
  255. }
  256. }
  257. puts( " include/ntp_calendar.h" );
  258. { /* I belive this is good, but just to be sure... */
  259. /* we are testing this #define */
  260. #define is_leapyear(y) (y%4 == 0 && !(y%100 == 0 && !(y%400 == 0)))
  261. for ( year = 1400; year <= 2200; year++ )
  262. {
  263. int LeapSw;
  264. LeapSw = GoodLeap(year);
  265. if ( !(!LeapSw) != !(!is_leapyear(year)) )
  266. {
  267. Error(year);
  268. fprintf( stdout,
  269. " %4d %2d *** ERROR\n", year, LeapSw );
  270. break;
  271. }
  272. }
  273. }
  274. puts( " libparse/parse.c" );
  275. {
  276. long Days1970; /* days from 1900 to 1970 */
  277. struct ParseTime /* womp up a test structure to all cut/paste code */
  278. {
  279. int year;
  280. } Clock_Time, *clock_time;
  281. clock_time = &Clock_Time;
  282. /* first test this #define */
  283. #define days_per_year(x) ((x) % 4 ? 365 : ((x % 400) ? ((x % 100) ? 366 : 365) : 366))
  284. for ( year = 1400; year <= 2200; year++ )
  285. {
  286. int LeapSw;
  287. int DayCnt;
  288. LeapSw = GoodLeap(year);
  289. DayCnt = (int)days_per_year(year);
  290. if ( ( LeapSw ? 366 : 365 ) != DayCnt )
  291. {
  292. Error(year);
  293. fprintf( stdout,
  294. " days_per_year() %4d %2d %3d *** ERROR\n",
  295. year, LeapSw, DayCnt );
  296. break;
  297. }
  298. }
  299. /* test (what is now julian0) calculations */
  300. Days1970 = Days( 1970 ); /* get days since 1970 using a known good */
  301. for ( year = 1970; year < yearend; year++ )
  302. {
  303. unsigned long t;
  304. long DaysYear ;
  305. clock_time->year = year;
  306. /* here is the code we are testing, cut and pasted out of the source */
  307. #if 0 /* old BUGGY code that has Y2K (and many other) failures */
  308. /* ghealton: this logic FAILED with great frequency when run
  309. * over a period of time, including for year 2000. True, it
  310. * had more successes than failures, but that's not really good
  311. * enough for critical time distribution software.
  312. * It is so awful I wonder if it has had a history of failure
  313. * and fixes? */
  314. t = (clock_time->year - 1970) * 365;
  315. t += (clock_time->year >> 2) - (1970 >> 2);
  316. t -= clock_time->year / 100 - 1970 / 100;
  317. t += clock_time->year / 400 - 1970 / 400;
  318. /* (immediate feare of rounding errors on integer
  319. * **divisions proved well founded) */
  320. #else
  321. /* my replacement, based on Days() above */
  322. t = julian0(year) - julian0(1970);
  323. #endif
  324. /* compare result in t against trusted calculations */
  325. DaysYear = Days( year ); /* get days to this year */
  326. if ( t != DaysYear - Days1970 )
  327. {
  328. Error(year);
  329. fprintf( stdout,
  330. " %4d 1970=%-8ld %4d=%-8ld %-3ld t=%-8ld *** ERROR ***\n",
  331. year, (long)Days1970,
  332. year,
  333. (long)DaysYear,
  334. (long)(DaysYear - Days1970),
  335. (long)t );
  336. }
  337. }
  338. #if 1 /* { */
  339. {
  340. debug = 1; /* enable debugging */
  341. for ( year = 1970; year < yearend; year++ )
  342. { /* (limited by theory unix 2038 related bug lives by, but
  343. * ends in yearend) */
  344. clocktime_t ct;
  345. time_t Observed;
  346. time_t Expected;
  347. u_long Flag;
  348. unsigned long t;
  349. ct.day = 1;
  350. ct.month = 1;
  351. ct.year = year;
  352. ct.hour = ct.minute = ct.second = ct.usecond = 0;
  353. ct.utcoffset = 0;
  354. ct.utctime = 0;
  355. ct.flags = 0;
  356. Flag = 0;
  357. Observed = parse_to_unixtime( &ct, &Flag );
  358. if ( ct.year != year )
  359. {
  360. fprintf( stdout,
  361. "%04d: parse_to_unixtime(,%d) CORRUPTED ct.year: was %d\n",
  362. (int)year, (int)Flag, (int)ct.year );
  363. Error(year);
  364. break;
  365. }
  366. t = julian0(year) - julian0(1970); /* Julian day from 1970 */
  367. Expected = t * 24 * 60 * 60;
  368. if ( Observed != Expected || Flag )
  369. { /* time difference */
  370. fprintf( stdout,
  371. "%04d: parse_to_unixtime(,%d) FAILURE: was=%lu s/b=%lu (%ld)\n",
  372. year, (int)Flag,
  373. (unsigned long)Observed, (unsigned long)Expected,
  374. ((long)Observed - (long)Expected) );
  375. Error(year);
  376. break;
  377. }
  378. if ( year >= YEAR_PIVOT+1900 )
  379. {
  380. /* check year % 100 code we put into parse_to_unixtime() */
  381. ct.utctime = 0;
  382. ct.year = year % 100;
  383. Flag = 0;
  384. Observed = parse_to_unixtime( &ct, &Flag );
  385. if ( Observed != Expected || Flag )
  386. { /* time difference */
  387. fprintf( stdout,
  388. "%04d: parse_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu (%ld)\n",
  389. year, (int)ct.year, (int)Flag,
  390. (unsigned long)Observed, (unsigned long)Expected,
  391. ((long)Observed - (long)Expected) );
  392. Error(year);
  393. break;
  394. }
  395. /* check year - 1900 code we put into parse_to_unixtime() */
  396. ct.utctime = 0;
  397. ct.year = year - 1900;
  398. Flag = 0;
  399. Observed = parse_to_unixtime( &ct, &Flag );
  400. if ( Observed != Expected || Flag )
  401. { /* time difference */
  402. fprintf( stdout,
  403. "%04d: parse_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu (%ld)\n",
  404. year, (int)ct.year, (int)Flag,
  405. (unsigned long)Observed, (unsigned long)Expected,
  406. ((long)Observed - (long)Expected) );
  407. Error(year);
  408. break;
  409. }
  410. }
  411. }
  412. #endif /* } */
  413. }
  414. }
  415. puts( " libntp/caljulian.c" );
  416. { /* test caljulian() */
  417. struct calendar ot;
  418. u_long ntp_time; /* NTP time */
  419. year = year0; /* calculate the basic year */
  420. printf( " starting year %04d\n", (int)year0 );
  421. printf( " ending year %04d\n", (int)yearend );
  422. ntp_time = julian0( year0 ); /* NTP starts in 1900-01-01 */
  423. #if DAY_NTP_STARTS == 693596
  424. ntp_time -= 365; /* BIAS required for successful test */
  425. #endif
  426. if ( DAY_NTP_STARTS != ntp_time )
  427. {
  428. Error(year);
  429. fprintf( stdout,
  430. "%04d: DAY_NTP_STARTS (%ld) NOT TRUE VALUE OF %ld (%ld)\n",
  431. (int)year0,
  432. (long)DAY_NTP_STARTS, (long)ntp_time,
  433. (long)DAY_NTP_STARTS - (long)ntp_time );
  434. }
  435. for ( ; year < yearend; year++ )
  436. {
  437. /* 01-01 for the current year */
  438. ntp_time = Days( year ) - Days( year0 ); /* days into NTP time */
  439. ntp_time *= 24 * 60 * 60; /* convert into seconds */
  440. caljulian( ntp_time, &ot ); /* convert January 1 */
  441. if ( ot.year != year
  442. || ot.month != 1
  443. || ot.monthday != 1 )
  444. {
  445. Error(year);
  446. fprintf( stdout, "%lu: EXPECTED %04d-01-01: FOUND %04d-%02d-%02d\n",
  447. (unsigned long)ntp_time,
  448. year,
  449. (int)ot.year, (int)ot.month, (int)ot.monthday );
  450. break;
  451. }
  452. ntp_time += (31 + 28-1) * ( 24 * 60 * 60 ); /* advance to 02-28 */
  453. caljulian( ntp_time, &ot ); /* convert Feb 28 */
  454. if ( ot.year != year
  455. || ot.month != 2
  456. || ot.monthday != 28 )
  457. {
  458. Error(year);
  459. fprintf( stdout, "%lu: EXPECTED %04d-02-28: FOUND %04d-%02d-%02d\n",
  460. (unsigned long)ntp_time,
  461. year,
  462. (int)ot.year, (int)ot.month, (int)ot.monthday );
  463. break;
  464. }
  465. {
  466. int m; /* expected month */
  467. int d; /* expected day */
  468. m = isleap_4(year) ? 2 : 3;
  469. d = isleap_4(year) ? 29 : 1;
  470. ntp_time += ( 24 * 60 * 60 ); /* advance to the next day */
  471. caljulian( ntp_time, &ot ); /* convert this day */
  472. if ( ot.year != year
  473. || ot.month != m
  474. || ot.monthday != d )
  475. {
  476. Error(year);
  477. fprintf( stdout, "%lu: EXPECTED %04d-%02d-%02d: FOUND %04d-%02d-%02d\n",
  478. (unsigned long)ntp_time,
  479. year, m, d,
  480. (int)ot.year, (int)ot.month, (int)ot.monthday );
  481. break;
  482. }
  483. }
  484. }
  485. }
  486. puts( " libntp/caltontp.c" );
  487. { /* test caltontp() */
  488. struct calendar ot;
  489. u_long ntp_time; /* NTP time */
  490. year = year0; /* calculate the basic year */
  491. printf( " starting year %04d\n", (int)year0 );
  492. printf( " ending year %04d\n", (int)yearend );
  493. for ( ; year < yearend; year++ )
  494. {
  495. u_long ObservedNtp;
  496. /* 01-01 for the current year */
  497. ot.year = year;
  498. ot.month = ot.monthday = 1; /* unused, but set anyway JIC */
  499. ot.yearday = 1; /* this is the magic value used by caltontp() */
  500. ot.hour = ot.minute = ot.second = 0;
  501. ntp_time = Days( year ) - Days( year0 ); /* days into NTP time */
  502. ntp_time *= 24 * 60 * 60; /* convert into seconds */
  503. ObservedNtp = caltontp( &ot );
  504. if ( ntp_time != ObservedNtp )
  505. {
  506. Error(year);
  507. fprintf( stdout, "%d: EXPECTED %lu: FOUND %lu (%ld)\n",
  508. (int)year,
  509. (unsigned long)ntp_time, (unsigned long)ObservedNtp ,
  510. (long)ntp_time - (long)ObservedNtp );
  511. break;
  512. }
  513. /* now call caljulian as a type of failsafe supercheck */
  514. caljulian( ObservedNtp, &ot ); /* convert January 1 */
  515. if ( ot.year != year
  516. || ot.month != 1
  517. || ot.monthday != 1 )
  518. {
  519. Error(year);
  520. fprintf( stdout, "%lu: caljulian FAILSAFE EXPECTED %04d-01-01: FOUND %04d-%02d-%02d\n",
  521. (unsigned long)ObservedNtp,
  522. year,
  523. (int)ot.year, (int)ot.month, (int)ot.monthday );
  524. break;
  525. }
  526. }
  527. }
  528. if ( Warnings > 0 )
  529. fprintf( stdout, "%d WARNINGS\n", Warnings );
  530. if ( Fatals > 0 )
  531. fprintf( stdout, "%d FATAL ERRORS\n", Fatals );
  532. return Fatals ? 1 : 0;
  533. }
  534. /* Y2KFixes ] */