sys_macosx: add support for ntp_adjtime() on macOS 10.13+
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.
This commit is contained in:
parent
778fce4039
commit
ccb94ac5fb
5 changed files with 109 additions and 22 deletions
9
configure
vendored
9
configure
vendored
|
@ -428,6 +428,15 @@ case $OPERATINGSYSTEM in
|
||||||
add_def FEAT_PRIVDROP
|
add_def FEAT_PRIVDROP
|
||||||
priv_ops="ADJUSTTIME SETTIME BINDSOCKET"
|
priv_ops="ADJUSTTIME SETTIME BINDSOCKET"
|
||||||
fi
|
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 ")"
|
echo "Configuring for macOS (" $SYSTEM "macOS version" $VERSION ")"
|
||||||
;;
|
;;
|
||||||
SunOS)
|
SunOS)
|
||||||
|
|
|
@ -587,11 +587,12 @@ can be specified.
|
||||||
To compute the rate of gain or loss of time, *chronyd* has to store a
|
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.
|
measurement history for each of the time sources it uses.
|
||||||
+
|
+
|
||||||
Certain systems (Linux, FreeBSD, NetBSD, Solaris) have operating system support
|
All supported systems, with the exception of macOS 10.12 and earlier, have
|
||||||
for setting the rate of gain or loss to compensate for known errors. (On Mac OS
|
operating system support for setting the rate of gain or loss to compensate for
|
||||||
X, *chronyd* must simulate such a capability by periodically slewing the system
|
known errors.
|
||||||
clock forwards or backwards by a suitable amount to compensate for the error
|
(On macOS 10.12 and earlier, *chronyd* must simulate such a capability by
|
||||||
built up since the previous slew.)
|
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
|
For such systems, it is possible to save the measurement history across
|
||||||
restarts of *chronyd* (assuming no changes are made to the system clock
|
restarts of *chronyd* (assuming no changes are made to the system clock
|
||||||
|
@ -690,8 +691,9 @@ distances are in milliseconds.
|
||||||
|
|
||||||
[[corrtimeratio]]*corrtimeratio* _ratio_::
|
[[corrtimeratio]]*corrtimeratio* _ratio_::
|
||||||
When *chronyd* is slewing the system clock to correct an offset, the rate at
|
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,
|
which it is slewing adds to the frequency error of the clock. On all supported
|
||||||
FreeBSD, NetBSD and Solaris this rate can be controlled.
|
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
|
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
|
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
|
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
|
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
|
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,
|
default mode when the system driver supports leap seconds (i.e. all supported
|
||||||
FreeBSD, NetBSD and Solaris).
|
systems with the exception of macOS 12 and earlier).
|
||||||
*step*:::
|
*step*:::
|
||||||
This is similar to the *system* mode, except the clock is stepped by
|
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
|
*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
|
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
|
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
|
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
|
By default, the maximum assumed drift is 500000 ppm, i.e. the adjustment is
|
||||||
limited by the system driver rather than this directive.
|
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
|
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
|
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.
|
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
|
For each system there is a maximum frequency offset of the clock that can be set
|
||||||
can be set by the driver. On Linux it is 100000 ppm, on FreeBSD and NetBSD
|
by the driver. On Linux it is 100000 ppm, on FreeBSD, NetBSD and macOS 10.13+ it
|
||||||
it is 5000 ppm, and on Solaris it is 32500 ppm. Also, due to a kernel
|
is 5000 ppm, and on Solaris it is 32500 ppm. Also, due to a kernel limitation,
|
||||||
limitation, setting *maxslewrate* on FreeBSD and NetBSD to a value between 500
|
setting *maxslewrate* on FreeBSD, NetBSD, macOS 10.13+ to a value between 500
|
||||||
ppm and 5000 ppm will effectively set it to 500 ppm.
|
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).
|
By default, the maximum slew rate is set to 83333.333 ppm (one twelfth).
|
||||||
|
|
||||||
[[tempcomp]]
|
[[tempcomp]]
|
||||||
|
|
|
@ -87,8 +87,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
|
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.
|
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
|
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
|
compensation whilst not under *chronyd*'s control (i.e. Linux, FreeBSD, NetBSD,
|
||||||
and Solaris).
|
Solaris, and macOS 10.13 or later).
|
||||||
|
|
||||||
*-R*::
|
*-R*::
|
||||||
When this option is used, the <<chrony.conf.adoc#initstepslew,*initstepslew*>>
|
When this option is used, the <<chrony.conf.adoc#initstepslew,*initstepslew*>>
|
||||||
|
|
80
sys_macosx.c
80
sys_macosx.c
|
@ -46,6 +46,15 @@
|
||||||
#include "privops.h"
|
#include "privops.h"
|
||||||
#include "util.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
|
/* 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
|
static void
|
||||||
SYS_MacOSX_Initialise(void)
|
legacy_MacOSX_Initialise(void)
|
||||||
{
|
{
|
||||||
clock_initialise();
|
clock_initialise();
|
||||||
|
|
||||||
|
@ -434,8 +443,8 @@ SYS_MacOSX_Initialise(void)
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
void
|
static void
|
||||||
SYS_MacOSX_Finalise(void)
|
legacy_MacOSX_Finalise(void)
|
||||||
{
|
{
|
||||||
SCH_RemoveTimeout(drift_removal_id);
|
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) {
|
||||||
|
LOG(LOGS_WARN, "adjtime() is buggy - using 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
|
#endif
|
||||||
|
|
|
@ -59,7 +59,7 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.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>
|
#include <sys/timex.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue