Compare commits

...

67 Commits

Author SHA1 Message Date
Miroslav Lichvar
04328ceead doc: update NEWS 2020-08-19 16:24:04 +02:00
Miroslav Lichvar
f00fed2009 main: create new file when writing pidfile
When writing the pidfile, open the file with the O_CREAT|O_EXCL flags
to avoid following a symlink and writing the PID to an unexpected file,
when chronyd still has the root privileges.

The Linux open(2) man page warns about O_EXCL not working as expected on
NFS versions before 3 and Linux versions before 2.6. Saving pidfiles on
a distributed filesystem like NFS is not generally expected, but if
there is a reason to do that, these old kernel and NFS versions are not
considered to be supported for saving files by chronyd.

This is a minimal backport specific to this issue of the following
commits:
- commit 2fc8edacb8 ("use PATH_MAX")
- commit f4c6a00b2a ("logging: call exit() in LOG_Message()")
- commit 7a4c396bba ("util: add functions for common file operations")
- commit e18903a6b5 ("switch to new util file functions")

Reported-by: Matthias Gerstner <mgerstner@suse.de>
2020-08-06 11:46:04 +02:00
Miroslav Lichvar
ffb9887cce doc: update NEWS 2019-05-10 12:22:57 +02:00
Miroslav Lichvar
9220c9b8a2 update copyright years 2019-05-10 11:01:27 +02:00
Miroslav Lichvar
2e28b19112 doc: add note about minsamples to FAQ 2019-05-10 11:01:27 +02:00
Miroslav Lichvar
636a4e2794 refclock: remove unnecessary strlen() call 2019-05-10 11:01:27 +02:00
Miroslav Lichvar
5c9e1e0b69 test: extend 133-hwtimestamp test 2019-05-10 11:01:27 +02:00
Miroslav Lichvar
64fd1b8ba5 ntp: check value returned by CMSG_FIRSTHDR
In NIO_Linux_RequestTxTimestamp(), check the returned pointer and the
length of the buffer before adding the control message. This fixes an
issue reported by the Clang static analyzer.
2019-05-10 10:58:37 +02:00
Miroslav Lichvar
69d3913f3e ntp: check timestamping configuration when SIOCSHWTSTAMP fails
With future kernels it may be possible to get, but not set, the HW
timestamping configuration on some specific interfaces like macvlan in
containers. This would require the admin to configure the timestamping
before starting chronyd.

If SIOCSHWTSTAMP failed on an interface, try SIOCGHWTSTAMP to check if
the current configuration matches the expected configuration and allow
the interface to be used for HW timestamping.
2019-05-09 14:44:58 +02:00
Miroslav Lichvar
08fd011b6a examples: remove /var from PIDFile in chronyd.service
Recent systemd versions complain when loading a unit using a PIDFile
that relies on the /var/run -> /run symlink.
2019-05-06 15:44:24 +02:00
Miroslav Lichvar
c172268cfe doc: update NEWS 2019-05-02 11:50:41 +02:00
Miroslav Lichvar
94b014865c doc: add more recommendations for best stability to FAQ 2019-04-30 14:46:19 +02:00
Miroslav Lichvar
099aaf2cb1 doc: update list of contributors
Include all authors from the git repository.
2019-04-30 12:56:25 +02:00
Miroslav Lichvar
4481a8b24f doc: simplify acknowledgements in README
Stop trying to maintain a list of individual contributions. Just list
the contributors. For tracking individual changes in the source code
there is git.
2019-04-30 12:56:25 +02:00
Miroslav Lichvar
b626fe661e doc: list build requirements in installation 2019-04-30 12:56:25 +02:00
Miroslav Lichvar
ba8fcd145d doc: improve combinelimit description 2019-04-26 11:19:20 +02:00
Miroslav Lichvar
981d09de40 doc: improve rtconutc description 2019-04-26 11:12:41 +02:00
Miroslav Lichvar
86a99bb257 test: use env in shebang of system tests
This should allow the tests to run on systems where bash is not in /bin.
2019-04-26 10:54:02 +02:00
Miroslav Lichvar
3093a11cd0 test: add 104-systemdirs system test 2019-04-25 18:58:01 +02:00
Miroslav Lichvar
058b788d38 test: fix owner of driftfile and keys in system tests 2019-04-25 18:57:39 +02:00
Miroslav Lichvar
66a42fa493 test: allow separate lib/log/run directories in system tests 2019-04-25 18:55:56 +02:00
Miroslav Lichvar
a85f63cc15 test: check if non-root user can access test directory 2019-04-25 18:24:50 +02:00
Miroslav Lichvar
bbe1e69dcc test: redirect error messages in system tests 2019-04-25 18:24:41 +02:00
Miroslav Lichvar
1b52bba7b9 test: allow TEST_DIR and CHRONYC_WRAPPER to be set for system tests 2019-04-25 17:29:34 +02:00
Stefan R. Filipek
c5c80ef400 sys_posix: support SCHED_FIFO and mlockall on more OSs
Real-time scheduling and memory locking is available on posix compliant
OSs. This patch centralizes this functionality and brings support to
FreeBSD, NetBSD, and Solaris.

