[chrony-dev] [PATCH] macOS - support for ntp_adjtime()

[ Thread Index | Date Index | More chrony.tuxfamily.org/chrony-dev Archives ]


macOS 10.13 will implement the ntp_adjtime() system call, allowing better
control over the system clock than is possible with the existing adjtime()
system call.
chronyd will support both the older and newer calls, enabling binary code to
run without recompilation on macOS 10.9 through macOS 10.13

Early releases of macOS 10.13 have a very buggy adjtime() call. The macOS
driver tests adjtime() to see if the bug has been fixed. If the bug
persists then the timex driver is invoked otherwise the netbsd driver.
---
 configure            |  9 ++++++
 doc/chrony.conf.adoc | 36 +++++++++++++----------
 doc/chronyd.adoc     |  4 +--
 sys_macosx.c         | 80 +++++++++++++++++++++++++++++++++++++++++++++++++---
 sysincl.h            |  2 +-
 5 files changed, 109 insertions(+), 22 deletions(-)

diff --git a/configure b/configure
index 9f7a5b2..5d2ed7a 100755
--- a/configure
+++ b/configure
@@ -428,6 +428,15 @@ case $OPERATINGSYSTEM in
           add_def FEAT_PRIVDROP
           priv_ops="ADJUSTTIME SETTIME BINDSOCKET"
         fi
+        major=`echo $VERSION | cut -d. -f1`
+        # ntp_adjtime is not available in macOS 10.12 (Darwin 16.x.x) and earlier
+        if [ $major -gt "16" ]; then
+          add_def HAVE_MACOS_SYS_TIMEX
+          EXTRA_OBJECTS="$EXTRA_OBJECTS sys_generic.o sys_netbsd.o sys_timex.o"
+          if [ $feat_droproot = "1" ]; then
+            priv_ops="$priv_ops ADJUSTTIMEX"
+          fi
+        fi
         echo "Configuring for macOS (" $SYSTEM "macOS version" $VERSION ")"
     ;;
     SunOS)
diff --git a/doc/chrony.conf.adoc b/doc/chrony.conf.adoc
index ed81d40..3607c83 100644
--- a/doc/chrony.conf.adoc
+++ b/doc/chrony.conf.adoc
@@ -587,11 +587,12 @@ can be specified.
 To compute the rate of gain or loss of time, *chronyd* has to store a
 measurement history for each of the time sources it uses.
 +
-Certain systems (Linux, FreeBSD, NetBSD, Solaris) have operating system support
-for setting the rate of gain or loss to compensate for known errors. (On Mac OS
-X, *chronyd* must simulate such a capability by periodically slewing the system
-clock forwards or backwards by a suitable amount to compensate for the error
-built up since the previous slew.)
+All supported systems, with the exception of macOS 10.12 and earlier, have
+operating system support for setting the rate of gain or loss to compensate for
+known errors.
+(On macOS 10.12 and earlier, *chronyd* must simulate such a capability by
+periodically slewing the system clock forwards or backwards by a suitable amount
+to compensate for the error built up since the previous slew.)
 +
 For such systems, it is possible to save the measurement history across
 restarts of *chronyd* (assuming no changes are made to the system clock
@@ -690,8 +691,9 @@ distances are in milliseconds.
 
 [[corrtimeratio]]*corrtimeratio* _ratio_::
 When *chronyd* is slewing the system clock to correct an offset, the rate at
-which it is slewing adds to the frequency error of the clock. On Linux,
-FreeBSD, NetBSD and Solaris this rate can be controlled.
+which it is slewing adds to the frequency error of the clock. On all supported
+systems, with the exception of macOS 12 and earlier, this rate can be
+controlled.
 +
 The *corrtimeratio* directive sets the ratio between the duration in which the
 clock is slewed for an average correction according to the source history and
@@ -774,8 +776,8 @@ that error is corrected. There are four options:
 When inserting a leap second, the kernel steps the system clock backwards by
 one second when the clock gets to 00:00:00 UTC. When deleting a leap second, it
 steps forward by one second when the clock gets to 23:59:59 UTC. This is the
-default mode when the system driver supports leap seconds (i.e. on Linux,
-FreeBSD, NetBSD and Solaris).
+default mode when the system driver supports leap seconds (i.e. all supported
+systems with the exception of macOS 12 and earlier).
 *step*:::
 This is similar to the *system* mode, except the clock is stepped by
 *chronyd* instead of the kernel. It can be useful to avoid bugs in the kernel
@@ -918,7 +920,7 @@ This directive specifies the maximum assumed drift (frequency error) of the
 system clock. It limits the frequency adjustment that *chronyd* is allowed to
 use to correct the measured drift. It is an additional limit to the maximum
 adjustment that can be set by the system driver (100000 ppm on Linux, 500 ppm
-on FreeBSD and NetBSD, 32500 ppm on Solaris).
+on FreeBSD, NetBSD, and macOS 10.13+, 32500 ppm on Solaris).
 +
 By default, the maximum assumed drift is 500000 ppm, i.e. the adjustment is
 limited by the system driver rather than this directive.
