From f168ca2c26e4c9f4f6c792730d3f44dd35535edd Mon Sep 17 00:00:00 2001 From: Vincent Blut Date: Tue, 14 May 2019 13:53:03 +0200 Subject: New upstream version 3.5 --- FAQ | 12 +- INSTALL | 23 ++- Makefile.in | 2 + NEWS | 19 +++ README | 109 ++----------- client.c | 2 +- configure | 44 ++++-- doc/chrony.conf.adoc | 58 +++---- doc/chrony.conf.man.in | 62 ++++---- doc/chronyc.man.in | 4 +- doc/chronyd.man.in | 4 +- doc/faq.adoc | 10 ++ doc/installation.adoc | 13 ++ examples/chronyd.service | 2 +- hash_intmd5.c | 1 + nameserv.c | 3 + ntp_io.c | 14 +- ntp_io_linux.c | 50 ++++-- refclock.c | 66 ++++++-- refclock.h | 1 + refclock_phc.c | 3 + refclock_pps.c | 3 + refclock_shm.c | 3 + refclock_sock.c | 2 + sys.c | 13 +- sys_linux.c | 206 ++++++++++++------------ sys_linux.h | 4 - sys_macosx.c | 42 +---- sys_posix.c | 109 +++++++++++++ sys_posix.h | 36 +++++ sysincl.h | 2 - test/simulation/008-ntpera | 2 +- test/simulation/105-ntpauth | 2 +- test/simulation/106-refclock | 4 + test/simulation/107-allowdeny | 2 + test/simulation/110-chronyc | 3 + test/simulation/112-port | 2 + test/simulation/113-leapsecond | 3 + test/simulation/115-cmdmontime | 3 +- test/simulation/119-smoothtime | 3 + test/simulation/121-orphan | 2 + test/simulation/124-tai | 3 + test/simulation/128-nocontrol | 2 + test/simulation/133-hwtimestamp | 35 +++-- test/simulation/134-log | 3 + test/simulation/test.common | 8 + test/system/001-minimal | 13 ++ test/system/002-extended | 13 ++ test/system/003-memlock | 15 ++ test/system/004-priority | 15 ++ test/system/005-scfilter | 17 ++ test/system/006-privdrop | 17 ++ test/system/007-cmdmon | 69 ++++++++ test/system/100-clockupdate | 30 ++++ test/system/101-rtc | 19 +++ test/system/102-hwtimestamp | 28 ++++ test/system/103-refclock | 19 +++ test/system/104-systemdirs | 19 +++ test/system/run | 64 ++++++++ test/system/test.common | 339 ++++++++++++++++++++++++++++++++++++++++ test/unit/ntp_core.c | 16 +- test/unit/ntp_sources.c | 14 +- test/unit/test.c | 8 + test/unit/test.h | 9 ++ version.txt | 2 +- 65 files changed, 1340 insertions(+), 385 deletions(-) create mode 100644 sys_posix.c create mode 100644 sys_posix.h create mode 100755 test/system/001-minimal create mode 100755 test/system/002-extended create mode 100755 test/system/003-memlock create mode 100755 test/system/004-priority create mode 100755 test/system/005-scfilter create mode 100755 test/system/006-privdrop create mode 100755 test/system/007-cmdmon create mode 100755 test/system/100-clockupdate create mode 100755 test/system/101-rtc create mode 100755 test/system/102-hwtimestamp create mode 100755 test/system/103-refclock create mode 100755 test/system/104-systemdirs create mode 100755 test/system/run create mode 100644 test/system/test.common diff --git a/FAQ b/FAQ index 089b3b8..426b134 100644 --- a/FAQ +++ b/FAQ @@ -227,6 +227,12 @@ tens of nanoseconds may be possible. For example: server ntp.local minpoll 0 maxpoll 0 xleave hwtimestamp eth0 +For best stability, the CPU should be running at a constant frequency (i.e. +disabled power saving and performance boosting). Energy-Efficient Ethernet +(EEE) should be disabled in the network. The switches should be configured to +prioritize NTP packets, especially if the network is expected to be heavily +loaded. + If it is acceptable for NTP clients in the network to send requests at an excessive rate, a sub-second polling interval may be specified. A median filter can be enabled in order to update the clock at a reduced rate with more stable @@ -265,6 +271,10 @@ makestep 0.128 -1 maxchange 1000 1 1 maxclockerror 15 +Note that increasing minsamples may cause the offsets in the tracking and +sourcestats reports/logs to be significantly smaller than the actual offsets +and be unsuitable for monitoring. + 2.9. What happened to the commandkey and generatecommandkey directives? They were removed in version 2.2. Authentication is no longer supported in the @@ -538,4 +548,4 @@ needs to be made to work as a service. We have no plans to do this. Anyone is welcome to pick this work up and contribute it back to the project. -Last updated 2018-09-19 16:38:15 CEST +Last updated 2019-05-10 12:22:57 CEST diff --git a/INSTALL b/INSTALL index b4ad72f..98bab69 100644 --- a/INSTALL +++ b/INSTALL @@ -4,6 +4,27 @@ The software is distributed as source code which has to be compiled. The source code is supplied in the form of a gzipped tar file, which unpacks to a subdirectory identifying the name and version of the program. +The following programs and libraries with their development files are needed to +build chrony: + + o C compiler (gcc or clang recommended) + + o GNU Make + + o Nettle, NSS, or LibTomCrypt (optional) + + o Editline (optional) + + o libcap (Linux only, optional) + + o libseccomp (Linux only, optional) + + o timepps.h header (optional) + + o Asciidoctor (for HTML documentation) + + o Bash (for testing) + After unpacking the source code, change directory into it, and type ./configure @@ -171,4 +192,4 @@ tar cvf - . | gzip -9 > chrony.tar.gz to build a package. When untarred within the root directory, this will install the files to the intended final locations. -Last updated 2018-09-19 16:38:15 CEST +Last updated 2019-05-10 12:22:57 CEST diff --git a/Makefile.in b/Makefile.in index 2d3e67d..8e68ef4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -113,10 +113,12 @@ install-docs : quickcheck : chronyd chronyc $(MAKE) -C test/unit check cd test/simulation && ./run + cd test/system && ./run check : chronyd chronyc $(MAKE) -C test/unit check cd test/simulation && ./run -i 20 -m 2 + cd test/system && ./run print-chronyd-objects : @echo $(OBJS) $(EXTRA_OBJS) diff --git a/NEWS b/NEWS index 51a0c22..3413361 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,22 @@ +New in version 3.5 +================== + +Enhancements +------------ +* Add support for more accurate reading of PHC on Linux 5.0 +* Add support for hardware timestamping on interfaces with read-only + timestamping configuration +* Add support for memory locking and real-time priority on FreeBSD, + NetBSD, Solaris +* Update seccomp filter to work on more architectures +* Validate refclock driver options + +Bug fixes +--------- +* Fix bindaddress directive on FreeBSD +* Fix transposition of hardware RX timestamp on Linux 4.13 and later +* Fix building on non-glibc systems + New in version 3.4 ================== diff --git a/README b/README index aad727e..a492446 100644 --- a/README +++ b/README @@ -108,132 +108,57 @@ The following people have provided patches and other major contributions to the program : Lonnie Abelbeck - Patch to add tab-completion to chronyc - Benny Lyne Amorsen - Patch to add minstratum option - Andrew Bishop - Fixes for bugs in logging when in daemon mode - Fixes for compiler warnings - Robustness improvements for drift file - Improve installation (directory checking etc) - Entries in contrib directory - Improvements to 'sources' and 'sourcestats' output from chronyc - Improvements to documentation - Investigation of required dosynctodr behaviour for various Solaris - versions - +Vincent Blut Stephan I. Boettcher - Entries in contrib directory - +Goswin Brederlow +Leigh Brown Erik Bryer - Entries in contrib directory - +Jonathan Cameron Bryan Christianson - Support for macOS - Support for privilege separation - Entries in contrib directory - Juliusz Chroboczek - Patch to fix install rule in Makefile if chronyd file is in use - Christian Ehrhardt - Patch to generate a warning message when CAP_SYS_TIME is missing - Paul Elliott - Entries in contrib directory - +Stefan R. Filipek Mike Fleetwood - Fixes for compiler warnings - Alexander Gretencord - Changes to installation directory system to make it easier for - package builders - Andrew Griffiths - Patch to add support for seccomp filter - Walter Haidinger - Access to a Linux installation where v1.12 wouldn't compile - Disc space for an independent backup of the sources - Juergen Hannken-Illjes - Port to NetBSD - John Hasler - Project and website at tuxfamily.org - Changes to support 64 bit machines (i.e. those where - sizeof(unsigned long) > 4) - Bug fix to initstepslew directive - Fix to remove potential buffer overrun errors - Memory locking and real-time scheduler support - Fix fault where chronyd enters an endless loop - Tjalling Hattink - Fix scheduler to allow stepping clock from timeout handler - Patch to take leap second in PPS refclock from locked source - Patch to make reading of RTC for initial trim more reliable - Liam Hatton - Advice on configuring for Linux on PPC - Jachym Holecek - Patch to make Linux real time clock work with devfs - HÃ¥kan Johansson - Patch to avoid large values in sources and sourcestats output - Jim Knoble - Fixes for compiler warnings - Antti Jrvinen - Advice on configuring for BSD/386 - +Eric Lammerts +Stefan Lucke +Victor Lum +Kevin Lyda +Paul Menzel +Vladimir Michl Victor Moroz - Patch to support Linux with HZ!=100 - Kalle Olavi Niemitalo - Patch to add acquisitionport directive - Frank Otto - Handling arbitrary HZ values - Denny Page - Advice on support for hardware timestamping - Chris Perl - Patches to improve support for refclocks keeping time in TAI - Gautier PHILIPPON - Patch to add refresh command to chronyc - Andreas Piesk - Patch to make chronyc use the readline library if available - Andreas Steinmetz - Patch to make stratum of refclocks configurable - +NAKAMURA Takumi Timo Teras - Patch to reply correctly on multihomed hosts - Bill Unruh - Advice on statistics - Stephen Wadeley - Improvements to man pages - +Bernhard Weiss Wolfgang Weisselberg - Entries in contrib directory - +Bernhard M. Wiedemann +Joachim Wiedorn Ralf Wildenhues - Many robustness and security improvements - -Ulrich Windl for the - Information about the Linux 2.2 kernel functionality compared to 2.0 - +Ulrich Windl Doug Woodward - Advice on configuring for Solaris 2.8 on x86 +Thomas Zajic Many other people have contributed bug reports and suggestions. We are sorry we cannot identify all of you individually. diff --git a/client.c b/client.c index 029860c..8736504 100644 --- a/client.c +++ b/client.c @@ -3159,7 +3159,7 @@ static void display_gpl(void) { printf("chrony version %s\n" - "Copyright (C) 1997-2003, 2007, 2009-2018 Richard P. Curnow and others\n" + "Copyright (C) 1997-2003, 2007, 2009-2019 Richard P. Curnow and others\n" "chrony comes with ABSOLUTELY NO WARRANTY. This is free software, and\n" "you are welcome to redistribute it under certain conditions. See the\n" "GNU General Public License version 2 for details.\n\n", diff --git a/configure b/configure index 486b0bc..323f574 100755 --- a/configure +++ b/configure @@ -6,6 +6,7 @@ # Copyright (C) Richard P. Curnow 1997-2003 # Copyright (C) Bryan Christianson 2016 # Copyright (C) Miroslav Lichvar 2009, 2012-2018 +# Copyright (C) Stefan R. Filipek 2019 # # ======================================================================= @@ -227,6 +228,7 @@ feat_timestamping=1 try_timestamping=0 feat_ntp_signd=0 ntp_era_split="" +use_pthread=0 default_user="root" default_hwclockfile="" default_pidfile="/var/run/chrony/chronyd.pid" @@ -395,7 +397,7 @@ SYSTEM=${OPERATINGSYSTEM}-${MACHINE} case $OPERATINGSYSTEM in Linux) - EXTRA_OBJECTS="sys_generic.o sys_linux.o sys_timex.o" + EXTRA_OBJECTS="sys_generic.o sys_linux.o sys_timex.o sys_posix.o" [ $try_libcap != "0" ] && try_libcap=1 try_rtc=1 [ $try_seccomp != "0" ] && try_seccomp=1 @@ -410,7 +412,9 @@ case $OPERATINGSYSTEM in # recvmmsg() seems to be broken on FreeBSD 11.0 and it's just # a wrapper around recvmsg() try_recvmmsg=0 - EXTRA_OBJECTS="sys_generic.o sys_netbsd.o sys_timex.o" + EXTRA_OBJECTS="sys_generic.o sys_netbsd.o sys_timex.o sys_posix.o" + try_setsched=1 + try_lockmem=1 add_def FREEBSD if [ $feat_droproot = "1" ]; then add_def FEAT_PRIVDROP @@ -419,8 +423,10 @@ case $OPERATINGSYSTEM in echo "Configuring for $SYSTEM" ;; NetBSD) - EXTRA_OBJECTS="sys_generic.o sys_netbsd.o sys_timex.o" + EXTRA_OBJECTS="sys_generic.o sys_netbsd.o sys_timex.o sys_posix.o" try_clockctl=1 + try_setsched=1 + try_lockmem=1 add_def NETBSD echo "Configuring for $SYSTEM" ;; @@ -445,9 +451,11 @@ case $OPERATINGSYSTEM in echo "Configuring for macOS (" $SYSTEM "macOS version" $VERSION ")" ;; SunOS) - EXTRA_OBJECTS="sys_generic.o sys_solaris.o sys_timex.o" + EXTRA_OBJECTS="sys_generic.o sys_solaris.o sys_timex.o sys_posix.o" EXTRA_LIBS="-lsocket -lnsl -lresolv" EXTRA_CLI_LIBS="-lsocket -lnsl -lresolv" + try_setsched=1 + try_lockmem=1 add_def SOLARIS # These are needed to have msg_control in struct msghdr add_def __EXTENSIONS__ @@ -652,7 +660,7 @@ then add_def FEAT_ASYNCDNS add_def USE_PTHREAD_ASYNCDNS EXTRA_OBJECTS="$EXTRA_OBJECTS nameserv_async.o" - MYCFLAGS="$MYCFLAGS -pthread" + use_pthread=1 fi if test_code 'arc4random_buf()' 'stdlib.h' '' '' 'arc4random_buf(NULL, 0);'; then @@ -786,25 +794,33 @@ fi if [ $try_setsched = "1" ] && \ test_code \ - 'sched_setscheduler()' \ - 'sched.h' '' '' ' + 'pthread_setschedparam()' \ + 'pthread.h sched.h' '-pthread' '' ' struct sched_param sched; sched_get_priority_max(SCHED_FIFO); - sched_setscheduler(0, SCHED_FIFO, &sched);' + pthread_setschedparam(pthread_self(), SCHED_FIFO, &sched);' then - add_def HAVE_SCHED_SETSCHEDULER + add_def HAVE_PTHREAD_SETSCHEDPARAM + use_pthread=1 fi if [ $try_lockmem = "1" ] && \ test_code \ 'mlockall()' \ - 'sys/mman.h sys/resource.h' '' '' ' - struct rlimit rlim; - setrlimit(RLIMIT_MEMLOCK, &rlim); + 'sys/mman.h' '' '' ' mlockall(MCL_CURRENT|MCL_FUTURE);' then add_def HAVE_MLOCKALL fi +if [ $try_lockmem = "1" ] && \ + test_code \ + 'setrlimit(RLIMIT_MEMLOCK, ...)' \ + 'sys/resource.h' '' '' ' + struct rlimit rlim; + setrlimit(RLIMIT_MEMLOCK, &rlim);' +then + add_def HAVE_SETRLIMIT_MEMLOCK +fi if [ $feat_forcednsretry = "1" ] then @@ -896,6 +912,10 @@ if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_tomcrypt = "1" ] fi fi +if [ $use_pthread = "1" ]; then + MYCFLAGS="$MYCFLAGS -pthread" +fi + SYSCONFDIR=/etc if [ "x$SETSYSCONFDIR" != "x" ]; then SYSCONFDIR=$SETSYSCONFDIR diff --git a/doc/chrony.conf.adoc b/doc/chrony.conf.adoc index 4b1239f..e1fbef3 100644 --- a/doc/chrony.conf.adoc +++ b/doc/chrony.conf.adoc @@ -374,12 +374,12 @@ for *initstepslew* to finish before exiting. This is useful to prevent programs started in the boot sequence after *chronyd* from reading the clock before it has been stepped. -[[refclock]]*refclock* _driver_ _parameter_[:__option__,...] [_option_]...:: +[[refclock]]*refclock* _driver_ _parameter_[:__option__]... [_option_]...:: The *refclock* directive specifies a hardware reference clock to be used as a time source. It has two mandatory parameters, a driver name and a driver-specific parameter. The two parameters are followed by zero or more refclock options. Some drivers have special options, which can be appended to -the driver-specific parameter (separated by the *:* and *,* characters). +the driver-specific parameter using the *:* character. + There are four drivers included in *chronyd*: + @@ -476,7 +476,7 @@ Examples: ---- refclock PHC /dev/ptp0 poll 0 dpoll -2 offset -37 refclock PHC /dev/ptp1:nocrossts poll 3 pps -refclock PHC /dev/ptp2:extpps,pin=1 width 0.2 poll 2 +refclock PHC /dev/ptp2:extpps:pin=1 width 0.2 poll 2 ---- + :: @@ -681,6 +681,8 @@ The *combinelimit* directive limits which sources are included in the combining algorithm. Their synchronisation distance has to be shorter than the distance of the selected source multiplied by the value of the limit. Also, their measured frequencies have to be close to the frequency of the selected source. +If the selected source was specified with the *prefer* option, it can be +combined only with other sources specified with this option. + By default, the limit is 3. Setting the limit to 0 effectively disables the source combining algorithm and only the selected source will be used to control @@ -1601,8 +1603,8 @@ If the *rtconutc* directive appears, it means the RTC is required to keep UTC. The directive takes no arguments. It is equivalent to specifying the *-u* switch to the Linux *hwclock* program. + -Note that this setting is overridden when the <> -directive is specified. +Note that this setting is overridden by the <> file +and is not relevant for the <> directive. [[rtcsync]]*rtcsync*:: The *rtcsync* directive enables a mode where the system time is periodically @@ -2063,11 +2065,11 @@ file when the <> command is issued by *chronyc*). [[lock_all]]*lock_all*:: The *lock_all* directive will lock chronyd into RAM so that it will never be -paged out. This mode is only supported on Linux. This directive uses the Linux -*mlockall()* system call to prevent *chronyd* from ever being swapped out. This -should result in lower and more consistent latency. It should not have -significant impact on performance as *chronyd's* memory usage is modest. The -*mlockall(2)* man page has more details. +paged out. This mode is supported on Linux, FreeBSD, NetBSD, and Solaris. This +directive uses the POSIX *mlockall()* system call to prevent *chronyd* from +ever being swapped out. This should result in lower and more consistent +latency. It should not have significant impact on performance as *chronyd's* +memory usage is modest. The *mlockall(2)* man page has more details. [[pidfile]]*pidfile* _file_:: Unless *chronyd* is started with the *-Q* option, it writes its process ID @@ -2081,26 +2083,26 @@ pidfile /run/chronyd.pid ---- [[sched_priority]]*sched_priority* _priority_:: -On Linux, the *sched_priority* directive will select the SCHED_FIFO real-time -scheduler at the specified priority (which must be between 0 and 100). On -macOS, this option must have either a value of 0 (the default) to disable the -thread time constraint policy or 1 for the policy to be enabled. Other systems -do not support this option. -+ -On Linux, this directive uses the *sched_setscheduler()* system call to -instruct the kernel to use the SCHED_FIFO first-in, first-out real-time -scheduling policy for *chronyd* with the specified priority. This means that -whenever *chronyd* is ready to run it will run, interrupting whatever else is -running unless it is a higher priority real-time process. This should not -impact performance as *chronyd* resource requirements are modest, but it should -result in lower and more consistent latency since *chronyd* will not need to -wait for the scheduler to get around to running it. You should not use this -unless you really need it. The *sched_setscheduler(2)* man page has more -details. +On Linux, FreeBSD, NetBSD, and Solaris, the *sched_priority* directive will +select the SCHED_FIFO real-time scheduler at the specified priority (which must +be between 0 and 100). On macOS, this option must have either a value of 0 (the +default) to disable the thread time constraint policy or 1 for the policy to be +enabled. ++ +On systems other than macOS, this directive uses the *pthread_setschedparam()* +system call to instruct the kernel to use the SCHED_FIFO first-in, first-out +real-time scheduling policy for *chronyd* with the specified priority. This +means that whenever *chronyd* is ready to run it will run, interrupting +whatever else is running unless it is a higher priority real-time process. This +should not impact performance as *chronyd* resource requirements are modest, +but it should result in lower and more consistent latency since *chronyd* will +not need to wait for the scheduler to get around to running it. You should not +use this unless you really need it. The *pthread_setschedparam(3)* man page has +more details. + On macOS, this directive uses the *thread_policy_set()* kernel call to -specify real-time scheduling. As noted for Linux, you should not use this -directive unless you really need it. +specify real-time scheduling. As noted above, you should not use this directive +unless you really need it. [[user]]*user* _user_:: The *user* directive sets the name of the system user to which *chronyd* will diff --git a/doc/chrony.conf.man.in b/doc/chrony.conf.man.in index d50e825..46dbbd6 100644 --- a/doc/chrony.conf.man.in +++ b/doc/chrony.conf.man.in @@ -2,12 +2,12 @@ .\" Title: chrony.conf .\" Author: [see the "AUTHORS" section] .\" Generator: Asciidoctor 1.5.6.1 -.\" Date: 2018-09-19 +.\" Date: 2019-05-10 .\" Manual: Configuration Files .\" Source: chrony @CHRONY_VERSION@ .\" Language: English .\" -.TH "CHRONY.CONF" "5" "2018-09-19" "chrony @CHRONY_VERSION@" "Configuration Files" +.TH "CHRONY.CONF" "5" "2019-05-10" "chrony @CHRONY_VERSION@" "Configuration Files" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 @@ -469,13 +469,13 @@ started in the boot sequence after \fBchronyd\fP from reading the clock before i has been stepped. .RE .sp -\fBrefclock\fP \fIdriver\fP \fIparameter\fP[:\fIoption\fP,...] [\fIoption\fP]... +\fBrefclock\fP \fIdriver\fP \fIparameter\fP[:\fIoption\fP]... [\fIoption\fP]... .RS 4 The \fBrefclock\fP directive specifies a hardware reference clock to be used as a time source. It has two mandatory parameters, a driver name and a driver\-specific parameter. The two parameters are followed by zero or more refclock options. Some drivers have special options, which can be appended to -the driver\-specific parameter (separated by the \fB:\fP and \fB,\fP characters). +the driver\-specific parameter using the \fB:\fP character. .sp There are four drivers included in \fBchronyd\fP: .sp @@ -626,7 +626,7 @@ Examples: .nf refclock PHC /dev/ptp0 poll 0 dpoll \-2 offset \-37 refclock PHC /dev/ptp1:nocrossts poll 3 pps -refclock PHC /dev/ptp2:extpps,pin=1 width 0.2 poll 2 +refclock PHC /dev/ptp2:extpps:pin=1 width 0.2 poll 2 .fi .if n \{\ .RE @@ -924,6 +924,8 @@ The \fBcombinelimit\fP directive limits which sources are included in the combin algorithm. Their synchronisation distance has to be shorter than the distance of the selected source multiplied by the value of the limit. Also, their measured frequencies have to be close to the frequency of the selected source. +If the selected source was specified with the \fBprefer\fP option, it can be +combined only with other sources specified with this option. .sp By default, the limit is 3. Setting the limit to 0 effectively disables the source combining algorithm and only the selected source will be used to control @@ -2159,8 +2161,8 @@ If the \fBrtconutc\fP directive appears, it means the RTC is required to keep UT The directive takes no arguments. It is equivalent to specifying the \fB\-u\fP switch to the Linux \fBhwclock\fP program. .sp -Note that this setting is overridden when the \fBhwclockfile\fP -directive is specified. +Note that this setting is overridden by the \fBhwclockfile\fP file +and is not relevant for the \fBrtcsync\fP directive. .RE .sp \fBrtcsync\fP @@ -3461,11 +3463,11 @@ file when the \fBrekey\fP command is issued by \fBchronyc\fP). \fBlock_all\fP .RS 4 The \fBlock_all\fP directive will lock chronyd into RAM so that it will never be -paged out. This mode is only supported on Linux. This directive uses the Linux -\fBmlockall()\fP system call to prevent \fBchronyd\fP from ever being swapped out. This -should result in lower and more consistent latency. It should not have -significant impact on performance as \fBchronyd\(cqs\fP memory usage is modest. The -\fBmlockall(2)\fP man page has more details. +paged out. This mode is supported on Linux, FreeBSD, NetBSD, and Solaris. This +directive uses the POSIX \fBmlockall()\fP system call to prevent \fBchronyd\fP from +ever being swapped out. This should result in lower and more consistent +latency. It should not have significant impact on performance as \fBchronyd\(cqs\fP +memory usage is modest. The \fBmlockall(2)\fP man page has more details. .RE .sp \fBpidfile\fP \fIfile\fP @@ -3489,26 +3491,26 @@ pidfile /run/chronyd.pid .sp \fBsched_priority\fP \fIpriority\fP .RS 4 -On Linux, the \fBsched_priority\fP directive will select the SCHED_FIFO real\-time -scheduler at the specified priority (which must be between 0 and 100). On -macOS, this option must have either a value of 0 (the default) to disable the -thread time constraint policy or 1 for the policy to be enabled. Other systems -do not support this option. -.sp -On Linux, this directive uses the \fBsched_setscheduler()\fP system call to -instruct the kernel to use the SCHED_FIFO first\-in, first\-out real\-time -scheduling policy for \fBchronyd\fP with the specified priority. This means that -whenever \fBchronyd\fP is ready to run it will run, interrupting whatever else is -running unless it is a higher priority real\-time process. This should not -impact performance as \fBchronyd\fP resource requirements are modest, but it should -result in lower and more consistent latency since \fBchronyd\fP will not need to -wait for the scheduler to get around to running it. You should not use this -unless you really need it. The \fBsched_setscheduler(2)\fP man page has more -details. +On Linux, FreeBSD, NetBSD, and Solaris, the \fBsched_priority\fP directive will +select the SCHED_FIFO real\-time scheduler at the specified priority (which must +be between 0 and 100). On macOS, this option must have either a value of 0 (the +default) to disable the thread time constraint policy or 1 for the policy to be +enabled. +.sp +On systems other than macOS, this directive uses the \fBpthread_setschedparam()\fP +system call to instruct the kernel to use the SCHED_FIFO first\-in, first\-out +real\-time scheduling policy for \fBchronyd\fP with the specified priority. This +means that whenever \fBchronyd\fP is ready to run it will run, interrupting +whatever else is running unless it is a higher priority real\-time process. This +should not impact performance as \fBchronyd\fP resource requirements are modest, +but it should result in lower and more consistent latency since \fBchronyd\fP will +not need to wait for the scheduler to get around to running it. You should not +use this unless you really need it. The \fBpthread_setschedparam(3)\fP man page has +more details. .sp On macOS, this directive uses the \fBthread_policy_set()\fP kernel call to -specify real\-time scheduling. As noted for Linux, you should not use this -directive unless you really need it. +specify real\-time scheduling. As noted above, you should not use this directive +unless you really need it. .RE .sp \fBuser\fP \fIuser\fP diff --git a/doc/chronyc.man.in b/doc/chronyc.man.in index 1a6ec02..6dc9f21 100644 --- a/doc/chronyc.man.in +++ b/doc/chronyc.man.in @@ -2,12 +2,12 @@ .\" Title: chronyc .\" Author: [see the "AUTHORS" section] .\" Generator: Asciidoctor 1.5.6.1 -.\" Date: 2018-09-19 +.\" Date: 2019-05-10 .\" Manual: User manual .\" Source: chrony @CHRONY_VERSION@ .\" Language: English .\" -.TH "CHRONYC" "1" "2018-09-19" "chrony @CHRONY_VERSION@" "User manual" +.TH "CHRONYC" "1" "2019-05-10" "chrony @CHRONY_VERSION@" "User manual" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/doc/chronyd.man.in b/doc/chronyd.man.in index 6342f1b..3e21041 100644 --- a/doc/chronyd.man.in +++ b/doc/chronyd.man.in @@ -2,12 +2,12 @@ .\" Title: chronyd .\" Author: [see the "AUTHORS" section] .\" Generator: Asciidoctor 1.5.6.1 -.\" Date: 2018-09-19 +.\" Date: 2019-05-10 .\" Manual: System Administration .\" Source: chrony @CHRONY_VERSION@ .\" Language: English .\" -.TH "CHRONYD" "8" "2018-09-19" "chrony @CHRONY_VERSION@" "System Administration" +.TH "CHRONYD" "8" "2019-05-10" "chrony @CHRONY_VERSION@" "System Administration" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/doc/faq.adoc b/doc/faq.adoc index b07c550..04cdae8 100644 --- a/doc/faq.adoc +++ b/doc/faq.adoc @@ -217,6 +217,12 @@ server ntp.local minpoll 0 maxpoll 0 xleave hwtimestamp eth0 ---- +For best stability, the CPU should be running at a constant frequency (i.e. +disabled power saving and performance boosting). Energy-Efficient Ethernet +(EEE) should be disabled in the network. The switches should be configured to +prioritize NTP packets, especially if the network is expected to be heavily +loaded. + If it is acceptable for NTP clients in the network to send requests at an excessive rate, a sub-second polling interval may be specified. A median filter can be enabled in order to update the clock at a reduced rate with more stable @@ -261,6 +267,10 @@ maxchange 1000 1 1 maxclockerror 15 ---- +Note that increasing `minsamples` may cause the offsets in the `tracking` and +`sourcestats` reports/logs to be significantly smaller than the actual offsets +and be unsuitable for monitoring. + === What happened to the `commandkey` and `generatecommandkey` directives? They were removed in version 2.2. Authentication is no longer supported in the diff --git a/doc/installation.adoc b/doc/installation.adoc index eea9088..3e0f3c3 100644 --- a/doc/installation.adoc +++ b/doc/installation.adoc @@ -22,6 +22,19 @@ The software is distributed as source code which has to be compiled. The source code is supplied in the form of a gzipped tar file, which unpacks to a subdirectory identifying the name and version of the program. +The following programs and libraries with their development files are needed to +build `chrony`: + +* C compiler (gcc or clang recommended) +* GNU Make +* Nettle, NSS, or LibTomCrypt (optional) +* Editline (optional) +* libcap (Linux only, optional) +* libseccomp (Linux only, optional) +* timepps.h header (optional) +* Asciidoctor (for HTML documentation) +* Bash (for testing) + After unpacking the source code, change directory into it, and type ---- diff --git a/examples/chronyd.service b/examples/chronyd.service index 1777413..289548c 100644 --- a/examples/chronyd.service +++ b/examples/chronyd.service @@ -7,7 +7,7 @@ ConditionCapability=CAP_SYS_TIME [Service] Type=forking -PIDFile=/var/run/chrony/chronyd.pid +PIDFile=/run/chrony/chronyd.pid EnvironmentFile=-/etc/sysconfig/chronyd ExecStart=/usr/sbin/chronyd $OPTIONS PrivateTmp=yes diff --git a/hash_intmd5.c b/hash_intmd5.c index 0b60f9b..49da1cf 100644 --- a/hash_intmd5.c +++ b/hash_intmd5.c @@ -29,6 +29,7 @@ #include "sysincl.h" #include "hash.h" #include "memory.h" +#include "util.h" #include "md5.c" diff --git a/nameserv.c b/nameserv.c index 1cb9608..90a65b1 100644 --- a/nameserv.c +++ b/nameserv.c @@ -30,6 +30,9 @@ #include "sysincl.h" +#include +#include + #include "nameserv.h" #include "util.h" diff --git a/ntp_io.c b/ntp_io.c index 305ba07..ab08372 100644 --- a/ntp_io.c +++ b/ntp_io.c @@ -105,6 +105,9 @@ static int separate_client_sockets; disabled */ static int permanent_server_sockets; +/* Flag indicating the server IPv4 socket is bound to an address */ +static int bound_server_sock_fd4; + /* Flag indicating that we have been initialised */ static int initialised=0; @@ -168,6 +171,9 @@ prepare_socket(int family, int port_number, int client_only) my_addr.in4.sin_port = htons(port_number); my_addr_len = sizeof (my_addr.in4); + if (!client_only) + bound_server_sock_fd4 = my_addr.in4.sin_addr.s_addr != htonl(INADDR_ANY); + break; #ifdef FEAT_IPV6 case AF_INET6: @@ -821,8 +827,8 @@ NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, msg.msg_flags = 0; cmsglen = 0; - if (local_addr->ip_addr.family == IPADDR_INET4) { #ifdef HAVE_IN_PKTINFO + if (local_addr->ip_addr.family == IPADDR_INET4) { struct in_pktinfo *ipi; cmsg = CMSG_FIRSTHDR(&msg); @@ -837,7 +843,11 @@ NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, ipi->ipi_spec_dst.s_addr = htonl(local_addr->ip_addr.addr.in4); if (local_addr->if_index != INVALID_IF_INDEX) ipi->ipi_ifindex = local_addr->if_index; + } #elif defined(IP_SENDSRCADDR) + /* Specify the IPv4 source address only if the socket is not bound */ + if (local_addr->ip_addr.family == IPADDR_INET4 && + local_addr->sock_fd == server_sock_fd4 && !bound_server_sock_fd4) { struct in_addr *addr; cmsg = CMSG_FIRSTHDR(&msg); @@ -850,8 +860,8 @@ NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, addr = (struct in_addr *)CMSG_DATA(cmsg); addr->s_addr = htonl(local_addr->ip_addr.addr.in4); -#endif } +#endif #ifdef HAVE_IN6_PKTINFO if (local_addr->ip_addr.family == IPADDR_INET6) { diff --git a/ntp_io_linux.c b/ntp_io_linux.c index 819792a..4e0c800 100644 --- a/ntp_io_linux.c +++ b/ntp_io_linux.c @@ -2,7 +2,7 @@ chronyd/chronyc - Programs for keeping computer clocks accurate. ********************************************************************** - * Copyright (C) Miroslav Lichvar 2016-2018 + * Copyright (C) Miroslav Lichvar 2016-2019 * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -123,7 +123,7 @@ add_interface(CNF_HwTsInterface *conf_iface) struct ethtool_ts_info ts_info; struct hwtstamp_config ts_config; struct ifreq req; - int sock_fd, if_index, phc_fd, req_hwts_flags; + int sock_fd, if_index, phc_fd, req_hwts_flags, rx_filter; unsigned int i; struct Interface *iface; @@ -177,40 +177,51 @@ add_interface(CNF_HwTsInterface *conf_iface) return 0; } - ts_config.flags = 0; - ts_config.tx_type = HWTSTAMP_TX_ON; - switch (conf_iface->rxfilter) { case CNF_HWTS_RXFILTER_ANY: #ifdef HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_NTP_ALL)) - ts_config.rx_filter = HWTSTAMP_FILTER_NTP_ALL; + rx_filter = HWTSTAMP_FILTER_NTP_ALL; else #endif if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_ALL)) - ts_config.rx_filter = HWTSTAMP_FILTER_ALL; + rx_filter = HWTSTAMP_FILTER_ALL; else - ts_config.rx_filter = HWTSTAMP_FILTER_NONE; + rx_filter = HWTSTAMP_FILTER_NONE; break; case CNF_HWTS_RXFILTER_NONE: - ts_config.rx_filter = HWTSTAMP_FILTER_NONE; + rx_filter = HWTSTAMP_FILTER_NONE; break; #ifdef HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP case CNF_HWTS_RXFILTER_NTP: - ts_config.rx_filter = HWTSTAMP_FILTER_NTP_ALL; + rx_filter = HWTSTAMP_FILTER_NTP_ALL; break; #endif default: - ts_config.rx_filter = HWTSTAMP_FILTER_ALL; + rx_filter = HWTSTAMP_FILTER_ALL; break; } + ts_config.flags = 0; + ts_config.tx_type = HWTSTAMP_TX_ON; + ts_config.rx_filter = rx_filter; req.ifr_data = (char *)&ts_config; if (ioctl(sock_fd, SIOCSHWTSTAMP, &req)) { DEBUG_LOG("ioctl(%s) failed : %s", "SIOCSHWTSTAMP", strerror(errno)); - close(sock_fd); - return 0; + + /* Check the current timestamping configuration in case this interface + allows only reading of the configuration and it was already configured + as requested */ + req.ifr_data = (char *)&ts_config; +#ifdef SIOCGHWTSTAMP + if (ioctl(sock_fd, SIOCGHWTSTAMP, &req) || + ts_config.tx_type != HWTSTAMP_TX_ON || ts_config.rx_filter != rx_filter) +#endif + { + close(sock_fd); + return 0; + } } close(sock_fd); @@ -584,7 +595,11 @@ process_hw_timestamp(struct Interface *iface, struct timespec *hw_ts, if (rx_ntp_length && iface->link_speed) { if (!l2_length) l2_length = (family == IPADDR_INET4 ? iface->l2_udp4_ntp_start : - iface->l2_udp6_ntp_start) + rx_ntp_length + 4; + iface->l2_udp6_ntp_start) + rx_ntp_length; + + /* Include the frame check sequence (FCS) */ + l2_length += 4; + rx_correction = l2_length / (1.0e6 / 8 * iface->link_speed); UTI_AddDoubleToTimespec(hw_ts, rx_correction, hw_ts); @@ -841,7 +856,12 @@ NIO_Linux_RequestTxTimestamp(struct msghdr *msg, int cmsglen, int sock_fd) /* Add control message that will enable TX timestamping for this message. Don't use CMSG_NXTHDR as the one in glibc is buggy for creating new control messages. */ - cmsg = (struct cmsghdr *)((char *)CMSG_FIRSTHDR(msg) + cmsglen); + + cmsg = CMSG_FIRSTHDR(msg); + if (!cmsg || cmsglen + CMSG_SPACE(sizeof (ts_tx_flags)) > msg->msg_controllen) + return cmsglen; + + cmsg = (struct cmsghdr *)((char *)cmsg + cmsglen); memset(cmsg, 0, CMSG_SPACE(sizeof (ts_tx_flags))); cmsglen += CMSG_SPACE(sizeof (ts_tx_flags)); diff --git a/refclock.c b/refclock.c index 8f234f6..561df45 100644 --- a/refclock.c +++ b/refclock.c @@ -2,7 +2,7 @@ chronyd/chronyc - Programs for keeping computer clocks accurate. ********************************************************************** - * Copyright (C) Miroslav Lichvar 2009-2011, 2013-2014, 2016-2018 + * Copyright (C) Miroslav Lichvar 2009-2011, 2013-2014, 2016-2019 * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -325,25 +325,57 @@ RCL_GetDriverParameter(RCL_Instance instance) return instance->driver_parameter; } -char * -RCL_GetDriverOption(RCL_Instance instance, char *name) +static char * +get_next_driver_option(RCL_Instance instance, char *option) { - char *s, *e; - int n; + if (option == NULL) + option = instance->driver_parameter; - s = instance->driver_parameter; - e = s + instance->driver_parameter_length; - n = strlen(name); + option += strlen(option) + 1; - while (1) { - s += strlen(s) + 1; - if (s >= e) - break; - if (!strncmp(name, s, n)) { - if (s[n] == '=') - return s + n + 1; - if (s[n] == '\0') - return s + n; + if (option >= instance->driver_parameter + instance->driver_parameter_length) + return NULL; + + return option; +} + +void +RCL_CheckDriverOptions(RCL_Instance instance, const char **options) +{ + char *option; + int i, len; + + for (option = get_next_driver_option(instance, NULL); + option; + option = get_next_driver_option(instance, option)) { + for (i = 0; options && options[i]; i++) { + len = strlen(options[i]); + if (!strncmp(options[i], option, len) && + (option[len] == '=' || option[len] == '\0')) + break; + } + + if (!options || !options[i]) + LOG_FATAL("Invalid refclock driver option %s", option); + } +} + +char * +RCL_GetDriverOption(RCL_Instance instance, char *name) +{ + char *option; + int len; + + len = strlen(name); + + for (option = get_next_driver_option(instance, NULL); + option; + option = get_next_driver_option(instance, option)) { + if (!strncmp(name, option, len)) { + if (option[len] == '=') + return option + len + 1; + if (option[len] == '\0') + return option + len; } } diff --git a/refclock.h b/refclock.h index 724f620..69a0152 100644 --- a/refclock.h +++ b/refclock.h @@ -72,6 +72,7 @@ extern void RCL_ReportSource(RPT_SourceReport *report, struct timespec *now); extern void RCL_SetDriverData(RCL_Instance instance, void *data); extern void *RCL_GetDriverData(RCL_Instance instance); extern char *RCL_GetDriverParameter(RCL_Instance instance); +extern void RCL_CheckDriverOptions(RCL_Instance instance, const char **options); extern char *RCL_GetDriverOption(RCL_Instance instance, char *name); extern int RCL_AddSample(RCL_Instance instance, struct timespec *sample_time, double offset, int leap); extern int RCL_AddPulse(RCL_Instance instance, struct timespec *pulse_time, double second); diff --git a/refclock_phc.c b/refclock_phc.c index 03450db..a000fe4 100644 --- a/refclock_phc.c +++ b/refclock_phc.c @@ -56,10 +56,13 @@ static void read_ext_pulse(int sockfd, int event, void *anything); static int phc_initialise(RCL_Instance instance) { + const char *options[] = {"nocrossts", "extpps", "pin", "channel", "clear", NULL}; struct phc_instance *phc; int phc_fd, rising_edge; char *path, *s; + RCL_CheckDriverOptions(instance, options); + path = RCL_GetDriverParameter(instance); phc_fd = SYS_Linux_OpenPHC(path, 0); diff --git a/refclock_pps.c b/refclock_pps.c index 85ff9e9..b9e8009 100644 --- a/refclock_pps.c +++ b/refclock_pps.c @@ -48,12 +48,15 @@ struct pps_instance { }; static int pps_initialise(RCL_Instance instance) { + const char *options[] = {"clear", NULL}; pps_handle_t handle; pps_params_t params; struct pps_instance *pps; int fd, edge_clear, mode; char *path; + RCL_CheckDriverOptions(instance, options); + path = RCL_GetDriverParameter(instance); edge_clear = RCL_GetDriverOption(instance, "clear") ? 1 : 0; diff --git a/refclock_shm.c b/refclock_shm.c index e8f6256..ed68095 100644 --- a/refclock_shm.c +++ b/refclock_shm.c @@ -59,10 +59,13 @@ struct shmTime { }; static int shm_initialise(RCL_Instance instance) { + const char *options[] = {"perm", NULL}; int id, param, perm; char *s; struct shmTime *shm; + RCL_CheckDriverOptions(instance, options); + param = atoi(RCL_GetDriverParameter(instance)); s = RCL_GetDriverOption(instance, "perm"); perm = s ? strtol(s, NULL, 8) & 0777 : 0600; diff --git a/refclock_sock.c b/refclock_sock.c index 176310c..492ee32 100644 --- a/refclock_sock.c +++ b/refclock_sock.c @@ -101,6 +101,8 @@ static int sock_initialise(RCL_Instance instance) int sockfd; char *path; + RCL_CheckDriverOptions(instance, NULL); + path = RCL_GetDriverParameter(instance); s.sun_family = AF_UNIX; diff --git a/sys.c b/sys.c index 4d68b37..f3797c4 100644 --- a/sys.c +++ b/sys.c @@ -35,10 +35,13 @@ #if defined(LINUX) #include "sys_linux.h" +#include "sys_posix.h" #elif defined(SOLARIS) #include "sys_solaris.h" +#include "sys_posix.h" #elif defined(NETBSD) || defined(FREEBSD) #include "sys_netbsd.h" +#include "sys_posix.h" #elif defined(MACOSX) #include "sys_macosx.h" #endif @@ -124,10 +127,10 @@ void SYS_EnableSystemCallFilter(int level) void SYS_SetScheduler(int SchedPriority) { -#if defined(LINUX) && defined(HAVE_SCHED_SETSCHEDULER) - SYS_Linux_SetScheduler(SchedPriority); -#elif defined(MACOSX) +#if defined(MACOSX) SYS_MacOSX_SetScheduler(SchedPriority); +#elif defined(HAVE_PTHREAD_SETSCHEDPARAM) + SYS_Posix_SetScheduler(SchedPriority); #else LOG_FATAL("scheduler priority setting not supported"); #endif @@ -137,8 +140,8 @@ void SYS_SetScheduler(int SchedPriority) void SYS_LockMemory(void) { -#if defined(LINUX) && defined(HAVE_MLOCKALL) - SYS_Linux_MemLockAll(1); +#if defined(HAVE_MLOCKALL) + SYS_Posix_MemLockAll(); #else LOG_FATAL("memory locking not supported"); #endif diff --git a/sys_linux.c b/sys_linux.c index 00bc239..898dc7a 100644 --- a/sys_linux.c +++ b/sys_linux.c @@ -33,15 +33,6 @@ #include -#if defined(HAVE_SCHED_SETSCHEDULER) -# include -#endif - -#if defined(HAVE_MLOCKALL) -# include -#include -#endif - #if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING) #include #endif @@ -493,25 +484,27 @@ SYS_Linux_EnableSystemCallFilter(int level) SCMP_SYS(clone), SCMP_SYS(exit), SCMP_SYS(exit_group), SCMP_SYS(getpid), SCMP_SYS(getrlimit), SCMP_SYS(rt_sigaction), SCMP_SYS(rt_sigreturn), SCMP_SYS(rt_sigprocmask), SCMP_SYS(set_tid_address), SCMP_SYS(sigreturn), - SCMP_SYS(wait4), + SCMP_SYS(wait4), SCMP_SYS(waitpid), /* Memory */ SCMP_SYS(brk), SCMP_SYS(madvise), SCMP_SYS(mmap), SCMP_SYS(mmap2), SCMP_SYS(mprotect), SCMP_SYS(mremap), SCMP_SYS(munmap), SCMP_SYS(shmdt), /* Filesystem */ - SCMP_SYS(access), SCMP_SYS(chmod), SCMP_SYS(chown), SCMP_SYS(chown32), + SCMP_SYS(_llseek), SCMP_SYS(access), SCMP_SYS(chmod), SCMP_SYS(chown), + SCMP_SYS(chown32), SCMP_SYS(faccessat), SCMP_SYS(fchmodat), SCMP_SYS(fchownat), SCMP_SYS(fstat), SCMP_SYS(fstat64), SCMP_SYS(getdents), SCMP_SYS(getdents64), - SCMP_SYS(lseek), SCMP_SYS(rename), SCMP_SYS(stat), SCMP_SYS(stat64), - SCMP_SYS(statfs), SCMP_SYS(statfs64), SCMP_SYS(unlink), + SCMP_SYS(lseek), SCMP_SYS(newfstatat), SCMP_SYS(rename), SCMP_SYS(renameat), + SCMP_SYS(stat), SCMP_SYS(stat64), SCMP_SYS(statfs), SCMP_SYS(statfs64), + SCMP_SYS(unlink), SCMP_SYS(unlinkat), /* Socket */ SCMP_SYS(bind), SCMP_SYS(connect), SCMP_SYS(getsockname), SCMP_SYS(getsockopt), - SCMP_SYS(recvfrom), SCMP_SYS(recvmmsg), SCMP_SYS(recvmsg), - SCMP_SYS(sendmmsg), SCMP_SYS(sendmsg), SCMP_SYS(sendto), + SCMP_SYS(recv), SCMP_SYS(recvfrom), SCMP_SYS(recvmmsg), SCMP_SYS(recvmsg), + SCMP_SYS(send), SCMP_SYS(sendmmsg), SCMP_SYS(sendmsg), SCMP_SYS(sendto), /* TODO: check socketcall arguments */ SCMP_SYS(socketcall), /* General I/O */ SCMP_SYS(_newselect), SCMP_SYS(close), SCMP_SYS(open), SCMP_SYS(openat), SCMP_SYS(pipe), - SCMP_SYS(poll), SCMP_SYS(read), SCMP_SYS(futex), SCMP_SYS(select), - SCMP_SYS(set_robust_list), SCMP_SYS(write), + SCMP_SYS(pipe2), SCMP_SYS(poll), SCMP_SYS(ppoll), SCMP_SYS(pselect6), SCMP_SYS(read), + SCMP_SYS(futex), SCMP_SYS(select), SCMP_SYS(set_robust_list), SCMP_SYS(write), /* Miscellaneous */ SCMP_SYS(getrandom), SCMP_SYS(sysinfo), SCMP_SYS(uname), }; @@ -544,6 +537,9 @@ SYS_Linux_EnableSystemCallFilter(int level) #ifdef PTP_PIN_SETFUNC PTP_PIN_SETFUNC, #endif +#ifdef PTP_SYS_OFFSET_EXTENDED + PTP_SYS_OFFSET_EXTENDED, +#endif #ifdef PTP_SYS_OFFSET_PRECISE PTP_SYS_OFFSET_PRECISE, #endif @@ -627,63 +623,6 @@ add_failed: /* ================================================== */ -#if defined(HAVE_SCHED_SETSCHEDULER) - /* Install SCHED_FIFO real-time scheduler with specified priority */ -void SYS_Linux_SetScheduler(int SchedPriority) -{ - int pmax, pmin; - struct sched_param sched; - - if (SchedPriority < 1 || SchedPriority > 99) { - LOG_FATAL("Bad scheduler priority: %d", SchedPriority); - } else { - sched.sched_priority = SchedPriority; - pmax = sched_get_priority_max(SCHED_FIFO); - pmin = sched_get_priority_min(SCHED_FIFO); - if ( SchedPriority > pmax ) { - sched.sched_priority = pmax; - } - else if ( SchedPriority < pmin ) { - sched.sched_priority = pmin; - } - if ( sched_setscheduler(0, SCHED_FIFO, &sched) == -1 ) { - LOG(LOGS_ERR, "sched_setscheduler() failed"); - } - else { - DEBUG_LOG("Enabled SCHED_FIFO with priority %d", - sched.sched_priority); - } - } -} -#endif /* HAVE_SCHED_SETSCHEDULER */ - -#if defined(HAVE_MLOCKALL) -/* Lock the process into RAM so that it will never be swapped out */ -void SYS_Linux_MemLockAll(int LockAll) -{ - struct rlimit rlim; - if (LockAll == 1 ) { - /* Make sure that we will be able to lock all the memory we need */ - /* even after dropping privileges. This does not actually reaerve any memory */ - rlim.rlim_max = RLIM_INFINITY; - rlim.rlim_cur = RLIM_INFINITY; - if (setrlimit(RLIMIT_MEMLOCK, &rlim) < 0) { - LOG(LOGS_ERR, "setrlimit() failed: not locking into RAM"); - } - else { - if (mlockall(MCL_CURRENT|MCL_FUTURE) < 0) { - LOG(LOGS_ERR, "mlockall() failed"); - } - else { - DEBUG_LOG("Successfully locked into RAM"); - } - } - } -} -#endif /* HAVE_MLOCKALL */ - -/* ================================================== */ - int SYS_Linux_CheckKernelVersion(int req_major, int req_minor) { @@ -701,35 +640,17 @@ SYS_Linux_CheckKernelVersion(int req_major, int req_minor) #define PHC_READINGS 10 static int -get_phc_sample(int phc_fd, double precision, struct timespec *phc_ts, - struct timespec *sys_ts, double *err) +process_phc_readings(struct timespec ts[][3], int n, double precision, + struct timespec *phc_ts, struct timespec *sys_ts, double *err) { - struct ptp_sys_offset sys_off; - struct timespec ts1, ts2, ts3, phc_tss[PHC_READINGS], sys_tss[PHC_READINGS]; - double min_delay = 0.0, delays[PHC_READINGS], phc_sum, sys_sum, sys_prec; - int i, n; + double min_delay = 0.0, delays[PTP_MAX_SAMPLES], phc_sum, sys_sum, sys_prec; + int i, combined; - /* Silence valgrind */ - memset(&sys_off, 0, sizeof (sys_off)); - - sys_off.n_samples = PHC_READINGS; - - if (ioctl(phc_fd, PTP_SYS_OFFSET, &sys_off)) { - DEBUG_LOG("ioctl(%s) failed : %s", "PTP_SYS_OFFSET", strerror(errno)); + if (n > PTP_MAX_SAMPLES) return 0; - } - for (i = 0; i < PHC_READINGS; i++) { - ts1.tv_sec = sys_off.ts[i * 2].sec; - ts1.tv_nsec = sys_off.ts[i * 2].nsec; - ts2.tv_sec = sys_off.ts[i * 2 + 1].sec; - ts2.tv_nsec = sys_off.ts[i * 2 + 1].nsec; - ts3.tv_sec = sys_off.ts[i * 2 + 2].sec; - ts3.tv_nsec = sys_off.ts[i * 2 + 2].nsec; - - sys_tss[i] = ts1; - phc_tss[i] = ts2; - delays[i] = UTI_DiffTimespecsToDouble(&ts3, &ts1); + for (i = 0; i < n; i++) { + delays[i] = UTI_DiffTimespecsToDouble(&ts[i][2], &ts[i][0]); if (delays[i] < 0.0) { /* Step in the middle of a PHC reading? */ @@ -744,23 +665,92 @@ get_phc_sample(int phc_fd, double precision, struct timespec *phc_ts, sys_prec = LCL_GetSysPrecisionAsQuantum(); /* Combine best readings */ - for (i = n = 0, phc_sum = sys_sum = 0.0; i < PHC_READINGS; i++) { + for (i = combined = 0, phc_sum = sys_sum = 0.0; i < n; i++) { if (delays[i] > min_delay + MAX(sys_prec, precision)) continue; - phc_sum += UTI_DiffTimespecsToDouble(&phc_tss[i], &phc_tss[0]); - sys_sum += UTI_DiffTimespecsToDouble(&sys_tss[i], &sys_tss[0]) + delays[i] / 2.0; - n++; + phc_sum += UTI_DiffTimespecsToDouble(&ts[i][1], &ts[0][1]); + sys_sum += UTI_DiffTimespecsToDouble(&ts[i][0], &ts[0][0]) + delays[i] / 2.0; + combined++; } - assert(n); + assert(combined); - UTI_AddDoubleToTimespec(&phc_tss[0], phc_sum / n, phc_ts); - UTI_AddDoubleToTimespec(&sys_tss[0], sys_sum / n, sys_ts); + UTI_AddDoubleToTimespec(&ts[0][1], phc_sum / combined, phc_ts); + UTI_AddDoubleToTimespec(&ts[0][0], sys_sum / combined, sys_ts); *err = MAX(min_delay / 2.0, precision); return 1; } + +/* ================================================== */ + +static int +get_phc_sample(int phc_fd, double precision, struct timespec *phc_ts, + struct timespec *sys_ts, double *err) +{ + struct timespec ts[PHC_READINGS][3]; + struct ptp_sys_offset sys_off; + int i; + + /* Silence valgrind */ + memset(&sys_off, 0, sizeof (sys_off)); + + sys_off.n_samples = PHC_READINGS; + + if (ioctl(phc_fd, PTP_SYS_OFFSET, &sys_off)) { + DEBUG_LOG("ioctl(%s) failed : %s", "PTP_SYS_OFFSET", strerror(errno)); + return 0; + } + + for (i = 0; i < PHC_READINGS; i++) { + ts[i][0].tv_sec = sys_off.ts[i * 2].sec; + ts[i][0].tv_nsec = sys_off.ts[i * 2].nsec; + ts[i][1].tv_sec = sys_off.ts[i * 2 + 1].sec; + ts[i][1].tv_nsec = sys_off.ts[i * 2 + 1].nsec; + ts[i][2].tv_sec = sys_off.ts[i * 2 + 2].sec; + ts[i][2].tv_nsec = sys_off.ts[i * 2 + 2].nsec; + } + + return process_phc_readings(ts, PHC_READINGS, precision, phc_ts, sys_ts, err); +} + +/* ================================================== */ + +static int +get_extended_phc_sample(int phc_fd, double precision, struct timespec *phc_ts, + struct timespec *sys_ts, double *err) +{ +#ifdef PTP_SYS_OFFSET_EXTENDED + struct timespec ts[PHC_READINGS][3]; + struct ptp_sys_offset_extended sys_off; + int i; + + /* Silence valgrind */ + memset(&sys_off, 0, sizeof (sys_off)); + + sys_off.n_samples = PHC_READINGS; + + if (ioctl(phc_fd, PTP_SYS_OFFSET_EXTENDED, &sys_off)) { + DEBUG_LOG("ioctl(%s) failed : %s", "PTP_SYS_OFFSET_EXTENDED", strerror(errno)); + return 0; + } + + for (i = 0; i < PHC_READINGS; i++) { + ts[i][0].tv_sec = sys_off.ts[i][0].sec; + ts[i][0].tv_nsec = sys_off.ts[i][0].nsec; + ts[i][1].tv_sec = sys_off.ts[i][1].sec; + ts[i][1].tv_nsec = sys_off.ts[i][1].nsec; + ts[i][2].tv_sec = sys_off.ts[i][2].sec; + ts[i][2].tv_nsec = sys_off.ts[i][2].nsec; + } + + return process_phc_readings(ts, PHC_READINGS, precision, phc_ts, sys_ts, err); +#else + return 0; +#endif +} + /* ================================================== */ static int @@ -834,6 +824,10 @@ SYS_Linux_GetPHCSample(int fd, int nocrossts, double precision, int *reading_mod get_precise_phc_sample(fd, precision, phc_ts, sys_ts, err)) { *reading_mode = 2; return 1; + } else if ((*reading_mode == 3 || !*reading_mode) && + get_extended_phc_sample(fd, precision, phc_ts, sys_ts, err)) { + *reading_mode = 3; + return 1; } else if ((*reading_mode == 1 || !*reading_mode) && get_phc_sample(fd, precision, phc_ts, sys_ts, err)) { *reading_mode = 1; diff --git a/sys_linux.h b/sys_linux.h index 799ae9a..551a186 100644 --- a/sys_linux.h +++ b/sys_linux.h @@ -35,10 +35,6 @@ extern void SYS_Linux_DropRoot(uid_t uid, gid_t gid, int clock_control); extern void SYS_Linux_EnableSystemCallFilter(int level); -extern void SYS_Linux_MemLockAll(int LockAll); - -extern void SYS_Linux_SetScheduler(int SchedPriority); - extern int SYS_Linux_CheckKernelVersion(int req_major, int req_minor); extern int SYS_Linux_OpenPHC(const char *path, int phc_index); diff --git a/sys_macosx.c b/sys_macosx.c index 00ce302..807d62e 100644 --- a/sys_macosx.c +++ b/sys_macosx.c @@ -49,10 +49,8 @@ #ifdef HAVE_MACOS_SYS_TIMEX #include #include "sys_netbsd.h" -#include "sys_timex.h" static int have_ntp_adjtime = 0; -static int have_bad_adjtime = 0; #endif /* ================================================== */ @@ -453,45 +451,13 @@ legacy_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(); - } + SYS_NetBSD_Initialise(); return; } #endif @@ -505,11 +471,7 @@ SYS_MacOSX_Finalise(void) { #ifdef HAVE_MACOS_SYS_TIMEX if (have_ntp_adjtime) { - if (have_bad_adjtime) { - SYS_Timex_Finalise(); - } else { - SYS_NetBSD_Finalise(); - } + SYS_NetBSD_Finalise(); return; } #endif diff --git a/sys_posix.c b/sys_posix.c new file mode 100644 index 0000000..356e86a --- /dev/null +++ b/sys_posix.c @@ -0,0 +1,109 @@ +/* + chronyd/chronyc - Programs for keeping computer clocks accurate. + + ********************************************************************** + * Copyright (C) Richard P. Curnow 1997-2003 + * Copyright (C) John G. Hasler 2009 + * Copyright (C) Miroslav Lichvar 2009-2012, 2014-2018 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + ********************************************************************** + + ======================================================================= + + This module is for POSIX compliant operating systems. + + */ + +#include "config.h" + +#include "sysincl.h" + +#include + +#if defined(HAVE_PTHREAD_SETSCHEDPARAM) +#include +#include +#endif + +#if defined(HAVE_MLOCKALL) +#include +#endif +#if defined(HAVE_SETRLIMIT_MEMLOCK) +#include +#endif + +#include "sys_posix.h" +#include "conf.h" +#include "local.h" +#include "logging.h" +#include "util.h" + +/* ================================================== */ + +#if defined(HAVE_PTHREAD_SETSCHEDPARAM) +/* Install SCHED_FIFO real-time scheduler with specified priority */ +void +SYS_Posix_SetScheduler(int priority) +{ + struct sched_param sched; + int pmax, pmin; + + if (priority < 1 || priority > 99) + LOG_FATAL("Bad scheduler priority: %d", priority); + + sched.sched_priority = priority; + pmax = sched_get_priority_max(SCHED_FIFO); + pmin = sched_get_priority_min(SCHED_FIFO); + if (priority > pmax) { + sched.sched_priority = pmax; + } else if (priority < pmin) { + sched.sched_priority = pmin; + } + + if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &sched) < 0) { + LOG(LOGS_ERR, "pthread_setschedparam() failed"); + } else { + DEBUG_LOG("Enabled SCHED_FIFO with priority %d", sched.sched_priority); + } +} +#endif /* HAVE_PTHREAD_SETSCHEDPARAM */ + +/* ================================================== */ + +#if defined(HAVE_MLOCKALL) +/* Lock the process into RAM so that it will never be swapped out */ +void +SYS_Posix_MemLockAll(void) +{ +#if defined(HAVE_SETRLIMIT_MEMLOCK) + struct rlimit rlim; + + /* Ensure we can reserve as much as we need */ + rlim.rlim_max = RLIM_INFINITY; + rlim.rlim_cur = RLIM_INFINITY; + if (setrlimit(RLIMIT_MEMLOCK, &rlim) < 0) { + LOG(LOGS_ERR, "setrlimit() failed"); + return; + } +#endif + + if (mlockall(MCL_CURRENT|MCL_FUTURE) < 0) { + LOG(LOGS_ERR, "mlockall() failed"); + } else { + DEBUG_LOG("Successfully locked into RAM"); + } +} +#endif /* HAVE_MLOCKALL */ diff --git a/sys_posix.h b/sys_posix.h new file mode 100644 index 0000000..bb34b80 --- /dev/null +++ b/sys_posix.h @@ -0,0 +1,36 @@ +/* + chronyd/chronyc - Programs for keeping computer clocks accurate. + + ********************************************************************** + * Copyright (C) Richard P. Curnow 1997-2003 + * Copyright (C) John G. Hasler 2009 + * Copyright (C) Miroslav Lichvar 2009-2012, 2014-2018 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + ********************************************************************** + + ======================================================================= + + The header file for shared Posix functionality + */ + +#ifndef GOT_SYS_POSIX_H +#define GOT_SYS_POSIX_H + +extern void SYS_Posix_MemLockAll(void); + +extern void SYS_Posix_SetScheduler(int priority); + +#endif /* GOT_SYS_POSIX_H */ diff --git a/sysincl.h b/sysincl.h index 54431de..296c5e6 100644 --- a/sysincl.h +++ b/sysincl.h @@ -38,10 +38,8 @@ #include #include #include -#include #include #include -#include #include #include #include diff --git a/test/simulation/008-ntpera b/test/simulation/008-ntpera index 3c63419..360a97d 100755 --- a/test/simulation/008-ntpera +++ b/test/simulation/008-ntpera @@ -16,7 +16,7 @@ check_packet_interval || test_fail check_sync || test_fail # The following tests need 64-bit time_t -grep -q 'HAVE_LONG_TIME_T 1' ../../config.h || test_skip +check_config_h 'HAVE_LONG_TIME_T 1' || test_skip for year in 1990 2090; do export CLKNETSIM_START_DATE=$(date -d "Jan 1 00:00:00 UTC $year" +'%s') diff --git a/test/simulation/105-ntpauth b/test/simulation/105-ntpauth index 4c77f10..9ec4fba 100755 --- a/test/simulation/105-ntpauth +++ b/test/simulation/105-ntpauth @@ -23,7 +23,7 @@ EOF keys=4 -if grep -q 'FEAT_SECHASH 1' ../../config.h; then +if check_config_h 'FEAT_SECHASH 1'; then hashes="MD5 SHA1 SHA256 SHA384 SHA512" else hashes="MD5" diff --git a/test/simulation/106-refclock b/test/simulation/106-refclock index 5c5794c..c4cec20 100755 --- a/test/simulation/106-refclock +++ b/test/simulation/106-refclock @@ -3,6 +3,10 @@ . ./test.common test_start "SHM refclock" +check_config_h 'FEAT_REFCLOCK 1' || test_skip +check_config_h 'FEAT_PHC 1' || test_skip +check_config_h 'FEAT_CMDMON 1' || test_skip + servers=0 limit=1000 refclock_jitter=$jitter diff --git a/test/simulation/107-allowdeny b/test/simulation/107-allowdeny index b11db32..3ab83ff 100755 --- a/test/simulation/107-allowdeny +++ b/test/simulation/107-allowdeny @@ -4,6 +4,8 @@ test_start "allow/deny directives" +check_config_h 'FEAT_CMDMON 1' || test_skip + limit=500 # Note that start_client in clknetsim.bash always adds allow to the config diff --git a/test/simulation/110-chronyc b/test/simulation/110-chronyc index 7fe5dcf..5736ae4 100755 --- a/test/simulation/110-chronyc +++ b/test/simulation/110-chronyc @@ -4,6 +4,9 @@ test_start "chronyc" +check_config_h 'FEAT_REFCLOCK 1' || test_skip +check_config_h 'FEAT_CMDMON 1' || test_skip + refclock_jitter=$jitter client_conf=" refclock SHM 0 noselect diff --git a/test/simulation/112-port b/test/simulation/112-port index e983757..a8efabd 100755 --- a/test/simulation/112-port +++ b/test/simulation/112-port @@ -4,6 +4,8 @@ test_start "port and acquisitionport directives" +check_config_h 'FEAT_CMDMON 1' || test_skip + run_test || test_fail check_chronyd_exit || test_fail check_source_selection || test_fail diff --git a/test/simulation/113-leapsecond b/test/simulation/113-leapsecond index 5b9758f..2fb81b8 100755 --- a/test/simulation/113-leapsecond +++ b/test/simulation/113-leapsecond @@ -1,8 +1,11 @@ #!/bin/bash . ./test.common + test_start "leap second" +check_config_h 'FEAT_REFCLOCK 1' || test_skip + export CLKNETSIM_START_DATE=$(TZ=UTC date -d 'Dec 30 2008 0:00:00' +'%s') leap=$[2 * 24 * 3600] diff --git a/test/simulation/115-cmdmontime b/test/simulation/115-cmdmontime index 2806a1f..732decd 100755 --- a/test/simulation/115-cmdmontime +++ b/test/simulation/115-cmdmontime @@ -5,7 +5,8 @@ test_start "cmdmon timestamps" # The following tests need 64-bit time_t -grep -q 'HAVE_LONG_TIME_T 1' ../../config.h || test_skip +check_config_h 'HAVE_LONG_TIME_T 1' || test_skip +check_config_h 'FEAT_CMDMON 1' || test_skip limit=2 client_server_options="noselect" diff --git a/test/simulation/119-smoothtime b/test/simulation/119-smoothtime index 6b4ae39..3f90715 100755 --- a/test/simulation/119-smoothtime +++ b/test/simulation/119-smoothtime @@ -1,8 +1,11 @@ #!/bin/bash . ./test.common + test_start "smoothtime option" +check_config_h 'FEAT_REFCLOCK 1' || test_skip + server_strata=2 server_conf="smoothtime 400 0.001" server_server_options="minpoll 8" diff --git a/test/simulation/121-orphan b/test/simulation/121-orphan index 1b47f76..bbebc9d 100755 --- a/test/simulation/121-orphan +++ b/test/simulation/121-orphan @@ -4,6 +4,8 @@ test_start "orphan option" +check_config_h 'FEAT_CMDMON 1' || test_skip + server_strata=3 server_conf="local stratum 5 orphan server 192.168.123.1 diff --git a/test/simulation/124-tai b/test/simulation/124-tai index b5be030..d41d29d 100755 --- a/test/simulation/124-tai +++ b/test/simulation/124-tai @@ -1,8 +1,11 @@ #!/bin/bash . ./test.common + test_start "tai option" +check_config_h 'FEAT_REFCLOCK 1' || test_skip + export CLKNETSIM_START_DATE=$(TZ=UTC date -d 'Dec 31 2008 23:50:00' +'%s') leap=$[10 * 60] diff --git a/test/simulation/128-nocontrol b/test/simulation/128-nocontrol index 0a98cd7..cca82f4 100755 --- a/test/simulation/128-nocontrol +++ b/test/simulation/128-nocontrol @@ -4,6 +4,8 @@ test_start "-x option" +check_config_h 'FEAT_CMDMON 1' || test_skip + wander=0.0 time_offset=0.0 freq_offset=0.0 diff --git a/test/simulation/133-hwtimestamp b/test/simulation/133-hwtimestamp index 1448c21..229d4ee 100755 --- a/test/simulation/133-hwtimestamp +++ b/test/simulation/133-hwtimestamp @@ -4,6 +4,8 @@ test_start "hwtimestamp directive" +check_config_h 'HAVE_LINUX_TIMESTAMPING 1' || test_skip + export CLKNETSIM_TIMESTAMPING=2 refclock_jitter=1e-8 @@ -11,22 +13,25 @@ refclock_offset=10.0 min_sync_time=4 max_sync_time=20 limit=200 -client_conf="hwtimestamp eth0" -client_server_options="minpoll 0 maxpoll 0 minsamples 32" +server_conf="hwtimestamp eth0" +client_server_options="minpoll 0 maxpoll 0 minsamples 32 xleave" client_chronyd_options="-d" -run_test || test_fail -check_chronyd_exit || test_fail -check_source_selection || test_fail -check_sync || test_fail - -if grep -q 'FEAT_DEBUG 1' ../../config.h; then - check_log_messages "HW clock samples" 190 200 || test_fail - check_log_messages "HW clock reset" 0 0 || test_fail - check_log_messages "Received.*tss=1" 1 1 || test_fail - check_log_messages "Received.*tss=2" 390 400 || test_fail - check_log_messages "update_tx_timestamp.*Updated" 50 140 || test_fail - check_log_messages "update_tx_timestamp.*Unacceptable" 50 140 || test_fail -fi +for client_conf in "hwtimestamp eth0" "hwtimestamp eth0 +acquisitionport 123"; do + run_test || test_fail + check_chronyd_exit || test_fail + check_source_selection || test_fail + check_sync || test_fail + + if check_config_h 'FEAT_DEBUG 1'; then + check_log_messages "HW clock samples" 190 200 || test_fail + check_log_messages "HW clock reset" 0 0 || test_fail + check_log_messages "Received.*tss=1" 1 1 || test_fail + check_log_messages "Received.*tss=2" 390 400 || test_fail + check_log_messages "update_tx_timestamp.*Updated" 50 140 || test_fail + check_log_messages "update_tx_timestamp.*Unacceptable" 50 140 || test_fail + fi +done test_pass diff --git a/test/simulation/134-log b/test/simulation/134-log index f5293c4..0a6ef76 100755 --- a/test/simulation/134-log +++ b/test/simulation/134-log @@ -1,8 +1,11 @@ #!/bin/bash . ./test.common + test_start "log directive" +check_config_h 'FEAT_PHC 1' || test_skip + refclock_jitter=$jitter client_server_options="maxpoll 6" client_conf="refclock PHC /dev/ptp0 dpoll 4 poll 6 noselect diff --git a/test/simulation/test.common b/test/simulation/test.common index 18dd9e1..951a794 100644 --- a/test/simulation/test.common +++ b/test/simulation/test.common @@ -84,6 +84,8 @@ done test_start() { rm -f tmp/* echo "Testing $@:" + + check_config_h 'FEAT_NTP 1' || test_skip } test_pass() { @@ -211,6 +213,12 @@ get_chronyd_conf() { fi } +# Check if chrony was built with specified option in config.h +check_config_h() { + local pattern=$1 + grep -q "^#define $pattern" ../../config.h +} + # Check if the clock was well synchronized check_sync() { local i sync_time max_time_error max_freq_error ret=0 diff --git a/test/system/001-minimal b/test/system/001-minimal new file mode 100755 index 0000000..107fa3f --- /dev/null +++ b/test/system/001-minimal @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +. ./test.common + +test_start "minimal configuration" + +minimal_config=1 + +start_chronyd || test_fail +stop_chronyd || test_fail +check_chronyd_messages || test_fail + +test_pass diff --git a/test/system/002-extended b/test/system/002-extended new file mode 100755 index 0000000..7a6734f --- /dev/null +++ b/test/system/002-extended @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +. ./test.common + +test_start "extended configuration" + +start_chronyd || test_fail +wait_for_sync || test_fail +stop_chronyd || test_fail +check_chronyd_messages || test_fail +check_chronyd_files || test_fail + +test_pass diff --git a/test/system/003-memlock b/test/system/003-memlock new file mode 100755 index 0000000..e4ab1bf --- /dev/null +++ b/test/system/003-memlock @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +. ./test.common + +test_start "memory locking" + +extra_chronyd_options="-m" + +start_chronyd || test_fail +wait_for_sync || test_fail +stop_chronyd || test_fail +check_chronyd_messages || test_fail +check_chronyd_files || test_fail + +test_pass diff --git a/test/system/004-priority b/test/system/004-priority new file mode 100755 index 0000000..bf8a04b --- /dev/null +++ b/test/system/004-priority @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +. ./test.common + +test_start "process priority" + +extra_chronyd_options="-P 1" + +start_chronyd || test_fail +wait_for_sync || test_fail +stop_chronyd || test_fail +check_chronyd_messages || test_fail +check_chronyd_files || test_fail + +test_pass diff --git a/test/system/005-scfilter b/test/system/005-scfilter new file mode 100755 index 0000000..778a688 --- /dev/null +++ b/test/system/005-scfilter @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +. ./test.common + +check_chronyd_features SCFILTER || test_skip "SCFILTER support disabled" + +test_start "system call filter" + +for extra_chronyd_options in "-F -1" "-F 1"; do + start_chronyd || test_fail + wait_for_sync || test_fail + stop_chronyd || test_fail + check_chronyd_messages || test_fail + check_chronyd_files || test_fail +done + +test_pass diff --git a/test/system/006-privdrop b/test/system/006-privdrop new file mode 100755 index 0000000..6d7b0c9 --- /dev/null +++ b/test/system/006-privdrop @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +. ./test.common + +check_chronyd_features PRIVDROP || test_skip "PRIVDROP support disabled" + +user="nobody" + +test_start "dropping of root privileges" + +minimal_config=1 + +start_chronyd || test_fail +stop_chronyd || test_fail +check_chronyd_messages || test_fail + +test_pass diff --git a/test/system/007-cmdmon b/test/system/007-cmdmon new file mode 100755 index 0000000..f705fb0 --- /dev/null +++ b/test/system/007-cmdmon @@ -0,0 +1,69 @@ +#!/usr/bin/env bash + +. ./test.common + +test_start "chronyc commands" + +start_chronyd || test_fail + +for command in \ + "accheck 1.2.3.4" \ + "delete $server" \ + "add server $server" \ + "deny" \ + "allow" \ + "burst 1/1" \ + "clients" \ + "cmdallow 1.2.3.4" \ + "cmdaccheck 1.2.3.4" \ + "cmddeny 1.2.3.4" \ + "cyclelogs" \ + "dfreq 1.0e-3" \ + "doffset -0.1" \ + "dump" \ + "local off" \ + "local" \ + "manual on" \ + "settime now" \ + "manual delete 0" \ + "settime now" \ + "manual reset" \ + "manual off" \ + "maxdelay $server 1e-2" \ + "maxdelaydevratio $server 5.0" \ + "maxdelayratio $server 3.0" \ + "maxpoll $server 5" \ + "maxupdateskew $server 10.0" \ + "minpoll $server 3" \ + "minstratum $server 1" \ + "ntpdata $server" \ + "offline" \ + "online" \ + "onoffline" \ + "polltarget $server 10" \ + "refresh" \ + "rekey" \ + "reselect" \ + "reselectdist 1e-3" \ + "serverstats" \ + "smoothtime reset" \ + "smoothtime activate" \ + "shutdown" \ +; do + run_chronyc "$command" || test_fail +done + +stop_chronyd || test_fail +check_chronyd_messages || test_fail +start_chronyd || test_fail + +run_chronyc "makestep" && test_fail +check_chronyc_output "500 Failure" || test_fail +run_chronyc "trimrtc" && test_fail +check_chronyc_output "513 RTC driver not running" || test_fail +run_chronyc "writertc" && test_fail +check_chronyc_output "513 RTC driver not running" || test_fail + +stop_chronyd || test_fail + +test_pass diff --git a/test/system/100-clockupdate b/test/system/100-clockupdate new file mode 100755 index 0000000..191e461 --- /dev/null +++ b/test/system/100-clockupdate @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +. ./test.common + +test_start "update of system clock" + +clock_control=1 +minimal_config=1 + +start_chronyd || test_fail +run_chronyc "dfreq 1e-3" || test_fail +check_chronyc_output "200 OK" || test_fail + +before=$(date '+%s') +run_chronyc "doffset -1.0" || test_fail +check_chronyc_output "200 OK" || test_fail +run_chronyc "makestep" || test_fail +check_chronyc_output "200 OK" || test_fail +after=$(date '+%s') + +test_message 1 0 "checking system clock" +[ "$before" -lt "$after" ] && test_ok || test_bad || test_fail + +run_chronyc "doffset 1.0" || test_fail +run_chronyc "makestep" || test_fail +stop_chronyd || test_fail +check_chronyd_messages || test_fail +check_chronyd_message_count "System clock was stepped by" 2 2 || test_fail + +test_pass diff --git a/test/system/101-rtc b/test/system/101-rtc new file mode 100755 index 0000000..fa9a70d --- /dev/null +++ b/test/system/101-rtc @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +. ./test.common + +check_chronyd_features RTC || test_skip "RTC support disabled" +[ -c "/dev/rtc" ] || test_skip "missing /dev/rtc" + +test_start "real-time clock" + +minimal_config=1 +extra_chronyd_options="-s" +extra_chronyd_directives="rtcfile $TEST_DIR/rtcfile" +echo "1 $(date +%s) 0.0 0.0" > "$TEST_DIR/rtcfile" + +start_chronyd || test_fail +stop_chronyd || test_fail +check_chronyd_message_count "\(clock off from RTC\|RTC time before last\)" 1 1 || test_fail + +test_pass diff --git a/test/system/102-hwtimestamp b/test/system/102-hwtimestamp new file mode 100755 index 0000000..86f2287 --- /dev/null +++ b/test/system/102-hwtimestamp @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +. ./test.common + +[ "$(uname -s)" = "Linux" ] || test_skip "non-Linux system" + +hwts_iface="" +for iface_path in /sys/class/net/*; do + iface=$(basename "$iface_path") + if ethtool -T "$iface" 2> /dev/null | grep -q HWTSTAMP_FILTER_ALL; then + hwts_iface="$iface" + break + fi +done + +[ -n "$hwts_iface" ] || test_skip "no HW timestamping interface found" + +test_start "hardware timestamping" + +minimal_config=1 +extra_chronyd_directives="hwtimestamp $hwts_iface" + +start_chronyd || test_fail +stop_chronyd || test_fail +check_chronyd_messages || test_fail +check_chronyd_message_count "Enabled HW timestamping on $hwts_iface" 1 1 || test_fail + +test_pass diff --git a/test/system/103-refclock b/test/system/103-refclock new file mode 100755 index 0000000..e5b74e0 --- /dev/null +++ b/test/system/103-refclock @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +. ./test.common + +check_chronyd_features REFCLOCK || test_skip "refclock support disabled" + +test_start "reference clocks" + +extra_chronyd_directives=" +refclock SOCK $TEST_DIR/refclock.sock +refclock SHM 100" + +start_chronyd || test_fail +wait_for_sync || test_fail +stop_chronyd || test_fail +check_chronyd_messages || test_fail +check_chronyd_files || test_fail + +test_pass diff --git a/test/system/104-systemdirs b/test/system/104-systemdirs new file mode 100755 index 0000000..15508dc --- /dev/null +++ b/test/system/104-systemdirs @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +TEST_LIBDIR=${CHRONY_LIBDIR:-/var/lib/chrony} +TEST_LOGDIR=${CHRONY_LOGDIR:-/var/log/chrony} +TEST_RUNDIR=${CHRONY_RUNDIR:-/var/run/chrony} + +. ./test.common + +user=$(ls -ld "$TEST_RUNDIR" 2> /dev/null | awk '{print $3}') + +test_start "system directories" + +start_chronyd || test_fail +wait_for_sync || test_fail +stop_chronyd || test_fail +check_chronyd_messages || test_fail +check_chronyd_files || test_fail + +test_pass diff --git a/test/system/run b/test/system/run new file mode 100755 index 0000000..5516ed4 --- /dev/null +++ b/test/system/run @@ -0,0 +1,64 @@ +#!/usr/bin/env bash + +print_help() { + echo "$1 [-a] [-d] [TEST]..." +} + +run_test() { + local result name=$1 + + if [ $destructive -ne 1 ] && [[ "$name" == 1[0-9][0-9]-* ]]; then + echo "SKIP (destructive test)" + return 9 + fi + + ./$name + result=$? + + if [ $result -ne 0 -a $result -ne 9 ]; then + if [ $abort_on_fail -ne 0 ]; then + exit 1 + fi + fi + + return $result +} + +passed=() failed=() skipped=() + +abort_on_fail=0 +destructive=0 + +while getopts ":ad" opt; do + case $opt in + a) abort_on_fail=1;; + d) destructive=1;; + *) print_help "$0"; exit 3;; + esac +done + +shift $[$OPTIND - 1] + +[ $# -gt 0 ] && tests=($@) || tests=([0-9]*-*[^_]) + +for test in "${tests[@]}"; do + printf "%s " "$test" + run_test $test + result=$? + echo + + case $result in + 0) passed=(${passed[@]} $test);; + 9) skipped=(${skipped[@]} $test);; + *) failed=(${failed[@]} $test);; + esac +done + +echo +echo "SUMMARY:" +echo " TOTAL $[${#passed[@]} + ${#failed[@]} + ${#skipped[@]}]" +echo " PASSED ${#passed[@]}" +echo " FAILED ${#failed[@]} (${failed[@]})" +echo " SKIPPED ${#skipped[@]} (${skipped[@]})" + +[ ${#failed[@]} -eq 0 ] diff --git a/test/system/test.common b/test/system/test.common new file mode 100644 index 0000000..28c4805 --- /dev/null +++ b/test/system/test.common @@ -0,0 +1,339 @@ +# Copyright (C) Miroslav Lichvar 2009 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +export LC_ALL=C +export PATH=${CHRONY_PATH:-../..}:$PATH + +TEST_DIR=${TEST_DIR:-$(pwd)/tmp} +TEST_LIBDIR=${TEST_LIBDIR:-$TEST_DIR} +TEST_LOGDIR=${TEST_LOGDIR:-$TEST_DIR} +TEST_RUNDIR=${TEST_RUNDIR:-$TEST_DIR} + +test_start() { + check_chronyd_features NTP CMDMON || test_skip "NTP/CMDMON support disabled" + + [ "${#TEST_DIR}" -ge 5 ] || test_skip "invalid TEST_DIR" + + rm -rf "$TEST_DIR" + mkdir -p "$TEST_DIR" && chmod 700 "$TEST_DIR" || test_skip "could not create $TEST_DIR" + + [ -d "$TEST_LIBDIR" ] || test_skip "missing $TEST_LIBDIR" + [ -d "$TEST_LOGDIR" ] || test_skip "missing $TEST_LOGDIR" + [ -d "$TEST_RUNDIR" ] || test_skip "missing $TEST_RUNDIR" + + rm -f "$TEST_LIBDIR"/* "$TEST_LOGDIR"/* "$TEST_RUNDIR"/* + + if [ "$user" != "root" ]; then + id -u "$user" > /dev/null 2> /dev/null || test_skip "missing user $user" + chown "$user:$(id -g "$user")" "$TEST_DIR" || test_skip "could not chown $TEST_DIR" + su "$user" -s /bin/sh -c "touch $TEST_DIR/test" 2> /dev/null || \ + test_skip "$user cannot access $TEST_DIR" + rm "$TEST_DIR/test" + fi + + echo "Testing $*:" +} + +test_pass() { + echo "PASS" + exit 0 +} + +test_fail() { + echo "FAIL" + exit 1 +} + +test_skip() { + local msg=$1 + + [ -n "$msg" ] && echo "SKIP ($msg)" || echo "SKIP" + exit 9 +} + +test_ok() { + pad_line + echo -e "\tOK" + return 0 +} + +test_bad() { + pad_line + echo -e "\tBAD" + return 1 +} + +test_error() { + pad_line + echo -e "\tERROR" + return 1 +} + +chronyd=$(command -v chronyd) +chronyc=$(command -v chronyc) + +[ $EUID -eq 0 ] || test_skip "not root" + +[ -x "$chronyd" ] || test_skip "chronyd not found" +[ -x "$chronyc" ] || test_skip "chronyc not found" + +netstat -aln > /dev/null 2> /dev/null || test_skip "missing netstat" + +# Default test testings +default_minimal_config=0 +default_extra_chronyd_directives="" +default_extra_chronyd_options="" +default_clock_control=0 +default_server=127.0.0.1 +default_user=root + +# Initialize test settings from their defaults +for defoptname in ${!default_*}; do + optname=${defoptname#default_} + [ -z "${!optname}" ] && declare "$optname"="${!defoptname}" +done + +msg_length=0 +pad_line() { + local line_length=56 + [ $msg_length -lt $line_length ] && \ + printf "%$((line_length - msg_length))s" "" + msg_length=0 +} + +# Print aligned message +test_message() { + local level=$1 eol=$2 + shift 2 + local msg="$*" + + while [ "$level" -gt 0 ]; do + echo -n " " + level=$((level - 1)) + msg_length=$((msg_length + 2)) + done + echo -n "$msg" + + msg_length=$((msg_length + ${#msg})) + if [ "$eol" -ne 0 ]; then + echo + msg_length=0 + fi +} + +# Check if chronyd has specified features +check_chronyd_features() { + local feature features + + features=$($chronyd -v | sed 's/.*(\(.*\)).*/\1/') + + for feature; do + echo "$features" | grep -q "+$feature" || return 1 + done +} + +# Print test settings which differ from default value +print_nondefaults() { + local defoptname optname + + test_message 1 1 "non-default settings:" + for defoptname in ${!default_*}; do + optname=${defoptname#default_} + [ "${!defoptname}" = "${!optname}" ] || \ + test_message 2 1 "$optname"=${!optname} + done +} + +get_conffile() { + echo "$TEST_DIR/chronyd.conf" +} + +get_pidfile() { + echo "$TEST_RUNDIR/chronyd.pid" +} + +get_logfile() { + echo "$TEST_LOGDIR/chronyd.log" +} + +get_cmdsocket() { + echo "$TEST_RUNDIR/chronyd.sock" +} + +# Find a free port in the 10000-20000 range (their use is racy) +get_free_port() { + local port + + while true; do + port=$((RANDOM % 10000 + 10000)) + netstat -aln | grep '^udp.*:'$port && continue + break + done + + echo $port +} + +generate_chrony_conf() { + local ntpport cmdport + + ntpport=$(get_free_port) + cmdport=$(get_free_port) + + echo "0.0 10000" > "$TEST_LIBDIR/driftfile" + echo "1 MD5 abcdefghijklmnopq" > "$TEST_DIR/keys" + chown "$user:$(id -g "$user")" "$TEST_LIBDIR/driftfile" "$TEST_DIR/keys" + echo "0.0" > "$TEST_DIR/tempcomp" + + ( + echo "pidfile $(get_pidfile)" + echo "bindcmdaddress $(get_cmdsocket)" + echo "port $ntpport" + echo "cmdport $cmdport" + + echo "$extra_chronyd_directives" + + [ "$minimal_config" -ne 0 ] && exit 0 + + echo "allow" + echo "cmdallow" + echo "local" + + echo "server $server port $ntpport minpoll -6 maxpoll -6" + + [ "$server" = "127.0.0.1" ] && echo "bindacqaddress $server" + echo "bindaddress 127.0.0.1" + echo "bindcmdaddress 127.0.0.1" + echo "dumpdir $TEST_RUNDIR" + echo "logdir $TEST_LOGDIR" + echo "log tempcomp rawmeasurements refclocks statistics tracking rtc" + echo "logbanner 0" + echo "smoothtime 100.0 0.001" + + echo "include /dev/null" + echo "keyfile $TEST_DIR/keys" + echo "driftfile $TEST_LIBDIR/driftfile" + echo "tempcomp $TEST_DIR/tempcomp 0.1 0 0 0 0" + + ) > "$(get_conffile)" +} + +get_chronyd_options() { + [ "$clock_control" -eq 0 ] && echo "-x" + echo "-l $(get_logfile)" + echo "-f $(get_conffile)" + echo "-u $user" + echo "$extra_chronyd_options" +} + +# Start a chronyd instance +start_chronyd() { + local pid pidfile=$(get_pidfile) + + print_nondefaults + test_message 1 0 "starting chronyd" + + generate_chrony_conf + + trap stop_chronyd EXIT + + $CHRONYD_WRAPPER "$chronyd" $(get_chronyd_options) > "$TEST_DIR/chronyd.out" 2>&1 + + [ $? -eq 0 ] && [ -f "$pidfile" ] && ps -p "$(cat "$pidfile")" > /dev/null && test_ok || test_error +} + +wait_for_sync() { + test_message 1 0 "waiting for synchronization" + sleep 1 && test_ok || test_error +} + +# Stop the chronyd instance +stop_chronyd() { + local pid pidfile + + pidfile=$(get_pidfile) + [ -f "$pidfile" ] || return 0 + + pid=$(cat "$pidfile") + + test_message 1 0 "stopping chronyd" + + if ! kill "$pid" 2> /dev/null; then + test_error + return + fi + + # Wait for the process to terminate (we cannot use "wait") + while ps -p "$pid" > /dev/null; do + sleep 0.1 + done + + test_ok +} + +# Check chronyd log for expected and unexpected messages +check_chronyd_messages() { + local logfile=$(get_logfile) + + test_message 1 0 "checking chronyd messages" + + grep -q 'chronyd exiting' "$logfile" && \ + ([ "$clock_control" -eq 0 ] || ! grep -q 'Disabled control of system clock' "$logfile") && \ + ([ "$clock_control" -ne 0 ] || grep -q 'Disabled control of system clock' "$logfile") && \ + ([ "$minimal_config" -ne 0 ] || grep -q 'Frequency .* read from' "$logfile") && \ + grep -q 'chronyd exiting' "$logfile" && \ + ! grep -q 'Could not' "$logfile" && \ + ! grep -q 'Disabled command socket' "$logfile" && \ + test_ok || test_bad +} + +# Check the number of messages matching a pattern in a specified file +check_chronyd_message_count() { + local count pattern=$1 min=$2 max=$3 logfile=$(get_logfile) + + test_message 1 0 "checking message \"$pattern\"" + + count=$(grep "$pattern" "$(get_logfile)" | wc -l) + + [ "$min" -le "$count" ] && [ "$count" -le "$max" ] && test_ok || test_bad +} + +# Check the logs and dump file for measurements and a clock update +check_chronyd_files() { + test_message 1 0 "checking chronyd files" + + grep -q " $server .* 111 111 1111 " "$TEST_LOGDIR/measurements.log" && \ + grep -q " $server " "$TEST_LOGDIR/statistics.log" && \ + grep -q " $server " "$TEST_LOGDIR/tracking.log" && \ + [ -f "$TEST_LOGDIR/tempcomp.log" ] && [ "$(wc -l < "$TEST_LOGDIR/tempcomp.log")" -ge 2 ] && \ + [ -f "$TEST_RUNDIR/$server.dat" ] && [ "$(wc -l < "$TEST_RUNDIR/$server.dat")" -ge 5 ] && \ + test_ok || test_bad +} + +# Run a chronyc command +run_chronyc() { + test_message 1 0 "running chronyc $*" + + $CHRONYC_WRAPPER "$chronyc" -h "$(get_cmdsocket)" -n -m "$@" > "$TEST_DIR/chronyc.out" && \ + test_ok || test_error +} + +# Compare chronyc output with specified pattern +check_chronyc_output() { + local pattern=$1 + + test_message 1 0 "checking chronyc output" + + [[ "$(cat "$TEST_DIR/chronyc.out")" =~ $pattern ]] && test_ok || test_bad +} diff --git a/test/unit/ntp_core.c b/test/unit/ntp_core.c index 5e519e5..ac01205 100644 --- a/test/unit/ntp_core.c +++ b/test/unit/ntp_core.c @@ -28,6 +28,8 @@ #include #include "test.h" +#ifdef FEAT_NTP + static struct timespec current_time; static NTP_Receive_Buffer req_buffer, res_buffer; static int req_length, res_length; @@ -332,10 +334,8 @@ test_unit(void) CPS_ParseNTPSourceAdd(source_line, &source); for (i = 0; i < 1000; i++) { - if (random() % 2) - source.params.interleaved = 1; - if (random() % 2) - source.params.authkey = get_random_key_id(); + source.params.interleaved = random() % 2; + source.params.authkey = random() % 2 ? get_random_key_id() : INACTIVE_AUTHKEY; source.params.version = random() % 4 + 1; UTI_ZeroTimespec(¤t_time); @@ -475,3 +475,11 @@ test_unit(void) CNF_Finalise(); HSH_Finalise(); } + +#else +void +test_unit(void) +{ + TEST_REQUIRE(0); +} +#endif diff --git a/test/unit/ntp_sources.c b/test/unit/ntp_sources.c index ea8f19c..f13852e 100644 --- a/test/unit/ntp_sources.c +++ b/test/unit/ntp_sources.c @@ -18,10 +18,14 @@ ********************************************************************** */ +#include +#include "test.h" + +#ifdef FEAT_NTP + #include #include #include -#include "test.h" void test_unit(void) @@ -98,3 +102,11 @@ test_unit(void) CNF_Finalise(); HSH_Finalise(); } + +#else +void +test_unit(void) +{ + TEST_REQUIRE(0); +} +#endif diff --git a/test/unit/test.c b/test/unit/test.c index 3a9ec74..fbfeb4b 100644 --- a/test/unit/test.c +++ b/test/unit/test.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "test.h" @@ -32,6 +33,13 @@ TST_Fail(int line) exit(1); } +void +TST_Skip(int line) +{ + printf("SKIP (on line %d)\n", line); + exit(0); +} + int main(int argc, char **argv) { diff --git a/test/unit/test.h b/test/unit/test.h index f409252..2d3637b 100644 --- a/test/unit/test.h +++ b/test/unit/test.h @@ -33,7 +33,16 @@ extern void test_unit(void); } \ } while (0) +#define TEST_REQUIRE(expr) \ + do { \ + if (!(expr)) { \ + TST_Skip(__LINE__); \ + exit(0); \ + } \ + } while (0) + extern void TST_Fail(int line); +extern void TST_Skip(int line); extern void TST_SuspendLogging(void); extern void TST_ResumeLogging(void); diff --git a/version.txt b/version.txt index 2f4b607..5a95802 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -3.4 +3.5 -- cgit v1.2.3