[ML: updated coding style]
2019-04-24 12:18:07 +02:00
Miroslav Lichvar
a78031ce0d refclock: check all driver options
In each driver provide a list of supported options and abort when an
unknown option is specified in the refclock directive.
2019-04-18 16:27:47 +02:00
Miroslav Lichvar
34e9dd13ce doc: fix syntax of refclock directive
When multiple driver options are specified, they need to be separated by
colon, not comma.
2019-04-18 16:27:19 +02:00
Miroslav Lichvar
6e52a9be7a test: add system tests
Add a new set of tests for testing basic functionality, starting chronyd
with root privileges on the actual system instead of the simulator.

Tests numbered in the 100-199 range are considered destructive and
intended to be used only on machines dedicated for development or
testing. They are started by the run script only with the -d option.
They may adjust/step the system clock and other clocks, block the RTC,
enable HW timestamping, create SHM segments, etc.

Other tests should not interfere with the system and should work even
when another NTP server/client is running.
2019-04-18 16:11:45 +02:00
Stefan R. Filipek
69c6dffd63 sys_linux: use pthread_setschedparam instead of sched_setscheduler
Fix an issue with Linux and musl libc where sched_setscheduler is not
implemented. It seems that pthread_setschedparam is more widely
supported across different C libraries and OSs. For our use case, it
should make no difference which call is used.
2019-04-08 16:38:38 +02:00
Vincent Blut
2ddd0ae231 sys_linux: allow further syscalls in seccomp filter
These are needed on arm64.
2019-03-18 14:24:54 +01:00
Leigh Brown
79db0b7eca sys_linux: allow recv and send in seccomp filter 2019-03-14 09:07:15 +01:00
Vincent Blut
2ebba7fbaa sys_linux: allow waitpid in seccomp filter 2019-02-28 17:42:02 +01:00
Vincent Blut
e392d1fde9 sys_linux: allow _llseek in seccomp filter
This is needed on various 32-bit platforms to reposition read/write file
offset on {raw}measurements and statistics log files.
2019-02-28 16:19:05 +01:00
Miroslav Lichvar
d7c93ec950 test: fix distribution of settings in ntp_core unit test 2019-02-20 10:11:58 +01:00
Miroslav Lichvar
6af39d63aa ntp: don't use IP_SENDSRCADDR on bound socket
On FreeBSD, sendmsg() fails when IP_SENDSRCADDR specifies a source
address on a socket that is bound to the address. This prevents a server
configured with the bindaddress directive from responding to clients.

Add a new variable to check whether the server IPv4 socket is not bound
before setting the source address.
2018-12-03 16:08:08 +01:00
Miroslav Lichvar
cc8414b1b3 sys_linux: add support for PTP_SYS_OFFSET_EXTENDED ioctl
A new ioctl will probably be added in Linux 4.21. It should enable a
significantly more accurate measurement of the offset between PHC and
system clock.
2018-11-27 14:56:17 +01:00
Miroslav Lichvar
6b44055e3d sys_linux: split reading and processing of PHC samples 2018-11-27 14:51:25 +01:00
Miroslav Lichvar
9f9c6cc6ab ntp: fix transposition with timestamping packet info
Don't forget to include the length of the frame check sequence (FCS) in
the RX timestamp transposition when the L2 length of the received packet
is from SCM_TIMESTAMPING_PKTINFO.

This fixes commit 934d4047f1.
2018-10-08 15:54:07 +02:00
Bryan Christianson
f176193d35 sys_macosx: remove adjtime() check
Remove the runtime checking of adjtime(). adjtime() was broken in beta
releases of macOS 10.13 but is ok now.
2018-10-02 10:50:04 +02:00
Miroslav Lichvar
e8bc41e862 test: fix tests to skip when missing required feature 2018-09-27 11:42:38 +02:00
Miroslav Lichvar
91dbe3c6c2 test: allow unit tests to be skipped 2018-09-27 11:42:38 +02:00
Miroslav Lichvar
3e876d4218 test: add function for checking config.h in tests 2018-09-27 11:42:38 +02:00
Miroslav Lichvar
31b1f2e8a1 test: include util.h for MIN macro 2018-09-27 11:42:38 +02:00
Miroslav Lichvar
4169e94b1d nameserv: adopt some include directives from sysincl.h
Move headers specific to name resolving to nameserv.c. This should hide
the system MIN/MAX macros from the rest of the code.
2018-09-20 15:34:24 +02:00
Miroslav Lichvar
948ecf8431 hash: include util.h for MIN macro
The hash_intmd5.c file inadvertently relied on the system headers to
provide the MIN macro, but it is missing with some libc implementations.
2018-09-20 15:34:24 +02:00
Miroslav Lichvar
91f3f97ea7 test: fix Makefile to not create .deps in project root 2018-09-19 16:38:15 +02:00
Miroslav Lichvar
65bb65b440 doc: add new question to FAQ 2018-09-17 18:38:46 +02:00
Miroslav Lichvar
ea6e8d85a3 doc: improve description of minsamples directive 2018-09-17 18:38:24 +02:00
Miroslav Lichvar
add932501f test: add 136-broadcast test 2018-09-17 18:36:22 +02:00
Miroslav Lichvar
89390a738f test: add 012-daemonts test 2018-09-17 18:36:22 +02:00
Miroslav Lichvar
ac4f6ab93b test: improve Makefile
The -s option of make apparently doesn't work when called from make -C.
Add another filter to ignore the Entering/Leaving messages.