@@ -953,14 +955,18 @@ The *maxslewrate* directive sets the maximum rate at which *chronyd* is allowed
 to slew the time. It limits the slew rate controlled by the correction time
 ratio (which can be set by the <<corrtimeratio,*corrtimeratio*>> directive) and
 is effective only on systems where *chronyd* is able to control the rate (i.e.
-Linux, FreeBSD, NetBSD, Solaris).
+all supported systems with the exception of macOS 12 or earlier).
 +
-For each system there is a maximum frequency offset of the clock that
-can be set by the driver. On Linux it is 100000 ppm, on FreeBSD and NetBSD
-it is 5000 ppm, and on Solaris it is 32500 ppm. Also, due to a kernel
-limitation, setting *maxslewrate* on FreeBSD and NetBSD to a value between 500
+For each system there is a maximum frequency offset of the clock that can be set
+by the driver. On Linux it is 100000 ppm, on FreeBSD, NetBSD and macOS 10.13+ it
+is 5000 ppm, and on Solaris it is 32500 ppm. Also, due to a kernel limitation,
+setting *maxslewrate* on FreeBSD, NetBSD, macOS 10.13+ to a value between 500
 ppm and 5000 ppm will effectively set it to 500 ppm.
 +
+In early beta releases of macOS 13 this capability is disabled because of a
+system kernel bug. When the kernel bug is fixed, chronyd will detect this and
+re-enable the capability (see above limitations) with no recompilation required.
++
 By default, the maximum slew rate is set to 83333.333 ppm (one twelfth).
 
 [[tempcomp]]
diff --git a/doc/chronyd.adoc b/doc/chronyd.adoc
index d1ac4d4..f6aac25 100644
--- a/doc/chronyd.adoc
+++ b/doc/chronyd.adoc
@@ -86,8 +86,8 @@ histories are created by using the <<chronyc.adoc#dump,*dump*>> command in
 directive in the configuration file. This option is useful if you want to stop
 and restart *chronyd* briefly for any reason, e.g. to install a new version.
 However, it should be used only on systems where the kernel can maintain clock
-compensation whilst not under *chronyd*'s control (i.e. Linux, FreeBSD, NetBSD
-and Solaris).
+compensation whilst not under *chronyd*'s control (i.e. Linux, FreeBSD, NetBSD,
+Solaris, and macOS 10.13 or later).
 
 *-R*::
 When this option is used, the <<chrony.conf.adoc#initstepslew,*initstepslew*>>
diff --git a/sys_macosx.c b/sys_macosx.c
index 5e27b6b..0160011 100644
--- a/sys_macosx.c
+++ b/sys_macosx.c
@@ -46,6 +46,15 @@
 #include "privops.h"
 #include "util.h"
 
