[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

leap second support for (portable) OpenNTPD



Hello people,

I have adapted my leap second patch (which has been part of
OpenBSD's base system's rdate(8) for years) to (portable)
OpenNTPD and attached it below.

A patch against OpenBSD ntpd(8) has been sent to henning@
some time ago already.

The patch does not modify default behaviour - instead, like
with rdate, you have to specify the -c option if you are
running a "right" timezone (as in contrast to a "posix" one).

bye,
//mirabile

PS: Please direct replies to me too, I don't read misc@ any more.
-- 
> emacs als auch vi zum Kotzen finde (joe rules) und pine f|r den einzig
> bedienbaren textmode-mailclient halte (und ich hab sie alle ausprobiert). ;)
Hallooooo, ich bin der Holger ("Hallo Holger!"), und ich bin ebenfalls
... pine-User, und das auch noch gewohnheitsmd_ig ("Oooooooohhh").  [aus dasr]

===== cutting here may damage your screen surface =====
$MirBSD: Web/pub/openntpd-3.7p1-leapsecs.diff,v 1.1 2006/05/09 09:18:06 tg Exp $

diff -pruN openntpd-3.7p1.orig/LICENCE openntpd-3.7p1/LICENCE
--- openntpd-3.7p1.orig/LICENCE	Sun Mar 13 13:02:56 2005
+++ openntpd-3.7p1/LICENCE	Tue May  9 09:10:26 2006
@@ -111,4 +111,8 @@ daemon.c, sys-queue.h: The Regents of th
  * SUCH DAMAGE.
  */
 
+The leap second support is an extension by Thorsten Glaser and
+is covered by the MirOS licence, but available under the ISC
+licence for use by the OpenBSD project in rdate(8) as well.
+
 $Id: openntpd-3.7p1-leapsecs.diff,v 1.1 2006/05/09 09:18:06 tg Exp $
diff -pruN openntpd-3.7p1.orig/Makefile.in openntpd-3.7p1/Makefile.in
--- openntpd-3.7p1.orig/Makefile.in	Wed Dec 15 01:59:53 2004
+++ openntpd-3.7p1/Makefile.in	Tue May  9 09:09:19 2006
@@ -30,9 +30,9 @@ STRIP_OPT=_(_at_)_STRIP_OPT@
 PROG=	ntpd
 LIBCOMPAT=openbsd-compat/libopenbsd-compat.a
 SRCS=	ntpd.c buffer.c log.c imsg.c ntp.c ntp_msg.c config.c \
-	server.c client.c util.c y.tab.c
+	server.c client.c util.c y.tab.c ntpleaps.c
 OBJS=	ntpd.o buffer.o log.o imsg.o ntp.o ntp_msg.o config.o \
-	server.o client.o util.o y.tab.o
+	server.o client.o util.o y.tab.o ntpleaps.o
 YFLAGS=
 MAN=	ntpd.8 ntpd.conf.5
 
@@ -45,7 +45,7 @@ $(LIBCOMPAT):	config.h  $(top_srcdir)/op
 $(OBJS):	config.h
 
 ntpd:	ntpd.o buffer.o log.o imsg.o ntp.o ntp_msg.o config.o \
-	server.o client.o util.o y.tab.o $(LIBCOMPAT)
+	server.o client.o util.o y.tab.o ntpleaps.o $(LIBCOMPAT)
 	$(CC) $(CFLAGS) $(LDFLAGS) -o ntpd $(OBJS) $(LIBCOMPAT) $(LIBS)
 
 .c.o:
diff -pruN openntpd-3.7p1.orig/contrib/redhat/openntpd.spec openntpd-3.7p1/contrib/redhat/openntpd.spec
--- openntpd-3.7p1.orig/contrib/redhat/openntpd.spec	Mon May 23 00:22:17 2005
+++ openntpd-3.7p1/contrib/redhat/openntpd.spec	Tue May  9 09:15:21 2006
@@ -13,7 +13,8 @@ Requires: /sbin/chkconfig
 #Patch1: openntpd-3.6p1-linux-adjtimex3.patch
 
 %description
-NTP Time Synchronization Client - http://www.openntpd.org
+NTP Time Synchronisation Client - http://www.openntpd.org
+Enhanced by correct leap second support facility by MirOS
 
 %prep
 %setup -q -n %{name}-%{version}
diff -pruN openntpd-3.7p1.orig/ntpd.8 openntpd-3.7p1/ntpd.8
--- openntpd-3.7p1.orig/ntpd.8	Tue Dec 14 01:20:13 2004
+++ openntpd-3.7p1/ntpd.8	Tue May  9 09:08:29 2006
@@ -23,7 +23,7 @@
 .Sh SYNOPSIS
 .Nm ntpd
 .Bk -words
-.Op Fl dSs
+.Op Fl cdSs
 .Op Fl f Ar file
 .Ek
 .Sh DESCRIPTION
@@ -61,6 +61,12 @@ typically
 .Pp
 The options are as follows:
 .Bl -tag -width "-f fileXXX"
+.It Fl c
+Correct leap seconds.
+Use this option if you are using one of the time zones from
+.Pa /usr/share/zoneinfo/right/
+(i\.e\. you are counting leap seconds in the kernel time,
+instead of following POSIX closely which denies their existence).
 .It Fl d
 Do not daemonize.
 If this option is specified,
diff -pruN openntpd-3.7p1.orig/ntpd.c openntpd-3.7p1/ntpd.c
--- openntpd-3.7p1.orig/ntpd.c	Sun Mar 13 12:41:24 2005
+++ openntpd-3.7p1/ntpd.c	Tue May  9 09:08:29 2006
@@ -39,6 +39,7 @@ RCSID("$Release: OpenNTPD "OPENNTPD_VERS
 #include <unistd.h>
 
 #include "ntpd.h"
+#include "ntpleaps.h"
 
 void		sighdlr(int);
 __dead void	usage(void);
@@ -52,6 +53,7 @@ volatile sig_atomic_t	 quit = 0;
 volatile sig_atomic_t	 reconfig = 0;
 volatile sig_atomic_t	 sigchld = 0;
 struct imsgbuf		*ibuf;
+int			 corrleaps = 0;
 
 void
 sighdlr(int sig)
@@ -102,8 +104,11 @@ main(int argc, char *argv[])
 	log_init(1);		/* log to stderr until daemonized */
 	res_init();		/* XXX */
 
-	while ((ch = getopt(argc, argv, "df:sS")) != -1) {
+	while ((ch = getopt(argc, argv, "cdf:sS")) != -1) {
 		switch (ch) {
+		case 'c':
+			corrleaps = 1;
+			break;
 		case 'd':
 			conf.debug = 1;
 			break;
@@ -121,6 +126,9 @@ main(int argc, char *argv[])
 			/* NOTREACHED */
 		}
 	}
+
+	if (corrleaps)
+		ntpleaps_init();
 
 	if (parse_config(conffile, &conf))
 		exit(1);
diff -pruN openntpd-3.7p1.orig/ntpleaps.c openntpd-3.7p1/ntpleaps.c
--- openntpd-3.7p1.orig/ntpleaps.c	Thu Jan  1 00:00:00 1970
+++ openntpd-3.7p1/ntpleaps.c	Tue May  9 09:08:29 2006
@@ -0,0 +1,200 @@
+/*	$OpenBSD: ntpleaps.c,v 1.7 2004/05/05 20:29:54 jakob Exp $	*/
+
+/*
+ * Copyright (c) 2002, 2005, 2006 Thorsten Glaser. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    - Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    - Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Leap second support for NTP clients (generic) */
+
+/*
+ * I could include tzfile.h, but this would make the code unportable
+ * at no real benefit. Read tzfile.h for why.
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ntpleaps.h"
+
+#ifndef __RCSID
+#define	__RCSID(x)	static const char __rcsid[] __attribute__((used)) = (x)
+#endif
+
+__RCSID("$MirOS: src/usr.sbin/rdate/ntpleaps.c,v 1.4 2006/05/09 09:00:00 tg Exp $");
+
+#ifndef O_NDELAY
+#define O_NDELAY	0
+#endif
+
+u_int64_t *leapsecs = NULL;
+unsigned int leapsecs_num = 0;
+static int flaginit = -1;
+static int flagwarn = 0;
+
+static u_int32_t read_be_dword(u_int8_t *);
+
+int
+ntpleaps_init(void)
+{
+	if (!flaginit)
+		return (0);
+
+	if (!ntpleaps_read()) {
+		flaginit = 0;
+		return (0);
+	}
+
+	/* This does not really hurt, but users will complain about
+	 * off-by-23-seconds (at time of coding) errors if we don't warn.
+	 */
+	if (!flagwarn) {
+		fputs("Warning: error reading tzfile. You will NOT be\n"
+		    "able to get legal time or posix compliance! To fix this,\n"
+		    "install the 240 byte /usr/share/zoneinfo/right/UTC file.\n",
+		    stderr);
+		flagwarn = 1;	/* put it only once */
+	}
+
+	return (-1);
+}
+
+int
+ntpleaps_sub(u_int64_t *t)
+{
+	u_int64_t u;
+	unsigned i = 0, r = 0;
+
+	if ((flaginit ? ntpleaps_init() : 0) == -1)
+		return (-1);
+
+	u = *t;
+	if (u > 0)
+		while ((i < leapsecs_num) && (*t >= leapsecs[i])) {
+			--u;
+			++i;
+			if (*t == leapsecs[i])
+				r = 1;
+		}
+	*t = u;
+	return (r);
+}
+
+static u_int32_t
+read_be_dword(u_int8_t *ptr)
+{
+	u_int32_t res;
+
+	memcpy(&res, ptr, 4);
+	return (ntohl(res));
+}
+
+int
+ntpleaps_read(void)
+{
+	int fd;
+	unsigned int r;
+	u_int8_t buf[32];
+	u_int32_t m1, m2, m3;
+	u_int64_t s;
+	u_int64_t *l;
+
+	fd = open("/usr/share/zoneinfo/right/UTC", O_RDONLY | O_NDELAY);
+	if (fd == -1)
+		fd = open("/usr/share/zoneinfo/UTC", O_RDONLY | O_NDELAY);
+	if (fd == -1)
+		return (-1);
+
+	/* Check signature */
+	read(fd, buf, 4);
+	buf[4] = 0;
+	if (strcmp((const char *)buf, "TZif")) {
+		close(fd);
+		return (-1);
+	}
+
+	/* Pre-initalise buf[24..27] so we need not check read(2) result */
+	buf[24] = 0;
+	buf[25] = 0;
+	buf[26] = 0;
+	buf[27] = 0;
+
+	/* Skip uninteresting parts of header */
+	read(fd, buf, 28);
+
+	/* Read number of leap second entries */
+	r = read_be_dword(&buf[24]);
+	/* Check for plausibility - arbitrary values */
+	if ((r < 20) || (r > 60000)) {
+		close(fd);
+		return (-1);
+	}
+	if ((l = (u_int64_t *)malloc(r << 3)) == NULL) {
+		close(fd);
+		return (-1);
+	}
+
+	/* Skip further uninteresting stuff */
+	read(fd, buf, 12);
+	m1 = read_be_dword(buf);
+	m2 = read_be_dword(&buf[4]);
+	m3 = read_be_dword(&buf[8]);
+	m3 += (m1 << 2)+m1+(m2 << 2)+(m2 << 1);
+	lseek(fd, (off_t)m3, SEEK_CUR);
+
+	/* Now go parse the tzfile leap second info */
+	for (m1 = 0; m1 < r; m1++) {
+		if (read(fd, buf, 8) != 8) {
+			free(l);
+			close(fd);
+			return (-1);
+		}
+		s = SEC_TO_TAI64(read_be_dword(buf));
+		/*
+		 * Assume just _one_ leap second on each entry, and compensate
+		 * the lacking error checking by validating the first entry
+		 * against the known value
+		 */
+		if (!m1 && s != 0x4000000004B2580AULL)
+			return (-1);
+		l[m1] = s;
+	}
+
+	/* Clean up and activate the table */
+	close(fd);
+	if (leapsecs != NULL)
+		free(leapsecs);
+	leapsecs = l;
+	leapsecs_num = r;
+	return (0);
+}
diff -pruN openntpd-3.7p1.orig/ntpleaps.h openntpd-3.7p1/ntpleaps.h
--- openntpd-3.7p1.orig/ntpleaps.h	Thu Jan  1 00:00:00 1970
+++ openntpd-3.7p1/ntpleaps.h	Tue May  9 09:08:29 2006
@@ -0,0 +1,75 @@
+/**	$MirOS: src/usr.sbin/rdate/ntpleaps.h,v 1.3 2006/05/09 09:00:00 tg Exp $ */
+/*	$OpenBSD: ntpleaps.h,v 1.3 2004/05/05 20:29:54 jakob Exp $	*/
+
+/*-
+ * Copyright (c) 2002, 2006
+ *	Thorsten Glaser <tg_(_at_)_mirbsd_(_dot_)_de>
+ *
+ * Licensee is hereby permitted to deal in this work without restric-
+ * tion, including unlimited rights to use, publicly perform, modify,
+ * merge, distribute, sell, give away or sublicence, provided all co-
+ * pyright notices above, these terms and the disclaimer are retained
+ * in all redistributions or reproduced in accompanying documentation
+ * or other materials provided with binary redistributions.
+ *
+ * Licensor offers the work "AS IS" and WITHOUT WARRANTY of any kind,
+ * express, or implied, to the maximum extent permitted by applicable
+ * law, without malicious intent or gross negligence; in no event may
+ * licensor, an author or contributor be held liable for any indirect
+ * or other damage, or direct damage except proven a consequence of a
+ * direct error of said person and intended use of this work, loss or
+ * other issues arising in any way out of its use, even if advised of
+ * the possibility of such damage or existence of a nontrivial bug.
+ */
+
+/* Leap second support for SNTP clients
+ * This header file and its corresponding C file provide generic
+ * ability for NTP or SNTP clients to correctly handle leap seconds
+ * by reading them from an always existing file and subtracting the
+ * leap seconds from the NTP return value before setting the posix
+ * clock. This is fairly portable between operating systems and may
+ * be used for patching other ntp clients, too. The tzfile used is:
+ * /usr/share/zoneinfo/right/UTC which is available on any unix-like
+ * platform with the Olson tz library, which is necessary to get real
+ * leap second zoneinfo files and userland support anyways.
+ */
+
+#ifndef	_NTPLEAPS_H
+#define	_NTPLEAPS_H
+
+/* Offset between struct timeval.tv_sec and a tai64_t */
+#define	NTPLEAPS_OFFSET	(4611686018427387914ULL)
+
+/* Hide this ugly value from programmes */
+#define	SEC_TO_TAI64(s)	(NTPLEAPS_OFFSET + (u_int64_t)(s))
+#define	TAI64_TO_SEC(t)	((t) - NTPLEAPS_OFFSET)
+
+/* Initialises the leap second table. Does not need to be called
+ * before usage of the subtract funtion, but calls ntpleaps_read.
+ * Returns 0 on success, -1 on error (displays a warning on stderr)
+ */
+int ntpleaps_init(void);
+
+/* Re-reads the leap second table, thus consuming quite much time.
+ * Ought to be called from within daemons at least once a month to
+ * ensure the in-memory table is always up-to-date.
+ * Returns 0 on success, -1 on error (leap seconds will not be available)
+ */
+int ntpleaps_read(void);
+
+/* Subtracts leap seconds from the given value (converts NTP time
+ * to posix clock tick time.
+ * Returns 0 on success, -1 on error (time is unchanged), 1 on leap second
+ */
+int ntpleaps_sub(u_int64_t *);
+
+/* This macro is not implemented on all operating systems */
+#ifndef	SA_LEN
+#define	SA_LEN(x)	(((x)->sa_family == AF_INET6) ? \
+			    sizeof(struct sockaddr_in6) : \
+			    (((x)->sa_family == AF_INET) ? \
+				sizeof(struct sockaddr_in) : \
+				sizeof(struct sockaddr)))
+#endif
+
+#endif
diff -pruN openntpd-3.7p1.orig/util.c openntpd-3.7p1/util.c
--- openntpd-3.7p1.orig/util.c	Tue Dec 14 01:18:13 2004
+++ openntpd-3.7p1/util.c	Tue May  9 09:08:29 2006
@@ -20,16 +20,25 @@
 #include <limits.h>
 
 #include "ntpd.h"
+#include "ntpleaps.h"
 
+extern int corrleaps;
+
 double
 gettime(void)
 {
 	struct timeval	tv;
+	uint64_t t;
 
 	if (gettimeofday(&tv, NULL) == -1)
 		fatal("gettimeofday");
 
-	return (tv.tv_sec + JAN_1970 + 1.0e-6 * tv.tv_usec);
+	/* subtract leap seconds to set the posix tick */
+	t = SEC_TO_TAI64(tv.tv_sec);
+	if (corrleaps)
+		ntpleaps_sub(&t);
+
+	return (TAI64_TO_SEC(t) + JAN_1970 + 1.0e-6 * tv.tv_usec);
 }



Visit your host, monkey.org