--- include/ntp_stdlib.h.orig 2025-04-18 12:54:14.000000000 -0700 +++ include/ntp_stdlib.h 2025-04-20 16:24:35.000000000 -0700 @@ -103,7 +103,9 @@ extern const char * eventstr (int); extern const char * ceventstr (int); extern const char * res_match_flags(unsigned short); extern const char * res_access_flags(unsigned short); +#ifdef HAVE_KERNEL_PLL extern const char * k_st_flags (uint32_t); +#endif extern char * statustoa (int, int); extern const char * socktoa (const sockaddr_u *); extern const char * socktoa_r (const sockaddr_u *sock, char *buf, size_t buflen); --- include/ntp_syscall.h.orig 2022-12-22 22:08:52.000000000 -0800 +++ include/ntp_syscall.h 2025-04-20 16:24:35.000000000 -0700 @@ -9,9 +9,11 @@ #ifndef GUARD_NTP_SYSCALL_H #define GUARD_NTP_SYSCALL_H +#ifdef HAVE_SYS_TIMEX_H # include /* prerequisite on NetBSD */ # include extern int ntp_adjtime_ns(struct timex *); +#endif /* * The units of the maxerror and esterror fields vary by platform. If --- libntp/clockwork.c.orig 2023-12-28 20:53:56.000000000 -0800 +++ libntp/clockwork.c 2025-04-20 16:24:35.000000000 -0700 @@ -5,8 +5,10 @@ #include "config.h" #include -#include /* prerequisite on NetBSD */ -#include +#ifdef HAVE_SYS_TIMEX_H +# include /* prerequisite on NetBSD */ +# include +#endif #include "ntp.h" #include "ntp_machine.h" --- libntp/statestr.c.orig 2025-04-18 12:54:14.000000000 -0700 +++ libntp/statestr.c 2025-04-20 16:24:35.000000000 -0700 @@ -12,7 +12,9 @@ #include "lib_strbuf.h" #include "ntp_refclock.h" #include "ntp_control.h" +#ifdef HAVE_KERNEL_PLL # include "ntp_syscall.h" +#endif /* @@ -186,23 +188,50 @@ static const struct codestring res_acces /* not used with getcode(), no terminating entry needed */ }; +#ifdef HAVE_KERNEL_PLL /* * kernel discipline status bits */ static const struct codestring k_st_bits[] = { +# ifdef STA_PLL { STA_PLL, "pll" }, +# endif +# ifdef STA_PPSFREQ { STA_PPSFREQ, "ppsfreq" }, +# endif +# ifdef STA_PPSTIME { STA_PPSTIME, "ppstime" }, +# endif +# ifdef STA_FLL { STA_FLL, "fll" }, +# endif +# ifdef STA_INS { STA_INS, "ins" }, +# endif +# ifdef STA_DEL { STA_DEL, "del" }, +# endif +# ifdef STA_UNSYNC { STA_UNSYNC, "unsync" }, +# endif +# ifdef STA_FREQHOLD { STA_FREQHOLD, "freqhold" }, +# endif +# ifdef STA_PPSSIGNAL { STA_PPSSIGNAL, "ppssignal" }, +# endif +# ifdef STA_PPSJITTER { STA_PPSJITTER, "ppsjitter" }, +# endif +# ifdef STA_PPSWANDER { STA_PPSWANDER, "ppswander" }, +# endif +# ifdef STA_PPSERROR { STA_PPSERROR, "ppserror" }, +# endif +# ifdef STA_CLOCKERR { STA_CLOCKERR, "clockerr" }, +# endif # ifdef STA_NANO { STA_NANO, "nano" }, # endif @@ -214,6 +243,7 @@ static const struct codestring k_st_bits # endif /* not used with getcode(), no terminating entry needed */ }; +#endif /* HAVE_KERNEL_PLL */ /* Forwards */ static const char * getcode(int, const struct codestring *); @@ -318,10 +348,12 @@ decode_bitflags( "decode_bitflags(%s) can't decode 0x%x in %d bytes", (tab == peer_st_bits) ? "peer_st" - : + : +#ifdef HAVE_KERNEL_PLL (tab == k_st_bits) ? "kern_st" : +#endif "", (unsigned)bits, (int)LIB_BUFLENGTH); errno = saved_errno; @@ -360,6 +392,7 @@ res_access_flags( } +#ifdef HAVE_KERNEL_PLL const char * k_st_flags( uint32_t st @@ -367,6 +400,8 @@ k_st_flags( { return decode_bitflags((int)st, " ", k_st_bits, COUNTOF(k_st_bits)); } +#endif /* HAVE_KERNEL_PLL */ + /* * statustoa - return a descriptive string for a peer status --- ntpclients/ntpq.py.orig 2025-04-18 12:54:14.000000000 -0700 +++ ntpclients/ntpq.py 2025-04-20 16:24:35.000000000 -0700 @@ -25,6 +25,14 @@ import socket import sys import time +# The BrokenPipeError doesn't exist in Python 2, but the problem that requires +# catching it also doesn't seem to exist in Python 2, so just make it a dummy +# in Python 2. +try: + BrokenPipeError +except NameError: + BrokenPipeError = None + try: import ntp.control import ntp.ntpc --- ntpd/ntp_control.c.orig 2025-04-18 12:54:14.000000000 -0700 +++ ntpd/ntp_control.c 2025-04-20 16:24:35.000000000 -0700 @@ -37,7 +37,9 @@ struct utsname utsnamebuf; /* Variables that need updating each time. */ static leap_signature_t lsig; +#ifdef HAVE_KERNEL_PLL static struct timex ntx; +#endif /* HAVE_KERNEL_PLL */ /* Ugh. timex slots are tough. The man page says "long" * But the actual implementation on Linux uses something else. @@ -382,6 +384,7 @@ static const struct var sys_var[] = { Var_uli("authcmacdecrypts", RO, authcmacdecrypt), Var_uli("authcmacfails", RO, authcmacfail), +#ifdef HAVE_KERNEL_PLL /* kerninfo: Kernel timekeeping info */ Var_kli("koffset", RO|N_CLOCK|KNUToMS, ntx.offset), Var_kli("kfreq", RO|N_CLOCK|K_16, ntx.freq), @@ -399,6 +402,7 @@ static const struct var sys_var[] = { Var_kli("kppscalibs", RO|N_CLOCK, ntx.calcnt), Var_kli("kppscaliberrs", RO|N_CLOCK, ntx.errcnt), Var_kli("kppsstbexc", RO|N_CLOCK, ntx.stbcnt), +#endif /* HAVE_KERNEL_PLL */ /* refclock stuff in ntp_io */ @@ -1402,7 +1406,9 @@ ctl_putarray( */ static void ctl_putsys(const struct var * v) { +#ifdef HAVE_KERNEL_PLL static unsigned long ntp_adjtime_time; +#endif /* HAVE_KERNEL_PLL */ static unsigned long ntp_leap_time; /* older compilers don't allow declarations on each case without {} */ @@ -1414,6 +1420,7 @@ ctl_putsys(const struct var * v) { * This should get pushed up a layer: flag, once per request * This could get data from 2 samples if the clock ticks while we are working.. */ +#ifdef HAVE_KERNEL_PLL /* The Kernel clock variables need up-to-date output of ntp_adjtime() */ if (v->flags&N_CLOCK && current_time != ntp_adjtime_time) { ZERO(ntx); @@ -1422,6 +1429,7 @@ ctl_putsys(const struct var * v) { "MODE6: ntp_adjtime() for mode 6 query failed: %s", strerror(errno)); ntp_adjtime_time = current_time; } +#endif /* HAVE_KERNEL_PLL */ /* The leap second variables need up-to-date info */ if (v->flags&N_LEAP && current_time != ntp_leap_time) { --- ntpd/ntp_loopfilter.c.orig 2025-04-18 12:54:14.000000000 -0700 +++ ntpd/ntp_loopfilter.c 2025-04-20 16:24:35.000000000 -0700 @@ -23,8 +23,10 @@ #define NTP_MAXFREQ 500e-6 +#ifdef HAVE_KERNEL_PLL # define FREQTOD(x) ((x) / 65536e6) /* NTP to double */ # define DTOFREQ(x) ((int32_t)((x) * 65536e6)) /* double to NTP */ +#endif /* HAVE_KERNEL_PLL */ /* * This is an implementation of the clock discipline algorithm described @@ -125,6 +127,7 @@ static void rstclock (int, double); /* t static double direct_freq(double); /* direct set frequency */ static void set_freq(double); /* set frequency */ +#ifdef HAVE_KERNEL_PLL #ifndef PATH_MAX # define PATH_MAX MAX_PATH #endif @@ -138,6 +141,7 @@ static unsigned int loop_tai; /* last TA #endif /* STA_NANO */ static void start_kern_loop(void); static void stop_kern_loop(void); +#endif /* HAVE_KERNEL_PLL */ /* * Clock state machine control flags @@ -154,7 +158,9 @@ struct clock_control_flags clock_ctl = { int freq_cnt; /* initial frequency clamp */ static int freq_set; /* initial set frequency switch */ +#ifdef HAVE_KERNEL_PLL static bool ext_enable; /* external clock enabled */ +#endif /* HAVE_KERNEL_PLL */ /* * Clock state machine variables @@ -172,10 +178,13 @@ static int sys_hufflen; /* huff-n'-puff static int sys_huffptr; /* huff-n'-puff filter pointer */ static double sys_mindly; /* huff-n'-puff filter min delay */ +#if defined(HAVE_KERNEL_PLL) /* Emacs cc-mode goes nuts if we split the next line... */ #define MOD_BITS (MOD_OFFSET | MOD_MAXERROR | MOD_ESTERROR | \ MOD_STATUS | MOD_TIMECONST) +#endif /* HAVE_KERNEL_PLL */ +#ifdef HAVE_KERNEL_PLL static void sync_status(const char *what, int ostatus, int nstatus) { /* only used in non-lockclock case */ @@ -199,6 +208,7 @@ static char *file_name(void) { } return this_file; } +#endif /* HAVE_KERNEL_PLL */ /* * init_loopfilter - initialize loop filter data @@ -213,6 +223,7 @@ init_loopfilter(void) { freq_cnt = (int)clock_minstep; } +#ifdef HAVE_KERNEL_PLL /* * ntp_adjtime_error_handler - process errors from ntp_adjtime */ @@ -411,6 +422,7 @@ or, from ntp_adjtime(): } return; } +#endif /* HAVE_KERNEL_PLL */ /* * local_clock - the NTP logical clock loop filter. @@ -444,7 +456,9 @@ local_clock( int rval; /* return code */ int osys_poll; /* old system poll */ +#ifdef HAVE_KERNEL_PLL int ntp_adj_ret; /* returned by ntp_adjtime */ +#endif /* HAVE_KERNEL_PLL */ double mu; /* interval since last update */ double clock_frequency; /* clock frequency */ double dtemp, etemp; /* double temps */ @@ -701,6 +715,7 @@ local_clock( } } +#ifdef HAVE_KERNEL_PLL /* * This code segment works when clock adjustments are made using * precision time kernel support and the ntp_adjtime() system @@ -810,6 +825,7 @@ local_clock( } #endif /* STA_NANO */ } +#endif /* HAVE_KERNEL_PLL */ /* * Clamp the frequency within the tolerance range and calculate @@ -921,8 +937,10 @@ adj_host_clock( } else if (freq_cnt > 0) { offset_adj = clock_offset / (CLOCK_PLL * ULOGTOD(1)); freq_cnt--; +#ifdef HAVE_KERNEL_PLL } else if (clock_ctl.pll_control && clock_ctl.kern_enable) { offset_adj = 0.; +#endif /* HAVE_KERNEL_PLL */ } else { offset_adj = clock_offset / (CLOCK_PLL * ULOGTOD(clkstate.sys_poll)); } @@ -933,9 +951,11 @@ adj_host_clock( * set_freq(). Otherwise it is a component of the adj_systime() * offset. */ +#ifdef HAVE_KERNEL_PLL if (clock_ctl.pll_control && clock_ctl.kern_enable) freq_adj = 0.; else +#endif /* HAVE_KERNEL_PLL */ freq_adj = loop_data.drift_comp; /* Bound absolute value of total adjustment to NTP_MAXFREQ. */ @@ -1024,6 +1044,7 @@ set_freq( loop_data.drift_comp = freq; loop_desc = "ntpd"; +#ifdef HAVE_KERNEL_PLL if (clock_ctl.pll_control) { int ntp_adj_ret; ZERO(ntv); @@ -1036,10 +1057,12 @@ set_freq( ntp_adjtime_error_handler(__func__, &ntv, ntp_adj_ret, errno, false, false, __LINE__ - 1); } } +#endif /* HAVE_KERNEL_PLL */ mprintf_event(EVNT_FSET, NULL, "%s %.6f PPM", loop_desc, loop_data.drift_comp * US_PER_S); } +#ifdef HAVE_KERNEL_PLL static void start_kern_loop(void) { @@ -1075,8 +1098,10 @@ start_kern_loop(void) "kernel time sync enabled"); } } +#endif /* HAVE_KERNEL_PLL */ +#ifdef HAVE_KERNEL_PLL static void stop_kern_loop(void) { @@ -1084,6 +1109,7 @@ stop_kern_loop(void) report_event(EVNT_KERN, NULL, "kernel time sync disabled"); } +#endif /* HAVE_KERNEL_PLL */ /* @@ -1096,11 +1122,15 @@ select_loop( { if (clock_ctl.kern_enable == use_kern_loop) return; +#ifdef HAVE_KERNEL_PLL if (clock_ctl.pll_control && !use_kern_loop) stop_kern_loop(); +#endif /* HAVE_KERNEL_PLL */ clock_ctl.kern_enable = use_kern_loop; +#ifdef HAVE_KERNEL_PLL if (clock_ctl.pll_control && use_kern_loop) start_kern_loop(); +#endif /* HAVE_KERNEL_PLL */ /* * If this loop selection change occurs after initial startup, * call set_freq() to switch the frequency compensation to or @@ -1156,10 +1186,12 @@ loop_config( * variables. Otherwise, continue leaving no harm behind. */ case LOOP_DRIFTINIT: +#ifdef HAVE_KERNEL_PLL if (loop_data.lockclock || clock_ctl.mode_ntpdate) break; start_kern_loop(); +#endif /* HAVE_KERNEL_PLL */ /* * Initialize frequency if given; otherwise, begin frequency @@ -1178,7 +1210,9 @@ loop_config( rstclock(EVNT_FSET, 0); else rstclock(EVNT_NSET, 0); +#ifdef HAVE_KERNEL_PLL loop_started = true; +#endif /* HAVE_KERNEL_PLL */ break; /* @@ -1252,4 +1286,3 @@ loop_config( "CONFIG: loop_config: unsupported option %d", item); } } - --- ntpd/ntp_timer.c.orig 2025-04-18 12:54:14.000000000 -0700 +++ ntpd/ntp_timer.c 2025-04-20 16:24:35.000000000 -0700 @@ -13,7 +13,9 @@ #include #include +#ifdef HAVE_KERNEL_PLL #include "ntp_syscall.h" +#endif /* HAVE_KERNEL_PLL */ #ifdef HAVE_TIMER_CREATE /* TC_ERR represents the timer_create() error return value. */ @@ -373,7 +375,11 @@ check_leapsec( leap_result_t lsdata; uint32_t lsprox; +#ifdef HAVE_KERNEL_PLL leapsec_electric((clock_ctl.pll_control && clock_ctl.kern_enable) ? electric_on : electric_off); +#else + leapsec_electric(electric_off); +#endif #ifdef ENABLE_LEAP_SMEAR leap_smear.enabled = (leap_smear_intv != 0); #endif --- ntpd/refclock_local.c.orig 2025-04-18 12:54:14.000000000 -0700 +++ ntpd/refclock_local.c 2025-04-20 16:24:35.000000000 -0700 @@ -164,6 +164,7 @@ local_poll( * If another process is disciplining the system clock, we set * the leap bits and quality indicators from the kernel. */ +#ifdef HAVE_KERNEL_PLL if (loop_data.lockclock) { /* Both ntp_adjtime() and ntp_gettime() return the clock status * which includes leap pending info. See man ntp_adjtime @@ -210,6 +211,13 @@ local_poll( pp->disp = DISPERSION; pp->jitter = 0; } + pp->disp = 0; + pp->jitter = 0; +#else /* !HAVE_KERNEL_PLL */ + pp->leap = LEAP_NOWARNING; + pp->disp = DISPERSION; + pp->jitter = 0; +#endif /* !HAVE_KERNEL_PLL */ pp->lastref = pp->lastrec; refclock_receive(peer); } --- tests/libntp/statestr.c.orig 2025-04-18 12:54:14.000000000 -0700 +++ tests/libntp/statestr.c 2025-04-20 16:24:35.000000000 -0700 @@ -4,7 +4,9 @@ #include "unity.h" #include "unity_fixture.h" +#ifdef HAVE_SYS_TIMEX_H #include +#endif TEST_GROUP(statestr); @@ -32,7 +34,9 @@ TEST(statestr, ResAccessFlags2) { // k_st_flags() TEST(statestr, KSTFlags) { +#ifdef STA_PPSFREQ TEST_ASSERT_EQUAL_STRING("ppsfreq", k_st_flags(STA_PPSFREQ)); +#endif } // statustoa --- wafhelpers/bin_test.py.orig 2025-04-18 12:54:14.000000000 -0700 +++ wafhelpers/bin_test.py 2025-04-20 16:24:35.000000000 -0700 @@ -88,8 +88,11 @@ def cmd_bin_test(ctx): (BIN, NTPCLIENTS, "ntpleapfetch", "--version"), (SBIN, NTPD, "ntpd", "--version"), (BIN, NTPFROB, "ntpfrob", "-V"), - (BIN, NTPTIME, "ntptime", "-V"), ] + # Only include ntptime if it was built + if ctx.env.HEADER_SYS_TIMEX_H: + cmd_list.append((BIN, NTPTIME, "ntptime", "-V")) + cmd_list_python = [ (BIN, NTPCLIENTS, "ntpdig", "--version"), (BIN, NTPCLIENTS, "ntpkeygen", "--version"), --- wafhelpers/options.py.orig 2025-04-18 12:54:14.000000000 -0700 +++ wafhelpers/options.py 2025-04-20 16:24:35.000000000 -0700 @@ -24,6 +24,8 @@ def options_cmd(ctx, config): help="Droproot earlier (breaks SHM and NetBSD).") grp.add_option('--enable-seccomp', action='store_true', default=False, help="Enable seccomp (restricts syscalls).") + grp.add_option('--disable-kernel-pll', action='store_true', + default=False, help="Disable kernel PLL.") grp.add_option('--disable-mdns-registration', action='store_true', default=False, help="Disable MDNS registration.") grp.add_option( --- wscript.orig 2025-04-18 12:54:14.000000000 -0700 +++ wscript 2025-04-20 16:24:35.000000000 -0700 @@ -578,7 +578,7 @@ int main(int argc, char **argv) { structures = ( ("struct if_laddrconf", ["sys/types.h", "net/if6.h"], False), ("struct if_laddrreq", ["sys/types.h", "net/if6.h"], False), - ("struct timex", ["sys/time.h", "sys/timex.h"], True), + ("struct timex", ["sys/time.h", "sys/timex.h"], False), ("struct ntptimeval", ["sys/time.h", "sys/timex.h"], False), ) for (s, h, r) in structures: @@ -809,6 +809,21 @@ int main(int argc, char **argv) { if ctx.options.disable_fuzz: pprint("YELLOW", "--disable-fuzz is now standard. Clock fuzzing is gone.") + # Does the kernel implement a phase-locked loop for timing? + # All modern Unixes (in particular Linux and *BSD) have this. + # + # The README for the (now deleted) kernel directory says this: + # "If the precision-time kernel (KERNEL_PLL define) is + # configured, the installation process requires the header + # file /usr/include/sys/timex.h for the particular + # architecture to be in place." + # + if ((ctx.get_define("HAVE_SYS_TIMEX_H") and + not ctx.options.disable_kernel_pll)): + ctx.define("HAVE_KERNEL_PLL", 1, + comment="Whether phase-locked loop for timing " + "exists and is enabled") + # SO_REUSEADDR socket option is needed to open a socket on an # interface when the port number is already in use on another # interface. Linux needs this, NetBSD does not, status on