xref: /netbsd-src/external/bsd/ntp/dist/ntpd/ntp_leapsec.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 /*	$NetBSD: ntp_leapsec.c,v 1.1.1.1 2013/12/27 23:31:03 christos Exp $	*/
2 
3 /*
4  * ntp_leapsec.c - leap second processing for NTPD
5  *
6  * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
7  * The contents of 'html/copyright.html' apply.
8  * ----------------------------------------------------------------------
9  * This is an attempt to get the leap second handling into a dedicated
10  * module to make the somewhat convoluted logic testable.
11  */
12 
13 #include <config.h>
14 #include <sys/types.h>
15 #include <ctype.h>
16 
17 #include "ntp_types.h"
18 #include "ntp_fp.h"
19 #include "ntp_stdlib.h"
20 #include "ntp_calendar.h"
21 #include "ntp_leapsec.h"
22 #include "ntp.h"
23 
24 /* ---------------------------------------------------------------------
25  * GCC is rather sticky with its 'const' attribute. We have to do it more
26  * explicit than with a cast if we want to get rid of a CONST qualifier.
27  * Greetings from the PASCAL world, where casting was only possible via
28  * untagged unions...
29  */
30 static void* noconst(const void* ptr)
31 {
32 	union {
33 		const void * cp;
34 		void *       vp;
35 	} tmp;
36 	tmp.cp = ptr;
37 	return tmp.vp;
38 }
39 
40 /* ---------------------------------------------------------------------
41  * Things to put into libntp...
42  */
43 
44 vint64
45 strtouv64(
46 	const char * begp,
47 	char **      endp,
48 	int          base)
49 {
50 	vint64  res;
51 	u_char  digit;
52 	int     sig, num;
53 	const u_char *src;
54 
55 	num = sig = 0;
56 	src = (const u_char*)begp;
57 	while (isspace(*src))
58 		src++;
59 
60 	if (*src == '-') {
61 		src++;
62 		sig = 1;
63 	} else  if (*src == '+') {
64 		src++;
65 	}
66 
67 	if (base == 0) {
68 		base = 10;
69 		if (*src == '0') {
70 			base = 8;
71 			if (toupper(*++src) == 'X') {
72 				src++;
73 				base = 16;
74 			}
75 		}
76 	} else if (base == 16) { /* remove optional leading '0x' or '0X' */
77 		if (src[0] == '0' && toupper(src[1]) == 'X')
78 			src += 2;
79 	} else if (base <= 2 || base > 36) {
80 		memset(&res, 0xFF, sizeof(res));
81 		errno = ERANGE;
82 		return res;
83 	}
84 
85 	memset(&res, 0, sizeof(res));
86 	while (*src) {
87 		if (isdigit(*src))
88 			digit = *src - '0';
89 		else if (isupper(*src))
90 			digit = *src - 'A' + 10;
91 		else if (islower(*src))
92 			digit = *src - 'a' + 10;
93 		else
94 			break;
95 		if (digit >= base)
96 			break;
97 		num = 1;
98 #if defined(HAVE_INT64)
99 		res.Q_s = res.Q_s * base + digit;
100 #else
101 		/* res *= base, using 16x16->32 bit
102 		 * multiplication. Slow but portable.
103 		 */
104 		{
105 			uint32_t accu;
106 			accu       = (uint32_t)res.W_s.ll * base;
107 			res.W_s.ll = (uint16_t)accu;
108 			accu       = (accu >> 16)
109 			           + (uint32_t)res.W_s.lh * base;
110 			res.W_s.lh = (uint16_t)accu;
111 			/* the upper bits can be done in one step: */
112 			res.D_s.hi = res.D_s.hi * base + (accu >> 16);
113 		}
114 		M_ADD(res.D_s.hi, res.D_s.lo, 0, digit);
115 #endif
116 		src++;
117 	}
118 	if (!num)
119 		errno = EINVAL;
120 	if (endp)
121 		*endp = (char*)noconst(src);
122 	if (sig)
123 		M_NEG(res.D_s.hi, res.D_s.lo);
124 	return res;
125 }
126 
127 int icmpv64(
128 	const vint64 * lhs,
129 	const vint64 * rhs)
130 {
131 	int res;
132 
133 #if defined(HAVE_INT64)
134 	res = (lhs->q_s > rhs->q_s)
135 	    - (lhs->q_s < rhs->q_s);
136 #else
137 	res = (lhs->d_s.hi > rhs->d_s.hi)
138 	    - (lhs->d_s.hi < rhs->d_s.hi);
139 	if ( ! res )
140 		res = (lhs->D_s.lo > rhs->D_s.lo)
141 		    - (lhs->D_s.lo < rhs->D_s.lo);
142 #endif
143 
144 	return res;
145 }
146 
147 
148 int ucmpv64(
149 	const vint64 * lhs,
150 	const vint64 * rhs)
151 {
152 	int res;
153 
154 #if defined(HAVE_INT64)
155 	res = (lhs->Q_s > rhs->Q_s)
156 	    - (lhs->Q_s < rhs->Q_s);
157 #else
158 	res = (lhs->D_s.hi > rhs->D_s.hi)
159 	    - (lhs->D_s.hi < rhs->D_s.hi);
160 	if ( ! res )
161 		res = (lhs->D_s.lo > rhs->D_s.lo)
162 		    - (lhs->D_s.lo < rhs->D_s.lo);
163 #endif
164 	return res;
165 }
166 
167 #if 0
168 static vint64
169 addv64(
170     const vint64 *lhs,
171     const vint64 *rhs)
172 {
173 	vint64 res;
174 
175 #if defined(HAVE_INT64)
176 	res.Q_s = lhs->Q_s + rhs->Q_s;
177 #else
178 	res = *lhs;
179 	M_ADD(res.D_s.hi, res.D_s.lo, rhs->D_s.hi, rhs->D_s.lo);
180 #endif
181 	return res;
182 }
183 #endif
184 
185 static vint64
186 subv64(
187     const vint64 *lhs,
188     const vint64 *rhs)
189 {
190 	vint64 res;
191 
192 #if defined(HAVE_INT64)
193 	res.Q_s = lhs->Q_s - rhs->Q_s;
194 #else
195 	res = *lhs;
196 	M_SUB(res.D_s.hi, res.D_s.lo, rhs->D_s.hi, rhs->D_s.lo);
197 #endif
198 	return res;
199 }
200 
201 static vint64
202 addv64i32(
203 	const vint64 * lhs,
204 	int32_t        rhs)
205 {
206 	vint64 res;
207 
208 	res = *lhs;
209 #if defined(HAVE_INT64)
210 	res.q_s += rhs;
211 #else
212 	M_ADD(res.D_s.hi, res.D_s.lo,  -(rhs < 0), rhs);
213 #endif
214 	return res;
215 }
216 
217 #if 0
218 static vint64
219 subv64i32(
220 	const vint64 * lhs,
221 	int32_t        rhs)
222 {
223 	vint64 res;
224 
225 	res = *lhs;
226 #if defined(HAVE_INT64)
227 	res.q_s -= rhs;
228 #else
229 	M_SUB(res.D_s.hi, res.D_s.lo,  -(rhs < 0), rhs);
230 #endif
231 	return res;
232 }
233 #endif
234 
235 #if 0
236 static vint64
237 addv64u32(
238 	const vint64 * lhs,
239 	uint32_t       rhs)
240 {
241 	vint64 res;
242 
243 	res = *lhs;
244 #if defined(HAVE_INT64)
245 	res.Q_s += rhs;
246 #else
247 	M_ADD(res.D_s.hi, res.D_s.lo, 0, rhs);
248 #endif
249 	return res;
250 }
251 #endif
252 
253 static vint64
254 subv64u32(
255 	const vint64 * lhs,
256 	uint32_t       rhs)
257 {
258 	vint64 res;
259 
260 	res = *lhs;
261 #if defined(HAVE_INT64)
262 	res.Q_s -= rhs;
263 #else
264 	M_SUB(res.D_s.hi, res.D_s.lo, 0, rhs);
265 #endif
266 	return res;
267 }
268 
269 /* ---------------------------------------------------------------------
270  * Things to put into ntp_calendar... (and consequently into libntp...)
271  */
272 
273 /* ------------------------------------------------------------------ */
274 static int
275 ntpcal_ntp64_to_date(
276 	struct calendar *jd,
277 	const vint64    *ntp)
278 {
279 	ntpcal_split ds;
280 
281 	ds = ntpcal_daysplit(ntp);
282 	ds.hi += ntpcal_daysec_to_date(jd, ds.lo);
283 
284 	return ntpcal_rd_to_date(jd, ds.hi + DAY_NTP_STARTS);
285 }
286 
287 /* ------------------------------------------------------------------ */
288 static vint64
289 ntpcal_date_to_ntp64(
290 	const struct calendar *jd)
291 {
292 	return ntpcal_dayjoin(ntpcal_date_to_rd(jd) - DAY_NTP_STARTS,
293 			      ntpcal_date_to_daysec(jd));
294 }
295 
296 
297 /* ---------------------------------------------------------------------
298  * Our internal data structure
299  */
300 #define MAX_HIST 10	/* history of leap seconds */
301 
302 struct leap_info {
303 	vint64   ttime;	/* transition time (after the step, ntp scale) */
304 	uint32_t stime;	/* schedule limit (a month before transition)  */
305 	int16_t  taiof;	/* TAI offset on and after the transition      */
306 	uint8_t  dynls; /* dynamic: inserted on peer/clock request     */
307 };
308 typedef struct leap_info leap_info_t;
309 
310 struct leap_head {
311 	vint64   update; /* time of information update                 */
312 	vint64   expire; /* table expiration time                      */
313 	uint16_t size;	 /* number of infos in table	               */
314 	int16_t  base_tai;	/* total leaps before first entry      */
315 	int16_t  this_tai;	/* current TAI offset	               */
316 	int16_t  next_tai;	/* TAI offset after 'when'             */
317 	vint64   dtime;	 /* due time (current era end)                 */
318 	vint64   ttime;	 /* nominal transition time (next era start)   */
319 	vint64   stime;	 /* schedule time (when we take notice)        */
320 	vint64   ebase;	 /* base time of this leap era                 */
321 	uint8_t  dynls;	 /* next leap is dynamic (by peer request)     */
322 };
323 typedef struct leap_head leap_head_t;
324 
325 struct leap_table {
326 	leap_signature_t lsig;
327 	leap_head_t	 head;
328 	leap_info_t  	 info[MAX_HIST];
329 };
330 
331 /* Where we store our tables */
332 static leap_table_t _ltab[2], *_lptr;
333 static int/*BOOL*/  _electric;
334 
335 /* Forward decls of local helpers */
336 static int    add_range(leap_table_t*, const leap_info_t*);
337 static char * get_line(leapsec_reader, void*, char*, size_t);
338 static char * skipws(const char*);
339 static int    parsefail(const char * cp, const char * ep);
340 static void   reload_limits(leap_table_t*, const vint64*);
341 static int    betweenu32(uint32_t, uint32_t, uint32_t);
342 static void   reset_times(leap_table_t*);
343 static int    leapsec_add(leap_table_t*, const vint64*, int);
344 static int    leapsec_raw(leap_table_t*, const vint64 *, int, int);
345 
346 /* =====================================================================
347  * Get & Set the current leap table
348  */
349 
350 /* ------------------------------------------------------------------ */
351 leap_table_t *
352 leapsec_get_table(
353 	int alternate)
354 {
355 	leap_table_t *p1, *p2;
356 
357 	p1 = _lptr;
358 	p1 = &_ltab[p1 == &_ltab[1]];
359 	p2 = &_ltab[p1 == &_ltab[0]];
360 	if (alternate) {
361 		memcpy(p2, p1, sizeof(leap_table_t));
362 		p1 = p2;
363 	}
364 
365 	return p1;
366 }
367 
368 /* ------------------------------------------------------------------ */
369 int/*BOOL*/
370 leapsec_set_table(
371 	leap_table_t * pt)
372 {
373 	if (pt == &_ltab[0] || pt == &_ltab[1])
374 		_lptr = pt;
375 	return _lptr == pt;
376 }
377 
378 /* ------------------------------------------------------------------ */
379 int/*BOOL*/
380 leapsec_electric(
381 	int/*BOOL*/ on)
382 {
383 	int res = _electric;
384 	if (on < 0)
385 		return res;
386 
387 	_electric = (on != 0);
388 	if (_electric == res)
389 		return res;
390 
391 	if (_lptr == &_ltab[0] || _lptr == &_ltab[1])
392 		reset_times(_lptr);
393 
394 	return res;
395 }
396 
397 /* =====================================================================
398  * API functions that operate on tables
399  */
400 
401 /* ---------------------------------------------------------------------
402  * Clear all leap second data. Use it for init & cleanup
403  */
404 void
405 leapsec_clear(
406 	leap_table_t * pt)
407 {
408 	memset(&pt->lsig, 0, sizeof(pt->lsig));
409 	memset(&pt->head, 0, sizeof(pt->head));
410 	reset_times(pt);
411 }
412 
413 /* ---------------------------------------------------------------------
414  * Load a leap second file and check expiration on the go
415  */
416 int/*BOOL*/
417 leapsec_load(
418 	leap_table_t * pt  ,
419 	leapsec_reader func,
420 	void *         farg,
421 	int            use_build_limit)
422 {
423 	char   *cp, *ep, linebuf[50];
424 	vint64 ttime, limit;
425 	long   taiof;
426 	struct calendar build;
427 
428 	leapsec_clear(pt);
429 	if (use_build_limit && ntpcal_get_build_date(&build))
430 		limit = ntpcal_date_to_ntp64(&build);
431 	else
432 		memset(&limit, 0, sizeof(limit));
433 
434 	while (get_line(func, farg, linebuf, sizeof(linebuf))) {
435 		cp = linebuf;
436 		if (*cp == '#') {
437 			cp++;
438 			if (*cp == '@') {
439 				cp = skipws(cp+1);
440 				pt->head.expire = strtouv64(cp, &ep, 10);
441 				if (parsefail(cp, ep))
442 					goto fail_read;
443 				pt->lsig.etime = pt->head.expire.D_s.lo;
444 			} else if (*cp == '$') {
445 				cp = skipws(cp+1);
446 				pt->head.update = strtouv64(cp, &ep, 10);
447 				if (parsefail(cp, ep))
448 					goto fail_read;
449 			}
450 		} else if (isdigit((u_char)*cp)) {
451 			ttime = strtouv64(cp, &ep, 10);
452 			if (parsefail(cp, ep))
453 				goto fail_read;
454 			cp = skipws(ep);
455 			taiof = strtol(cp, &ep, 10);
456 			if (   parsefail(cp, ep)
457 			    || taiof > SHRT_MAX || taiof < SHRT_MIN)
458 				goto fail_read;
459 			if (ucmpv64(&ttime, &limit) >= 0) {
460 				if (!leapsec_raw(pt, &ttime,
461 						 taiof, FALSE))
462 					goto fail_insn;
463 			} else {
464 				pt->head.base_tai = (int16_t)taiof;
465 			}
466 			pt->lsig.ttime = ttime.D_s.lo;
467 			pt->lsig.taiof = (int16_t)taiof;
468 		}
469 	}
470 	return TRUE;
471 
472 fail_read:
473 	errno = EILSEQ;
474 fail_insn:
475 	leapsec_clear(pt);
476 	return FALSE;
477 }
478 
479 /* ---------------------------------------------------------------------
480  * Dump a table in human-readable format. Use 'fprintf' and a FILE
481  * pointer if you want to get it printed into a stream.
482  */
483 void
484 leapsec_dump(
485 	const leap_table_t * pt  ,
486 	leapsec_dumper       func,
487 	void *               farg)
488 {
489 	int             idx;
490 	vint64          ts;
491 	struct calendar atb, ttb;
492 
493 	ntpcal_ntp64_to_date(&ttb, &pt->head.expire);
494 	(*func)(farg, "leap table (%u entries) expires at %04u-%02u-%02u:\n",
495 		pt->head.size,
496 		ttb.year, ttb.month, ttb.monthday);
497 	idx = pt->head.size;
498 	while (idx-- != 0) {
499 		ts = pt->info[idx].ttime;
500 		ntpcal_ntp64_to_date(&ttb, &ts);
501 		ts = subv64u32(&ts, pt->info[idx].stime);
502 		ntpcal_ntp64_to_date(&atb, &ts);
503 
504 		(*func)(farg, "%04u-%02u-%02u [%c] (%04u-%02u-%02u) - %d\n",
505 			ttb.year, ttb.month, ttb.monthday,
506 			"-*"[pt->info[idx].dynls != 0],
507 			atb.year, atb.month, atb.monthday,
508 			pt->info[idx].taiof);
509 	}
510 }
511 
512 /* =====================================================================
513  * usecase driven API functions
514  */
515 
516 int/*BOOL*/
517 leapsec_query(
518 	leap_result_t * qr   ,
519 	uint32_t        ts32 ,
520 	const time_t *  pivot)
521 {
522 	leap_table_t *   pt;
523 	vint64           ts64, last, next;
524 	uint32_t         due32;
525 	int              fired;
526 
527 	/* preset things we use later on... */
528 	fired = FALSE;
529 	ts64  = ntpcal_ntp_to_ntp(ts32, pivot);
530 	pt    = leapsec_get_table(FALSE);
531 	memset(qr, 0, sizeof(leap_result_t));
532 
533 	if (ucmpv64(&ts64, &pt->head.ebase) < 0) {
534 		/* Most likely after leap frame reset. Could also be a
535 		 * backstep of the system clock. Anyway, get the new
536 		 * leap era frame.
537 		 */
538 		reload_limits(pt, &ts64);
539 	} else if (ucmpv64(&ts64, &pt->head.dtime) >= 0)	{
540 		/* Boundary crossed in forward direction. This might
541 		 * indicate a leap transition, so we prepare for that
542 		 * case.
543 		 *
544 		 * Some operations below are actually NOPs in electric
545 		 * mode, but having only one code path that works for
546 		 * both modes is easier to maintain.
547 		 */
548 		last = pt->head.ttime;
549 		qr->warped = (int16_t)(last.D_s.lo -
550 				       pt->head.dtime.D_s.lo);
551 		next = addv64i32(&ts64, qr->warped);
552 		reload_limits(pt, &next);
553 		fired = ucmpv64(&pt->head.ebase, &last) == 0;
554 		if (fired) {
555 			ts64 = next;
556 			ts32 = next.D_s.lo;
557 		} else {
558 			qr->warped = 0;
559 		}
560 	}
561 
562 	qr->tai_offs = pt->head.this_tai;
563 
564 	/* If before the next scheduling alert, we're done. */
565 	if (ucmpv64(&ts64, &pt->head.stime) < 0)
566 		return fired;
567 
568 	/* now start to collect the remaing data */
569 	due32 = pt->head.dtime.D_s.lo;
570 
571 	qr->tai_diff  = pt->head.next_tai - pt->head.this_tai;
572 	qr->ttime     = pt->head.ttime;
573 	qr->ddist     = due32 - ts32;
574 	qr->dynamic   = pt->head.dynls;
575 	qr->proximity = LSPROX_SCHEDULE;
576 
577 	/* if not in the last day before transition, we're done. */
578 	if (!betweenu32(due32 - SECSPERDAY, ts32, due32))
579 		return fired;
580 
581 	qr->proximity = LSPROX_ANNOUNCE;
582 	if (!betweenu32(due32 - 10, ts32, due32))
583 		return fired;
584 
585 	/* The last 10s before the transition. Prepare for action! */
586 	qr->proximity = LSPROX_ALERT;
587 	return fired;
588 }
589 
590 /* ------------------------------------------------------------------ */
591 int/*BOOL*/
592 leapsec_frame(
593         leap_result_t *qr)
594 {
595 	const leap_table_t * pt;
596 
597         memset(qr, 0, sizeof(leap_result_t));
598 	pt = leapsec_get_table(FALSE);
599 	if (ucmpv64(&pt->head.ttime, &pt->head.stime) <= 0)
600                 return FALSE;
601 
602 	qr->tai_offs = pt->head.this_tai;
603 	qr->tai_diff = pt->head.next_tai - pt->head.this_tai;
604 	qr->ttime    = pt->head.ttime;
605 	qr->dynamic  = pt->head.dynls;
606 
607         return TRUE;
608 }
609 
610 /* ------------------------------------------------------------------ */
611 /* Reset the current leap frame */
612 void
613 leapsec_reset_frame(void)
614 {
615 	reset_times(leapsec_get_table(FALSE));
616 }
617 
618 /* ------------------------------------------------------------------ */
619 int/*BOOL*/
620 leapsec_load_file(
621 	FILE * ifp   ,
622 	int    blimit)
623 {
624 	leap_table_t * pt;
625 
626 	pt = leapsec_get_table(TRUE);
627 	return leapsec_load(pt, (leapsec_reader)getc, ifp, blimit)
628 	    && leapsec_set_table(pt);
629 }
630 
631 /* ------------------------------------------------------------------ */
632 void
633 leapsec_getsig(
634 	leap_signature_t * psig)
635 {
636 	const leap_table_t * pt;
637 
638 	pt = leapsec_get_table(FALSE);
639 	memcpy(psig, &pt->lsig, sizeof(leap_signature_t));
640 }
641 
642 /* ------------------------------------------------------------------ */
643 int/*BOOL*/
644 leapsec_expired(
645 	uint32_t       when,
646 	const time_t * tpiv)
647 {
648 	const leap_table_t * pt;
649 	vint64 limit;
650 
651 	pt = leapsec_get_table(FALSE);
652 	limit = ntpcal_ntp_to_ntp(when, tpiv);
653 	return ucmpv64(&limit, &pt->head.expire) >= 0;
654 }
655 
656 /* ------------------------------------------------------------------ */
657 int32_t
658 leapsec_daystolive(
659 	uint32_t       when,
660 	const time_t * tpiv)
661 {
662 	const leap_table_t * pt;
663 	vint64 limit;
664 
665 	pt = leapsec_get_table(FALSE);
666 	limit = ntpcal_ntp_to_ntp(when, tpiv);
667 	limit = subv64(&pt->head.expire, &limit);
668 	return ntpcal_daysplit(&limit).hi;
669 }
670 
671 /* ------------------------------------------------------------------ */
672 int/*BOOL*/
673 leapsec_add_fix(
674 	int            total,
675 	uint32_t       ttime,
676 	uint32_t       etime,
677 	const time_t * pivot)
678 {
679 	time_t         tpiv;
680 	leap_table_t * pt;
681 	vint64         tt64, et64;
682 
683 	if (pivot == NULL) {
684 		time(&tpiv);
685 		pivot = &tpiv;
686 	}
687 
688 	et64 = ntpcal_ntp_to_ntp(etime, pivot);
689 	tt64 = ntpcal_ntp_to_ntp(ttime, pivot);
690 	pt   = leapsec_get_table(TRUE);
691 
692 	if (   ucmpv64(&et64, &pt->head.expire) <= 0
693 	   || !leapsec_raw(pt, &tt64, total, FALSE) )
694 		return FALSE;
695 
696 	pt->lsig.etime = etime;
697 	pt->lsig.ttime = ttime;
698 	pt->lsig.taiof = (int16_t)total;
699 
700 	pt->head.expire = et64;
701 
702 	return leapsec_set_table(pt);
703 }
704 
705 /* ------------------------------------------------------------------ */
706 int/*BOOL*/
707 leapsec_add_dyn(
708 	int            insert,
709 	uint32_t       ntpnow,
710 	const time_t * pivot )
711 {
712 	leap_table_t * pt;
713 	vint64         now64;
714 
715 	pt = leapsec_get_table(TRUE);
716 	now64 = ntpcal_ntp_to_ntp(ntpnow, pivot);
717 	return leapsec_add(pt, &now64, (insert != 0))
718 	    && leapsec_set_table(pt);
719 }
720 
721 /* =====================================================================
722  * internal helpers
723  */
724 
725 /* [internal] Reset / init the time window in the leap processor to
726  * force reload on next query. Since a leap transition cannot take place
727  * at an odd second, the value chosen avoids spurious leap transition
728  * triggers. Making all three times equal forces a reload. Using the
729  * maximum value for unsigned 64 bits makes finding the next leap frame
730  * a bit easier.
731  */
732 static void
733 reset_times(
734 	leap_table_t * pt)
735 {
736 	memset(&pt->head.ebase, 0xFF, sizeof(vint64));
737 	pt->head.stime = pt->head.ebase;
738 	pt->head.ttime = pt->head.ebase;
739 	pt->head.dtime = pt->head.ebase;
740 }
741 
742 /* [internal] Add raw data to the table, removing old entries on the
743  * fly. This cannot fail currently.
744  */
745 static int/*BOOL*/
746 add_range(
747 	leap_table_t *      pt,
748 	const leap_info_t * pi)
749 {
750 	/* If the table is full, make room by throwing out the oldest
751 	 * entry. But remember the accumulated leap seconds!
752 	 */
753 	if (pt->head.size >= MAX_HIST) {
754 		pt->head.size     = MAX_HIST - 1;
755 		pt->head.base_tai = pt->info[pt->head.size].taiof;
756 	}
757 
758 	/* make room in lower end and insert item */
759 	memmove(pt->info+1, pt->info, pt->head.size*sizeof(*pt->info));
760 	pt->info[0] = *pi;
761 	pt->head.size++;
762 
763 	/* invalidate the cached limit data -- we might have news ;-)
764 	 *
765 	 * This blocks a spurious transition detection. OTOH, if you add
766 	 * a value after the last query before a leap transition was
767 	 * expected to occur, this transition trigger is lost. But we
768 	 * can probably live with that.
769 	 */
770 	reset_times(pt);
771 	return TRUE;
772 }
773 
774 /* [internal] given a reader function, read characters into a buffer
775  * until either EOL or EOF is reached. Makes sure that the buffer is
776  * always NUL terminated, but silently truncates excessive data. The
777  * EOL-marker ('\n') is *not* stored in the buffer.
778  *
779  * Returns the pointer to the buffer, unless EOF was reached when trying
780  * to read the first character of a line.
781  */
782 static char *
783 get_line(
784 	leapsec_reader func,
785 	void *         farg,
786 	char *         buff,
787 	size_t         size)
788 {
789 	int   ch;
790 	char *ptr;
791 
792 	/* if we cannot even store the delimiter, declare failure */
793 	if (buff == NULL || size == 0)
794 		return NULL;
795 
796 	ptr = buff;
797 	while (EOF != (ch = (*func)(farg)) && '\n' != ch)
798 		if (size > 1) {
799 			size--;
800 			*ptr++ = (char)ch;
801 		}
802 	/* discard trailing whitespace */
803 	while (ptr != buff && isspace((u_char)ptr[-1]))
804 		ptr--;
805 	*ptr = '\0';
806 	return (ptr == buff && ch == EOF) ? NULL : buff;
807 }
808 
809 /* [internal] skips whitespace characters from a character buffer. */
810 static char *
811 skipws(
812 	const char *ptr)
813 {
814 	while (isspace((u_char)*ptr))
815 		ptr++;
816 	return (char*)noconst(ptr);
817 }
818 
819 /* [internal] check if a strtoXYZ ended at EOL or whistespace and
820  * converted something at all. Return TRUE if something went wrong.
821  */
822 static int/*BOOL*/
823 parsefail(
824 	const char * cp,
825 	const char * ep)
826 {
827 	return (cp == ep)
828 	    || (*ep && *ep != '#' && !isspace((u_char)*ep));
829 }
830 
831 /* [internal] reload the table limits around the given time stamp. This
832  * is where the real work is done when it comes to table lookup and
833  * evaluation. Some care has been taken to have correct code for dealing
834  * with boundary conditions and empty tables.
835  *
836  * In electric mode, transition and trip time are the same. In dumb
837  * mode, the difference of the TAI offsets must be taken into account
838  * and trip time and transition time become different. The difference
839  * becomes the warping distance when the trip time is reached.
840  */
841 static void
842 reload_limits(
843 	leap_table_t * pt,
844 	const vint64 * ts)
845 {
846 	int idx;
847 
848 	/* Get full time and search the true lower bound. Use a
849 	 * simple loop here, since the number of entries does
850 	 * not warrant a binary search. This also works for an empty
851 	 * table, so there is no shortcut for that case.
852 	 */
853 	for (idx = 0; idx != pt->head.size; idx++)
854 		if (ucmpv64(ts, &pt->info[idx].ttime) >= 0)
855 			break;
856 
857 	/* get time limits with proper bound conditions. Note that the
858 	 * bounds of the table will be observed even if the table is
859 	 * empty -- no undefined condition must arise from this code.
860 	 */
861 	if (idx >= pt->head.size) {
862 		memset(&pt->head.ebase, 0x00, sizeof(vint64));
863 		pt->head.this_tai = pt->head.base_tai;
864 	} else {
865 		pt->head.ebase    = pt->info[idx].ttime;
866 		pt->head.this_tai = pt->info[idx].taiof;
867 	}
868 	if (--idx >= 0) {
869 		pt->head.next_tai = pt->info[idx].taiof;
870 		pt->head.dynls    = pt->info[idx].dynls;
871 		pt->head.ttime    = pt->info[idx].ttime;
872 
873 		if (_electric)
874 			pt->head.dtime = pt->head.ttime;
875                 else
876 			pt->head.dtime = addv64i32(
877 				&pt->head.ttime,
878 				pt->head.next_tai - pt->head.this_tai);
879 
880 		pt->head.stime = subv64u32(
881 			&pt->head.ttime, pt->info[idx].stime);
882 
883 	} else {
884 		memset(&pt->head.ttime, 0xFF, sizeof(vint64));
885 		pt->head.stime    = pt->head.ttime;
886 		pt->head.dtime    = pt->head.ttime;
887 		pt->head.next_tai = pt->head.this_tai;
888 		pt->head.dynls    = 0;
889 	}
890 }
891 
892 /* [internal] Take a time stamp and create a leap second frame for
893  * it. This will schedule a leap second for the beginning of the next
894  * month, midnight UTC. The 'insert' argument tells if a leap second is
895  * added (!=0) or removed (==0). We do not handle multiple inserts
896  * (yet?)
897  *
898  * Returns 1 if the insert worked, 0 otherwise. (It's not possible to
899  * insert a leap second into the current history -- only appending
900  * towards the future is allowed!)
901  */
902 static int/*BOOL*/
903 leapsec_add(
904 	leap_table_t*  pt    ,
905 	const vint64 * now64 ,
906 	int            insert)
907 {
908 	vint64		ttime, stime;
909 	struct calendar	fts;
910 	leap_info_t	li;
911 
912 	/* Check against the table expiration and the lates available
913 	 * leap entry. Do not permit inserts, only appends, and only if
914 	 * the extend the table beyond the expiration!
915 	 */
916 	if (   ucmpv64(now64, &pt->head.expire) < 0
917 	   || (pt->head.size && ucmpv64(now64, &pt->info[0].ttime) <= 0)) {
918 		errno = ERANGE;
919 		return FALSE;
920 	}
921 
922 	ntpcal_ntp64_to_date(&fts, now64);
923 	/* To guard against dangling leap flags: do not accept leap
924 	 * second request on the 1st hour of the 1st day of the month.
925 	 */
926 	if (fts.monthday == 1 && fts.hour == 0) {
927 		errno = EINVAL;
928 		return FALSE;
929 	}
930 
931 	/* Ok, do the remaining calculations */
932 	fts.monthday = 1;
933 	fts.hour     = 0;
934 	fts.minute   = 0;
935 	fts.second   = 0;
936 	stime = ntpcal_date_to_ntp64(&fts);
937 	fts.month++;
938 	ttime = ntpcal_date_to_ntp64(&fts);
939 
940 	li.ttime = ttime;
941 	li.stime = ttime.D_s.lo - stime.D_s.lo;
942 	li.taiof = (pt->head.size ? pt->info[0].taiof : pt->head.base_tai)
943 	         + (insert ? 1 : -1);
944 	li.dynls = 1;
945 	return add_range(pt, &li);
946 }
947 
948 /* [internal] Given a time stamp for a leap insertion (the exact begin
949  * of the new leap era), create new leap frame and put it into the
950  * table. This is the work horse for reading a leap file and getting a
951  * leap second update via authenticated network packet.
952  */
953 int/*BOOL*/
954 leapsec_raw(
955 	leap_table_t * pt,
956 	const vint64 * ttime,
957 	int            taiof,
958 	int            dynls)
959 {
960 	vint64		stime;
961 	struct calendar	fts;
962 	leap_info_t	li;
963 
964 	/* Check that we only extend the table. Paranoia rulez! */
965 	if (pt->head.size && ucmpv64(ttime, &pt->info[0].ttime) <= 0) {
966 		errno = ERANGE;
967 		return FALSE;
968 	}
969 
970 	ntpcal_ntp64_to_date(&fts, ttime);
971 	/* If this does not match the exact month start, bail out. */
972 	if (fts.monthday != 1 || fts.hour || fts.minute || fts.second) {
973 		errno = EINVAL;
974 		return FALSE;
975 	}
976 	fts.month--; /* was in range 1..12, no overflow here! */
977 	stime    = ntpcal_date_to_ntp64(&fts);
978 	li.ttime = *ttime;
979 	li.stime = ttime->D_s.lo - stime.D_s.lo;
980 	li.taiof = (int16_t)taiof;
981 	li.dynls = (dynls != 0);
982 	return add_range(pt, &li);
983 }
984 
985 /* [internal] Do a wrap-around save range inclusion check.
986  * Returns TRUE if x in [lo,hi[ (intervall open on right side) with full
987  * handling of an overflow / wrap-around.
988  */
989 static int/*BOOL*/
990 betweenu32(
991 	uint32_t lo,
992 	uint32_t x,
993 	uint32_t hi)
994 {
995 	int rc;
996 	if (lo <= hi)
997 		rc = (lo <= x) && (x < hi);
998 	else
999 		rc = (lo <= x) || (x < hi);
1000 	return rc;
1001 }
1002 
1003 /* -*- that's all folks! -*- */
1004