Also, fix a typo.
2018-09-13 16:29:49 +02:00
Miroslav Lichvar
dbcb1b9b0b test: include all objects in prerequisites of unit tests 2018-09-13 11:23:16 +02:00
Miroslav Lichvar
6375307798 test: get list of objects from main Makefile
Instead of linking unit tests with *.o in the root directory, which may
include conflicting objects from a different configuration (e.g. hash),
add a print target to the main Makefile and use it in the unit test
Makefile to link only with objects that are relevant in the current
configuration.
2018-09-13 11:23:16 +02:00
Miroslav Lichvar
fb78e60d26 test: add 135-ratelimit test 2018-09-12 19:27:48 +02:00
Miroslav Lichvar
b822c7164f test: add 134-log test 2018-09-12 19:04:11 +02:00
Miroslav Lichvar
aa295730a0 test: extend 110-chronyc test 2018-09-12 18:17:35 +02:00
Miroslav Lichvar
69d70703b2 git: update .gitignore 2018-09-12 17:16:33 +02:00
Miroslav Lichvar
b2b6ef00dc makefile: remove gcov files and core dumps 2018-09-12 17:15:30 +02:00
Miroslav Lichvar
5dc86c236b update copyright years 2018-09-12 11:38:10 +02:00
Miroslav Lichvar
2563dd9d29 examples: drop chrony.spec
The example spec file was too limited to be recommended for use in any
rpm-based distribution, e.g. it didn't configure chronyd to drop the
root privileges.

Users that want to build a package from the latest source code should
start with the official package of their distribution.
2018-09-12 11:38:10 +02:00
Miroslav Lichvar
a899e3df33 examples: improve description in chrony.keys example 2018-09-12 11:38:08 +02:00
Miroslav Lichvar
692cea49f8 doc: warn about permissions in keyfile description 2018-09-12 10:43:01 +02:00
Miroslav Lichvar
bcedacaa3d test: fix samplefilt unit test to work with low-precision clock 2018-09-10 14:56:03 +02:00
Miroslav Lichvar
be3c1b5243 samplefilt: use SQUARE macro in SPF_CreateInstance() 2018-09-10 13:20:14 +02:00
Miroslav Lichvar
e626ec6c37 examples: update chrony.conf example for new default pidfile 2018-09-10 10:37:37 +02:00
Miroslav Lichvar
49d52b547f test: make 129-reload more reliable 2018-08-31 12:48:36 +02:00
Miroslav Lichvar
74a546a9e7 configure: fix compiler warning in pthread test code 2018-08-31 11:04:36 +02:00
83 changed files with 1583 additions and 428 deletions

3
.gitignore vendored
View File

@@ -1,9 +1,12 @@
.deps
.vimrc
*.gcda
*.gcno
*.o
*.swp
*.dSYM
*.DS_Store
core.*
tags
/RELEASES
/Makefile

View File

@@ -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

26
NEWS
View File

@@ -1,3 +1,29 @@
New in version 3.5.1
====================
Security fixes
--------------
* Create new file when writing pidfile (CVE-2020-14367)
New in version 3.5
==================
Enhancements
------------
* Add support for more accurate reading of PHC on Linux 5.0
* Add support for hardware timestamping on interfaces with read-only
timestamping configuration
* Add support for memory locking and real-time priority on FreeBSD,
NetBSD, Solaris
* Update seccomp filter to work on more architectures
* Validate refclock driver options
Bug fixes
---------
* Fix bindaddress directive on FreeBSD
* Fix transposition of hardware RX timestamp on Linux 4.13 and later
* Fix building on non-glibc systems
New in version 3.4
==================

109
README
View File

@@ -108,132 +108,57 @@ The following people have provided patches and other major contributions
to the program :
Lonnie Abelbeck <lonnie@abelbeck.com>
Patch to add tab-completion to chronyc
Benny Lyne Amorsen <benny@amorsen.dk>
Patch to add minstratum option
Andrew Bishop <amb@gedanken.demon.co.uk>
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 <vincent.debian@free.fr>
Stephan I. Boettcher <stephan@nevis1.columbia.edu>
Entries in contrib directory
Goswin Brederlow <brederlo@informatik.uni-tuebingen.de>
Leigh Brown <leigh@solinno.co.uk>
Erik Bryer <ebryer@spots.ab.ca>
Entries in contrib directory
Jonathan Cameron <jic23@cam.ac.uk>
Bryan Christianson <bryan@whatroute.net>
Support for macOS
Support for privilege separation
Entries in contrib directory
Juliusz Chroboczek <jch@pps.jussieu.fr>
Patch to fix install rule in Makefile if chronyd file is in use
Christian Ehrhardt <christian.ehrhardt@canonical.com>
Patch to generate a warning message when CAP_SYS_TIME is missing
Paul Elliott <pelliott@io.com>
Entries in contrib directory
Stefan R. Filipek <srfilipek@gmail.com>
Mike Fleetwood <mike@rockover.demon.co.uk>
Fixes for compiler warnings
Alexander Gretencord <arutha@gmx.de>
Changes to installation directory system to make it easier for
package builders
Andrew Griffiths <agriffit@redhat.com>
Patch to add support for seccomp filter
Walter Haidinger <walter.haidinger@gmx.at>
Access to a Linux installation where v1.12 wouldn't compile
Disc space for an independent backup of the sources
Juergen Hannken-Illjes <hannken@eis.cs.tu-bs.de>
Port to NetBSD
John Hasler <john@dhh.gt.org>
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 <t.hattink@fugro.nl>
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 <me@liamhatton.com>
Advice on configuring for Linux on PPC
Jachym Holecek <jakym@volny.cz>
Patch to make Linux real time clock work with devfs
Håkan Johansson <f96hajo@chalmers.se>
Patch to avoid large values in sources and sourcestats output
Jim Knoble <jmknoble@pobox.com>
Fixes for compiler warnings
Antti Jrvinen <costello@iki.fi>
Advice on configuring for BSD/386
Eric Lammerts <eric@lammerts.org>
Stefan Lucke <stefan@lucke.in-berlin.de>
Victor Lum <viclum@vanu.com>
Kevin Lyda <kevin@ie.suberic.net>
Paul Menzel <paulepanter@users.sourceforge.net>
Vladimir Michl <vladimir.michl@seznam.cz>
Victor Moroz <vim@prv.adlum.ru>
Patch to support Linux with HZ!=100
Kalle Olavi Niemitalo <tosi@stekt.oulu.fi>
Patch to add acquisitionport directive
Frank Otto <sandwichmacher@web.de>
Handling arbitrary HZ values
Denny Page <dennypage@me.com>
Advice on support for hardware timestamping
Chris Perl <cperl@janestreet.com>
Patches to improve support for refclocks keeping time in TAI
Gautier PHILIPPON <gautier.philippon@ensimag.grenoble-inp.fr>
Patch to add refresh command to chronyc
Andreas Piesk <apiesk@virbus.de>
Patch to make chronyc use the readline library if available
Andreas Steinmetz <ast@domdv.de>
Patch to make stratum of refclocks configurable
NAKAMURA Takumi <takumi@ps.sakura.ne.jp>
Timo Teras <timo.teras@iki.fi>
Patch to reply correctly on multihomed hosts
Bill Unruh <unruh@physics.ubc.ca>
Advice on statistics
Stephen Wadeley <swadeley@redhat.com>
Improvements to man pages
Bernhard Weiss <lisnablagh@web.de>
Wolfgang Weisselberg <weissel@netcologne.de>
Entries in contrib directory
Bernhard M. Wiedemann <bwiedemann@suse.de>
Joachim Wiedorn <ad_debian@joonet.de>
Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
Many robustness and security improvements
Ulrich Windl <ulrich.windl@rz.uni-regensburg.de> for the
Information about the Linux 2.2 kernel functionality compared to 2.0
Ulrich Windl <ulrich.windl@rz.uni-regensburg.de>
Doug Woodward <dougw@whistler.com>
Advice on configuring for Solaris 2.8 on x86
Thomas Zajic <zlatko@zlatko.fdns.net>
Many other people have contributed bug reports and suggestions. We are sorry
we cannot identify all of you individually.

View File