+#ifdef HAVE_MACOS_SYS_TIMEX
+#include <dlfcn.h>
+#include "sys_netbsd.h"
+#include "sys_timex.h"
+
+static int have_ntp_adjtime = 0;
+static int have_bad_adjtime = 0;
+#endif
+
 /* ================================================== */
 
 /* This register contains the number of seconds by which the local
@@ -417,8 +426,8 @@ void SYS_MacOSX_DropRoot(uid_t uid, gid_t gid)
 
 /* ================================================== */
 
-void
-SYS_MacOSX_Initialise(void)
+static void
+legacy_MacOSX_Initialise(void)
 {
   clock_initialise();
 
@@ -434,8 +443,8 @@ SYS_MacOSX_Initialise(void)
 
 /* ================================================== */
 
-void
-SYS_MacOSX_Finalise(void)
+static void
+legacy_MacOSX_Finalise(void)
 {
   SCH_RemoveTimeout(drift_removal_id);
 
@@ -444,4 +453,67 @@ SYS_MacOSX_Finalise(void)
 
 /* ================================================== */
 
+#ifdef HAVE_MACOS_SYS_TIMEX
+/*
+    Test adjtime() to see if Apple have fixed the signed/unsigned bug
+*/
+static int
+test_adjtime()
+{
+  struct timeval tv1 = {-1, 0};
+  struct timeval tv2 = {0, 0};
+  struct timeval tv;
+
+  if (PRV_AdjustTime(&tv1, &tv) != 0) {
+    return 0;
+  }
+  if (PRV_AdjustTime(&tv2, &tv) != 0) {
+    return 0;
+  }
+  if (tv.tv_sec < -1 || tv.tv_sec > 1) {
+    return 0;
+  }
+  return 1;
+}
+#endif
+
+/* ================================================== */
+
+void
+SYS_MacOSX_Initialise(void)
+{
+#ifdef HAVE_MACOS_SYS_TIMEX
+  have_ntp_adjtime = (dlsym(RTLD_NEXT, "ntp_adjtime") != NULL);
+  if (have_ntp_adjtime) {
+    have_bad_adjtime = !test_adjtime();
+    if (have_bad_adjtime) {
+      DEBUG_LOG("adjtime() is buggy - use the timex driver");
+      SYS_Timex_Initialise();
+    } else {
+      SYS_NetBSD_Initialise();
+    }
+    return;
+  }
+#endif
+  legacy_MacOSX_Initialise();
+}
+
+/* ================================================== */
+
+void
+SYS_MacOSX_Finalise(void)
+{
+#ifdef HAVE_MACOS_SYS_TIMEX
+  if (have_ntp_adjtime) {
+    if (have_bad_adjtime) {
+      SYS_Timex_Finalise();
+    } else {
+      SYS_NetBSD_Finalise();
+    }
+    return;
+  }
+#endif
+  legacy_MacOSX_Finalise();
+}
+
 #endif
diff --git a/sysincl.h b/sysincl.h
index 0e1c65a..a9e4da0 100644
--- a/sysincl.h
+++ b/sysincl.h
@@ -59,7 +59,7 @@
 #include <time.h>
 #include <unistd.h>
 
-#if defined(LINUX) || defined(FREEBSD) || defined(NETBSD) || defined(SOLARIS)
+#if defined(LINUX) || defined(FREEBSD) || defined(NETBSD) || defined(SOLARIS) || defined(HAVE_MACOS_SYS_TIMEX)
 #include <sys/timex.h>
 #endif
 
-- 
2.11.0 (Apple Git-81)


-- 
To unsubscribe email chrony-dev-request@xxxxxxxxxxxxxxxxxxxx with "unsubscribe" in the subject.
For help email chrony-dev-request@xxxxxxxxxxxxxxxxxxxx with "help" in the subject.
Trouble?  Email listmaster@xxxxxxxxxxxxxxxxxxxx.


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/