From aff496ced38fb2ac20b6b4607c29a9b25042d28f Mon Sep 17 00:00:00 2001 From: Vincent Blut Date: Fri, 3 May 2019 23:09:08 +0200 Subject: New upstream version 3.5-pre1 --- FAQ | 34 +++- INSTALL | 23 ++- Makefile.in | 8 +- NEWS | 17 ++ README | 109 ++----------- client.c | 2 +- cmdmon.c | 2 +- configure | 45 ++++-- doc/chrony.conf.adoc | 69 ++++---- doc/chrony.conf.man.in | 73 +++++---- doc/chronyc.man.in | 4 +- doc/chronyd.man.in | 4 +- doc/faq.adoc | 29 ++++ doc/installation.adoc | 13 ++ examples/chrony.conf.example3 | 2 +- examples/chrony.keys.example | 7 +- examples/chrony.spec | 46 ------ hash_intmd5.c | 1 + hash_tomcrypt.c | 2 +- hwclock.c | 2 +- logging.c | 2 +- main.c | 2 +- nameserv.c | 3 + ntp_io.c | 16 +- ntp_io_linux.c | 6 +- refclock.c | 66 ++++++-- refclock.h | 1 + refclock_phc.c | 3 + refclock_pps.c | 3 + refclock_shm.c | 3 + refclock_sock.c | 2 + reference.c | 2 +- samplefilt.c | 2 +- sources.c | 2 +- sourcestats.c | 2 +- sys.c | 13 +- sys_linux.c | 208 ++++++++++++------------ 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/012-daemonts | 15 ++ test/simulation/105-ntpauth | 2 +- test/simulation/106-refclock | 4 + test/simulation/107-allowdeny | 2 + test/simulation/110-chronyc | 26 +++ 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/129-reload | 3 +- test/simulation/133-hwtimestamp | 4 +- test/simulation/134-log | 33 ++++ test/simulation/135-ratelimit | 18 +++ test/simulation/136-broadcast | 16 ++ test/simulation/test.common | 29 +++- 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/Makefile.in | 12 +- test/unit/hwclock.c | 2 +- test/unit/ntp_core.c | 16 +- test/unit/ntp_sources.c | 14 +- test/unit/samplefilt.c | 6 +- test/unit/sources.c | 2 +- test/unit/test.c | 8 + test/unit/test.h | 9 ++ util.c | 2 +- version.txt | 2 +- 85 files changed, 1511 insertions(+), 432 deletions(-) delete mode 100644 examples/chrony.spec create mode 100644 sys_posix.c create mode 100644 sys_posix.h create mode 100755 test/simulation/012-daemonts create mode 100755 test/simulation/134-log create mode 100755 test/simulation/135-ratelimit create mode 100755 test/simulation/136-broadcast 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 76e62fc..f4b38fe 100644 --- a/FAQ +++ b/FAQ @@ -15,7 +15,8 @@ Table of Contents ? 2.6. How can I improve the accuracy of the system clock with NTP sources? ? 2.7. Does chronyd have an ntpdate mode? - ? 2.8. What happened to the commandkey and generatecommandkey directives? + ? 2.8. Can chronyd be configured to control the clock like ntpd? + ? 2.9. What happened to the commandkey and generatecommandkey directives? o 3. Computer is not synchronising ? 3.1. Behind a firewall? ? 3.2. Are NTP servers specified with the offline option? @@ -226,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 @@ -243,7 +250,28 @@ command line. For example: # chronyd -q 'pool pool.ntp.org iburst' -2.8. What happened to the commandkey and generatecommandkey directives? +2.8. Can chronyd be configured to control the clock like ntpd? + +It is not possible to perfectly emulate ntpd, but there are some options that +can configure chronyd to behave more like ntpd. + +In the following example the minsamples directive slows down the response to +changes in the frequency and offset of the clock. The maxslewrate and +corrtimeratio directives reduce the maximum frequency error due to an offset +correction and the maxdrift directive reduces the maximum assumed frequency +error of the clock. The makestep directive enables a step threshold and the +maxchange directive enables a panic threshold. The maxclockerror directive +increases the minimum dispersion rate. + +minsamples 32 +maxslewrate 500 +corrtimeratio 100 +maxdrift 500 +makestep 0.128 -1 +maxchange 1000 1 1 +maxclockerror 15 + +2.9. What happened to the commandkey and generatecommandkey directives? They were removed in version 2.2. Authentication is no longer supported in the command protocol. Commands that required authentication are now allowed only @@ -516,4 +544,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-08-31 10:11:17 CEST +Last updated 2019-05-02 11:50:41 CEST diff --git a/INSTALL b/INSTALL index 250dd45..a77cfa7 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-08-31 10:11:17 CEST +Last updated 2019-05-02 11:50:41 CEST diff --git a/Makefile.in b/Makefile.in index e748968..8e68ef4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -70,7 +70,8 @@ distclean : clean -rm -f Makefile config.h config.log clean : - -rm -f *.o *.s chronyc chronyd core *~ + -rm -f *.o *.s chronyc chronyd core.* *~ + -rm -f *.gcda *.gcno -rm -rf .deps -rm -rf *.dSYM @@ -112,10 +113,15 @@ 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) Makefile : Makefile.in configure @echo diff --git a/NEWS b/NEWS index 51a0c22..b0baf06 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,20 @@ +New in version 3.5 +================== + +Enhancements +------------ +* Add support for more accurate reading of PHC on Linux 5.0 +* 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 5b6056e..029860c 100644 --- a/client.c +++ b/client.c @@ -3,7 +3,7 @@ ********************************************************************** * Copyright (C) Richard P. Curnow 1997-2003 - * Copyright (C) Lonnie Abelbeck 2016 + * Copyright (C) Lonnie Abelbeck 2016, 2018 * Copyright (C) Miroslav Lichvar 2009-2018 * * This program is free software; you can redistribute it and/or modify diff --git a/cmdmon.c b/cmdmon.c index e069588..3b4277a 100644 --- a/cmdmon.c +++ b/cmdmon.c @@ -3,7 +3,7 @@ ********************************************************************** * Copyright (C) Richard P. Curnow 1997-2003 - * Copyright (C) Miroslav Lichvar 2009-2016 + * Copyright (C) Miroslav Lichvar 2009-2016, 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 diff --git a/configure b/configure index 33aacdf..9e21a8b 100755 --- a/configure +++ b/configure @@ -227,6 +227,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 +396,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 +411,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 +422,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 +450,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__ @@ -647,12 +654,12 @@ fi if [ $feat_asyncdns = "1" ] && \ test_code 'pthread' 'pthread.h' '-pthread' '' \ - 'return pthread_create((void *)1, NULL, (void *)1, NULL);' + 'return (int)pthread_create((void *)1, NULL, (void *)1, NULL);' 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 +793,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 +911,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 4a39c21..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 ---- + :: @@ -661,6 +661,13 @@ The *minsamples* directive sets the default minimum number of samples that *chronyd* should keep for each source. This setting can be overridden for individual sources in the <> and <> directives. The default value is 6. The useful range is 4 to 64. ++ +Forcing *chronyd* to keep more samples than it would normally keep reduces +noise in the estimated frequency and offset, but slows down the response to +changes in the frequency and offset of the clock. The offsets in the +<> and +<> reports (and the _tracking.log_ and +_statistics.log_ files) may be smaller than the actual offsets. === Source selection @@ -674,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 @@ -1594,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 @@ -2049,14 +2058,18 @@ that has password shorter than 80 bits. The <> command of *chronyc* can be used to generate random keys for the key file. By default, it generates 160-bit MD5 or SHA1 keys. ++ +For security reasons, the file should be readable only by root and the user +under which *chronyd* is normally running (to allow *chronyd* to re-read the +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 @@ -2070,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 28fb647..c058e8d 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-08-31 +.\" Date: 2019-05-02 .\" Manual: Configuration Files .\" Source: chrony @CHRONY_VERSION@ .\" Language: English .\" -.TH "CHRONY.CONF" "5" "2018-08-31" "chrony @CHRONY_VERSION@" "Configuration Files" +.TH "CHRONY.CONF" "5" "2019-05-02" "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 @@ -903,6 +903,13 @@ The \fBminsamples\fP directive sets the default minimum number of samples that \fBchronyd\fP should keep for each source. This setting can be overridden for individual sources in the \fBserver\fP and \fBrefclock\fP directives. The default value is 6. The useful range is 4 to 64. +.sp +Forcing \fBchronyd\fP to keep more samples than it would normally keep reduces +noise in the estimated frequency and offset, but slows down the response to +changes in the frequency and offset of the clock. The offsets in the +\fBtracking\fP and +\fBsourcestats\fP reports (and the \fItracking.log\fP and +\fIstatistics.log\fP files) may be smaller than the actual offsets. .RE .SS "Source selection" .sp @@ -917,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 @@ -2152,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 @@ -3445,16 +3454,20 @@ that has password shorter than 80 bits. The \fBkeygen\fP command of \fBchronyc\fP can be used to generate random keys for the key file. By default, it generates 160\-bit MD5 or SHA1 keys. +.sp +For security reasons, the file should be readable only by root and the user +under which \fBchronyd\fP is normally running (to allow \fBchronyd\fP to re\-read the +file when the \fBrekey\fP command is issued by \fBchronyc\fP). .RE .sp \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 @@ -3478,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 5c76fe4..6ad8e01 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-08-31 +.\" Date: 2019-05-02 .\" Manual: User manual .\" Source: chrony @CHRONY_VERSION@ .\" Language: English .\" -.TH "CHRONYC" "1" "2018-08-31" "chrony @CHRONY_VERSION@" "User manual" +.TH "CHRONYC" "1" "2019-05-02" "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 a95de6a..e346d78 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-08-31 +.\" Date: 2019-05-02 .\" Manual: System Administration .\" Source: chrony @CHRONY_VERSION@ .\" Language: English .\" -.TH "CHRONYD" "8" "2018-08-31" "chrony @CHRONY_VERSION@" "System Administration" +.TH "CHRONYD" "8" "2019-05-02" "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 8e6926b..318b418 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 @@ -238,6 +244,29 @@ specified on the command line. For example: # chronyd -q 'pool pool.ntp.org iburst' ---- +=== Can `chronyd` be configured to control the clock like `ntpd`? + +It is not possible to perfectly emulate `ntpd`, but there are some options that +can configure `chronyd` to behave more like `ntpd`. + +In the following example the `minsamples` directive slows down the response to +changes in the frequency and offset of the clock. The `maxslewrate` and +`corrtimeratio` directives reduce the maximum frequency error due to an offset +correction and the `maxdrift` directive reduces the maximum assumed frequency +error of the clock. The `makestep` directive enables a step threshold and the +`maxchange` directive enables a panic threshold. The `maxclockerror` directive +increases the minimum dispersion rate. + +---- +minsamples 32 +maxslewrate 500 +corrtimeratio 100 +maxdrift 500 +makestep 0.128 -1 +maxchange 1000 1 1 +maxclockerror 15 +---- + === 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/chrony.conf.example3 b/examples/chrony.conf.example3 index 05a4e98..c04f871 100644 --- a/examples/chrony.conf.example3 +++ b/examples/chrony.conf.example3 @@ -95,7 +95,7 @@ driftfile /var/lib/chrony/drift # still running and bail out. If you want to change the path to the PID # file, uncomment this line and edit it. The default path is shown. -! pidfile /var/run/chronyd.pid +! pidfile /var/run/chrony/chronyd.pid # If the system timezone database is kept up to date and includes the # right/UTC timezone, chronyd can use it to determine the current diff --git a/examples/chrony.keys.example b/examples/chrony.keys.example index 2dd19cd..65b6be2 100644 --- a/examples/chrony.keys.example +++ b/examples/chrony.keys.example @@ -1,6 +1,7 @@ -# This is an example chrony keys file. It is used for NTP authentication with -# symmetric keys. It should be readable only by root or the user to which -# chronyd is configured to switch to after start. +# This is an example chrony keys file. It enables authentication of NTP +# packets with symmetric keys when its location is specified by the keyfile +# directive in chrony.conf(5). It should be readable only by root and the +# user under which chronyd is running. # # Don't use the example keys! It's recommended to generate random keys using # the chronyc keygen command. diff --git a/examples/chrony.spec b/examples/chrony.spec deleted file mode 100644 index 94454a5..0000000 --- a/examples/chrony.spec +++ /dev/null @@ -1,46 +0,0 @@ -%global chrony_version 3.4-pre1 -%if 0%(echo %{chrony_version} | grep -q pre && echo 1) -%global prerelease %(echo %{chrony_version} | sed 's/.*-//') -%endif -Summary: An NTP client/server -Name: chrony -Version: %(echo %{chrony_version} | sed 's/-.*//') -Release: %{!?prerelease:1}%{?prerelease:0.1.%{prerelease}} -Source: chrony-%{version}%{?prerelease:-%{prerelease}}.tar.gz -License: GPLv2 -Group: Applications/Utilities -BuildRoot: %{_tmppath}/%{name}-%{version}-root-%(id -u -n) - -%description -chrony is a client and server for the Network Time Protocol (NTP). -This program keeps your computer's clock accurate. It was specially -designed to support systems with intermittent Internet connections, -but it also works well in permanently connected environments. It can -also use hardware reference clocks, the system real-time clock, or -manual input as time references. - -%prep -%setup -q -n %{name}-%{version}%{?prerelease:-%{prerelease}} - -%build -./configure \ - --prefix=%{_prefix} \ - --bindir=%{_bindir} \ - --sbindir=%{_sbindir} \ - --mandir=%{_mandir} -make - -%install -rm -rf $RPM_BUILD_ROOT -make install DESTDIR=$RPM_BUILD_ROOT - -%files -%{_sbindir}/chronyd -%{_bindir}/chronyc -%{_mandir}/man1/chronyc.1.gz -%{_mandir}/man5/chrony.conf.5.gz -%{_mandir}/man8/chronyd.8.gz -%doc README FAQ NEWS COPYING -%doc examples/chrony.conf.example* -%doc examples/chrony.keys.example - 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/hash_tomcrypt.c b/hash_tomcrypt.c index 51b63d9..4326c9e 100644 --- a/hash_tomcrypt.c +++ b/hash_tomcrypt.c @@ -2,7 +2,7 @@ chronyd/chronyc - Programs for keeping computer clocks accurate. ********************************************************************** - * Copyright (C) Miroslav Lichvar 2012 + * Copyright (C) Miroslav Lichvar 2012, 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 diff --git a/hwclock.c b/hwclock.c index 6122ab2..8e13e7e 100644 --- a/hwclock.c +++ b/hwclock.c @@ -2,7 +2,7 @@ chronyd/chronyc - Programs for keeping computer clocks accurate. ********************************************************************** - * Copyright (C) Miroslav Lichvar 2016-2017 + * Copyright (C) Miroslav Lichvar 2016-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 diff --git a/logging.c b/logging.c index 828ae30..d2296e0 100644 --- a/logging.c +++ b/logging.c @@ -3,7 +3,7 @@ ********************************************************************** * Copyright (C) Richard P. Curnow 1997-2003 - * Copyright (C) Miroslav Lichvar 2011-2014 + * Copyright (C) Miroslav Lichvar 2011-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 diff --git a/main.c b/main.c index c40fb25..6ccf32e 100644 --- a/main.c +++ b/main.c @@ -4,7 +4,7 @@ ********************************************************************** * Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) John G. Hasler 2009 - * Copyright (C) Miroslav Lichvar 2012-2017 + * Copyright (C) Miroslav Lichvar 2012-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 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 b71a1d4..ab08372 100644 --- a/ntp_io.c +++ b/ntp_io.c @@ -4,7 +4,7 @@ ********************************************************************** * Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) Timo Teras 2009 - * Copyright (C) Miroslav Lichvar 2009, 2013-2016 + * Copyright (C) Miroslav Lichvar 2009, 2013-2016, 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 @@ -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..eb4a3a8 100644 --- a/ntp_io_linux.c +++ b/ntp_io_linux.c @@ -584,7 +584,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); diff --git a/refclock.c b/refclock.c index 66224d5..42fee4c 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-2017 + * Copyright (C) Miroslav Lichvar 2009-2011, 2013-2014, 2016-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 @@ -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, strlen(options[i])) && + (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/reference.c b/reference.c index 2f1ffc8..40b7482 100644 --- a/reference.c +++ b/reference.c @@ -3,7 +3,7 @@ ********************************************************************** * Copyright (C) Richard P. Curnow 1997-2003 - * Copyright (C) Miroslav Lichvar 2009-2017 + * Copyright (C) Miroslav Lichvar 2009-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 diff --git a/samplefilt.c b/samplefilt.c index 7226963..2b737e9 100644 --- a/samplefilt.c +++ b/samplefilt.c @@ -75,7 +75,7 @@ SPF_CreateInstance(int min_samples, int max_samples, double max_dispersion, doub filter->last = -1; /* Set the first estimate to the system precision */ filter->avg_var_n = 0; - filter->avg_var = LCL_GetSysPrecisionAsQuantum() * LCL_GetSysPrecisionAsQuantum(); + filter->avg_var = SQUARE(LCL_GetSysPrecisionAsQuantum()); filter->max_var = SQUARE(max_dispersion); filter->combine_ratio = combine_ratio; filter->samples = MallocArray(NTP_Sample, filter->max_samples); diff --git a/sources.c b/sources.c index 47d6638..9ca937e 100644 --- a/sources.c +++ b/sources.c @@ -3,7 +3,7 @@ ********************************************************************** * Copyright (C) Richard P. Curnow 1997-2003 - * Copyright (C) Miroslav Lichvar 2011-2016 + * Copyright (C) Miroslav Lichvar 2011-2016, 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 diff --git a/sourcestats.c b/sourcestats.c index 7150f6e..2c49272 100644 --- a/sourcestats.c +++ b/sourcestats.c @@ -3,7 +3,7 @@ ********************************************************************** * Copyright (C) Richard P. Curnow 1997-2003 - * Copyright (C) Miroslav Lichvar 2011-2014, 2016-2017 + * Copyright (C) Miroslav Lichvar 2011-2014, 2016-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 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 b829022..898dc7a 100644 --- a/sys_linux.c +++ b/sys_linux.c @@ -4,7 +4,7 @@ ********************************************************************** * Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) John G. Hasler 2009 - * Copyright (C) Miroslav Lichvar 2009-2012, 2014-2017 + * 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 @@ -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/012-daemonts b/test/simulation/012-daemonts new file mode 100755 index 0000000..b883516 --- /dev/null +++ b/test/simulation/012-daemonts @@ -0,0 +1,15 @@ +#!/bin/bash + +. ./test.common + +test_start "daemon timestamping" + +export CLKNETSIM_TIMESTAMPING=0 + +run_test || test_fail +check_chronyd_exit || test_fail +check_source_selection || test_fail +check_packet_interval || test_fail +check_sync || test_fail + +test_pass 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 944cf3f..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 @@ -95,6 +98,8 @@ for chronyc_conf in \ "delete 10.0.0.0" \ "deny 1.2.3.4" \ "deny all 1.2.3.0/24" \ + "dfreq 1.0e-3" \ + "doffset -1.0" \ "dump" \ "local stratum 5 distance 1.0 orphan" \ "local off" \ @@ -126,6 +131,7 @@ for chronyc_conf in \ "settime 16:30" \ "settime 16:30:05" \ "settime Nov 21, 2015 16:30:05" \ + "serverstats" \ "shutdown" \ "smoothtime reset" \ "smoothtime activate" \ @@ -137,4 +143,24 @@ do check_chronyc_output "501 Not authorised" || test_fail done +chronyc_conf="dns -n +dns +n +dns -4 +dns -6 +dns -46 +timeout 200 +retries 1 +keygen +keygen 10 MD5 128 +help +quit +nosuchcommand" + +run_test || test_fail + +check_chronyc_output "^1 (MD5|SHA1) HEX:........................................ +10 MD5 HEX:................................ +System clock:.*this help + *$" || test_fail + test_pass 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/129-reload b/test/simulation/129-reload index 9c4e985..7a346a4 100755 --- a/test/simulation/129-reload +++ b/test/simulation/129-reload @@ -9,7 +9,8 @@ limit=100 min_sync_time=100 max_sync_time=104 client_chronyd_options="-r" -client_conf="dumpdir tmp" +client_conf="dumpdir tmp +maxupdateskew 10000" run_test || test_fail diff --git a/test/simulation/133-hwtimestamp b/test/simulation/133-hwtimestamp index 1448c21..113ea69 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 @@ -20,7 +22,7 @@ check_chronyd_exit || test_fail check_source_selection || test_fail check_sync || test_fail -if grep -q 'FEAT_DEBUG 1' ../../config.h; then +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 diff --git a/test/simulation/134-log b/test/simulation/134-log new file mode 100755 index 0000000..0a6ef76 --- /dev/null +++ b/test/simulation/134-log @@ -0,0 +1,33 @@ +#!/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 +logbanner 10 +logdir tmp +log tracking rawmeasurements measurements statistics rtc refclocks tempcomp +tempcomp tmp/tempcomp 64 0.0 0.0 0.0 0.0" + +echo 0.0 > tmp/tempcomp + +run_test || test_fail +check_chronyd_exit || test_fail +check_source_selection || test_fail +check_packet_interval || test_fail +check_sync || test_fail + +check_file_messages "=============" 31 33 \ + tracking.log measurements.log tempcomp.log || test_fail +check_file_messages "20.*192\.168\.123\.1" 150 160 \ + tracking.log measurements.log statistics.log || test_fail +check_file_messages "20.*PHC0" 150 160 statistics.log || test_fail +check_file_messages "20.*PHC0" 750 800 refclocks.log || test_fail +check_file_messages "20.* 0\.0000" 150 160 tempcomp.log || test_fail + +test_pass diff --git a/test/simulation/135-ratelimit b/test/simulation/135-ratelimit new file mode 100755 index 0000000..cfa5eab --- /dev/null +++ b/test/simulation/135-ratelimit @@ -0,0 +1,18 @@ +#!/bin/bash + +. ./test.common +test_start "ratelimit directive" + +server_conf="ratelimit interval 6 burst 2 leak 4" +client_server_options="minpoll 3 maxpoll 3" +min_sync_time=16 + +run_test || test_fail +check_chronyd_exit || test_fail +check_packet_interval || test_fail +check_sync || test_fail + +check_file_messages " 2 1 " 1200 1300 log.packets || test_fail +check_file_messages " 1 2 " 180 220 log.packets || test_fail + +test_pass diff --git a/test/simulation/136-broadcast b/test/simulation/136-broadcast new file mode 100755 index 0000000..d60d678 --- /dev/null +++ b/test/simulation/136-broadcast @@ -0,0 +1,16 @@ +#!/bin/bash + +. ./test.common + +test_start "broadcast directive" + +server_conf="broadcast 64 192.168.123.255" +client_server_options="offline" + +run_test || test_fail +check_chronyd_exit || test_fail +check_packet_interval && test_fail + +check_file_messages " 1 2 " 150 160 log.packets || test_fail + +test_pass diff --git a/test/simulation/test.common b/test/simulation/test.common index c5758c6..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 @@ -337,7 +345,7 @@ check_chronyc_output() { return $ret } -# Check the number of messages matching a matter in the client logs +# Check the number of messages matching a pattern in the client logs check_log_messages() { local i count ret=0 pattern=$1 min=$2 max=$3 @@ -355,6 +363,25 @@ check_log_messages() { return $ret } +# Check the number of messages matching a pattern in a specified file +check_file_messages() { + local i count ret=0 pattern=$1 min=$2 max=$3 + shift 3 + + test_message 2 1 "checking number of messages \"$pattern\":" + + for i; do + count=$(grep "$pattern" tmp/$i | wc -l) + test_message 3 0 "$i: $count" + + [ "$min" -le "$count" ] && [ "$count" -le "$max" ] && \ + test_ok || test_bad + [ $? -eq 0 ] || ret=1 + done + + return $ret +} + # Check if only NTP port (123) was used check_packet_port() { local i ret=0 port=123 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/Makefile.in b/test/unit/Makefile.in index 554663b..e789a1b 100644 --- a/test/unit/Makefile.in +++ b/test/unit/Makefile.in @@ -11,13 +11,15 @@ SHARED_OBJS = test.o TEST_OBJS := $(sort $(patsubst %.c,%.o,$(wildcard *.c))) TESTS := $(patsubst %.o,%.test,$(filter-out $(SHARED_OBJS),$(TEST_OBJS))) -FILTER_OBJS = %/main.o %/client.o %/getdate.o -CHRONY_OBJS := $(filter-out $(FILTER_OBJS),$(wildcard $(CHRONY_SRCDIR)/*.o)) +CHRONYD_OBJS := $(patsubst %.o,$(CHRONY_SRCDIR)/%.o,$(filter-out main.o,\ + $(filter %.o,$(shell $(MAKE) -f $(CHRONY_SRCDIR)/Makefile print-chronyd-objects)))) all: $(TESTS) -%.test: %.o $(SHARED_OBJS) - $(CC) $(CFLAGS) -o $@ $^ $(CHRONY_OBJS:%/$*.o=) $(LDFLAGS) +$(CHRONYD_OBJS): ; + +%.test: %.o $(SHARED_OBJS) $(CHRONYD_OBJS) + $(CC) $(CFLAGS) -o $@ $(filter-out $(CHRONY_SRCDIR)/$<,$^) $(LDFLAGS) %.o: %.c $(CC) $(CPPFLAGS) $(CFLAGS) -c $< @@ -30,7 +32,7 @@ check: $(TESTS) exit $$ret clean: - rm -f *.o $(TESTS) + rm -f *.o *.gcda *.gcno core.* $(TESTS) rm -rf .deps distclean: clean diff --git a/test/unit/hwclock.c b/test/unit/hwclock.c index 216dbfb..6462c5c 100644 --- a/test/unit/hwclock.c +++ b/test/unit/hwclock.c @@ -1,6 +1,6 @@ /* ********************************************************************** - * Copyright (C) Miroslav Lichvar 2016-2017 + * Copyright (C) Miroslav Lichvar 2016-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 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/samplefilt.c b/test/unit/samplefilt.c index 294a9bf..a371b3a 100644 --- a/test/unit/samplefilt.c +++ b/test/unit/samplefilt.c @@ -18,9 +18,13 @@ ********************************************************************** */ -#include +#include #include "test.h" +#define LCL_GetSysPrecisionAsQuantum() (1.0e-6) + +#include + void test_unit(void) { diff --git a/test/unit/sources.c b/test/unit/sources.c index b81f808..83f7060 100644 --- a/test/unit/sources.c +++ b/test/unit/sources.c @@ -1,6 +1,6 @@ /* ********************************************************************** - * Copyright (C) Miroslav Lichvar 2016 + * Copyright (C) Miroslav Lichvar 2016, 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 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/util.c b/util.c index bfbae33..e7e3442 100644 --- a/util.c +++ b/util.c @@ -3,7 +3,7 @@ ********************************************************************** * Copyright (C) Richard P. Curnow 1997-2003 - * Copyright (C) Miroslav Lichvar 2009, 2012-2017 + * Copyright (C) Miroslav Lichvar 2009, 2012-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 diff --git a/version.txt b/version.txt index 37969b7..c50661d 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -3.4-pre1 +3.5-pre1 -- cgit v1.2.3