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