@@ -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
@@ -3159,7 +3159,7 @@ static void
display_gpl(void)
{
printf("chrony version %s\n"
"Copyright (C) 1997-2003, 2007, 2009-2018 Richard P. Curnow and others\n"
"Copyright (C) 1997-2003, 2007, 2009-2019 Richard P. Curnow and others\n"
"chrony comes with ABSOLUTELY NO WARRANTY. This is free software, and\n"
"you are welcome to redistribute it under certain conditions. See the\n"
"GNU General Public License version 2 for details.\n\n",

View File

@@ -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

46
configure vendored
View File

@@ -6,6 +6,7 @@
# Copyright (C) Richard P. Curnow 1997-2003
# Copyright (C) Bryan Christianson 2016
# Copyright (C) Miroslav Lichvar 2009, 2012-2018
# Copyright (C) Stefan R. Filipek 2019
#
# =======================================================================
@@ -227,6 +228,7 @@ feat_timestamping=1
try_timestamping=0
feat_ntp_signd=0
ntp_era_split=""
use_pthread=0
default_user="root"
default_hwclockfile=""
default_pidfile="/var/run/chrony/chronyd.pid"
@@ -395,7 +397,7 @@ SYSTEM=${OPERATINGSYSTEM}-${MACHINE}
case $OPERATINGSYSTEM in
Linux)
EXTRA_OBJECTS="sys_generic.o sys_linux.o sys_timex.o"
EXTRA_OBJECTS="sys_generic.o sys_linux.o sys_timex.o sys_posix.o"
[ $try_libcap != "0" ] && try_libcap=1
try_rtc=1
[ $try_seccomp != "0" ] && try_seccomp=1
@@ -410,7 +412,9 @@ case $OPERATINGSYSTEM in
# recvmmsg() seems to be broken on FreeBSD 11.0 and it's just
# a wrapper around recvmsg()
try_recvmmsg=0
EXTRA_OBJECTS="sys_generic.o sys_netbsd.o sys_timex.o"
EXTRA_OBJECTS="sys_generic.o sys_netbsd.o sys_timex.o sys_posix.o"
try_setsched=1
try_lockmem=1
add_def FREEBSD
if [ $feat_droproot = "1" ]; then
add_def FEAT_PRIVDROP
@@ -419,8 +423,10 @@ case $OPERATINGSYSTEM in
echo "Configuring for $SYSTEM"
;;
NetBSD)
EXTRA_OBJECTS="sys_generic.o sys_netbsd.o sys_timex.o"
EXTRA_OBJECTS="sys_generic.o sys_netbsd.o sys_timex.o sys_posix.o"
try_clockctl=1
try_setsched=1
try_lockmem=1
add_def NETBSD
echo "Configuring for $SYSTEM"
;;
@@ -445,9 +451,11 @@ case $OPERATINGSYSTEM in
echo "Configuring for macOS (" $SYSTEM "macOS version" $VERSION ")"
;;
SunOS)
EXTRA_OBJECTS="sys_generic.o sys_solaris.o sys_timex.o"
EXTRA_OBJECTS="sys_generic.o sys_solaris.o sys_timex.o sys_posix.o"
EXTRA_LIBS="-lsocket -lnsl -lresolv"
EXTRA_CLI_LIBS="-lsocket -lnsl -lresolv"
try_setsched=1
try_lockmem=1
add_def SOLARIS
# These are needed to have msg_control in struct msghdr
add_def __EXTENSIONS__
@@ -647,12 +655,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 +794,33 @@ fi
if [ $try_setsched = "1" ] && \
test_code \
'sched_setscheduler()' \
'sched.h' '' '' '
'pthread_setschedparam()' \
'pthread.h sched.h' '-pthread' '' '
struct sched_param sched;
sched_get_priority_max(SCHED_FIFO);
sched_setscheduler(0, SCHED_FIFO, &sched);'
pthread_setschedparam(pthread_self(), SCHED_FIFO, &sched);'
then
add_def HAVE_SCHED_SETSCHEDULER
add_def HAVE_PTHREAD_SETSCHEDPARAM
use_pthread=1
fi
if [ $try_lockmem = "1" ] && \
test_code \
'mlockall()' \
'sys/mman.h sys/resource.h' '' '' '
struct rlimit rlim;
setrlimit(RLIMIT_MEMLOCK, &rlim);
'sys/mman.h' '' '' '
mlockall(MCL_CURRENT|MCL_FUTURE);'
then
add_def HAVE_MLOCKALL
fi
if [ $try_lockmem = "1" ] && \
test_code \
'setrlimit(RLIMIT_MEMLOCK, ...)' \
'sys/resource.h' '' '' '
struct rlimit rlim;
setrlimit(RLIMIT_MEMLOCK, &rlim);'
then
add_def HAVE_SETRLIMIT_MEMLOCK
fi
if [ $feat_forcednsretry = "1" ]
then
@@ -896,6 +912,10 @@ if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_tomcrypt = "1" ]
fi
fi
if [ $use_pthread = "1" ]; then
MYCFLAGS="$MYCFLAGS -pthread"
fi
SYSCONFDIR=/etc
if [ "x$SETSYSCONFDIR" != "x" ]; then
SYSCONFDIR=$SETSYSCONFDIR

View File

@@ -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 <<server,*server*>> and <<refclock,*refclock*>>
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
<<chronyc.adoc#tracking,*tracking*>> and
<<chronyc.adoc#sourcestats,*sourcestats*>> 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 <<hwclockfile,*hwclockfile*>>
directive is specified.
Note that this setting is overridden by the <<hwclockfile,*hwclockfile*>> file
and is not relevant for the <<rtcsync,*rtcsync*>> 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 <<chronyc.adoc#keygen,*keygen*>> 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 <<chronyc.adoc#rekey,*rekey*>> 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, 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 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 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

View File

@@ -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,33 @@ 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
----
Note that increasing `minsamples` may cause the offsets in the `tracking` and
`sourcestats` reports/logs to be significantly smaller than the actual offsets
and be unsuitable for monitoring.
=== What happened to the `commandkey` and `generatecommandkey` directives?
They were removed in version 2.2. Authentication is no longer supported in the

View File

@@ -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
----

View File

@@ -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

View File

@@ -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.

View File

@@ -1,46 +0,0 @@
%global chrony_version @@VERSION@@
%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

View File

@@ -7,7 +7,7 @@ ConditionCapability=CAP_SYS_TIME
[Service]
Type=forking
PIDFile=/var/run/chrony/chronyd.pid
PIDFile=/run/chrony/chronyd.pid
EnvironmentFile=-/etc/sysconfig/chronyd
ExecStart=/usr/sbin/chronyd $OPTIONS
PrivateTmp=yes

View File

@@ -29,6 +29,7 @@
#include "sysincl.h"
#include "hash.h"
#include "memory.h"
#include "util.h"
#include "md5.c"

View File

@@ -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

View File

@@ -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

View File

@@ -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
@@ -171,6 +171,7 @@ void LOG_Message(LOG_Severity severity,
system_log = 0;
log_message(1, severity, buf);
}
exit(1);
break;
default:
assert(0);

12
main.c
View File

@@ -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
@@ -281,13 +281,9 @@ write_pidfile(void)
if (!pidfile[0])
return;
out = fopen(pidfile, "w");
if (!out) {
LOG_FATAL("Could not open %s : %s", pidfile, strerror(errno));
} else {
fprintf(out, "%d\n", (int)getpid());
fclose(out);
}
out = UTI_OpenFile(NULL, pidfile, NULL, 'W', 0644);
fprintf(out, "%d\n", (int)getpid());
fclose(out);
}
/* ================================================== */

View File

@@ -36,8 +36,6 @@ cd RELEASES/$subdir || exit 1
echo $version > version.txt
sed -i -e "s%@@VERSION@@%${version}%" examples/chrony.spec
./configure && make -C doc man txt || exit 1
iconv -f utf-8 -t ascii//TRANSLIT < doc/installation.txt > INSTALL

View File

@@ -30,6 +30,9 @@
#include "sysincl.h"
#include <netdb.h>
#include <resolv.h>
#include "nameserv.h"
#include "util.h"

View File

@@ -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) {

View File

@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2016-2018
* Copyright (C) Miroslav Lichvar 2016-2019
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -123,7 +123,7 @@ add_interface(CNF_HwTsInterface *conf_iface)
struct ethtool_ts_info ts_info;
struct hwtstamp_config ts_config;
struct ifreq req;
int sock_fd, if_index, phc_fd, req_hwts_flags;
int sock_fd, if_index, phc_fd, req_hwts_flags, rx_filter;
unsigned int i;
struct Interface *iface;
@@ -177,40 +177,51 @@ add_interface(CNF_HwTsInterface *conf_iface)
return 0;
}
ts_config.flags = 0;
ts_config.tx_type = HWTSTAMP_TX_ON;
switch (conf_iface->rxfilter) {
case CNF_HWTS_RXFILTER_ANY:
#ifdef HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP
if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_NTP_ALL))
ts_config.rx_filter = HWTSTAMP_FILTER_NTP_ALL;
rx_filter = HWTSTAMP_FILTER_NTP_ALL;
else
#endif
if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_ALL))
ts_config.rx_filter = HWTSTAMP_FILTER_ALL;
rx_filter = HWTSTAMP_FILTER_ALL;
else
ts_config.rx_filter = HWTSTAMP_FILTER_NONE;
rx_filter = HWTSTAMP_FILTER_NONE;
break;
case CNF_HWTS_RXFILTER_NONE:
ts_config.rx_filter = HWTSTAMP_FILTER_NONE;
rx_filter = HWTSTAMP_FILTER_NONE;
break;
#ifdef HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP
case CNF_HWTS_RXFILTER_NTP:
ts_config.rx_filter = HWTSTAMP_FILTER_NTP_ALL;
rx_filter = HWTSTAMP_FILTER_NTP_ALL;
break;
#endif
default:
ts_config.rx_filter = HWTSTAMP_FILTER_ALL;
rx_filter = HWTSTAMP_FILTER_ALL;
break;
}
ts_config.flags = 0;
ts_config.tx_type = HWTSTAMP_TX_ON;
ts_config.rx_filter = rx_filter;
req.ifr_data = (char *)&ts_config;
if (ioctl(sock_fd, SIOCSHWTSTAMP, &req)) {
DEBUG_LOG("ioctl(%s) failed : %s", "SIOCSHWTSTAMP", strerror(errno));
close(sock_fd);
return 0;
/* Check the current timestamping configuration in case this interface
allows only reading of the configuration and it was already configured
as requested */
req.ifr_data = (char *)&ts_config;
#ifdef SIOCGHWTSTAMP
if (ioctl(sock_fd, SIOCGHWTSTAMP, &req) ||
ts_config.tx_type != HWTSTAMP_TX_ON || ts_config.rx_filter != rx_filter)
#endif
{
close(sock_fd);
return 0;
}
}
close(sock_fd);
@@ -584,7 +595,11 @@ process_hw_timestamp(struct Interface *iface, struct timespec *hw_ts,
if (rx_ntp_length && iface->link_speed) {
if (!l2_length)
l2_length = (family == IPADDR_INET4 ? iface->l2_udp4_ntp_start :
iface->l2_udp6_ntp_start) + rx_ntp_length + 4;
iface->l2_udp6_ntp_start) + rx_ntp_length;
/* Include the frame check sequence (FCS) */
l2_length += 4;
rx_correction = l2_length / (1.0e6 / 8 * iface->link_speed);
UTI_AddDoubleToTimespec(hw_ts, rx_correction, hw_ts);
@@ -841,7 +856,12 @@ NIO_Linux_RequestTxTimestamp(struct msghdr *msg, int cmsglen, int sock_fd)
/* Add control message that will enable TX timestamping for this message.
Don't use CMSG_NXTHDR as the one in glibc is buggy for creating new
control messages. */
cmsg = (struct cmsghdr *)((char *)CMSG_FIRSTHDR(msg) + cmsglen);
cmsg = CMSG_FIRSTHDR(msg);
if (!cmsg || cmsglen + CMSG_SPACE(sizeof (ts_tx_flags)) > msg->msg_controllen)
return cmsglen;
cmsg = (struct cmsghdr *)((char *)cmsg + cmsglen);
memset(cmsg, 0, CMSG_SPACE(sizeof (ts_tx_flags)));
cmsglen += CMSG_SPACE(sizeof (ts_tx_flags));

View File

@@ -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-2019
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -325,25 +325,57 @@ RCL_GetDriverParameter(RCL_Instance instance)
return instance->driver_parameter;
}
static char *
get_next_driver_option(RCL_Instance instance, char *option)
{
if (option == NULL)
option = instance->driver_parameter;
option += strlen(option) + 1;
if (option >= instance->driver_parameter + instance->driver_parameter_length)
return NULL;
return option;
}
void
RCL_CheckDriverOptions(RCL_Instance instance, const char **options)
{
char *option;
int i, len;
for (option = get_next_driver_option(instance, NULL);
option;
option = get_next_driver_option(instance, option)) {
for (i = 0; options && options[i]; i++) {
len = strlen(options[i]);
if (!strncmp(options[i], option, len) &&
(option[len] == '=' || option[len] == '\0'))
break;
}
if (!options || !options[i])
LOG_FATAL("Invalid refclock driver option %s", option);
}
}
char *
RCL_GetDriverOption(RCL_Instance instance, char *name)
{
char *s, *e;
int n;
char *option;
int len;
s = instance->driver_parameter;
e = s + instance->driver_parameter_length;
n = strlen(name);
len = strlen(name);
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;
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;
}
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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

13
sys.c
View File

@@ -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

View File

@@ -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 <sys/utsname.h>
#if defined(HAVE_SCHED_SETSCHEDULER)
# include <sched.h>
#endif
#if defined(HAVE_MLOCKALL)
# include <sys/mman.h>
#include <sys/resource.h>
#endif
#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING)
#include <linux/ptp_clock.h>
#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;

View File

@@ -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);

View File

@@ -49,10 +49,8 @@
#ifdef HAVE_MACOS_SYS_TIMEX
#include <dlfcn.h>
#include "sys_netbsd.h"
#include "sys_timex.h"
static int have_ntp_adjtime = 0;
static int have_bad_adjtime = 0;
#endif
/* ================================================== */
@@ -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

109
sys_posix.c Normal file
View File

@@ -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 <sys/utsname.h>
#if defined(HAVE_PTHREAD_SETSCHEDPARAM)
#include <pthread.h>
#include <sched.h>
#endif
#if defined(HAVE_MLOCKALL)
#include <sys/mman.h>
#endif
#if defined(HAVE_SETRLIMIT_MEMLOCK)
#include <sys/resource.h>
#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 */

36
sys_posix.h Normal file
View File

@@ -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 */

View File

@@ -37,11 +37,10 @@
#include <glob.h>
#include <grp.h>
#include <inttypes.h>
#include <limits.h>
#include <math.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pwd.h>
#include <resolv.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>

View File

@@ -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')

15
test/simulation/012-daemonts Executable file
View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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]

View File

@@ -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"

View File

@@ -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"

View File

@@ -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

View File

@@ -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]

View File

@@ -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

View File

@@ -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

View File

@@ -4,6 +4,8 @@
test_start "hwtimestamp directive"
check_config_h 'HAVE_LINUX_TIMESTAMPING 1' || test_skip
export CLKNETSIM_TIMESTAMPING=2
refclock_jitter=1e-8
@@ -11,22 +13,25 @@ refclock_offset=10.0
min_sync_time=4
max_sync_time=20
limit=200
client_conf="hwtimestamp eth0"
client_server_options="minpoll 0 maxpoll 0 minsamples 32"
server_conf="hwtimestamp eth0"
client_server_options="minpoll 0 maxpoll 0 minsamples 32 xleave"
client_chronyd_options="-d"
run_test || test_fail
check_chronyd_exit || test_fail
check_source_selection || test_fail
check_sync || test_fail
for client_conf in "hwtimestamp eth0" "hwtimestamp eth0
acquisitionport 123"; do
run_test || test_fail
check_chronyd_exit || test_fail
check_source_selection || test_fail
check_sync || test_fail
if grep -q 'FEAT_DEBUG 1' ../../config.h; then
check_log_messages "HW clock samples" 190 200 || test_fail
check_log_messages "HW clock reset" 0 0 || test_fail
check_log_messages "Received.*tss=1" 1 1 || test_fail
check_log_messages "Received.*tss=2" 390 400 || test_fail
check_log_messages "update_tx_timestamp.*Updated" 50 140 || test_fail
check_log_messages "update_tx_timestamp.*Unacceptable" 50 140 || test_fail
fi
if check_config_h 'FEAT_DEBUG 1'; then
check_log_messages "HW clock samples" 190 200 || test_fail
check_log_messages "HW clock reset" 0 0 || test_fail
check_log_messages "Received.*tss=1" 1 1 || test_fail
check_log_messages "Received.*tss=2" 390 400 || test_fail
check_log_messages "update_tx_timestamp.*Updated" 50 140 || test_fail
check_log_messages "update_tx_timestamp.*Unacceptable" 50 140 || test_fail
fi
done
test_pass

33
test/simulation/134-log Executable file
View File

@@ -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

18
test/simulation/135-ratelimit Executable file
View File

@@ -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

16
test/simulation/136-broadcast Executable file
View File

@@ -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

View File

@@ -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

13
test/system/001-minimal Executable file
View File

@@ -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

13
test/system/002-extended Executable file
View File

@@ -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

15
test/system/003-memlock Executable file
View File

@@ -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

15
test/system/004-priority Executable file
View File

@@ -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

17
test/system/005-scfilter Executable file
View File

@@ -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

17
test/system/006-privdrop Executable file
View File

@@ -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

69
test/system/007-cmdmon Executable file
View File

@@ -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

30
test/system/100-clockupdate Executable file
View File

@@ -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

19
test/system/101-rtc Executable file
View File

@@ -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

28
test/system/102-hwtimestamp Executable file
View File

@@ -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

19
test/system/103-refclock Executable file
View File

@@ -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

19
test/system/104-systemdirs Executable file
View File

@@ -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

64
test/system/run Executable file
View File

@@ -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 ]

339
test/system/test.common Normal file
View File

@@ -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
}

View File

@@ -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

View File

@@ -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

View File

@@ -28,6 +28,8 @@
#include <local.h>
#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(&current_time);
@@ -475,3 +475,11 @@ test_unit(void)
CNF_Finalise();
HSH_Finalise();
}
#else
void
test_unit(void)
{
TEST_REQUIRE(0);
}
#endif

View File

@@ -18,10 +18,14 @@
**********************************************************************
*/
#include <config.h>
#include "test.h"
#ifdef FEAT_NTP
#include <ntp_sources.c>
#include <conf.h>
#include <ntp_io.h>
#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

View File

@@ -18,9 +18,13 @@
**********************************************************************
*/
#include <samplefilt.c>
#include <local.h>
#include "test.h"
#define LCL_GetSysPrecisionAsQuantum() (1.0e-6)
#include <samplefilt.c>
void
test_unit(void)
{

View File

@@ -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

View File

@@ -22,6 +22,7 @@
#include <sysincl.h>
#include <logging.h>
#include <localp.h>
#include <util.h>
#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)
{

View File

@@ -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);

97
util.c
View File

@@ -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
@@ -1179,6 +1179,101 @@ UTI_CheckDirPermissions(const char *path, mode_t perm, uid_t uid, gid_t gid)
/* ================================================== */
static int
join_path(const char *basedir, const char *name, const char *suffix,
char *buffer, size_t length, LOG_Severity severity)
{
const char *sep;
if (!basedir) {
basedir = "";
sep = "";
} else {
sep = "/";
}
if (!suffix)
suffix = "";
if (snprintf(buffer, length, "%s%s%s%s", basedir, sep, name, suffix) >= length) {
LOG(severity, "File path %s%s%s%s too long", basedir, sep, name, suffix);
return 0;
}
return 1;
}
/* ================================================== */
FILE *
UTI_OpenFile(const char *basedir, const char *name, const char *suffix,
char mode, mode_t perm)
{
const char *file_mode;
char path[PATH_MAX];
LOG_Severity severity;
int fd, flags;
FILE *file;
severity = mode >= 'A' && mode <= 'Z' ? LOGS_FATAL : LOGS_ERR;
if (!join_path(basedir, name, suffix, path, sizeof (path), severity))
return NULL;
switch (mode) {
case 'r':
case 'R':
flags = O_RDONLY;
file_mode = "r";
if (severity != LOGS_FATAL)
severity = LOGS_DEBUG;
break;
case 'w':
case 'W':
flags = O_WRONLY | O_CREAT | O_EXCL;
file_mode = "w";
break;
case 'a':
case 'A':
flags = O_WRONLY | O_CREAT | O_APPEND;
file_mode = "a";
break;
default:
assert(0);
return NULL;
}
try_again:
fd = open(path, flags, perm);
if (fd < 0) {
if (errno == EEXIST) {
if (unlink(path) < 0) {
LOG(severity, "Could not remove %s : %s", path, strerror(errno));
return NULL;
}
DEBUG_LOG("Removed %s", path);
goto try_again;
}
LOG(severity, "Could not open %s : %s", path, strerror(errno));
return NULL;
}
UTI_FdSetCloexec(fd);
file = fdopen(fd, file_mode);
if (!file) {
LOG(severity, "Could not open %s : %s", path, strerror(errno));
close(fd);
return NULL;
}
DEBUG_LOG("Opened %s fd=%d mode=%c", path, fd, mode);
return file;
}
/* ================================================== */
void
UTI_DropRoot(uid_t uid, gid_t gid)
{

11
util.h
View File

@@ -176,6 +176,17 @@ extern int UTI_CreateDirAndParents(const char *path, mode_t mode, uid_t uid, gid
permissions and its uid/gid must match the specified values. */
extern int UTI_CheckDirPermissions(const char *path, mode_t perm, uid_t uid, gid_t gid);
/* Open a file. The full path of the file is constructed from the basedir
(may be NULL), '/' (if basedir is not NULL), name, and suffix (may be NULL).
Created files have specified permissions (umasked). Returns NULL on error.
The following modes are supported (if the mode is an uppercase character,
errors are fatal):
r/R - open an existing file for reading
w/W - open a new file for writing (remove existing file)
a/A - open an existing file for appending (create if does not exist) */
extern FILE *UTI_OpenFile(const char *basedir, const char *name, const char *suffix,
char mode, mode_t perm);
/* Set process user/group IDs and drop supplementary groups */
extern void UTI_DropRoot(uid_t uid, gid_t gid);