mirror of
https://gitlab.com/chrony/chrony.git
synced 2025-12-03 18:35:06 -05:00
Compare commits
115 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a466395a19 | ||
|
|
a3cb3fc490 | ||
|
|
3396778061 | ||
|
|
01cef64070 | ||
|
|
a9bfaf9e54 | ||
|
|
cec7c44f61 | ||
|
|
38ac2b39ce | ||
|
|
967e358dbc | ||
|
|
60721d2cc1 | ||
|
|
b698184939 | ||
|
|
c6c833fb9c | ||
|
|
3eb43f4619 | ||
|
|
440c159217 | ||
|
|
b49dcfbef7 | ||
|
|
a4d9cfaaeb | ||
|
|
7b2430fc3c | ||
|
|
bd8be7133d | ||
|
|
692ef0549b | ||
|
|
d6fdae5f1d | ||
|
|
8feb37df2b | ||
|
|
1d2b481069 | ||
|
|
c062fa2fa9 | ||
|
|
f444561a10 | ||
|
|
046f219a0e | ||
|
|
3cd32ed660 | ||
|
|
4f172f6f9f | ||
|
|
22fc0a6846 | ||
|
|
71e596b443 | ||
|
|
98c245ed7b | ||
|
|
bf57222e96 | ||
|
|
c075c070f0 | ||
|
|
4bc6950632 | ||
|
|
bde279c093 | ||
|
|
4f6ab8ac93 | ||
|
|
d2d82e2e5f | ||
|
|
1b2510e4b2 | ||
|
|
e735be59a7 | ||
|
|
5190539ce1 | ||
|
|
5776eb35b6 | ||
|
|
f102acd423 | ||
|
|
06486f3162 | ||
|
|
1619453b2b | ||
|
|
5a40950ffd | ||
|
|
16eb18e797 | ||
|
|
7bf0684557 | ||
|
|
961c490436 | ||
|
|
d8b0a4a288 | ||
|
|
76d12ac136 | ||
|
|
434faeecb8 | ||
|
|
ea2858b323 | ||
|
|
3391d5f846 | ||
|
|
7d6de7afe6 | ||
|
|
67ce6bd279 | ||
|
|
770db1fe02 | ||
|
|
d73394dde1 | ||
|
|
eb0c7e33d2 | ||
|
|
b9cfdaf666 | ||
|
|
5039f959e0 | ||
|
|
b7a54f8cd8 | ||
|
|
7b6435b2b8 | ||
|
|
8854c00d48 | ||
|
|
c0867b58f5 | ||
|
|
05183748a8 | ||
|
|
e56154a687 | ||
|
|
e5784c1ca8 | ||
|
|
282a9c7d7c | ||
|
|
b11ca92ca6 | ||
|
|
49846b3e68 | ||
|
|
0887824324 | ||
|
|
fbe65f2c71 | ||
|
|
eb5a412bed | ||
|
|
0cc8f68754 | ||
|
|
7079ca2718 | ||
|
|
70ad0bc573 | ||
|
|
22345c5ddf | ||
|
|
28b0a23949 | ||
|
|
1b57a796b1 | ||
|
|
0abb470022 | ||
|
|
b7a4b84f0a | ||
|
|
794a1e6cfe | ||
|
|
7c4db99d44 | ||
|
|
30b6213910 | ||
|
|
b6a27df5b9 | ||
|
|
18d514d552 | ||
|
|
f1ed08abf0 | ||
|
|
6d42dd8603 | ||
|
|
e7100e106d | ||
|
|
6402350c83 | ||
|
|
236576c124 | ||
|
|
9a83cab2f8 | ||
|
|
92706b158e | ||
|
|
ad34b26955 | ||
|
|
12c434fdc0 | ||
|
|
9ceaef6479 | ||
|
|
abb56bded2 | ||
|
|
0bcd10560a | ||
|
|
46b7148f3b | ||
|
|
37732130e1 | ||
|
|
7a3b1414cd | ||
|
|
a4a21c1dca | ||
|
|
206e597b04 | ||
|
|
ceef8ad2d8 | ||
|
|
2d581a6a86 | ||
|
|
82f7fa3887 | ||
|
|
f88a01e8c7 | ||
|
|
ca8e03b785 | ||
|
|
15932c9d7b | ||
|
|
0fc0f906e1 | ||
|
|
7f58852ec0 | ||
|
|
85a9a53e69 | ||
|
|
aa0c0fc401 | ||
|
|
0e694e08fc | ||
|
|
c2ddcc9f36 | ||
|
|
7a7cf6a5ce | ||
|
|
c2f83bd8a4 |
29
.gitignore
vendored
29
.gitignore
vendored
@@ -4,20 +4,21 @@
|
||||
*.swp
|
||||
*.dSYM
|
||||
*.DS_Store
|
||||
RELEASES
|
||||
Makefile
|
||||
chrony.conf.5
|
||||
chrony.info
|
||||
chrony.html
|
||||
chrony.texi
|
||||
chrony.txt
|
||||
chronyc
|
||||
chronyc.1
|
||||
chronyd
|
||||
chronyd.8
|
||||
config.h
|
||||
config.log
|
||||
tags
|
||||
version.h
|
||||
/RELEASES
|
||||
/Makefile
|
||||
/chrony.conf.5
|
||||
/chrony.info
|
||||
/chrony.html
|
||||
/chrony.texi
|
||||
/chrony.txt
|
||||
/chronyc
|
||||
/chronyc.1
|
||||
/chronyd
|
||||
/chronyd.8
|
||||
/config.h
|
||||
/config.log
|
||||
/getdate.c
|
||||
/version.h
|
||||
/test/simulation/clknetsim
|
||||
/test/simulation/tmp
|
||||
|
||||
16
Makefile.in
16
Makefile.in
@@ -38,13 +38,13 @@ DESTDIR=
|
||||
|
||||
HASH_OBJ = @HASH_OBJ@
|
||||
|
||||
OBJS = array.o cmdparse.o conf.o local.o logging.o main.o memory.o mkdirpp.o \
|
||||
OBJS = array.o cmdparse.o conf.o local.o logging.o main.o memory.o \
|
||||
reference.o regress.o rtc.o sched.o sources.o sourcestats.o stubs.o \
|
||||
sys.o smooth.o tempcomp.o util.o $(HASH_OBJ)
|
||||
|
||||
EXTRA_OBJS=@EXTRA_OBJECTS@
|
||||
|
||||
CLI_OBJS = client.o nameserv.o getdate.o cmdparse.o \
|
||||
CLI_OBJS = array.o client.o cmdparse.o getdate.o memory.o nameserv.o \
|
||||
pktlength.o util.o $(HASH_OBJ)
|
||||
|
||||
ALL_OBJS = $(OBJS) $(EXTRA_OBJS) $(CLI_OBJS)
|
||||
@@ -82,7 +82,7 @@ clean :
|
||||
-rm -rf .deps
|
||||
-rm -rf *.dSYM
|
||||
|
||||
getdate.c :
|
||||
getdate.c : getdate.y
|
||||
bison -o getdate.c getdate.y
|
||||
|
||||
# This can be used to force regeneration of getdate.c
|
||||
@@ -92,15 +92,13 @@ getdate :
|
||||
# For install, don't use the install command, because its switches
|
||||
# seem to vary between systems.
|
||||
|
||||
install: chronyd chronyc chrony.txt
|
||||
install: chronyd chronyc
|
||||
[ -d $(DESTDIR)$(SYSCONFDIR) ] || mkdir -p $(DESTDIR)$(SYSCONFDIR)
|
||||
[ -d $(DESTDIR)$(SBINDIR) ] || mkdir -p $(DESTDIR)$(SBINDIR)
|
||||
[ -d $(DESTDIR)$(BINDIR) ] || mkdir -p $(DESTDIR)$(BINDIR)
|
||||
[ -d $(DESTDIR)$(DOCDIR) ] || mkdir -p $(DESTDIR)$(DOCDIR)
|
||||
[ -d $(DESTDIR)$(MANDIR)/man1 ] || mkdir -p $(DESTDIR)$(MANDIR)/man1
|
||||
[ -d $(DESTDIR)$(MANDIR)/man5 ] || mkdir -p $(DESTDIR)$(MANDIR)/man5
|
||||
[ -d $(DESTDIR)$(MANDIR)/man8 ] || mkdir -p $(DESTDIR)$(MANDIR)/man8
|
||||
[ -d $(DESTDIR)$(DOCDIR) ] || mkdir -p $(DESTDIR)$(DOCDIR)
|
||||
[ -d $(DESTDIR)$(CHRONYVARDIR) ] || mkdir -p $(DESTDIR)$(CHRONYVARDIR)
|
||||
if [ -f $(DESTDIR)$(SBINDIR)/chronyd ]; then rm -f $(DESTDIR)$(SBINDIR)/chronyd ; fi
|
||||
if [ -f $(DESTDIR)$(BINDIR)/chronyc ]; then rm -f $(DESTDIR)$(BINDIR)/chronyc ; fi
|
||||
@@ -108,12 +106,6 @@ install: chronyd chronyc chrony.txt
|
||||
chmod 755 $(DESTDIR)$(SBINDIR)/chronyd
|
||||
cp chronyc $(DESTDIR)$(BINDIR)/chronyc
|
||||
chmod 755 $(DESTDIR)$(BINDIR)/chronyc
|
||||
cp chrony.txt $(DESTDIR)$(DOCDIR)/chrony.txt
|
||||
chmod 644 $(DESTDIR)$(DOCDIR)/chrony.txt
|
||||
cp COPYING $(DESTDIR)$(DOCDIR)/COPYING
|
||||
chmod 644 $(DESTDIR)$(DOCDIR)/COPYING
|
||||
cp README $(DESTDIR)$(DOCDIR)/README
|
||||
chmod 644 $(DESTDIR)$(DOCDIR)/README
|
||||
cp chronyc.1 $(DESTDIR)$(MANDIR)/man1
|
||||
chmod 644 $(DESTDIR)$(MANDIR)/man1/chronyc.1
|
||||
cp chronyd.8 $(DESTDIR)$(MANDIR)/man8
|
||||
|
||||
37
NEWS
37
NEWS
@@ -1,3 +1,40 @@
|
||||
New in version 2.2
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add support for configuration and monitoring over Unix domain socket
|
||||
(accessible by root or chrony user when root privileges are dropped)
|
||||
* Add support for system call filtering with seccomp on Linux
|
||||
* Add support for dropping root privileges on NetBSD
|
||||
* Control frequency of system clock on FreeBSD, NetBSD, Solaris
|
||||
* Add system leap second handling mode on FreeBSD, NetBSD, Solaris
|
||||
* Add dynamic drift removal on Mac OS X
|
||||
* Add support for setting real-time priority on Mac OS X
|
||||
* Add maxdistance directive to limit source selection by root distance
|
||||
* Add refresh command to get new addresses of NTP sources
|
||||
* Allow wildcard patterns in include directive
|
||||
* Add -d option to chronyc to enable debug messages
|
||||
* Allow multiple addresses to be specified for chronyc with -h option
|
||||
and reconnect when no valid reply is received
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix building on Solaris
|
||||
* Restore time from driftfile with -s option if reading RTC failed
|
||||
|
||||
Removed features
|
||||
----------------
|
||||
* Drop support for authentication with command key (run-time configuration
|
||||
is now allowed only for local users that can access the Unix domain socket)
|
||||
|
||||
New in version 2.1.1
|
||||
====================
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix clock stepping by integer number of seconds on Linux
|
||||
|
||||
New in version 2.1
|
||||
==================
|
||||
|
||||
|
||||
6
README
6
README
@@ -145,6 +145,9 @@ 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>
|
||||
Providing me with login access to a Linux installation where v1.12
|
||||
wouldn't compile, so I could develop the fixes for v1.13. Also, for
|
||||
@@ -204,6 +207,9 @@ Kalle Olavi Niemitalo <tosi@stekt.oulu.fi>
|
||||
Frank Otto <sandwichmacher@web.de>
|
||||
Handling arbitrary HZ values
|
||||
|
||||
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
|
||||
|
||||
|
||||
29
candm.h
29
candm.h
@@ -31,7 +31,6 @@
|
||||
|
||||
#include "sysincl.h"
|
||||
#include "addressing.h"
|
||||
#include "hash.h"
|
||||
|
||||
/* This is the default port to use for CANDM, if no alternative is
|
||||
defined */
|
||||
@@ -91,7 +90,8 @@
|
||||
#define REQ_MODIFY_MAKESTEP 50
|
||||
#define REQ_SMOOTHING 51
|
||||
#define REQ_SMOOTHTIME 52
|
||||
#define N_REQUEST_TYPES 53
|
||||
#define REQ_REFRESH 53
|
||||
#define N_REQUEST_TYPES 54
|
||||
|
||||
/* Special utoken value used to log on with first exchange being the
|
||||
password. (This time value has long since gone by) */
|
||||
@@ -336,6 +336,8 @@ typedef struct {
|
||||
Version 6 : added padding to requests to prevent amplification attack,
|
||||
changed maximum number of samples in manual list to 16, new commands: modify
|
||||
makestep, smoothing report, smoothtime command
|
||||
|
||||
Authentication was removed later in version 6.
|
||||
*/
|
||||
|
||||
#define PROTO_VERSION_NUMBER 6
|
||||
@@ -364,8 +366,8 @@ typedef struct {
|
||||
(count up from zero for same sequence
|
||||
number) */
|
||||
uint32_t sequence; /* Client's sequence number */
|
||||
uint32_t utoken; /* Unique token per incarnation of daemon */
|
||||
uint32_t token; /* Command token (to prevent replay attack) */
|
||||
uint32_t pad1;
|
||||
uint32_t pad2;
|
||||
|
||||
union {
|
||||
REQ_Null null;
|
||||
@@ -400,15 +402,10 @@ typedef struct {
|
||||
REQ_SmoothTime smoothtime;
|
||||
} data; /* Command specific parameters */
|
||||
|
||||
/* The following fields only set the maximum size of the packet.
|
||||
There are no holes between them and the actual data. */
|
||||
|
||||
/* Padding used to prevent traffic amplification */
|
||||
/* Padding used to prevent traffic amplification. It only defines the
|
||||
maximum size of the packet, there is no hole after the data field. */
|
||||
uint8_t padding[MAX_PADDING_LENGTH];
|
||||
|
||||
/* Authentication data */
|
||||
uint8_t auth[MAX_HASH_LENGTH];
|
||||
|
||||
} CMD_Request;
|
||||
|
||||
/* ================================================== */
|
||||
@@ -614,9 +611,9 @@ typedef struct {
|
||||
uint16_t pad2;
|
||||
uint16_t pad3;
|
||||
uint32_t sequence; /* Echo of client's sequence number */
|
||||
uint32_t utoken; /* Unique token per incarnation of daemon */
|
||||
uint32_t token; /* New command token (only if command was successfully
|
||||
authenticated) */
|
||||
uint32_t pad4;
|
||||
uint32_t pad5;
|
||||
|
||||
union {
|
||||
RPY_Null null;
|
||||
RPY_N_Sources n_sources;
|
||||
@@ -631,10 +628,6 @@ typedef struct {
|
||||
RPY_Smoothing smoothing;
|
||||
} data; /* Reply specific parameters */
|
||||
|
||||
/* authentication of the packet, there is no hole after the actual data
|
||||
from the data union, this field only sets the maximum auth size */
|
||||
uint8_t auth[MAX_HASH_LENGTH];
|
||||
|
||||
} CMD_Reply;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
527
chrony.texi.in
527
chrony.texi.in
@@ -120,8 +120,9 @@ different quirks in its behaviour.
|
||||
|
||||
The software is known to work on Linux, FreeBSD, NetBSD, Mac OS X and Solaris.
|
||||
Closely related systems may work too. Porting the software to other systems
|
||||
(particularly to those supporting an @code{adjtime} system call) should not be
|
||||
difficult, however it requires access to such systems to test out the driver.
|
||||
(particularly to those supporting an @code{adjtime} or @code{ntp_adjtime}
|
||||
system call) should not be difficult, however it requires access to such
|
||||
systems to test out the driver.
|
||||
@c }}}
|
||||
@c {{{ S:Other programs
|
||||
@node Other time synchronisation packages
|
||||
@@ -163,9 +164,9 @@ step the time too, but it has to use a different means of adjusting the
|
||||
clock, which has some
|
||||
disadvantages.
|
||||
@item
|
||||
@code{chronyd} can adjust the rate of the clock on Linux in a larger
|
||||
range, which allows it to operate even on machines with broken or
|
||||
unstable clock (e.g. in some virtual machines).
|
||||
@code{chronyd} can adjust the rate of the clock in a larger range, which
|
||||
allows it to operate even on machines with broken or unstable clock
|
||||
(e.g. in some virtual machines).
|
||||
@end itemize
|
||||
|
||||
Things @code{chronyd} can do that @code{ntpd} can't:
|
||||
@@ -387,9 +388,10 @@ entered.
|
||||
make install
|
||||
@end example
|
||||
|
||||
This will install the binaries, plain text manual and manpages.
|
||||
This will install the binaries and manpages.
|
||||
|
||||
To install the HTML and info versions of the manual as well, enter the command
|
||||
To install the plain text, HTML and info versions of the manual, enter the
|
||||
command
|
||||
|
||||
@example
|
||||
make install-docs
|
||||
@@ -635,16 +637,9 @@ server bar.example.net offline
|
||||
server baz.example.net offline
|
||||
@end example
|
||||
|
||||
The @code{offline} keyword indicates that the servers start
|
||||
in an offline state, and that they should not be contacted until @code{chronyd}
|
||||
receives notification that the link to the internet is present.
|
||||
|
||||
In order to notify @code{chronyd} of the presence of the link, you will need to
|
||||
be able to log in to it with the program @code{chronyc}. To do this,
|
||||
@code{chronyd} needs to be configured with an administrator password. The
|
||||
password is read from a file specified by the @code{keyfile} directive. The
|
||||
@code{generatecommandkey} directive can be used to generate a random password
|
||||
automatically on the first @code{chronyd} start.
|
||||
The @code{offline} keyword indicates that the servers start in an offline
|
||||
state, and that they should not be contacted until @code{chronyd} receives
|
||||
notification from @code{chronyc} that the link to the internet is present.
|
||||
|
||||
The smallest useful configuration file would look something like
|
||||
|
||||
@@ -652,10 +647,9 @@ The smallest useful configuration file would look something like
|
||||
server foo.example.net offline
|
||||
server bar.example.net offline
|
||||
server baz.example.net offline
|
||||
keyfile @SYSCONFDIR@/chrony.keys
|
||||
generatecommandkey
|
||||
driftfile @CHRONYVARDIR@/drift
|
||||
makestep 10 3
|
||||
rtcsync
|
||||
@end example
|
||||
|
||||
The next section describes how to tell @code{chronyd} when the internet link
|
||||
@@ -663,28 +657,22 @@ goes up and down.
|
||||
|
||||
@node Advising chronyd of internet availability
|
||||
@subsection How to tell chronyd when the internet link is available.
|
||||
To use this option, you will need to configure a command key in
|
||||
@code{chronyd's} configuration file @file{@SYSCONFDIR@/chrony.conf}, as described in
|
||||
the previous section.
|
||||
|
||||
To tell @code{chronyd} when to start and finish sampling the servers, the
|
||||
@code{online} and @code{offline} commands of chronyc need to be used.
|
||||
@code{online} and @code{offline} commands of @code{chronyc} need to be used.
|
||||
To give an example of their use, we assume that @code{pppd} is the
|
||||
program being used to connect to the internet, and that chronyc has been
|
||||
installed at its default location @file{@BINDIR@/chronyc}. We
|
||||
also assume that the command key has been set up as described in the
|
||||
previous section.
|
||||
program being used to connect to the internet, and that @code{chronyc} has been
|
||||
installed at its default location @file{@BINDIR@/chronyc}.
|
||||
|
||||
In the file @file{/etc/ppp/ip-up} we add the command sequence
|
||||
|
||||
@example
|
||||
@BINDIR@/chronyc -a online
|
||||
@BINDIR@/chronyc online
|
||||
@end example
|
||||
|
||||
and in the file @file{/etc/ppp/ip-down} we add the sequence
|
||||
|
||||
@example
|
||||
@BINDIR@/chronyc -a offline
|
||||
@BINDIR@/chronyc offline
|
||||
@end example
|
||||
|
||||
@code{chronyd's} polling of the servers will now only occur whilst the
|
||||
@@ -707,44 +695,31 @@ support for this, in the form of the @code{manual} directive in the
|
||||
configuration file and the @code{settime} command in the @code{chronyc}
|
||||
program.
|
||||
|
||||
If the master is rebooted, @code{chronyd} can re-read the drift rate
|
||||
from the drift file. However, the master has no accurate estimate of
|
||||
the current time. To get around this, the system can be configured so
|
||||
that the master can initially set itself to a `majority-vote' of
|
||||
selected clients' times; this allows the clients to `flywheel' the
|
||||
master across its outage.
|
||||
The @code{smoothtime} directive (@pxref{smoothtime directive}) is useful when
|
||||
the clocks of the clients need to stay close together when the local time is
|
||||
adjusted by the @code{settime} command. The smoothing process needs to be
|
||||
activated by the @code{smoothtime activate} command when the local time is
|
||||
ready to be served. After that point, any adjustments will be smoothed out.
|
||||
|
||||
A typical configuration file for the master (called @code{master}) might
|
||||
be (assuming the clients are in the 192.168.165.x subnet and that the
|
||||
master's address is 192.168.169.170)
|
||||
A typical configuration file for the master (called @code{master}) might be
|
||||
(assuming the clients are in the 192.168.165.x subnet)
|
||||
|
||||
@example
|
||||
driftfile @CHRONYVARDIR@/drift
|
||||
generatecommandkey
|
||||
keyfile @SYSCONFDIR@/chrony.keys
|
||||
initstepslew 10 client1 client3 client6
|
||||
local stratum 8
|
||||
manual
|
||||
allow 192.168.165
|
||||
smoothtime 400 0.01
|
||||
@end example
|
||||
|
||||
For the clients that have to resynchronise the master when it restarts,
|
||||
the configuration file might be
|
||||
For the clients the configuration file might be
|
||||
|
||||
@example
|
||||
server master
|
||||
server master iburst
|
||||
driftfile @CHRONYVARDIR@/drift
|
||||
logdir /var/log/chrony
|
||||
log measurements statistics tracking
|
||||
keyfile @SYSCONFDIR@/chrony.keys
|
||||
generatecommandkey
|
||||
local stratum 10
|
||||
initstepslew 20 master
|
||||
allow 192.168.169.170
|
||||
@end example
|
||||
|
||||
The rest of the clients would be the same, except that the @code{local}
|
||||
and @code{allow} directives are not required.
|
||||
@c }}}
|
||||
@c {{{ S:Dial-up home PCs
|
||||
@node Dial-up home PCs
|
||||
@@ -870,8 +845,6 @@ server baz.example.net maxdelay 0.4 offline
|
||||
logdir /var/log/chrony
|
||||
log statistics measurements tracking
|
||||
driftfile @CHRONYVARDIR@/drift
|
||||
keyfile @SYSCONFDIR@/chrony.keys
|
||||
generatecommandkey
|
||||
makestep 10 3
|
||||
maxupdateskew 100.0
|
||||
dumponexit
|
||||
@@ -886,13 +859,13 @@ online and offline respectively.
|
||||
The relevant part of the @file{/etc/ppp/ip-up} file is
|
||||
|
||||
@example
|
||||
@BINDIR@/chronyc -a online
|
||||
@BINDIR@/chronyc online
|
||||
@end example
|
||||
|
||||
and the relevant part of the @file{/etc/ppp/ip-down} script is
|
||||
|
||||
@example
|
||||
@BINDIR@/chronyc -a -m offline dump writertc
|
||||
@BINDIR@/chronyc -m offline dump writertc
|
||||
@end example
|
||||
|
||||
To start @code{chronyd} during the boot sequence, the following
|
||||
@@ -989,10 +962,9 @@ used. These histories are created by using the @code{dump} command in
|
||||
@code{chronyc}, or by setting the @code{dumponexit} directive in the
|
||||
configuration file. This option is useful if you want to stop and
|
||||
restart @code{chronyd} briefly for any reason, e.g. to install a new
|
||||
version. However, it only makes sense on systems where the kernel can
|
||||
maintain clock compensation whilst not under @code{chronyd's} control.
|
||||
The only version where this happens so far is Linux. On other systems
|
||||
this option should not be used.
|
||||
version. However, it should be used only on systems where the kernel
|
||||
can maintain clock compensation whilst not under @code{chronyd's}
|
||||
control (i.e. Linux, FreeBSD, NetBSD and Solaris).
|
||||
@item -R
|
||||
When this option is used, the @code{initstepslew} directive and the
|
||||
@code{makestep} directive used with a positive limit will be ignored.
|
||||
@@ -1023,9 +995,16 @@ the last modification of the drift file (specified by the @code{driftfile}
|
||||
directive) to restore the system time at which @code{chronyd} was previously
|
||||
stopped.
|
||||
@item -u <user>
|
||||
This option sets the name of the user to which will @code{chronyd} switch to
|
||||
drop root privileges if compiled with Linux capabilities support (default
|
||||
@code{@DEFAULT_USER@}).
|
||||
This option sets the name of the system user to which @code{chronyd} will
|
||||
switch after start in order to drop root privileges. It overrides the
|
||||
@code{user} directive (default @code{@DEFAULT_USER@}). It may be set to a
|
||||
non-root user only when @code{chronyd} is compiled with support for Linux
|
||||
capabilities (libcap) or on NetBSD with the @code{/dev/clockctl} device.
|
||||
@item -F <level>
|
||||
This option configures a system call filter when @code{chronyd} is compiled with
|
||||
support for the Linux secure computing (seccomp) facility. In level 1 the
|
||||
process is killed when a forbidden system call is made, in level -1 the SYSSIG
|
||||
signal is thrown instead and in level 0 the filter is disabled (default 0).
|
||||
@item -q
|
||||
When run in this mode, @code{chronyd} will set the system clock once
|
||||
and exit. It will not detach from the terminal.
|
||||
@@ -1036,9 +1015,11 @@ not correct the clock.
|
||||
This option displays @code{chronyd's} version number to the terminal and
|
||||
exits.
|
||||
@item -P <priority>
|
||||
This option will select the SCHED_FIFO real-time scheduler at the
|
||||
specified priority (which must be between 0 and 100). This mode is
|
||||
supported only on Linux.
|
||||
On Linux, this option will select the SCHED_FIFO real-time scheduler at the
|
||||
specified priority (which must be between 0 and 100). On Mac OS X, 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.
|
||||
@item -m
|
||||
This option will lock chronyd into RAM so that it will never be paged
|
||||
out. This mode is only supported on Linux.
|
||||
@@ -1120,18 +1101,16 @@ the configuration file is ignored.
|
||||
* bindcmdaddress directive:: Limit network interface used for commands
|
||||
* broadcast directive:: Make chronyd act as an NTP broadcast server
|
||||
* clientloglimit directive:: Set client log memory limit
|
||||
* cmdallow directive:: Give control access to chronyc on other computers
|
||||
* cmddeny directive:: Deny control access to chronyc on other computers
|
||||
* cmdport directive:: Set port to use for runtime commanding
|
||||
* cmdallow directive:: Give monitoring access to chronyc on other computers
|
||||
* cmddeny directive:: Deny monitoring access to chronyc on other computers
|
||||
* cmdport directive:: Set port to use for runtime monitoring
|
||||
* combinelimit directive:: Limit sources included in combining algorithm
|
||||
* commandkey directive:: Set runtime command key
|
||||
* corrtimeratio directive:: Set correction time ratio
|
||||
* deny directive:: Deny access to NTP clients
|
||||
* driftfile directive:: Specify location of file containing drift data
|
||||
* dumpdir directive:: Specify directory for dumping measurements
|
||||
* dumponexit directive:: Dump measurements when daemon exits
|
||||
* fallbackdrift directive:: Specify fallback drift intervals
|
||||
* generatecommandkey directive:: Generate command key automatically
|
||||
* hwclockfile directive:: Specify location of hwclock's adjtime file
|
||||
* include directive:: Include a configuration file
|
||||
* initstepslew directive:: Trim the system clock on boot-up
|
||||
@@ -1149,6 +1128,7 @@ the configuration file is ignored.
|
||||
* manual directive:: Allow manual entry using chronyc's settime cmd
|
||||
* maxchange directive:: Set maximum allowed offset
|
||||
* maxclockerror directive:: Set maximum frequency error of local clock
|
||||
* maxdistance directive:: Set maximum allowed distance of sources
|
||||
* maxsamples directive:: Set maximum number of samples per source
|
||||
* maxslewrate directive:: Set maximum slew rate
|
||||
* maxupdateskew directive:: Stop bad estimates upsetting machine clock
|
||||
@@ -1318,9 +1298,15 @@ on multiple network interfaces.
|
||||
@node bindcmdaddress directive
|
||||
@subsection bindcmdaddress
|
||||
The @code{bindcmdaddress} directive allows you to specify the network
|
||||
interface to which @code{chronyd} will listen for command packets (issued by
|
||||
@code{chronyc}). This provides an additional level of access restriction above
|
||||
that available through @code{cmddeny} mechanism.
|
||||
interface to which @code{chronyd} will listen for monitoring command packets
|
||||
(issued by @code{chronyc}). This provides an additional level of access
|
||||
restriction above that available through @code{cmddeny} mechanism.
|
||||
|
||||
This directive can also change the path of the Unix domain command socket,
|
||||
which is used by @code{chronyc} to send configuration commands. The socket
|
||||
must be in a directory that is accessible only by the root or chrony user. The
|
||||
directory will be created on start if it doesn't exist. The default path of
|
||||
the socket is @code{@CHRONYSOCKDIR@/chronyd.sock}.
|
||||
|
||||
By default, @code{chronyd} binds to the loopback interface (with addresses
|
||||
@code{127.0.0.1} and @code{::1}). This blocks all access except from
|
||||
@@ -1336,6 +1322,11 @@ to the configuration file.
|
||||
|
||||
For each of IPv4 and IPv6 protocols, only one @code{bindcmdaddress}
|
||||
directive can be specified.
|
||||
|
||||
An example that sets the path of the Unix domain command socket is
|
||||
@example
|
||||
bindcmdaddress /var/run/chrony/chronyd.sock
|
||||
@end example
|
||||
@c }}}
|
||||
@c {{{ broadcast directive
|
||||
@node broadcast directive
|
||||
@@ -1394,14 +1385,15 @@ clientloglimit 1048576
|
||||
@subsection cmdallow
|
||||
|
||||
This is similar to the @code{allow} directive (@pxref{allow directive}), except
|
||||
that it allows control access (rather than NTP client access) to a particular
|
||||
subnet or host. (By 'control access' is meant that chronyc can be run on those
|
||||
hosts and successfully connect to chronyd on this computer.)
|
||||
that it allows monitoring access (rather than NTP client access) to a particular
|
||||
subnet or host. (By 'monitoring access' is meant that @code{chronyc} can be
|
||||
run on those hosts and retrieve monitoring data from @code{chronyd} on this
|
||||
computer.)
|
||||
|
||||
The syntax is identical to the @code{allow} directive.
|
||||
|
||||
There is also a @code{cmdallow all} directive with similar behaviour to the
|
||||
@code{allow all} directive (but applying to control access in this case, of
|
||||
@code{allow all} directive (but applying to monitoring access in this case, of
|
||||
course).
|
||||
|
||||
Note that @code{chronyd} has to be configured with the @code{bindcmdaddress}
|
||||
@@ -1413,7 +1405,7 @@ access.
|
||||
@subsection cmddeny
|
||||
|
||||
This is similar to the @code{cmdallow} directive (@pxref{cmdallow directive}),
|
||||
except that it denies control access to a particular subnet or host,
|
||||
except that it denies monitoring access to a particular subnet or host,
|
||||
rather than allowing it.
|
||||
|
||||
The syntax is identical.
|
||||
@@ -1426,9 +1418,10 @@ There is also a @code{cmddeny all} directive with similar behaviour to the
|
||||
@subsection cmdport
|
||||
|
||||
The @code{cmdport} directive allows the port that is used for run-time
|
||||
command and monitoring (via the program @code{chronyc}) to be altered
|
||||
monitoring (via the @code{chronyc} program) to be altered
|
||||
from its default (323/udp). If set to 0, @code{chronyd} will not open the
|
||||
port, this is useful to disable the @code{chronyc} access completely.
|
||||
port, this is useful to disable the @code{chronyc} access from the internet.
|
||||
(It does not disable the Unix domain command socket.)
|
||||
|
||||
An example shows the syntax
|
||||
|
||||
@@ -1464,46 +1457,12 @@ The syntax is
|
||||
combinelimit <limit>
|
||||
@end example
|
||||
@c }}}
|
||||
@c {{{ commandkey
|
||||
@node commandkey directive
|
||||
@subsection commandkey
|
||||
The commandkey command is used to set the key number used for
|
||||
authenticating user commands via the chronyc program at run time.
|
||||
This allows certain actions of the chronyc program to be restricted to
|
||||
administrators.
|
||||
|
||||
An example of the commandkey command is
|
||||
|
||||
@example
|
||||
commandkey 20
|
||||
@end example
|
||||
|
||||
By default, the key number is 0.
|
||||
|
||||
In the key file (see the keyfile command) there should be a line of
|
||||
the form
|
||||
|
||||
@example
|
||||
20 MD5 HEX:B028F91EA5C38D06C2E140B26C7F41EC
|
||||
@end example
|
||||
|
||||
When running the chronyc program to perform run-time configuration,
|
||||
the command
|
||||
|
||||
@example
|
||||
password HEX:B028F91EA5C38D06C2E140B26C7F41EC
|
||||
@end example
|
||||
|
||||
must be entered before any commands affecting the operation of the
|
||||
daemon can be entered, or chronyc must be started with the `-a' option to run
|
||||
the password command automatically.
|
||||
@c }}}
|
||||
@c {{{ corrtimeratio
|
||||
@node corrtimeratio directive
|
||||
@subsection corrtimeratio
|
||||
When @code{chronyd} makes a time correction, it controls how quickly
|
||||
the system clock is slewed (so far only on Linux). This rate
|
||||
affects the frequency error of the system clock.
|
||||
When @code{chronyd} is slewing the system clock to correct an offset, the rate
|
||||
at which it is slewing adds to the frequency error of the clock. On Linux,
|
||||
FreeBSD, NetBSD and Solaris this rate can be controlled.
|
||||
|
||||
The @code{corrtimeratio} directive sets the ratio between the
|
||||
duration in which the clock is slewed for an average correction
|
||||
@@ -1580,12 +1539,11 @@ driftfile @CHRONYVARDIR@/drift
|
||||
To compute the rate of gain or loss of time, @code{chronyd} has to store
|
||||
a measurement history for each of the time sources it uses.
|
||||
|
||||
Certain systems (so far only Linux) have operating system support for
|
||||
setting the rate of gain or loss to compensate for known errors. (On
|
||||
other systems, @code{chronyd} must simulate such a capability by
|
||||
periodically slewing the system clock forwards or backwards by a
|
||||
suitable amount to compensate for the error built up since the previous
|
||||
slew).
|
||||
Certain systems (Linux, FreeBSD, NetBSD, Solaris) have operating system
|
||||
support for setting the rate of gain or loss to compensate for known errors.
|
||||
(On Mac OS X, @code{chronyd} must simulate such a capability by periodically
|
||||
slewing the system clock forwards or backwards by a suitable amount to
|
||||
compensate for the error built up since the previous slew).
|
||||
|
||||
For such systems, it is possible to save the measurement history across
|
||||
restarts of @code{chronyd} (assuming no changes are made to the system
|
||||
@@ -1638,16 +1596,6 @@ By default (or if the specified maximum or minimum is 0), no fallbacks
|
||||
are used and the clock frequency changes only with new measurements from
|
||||
NTP, reference clocks or manual input.
|
||||
@c }}}
|
||||
@c {{{ generatecommandkey
|
||||
@node generatecommandkey directive
|
||||
@subsection generatecommandkey
|
||||
With this directive, if the command key is not found on start in the file
|
||||
specified by the @code{keyfile} directive, @code{chronyd} will generate a new
|
||||
command key from the /dev/urandom file and write it to the key file.
|
||||
|
||||
The generated key will use SHA1 if @code{chronyd} is compiled with the support,
|
||||
otherwise MD5 will be used.
|
||||
@c }}}
|
||||
@c {{{ hwclockfile
|
||||
@node hwclockfile directive
|
||||
@subsection hwclockfile
|
||||
@@ -1665,12 +1613,15 @@ hwclockfile /etc/adjtime
|
||||
@c {{{ include
|
||||
@node include directive
|
||||
@subsection include
|
||||
The @code{include} directive includes a specified configuration file.
|
||||
This is useful when maintaining configuration on multiple hosts to
|
||||
keep the differences in a separate file.
|
||||
The @code{include} directive includes a specified configuration file or
|
||||
multiple configuration files when a wildcard pattern is specified. This can be
|
||||
useful when maintaining configuration on multiple hosts to keep the differences
|
||||
in separate files.
|
||||
|
||||
An example of the command is
|
||||
|
||||
@example
|
||||
include @SYSCONFDIR@/chrony/local.conf
|
||||
include @SYSCONFDIR@/chrony.d/*.conf
|
||||
@end example
|
||||
@c }}}
|
||||
@c {{{ initstepslew
|
||||
@@ -1743,12 +1694,7 @@ from reading the clock before it's stepped.
|
||||
@node keyfile directive
|
||||
@subsection keyfile
|
||||
This command is used to specify the location of the file containing
|
||||
ID/key pairs for the following 2 uses:
|
||||
|
||||
@itemize @bullet
|
||||
@item Authentication of NTP packets.
|
||||
@item Authentication of administrator commands entered via chronyc.
|
||||
@end itemize
|
||||
ID/key pairs for authentication of NTP packets.
|
||||
|
||||
The format of the command is shown in the example below
|
||||
|
||||
@@ -1768,24 +1714,27 @@ pairs. The format of the file is shown below
|
||||
@end example
|
||||
|
||||
Each line consists of an ID, a name of authentication hash function (optional)
|
||||
and a password. The ID can be any unsigned integer in the range 0 through
|
||||
2**32-1, but ID of 0 can be used only for the command key and not for the NTP
|
||||
authentication. The hash function is MD5 by default, depending on how was
|
||||
@code{chronyd} compiled other allowed hash functions may be SHA1, SHA256,
|
||||
and a password. The ID can be any unsigned integer in the range 1 through
|
||||
2**32-1. The hash function is MD5 by default, depending on how was
|
||||
@code{chronyd} compiled, other allowed hash functions may be SHA1, SHA256,
|
||||
SHA384, SHA512, RMD128, RMD160, RMD256, RMD320, TIGER and WHIRLPOOL. The
|
||||
password can be encoded as a string of characters not containing a space with
|
||||
optional @code{ASCII:} prefix or as a hexadecimal number with @code{HEX:}
|
||||
prefix.
|
||||
|
||||
The password is used with the hash function to generate and verify a message
|
||||
authentication code (MAC) in NTP and command packets.
|
||||
authentication code (MAC) in NTP packets.
|
||||
For maximum security, it's recommended to use SHA1 or stronger hash function.
|
||||
The passwords should be random and they should be as long as the output size of
|
||||
the configured hash function, e.g. 160 bits with SHA1.
|
||||
|
||||
The ID for the chronyc authentication key is specified with the commandkey
|
||||
command (see earlier). The command key can be generated automatically on
|
||||
start with the @code{generatecommandkey} directive.
|
||||
These shell commands can be used to generate random MD5 and SHA1 keys on
|
||||
systems which have the @code{/dev/urandom} device:
|
||||
|
||||
@example
|
||||
echo "1 MD5 HEX:$(tr -d -c '[:xdigit:]' < /dev/urandom | head -c 32)"
|
||||
echo "1 SHA1 HEX:$(tr -d -c '[:xdigit:]' < /dev/urandom | head -c 40)"
|
||||
@end example
|
||||
@c }}}
|
||||
@c {{{ leapsecmode
|
||||
@node leapsecmode directive
|
||||
@@ -1806,8 +1755,8 @@ selects how that error is corrected. There are four options:
|
||||
When inserting a leap second, the kernel steps the system clock backwards by
|
||||
one second when the clock gets to 00:00:00 UTC. When deleting a leap second,
|
||||
it steps forward by one second when the clock gets to 23:59:59 UTC. This is
|
||||
the default mode when the system driver supports leap seconds (currently Linux
|
||||
only).
|
||||
the default mode when the system driver supports leap seconds (i.e. on
|
||||
Linux, FreeBSD, NetBSD and Solaris).
|
||||
@item step
|
||||
This is similar to the @code{system} mode, except the clock is stepped by
|
||||
@code{chronyd} instead of the kernel. It can be useful to avoid bugs in the
|
||||
@@ -2354,6 +2303,10 @@ mailonchange root@@localhost 0.5
|
||||
|
||||
This would send a mail message to root if a change of more than 0.5
|
||||
seconds were applied to the system clock.
|
||||
|
||||
This directive can't be used when a system call filter is enabled by the
|
||||
@code{-F} option as the @code{chronyd} process will not be allowed to fork
|
||||
and execute the sendmail binary.
|
||||
@c }}}
|
||||
@c {{{ makestep
|
||||
@node makestep directive
|
||||
@@ -2435,6 +2388,23 @@ Typical values for <error-in-ppm> might be 10 for a low quality clock
|
||||
to 0.1 for a high quality clock using a temperature compensated
|
||||
crystal oscillator.
|
||||
@c }}}
|
||||
@c {{{ maxdistance
|
||||
@node maxdistance directive
|
||||
@subsection maxdistance
|
||||
The @code{maxdistance} directive sets the maximum allowed root distance of the
|
||||
sources to not be rejected by the source selection algorithm. The distance
|
||||
includes the accumulated dispersion, which may be large when the source is no
|
||||
longer synchronised, and half of the total round-trip delay to the primary
|
||||
source.
|
||||
|
||||
By default, the maximum distance is 3 seconds.
|
||||
|
||||
The syntax is
|
||||
|
||||
@example
|
||||
maxdistance <seconds>
|
||||
@end example
|
||||
@c }}}
|
||||
@c {{{ maxsamples
|
||||
@node maxsamples directive
|
||||
@subsection maxsamples
|
||||
@@ -2456,10 +2426,16 @@ maxsamples <samples>
|
||||
The @code{maxslewrate} directive sets the maximum rate at which @code{chronyd}
|
||||
is allowed to slew the time. It limits the slew rate controlled by the
|
||||
correction time ratio (@pxref{corrtimeratio directive}) and is effective
|
||||
only on systems where @code{chronyd} is able to control the rate (so
|
||||
far only Linux).
|
||||
only on systems where @code{chronyd} is able to control the rate (i.e.
|
||||
Linux, FreeBSD, NetBSD, Solaris).
|
||||
|
||||
By default, the maximum slew rate is 83333.333 ppm (one twelfth).
|
||||
For each system there is a maximum frequency offset of the clock that
|
||||
can be set by the driver. On Linux it's 100000 ppm, on FreeBSD and NetBSD
|
||||
it's 5000 ppm and on Solaris it is 32500 ppm. Also, due to a kernel
|
||||
limitation, setting @code{maxslewrate} on FreeBSD and NetBSD to a value between
|
||||
500 ppm and 5000 ppm will effectively set it to 500 ppm.
|
||||
|
||||
By default, the maximum slew rate is set to 83333.333 ppm (one twelfth).
|
||||
|
||||
The syntax is
|
||||
|
||||
@@ -2880,19 +2856,21 @@ system time is copied to the real time clock (RTC) every 11 minutes.
|
||||
|
||||
This directive is supported only on Linux and cannot be used when the
|
||||
normal RTC tracking is enabled, i.e. when the @code{rtcfile} directive
|
||||
is used.
|
||||
is used. On other systems this directive does nothing.
|
||||
@c }}}
|
||||
@c {{{ sched_priority
|
||||
@node sched_priority directive
|
||||
@subsection sched_priority
|
||||
|
||||
The @code{sched_priority} directive will select the SCHED_FIFO real-time
|
||||
scheduler at the specified priority (which must be between 0 and 100).
|
||||
This mode is supported only on Linux.
|
||||
On Linux, the @code{sched_priority} directive will select the SCHED_FIFO
|
||||
real-time scheduler at the specified priority (which must be between 0 and
|
||||
100). On Mac OS X, 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.
|
||||
|
||||
This directive uses the Linux sched_setscheduler() system call to
|
||||
instruct the kernel to use the SCHED_FIFO first-in, first-out
|
||||
real-time scheduling policy for @code{chronyd} with the specified priority.
|
||||
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 @code{chronyd} with the specified priority.
|
||||
This means that whenever @code{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 @code{chronyd's}
|
||||
@@ -2900,6 +2878,10 @@ resource requirements are modest, but it should result in lower and
|
||||
more consistent latency since @code{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 man page has more details.
|
||||
|
||||
On Mac OS X, 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.
|
||||
@c }}}
|
||||
@c {{{ server
|
||||
@node server directive
|
||||
@@ -3199,10 +3181,11 @@ Valid measurements with corresponding compensations are logged to the
|
||||
@c {{{ user
|
||||
@node user directive
|
||||
@subsection user
|
||||
The @code{user} directive sets the name of the user to which will
|
||||
@code{chronyd} switch on initialisation to drop root privileges.
|
||||
So far, it works only on Linux when compiled with capabilities support.
|
||||
Setting the name to root will disable it.
|
||||
The @code{user} directive sets the name of the system user to which
|
||||
@code{chronyd} will switch after start in order to drop root privileges.
|
||||
It may be set to a non-root user only when @code{chronyd} is compiled with
|
||||
support for Linux capabilities (libcap) or on NetBSD with the
|
||||
@code{/dev/clockctl} device.
|
||||
|
||||
The default value is @code{@DEFAULT_USER@}.
|
||||
@c }}}
|
||||
@@ -3234,7 +3217,7 @@ chronyc
|
||||
at the command line. The prompt @code{chronyc} is displayed whilst
|
||||
chronyc is expecting input from the user, when it is being run from a
|
||||
terminal. If chronyc's input or output are redirected from/to a file,
|
||||
the prompt is now shown.
|
||||
the prompt is not shown.
|
||||
|
||||
When you are finished entering commands, the commands @code{exit} or
|
||||
@code{quit} will terminate the program. (Entering @key{Control-D} will
|
||||
@@ -3249,9 +3232,9 @@ Chronyc supports the following command line options.
|
||||
@item -v
|
||||
Displays the version number of chronyc on the terminal, and exists.
|
||||
@item -h <host>
|
||||
This option allows the user to specify which host running the
|
||||
@code{chronyd} program is to be contacted. This allows for remote
|
||||
configuration, without having to ssh to the other host first.
|
||||
This option allows the user to specify which host (or comma-separated list of
|
||||
addresses) running the @code{chronyd} program is to be contacted. This allows
|
||||
for remote monitoring, without having to ssh to the other host first.
|
||||
|
||||
The default is to contact @code{chronyd} running on the same host as
|
||||
that where chronyc is being run.
|
||||
@@ -3262,6 +3245,9 @@ This defaults to the compiled-in default; there would rarely be a need
|
||||
to change this.
|
||||
@item -n
|
||||
This option disables resolving IP addresses to hostnames.
|
||||
@item -d
|
||||
This option enables printing of debugging messages (if compiled with debugging
|
||||
support).
|
||||
@item -4
|
||||
With this option hostnames will be resolved only to IPv4 addresses.
|
||||
@item -6
|
||||
@@ -3270,13 +3256,9 @@ With this option hostnames will be resolved only to IPv6 addresses.
|
||||
With this option multiple commands can be specified on the command line.
|
||||
Each argument will be interpreted as a whole command.
|
||||
@item -f <conf-file>
|
||||
This option can be used to specify an alternate location of the @code{chronyd}
|
||||
configuration file (default @file{@SYSCONFDIR@/chrony.conf}). The configuration file is
|
||||
needed for the `-a' option.
|
||||
This option is ignored and is provided only for compatibility.
|
||||
@item -a
|
||||
With this option @code{chronyc} will try to authenticate automatically on
|
||||
start. It will read the configuration file, read the command key from the
|
||||
keyfile and run the authhash and password commands.
|
||||
This option is ignored and is provided only for compatibility.
|
||||
@end table
|
||||
@c }}}
|
||||
@c {{{ SS:Security with chronyc
|
||||
@@ -3285,51 +3267,49 @@ keyfile and run the authhash and password commands.
|
||||
Many of the commands available through chronyc have a fair amount of
|
||||
power to reconfigure the run-time behaviour of @code{chronyd}. Consequently,
|
||||
@code{chronyc} is quite dangerous for the integrity of the target
|
||||
system's clock performance. Having access to @code{chronyd} via chronyc is
|
||||
more or less equivalent to being able to modify @code{chronyd's} configuration
|
||||
file (typically @file{@SYSCONFDIR@/chrony.conf}) and to restart @code{chronyd}.
|
||||
system's clock performance. Having access to @code{chronyd} via @code{chronyc}
|
||||
is more or less equivalent to being able to modify @code{chronyd's}
|
||||
configuration file (typically @file{@SYSCONFDIR@/chrony.conf}) and to restart
|
||||
@code{chronyd}.
|
||||
|
||||
Chronyc also provides a number of monitoring (as opposed to commanding)
|
||||
commands, which will not affect the behaviour of @code{chronyd}. However, you
|
||||
may still want to restrict access to these commands.
|
||||
@code{chronyc} also provides a number of monitoring (as opposed to
|
||||
commanding or configuration) commands, which will not affect the behaviour of
|
||||
@code{chronyd}. However, you may still want to restrict access to these
|
||||
commands.
|
||||
|
||||
In view of this, access to some of the capabilities of chronyc will
|
||||
usually be tightly controlled. There are two mechanisms supported:
|
||||
There are two ways how @code{chronyc} can access @code{chronyd}. One is the
|
||||
Internet Protocol (IPv4 or IPv6) and the other is a Unix domain socket, which
|
||||
is accessible only locally by the root or chrony user (by default
|
||||
@code{@CHRONYSOCKDIR@/chronyd.sock}).
|
||||
|
||||
@enumerate 1
|
||||
@item
|
||||
The set of hosts from which @code{chronyd} will accept commands can be
|
||||
restricted. By default, commands will only be accepted from the same
|
||||
host that @code{chronyd} is running on.
|
||||
@item
|
||||
Any command that actually reconfigures some aspect of @code{chronyd's}
|
||||
behaviour requires the user of chronyc to know a password. This
|
||||
password is specified in @code{chronyd's} keys file (@pxref{keyfile directive})
|
||||
and specified via the commandkey option in its configuration file
|
||||
(@pxref{commandkey directive}).
|
||||
@end enumerate
|
||||
|
||||
Only the following commands can be used @emph{without} providing a
|
||||
password:
|
||||
Only the following monitoring commands are allowed from the internet:
|
||||
|
||||
@itemize @bullet
|
||||
@item @code{activity}
|
||||
@item @code{authhash}
|
||||
@item @code{dns}
|
||||
@item @code{exit}
|
||||
@item @code{help}
|
||||
@item @code{password}
|
||||
@item @code{quit}
|
||||
@item @code{manual list}
|
||||
@item @code{rtcdata}
|
||||
@item @code{smoothing}
|
||||
@item @code{sources}
|
||||
@item @code{sourcestats}
|
||||
@item @code{tracking}
|
||||
@item @code{waitsync}
|
||||
@item @code{waitsync}.
|
||||
@end itemize
|
||||
|
||||
All other commands require a password to have been specified previously,
|
||||
because they affect @code{chronyd's} operation.
|
||||
The set of hosts from which @code{chronyd} will accept these commands can be
|
||||
restricted. By default, the commands will be accepted only from the localhost
|
||||
(127.0.0.1 or ::1).
|
||||
|
||||
All other commands are allowed only through the Unix domain socket. When sent
|
||||
over the internet, @code{chronyd} will respond with a @code{Not authorised}
|
||||
error, even if it's from the localhost.
|
||||
|
||||
In @code{chrony} versions before 2.2 the commands had to be authenticated with
|
||||
a password and they were allowed from the internet, but that is no longer
|
||||
supported.
|
||||
|
||||
By default, @code{chronyc} tries to connect to the Unix domain socket first.
|
||||
If that fails (e.g. because @code{chronyc} is running under a non-root user),
|
||||
it will try to connect to 127.0.0.1 and then ::1.
|
||||
@c }}}
|
||||
@c {{{ SS:Chronyc command reference
|
||||
@node Chronyc command reference
|
||||
@@ -3346,14 +3326,13 @@ interface.
|
||||
* add server command:: Add a new NTP server
|
||||
* allow all command:: Allowing NTP client access
|
||||
* allow command:: Allowing NTP client access
|
||||
* authhash command:: Set the command authentication hash function
|
||||
* burst command:: Initiating a rapid set of measurements
|
||||
* clients command:: Show clients that have accessed the server
|
||||
* cmdaccheck command:: Verifying command client access
|
||||
* cmdallow all command:: Allowing command client access
|
||||
* cmdallow command:: Allowing command client access
|
||||
* cmddeny all command:: Denying command client access
|
||||
* cmddeny command:: Denying command client access
|
||||
* cmdaccheck command:: Verifying monitoring client access
|
||||
* cmdallow all command:: Allowing monitoring client access
|
||||
* cmdallow command:: Allowing monitoring client access
|
||||
* cmddeny all command:: Denying monitoring client access
|
||||
* cmddeny command:: Denying monitoring client access
|
||||
* cyclelogs command:: Close and re-open open log files
|
||||
* delete command:: Remove an NTP server or peer
|
||||
* deny all command:: Denying NTP client access
|
||||
@@ -3374,9 +3353,9 @@ interface.
|
||||
* minstratum command:: Set minimum stratum for a source
|
||||
* offline command:: Warn that connectivity to a source will be lost
|
||||
* online command:: Warn that connectivity to a source has been restored
|
||||
* password command:: Provide password needed for most commands
|
||||
* polltarget command:: Set poll target for a source
|
||||
* quit command:: Exit from chronyc
|
||||
* refresh command:: Refresh IP addresses
|
||||
* reselect command:: Reselect synchronisation source
|
||||
* reselectdist command:: Set improvement in distance needed to reselect a source
|
||||
* retries command:: Set maximum number of retries
|
||||
@@ -3504,24 +3483,6 @@ allow
|
||||
The effect of each of these examples is the same as that of the @code{allow}
|
||||
directive in the configuration file.
|
||||
@c }}}
|
||||
@c {{{ authhash
|
||||
@node authhash command
|
||||
@subsubsection authhash
|
||||
This command selects the hash function used for authenticating user commands.
|
||||
For successful authentication the hash function has to be the same as the
|
||||
function specified for the command key in the keys file on the server
|
||||
(@pxref{keyfile directive}). It needs to be selected before the
|
||||
@code{password} command is used. The default hash function is MD5.
|
||||
|
||||
An example is
|
||||
|
||||
@example
|
||||
authhash SHA1
|
||||
@end example
|
||||
|
||||
The authhash command is run automatically on start if @code{chronyc} was
|
||||
started with the `-a' option.
|
||||
@c }}}
|
||||
@c {{{ burst
|
||||
@node burst command
|
||||
@subsubsection burst
|
||||
@@ -3614,14 +3575,15 @@ burst 2/10 foo.example.net
|
||||
@comment node-name, next, previous, up
|
||||
@subsubsection clients
|
||||
This command shows a list of all clients that have accessed the server,
|
||||
through either the NTP or command/monitoring ports. There are no arguments.
|
||||
through either the NTP or command/monitoring ports. It doesn't include
|
||||
access to the Unix domain comamnd socket. There are no arguments.
|
||||
|
||||
An example of the output is
|
||||
|
||||
@example
|
||||
Hostname Client Peer CmdAuth CmdNorm CmdBad LstN LstC
|
||||
========================= ====== ====== ====== ====== ====== ==== ====
|
||||
localhost 0 0 15 1 0 29y 0
|
||||
localhost 0 0 0 1 0 29y 0
|
||||
aardvark.xxx 4 0 0 0 0 49 29y
|
||||
badger.xxx 4 0 0 0 0 6 29y
|
||||
@end example
|
||||
@@ -3643,9 +3605,9 @@ client mode packet.
|
||||
The number of times the client has accessed the server using an NTP
|
||||
symmetric active mode packet.
|
||||
@item
|
||||
The number of authenticated command packets that have been processed
|
||||
from the client (i.e. those following a successful @code{password}
|
||||
command).
|
||||
The number of authenticated command packets that have been processed from the
|
||||
client. Authentication is no longer supported in command packets, so the
|
||||
number should be always zero.
|
||||
@item
|
||||
The number of unauthenticated command packets that have been processed
|
||||
from the client.
|
||||
@@ -3665,7 +3627,7 @@ of that type has ever been received.
|
||||
@node cmdaccheck command
|
||||
@subsubsection cmdaccheck
|
||||
This command is similar to the @code{accheck} command, except that it is
|
||||
used to check whether command access is permitted from a named host.
|
||||
used to check whether monitoring access is permitted from a named host.
|
||||
|
||||
Examples of use are as follows:
|
||||
|
||||
@@ -3678,30 +3640,30 @@ cmdaccheck 2001:db8::1
|
||||
@c {{{ cmdallow all
|
||||
@node cmdallow all command
|
||||
@subsubsection cmdallow all
|
||||
This is similar to the @code{allow all} command, except that it is used to@c {{{
|
||||
allow particular hosts or subnets to use the chronyc program to interact@c }}}
|
||||
with @code{chronyd} on the current host.
|
||||
This is similar to the @code{allow all} command, except that it is used to
|
||||
allow particular hosts or subnets to use @code{chronyc} to monitor with
|
||||
@code{chronyd} on the current host.
|
||||
@c }}}
|
||||
@c {{{ cmdallow
|
||||
@node cmdallow command
|
||||
@subsubsection cmdallow
|
||||
This is similar to the @code{allow} command, except that it is used to
|
||||
allow particular hosts or subnets to use the chronyc program to interact
|
||||
with @code{chronyd} on the current host.
|
||||
This is similar to the @code{allow} command, except that it is used to allow
|
||||
particular hosts or subnets to use @code{chronyc} to monitor with
|
||||
@code{chronyd} on the current host.
|
||||
@c }}}
|
||||
@c {{{ cmddeny all
|
||||
@node cmddeny all command
|
||||
@subsubsection cmddeny all
|
||||
This is similar to the @code{deny all} command, except that it is used
|
||||
to allow particular hosts or subnets to use the chronyc program to
|
||||
interact with @code{chronyd} on the current host.
|
||||
This is similar to the @code{deny all} command, except that it is used to allow
|
||||
particular hosts or subnets to use @code{chronyc} to monitor @code{chronyd} on
|
||||
the current host.
|
||||
@c }}}
|
||||
@c {{{ cmddeny
|
||||
@node cmddeny command
|
||||
@subsubsection cmddeny
|
||||
This is similar to the @code{deny} command, except that it is used to
|
||||
allow particular hosts or subnets to use the chronyc program to interact
|
||||
with @code{chronyd} on the current host.
|
||||
This is similar to the @code{deny} command, except that it is used to allow
|
||||
particular hosts or subnets to use @code{chronyc} to monitor @code{chronyd} on
|
||||
the current host.
|
||||
@c }}}
|
||||
@c {{{ cyclelogs
|
||||
@node cyclelogs command
|
||||
@@ -3712,7 +3674,7 @@ periodically purged. An example of how to do this is shown below.
|
||||
|
||||
@example
|
||||
% mv /var/log/chrony/measurements.log /var/log/chrony/measurements1.log
|
||||
% chronyc -a cyclelogs
|
||||
% chronyc cyclelogs
|
||||
% ls -l /var/log/chrony
|
||||
-rw-r--r-- 1 root root 0 Jun 8 18:17 measurements.log
|
||||
-rw-r--r-- 1 root root 12345 Jun 8 18:17 measurements1.log
|
||||
@@ -4181,40 +4143,6 @@ particular source or sources has been restored.
|
||||
The syntax is identical to that of the @code{offline} command, see
|
||||
@ref{offline command}.
|
||||
@c }}}
|
||||
@c {{{ password
|
||||
@node password command
|
||||
@subsubsection password
|
||||
The password command is used to allow chronyc to send privileged
|
||||
commands to @code{chronyd}. The password can either be entered on the command
|
||||
line, or can be entered without echoing. The syntax for entering the
|
||||
password on the command line is as follows
|
||||
|
||||
@example
|
||||
password xyzzy
|
||||
password ASCII:xyzzy
|
||||
password HEX:78797a7a79
|
||||
@end example
|
||||
|
||||
To enter the password without it being echoed, enter
|
||||
|
||||
@example
|
||||
password
|
||||
@end example
|
||||
|
||||
The computer will respond with a @samp{Password:} prompt, at which you
|
||||
should enter the password and press return.
|
||||
|
||||
The password can be encoded as a string of characters not containing a space
|
||||
with optional @code{ASCII:} prefix or as a hexadecimal number with @code{HEX:}
|
||||
prefix. It has to match @code{chronyd's} currently defined command key
|
||||
(@pxref{commandkey directive}). If the command key was specified with a
|
||||
different hash function than MD5, it's necessary to select the hash function
|
||||
with the @code{authhash} command (@pxref{authhash command}) before entering the
|
||||
password.
|
||||
|
||||
The password command is run automatically on start if @code{chronyc} was
|
||||
started with the `-a' option.
|
||||
@c }}}
|
||||
@c {{{ polltarget
|
||||
@node polltarget command
|
||||
@subsubsection polltarget
|
||||
@@ -4247,6 +4175,17 @@ to 12.
|
||||
The quit command exits from chronyc and returns the user to the shell
|
||||
(same as the exit command).
|
||||
@c }}}
|
||||
@c {{{ refresh command
|
||||
@node refresh command
|
||||
@subsubsection refresh
|
||||
The @code{refresh} command can be used to force @code{chronyd} to resolve the
|
||||
names of configured sources to IP addresses again, e.g. after suspending and
|
||||
resuming the machine in a different network.
|
||||
|
||||
Sources that stop responding will be replaced with newly resolved addresses
|
||||
automatically after 8 polling intervals, but this command may still be useful
|
||||
to replace them immediately and not wait until they are marked as unreachable.
|
||||
@c }}}
|
||||
@c {{{ reselect command
|
||||
@node reselect command
|
||||
@subsubsection reselect
|
||||
@@ -4587,9 +4526,7 @@ in milliseconds. If no response is received from @code{chronyd}, the timeout is
|
||||
doubled and the request is resent. The maximum number of retries is configured
|
||||
with the @code{retries} command (@pxref{retries command}).
|
||||
|
||||
By default, the timeout is 1000 milliseconds or 100 milliseconds if
|
||||
@code{chronyc} is contacting localhost (i.e. the `-h' option wasn't specified)
|
||||
and @code{chronyd} was compiled with asynchronous name resolving.
|
||||
By default, the timeout is 1000 milliseconds.
|
||||
@c }}}
|
||||
@c {{{ tracking
|
||||
@node tracking command
|
||||
@@ -4649,12 +4586,6 @@ true time (which it reports to NTP clients when it is operating in
|
||||
server mode). The value reported on this line is the difference due to
|
||||
this effect.
|
||||
|
||||
On systems other than Linux, @code{chronyd} doesn't
|
||||
adjust the fundamental rate of the system clock, so keeps the system
|
||||
time correct by periodically making offsets to it as though an error had
|
||||
been measured. The build up of these offsets will be observed in this
|
||||
report.
|
||||
|
||||
@item Last offset
|
||||
This is the estimated local offset on the last clock update.
|
||||
|
||||
|
||||
14
chronyc.1.in
14
chronyc.1.in
@@ -24,7 +24,8 @@ A summary of the options supported by \fBchronyc\fR is included below.
|
||||
|
||||
.TP
|
||||
\fB\-h\fR \fIhostname\fR
|
||||
specify hostname (default 127.0.0.1)
|
||||
specify hostname or comma-separated list of addresses
|
||||
(default @CHRONYSOCKDIR@/chronyd.sock,127.0.0.1,::1)
|
||||
.TP
|
||||
\fB\-p\fR \fIport-number\fR
|
||||
specify port-number
|
||||
@@ -32,6 +33,9 @@ specify port-number
|
||||
\fB\-n\fR
|
||||
display raw IP addresses (don't attempt to look up hostnames)
|
||||
.TP
|
||||
\fB\-d\fR
|
||||
print debugging messages (if compiled with debugging support)
|
||||
.TP
|
||||
\fB\-4\fR
|
||||
resolve hostnames only to IPv4 addresses
|
||||
.TP
|
||||
@@ -43,14 +47,10 @@ allow multiple commands to be specified on the command line. Each argument
|
||||
will be interpreted as a whole command.
|
||||
.TP
|
||||
\fB\-f\fR \fIconf-file\fR
|
||||
This option can be used to specify an alternate location for the
|
||||
configuration file (default \fI@SYSCONFDIR@/chrony.conf\fR). The configuration file is
|
||||
needed for the \fB-a\fR option.
|
||||
this option is ignored and is provided only for compatibility.
|
||||
.TP
|
||||
\fB\-a\fR
|
||||
With this option chronyc will try to authenticate automatically on
|
||||
start. It will read the configuration file, read the command key from the
|
||||
keyfile and run the authhash and password commands.
|
||||
this option is ignored and is provided only for compatibility.
|
||||
.TP
|
||||
\fIcommand\fR
|
||||
specify command. If no command is given, chronyc will read commands
|
||||
|
||||
27
chronyd.8.in
27
chronyd.8.in
@@ -40,9 +40,11 @@ A summary of the options supported by \fBchronyd\fR is included below.
|
||||
|
||||
.TP
|
||||
\fB\-P\fR \fIpriority\fR
|
||||
This option will select the SCHED_FIFO real-time scheduler at the specified
|
||||
priority (which must be between 0 and 100). This mode is supported only on
|
||||
Linux.
|
||||
On Linux, this option will select the SCHED_FIFO real-time scheduler at the
|
||||
specified priority (which must be between 0 and 100). On Mac OS X, 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.
|
||||
.TP
|
||||
.B \-m
|
||||
This option will lock chronyd into RAM so that it will never be paged out.
|
||||
@@ -67,10 +69,9 @@ This option will reload sample histories for each of the servers being used.
|
||||
These histories are created by using the \fIdump\fR command in \fIchronyc\fR,
|
||||
or by setting the \fIdumponexit\fR directive in the configuration file. This
|
||||
option is useful if you want to stop and restart \fBchronyd\fR briefly for any
|
||||
reason, e.g. to install a new version. However, it only makes sense on
|
||||
reason, e.g. to install a new version. However, it should be used only on
|
||||
systems where the kernel can maintain clock compensation whilst not under
|
||||
\fBchronyd\fR's control. The only version where this happens so far is Linux.
|
||||
On other systems this option should not be used.
|
||||
\fBchronyd\fR's control (i.e. Linux, FreeBSD, NetBSD and Solaris).
|
||||
.TP
|
||||
.B \-R
|
||||
When this option is used, the \fIinitstepslew\fR directive and the
|
||||
@@ -103,9 +104,17 @@ directive) to restore the system time at which \fBchronyd\fR was previously
|
||||
stopped.
|
||||
.TP
|
||||
\fB\-u\fR \fIuser\fR
|
||||
This option sets the name of the user to which will \fBchronyd\fR switch to
|
||||
drop root privileges if compiled with Linux capabilities support (default
|
||||
\fB@DEFAULT_USER@\fR).
|
||||
This option sets the name of the system user to which \fBchronyd\fR will switch
|
||||
after start in order to drop root privileges. It overrides the \fBuser\fR
|
||||
directive (default \fB@DEFAULT_USER@\fR). It may be set to a non-root user
|
||||
only when \fBchronyd\fR is compiled with support for Linux capabilities
|
||||
(libcap) or on NetBSD with the \fB/dev/clockctl\fR device.
|
||||
.TP
|
||||
\fB\-F\fR \fIlevel\fR
|
||||
This option configures a system call filter when \fBchronyd\fR is compiled with
|
||||
support for the Linux secure computing (seccomp) facility. In level 1 the
|
||||
process is killed when a forbidden system call is made, in level -1 the SYSSIG
|
||||
signal is thrown instead and in level 0 the filter is disabled (default 0).
|
||||
.TP
|
||||
.B \-q
|
||||
When run in this mode, chronyd will set the system clock once
|
||||
|
||||
60
clientlog.c
60
clientlog.c
@@ -263,25 +263,31 @@ find_subnet(Subnet *subnet, uint32_t *addr, int addr_len, int bits_consumed)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static Node *
|
||||
get_node(IPAddr *ip)
|
||||
{
|
||||
uint32_t ip6[4];
|
||||
|
||||
switch (ip->family) {
|
||||
case IPADDR_INET4:
|
||||
return (Node *)find_subnet(&top_subnet4, &ip->addr.in4, 1, 0);
|
||||
case IPADDR_INET6:
|
||||
split_ip6(ip, ip6);
|
||||
return (Node *)find_subnet(&top_subnet6, ip6, 4, 0);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
CLG_LogNTPClientAccess (IPAddr *client, time_t now)
|
||||
{
|
||||
uint32_t ip6[4];
|
||||
Node *node;
|
||||
|
||||
if (active) {
|
||||
switch (client->family) {
|
||||
case IPADDR_INET4:
|
||||
node = (Node *) find_subnet(&top_subnet4, &client->addr.in4, 1, 0);
|
||||
break;
|
||||
case IPADDR_INET6:
|
||||
split_ip6(client, ip6);
|
||||
node = (Node *) find_subnet(&top_subnet6, ip6, 4, 0);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
node = get_node(client);
|
||||
if (node == NULL)
|
||||
return;
|
||||
|
||||
@@ -296,22 +302,10 @@ CLG_LogNTPClientAccess (IPAddr *client, time_t now)
|
||||
void
|
||||
CLG_LogNTPPeerAccess(IPAddr *client, time_t now)
|
||||
{
|
||||
uint32_t ip6[4];
|
||||
Node *node;
|
||||
|
||||
if (active) {
|
||||
switch (client->family) {
|
||||
case IPADDR_INET4:
|
||||
node = (Node *) find_subnet(&top_subnet4, &client->addr.in4, 1, 0);
|
||||
break;
|
||||
case IPADDR_INET6:
|
||||
split_ip6(client, ip6);
|
||||
node = (Node *) find_subnet(&top_subnet6, ip6, 4, 0);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
node = get_node(client);
|
||||
if (node == NULL)
|
||||
return;
|
||||
|
||||
@@ -326,22 +320,10 @@ CLG_LogNTPPeerAccess(IPAddr *client, time_t now)
|
||||
void
|
||||
CLG_LogCommandAccess(IPAddr *client, CLG_Command_Type type, time_t now)
|
||||
{
|
||||
uint32_t ip6[4];
|
||||
Node *node;
|
||||
|
||||
if (active) {
|
||||
switch (client->family) {
|
||||
case IPADDR_INET4:
|
||||
node = (Node *) find_subnet(&top_subnet4, &client->addr.in4, 1, 0);
|
||||
break;
|
||||
case IPADDR_INET6:
|
||||
split_ip6(client, ip6);
|
||||
node = (Node *) find_subnet(&top_subnet6, ip6, 4, 0);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
node = get_node(client);
|
||||
if (node == NULL)
|
||||
return;
|
||||
|
||||
|
||||
737
cmdmon.c
737
cmdmon.c
@@ -53,15 +53,17 @@
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
union sockaddr_in46 {
|
||||
union sockaddr_all {
|
||||
struct sockaddr_in in4;
|
||||
#ifdef FEAT_IPV6
|
||||
struct sockaddr_in6 in6;
|
||||
#endif
|
||||
struct sockaddr u;
|
||||
struct sockaddr_un un;
|
||||
struct sockaddr sa;
|
||||
};
|
||||
|
||||
/* File descriptors for command and monitoring sockets */
|
||||
static int sock_fdu;
|
||||
static int sock_fd4;
|
||||
#ifdef FEAT_IPV6
|
||||
static int sock_fd6;
|
||||
@@ -70,44 +72,6 @@ static int sock_fd6;
|
||||
/* Flag indicating whether this module has been initialised or not */
|
||||
static int initialised = 0;
|
||||
|
||||
/* Token which is unique every time the daemon is run */
|
||||
static unsigned long utoken;
|
||||
|
||||
/* The register of issued tokens */
|
||||
static unsigned long issued_tokens;
|
||||
|
||||
/* The register of received tokens */
|
||||
static unsigned long returned_tokens;
|
||||
|
||||
/* The token number corresponding to the base of the registers */
|
||||
static unsigned long token_base;
|
||||
|
||||
/* The position of the next free token to issue in the issue register */
|
||||
static unsigned long issue_pointer;
|
||||
|
||||
/* Type and linked list for buffering responses */
|
||||
typedef struct _ResponseCell {
|
||||
struct _ResponseCell *next;
|
||||
unsigned long tok; /* The token that the client sent in the message
|
||||
to which this was the reply */
|
||||
unsigned long next_tok; /* The next token issued to the same client.
|
||||
If we receive a request with this token,
|
||||
it implies the reply stored in this cell
|
||||
was successfully received */
|
||||
unsigned long msg_seq; /* Client's sequence number used in request
|
||||
to which this is the response. */
|
||||
unsigned long attempt; /* Attempt number that we saw in the last request
|
||||
with this sequence number (prevents attacker
|
||||
firing the same request at us to make us
|
||||
keep generating the same reply). */
|
||||
struct timeval ts; /* Time we saved the reply - allows purging based
|
||||
on staleness. */
|
||||
CMD_Reply rpy;
|
||||
} ResponseCell;
|
||||
|
||||
static ResponseCell kept_replies;
|
||||
static ResponseCell *free_replies;
|
||||
|
||||
/* ================================================== */
|
||||
/* Array of permission levels for command types */
|
||||
|
||||
@@ -165,6 +129,7 @@ static const char permissions[] = {
|
||||
PERMIT_AUTH, /* MODIFY_MAKESTEP */
|
||||
PERMIT_OPEN, /* SMOOTHING */
|
||||
PERMIT_AUTH, /* SMOOTHTIME */
|
||||
PERMIT_AUTH, /* REFRESH */
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
@@ -184,43 +149,45 @@ prepare_socket(int family, int port_number)
|
||||
{
|
||||
int sock_fd;
|
||||
socklen_t my_addr_len;
|
||||
union sockaddr_in46 my_addr;
|
||||
union sockaddr_all my_addr;
|
||||
IPAddr bind_address;
|
||||
int on_off = 1;
|
||||
|
||||
sock_fd = socket(family, SOCK_DGRAM, 0);
|
||||
if (sock_fd < 0) {
|
||||
LOG(LOGS_ERR, LOGF_CmdMon, "Could not open %s command socket : %s",
|
||||
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
|
||||
UTI_SockaddrFamilyToString(family), strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Close on exec */
|
||||
UTI_FdSetCloexec(sock_fd);
|
||||
|
||||
/* Allow reuse of port number */
|
||||
if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on_off, sizeof(on_off)) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_CmdMon, "Could not set reuseaddr socket options");
|
||||
/* Don't quit - we might survive anyway */
|
||||
}
|
||||
if (family != AF_UNIX) {
|
||||
/* Allow reuse of port number */
|
||||
if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on_off, sizeof(on_off)) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_CmdMon, "Could not set reuseaddr socket options");
|
||||
/* Don't quit - we might survive anyway */
|
||||
}
|
||||
|
||||
#ifdef IP_FREEBIND
|
||||
/* Allow binding to address that doesn't exist yet */
|
||||
if (setsockopt(sock_fd, IPPROTO_IP, IP_FREEBIND, (char *)&on_off, sizeof(on_off)) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_CmdMon, "Could not set free bind socket option");
|
||||
}
|
||||
/* Allow binding to address that doesn't exist yet */
|
||||
if (setsockopt(sock_fd, IPPROTO_IP, IP_FREEBIND, (char *)&on_off, sizeof(on_off)) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_CmdMon, "Could not set free bind socket option");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_IPV6
|
||||
if (family == AF_INET6) {
|
||||
if (family == AF_INET6) {
|
||||
#ifdef IPV6_V6ONLY
|
||||
/* Receive IPv6 packets only */
|
||||
if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on_off, sizeof(on_off)) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_CmdMon, "Could not request IPV6_V6ONLY socket option");
|
||||
/* Receive IPv6 packets only */
|
||||
if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on_off, sizeof(on_off)) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_CmdMon, "Could not request IPV6_V6ONLY socket option");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
memset(&my_addr, 0, sizeof (my_addr));
|
||||
|
||||
@@ -252,13 +219,21 @@ prepare_socket(int family, int port_number)
|
||||
my_addr.in6.sin6_addr = in6addr_loopback;
|
||||
break;
|
||||
#endif
|
||||
case AF_UNIX:
|
||||
my_addr_len = sizeof (my_addr.un);
|
||||
my_addr.un.sun_family = family;
|
||||
if (snprintf(my_addr.un.sun_path, sizeof (my_addr.un.sun_path), "%s",
|
||||
CNF_GetBindCommandPath()) >= sizeof (my_addr.un.sun_path))
|
||||
LOG_FATAL(LOGF_CmdMon, "Unix socket path too long");
|
||||
unlink(my_addr.un.sun_path);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (bind(sock_fd, &my_addr.u, my_addr_len) < 0) {
|
||||
if (bind(sock_fd, &my_addr.sa, my_addr_len) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_CmdMon, "Could not bind %s command socket : %s",
|
||||
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
|
||||
UTI_SockaddrFamilyToString(family), strerror(errno));
|
||||
close(sock_fd);
|
||||
return -1;
|
||||
}
|
||||
@@ -293,14 +268,7 @@ CAM_Initialise(int family)
|
||||
assert(command_length == 0 || command_length >= offsetof(CMD_Reply, data));
|
||||
}
|
||||
|
||||
utoken = (unsigned long) time(NULL);
|
||||
|
||||
issued_tokens = returned_tokens = issue_pointer = 0;
|
||||
token_base = 1; /* zero is the value used when the previous command was
|
||||
unauthenticated */
|
||||
|
||||
free_replies = NULL;
|
||||
kept_replies.next = NULL;
|
||||
sock_fdu = -1;
|
||||
|
||||
port_number = CNF_GetCommandPort();
|
||||
|
||||
@@ -332,6 +300,12 @@ CAM_Initialise(int family)
|
||||
void
|
||||
CAM_Finalise(void)
|
||||
{
|
||||
if (sock_fdu >= 0) {
|
||||
SCH_RemoveInputFileHandler(sock_fdu);
|
||||
close(sock_fdu);
|
||||
unlink(CNF_GetBindCommandPath());
|
||||
}
|
||||
sock_fdu = -1;
|
||||
if (sock_fd4 >= 0) {
|
||||
SCH_RemoveInputFileHandler(sock_fd4);
|
||||
close(sock_fd4);
|
||||
@@ -351,343 +325,27 @@ CAM_Finalise(void)
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* This function checks whether the authenticator field of the packet
|
||||
checks correctly against what we would compute locally given the
|
||||
rest of the packet */
|
||||
|
||||
static int
|
||||
check_rx_packet_auth(CMD_Request *packet, int packet_len)
|
||||
void
|
||||
CAM_OpenUnixSocket(void)
|
||||
{
|
||||
int pkt_len, auth_len;
|
||||
|
||||
pkt_len = PKL_CommandLength(packet);
|
||||
auth_len = packet_len - pkt_len;
|
||||
|
||||
return KEY_CheckAuth(KEY_GetCommandKey(), (unsigned char *)packet,
|
||||
pkt_len, ((unsigned char *)packet) + pkt_len, auth_len);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
generate_tx_packet_auth(CMD_Reply *packet)
|
||||
{
|
||||
int pkt_len;
|
||||
|
||||
pkt_len = PKL_ReplyLength(packet);
|
||||
|
||||
return KEY_GenerateAuth(KEY_GetCommandKey(), (unsigned char *)packet,
|
||||
pkt_len, ((unsigned char *)packet) + pkt_len, sizeof (packet->auth));
|
||||
/* This is separated from CAM_Initialise() as it needs to be called when
|
||||
the process has already dropped the root privileges */
|
||||
if (CNF_GetBindCommandPath()[0])
|
||||
sock_fdu = prepare_socket(AF_UNIX, 0);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
shift_tokens(void)
|
||||
{
|
||||
do {
|
||||
issued_tokens >>= 1;
|
||||
returned_tokens >>= 1;
|
||||
token_base++;
|
||||
issue_pointer--;
|
||||
} while ((issued_tokens & 1) && (returned_tokens & 1));
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static unsigned long
|
||||
get_token(void)
|
||||
{
|
||||
unsigned long result;
|
||||
|
||||
if (issue_pointer == 32) {
|
||||
/* The lowest number open token has not been returned - bad luck
|
||||
to that command client */
|
||||
shift_tokens();
|
||||
}
|
||||
|
||||
result = token_base + issue_pointer;
|
||||
issued_tokens |= (1UL << issue_pointer);
|
||||
issue_pointer++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
check_token(unsigned long token)
|
||||
{
|
||||
int result;
|
||||
unsigned long pos;
|
||||
|
||||
if (token < token_base) {
|
||||
/* Token too old */
|
||||
result = 0;
|
||||
} else {
|
||||
pos = token - token_base;
|
||||
if (pos >= issue_pointer) {
|
||||
/* Token hasn't been issued yet */
|
||||
result = 0;
|
||||
} else {
|
||||
if (returned_tokens & (1UL << pos)) {
|
||||
/* Token has already been returned */
|
||||
result = 0;
|
||||
} else {
|
||||
/* Token is OK */
|
||||
result = 1;
|
||||
returned_tokens |= (1UL << pos);
|
||||
if (pos == 0) {
|
||||
shift_tokens();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#define TS_MARGIN 20
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
typedef struct _TimestampCell {
|
||||
struct _TimestampCell *next;
|
||||
struct timeval ts;
|
||||
} TimestampCell;
|
||||
|
||||
static struct _TimestampCell seen_ts_list={NULL};
|
||||
static struct _TimestampCell *free_ts_list=NULL;
|
||||
|
||||
#define EXTEND_QUANTUM 32
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static TimestampCell *
|
||||
allocate_ts_cell(void)
|
||||
{
|
||||
TimestampCell *result;
|
||||
int i;
|
||||
if (free_ts_list == NULL) {
|
||||
free_ts_list = MallocArray(TimestampCell, EXTEND_QUANTUM);
|
||||
for (i=0; i<EXTEND_QUANTUM-1; i++) {
|
||||
free_ts_list[i].next = free_ts_list + i + 1;
|
||||
}
|
||||
free_ts_list[EXTEND_QUANTUM - 1].next = NULL;
|
||||
}
|
||||
|
||||
result = free_ts_list;
|
||||
free_ts_list = free_ts_list->next;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
release_ts_cell(TimestampCell *node)
|
||||
{
|
||||
node->next = free_ts_list;
|
||||
free_ts_list = node;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Return 1 if not found, 0 if found (i.e. not unique). Prune out any
|
||||
stale entries. */
|
||||
|
||||
static int
|
||||
check_unique_ts(struct timeval *ts, struct timeval *now)
|
||||
{
|
||||
TimestampCell *last_valid, *cell, *next;
|
||||
int ok;
|
||||
|
||||
ok = 1;
|
||||
last_valid = &(seen_ts_list);
|
||||
cell = last_valid->next;
|
||||
|
||||
while (cell) {
|
||||
next = cell->next;
|
||||
/* Check if stale */
|
||||
if ((now->tv_sec - cell->ts.tv_sec) > TS_MARGIN) {
|
||||
release_ts_cell(cell);
|
||||
last_valid->next = next;
|
||||
} else {
|
||||
/* Timestamp in cell is still within window */
|
||||
last_valid->next = cell;
|
||||
last_valid = cell;
|
||||
if ((cell->ts.tv_sec == ts->tv_sec) && (cell->ts.tv_usec == ts->tv_usec)) {
|
||||
ok = 0;
|
||||
}
|
||||
}
|
||||
cell = next;
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
/* Need to add this timestamp to the list */
|
||||
cell = allocate_ts_cell();
|
||||
last_valid->next = cell;
|
||||
cell->next = NULL;
|
||||
cell->ts = *ts;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
ts_is_unique_and_not_stale(struct timeval *ts, struct timeval *now)
|
||||
{
|
||||
int within_margin=0;
|
||||
int is_unique=0;
|
||||
long diff;
|
||||
|
||||
diff = now->tv_sec - ts->tv_sec;
|
||||
if ((diff < TS_MARGIN) && (diff > -TS_MARGIN)) {
|
||||
within_margin = 1;
|
||||
} else {
|
||||
within_margin = 0;
|
||||
}
|
||||
is_unique = check_unique_ts(ts, now);
|
||||
|
||||
return within_margin && is_unique;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#define REPLY_EXTEND_QUANTUM 8
|
||||
|
||||
static void
|
||||
get_more_replies(void)
|
||||
{
|
||||
ResponseCell *new_replies;
|
||||
int i;
|
||||
|
||||
if (!free_replies) {
|
||||
new_replies = MallocArray(ResponseCell, REPLY_EXTEND_QUANTUM);
|
||||
for (i=1; i<REPLY_EXTEND_QUANTUM; i++) {
|
||||
new_replies[i-1].next = new_replies + i;
|
||||
}
|
||||
new_replies[REPLY_EXTEND_QUANTUM - 1].next = NULL;
|
||||
free_replies = new_replies;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static ResponseCell *
|
||||
get_reply_slot(void)
|
||||
{
|
||||
ResponseCell *result;
|
||||
if (!free_replies) {
|
||||
get_more_replies();
|
||||
}
|
||||
result = free_replies;
|
||||
free_replies = result->next;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
free_reply_slot(ResponseCell *cell)
|
||||
{
|
||||
cell->next = free_replies;
|
||||
free_replies = cell;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
save_reply(CMD_Reply *msg,
|
||||
unsigned long tok_reply_to,
|
||||
unsigned long new_tok_issued,
|
||||
unsigned long client_msg_seq,
|
||||
unsigned short attempt,
|
||||
struct timeval *now)
|
||||
{
|
||||
ResponseCell *cell;
|
||||
|
||||
cell = get_reply_slot();
|
||||
|
||||
cell->ts = *now;
|
||||
memcpy(&cell->rpy, msg, sizeof(CMD_Reply));
|
||||
cell->tok = tok_reply_to;
|
||||
cell->next_tok = new_tok_issued;
|
||||
cell->msg_seq = client_msg_seq;
|
||||
cell->attempt = (unsigned long) attempt;
|
||||
|
||||
cell->next = kept_replies.next;
|
||||
kept_replies.next = cell;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static CMD_Reply *
|
||||
lookup_reply(unsigned long prev_msg_token, unsigned long client_msg_seq, unsigned short attempt)
|
||||
{
|
||||
ResponseCell *ptr;
|
||||
|
||||
ptr = kept_replies.next;
|
||||
while (ptr) {
|
||||
if ((ptr->tok == prev_msg_token) &&
|
||||
(ptr->msg_seq == client_msg_seq) &&
|
||||
((unsigned long) attempt > ptr->attempt)) {
|
||||
|
||||
/* Set the attempt field to remember the highest number we have
|
||||
had so far */
|
||||
ptr->attempt = (unsigned long) attempt;
|
||||
return &ptr->rpy;
|
||||
}
|
||||
ptr = ptr->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#define REPLY_MAXAGE 300
|
||||
|
||||
static void
|
||||
token_acknowledged(unsigned long token, struct timeval *now)
|
||||
{
|
||||
ResponseCell *last_valid, *cell, *next;
|
||||
|
||||
last_valid = &kept_replies;
|
||||
cell = kept_replies.next;
|
||||
|
||||
while(cell) {
|
||||
next = cell->next;
|
||||
|
||||
/* Discard if it's the one or if the reply is stale */
|
||||
if ((cell->next_tok == token) ||
|
||||
((now->tv_sec - cell->ts.tv_sec) > REPLY_MAXAGE)) {
|
||||
free_reply_slot(cell);
|
||||
last_valid->next = next;
|
||||
} else {
|
||||
last_valid->next = cell;
|
||||
last_valid = cell;
|
||||
}
|
||||
cell = next;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to, int auth_len)
|
||||
transmit_reply(CMD_Reply *msg, union sockaddr_all *where_to)
|
||||
{
|
||||
int status;
|
||||
int tx_message_length;
|
||||
int sock_fd;
|
||||
socklen_t addrlen;
|
||||
|
||||
switch (where_to->u.sa_family) {
|
||||
|
||||
switch (where_to->sa.sa_family) {
|
||||
case AF_INET:
|
||||
sock_fd = sock_fd4;
|
||||
addrlen = sizeof (where_to->in4);
|
||||
@@ -698,21 +356,26 @@ transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to, int auth_len)
|
||||
addrlen = sizeof (where_to->in6);
|
||||
break;
|
||||
#endif
|
||||
case AF_UNIX:
|
||||
sock_fd = sock_fdu;
|
||||
addrlen = sizeof (where_to->un);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
tx_message_length = PKL_ReplyLength(msg) + auth_len;
|
||||
tx_message_length = PKL_ReplyLength(msg);
|
||||
status = sendto(sock_fd, (void *) msg, tx_message_length, 0,
|
||||
&where_to->u, addrlen);
|
||||
&where_to->sa, addrlen);
|
||||
|
||||
if (status < 0) {
|
||||
unsigned short port;
|
||||
IPAddr ip;
|
||||
|
||||
UTI_SockaddrToIPAndPort(&where_to->u, &ip, &port);
|
||||
DEBUG_LOG(LOGF_CmdMon, "Could not send response to %s:%hu", UTI_IPToString(&ip), port);
|
||||
DEBUG_LOG(LOGF_CmdMon, "Could not send to %s fd %d : %s",
|
||||
UTI_SockaddrToString(&where_to->sa), sock_fd, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_LOG(LOGF_CmdMon, "Sent %d bytes to %s fd %d", status,
|
||||
UTI_SockaddrToString(&where_to->sa), sock_fd);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1478,6 +1141,14 @@ handle_reselect(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
SRC_ReselectSource();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
handle_refresh(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
NSR_RefreshAddresses();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Read a packet and process it */
|
||||
|
||||
@@ -1489,26 +1160,16 @@ read_from_cmd_socket(void *anything)
|
||||
int expected_length; /* Expected length of packet without auth data */
|
||||
unsigned long flags;
|
||||
CMD_Request rx_message;
|
||||
CMD_Reply tx_message, *prev_tx_message;
|
||||
int rx_message_length, tx_message_length;
|
||||
CMD_Reply tx_message;
|
||||
int rx_message_length;
|
||||
int sock_fd;
|
||||
union sockaddr_in46 where_from;
|
||||
union sockaddr_all where_from;
|
||||
socklen_t from_length;
|
||||
IPAddr remote_ip;
|
||||
unsigned short remote_port;
|
||||
int auth_length;
|
||||
int auth_ok;
|
||||
int utoken_ok, token_ok;
|
||||
int issue_token;
|
||||
int valid_ts;
|
||||
int authenticated;
|
||||
int localhost;
|
||||
int allowed;
|
||||
unsigned short rx_command;
|
||||
unsigned long rx_message_token;
|
||||
unsigned long tx_message_token;
|
||||
unsigned long rx_message_seq;
|
||||
unsigned long rx_attempt;
|
||||
struct timeval now;
|
||||
struct timeval cooked_now;
|
||||
|
||||
@@ -1518,7 +1179,7 @@ read_from_cmd_socket(void *anything)
|
||||
|
||||
sock_fd = (long)anything;
|
||||
status = recvfrom(sock_fd, (char *)&rx_message, rx_message_length, flags,
|
||||
&where_from.u, &from_length);
|
||||
&where_from.sa, &from_length);
|
||||
|
||||
if (status < 0) {
|
||||
LOG(LOGS_WARN, LOGF_CmdMon, "Error [%s] reading from control socket %d",
|
||||
@@ -1526,31 +1187,46 @@ read_from_cmd_socket(void *anything)
|
||||
return;
|
||||
}
|
||||
|
||||
if (from_length > sizeof (where_from))
|
||||
LOG_FATAL(LOGF_CmdMon, "Truncated source address");
|
||||
if (from_length > sizeof (where_from) ||
|
||||
from_length <= sizeof (where_from.sa.sa_family)) {
|
||||
DEBUG_LOG(LOGF_CmdMon, "Read command packet without source address");
|
||||
return;
|
||||
}
|
||||
|
||||
read_length = status;
|
||||
|
||||
/* Get current time cheaply */
|
||||
SCH_GetLastEventTime(&cooked_now, NULL, &now);
|
||||
|
||||
UTI_SockaddrToIPAndPort(&where_from.u, &remote_ip, &remote_port);
|
||||
UTI_SockaddrToIPAndPort(&where_from.sa, &remote_ip, &remote_port);
|
||||
|
||||
/* Check if it's a loopback address (127.0.0.1 or ::1) */
|
||||
/* Check if it's from localhost (127.0.0.1, ::1, or Unix domain) */
|
||||
switch (remote_ip.family) {
|
||||
case IPADDR_INET4:
|
||||
assert(sock_fd == sock_fd4);
|
||||
localhost = remote_ip.addr.in4 == INADDR_LOOPBACK;
|
||||
break;
|
||||
#ifdef FEAT_IPV6
|
||||
case IPADDR_INET6:
|
||||
assert(sock_fd == sock_fd6);
|
||||
localhost = !memcmp(remote_ip.addr.in6, &in6addr_loopback,
|
||||
sizeof (in6addr_loopback));
|
||||
break;
|
||||
#endif
|
||||
case IPADDR_UNSPEC:
|
||||
/* This should be the Unix domain socket */
|
||||
if (where_from.sa.sa_family != AF_UNIX)
|
||||
return;
|
||||
assert(sock_fd == sock_fdu);
|
||||
localhost = 1;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
DEBUG_LOG(LOGF_CmdMon, "Received %d bytes from %s fd %d",
|
||||
status, UTI_SockaddrToString(&where_from.sa), sock_fd);
|
||||
|
||||
if (!(localhost || ADF_IsAllowed(access_auth_table, &remote_ip))) {
|
||||
/* The client is not allowed access, so don't waste any more time
|
||||
on him. Note that localhost is always allowed access
|
||||
@@ -1585,204 +1261,79 @@ read_from_cmd_socket(void *anything)
|
||||
tx_message.res1 = 0;
|
||||
tx_message.res2 = 0;
|
||||
tx_message.command = rx_message.command;
|
||||
tx_message.sequence = rx_message.sequence;
|
||||
tx_message.reply = htons(RPY_NULL);
|
||||
tx_message.status = htons(STT_SUCCESS);
|
||||
tx_message.pad1 = 0;
|
||||
tx_message.pad2 = 0;
|
||||
tx_message.pad3 = 0;
|
||||
tx_message.utoken = htonl(utoken);
|
||||
/* Set this to a default (invalid) value. This protects against the
|
||||
token field being set to an arbitrary value if we reject the
|
||||
message, e.g. due to the host failing the access check. */
|
||||
tx_message.token = htonl(0xffffffffUL);
|
||||
memset(&tx_message.auth, 0, sizeof(tx_message.auth));
|
||||
tx_message.sequence = rx_message.sequence;
|
||||
tx_message.pad4 = 0;
|
||||
tx_message.pad5 = 0;
|
||||
|
||||
if (rx_message.version != PROTO_VERSION_NUMBER) {
|
||||
DEBUG_LOG(LOGF_CmdMon, "Read command packet with protocol version %d (expected %d) from %s:%hu", rx_message.version, PROTO_VERSION_NUMBER, UTI_IPToString(&remote_ip), remote_port);
|
||||
DEBUG_LOG(LOGF_CmdMon, "Read command packet with protocol version %d (expected %d) from %s",
|
||||
rx_message.version, PROTO_VERSION_NUMBER, UTI_SockaddrToString(&where_from.sa));
|
||||
|
||||
CLG_LogCommandAccess(&remote_ip, CLG_CMD_BAD_PKT, cooked_now.tv_sec);
|
||||
|
||||
if (rx_message.version >= PROTO_VERSION_MISMATCH_COMPAT_SERVER) {
|
||||
tx_message.status = htons(STT_BADPKTVERSION);
|
||||
transmit_reply(&tx_message, &where_from, 0);
|
||||
transmit_reply(&tx_message, &where_from);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (rx_command >= N_REQUEST_TYPES) {
|
||||
DEBUG_LOG(LOGF_CmdMon, "Read command packet with invalid command %d from %s:%hu", rx_command, UTI_IPToString(&remote_ip), remote_port);
|
||||
DEBUG_LOG(LOGF_CmdMon, "Read command packet with invalid command %d from %s",
|
||||
rx_command, UTI_SockaddrToString(&where_from.sa));
|
||||
|
||||
CLG_LogCommandAccess(&remote_ip, CLG_CMD_BAD_PKT, cooked_now.tv_sec);
|
||||
|
||||
tx_message.status = htons(STT_INVALID);
|
||||
transmit_reply(&tx_message, &where_from, 0);
|
||||
transmit_reply(&tx_message, &where_from);
|
||||
return;
|
||||
}
|
||||
|
||||
if (read_length < expected_length) {
|
||||
DEBUG_LOG(LOGF_CmdMon, "Read incorrectly sized command packet from %s:%hu", UTI_IPToString(&remote_ip), remote_port);
|
||||
DEBUG_LOG(LOGF_CmdMon, "Read incorrectly sized command packet from %s",
|
||||
UTI_SockaddrToString(&where_from.sa));
|
||||
|
||||
CLG_LogCommandAccess(&remote_ip, CLG_CMD_BAD_PKT, cooked_now.tv_sec);
|
||||
|
||||
tx_message.status = htons(STT_BADPKTLENGTH);
|
||||
transmit_reply(&tx_message, &where_from, 0);
|
||||
transmit_reply(&tx_message, &where_from);
|
||||
return;
|
||||
}
|
||||
|
||||
/* OK, we have a valid message. Now dispatch on message type and process it. */
|
||||
|
||||
/* Do authentication stuff and command tokens here. Well-behaved
|
||||
clients will set their utokens to 0 to save us wasting our time
|
||||
if the packet is unauthenticatable. */
|
||||
if (rx_message.utoken != 0) {
|
||||
auth_ok = check_rx_packet_auth(&rx_message, read_length);
|
||||
} else {
|
||||
auth_ok = 0;
|
||||
}
|
||||
|
||||
/* All this malarky is to protect the system against various forms
|
||||
of attack.
|
||||
|
||||
Simple packet forgeries are blocked by requiring the packet to
|
||||
authenticate properly with MD5 or other crypto hash. (The
|
||||
assumption is that the command key is in a read-only keys file
|
||||
read by the daemon, and is known only to administrators.)
|
||||
|
||||
Replay attacks are prevented by 2 fields in the packet. The
|
||||
'token' field is where the client plays back to us a token that
|
||||
he was issued in an earlier reply. Each time we reply to a
|
||||
suitable packet, we issue a new token. The 'utoken' field is set
|
||||
to a new (hopefully increasing) value each time the daemon is
|
||||
run. This prevents packets from a previous incarnation being
|
||||
played back at us when the same point in the 'token' sequence
|
||||
comes up. (The token mechanism also prevents a non-idempotent
|
||||
command from being executed twice from the same client, if the
|
||||
client fails to receive our reply the first time and tries a
|
||||
resend.)
|
||||
|
||||
The problem is how a client should get its first token. Our
|
||||
token handling only remembers a finite number of issued tokens
|
||||
(actually 32) - if a client replies with a (legitimate) token
|
||||
older than that, it will be treated as though a duplicate token
|
||||
has been supplied. If a simple token-request protocol were used,
|
||||
the whole thing would be vulnerable to a denial of service
|
||||
attack, where an attacker just replays valid token-request
|
||||
packets at us, causing us to keep issuing new tokens,
|
||||
invalidating all the ones we have given out to true clients
|
||||
already.
|
||||
|
||||
To protect against this, the token-request (REQ_LOGON) packet
|
||||
includes a timestamp field. To issue a token, we require that
|
||||
this field is different from any we have processed before. To
|
||||
bound our storage, we require that the timestamp is within a
|
||||
certain period of our current time. For clients running on the
|
||||
same host this will be easily satisfied.
|
||||
|
||||
*/
|
||||
|
||||
utoken_ok = (ntohl(rx_message.utoken) == utoken);
|
||||
|
||||
/* Avoid binning a valid user's token if we merely get a forged
|
||||
packet */
|
||||
rx_message_token = ntohl(rx_message.token);
|
||||
rx_message_seq = ntohl(rx_message.sequence);
|
||||
rx_attempt = ntohs(rx_message.attempt);
|
||||
|
||||
if (auth_ok && utoken_ok) {
|
||||
token_ok = check_token(rx_message_token);
|
||||
} else {
|
||||
token_ok = 0;
|
||||
}
|
||||
|
||||
if (auth_ok && utoken_ok && !token_ok) {
|
||||
/* This might be a resent message, due to the client not getting
|
||||
our reply to the first attempt. See if we can find the message. */
|
||||
prev_tx_message = lookup_reply(rx_message_token, rx_message_seq, rx_attempt);
|
||||
if (prev_tx_message) {
|
||||
/* Just send this message again */
|
||||
tx_message_length = PKL_ReplyLength(prev_tx_message);
|
||||
status = sendto(sock_fd, (void *) prev_tx_message, tx_message_length, 0,
|
||||
&where_from.u, from_length);
|
||||
if (status < 0) {
|
||||
DEBUG_LOG(LOGF_CmdMon, "Could not send response to %s:%hu", UTI_IPToString(&remote_ip), remote_port);
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* Otherwise, just fall through into normal processing */
|
||||
|
||||
}
|
||||
|
||||
if (auth_ok && utoken_ok && token_ok) {
|
||||
/* See whether we can discard the previous reply from storage */
|
||||
token_acknowledged(rx_message_token, &now);
|
||||
}
|
||||
|
||||
valid_ts = 0;
|
||||
issue_token = 0;
|
||||
|
||||
if (auth_ok) {
|
||||
if (utoken_ok && token_ok) {
|
||||
issue_token = 1;
|
||||
} else if (rx_command == REQ_LOGON &&
|
||||
ntohl(rx_message.utoken) == SPECIAL_UTOKEN) {
|
||||
struct timeval ts;
|
||||
|
||||
UTI_TimevalNetworkToHost(&rx_message.data.logon.ts, &ts);
|
||||
valid_ts = ts_is_unique_and_not_stale(&ts, &now);
|
||||
|
||||
if (valid_ts) {
|
||||
issue_token = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
authenticated = auth_ok & utoken_ok & token_ok;
|
||||
|
||||
if (authenticated) {
|
||||
CLG_LogCommandAccess(&remote_ip, CLG_CMD_AUTH, cooked_now.tv_sec);
|
||||
} else {
|
||||
CLG_LogCommandAccess(&remote_ip, CLG_CMD_NORMAL, cooked_now.tv_sec);
|
||||
}
|
||||
|
||||
if (issue_token) {
|
||||
/* Only command clients where the user has apparently 'logged on'
|
||||
get a token to allow them to emit an authenticated command next
|
||||
time */
|
||||
tx_message_token = get_token();
|
||||
} else {
|
||||
tx_message_token = 0xffffffffUL;
|
||||
}
|
||||
|
||||
tx_message.token = htonl(tx_message_token);
|
||||
|
||||
CLG_LogCommandAccess(&remote_ip, CLG_CMD_NORMAL, cooked_now.tv_sec);
|
||||
|
||||
if (rx_command >= N_REQUEST_TYPES) {
|
||||
/* This should be already handled */
|
||||
assert(0);
|
||||
} else {
|
||||
/* Check level of authority required to issue the command */
|
||||
switch(permissions[rx_command]) {
|
||||
case PERMIT_AUTH:
|
||||
if (authenticated) {
|
||||
allowed = 1;
|
||||
} else {
|
||||
/* Check level of authority required to issue the command. All commands
|
||||
from the Unix domain socket (which is accessible only by the root and
|
||||
chrony user/group) are allowed. */
|
||||
if (where_from.sa.sa_family == AF_UNIX) {
|
||||
assert(sock_fd == sock_fdu);
|
||||
allowed = 1;
|
||||
} else {
|
||||
switch (permissions[rx_command]) {
|
||||
case PERMIT_AUTH:
|
||||
allowed = 0;
|
||||
}
|
||||
break;
|
||||
case PERMIT_LOCAL:
|
||||
if (authenticated || localhost) {
|
||||
break;
|
||||
case PERMIT_LOCAL:
|
||||
allowed = localhost;
|
||||
break;
|
||||
case PERMIT_OPEN:
|
||||
allowed = 1;
|
||||
} else {
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
allowed = 0;
|
||||
}
|
||||
break;
|
||||
case PERMIT_OPEN:
|
||||
allowed = 1;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
allowed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (allowed) {
|
||||
@@ -1836,25 +1387,8 @@ read_from_cmd_socket(void *anything)
|
||||
break;
|
||||
|
||||
case REQ_LOGON:
|
||||
/* If the log-on fails, record the reason why */
|
||||
if (!issue_token) {
|
||||
DEBUG_LOG(LOGF_CmdMon,
|
||||
"Bad command logon from %s port %d (auth_ok=%d valid_ts=%d)",
|
||||
UTI_IPToString(&remote_ip),
|
||||
remote_port,
|
||||
auth_ok, valid_ts);
|
||||
}
|
||||
|
||||
if (issue_token == 1) {
|
||||
tx_message.status = htons(STT_SUCCESS);
|
||||
} else if (!auth_ok) {
|
||||
tx_message.status = htons(STT_UNAUTH);
|
||||
} else if (!valid_ts) {
|
||||
tx_message.status = htons(STT_INVALIDTS);
|
||||
} else {
|
||||
tx_message.status = htons(STT_FAILED);
|
||||
}
|
||||
|
||||
/* Authentication is no longer supported, log-on always fails */
|
||||
tx_message.status = htons(STT_FAILED);
|
||||
break;
|
||||
|
||||
case REQ_SETTIME:
|
||||
@@ -2009,6 +1543,10 @@ read_from_cmd_socket(void *anything)
|
||||
handle_modify_polltarget(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_REFRESH:
|
||||
handle_refresh(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
@@ -2018,21 +1556,6 @@ read_from_cmd_socket(void *anything)
|
||||
}
|
||||
}
|
||||
|
||||
if (auth_ok) {
|
||||
auth_length = generate_tx_packet_auth(&tx_message);
|
||||
} else {
|
||||
auth_length = 0;
|
||||
}
|
||||
|
||||
if (token_ok) {
|
||||
save_reply(&tx_message,
|
||||
rx_message_token,
|
||||
tx_message_token,
|
||||
rx_message_seq,
|
||||
rx_attempt,
|
||||
&now);
|
||||
}
|
||||
|
||||
/* Transmit the response */
|
||||
{
|
||||
/* Include a simple way to lose one message in three to test resend */
|
||||
@@ -2040,7 +1563,7 @@ read_from_cmd_socket(void *anything)
|
||||
static int do_it=1;
|
||||
|
||||
if (do_it) {
|
||||
transmit_reply(&tx_message, &where_from, auth_length);
|
||||
transmit_reply(&tx_message, &where_from);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
1
cmdmon.h
1
cmdmon.h
@@ -33,6 +33,7 @@ extern void CAM_Initialise(int family);
|
||||
|
||||
extern void CAM_Finalise(void);
|
||||
|
||||
extern void CAM_OpenUnixSocket(void);
|
||||
extern int CAM_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all);
|
||||
extern int CAM_CheckAccessRestriction(IPAddr *ip_addr);
|
||||
|
||||
|
||||
124
conf.c
124
conf.c
@@ -47,7 +47,6 @@
|
||||
|
||||
static int parse_string(char *line, char **result);
|
||||
static int parse_int(char *line, int *result);
|
||||
static int parse_uint32(char *, uint32_t *result);
|
||||
static int parse_double(char *line, double *result);
|
||||
static int parse_null(char *line);
|
||||
|
||||
@@ -80,19 +79,18 @@ static void parse_tempcomp(char *);
|
||||
/* Configuration variables */
|
||||
|
||||
static int restarted = 0;
|
||||
static int generate_command_key = 0;
|
||||
static char *rtc_device;
|
||||
static int acquisition_port = -1;
|
||||
static int ntp_port = 123;
|
||||
static char *keys_file = NULL;
|
||||
static char *drift_file = NULL;
|
||||
static char *rtc_file = NULL;
|
||||
static uint32_t command_key_id;
|
||||
static double max_update_skew = 1000.0;
|
||||
static double correction_time_ratio = 3.0;
|
||||
static double max_clock_error = 1.0; /* in ppm */
|
||||
static double max_slew_rate = 1e6 / 12.0; /* in ppm */
|
||||
|
||||
static double max_distance = 3.0;
|
||||
static double reselect_distance = 1e-4;
|
||||
static double stratum_weight = 1e-3;
|
||||
static double combine_limit = 3.0;
|
||||
@@ -182,6 +180,9 @@ static IPAddr bind_acq_address4, bind_acq_address6;
|
||||
the loopback address will be used */
|
||||
static IPAddr bind_cmd_address4, bind_cmd_address6;
|
||||
|
||||
/* Path to the Unix domain command socket. */
|
||||
static char *bind_cmd_path;
|
||||
|
||||
/* Filename to use for storing pid of running chronyd, to prevent multiple
|
||||
* chronyds being started. */
|
||||
static char *pidfile;
|
||||
@@ -320,6 +321,7 @@ CNF_Initialise(int r)
|
||||
|
||||
dumpdir = Strdup(".");
|
||||
logdir = Strdup(".");
|
||||
bind_cmd_path = Strdup(DEFAULT_COMMAND_SOCKET);
|
||||
pidfile = Strdup("/var/run/chronyd.pid");
|
||||
rtc_device = Strdup("/dev/rtc");
|
||||
user = Strdup(DEFAULT_USER);
|
||||
@@ -349,6 +351,7 @@ CNF_Finalise(void)
|
||||
Free(keys_file);
|
||||
Free(leapsec_tz);
|
||||
Free(logdir);
|
||||
Free(bind_cmd_path);
|
||||
Free(pidfile);
|
||||
Free(rtc_device);
|
||||
Free(rtc_file);
|
||||
@@ -370,10 +373,13 @@ CNF_ReadFile(const char *filename)
|
||||
|
||||
in = fopen(filename, "r");
|
||||
if (!in) {
|
||||
LOG_FATAL(LOGF_Configure, "Could not open configuration file %s", filename);
|
||||
LOG_FATAL(LOGF_Configure, "Could not open configuration file %s : %s",
|
||||
filename, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_LOG(LOGF_Configure, "Reading %s", filename);
|
||||
|
||||
for (i = 1; fgets(line, sizeof(line), in); i++) {
|
||||
CNF_ParseLine(filename, i, line);
|
||||
}
|
||||
@@ -426,8 +432,6 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
parse_int(p, &cmd_port);
|
||||
} else if (!strcasecmp(command, "combinelimit")) {
|
||||
parse_double(p, &combine_limit);
|
||||
} else if (!strcasecmp(command, "commandkey")) {
|
||||
parse_uint32(p, &command_key_id);
|
||||
} else if (!strcasecmp(command, "corrtimeratio")) {
|
||||
parse_double(p, &correction_time_ratio);
|
||||
} else if (!strcasecmp(command, "deny")) {
|
||||
@@ -440,8 +444,6 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
do_dump_on_exit = parse_null(p);
|
||||
} else if (!strcasecmp(command, "fallbackdrift")) {
|
||||
parse_fallbackdrift(p);
|
||||
} else if (!strcasecmp(command, "generatecommandkey")) {
|
||||
generate_command_key = parse_null(p);
|
||||
} else if (!strcasecmp(command, "hwclockfile")) {
|
||||
parse_string(p, &hwclock_file);
|
||||
} else if (!strcasecmp(command, "include")) {
|
||||
@@ -454,10 +456,6 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
parse_leapsecmode(p);
|
||||
} else if (!strcasecmp(command, "leapsectz")) {
|
||||
parse_string(p, &leapsec_tz);
|
||||
} else if (!strcasecmp(command, "linux_freq_scale")) {
|
||||
LOG(LOGS_WARN, LOGF_Configure, "%s directive is no longer supported", command);
|
||||
} else if (!strcasecmp(command, "linux_hz")) {
|
||||
LOG(LOGS_WARN, LOGF_Configure, "%s directive is no longer supported", command);
|
||||
} else if (!strcasecmp(command, "local")) {
|
||||
parse_local(p);
|
||||
} else if (!strcasecmp(command, "lock_all")) {
|
||||
@@ -480,6 +478,8 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
parse_maxchange(p);
|
||||
} else if (!strcasecmp(command, "maxclockerror")) {
|
||||
parse_double(p, &max_clock_error);
|
||||
} else if (!strcasecmp(command, "maxdistance")) {
|
||||
parse_double(p, &max_distance);
|
||||
} else if (!strcasecmp(command, "maxsamples")) {
|
||||
parse_int(p, &max_samples);
|
||||
} else if (!strcasecmp(command, "maxslewrate")) {
|
||||
@@ -526,6 +526,11 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
parse_tempcomp(p);
|
||||
} else if (!strcasecmp(command, "user")) {
|
||||
parse_string(p, &user);
|
||||
} else if (!strcasecmp(command, "commandkey") ||
|
||||
!strcasecmp(command, "generatecommandkey") ||
|
||||
!strcasecmp(command, "linux_freq_scale") ||
|
||||
!strcasecmp(command, "linux_hz")) {
|
||||
LOG(LOGS_WARN, LOGF_Configure, "%s directive is no longer supported", command);
|
||||
} else {
|
||||
other_parse_error("Invalid command");
|
||||
}
|
||||
@@ -557,19 +562,6 @@ parse_int(char *line, int *result)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
parse_uint32(char *line, uint32_t *result)
|
||||
{
|
||||
check_number_of_args(line, 1);
|
||||
if (sscanf(line, "%"SCNu32, result) != 1) {
|
||||
command_parse_error();
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
parse_double(char *line, double *result)
|
||||
{
|
||||
@@ -1113,7 +1105,14 @@ parse_bindcmdaddress(char *line)
|
||||
IPAddr ip;
|
||||
|
||||
check_number_of_args(line, 1);
|
||||
if (UTI_StringToIP(line, &ip)) {
|
||||
|
||||
/* Address starting with / is for the Unix domain socket */
|
||||
if (line[0] == '/') {
|
||||
parse_string(line, &bind_cmd_path);
|
||||
/* / disables the socket */
|
||||
if (!strcmp(bind_cmd_path, "/"))
|
||||
bind_cmd_path[0] = '\0';
|
||||
} else if (UTI_StringToIP(line, &ip)) {
|
||||
if (ip.family == IPADDR_INET4)
|
||||
bind_cmd_address4 = ip;
|
||||
else if (ip.family == IPADDR_INET6)
|
||||
@@ -1240,8 +1239,47 @@ parse_tempcomp(char *line)
|
||||
static void
|
||||
parse_include(char *line)
|
||||
{
|
||||
glob_t gl;
|
||||
size_t i;
|
||||
|
||||
check_number_of_args(line, 1);
|
||||
CNF_ReadFile(line);
|
||||
|
||||
if (glob(line, 0, NULL, &gl)) {
|
||||
DEBUG_LOG(LOGF_Configure, "glob of %s failed", line);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < gl.gl_pathc; i++)
|
||||
CNF_ReadFile(gl.gl_pathv[i]);
|
||||
|
||||
globfree(&gl);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
CNF_CreateDirs(uid_t uid, gid_t gid)
|
||||
{
|
||||
char *dir;
|
||||
|
||||
UTI_CreateDirAndParents(logdir, 0755, uid, gid);
|
||||
UTI_CreateDirAndParents(dumpdir, 0755, uid, gid);
|
||||
|
||||
/* Create a directory for the Unix domain command socket */
|
||||
if (bind_cmd_path[0]) {
|
||||
dir = UTI_PathToDir(bind_cmd_path);
|
||||
UTI_CreateDirAndParents(dir, 0770, uid, gid);
|
||||
|
||||
/* Check the permissions and owner/group in case the directory already
|
||||
existed. It MUST NOT be accessible by others as permissions on Unix
|
||||
domain sockets are ignored on some systems (e.g. Solaris). */
|
||||
if (!UTI_CheckDirPermissions(dir, 0770, uid, gid)) {
|
||||
LOG(LOGS_WARN, LOGF_Configure, "Disabled command socket %s", bind_cmd_path);
|
||||
bind_cmd_path[0] = '\0';
|
||||
}
|
||||
|
||||
Free(dir);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1449,22 +1487,6 @@ CNF_GetRtcDevice(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
uint32_t
|
||||
CNF_GetCommandKey(void)
|
||||
{
|
||||
return command_key_id;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CNF_GetGenerateCommandKey(void)
|
||||
{
|
||||
return generate_command_key;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CNF_GetDumpOnExit(void)
|
||||
{
|
||||
@@ -1505,6 +1527,14 @@ CNF_GetMaxSlewRate(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
double
|
||||
CNF_GetMaxDistance(void)
|
||||
{
|
||||
return max_distance;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
double
|
||||
CNF_GetReselectDistance(void)
|
||||
{
|
||||
@@ -1697,6 +1727,14 @@ CNF_GetBindAcquisitionAddress(int family, IPAddr *addr)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
char *
|
||||
CNF_GetBindCommandPath(void)
|
||||
{
|
||||
return bind_cmd_path;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
CNF_GetBindCommandAddress(int family, IPAddr *addr)
|
||||
{
|
||||
|
||||
6
conf.h
6
conf.h
@@ -39,6 +39,8 @@ extern char *CNF_GetRtcDevice(void);
|
||||
extern void CNF_ReadFile(const char *filename);
|
||||
extern void CNF_ParseLine(const char *filename, int number, char *line);
|
||||
|
||||
extern void CNF_CreateDirs(uid_t uid, gid_t gid);
|
||||
|
||||
extern void CNF_AddInitSources(void);
|
||||
extern void CNF_AddSources(void);
|
||||
extern void CNF_AddBroadcasts(void);
|
||||
@@ -58,8 +60,6 @@ extern int CNF_GetLogRefclocks(void);
|
||||
extern int CNF_GetLogTempComp(void);
|
||||
extern char *CNF_GetKeysFile(void);
|
||||
extern char *CNF_GetRtcFile(void);
|
||||
extern uint32_t CNF_GetCommandKey(void);
|
||||
extern int CNF_GetGenerateCommandKey(void);
|
||||
extern int CNF_GetDumpOnExit(void);
|
||||
extern int CNF_GetManualEnabled(void);
|
||||
extern int CNF_GetCommandPort(void);
|
||||
@@ -75,6 +75,7 @@ extern void CNF_GetFallbackDrifts(int *min, int *max);
|
||||
extern void CNF_GetBindAddress(int family, IPAddr *addr);
|
||||
extern void CNF_GetBindAcquisitionAddress(int family, IPAddr *addr);
|
||||
extern void CNF_GetBindCommandAddress(int family, IPAddr *addr);
|
||||
extern char *CNF_GetBindCommandPath(void);
|
||||
extern char *CNF_GetPidFile(void);
|
||||
extern REF_LeapMode CNF_GetLeapSecMode(void);
|
||||
extern char *CNF_GetLeapSecTimezone(void);
|
||||
@@ -85,6 +86,7 @@ extern double CNF_GetMaxClockError(void);
|
||||
extern double CNF_GetCorrectionTimeRatio(void);
|
||||
extern double CNF_GetMaxSlewRate(void);
|
||||
|
||||
extern double CNF_GetMaxDistance(void);
|
||||
extern double CNF_GetReselectDistance(void);
|
||||
extern double CNF_GetStratumWeight(void);
|
||||
extern double CNF_GetCombineLimit(void);
|
||||
|
||||
193
configure
vendored
193
configure
vendored
@@ -4,32 +4,12 @@
|
||||
# chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
#
|
||||
# Copyright (C) Richard P. Curnow 1997-2003
|
||||
# Copyright (C) Miroslav Lichvar 2009, 2012-2014
|
||||
# Copyright (C) Miroslav Lichvar 2009, 2012-2015
|
||||
#
|
||||
# =======================================================================
|
||||
|
||||
# This configure script determines the operating system type and version
|
||||
|
||||
if [ "x${CC}" = "x" ]; then
|
||||
MYCC="gcc"
|
||||
else
|
||||
MYCC="${CC}"
|
||||
fi
|
||||
|
||||
if [ "x${CFLAGS}" = "x" ]; then
|
||||
MYCFLAGS="-O2 -g"
|
||||
else
|
||||
MYCFLAGS="${CFLAGS}"
|
||||
fi
|
||||
|
||||
MYCPPFLAGS="${CPPFLAGS}"
|
||||
|
||||
if [ "x${MYCC}" = "xgcc" ]; then
|
||||
MYCFLAGS="${MYCFLAGS} -Wmissing-prototypes -Wall"
|
||||
fi
|
||||
|
||||
MYLDFLAGS="${LDFLAGS}"
|
||||
|
||||
# ======================================================================
|
||||
# FUNCTIONS
|
||||
|
||||
@@ -41,7 +21,7 @@ test_code () {
|
||||
ldflags=$4
|
||||
code=$5
|
||||
|
||||
echo -n "Checking for $name : "
|
||||
printf "%s" "Checking for $name : "
|
||||
|
||||
(
|
||||
for h in $headers; do
|
||||
@@ -113,7 +93,10 @@ For better control, use the options below.
|
||||
--disable-pps Disable PPS refclock driver
|
||||
--disable-ipv6 Disable IPv6 support
|
||||
--disable-rtc Don't include RTC even on Linux
|
||||
--disable-linuxcaps Disable libcap (Linux capabilities) support
|
||||
--disable-privdrop Disable support for dropping root privileges
|
||||
--without-libcap Don't use libcap even if it is available
|
||||
--disable-scfilter Disable support for system call filtering
|
||||
--without-seccomp Don't use seccomp even if it is available
|
||||
--disable-asyncdns Disable asynchronous name resolving
|
||||
--disable-forcednsretry Don't retry on permanent DNS error
|
||||
--with-ntp-era=SECONDS Specify earliest assumed NTP time in seconds
|
||||
@@ -131,6 +114,7 @@ Fine tuning of the installation directories:
|
||||
--mandir=DIR man documentation [DATAROOTDIR/man]
|
||||
--docdir=DIR documentation root [DATAROOTDIR/doc/chrony]
|
||||
--localstatedir=DIR modifiable single-machine data [/var]
|
||||
--chronysockdir=DIR location for chrony sockets [LOCALSTATEDIR/run/chrony]
|
||||
--chronyvardir=DIR location for chrony data [LOCALSTATEDIR/lib/chrony]
|
||||
|
||||
Overriding system detection when cross-compiling:
|
||||
@@ -174,12 +158,12 @@ get_features () {
|
||||
ff=1
|
||||
for f; do
|
||||
if [ "$ff" = "0" ]; then
|
||||
echo -n " "
|
||||
printf " "
|
||||
fi
|
||||
if grep "define FEAT_$f" config.h > /dev/null; then
|
||||
echo -n "+$f"
|
||||
printf "%s" "+$f"
|
||||
else
|
||||
echo -n "-$f"
|
||||
printf "%s" "-$f"
|
||||
fi
|
||||
ff=0
|
||||
done
|
||||
@@ -213,7 +197,10 @@ try_tomcrypt=1
|
||||
feat_rtc=1
|
||||
try_rtc=0
|
||||
feat_droproot=1
|
||||
try_libcap=0
|
||||
try_libcap=-1
|
||||
try_clockctl=0
|
||||
feat_scfilter=1
|
||||
try_seccomp=-1
|
||||
readline_lib=""
|
||||
readline_inc=""
|
||||
ncurses_lib=""
|
||||
@@ -283,6 +270,9 @@ do
|
||||
--localstatedir=* )
|
||||
SETLOCALSTATEDIR=`echo $option | sed -e 's/^.*=//;'`
|
||||
;;
|
||||
--chronysockdir=* )
|
||||
SETCHRONYSOCKDIR=`echo $option | sed -e 's/^.*=//;'`
|
||||
;;
|
||||
--chronyvardir=* )
|
||||
SETCHRONYVARDIR=`echo $option | sed -e 's/^.*=//;'`
|
||||
;;
|
||||
@@ -307,9 +297,18 @@ do
|
||||
--disable-pps)
|
||||
feat_pps=0
|
||||
;;
|
||||
--disable-linuxcaps)
|
||||
--disable-privdrop)
|
||||
feat_droproot=0
|
||||
;;
|
||||
--without-libcap|--disable-linuxcaps)
|
||||
try_libcap=0
|
||||
;;
|
||||
--disable-scfilter)
|
||||
feat_scfilter=0
|
||||
;;
|
||||
--without-seccomp)
|
||||
try_seccomp=0
|
||||
;;
|
||||
--disable-asyncdns)
|
||||
feat_asyncdns=0
|
||||
;;
|
||||
@@ -356,78 +355,50 @@ rm -f config.h config.log
|
||||
|
||||
SYSTEM=${OPERATINGSYSTEM}-${MACHINE}
|
||||
|
||||
case $SYSTEM in
|
||||
SunOS-sun4* )
|
||||
case $VERSION in
|
||||
4.* )
|
||||
EXTRA_OBJECTS="sys_sunos.o strerror.o"
|
||||
EXTRA_LIBS="-lkvm"
|
||||
add_def SUNOS
|
||||
echo "Configuring for SunOS (" $SYSTEM "version" $VERSION ")"
|
||||
;;
|
||||
5.* )
|
||||
EXTRA_OBJECTS="sys_solaris.o"
|
||||
EXTRA_LIBS="-lsocket -lnsl -lkvm -lelf"
|
||||
EXTRA_CLI_LIBS="-lsocket -lnsl"
|
||||
add_def SOLARIS
|
||||
echo "Configuring for Solaris (" $SYSTEM "SunOS version" $VERSION ")"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
Linux* )
|
||||
EXTRA_OBJECTS="sys_generic.o sys_linux.o wrap_adjtimex.o"
|
||||
try_libcap=1
|
||||
case $OPERATINGSYSTEM in
|
||||
Linux)
|
||||
EXTRA_OBJECTS="sys_generic.o sys_linux.o sys_timex.o"
|
||||
[ $try_libcap != "0" ] && try_libcap=1
|
||||
try_rtc=1
|
||||
[ $try_seccomp != "0" ] && try_seccomp=1
|
||||
try_setsched=1
|
||||
try_lockmem=1
|
||||
try_phc=1
|
||||
add_def LINUX
|
||||
echo "Configuring for " $SYSTEM
|
||||
if [ "${MACHINE}" = "alpha" ]; then
|
||||
echo "Enabling -mieee"
|
||||
# FIXME: Should really test for GCC
|
||||
MYCFLAGS="$MYCFLAGS -mieee"
|
||||
fi
|
||||
;;
|
||||
|
||||
BSD/386-i[3456]86|FreeBSD-i386|FreeBSD-amd64 )
|
||||
# Antti Jrvinen <costello@iki.fi> reported that this system can
|
||||
# be supported with the SunOS 4.x driver files.
|
||||
EXTRA_OBJECTS="sys_sunos.o strerror.o"
|
||||
EXTRA_LIBS="-lkvm"
|
||||
add_def SUNOS
|
||||
echo "Configuring for $SYSTEM (using SunOS driver)"
|
||||
;;
|
||||
NetBSD-* )
|
||||
EXTRA_OBJECTS="sys_netbsd.o"
|
||||
EXTRA_LIBS="-lkvm"
|
||||
SYSDEFS=""
|
||||
FreeBSD)
|
||||
EXTRA_OBJECTS="sys_generic.o sys_netbsd.o sys_timex.o"
|
||||
add_def FREEBSD
|
||||
echo "Configuring for $SYSTEM"
|
||||
;;
|
||||
Darwin-* )
|
||||
NetBSD)
|
||||
EXTRA_OBJECTS="sys_generic.o sys_netbsd.o sys_timex.o"
|
||||
try_clockctl=1
|
||||
add_def NETBSD
|
||||
echo "Configuring for $SYSTEM"
|
||||
;;
|
||||
Darwin)
|
||||
EXTRA_OBJECTS="sys_macosx.o"
|
||||
EXTRA_LIBS="-lresolv"
|
||||
EXTRA_CLI_LIBS="-lresolv"
|
||||
add_def MACOSX
|
||||
echo "Configuring for MacOS X (" $SYSTEM "MacOS X version" $VERSION ")"
|
||||
;;
|
||||
SunOS-i86pc* )
|
||||
# Doug Woodward <dougw@whistler.com> reported that this configuration
|
||||
# works for Solaris 2.8 / SunOS 5.8 on x86 platforms
|
||||
EXTRA_OBJECTS="sys_solaris.o"
|
||||
EXTRA_LIBS="-lsocket -lnsl -lkvm -lelf"
|
||||
EXTRA_CLI_LIBS="-lsocket -lnsl"
|
||||
SunOS)
|
||||
EXTRA_OBJECTS="sys_generic.o sys_solaris.o sys_timex.o"
|
||||
EXTRA_LIBS="-lsocket -lnsl -lresolv"
|
||||
EXTRA_CLI_LIBS="-lsocket -lnsl -lresolv"
|
||||
add_def SOLARIS
|
||||
# These are needed to have msg_control in struct msghdr
|
||||
add_def __EXTENSIONS__
|
||||
add_def _XOPEN_SOURCE 1
|
||||
add_def _XOPEN_SOURCE_EXTENDED 1
|
||||
echo "Configuring for Solaris (" $SYSTEM "SunOS version" $VERSION ")"
|
||||
;;
|
||||
CYGWIN32_NT-i[3456]86 )
|
||||
EXTRA_OBJECTS="sys_winnt.o"
|
||||
EXTRA_LIBS=""
|
||||
add_def WINNT
|
||||
echo "Configuring for Windows NT (Cygwin32)"
|
||||
;;
|
||||
* )
|
||||
echo "Sorry, I don't know how to build this software on your system."
|
||||
echo "error: $SYSTEM is not supported (yet?)"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -460,6 +431,35 @@ if [ $feat_refclock = "1" ]; then
|
||||
EXTRA_OBJECTS="$EXTRA_OBJECTS refclock.o refclock_phc.o refclock_pps.o refclock_shm.o refclock_sock.o"
|
||||
fi
|
||||
|
||||
MYCC="$CC"
|
||||
MYCFLAGS="$CFLAGS"
|
||||
MYCPPFLAGS="$CPPFLAGS"
|
||||
MYLDFLAGS="$LDFLAGS"
|
||||
|
||||
if [ "x$MYCC" = "x" ]; then
|
||||
MYCC=gcc
|
||||
if ! test_code "$MYCC" '' '' '' ''; then
|
||||
MYCC=cc
|
||||
if ! test_code "$MYCC" '' '' '' ''; then
|
||||
echo "error: no C compiler found"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if ! test_code "$MYCC" '' '' '' ''; then
|
||||
echo "error: C compiler $MYCC cannot create executables"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "x$MYCFLAGS" = "x" ]; then
|
||||
MYCFLAGS="-O2 -g"
|
||||
fi
|
||||
|
||||
if [ "x$MYCC" = "xgcc" ]; then
|
||||
MYCFLAGS="$MYCFLAGS -Wmissing-prototypes -Wall"
|
||||
fi
|
||||
|
||||
if test_code '64-bit time_t' 'time.h' '' '' '
|
||||
char x[sizeof(time_t) > 4 ? 1 : -1] = {0};
|
||||
return x[0];'
|
||||
@@ -472,7 +472,7 @@ then
|
||||
else
|
||||
split_seconds=`date '+%s'`
|
||||
if [ "x$split_seconds" = "" ]; then
|
||||
echo "Could not get current time, --with-ntp-era option is needed"
|
||||
echo "error: could not get current time, --with-ntp-era option is needed"
|
||||
exit 1
|
||||
fi
|
||||
split_days=$((50 * 365))
|
||||
@@ -501,7 +501,7 @@ else
|
||||
if test_code 'math in -lm' 'math.h' '' '-lm' "$MATHCODE"; then
|
||||
LIBS="-lm"
|
||||
else
|
||||
echo "Can't compile/link a program which uses sqrt(), log(), pow(), bailing out"
|
||||
echo "error: could not compile/link a program which uses sqrt(), log(), pow()"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
@@ -515,7 +515,7 @@ if test_code '<inttypes.h>' 'inttypes.h' '' '' ''; then
|
||||
fi
|
||||
|
||||
if [ $feat_ipv6 = "1" ] && \
|
||||
test_code 'IPv6 support' 'arpa/inet.h sys/socket.h netinet/in.h' '' '' '
|
||||
test_code 'IPv6 support' 'arpa/inet.h sys/socket.h netinet/in.h' '' "$EXTRA_LIBS" '
|
||||
struct sockaddr_in6 n;
|
||||
char p[100];
|
||||
n.sin6_addr = in6addr_any;
|
||||
@@ -536,7 +536,7 @@ then
|
||||
fi
|
||||
fi
|
||||
|
||||
if test_code 'getaddrinfo()' 'sys/types.h sys/socket.h netdb.h' '' '' \
|
||||
if test_code 'getaddrinfo()' 'sys/types.h sys/socket.h netdb.h' '' "$EXTRA_LIBS" \
|
||||
'return getaddrinfo(0, 0, 0, 0);'
|
||||
then
|
||||
add_def HAVE_GETADDRINFO
|
||||
@@ -586,6 +586,20 @@ then
|
||||
EXTRA_LIBS="$EXTRA_LIBS -lcap"
|
||||
fi
|
||||
|
||||
if [ $feat_droproot = "1" ] && [ $try_clockctl = "1" ] && \
|
||||
test_code '<sys/clockctl.h>' 'sys/clockctl.h' '' '' ''
|
||||
then
|
||||
add_def FEAT_PRIVDROP
|
||||
fi
|
||||
|
||||
if [ $feat_scfilter = "1" ] && [ $try_seccomp = "1" ] && \
|
||||
test_code seccomp 'seccomp.h' '' '-lseccomp' \
|
||||
'seccomp_init(SCMP_ACT_KILL);'
|
||||
then
|
||||
add_def FEAT_SCFILTER
|
||||
EXTRA_LIBS="$EXTRA_LIBS -lseccomp"
|
||||
fi
|
||||
|
||||
if [ $feat_rtc = "1" ] && [ $try_rtc = "1" ] && \
|
||||
test_code '<linux/rtc.h>' 'sys/ioctl.h linux/rtc.h' '' '' \
|
||||
'ioctl(1, RTC_UIE_ON&RTC_UIE_OFF&RTC_RD_TIME&RTC_SET_TIME, 0&RTC_UF);'
|
||||
@@ -759,6 +773,11 @@ if [ "x$SETLOCALSTATEDIR" != "x" ]; then
|
||||
LOCALSTATEDIR=$SETLOCALSTATEDIR
|
||||
fi
|
||||
|
||||
CHRONYSOCKDIR=${LOCALSTATEDIR}/run/chrony
|
||||
if [ "x$SETCHRONYSOCKDIR" != "x" ]; then
|
||||
CHRONYSOCKDIR=$SETCHRONYSOCKDIR
|
||||
fi
|
||||
|
||||
CHRONYVARDIR=${LOCALSTATEDIR}/lib/chrony
|
||||
if [ "x$SETCHRONYVARDIR" != "x" ]; then
|
||||
CHRONYVARDIR=$SETCHRONYVARDIR
|
||||
@@ -766,11 +785,12 @@ fi
|
||||
|
||||
add_def DEFAULT_CONF_FILE "\"$SYSCONFDIR/chrony.conf\""
|
||||
add_def DEFAULT_USER "\"$default_user\""
|
||||
add_def DEFAULT_COMMAND_SOCKET "\"$CHRONYSOCKDIR/chronyd.sock\""
|
||||
add_def MAIL_PROGRAM "\"$mail_program\""
|
||||
|
||||
common_features="`get_features ASYNCDNS IPV6 SECHASH`"
|
||||
common_features="`get_features IPV6 DEBUG`"
|
||||
chronyc_features="`get_features READLINE`"
|
||||
chronyd_features="`get_features CMDMON NTP REFCLOCK RTC PRIVDROP DEBUG`"
|
||||
chronyd_features="`get_features CMDMON NTP REFCLOCK RTC PRIVDROP SCFILTER SECHASH ASYNCDNS`"
|
||||
add_def CHRONYC_FEATURES "\"$chronyc_features $common_features\""
|
||||
add_def CHRONYD_FEATURES "\"$chronyd_features $common_features\""
|
||||
echo "Features : $chronyd_features $chronyc_features $common_features"
|
||||
@@ -802,6 +822,7 @@ do
|
||||
s%@MANDIR@%${MANDIR}%;\
|
||||
s%@INFODIR@%${INFODIR}%;\
|
||||
s%@LOCALSTATEDIR@%${LOCALSTATEDIR}%;\
|
||||
s%@CHRONYSOCKDIR@%${CHRONYSOCKDIR}%;\
|
||||
s%@CHRONYVARDIR@%${CHRONYVARDIR}%;\
|
||||
s%@DEFAULT_USER@%${default_user}%;"\
|
||||
< ${f}.in > $f
|
||||
|
||||
103
contrib/bryan_christianson_1/README.txt
Normal file
103
contrib/bryan_christianson_1/README.txt
Normal file
@@ -0,0 +1,103 @@
|
||||
Notes for installing chrony on MacOS X
|
||||
Author: Bryan Christianson (bryan@whatroute.net)
|
||||
------------------------------------------------
|
||||
|
||||
These files are for those admins/users who would prefer to install chrony
|
||||
from the source distribution and are intended as guidelines rather than
|
||||
being definitive. They can be edited with a plain text editor, such as
|
||||
vi, emacs or your favourite IDE (xcode)
|
||||
|
||||
It is assumed you are comfortable with installing software from the
|
||||
terminal command line and know how to use sudo to acquire root access.
|
||||
|
||||
If you are not familiar with the MacOS X command line then
|
||||
please consider using ChronyControl from http://whatroute.net/chronycontrol.html
|
||||
|
||||
ChronyControl provides a gui wrapper for installing these files and sets the
|
||||
necessary permissions on each file.
|
||||
|
||||
|
||||
Install the chrony software
|
||||
---------------------------
|
||||
|
||||
You will need xcode and the commandline additions to build and install chrony.
|
||||
These can be obtained from Apple's website via the App Store.
|
||||
|
||||
cd to the chrony directory
|
||||
./configure
|
||||
make
|
||||
sudo make install
|
||||
|
||||
chrony is now installed in default locations (/usr/local/sbin/chronyd,
|
||||
/usr/local/bin/chronyc)
|
||||
|
||||
Create a chrony.conf file - see the chrony website for details
|
||||
|
||||
The support files here assume the following directives are specified in the
|
||||
chrony.conf file
|
||||
|
||||
keyfile /etc/chrony.d/chrony.keys
|
||||
driftfile /var/db/chrony/chrony.drift
|
||||
bindcmdaddress /var/db/chrony/chronyd.sock
|
||||
logdir /var/log/chrony
|
||||
dumpdir /var/db/chrony
|
||||
|
||||
Install this file as /etc/chrony.d/chrony.conf and create
|
||||
the directories specified in the above directives if they don't exist.
|
||||
You will need root permissions to create the directories.
|
||||
|
||||
|
||||
Running chronyd
|
||||
---------------
|
||||
At this point chronyd *could* be run as a daemon. Apple discourage running
|
||||
daemons and their preferred method uses the launchd facility. The
|
||||
support files here provide a launchd configuration file for chronyd and also
|
||||
a shell script and launchd configuration file to rotate the chronyd logs on a daily basis.
|
||||
|
||||
|
||||
Support files
|
||||
-------------
|
||||
Dates and sizes may differ
|
||||
-rw-r--r-- 1 yourname staff 2084 4 Aug 22:54 README.txt
|
||||
-rwxr-xr-x 1 yourname staff 676 4 Aug 21:18 chronylogrotate.sh
|
||||
-rw-r--r-- 1 yourname staff 543 18 Jul 20:10 org.tuxfamily.chronyc.plist
|
||||
-rw-r--r-- 1 yourname staff 511 19 Jun 18:30 org.tuxfamily.chronyd.plist
|
||||
|
||||
If you have used chrony support directories other than those suggested, you
|
||||
will need to edit each file and make the appropriate changes.
|
||||
|
||||
|
||||
Installing the support files
|
||||
----------------------------
|
||||
|
||||
1. chronylogrotate.sh
|
||||
This is a simple shell script that deletes old log files. Unfortunately because
|
||||
of the need to run chronyc, the standard MacOS X logrotation does not work with
|
||||
chrony logs.
|
||||
|
||||
This script runs on a daily basis under control of launchd and should be
|
||||
installed in the /usr/local/bin directory
|
||||
|
||||
sudo cp chronylogrotate.sh /usr/local/bin
|
||||
sudo chmod +x /usr/local/bin/chronylogrotate.sh
|
||||
sudo chown root:wheel /usr/local/bin/chronylogrotate.sh
|
||||
|
||||
|
||||
2. org.tuxfamily.chronyc.plist
|
||||
This file is the launchd plist that runs logrotation each day. You may
|
||||
wish to edit this file to change the time of day at which the rotation
|
||||
will run, currently 04:05 am
|
||||
|
||||
sudo cp org.tuxfamily.chronyc.plist /Library/LaunchDaemons
|
||||
sudo chown root:wheel /Library/LaunchDaemons/org.tuxfamily.chronyc.plist
|
||||
sudo chmod 0644 /Library/LaunchDaemons/org.tuxfamily.chronyc.plist
|
||||
sudo launchctl load -w /Library/LaunchDaemons/org.tuxfamily.chronyc.plist
|
||||
|
||||
|
||||
3. org.tuxfamily.chronyd.plist
|
||||
This file is the launchd plist that runs chronyd when the Macintosh starts.
|
||||
|
||||
sudo cp org.tuxfamily.chronyd.plist /Library/LaunchDaemons
|
||||
sudo chown root:wheel /Library/LaunchDaemons/org.tuxfamily.chronyd.plist
|
||||
sudo chmod 0644 /Library/LaunchDaemons/org.tuxfamily.chronyd.plist
|
||||
sudo launchctl load -w /Library/LaunchDaemons/org.tuxfamily.chronyd.plist
|
||||
45
contrib/bryan_christianson_1/chronylogrotate.sh
Executable file
45
contrib/bryan_christianson_1/chronylogrotate.sh
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/bin/sh
|
||||
|
||||
# chronylogrotate.sh
|
||||
# ChronyControl
|
||||
#
|
||||
# Created by Bryan Christianson on 12/07/15.
|
||||
#
|
||||
|
||||
LOGDIR=/var/log/chrony
|
||||
|
||||
if [ ! -e "$LOGDIR" ]; then
|
||||
echo "missing directory: $LOGDIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd $LOGDIR
|
||||
|
||||
rotate () {
|
||||
prefix=$1
|
||||
|
||||
rm -f $prefix.log.10
|
||||
|
||||
for (( count=9; count>= 0; count-- ))
|
||||
do
|
||||
next=$(( $count+1 ))
|
||||
if [ -f $prefix.log.$count ]; then
|
||||
mv $prefix.log.$count $prefix.log.$next
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -f $prefix.log ]; then
|
||||
mv $prefix.log $prefix.log.0
|
||||
fi
|
||||
}
|
||||
|
||||
rotate measurements
|
||||
rotate statistics
|
||||
rotate tracking
|
||||
|
||||
#
|
||||
# signal chronyd via chronyc
|
||||
|
||||
/usr/local/bin/chronyc -a -f /etc/chrony.d/chrony.conf cyclelogs > /dev/null
|
||||
|
||||
exit $?
|
||||
22
contrib/bryan_christianson_1/org.tuxfamily.chronyc.plist
Normal file
22
contrib/bryan_christianson_1/org.tuxfamily.chronyc.plist
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>org.tuxfamily.logrotate</string>
|
||||
<key>KeepAlive</key>
|
||||
<false/>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/bin/sh</string>
|
||||
<string>/usr/local/bin/chronylogrotate.sh</string>
|
||||
</array>
|
||||
<key>StartCalendarInterval</key>
|
||||
<dict>
|
||||
<key>Minute</key>
|
||||
<integer>5</integer>
|
||||
<key>Hour</key>
|
||||
<integer>4</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
19
contrib/bryan_christianson_1/org.tuxfamily.chronyd.plist
Normal file
19
contrib/bryan_christianson_1/org.tuxfamily.chronyd.plist
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>org.tuxfamily.chronyd</string>
|
||||
<key>Program</key>
|
||||
<string>/usr/local/sbin/chronyd</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>chronyd</string>
|
||||
<string>-n</string>
|
||||
<string>-f</string>
|
||||
<string>/private/etc/chrony.d/chrony.conf</string>
|
||||
</array>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
198
doc/faq.adoc
198
doc/faq.adoc
@@ -4,25 +4,29 @@
|
||||
Frequently Asked Questions
|
||||
==========================
|
||||
|
||||
== Chrony compared to other programs
|
||||
== +chrony+ compared to other programs
|
||||
|
||||
=== How does +chrony+ compare to +ntpd+?
|
||||
|
||||
+chrony+ can usually synchronise the system clock faster and with better time
|
||||
accuracy, but it doesn't implement all NTP features, e.g. broadcast/multicast
|
||||
mode, or authentication based on public-key cryptography. For a more detailed
|
||||
comparison, see the http://chrony.tuxfamily.org/comparison.html[comparison
|
||||
page] on the chrony website and section
|
||||
+chronyd+ was designed to work well in a wide range of conditions and it can
|
||||
usually synchronise the system clock faster and with better time accuracy. It
|
||||
doesn't implement some of the less useful NTP modes like broadcast client or
|
||||
multicast server/client.
|
||||
|
||||
For a more detailed comparison of features and performance, see the
|
||||
http://chrony.tuxfamily.org/comparison.html[comparison page] on the +chrony+
|
||||
website and the
|
||||
http://chrony.tuxfamily.org/manual.html#Comparison-with-ntpd[Comparison with
|
||||
ntpd] in the manual.
|
||||
ntpd] section in the manual.
|
||||
|
||||
If your computer connects to the 'net only for few minutes at a time, you turn
|
||||
your Linux computer off or suspend it frequently, the clock is not very stable
|
||||
(e.g. it is a virtual machine), or you want to use NTP on an isolated network
|
||||
with no hardware clocks in sight, +chrony+ will probably work much better for
|
||||
you.
|
||||
If your computer is connected to the internet only for few minutes at a time,
|
||||
the network connection is often congested, you turn your computer off or
|
||||
suspend it frequently, the clock is not very stable (e.g. there are rapid
|
||||
changes in the temperature or it's a virtual machine), or you want to use NTP
|
||||
on an isolated network with no hardware reference clocks in sight, +chrony+
|
||||
will probably work much better for you.
|
||||
|
||||
The original reason +chrony+ was written was that ntpd (called xntpd at the
|
||||
The original reason +chrony+ was written was that +ntpd+ (called +xntpd+ at the
|
||||
time) could not to do anything sensible on a PC which was connected to the 'net
|
||||
only for about 5 minutes once or twice a day, mainly to upload/download email
|
||||
and news. The requirements were
|
||||
@@ -39,7 +43,7 @@ and news. The requirements were
|
||||
information to set the system clock correctly at boot up.
|
||||
|
||||
Also, when working with isolated networks with no true time references at all
|
||||
ntpd was found to give no help with managing the local clock's gain/loss rate
|
||||
+ntpd+ was found to give no help with managing the local clock's gain/loss rate
|
||||
on the NTP master node (which was set from watch). Some automated support was
|
||||
added to +chrony+ to deal with this.
|
||||
|
||||
@@ -63,7 +67,7 @@ the hostnames specified in the +server+ and +peer+ directives in
|
||||
increasing intervals until it succeeds. The +online+ command can be
|
||||
issued from +chronyc+ to try to resolve them immediately.
|
||||
|
||||
=== How can I make chronyd more secure?
|
||||
=== How can I make +chronyd+ more secure?
|
||||
|
||||
If you don't need to serve time to NTP clients or peers, you can add +port 0+
|
||||
to the 'chrony.conf' file to completely disable the NTP server functionality
|
||||
@@ -81,14 +85,26 @@ bindcmdaddress 127.0.0.1
|
||||
bindcmdaddress ::1
|
||||
----
|
||||
|
||||
If you don't need to use +chronyc+ at all, you can disable the command sockets
|
||||
by adding +cmdport 0+ to the configuration file.
|
||||
If you don't need to use +chronyc+ at all or you need to run +chronyc+ only
|
||||
under the root or chrony user (which can access +chronyd+ through a Unix domain
|
||||
socket since version 2.2), you can disable the internet command sockets
|
||||
completely by adding +cmdport 0+ to the configuration file.
|
||||
|
||||
On Linux, if +chronyd+ is compiled with support for Linux capabilities
|
||||
(available in the libcap library), you can specify an unprivileged user with
|
||||
the +-u+ option or +user+ directive in the 'chrony.conf' file to drop root
|
||||
privileges after start. The configure option +--with-user+ can be used to drop
|
||||
the privileges by default.
|
||||
(available in the libcap library), or on NetBSD with the +/dev/clockctl+
|
||||
device, you can specify an unprivileged user with the +-u+ option or +user+
|
||||
directive in the 'chrony.conf' file to drop root privileges after start. The
|
||||
configure option +--with-user+ can be used to drop the privileges by default.
|
||||
|
||||
Also, if +chronyd+ is compiled with support for the Linux secure computing
|
||||
(seccomp) facility, you can enable a system call filter with the +-F+ option.
|
||||
It will significantly reduce the kernel attack surface and possibly prevent
|
||||
kernel exploits from the +chronyd+ process if compromised. The filter
|
||||
shouldn't be enabled without testing that it allows all system calls needed
|
||||
with the specific configuration and libraries that +chronyd+ is using (e.g.
|
||||
libc and its NSS configuration). If +chronyd+ is getting killed, some system
|
||||
call is missing and the filter has to be disabled until it's patched to allow
|
||||
that call.
|
||||
|
||||
=== How can I improve the accuracy of the system clock with NTP sources?
|
||||
|
||||
@@ -138,6 +154,15 @@ with local NTP server
|
||||
server ntp.local minpoll 2 maxpoll 4 polltarget 30 maxdelaydevratio 2
|
||||
----
|
||||
|
||||
=== What happened to the +commandkey+ and +generatecommandkey+ directives?
|
||||
|
||||
They were removed in version 2.2. Authentication is no longer supported in the
|
||||
command protocol. Commands that required authentication are now allowed only
|
||||
through a Unix domain socket, which is accessible only by the root and chrony
|
||||
users. If you need to configure +chronyd+ remotely or locally without the root
|
||||
password, please consider using ssh and/or sudo to run +chronyc+ under the root
|
||||
or chrony user on the same host as +chronyd+ is running.
|
||||
|
||||
== Computer is not synchronising
|
||||
|
||||
This is the most common problem. There are a number of reasons, see the
|
||||
@@ -146,11 +171,11 @@ following questions.
|
||||
=== Behind a firewall?
|
||||
|
||||
If there is a firewall between you and the NTP server you're trying to use, the
|
||||
packets may be blocked. Try using a tool like wireshark or tcpdump to see if
|
||||
packets may be blocked. Try using a tool like +wireshark+ or +tcpdump+ to see if
|
||||
you're getting responses from the server. If you have an external modem, see
|
||||
if the receive light blinks straight after the transmit light (when the link is
|
||||
quiet apart from the NTP traffic.) Try adding +log measurements+ to the
|
||||
'chrony.conf' file and look in the 'measurements.log' file after +chrony+ has
|
||||
'chrony.conf' file and look in the 'measurements.log' file after +chronyd+ has
|
||||
been running for a short period. See if any measurements appear.
|
||||
|
||||
=== Are NTP servers specified with the +offline+ option?
|
||||
@@ -159,6 +184,32 @@ Check that you're using +chronyc+\'s +online+ and +offline+ commands
|
||||
appropriately. Again, check in 'measurements.log' to see if you're getting any
|
||||
data back from the server.
|
||||
|
||||
=== Is +chronyd+ allowed to step the system clock?
|
||||
|
||||
By default, +chronyd+ adjusts the clock gradually by slowing it down or
|
||||
speeding it up. If the clock is too far from the correct time, it will take
|
||||
a long time to correct the error. The +System time+ value printed by the
|
||||
+chronyc+'s +tracking+ command is the remaining correction that needs to be
|
||||
applied to the system clock.
|
||||
|
||||
The +makestep+ directive can be used to allow +chronyd+ to step the clock. For
|
||||
example, if 'chrony.conf' had
|
||||
|
||||
----
|
||||
makestep 1 3
|
||||
----
|
||||
|
||||
the clock would be stepped in the first three updates if its offset was larger
|
||||
than one second. Normally, it's recommended to allow the step only in the
|
||||
first few updates, but in some cases (e.g. a computer without RTC or virtual
|
||||
machine which can be suspended and resumed with incorrect time) it may be
|
||||
necessary to allow the step at any clock update. The example above would
|
||||
change to
|
||||
|
||||
----
|
||||
makestep 1 -1
|
||||
----
|
||||
|
||||
== Issues with +chronyc+
|
||||
|
||||
=== I keep getting the error +506 Cannot talk to daemon+
|
||||
@@ -176,6 +227,12 @@ problem with the way you are trying to start it (e.g. at boot time).
|
||||
Perhaps you have a firewall set up in a way that blocks packets on port
|
||||
323/udp. You need to amend the firewall configuration in this case.
|
||||
|
||||
=== I keep getting the error +501 Not authorised+
|
||||
|
||||
Since version 2.2, the +password+ command doesn't do anything and +chronyc+
|
||||
needs to run under the root or chrony user, which are allowed to access the
|
||||
Unix domain command socket.
|
||||
|
||||
=== Is the +chronyc+ / +chronyd+ protocol documented anywhere?
|
||||
|
||||
Only by the source code :-) See 'cmdmon.c' (+chronyd+ side) and 'client.c'
|
||||
@@ -186,21 +243,37 @@ Only by the source code :-) See 'cmdmon.c' (+chronyd+ side) and 'client.c'
|
||||
=== What is the real-time clock (RTC)?
|
||||
|
||||
This is the clock which keeps the time even when your computer is turned off.
|
||||
It works with 1 second resolution. +chronyd+ can monitor the rate at which the
|
||||
real-time clock gains or loses time, and compensate for it when you set the
|
||||
system time from it at the next reboot. See the documentation for details.
|
||||
It is used to initialize the system clock on boot. It normally doesn't drift
|
||||
more than few seconds per day.
|
||||
|
||||
=== I want to use +chronyd+'s real-time clock support. Must I disable hwclock?
|
||||
There are two approaches how +chronyd+ can work with it. One is to use the
|
||||
+rtcsync+ directive, which tells +chronyd+ to enable a kernel mode which sets
|
||||
the RTC from the system clock every 11 minutes. +chronyd+ itself won't touch
|
||||
the RTC. If the computer is not turned off for a long time, the RTC should
|
||||
still be close to the true time when the system clock will be initialized from
|
||||
it on the next boot.
|
||||
|
||||
The hwclock program is often set-up by default in the boot and shutdown scripts
|
||||
with many Linux installations. If you want to use +chronyd+'s real-time clock
|
||||
support, the important thing is to disable hwclock in the shutdown procedure.
|
||||
If you don't, it will over-write the RTC with a new value, unknown to
|
||||
+chronyd+. At the next reboot, +chronyd+ will compensate this (wrong) time
|
||||
with its estimate of how far the RTC has drifted whilst the power was off,
|
||||
giving a meaningless initial system time.
|
||||
The other option is to use the +rtcfile+ directive, which will tell +chronyd+
|
||||
to monitor the rate at which the RTC gains or loses time. When +chronyd+ is
|
||||
started with the +-s+ option on the next boot, it will set the system time from
|
||||
the RTC and also compensate for the drift it has measured previously. The
|
||||
+rtcautotrim+ directive can be used to keep the RTC close to the true time, but
|
||||
it's not strictly necessary if its only purpose is to set the system clock when
|
||||
+chronyd+ is started on boot. See the documentation for details.
|
||||
|
||||
There is no need to remove hwclock from the boot process, as long as +chronyd+
|
||||
=== I want to use +chronyd+'s RTC support. Must I disable +hwclock+?
|
||||
|
||||
The +hwclock+ program is often set-up by default in the boot and shutdown
|
||||
scripts with many Linux installations. With the kernel RTC synchronisation
|
||||
(+rtcsync+ directive), the RTC will be set also every 11 minutes as long as the
|
||||
system clock is synchronised. If you want to use +chronyd+'s RTC monitoring
|
||||
(+rtcfile+ directive), it's important to disable +hwclock+ in the shutdown
|
||||
procedure. If you don't, it will over-write the RTC with a new value, unknown
|
||||
to +chronyd+. At the next reboot, +chronyd+ started with the +-s+ option will
|
||||
compensate this (wrong) time with its estimate of how far the RTC has drifted
|
||||
whilst the power was off, giving a meaningless initial system time.
|
||||
|
||||
There is no need to remove +hwclock+ from the boot process, as long as +chronyd+
|
||||
is started after it has run.
|
||||
|
||||
=== I just keep getting the +513 RTC driver not running+ message
|
||||
@@ -212,33 +285,24 @@ things
|
||||
* enhanced RTC support compiled into the kernel
|
||||
* an +rtcfile+ directive in your 'chrony.conf' file
|
||||
|
||||
== Microsoft Windows
|
||||
|
||||
=== Does +chrony+ support Windows?
|
||||
|
||||
No. The +chronyc+ program (the command-line client used for configuring
|
||||
+chronyd+ while it is running) has been successfully built and run under
|
||||
Cygwin in the past. +chronyd+ is not portable, because part of it is
|
||||
very system-dependent. It needs adapting to work with Windows'
|
||||
equivalent of the adjtimex() call, and it needs to be made to work as a
|
||||
service.
|
||||
|
||||
=== Are there any plans to support Windows?
|
||||
|
||||
We have no plans to do this. Anyone is welcome to pick this work up and
|
||||
contribute it back to the project.
|
||||
|
||||
== NTP-specific issues
|
||||
|
||||
=== Can +chrony+ be driven from broadcast NTP servers?
|
||||
=== Can +chronyd+ be driven from broadcast NTP servers?
|
||||
|
||||
No, this NTP mode is not implemented yet.
|
||||
No, the broadcast client mode is not supported and there is currently no plan
|
||||
to implement it. The broadcast and multicast modes are inherently less
|
||||
accurate and less secure (even with authentication) than the ordinary
|
||||
server/client mode and they are not as useful as they used to be. Even with
|
||||
very modest hardware a single NTP server can serve time to hundreds of
|
||||
thousands of clients using the ordinary mode.
|
||||
|
||||
=== Can chronyd transmit broadcast NTP packets (e.g. to synchronise other computers on a private LAN)?
|
||||
=== Can +chronyd+ transmit broadcast NTP packets?
|
||||
|
||||
Yes. Starting from version 1.17, +chrony+ has this capability.
|
||||
Yes, the +broadcast+ directive can be used to enable the broadcast server mode
|
||||
to serve time to clients in the network which support the broadcast client mode
|
||||
(it's not supported in +chronyd+, see the previous question).
|
||||
|
||||
=== Can +chrony+ keep the system clock a fixed offset away from real time?
|
||||
=== Can +chronyd+ keep the system clock a fixed offset away from real time?
|
||||
|
||||
This is not possible as the program currently stands.
|
||||
|
||||
@@ -260,14 +324,18 @@ be useful to switch the servers to the offline state automatically.
|
||||
|
||||
Some other program running on the system may be using the device.
|
||||
|
||||
== Solaris-specific issues
|
||||
== Microsoft Windows
|
||||
|
||||
=== I get an error message about not being able to open kvm to change dosynctodr
|
||||
=== Does +chrony+ support Windows?
|
||||
|
||||
(The dosynctodr variable controls whether Solaris couples the equivalent
|
||||
of its BIOS clock into its system clock at regular intervals). The
|
||||
Solaris port of +chrony+ was developed in the Solaris 2.5 era. Some
|
||||
aspect of the Solaris kernel has changed which prevents the same
|
||||
technique working. We no longer have root access to any Solaris
|
||||
machines to work on this, and we are reliant on somebody developing the
|
||||
patch and testing it.
|
||||
No. The +chronyc+ program (the command-line client used for configuring
|
||||
+chronyd+ while it is running) has been successfully built and run under
|
||||
Cygwin in the past. +chronyd+ is not portable, because part of it is
|
||||
very system-dependent. It needs adapting to work with Windows'
|
||||
equivalent of the adjtimex() call, and it needs to be made to work as a
|
||||
service.
|
||||
|
||||
=== Are there any plans to support Windows?
|
||||
|
||||
We have no plans to do this. Anyone is welcome to pick this work up and
|
||||
contribute it back to the project.
|
||||
|
||||
@@ -18,14 +18,8 @@ rtcsync
|
||||
# Serve time even if not synchronized to any NTP server.
|
||||
#local stratum 10
|
||||
|
||||
# Specify file containing keys for NTP and command authentication.
|
||||
keyfile /etc/chrony.keys
|
||||
|
||||
# Specify key number for command authentication.
|
||||
commandkey 1
|
||||
|
||||
# Generate new command key on start if missing.
|
||||
generatecommandkey
|
||||
# Specify file containing keys for NTP authentication.
|
||||
#keyfile /etc/chrony.keys
|
||||
|
||||
# Disable logging of client accesses.
|
||||
noclientlog
|
||||
|
||||
@@ -95,24 +95,10 @@
|
||||
|
||||
driftfile /var/lib/chrony/drift
|
||||
|
||||
# If you want to use the program called chronyc to configure aspects of
|
||||
# chronyd's operation once it is running (e.g. tell it the Internet link
|
||||
# has gone up or down), you need a password. This is stored in the
|
||||
# following keys file. (You also need keys to support authenticated NTP
|
||||
# exchanges between cooperating machines.) Again, this option is
|
||||
# assumed by default.
|
||||
# If you want to enable NTP authentication with symmetric keys, you will need
|
||||
# to uncomment the following line and edit the file to set up the keys.
|
||||
|
||||
keyfile /etc/chrony.keys
|
||||
|
||||
# Tell chronyd which numbered key in the file is used as the password
|
||||
# for chronyc. (You can pick any integer up to 2**32-1. '1' is just a
|
||||
# default. Using another value will _NOT_ increase security.)
|
||||
|
||||
commandkey 1
|
||||
|
||||
# With this directive a random password will be generated automatically.
|
||||
|
||||
generatecommandkey
|
||||
! keyfile /etc/chrony.keys
|
||||
|
||||
# chronyd can save the measurement history for the servers to files when
|
||||
# it it exits. This is useful in 2 situations:
|
||||
@@ -262,11 +248,6 @@ generatecommandkey
|
||||
# syntax and meaning is the same as for 'allow' and 'deny', except that
|
||||
# 'cmdallow' and 'cmddeny' control access to the chronyd's command port.
|
||||
|
||||
# NOTE, even if the host where you run chronyc is granted access, you
|
||||
# still need a command key set up and you have to know the password to
|
||||
# put into chronyc to allow you to modify chronyd's parameters. By
|
||||
# default all you can do is view information about chronyd's operation.
|
||||
|
||||
#######################################################################
|
||||
### REAL TIME CLOCK
|
||||
# chronyd can characterise the system's real-time clock. This is the
|
||||
|
||||
@@ -1,29 +1,15 @@
|
||||
#######################################################################
|
||||
# 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.
|
||||
#
|
||||
# This is an example chrony keys file. You should copy it to /etc/chrony.keys
|
||||
# after editing it to set up the key(s) you want to use. It should be readable
|
||||
# only by root or the user chronyd drops the root privileges to. In most
|
||||
# situations, you will require a single key (the 'commandkey') so that you can
|
||||
# supply a password to chronyc to enable you to modify chronyd's operation
|
||||
# whilst it is running.
|
||||
#
|
||||
# Copyright 2002 Richard P. Curnow
|
||||
#
|
||||
######################################################################
|
||||
# Don't use the example keys! The keys need to be random for maximum security.
|
||||
# These shell commands can be used to generate random MD5 and SHA1 keys on
|
||||
# systems which have the /dev/urandom device:
|
||||
# echo "1 MD5 HEX:$(tr -d -c '[:xdigit:]' < /dev/urandom | head -c 32)"
|
||||
# echo "1 SHA1 HEX:$(tr -d -c '[:xdigit:]' < /dev/urandom | head -c 40)"
|
||||
|
||||
# Examples of valid keys:
|
||||
|
||||
#1 ALongAndRandomPassword
|
||||
#2 MD5 HEX:B028F91EA5C38D06C2E140B26C7F41EC
|
||||
#3 SHA1 HEX:1DC764E0791B11FA67EFC7ECBC4B0D73F68A070C
|
||||
|
||||
# The keys should be random for maximum security. If you wanted to use a key
|
||||
# with ID 1 as your commandkey (i.e. chronyc password) you would put
|
||||
# "commandkey 1" into chrony.conf. If no commandkey is present in the keys
|
||||
# file and the generatecommandkey directive is specified in chrony.conf,
|
||||
# a random commandkey will be generated and added to the keys file
|
||||
# automatically on chronyd start.
|
||||
|
||||
# You might want to define more keys if you use the authentication facility
|
||||
# in the network time protocol to authenticate request/response packets between
|
||||
# trusted clients and servers.
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
nocreate
|
||||
sharedscripts
|
||||
postrotate
|
||||
/usr/bin/chronyc -a cyclelogs > /dev/null 2>&1 || true
|
||||
/usr/bin/chronyc cyclelogs > /dev/null 2>&1 || true
|
||||
endscript
|
||||
}
|
||||
|
||||
@@ -6,12 +6,12 @@ export LC_ALL=C
|
||||
|
||||
if [ "$2" = "up" ]; then
|
||||
/sbin/ip route list dev "$1" | grep -q '^default' &&
|
||||
/usr/bin/chronyc -a online > /dev/null 2>&1
|
||||
/usr/bin/chronyc online > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
if [ "$2" = "down" ]; then
|
||||
/sbin/ip route list | grep -q '^default' ||
|
||||
/usr/bin/chronyc -a offline > /dev/null 2>&1
|
||||
/usr/bin/chronyc offline > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -8,12 +8,7 @@
|
||||
** This code is in the public domain and has no copyright.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
# ifdef HAVE_ALLOCA_H
|
||||
# include <alloca.h>
|
||||
# endif
|
||||
#endif
|
||||
#include "config.h"
|
||||
|
||||
/* Since the code of getdate.y is not included in the Emacs executable
|
||||
itself, there is no need to #define static in this file. Even if
|
||||
|
||||
@@ -25,11 +25,12 @@
|
||||
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <nss.h>
|
||||
#include <hasht.h>
|
||||
#include <nsslowhash.h>
|
||||
|
||||
/* #include "config.h" */
|
||||
#include "hash.h"
|
||||
|
||||
static NSSLOWInitContext *ictx;
|
||||
|
||||
79
keys.c
79
keys.c
@@ -50,72 +50,12 @@ typedef struct {
|
||||
|
||||
static ARR_Instance keys;
|
||||
|
||||
static int command_key_valid;
|
||||
static uint32_t command_key_id;
|
||||
static int cache_valid;
|
||||
static uint32_t cache_key_id;
|
||||
static int cache_key_pos;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
generate_key(uint32_t key_id)
|
||||
{
|
||||
#ifdef FEAT_SECHASH
|
||||
unsigned char key[20];
|
||||
const char *hashname = "SHA1";
|
||||
#else
|
||||
unsigned char key[16];
|
||||
const char *hashname = "MD5";
|
||||
#endif
|
||||
const char *key_file, *rand_dev = "/dev/urandom";
|
||||
FILE *f;
|
||||
struct stat st;
|
||||
int i;
|
||||
|
||||
key_file = CNF_GetKeysFile();
|
||||
|
||||
if (!key_file)
|
||||
return 0;
|
||||
|
||||
f = fopen(rand_dev, "r");
|
||||
if (!f || fread(key, sizeof (key), 1, f) != 1) {
|
||||
if (f)
|
||||
fclose(f);
|
||||
LOG_FATAL(LOGF_Keys, "Could not read %s", rand_dev);
|
||||
return 0;
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen(key_file, "a");
|
||||
if (!f) {
|
||||
LOG_FATAL(LOGF_Keys, "Could not open keyfile %s for writing", key_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make sure the keyfile is not world-readable */
|
||||
if (stat(key_file, &st) || chmod(key_file, st.st_mode & 0770)) {
|
||||
fclose(f);
|
||||
LOG_FATAL(LOGF_Keys, "Could not change permissions of keyfile %s", key_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(f, "\n%"PRIu32" %s HEX:", key_id, hashname);
|
||||
for (i = 0; i < sizeof (key); i++)
|
||||
fprintf(f, "%02hhX", key[i]);
|
||||
fprintf(f, "\n");
|
||||
fclose(f);
|
||||
|
||||
/* Erase the key from stack */
|
||||
memset(key, 0, sizeof (key));
|
||||
|
||||
LOG(LOGS_INFO, LOGF_Keys, "Generated key %"PRIu32, key_id);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
free_keys(void)
|
||||
{
|
||||
@@ -125,7 +65,6 @@ free_keys(void)
|
||||
Free(((Key *)ARR_GetElement(keys, i))->val);
|
||||
|
||||
ARR_SetSize(keys, 0);
|
||||
command_key_valid = 0;
|
||||
cache_valid = 0;
|
||||
}
|
||||
|
||||
@@ -135,14 +74,8 @@ void
|
||||
KEY_Initialise(void)
|
||||
{
|
||||
keys = ARR_CreateInstance(sizeof (Key));
|
||||
command_key_valid = 0;
|
||||
cache_valid = 0;
|
||||
KEY_Reload();
|
||||
|
||||
if (CNF_GetGenerateCommandKey() && !KEY_KeyKnown(KEY_GetCommandKey())) {
|
||||
if (generate_key(KEY_GetCommandKey()))
|
||||
KEY_Reload();
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -334,18 +267,6 @@ get_key_by_id(uint32_t key_id)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
uint32_t
|
||||
KEY_GetCommandKey(void)
|
||||
{
|
||||
if (!command_key_valid) {
|
||||
command_key_id = CNF_GetCommandKey();
|
||||
}
|
||||
|
||||
return command_key_id;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
KEY_KeyKnown(uint32_t key_id)
|
||||
{
|
||||
|
||||
2
keys.h
2
keys.h
@@ -34,8 +34,6 @@ extern void KEY_Finalise(void);
|
||||
|
||||
extern void KEY_Reload(void);
|
||||
|
||||
extern uint32_t KEY_GetCommandKey(void);
|
||||
|
||||
extern int KEY_GetKey(uint32_t key_id, char **key, int *len);
|
||||
extern int KEY_KeyKnown(uint32_t key_id);
|
||||
extern int KEY_GetAuthDelay(uint32_t key_id);
|
||||
|
||||
52
logging.c
52
logging.c
@@ -31,7 +31,6 @@
|
||||
|
||||
#include "conf.h"
|
||||
#include "logging.h"
|
||||
#include "mkdirpp.h"
|
||||
#include "util.h"
|
||||
|
||||
/* This is used by DEBUG_LOG macro */
|
||||
@@ -49,10 +48,6 @@ static int parent_fd = 0;
|
||||
#define DEBUG_LEVEL_PRINT_DEBUG 2
|
||||
static int debug_level = 0;
|
||||
|
||||
#ifdef WINNT
|
||||
static FILE *logfile;
|
||||
#endif
|
||||
|
||||
struct LogFile {
|
||||
const char *name;
|
||||
const char *banner;
|
||||
@@ -74,10 +69,6 @@ void
|
||||
LOG_Initialise(void)
|
||||
{
|
||||
initialised = 1;
|
||||
|
||||
#ifdef WINNT
|
||||
logfile = fopen("./chronyd.err", "a");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -86,15 +77,9 @@ LOG_Initialise(void)
|
||||
void
|
||||
LOG_Finalise(void)
|
||||
{
|
||||
#ifdef WINNT
|
||||
if (logfile) {
|
||||
fclose(logfile);
|
||||
}
|
||||
#else
|
||||
if (system_log) {
|
||||
closelog();
|
||||
}
|
||||
#endif
|
||||
|
||||
LOG_CycleLogFiles();
|
||||
|
||||
@@ -105,11 +90,6 @@ LOG_Finalise(void)
|
||||
|
||||
static void log_message(int fatal, LOG_Severity severity, const char *message)
|
||||
{
|
||||
#ifdef WINNT
|
||||
if (logfile) {
|
||||
fprintf(logfile, fatal ? "Fatal error : %s\n" : "%s\n", message);
|
||||
}
|
||||
#else
|
||||
if (system_log) {
|
||||
int priority;
|
||||
switch (severity) {
|
||||
@@ -135,32 +115,33 @@ static void log_message(int fatal, LOG_Severity severity, const char *message)
|
||||
} else {
|
||||
fprintf(stderr, fatal ? "Fatal error : %s\n" : "%s\n", message);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void LOG_Message(LOG_Severity severity, LOG_Facility facility,
|
||||
int line_number, const char *filename,
|
||||
const char *function_name, const char *format, ...)
|
||||
void LOG_Message(LOG_Severity severity,
|
||||
#if DEBUG > 0
|
||||
LOG_Facility facility, int line_number,
|
||||
const char *filename, const char *function_name,
|
||||
#endif
|
||||
const char *format, ...)
|
||||
{
|
||||
char buf[2048];
|
||||
va_list other_args;
|
||||
time_t t;
|
||||
struct tm stm;
|
||||
|
||||
#ifdef WINNT
|
||||
#else
|
||||
if (!system_log) {
|
||||
/* Don't clutter up syslog with timestamps and internal debugging info */
|
||||
time(&t);
|
||||
stm = *gmtime(&t);
|
||||
strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", &stm);
|
||||
fprintf(stderr, "%s ", buf);
|
||||
#if DEBUG > 0
|
||||
if (debug_level >= DEBUG_LEVEL_PRINT_FUNCTION)
|
||||
fprintf(stderr, "%s:%d:(%s) ", filename, line_number, function_name);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
va_start(other_args, format);
|
||||
vsnprintf(buf, sizeof(buf), format, other_args);
|
||||
@@ -198,11 +179,8 @@ void LOG_Message(LOG_Severity severity, LOG_Facility facility,
|
||||
void
|
||||
LOG_OpenSystemLog(void)
|
||||
{
|
||||
#ifdef WINNT
|
||||
#else
|
||||
system_log = 1;
|
||||
openlog("chronyd", LOG_PID, LOG_DAEMON);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -300,20 +278,6 @@ LOG_FileWrite(LOG_FileID id, const char *format, ...)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LOG_CreateLogFileDir(void)
|
||||
{
|
||||
const char *logdir;
|
||||
|
||||
logdir = CNF_GetLogDir();
|
||||
|
||||
if (!mkdir_and_parents(logdir)) {
|
||||
LOG(LOGS_ERR, LOGF_Logging, "Could not create directory %s", logdir);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LOG_CycleLogFiles(void)
|
||||
{
|
||||
|
||||
26
logging.h
26
logging.h
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
* Copyright (C) Miroslav Lichvar 2013-2014
|
||||
* Copyright (C) Miroslav Lichvar 2013-2015
|
||||
*
|
||||
* 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
|
||||
@@ -45,18 +45,28 @@ extern int log_debug_enabled;
|
||||
#define FORMAT_ATTRIBUTE_PRINTF(str, first)
|
||||
#endif
|
||||
|
||||
#if DEBUG > 0
|
||||
#define LOG_MESSAGE(severity, facility, ...) \
|
||||
LOG_Message(LOGS_DEBUG, facility, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__);
|
||||
#else
|
||||
#define LOG_MESSAGE(severity, facility, ...) \
|
||||
LOG_Message(severity, __VA_ARGS__);
|
||||
#endif
|
||||
|
||||
#define DEBUG_LOG(facility, ...) \
|
||||
do { \
|
||||
if (DEBUG && log_debug_enabled) \
|
||||
LOG_Message(LOGS_DEBUG, facility, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__); \
|
||||
LOG_MESSAGE(LOGS_DEBUG, facility, __VA_ARGS__); \
|
||||
} while (0)
|
||||
#define LOG(severity, facility, ...) LOG_Message(severity, facility, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__)
|
||||
|
||||
#define LOG_FATAL(facility, ...) \
|
||||
do { \
|
||||
LOG_Message(LOGS_FATAL, facility, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__); \
|
||||
LOG_MESSAGE(LOGS_FATAL, facility, __VA_ARGS__); \
|
||||
exit(1); \
|
||||
} while (0)
|
||||
|
||||
#define LOG(severity, facility, ...) LOG_MESSAGE(severity, facility, __VA_ARGS__)
|
||||
|
||||
/* Definition of severity */
|
||||
typedef enum {
|
||||
LOGS_INFO,
|
||||
@@ -81,6 +91,7 @@ typedef enum {
|
||||
LOGF_Util,
|
||||
LOGF_Main,
|
||||
LOGF_Memory,
|
||||
LOGF_Client,
|
||||
LOGF_ClientLog,
|
||||
LOGF_Configure,
|
||||
LOGF_CmdMon,
|
||||
@@ -98,6 +109,7 @@ typedef enum {
|
||||
LOGF_SysNetBSD,
|
||||
LOGF_SysSolaris,
|
||||
LOGF_SysSunOS,
|
||||
LOGF_SysTimex,
|
||||
LOGF_SysWinnt,
|
||||
LOGF_TempComp,
|
||||
LOGF_RtcLinux,
|
||||
@@ -112,10 +124,15 @@ extern void LOG_Initialise(void);
|
||||
extern void LOG_Finalise(void);
|
||||
|
||||
/* Line logging function */
|
||||
#if DEBUG > 0
|
||||
FORMAT_ATTRIBUTE_PRINTF(6, 7)
|
||||
extern void LOG_Message(LOG_Severity severity, LOG_Facility facility,
|
||||
int line_number, const char *filename,
|
||||
const char *function_name, const char *format, ...);
|
||||
#else
|
||||
FORMAT_ATTRIBUTE_PRINTF(2, 3)
|
||||
extern void LOG_Message(LOG_Severity severity, const char *format, ...);
|
||||
#endif
|
||||
|
||||
/* Set debug level:
|
||||
0, 1 - only non-debug messages are logged
|
||||
@@ -142,7 +159,6 @@ extern LOG_FileID LOG_FileOpen(const char *name, const char *banner);
|
||||
FORMAT_ATTRIBUTE_PRINTF(2, 3)
|
||||
extern void LOG_FileWrite(LOG_FileID id, const char *format, ...);
|
||||
|
||||
extern void LOG_CreateLogFileDir(void);
|
||||
extern void LOG_CycleLogFiles(void);
|
||||
|
||||
#endif /* GOT_LOGGING_H */
|
||||
|
||||
61
main.c
61
main.c
@@ -4,7 +4,7 @@
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) John G. Hasler 2009
|
||||
* Copyright (C) Miroslav Lichvar 2012-2014
|
||||
* Copyright (C) Miroslav Lichvar 2012-2015
|
||||
*
|
||||
* 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
|
||||
@@ -51,6 +51,7 @@
|
||||
#include "nameserv.h"
|
||||
#include "smooth.h"
|
||||
#include "tempcomp.h"
|
||||
#include "util.h"
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -94,10 +95,10 @@ MAI_CleanupAndExit(void)
|
||||
MNL_Finalise();
|
||||
CLG_Finalise();
|
||||
NSR_Finalise();
|
||||
NCR_Finalise();
|
||||
CAM_Finalise();
|
||||
NIO_Finalise();
|
||||
SST_Finalise();
|
||||
NCR_Finalise();
|
||||
NIO_Finalise();
|
||||
CAM_Finalise();
|
||||
KEY_Finalise();
|
||||
RCL_Finalise();
|
||||
SRC_Finalise();
|
||||
@@ -264,7 +265,7 @@ write_lockfile(void)
|
||||
if (!out) {
|
||||
LOG_FATAL(LOGF_Main, "could not open lockfile %s for writing", pidfile);
|
||||
} else {
|
||||
fprintf(out, "%d\n", getpid());
|
||||
fprintf(out, "%d\n", (int)getpid());
|
||||
fclose(out);
|
||||
}
|
||||
}
|
||||
@@ -274,11 +275,6 @@ write_lockfile(void)
|
||||
static void
|
||||
go_daemon(void)
|
||||
{
|
||||
#ifdef WINNT
|
||||
|
||||
|
||||
#else
|
||||
|
||||
int pid, fd, pipefd[2];
|
||||
|
||||
/* Create pipe which will the daemon use to notify the grandparent
|
||||
@@ -337,8 +333,6 @@ go_daemon(void)
|
||||
LOG_SetParentFd(pipefd[1]);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -349,10 +343,11 @@ int main
|
||||
const char *conf_file = DEFAULT_CONF_FILE;
|
||||
const char *progname = argv[0];
|
||||
char *user = NULL;
|
||||
struct passwd *pw;
|
||||
int debug = 0, nofork = 0, address_family = IPADDR_UNSPEC;
|
||||
int do_init_rtc = 0, restarted = 0;
|
||||
int other_pid;
|
||||
int lock_memory = 0, sched_priority = 0;
|
||||
int scfilter_level = 0, lock_memory = 0, sched_priority = 0;
|
||||
int system_log = 1;
|
||||
int config_args = 0;
|
||||
|
||||
@@ -382,6 +377,10 @@ int main
|
||||
} else {
|
||||
user = *argv;
|
||||
}
|
||||
} else if (!strcmp("-F", *argv)) {
|
||||
++argv, --argc;
|
||||
if (argc == 0 || sscanf(*argv, "%d", &scfilter_level) != 1)
|
||||
LOG_FATAL(LOGF_Main, "Bad syscall filter level");
|
||||
} else if (!strcmp("-s", *argv)) {
|
||||
do_init_rtc = 1;
|
||||
} else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) {
|
||||
@@ -472,6 +471,12 @@ int main
|
||||
RCL_Initialise();
|
||||
KEY_Initialise();
|
||||
|
||||
/* Open privileged ports before dropping root */
|
||||
CAM_Initialise(address_family);
|
||||
NIO_Initialise(address_family);
|
||||
NCR_Initialise();
|
||||
CNF_SetupAccessRestrictions();
|
||||
|
||||
/* Command-line switch must have priority */
|
||||
if (!sched_priority) {
|
||||
sched_priority = CNF_GetSchedPriority();
|
||||
@@ -487,17 +492,19 @@ int main
|
||||
if (!user) {
|
||||
user = CNF_GetUser();
|
||||
}
|
||||
if (user && strcmp(user, "root")) {
|
||||
SYS_DropRoot(user);
|
||||
}
|
||||
|
||||
LOG_CreateLogFileDir();
|
||||
if ((pw = getpwnam(user)) == NULL)
|
||||
LOG_FATAL(LOGF_Main, "Could not get %s uid/gid", user);
|
||||
|
||||
/* Create all directories before dropping root */
|
||||
CNF_CreateDirs(pw->pw_uid, pw->pw_gid);
|
||||
|
||||
/* Drop root privileges if the user has non-zero uid or gid */
|
||||
if (pw->pw_uid || pw->pw_gid)
|
||||
SYS_DropRoot(pw->pw_uid, pw->pw_gid);
|
||||
|
||||
REF_Initialise();
|
||||
SST_Initialise();
|
||||
NIO_Initialise(address_family);
|
||||
CAM_Initialise(address_family);
|
||||
NCR_Initialise();
|
||||
NSR_Initialise();
|
||||
CLG_Initialise();
|
||||
MNL_Initialise();
|
||||
@@ -507,7 +514,12 @@ int main
|
||||
/* From now on, it is safe to do finalisation on exit */
|
||||
initialised = 1;
|
||||
|
||||
CNF_SetupAccessRestrictions();
|
||||
UTI_SetQuitSignalsHandler(signal_cleanup);
|
||||
|
||||
CAM_OpenUnixSocket();
|
||||
|
||||
if (scfilter_level)
|
||||
SYS_EnableSystemCallFilter(scfilter_level);
|
||||
|
||||
if (ref_mode == REF_ModeNormal && CNF_GetInitSources() > 0) {
|
||||
ref_mode = REF_ModeInitStepSlew;
|
||||
@@ -522,13 +534,6 @@ int main
|
||||
post_init_rtc_hook(NULL);
|
||||
}
|
||||
|
||||
signal(SIGINT, signal_cleanup);
|
||||
signal(SIGTERM, signal_cleanup);
|
||||
#if !defined(WINNT)
|
||||
signal(SIGQUIT, signal_cleanup);
|
||||
signal(SIGHUP, signal_cleanup);
|
||||
#endif /* WINNT */
|
||||
|
||||
/* The program normally runs under control of the main loop in
|
||||
the scheduler. */
|
||||
SCH_MainLoop();
|
||||
|
||||
@@ -45,10 +45,7 @@ for m in chronyc.1.in chrony.conf.5.in chronyd.8.in; do
|
||||
mv -f ${m}_ $m
|
||||
done
|
||||
|
||||
./configure && make chrony.txt || exit 1
|
||||
mv chrony.txt chrony.txt_
|
||||
make distclean
|
||||
mv chrony.txt_ chrony.txt
|
||||
./configure && make chrony.txt getdate.c || exit 1
|
||||
|
||||
awk '/^[1-9] Installation$/{p=1}
|
||||
/^[1-9]\.. Support for line editing/{exit}; p' chrony.txt | \
|
||||
@@ -63,6 +60,7 @@ a2x --lynx -f text doc/faq.adoc || exit 1
|
||||
mv doc/faq.text FAQ
|
||||
rm -rf doc
|
||||
|
||||
make distclean
|
||||
rm -f config.h config.log make_release .gitignore
|
||||
|
||||
cd ..
|
||||
|
||||
135
mkdirpp.c
135
mkdirpp.c
@@ -1,135 +0,0 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
A function for creating a directory and any parent directories that
|
||||
don't exist.
|
||||
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "memory.h"
|
||||
#include "mkdirpp.h"
|
||||
|
||||
static int
|
||||
do_dir(char *p)
|
||||
{
|
||||
int status;
|
||||
struct stat buf;
|
||||
|
||||
#if defined(TEST)
|
||||
fprintf(stderr, "do_dir(%s)\n", p);
|
||||
#endif
|
||||
|
||||
/* See if directory exists */
|
||||
status = stat(p, &buf);
|
||||
|
||||
if (status < 0) {
|
||||
if (errno == ENOENT) {
|
||||
/* Try to create directory */
|
||||
status = mkdir(p, 0755);
|
||||
return status;
|
||||
} else {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (!S_ISDIR(buf.st_mode)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Return 0 if the directory couldn't be created, 1 if it could (or
|
||||
already existed) */
|
||||
|
||||
int
|
||||
mkdir_and_parents(const char *path)
|
||||
{
|
||||
char *p;
|
||||
int len;
|
||||
int i, j, k, last;
|
||||
len = strlen(path);
|
||||
|
||||
p = (char *)Malloc(1 + len);
|
||||
|
||||
i = k = 0;
|
||||
while (1) {
|
||||
p[i++] = path[k++];
|
||||
|
||||
if (path[k] == '/' || !path[k]) {
|
||||
p[i] = 0;
|
||||
|
||||
if (do_dir(p) < 0) {
|
||||
Free(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!path[k]) {
|
||||
/* End of the string */
|
||||
break;
|
||||
}
|
||||
|
||||
/* check whether its a trailing / or group of / */
|
||||
last = 1;
|
||||
j = k+1;
|
||||
while (path[j]) {
|
||||
if (path[j] != '/') {
|
||||
k = j - 1; /* Pick up a / into p[] thru the assignment at the top of the loop */
|
||||
last = 0;
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
|
||||
if (last) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!path[k]) break;
|
||||
|
||||
}
|
||||
|
||||
Free(p);
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#if defined(TEST)
|
||||
int main(int argc, char **argv) {
|
||||
if (argc > 1) {
|
||||
/* Invert sense of result */
|
||||
return mkdir_and_parents(argv[1]) ? 0 : 1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
31
mkdirpp.h
31
mkdirpp.h
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GOT_MKDIRPP_H
|
||||
#define GOT_MKDIRPP_H
|
||||
|
||||
extern int mkdir_and_parents(const char *path);
|
||||
|
||||
#endif
|
||||
@@ -34,8 +34,7 @@
|
||||
typedef void (*DNS_NameResolveHandler)(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *anything);
|
||||
|
||||
/* Request resolving of a name to IP address. The handler will be
|
||||
called when the result is available, but it may be also called
|
||||
directly from this function call. */
|
||||
called when the result is available. */
|
||||
extern void DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *anything);
|
||||
|
||||
#endif
|
||||
|
||||
6
ntp_io.c
6
ntp_io.c
@@ -99,10 +99,10 @@ prepare_socket(int family, int port_number, int client_only)
|
||||
if (sock_fd < 0) {
|
||||
if (!client_only) {
|
||||
LOG(LOGS_ERR, LOGF_NtpIO, "Could not open %s NTP socket : %s",
|
||||
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
|
||||
UTI_SockaddrFamilyToString(family), strerror(errno));
|
||||
} else {
|
||||
DEBUG_LOG(LOGF_NtpIO, "Could not open %s NTP socket : %s",
|
||||
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
|
||||
UTI_SockaddrFamilyToString(family), strerror(errno));
|
||||
}
|
||||
return INVALID_SOCK_FD;
|
||||
}
|
||||
@@ -221,7 +221,7 @@ prepare_socket(int family, int port_number, int client_only)
|
||||
/* Bind the socket if a port or address was specified */
|
||||
if (my_addr_len > 0 && bind(sock_fd, &my_addr.u, my_addr_len) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_NtpIO, "Could not bind %s NTP socket : %s",
|
||||
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
|
||||
UTI_SockaddrFamilyToString(family), strerror(errno));
|
||||
close(sock_fd);
|
||||
return INVALID_SOCK_FD;
|
||||
}
|
||||
|
||||
@@ -703,6 +703,23 @@ NSR_HandleBadSource(IPAddr *address)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NSR_RefreshAddresses(void)
|
||||
{
|
||||
SourceRecord *record;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARR_GetSize(records); i++) {
|
||||
record = get_record(i);
|
||||
if (!record->remote_addr || !record->name)
|
||||
continue;
|
||||
|
||||
resolve_source_replacement(record);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void remove_tentative_pool_sources(int pool)
|
||||
{
|
||||
SourceRecord *record;
|
||||
|
||||
@@ -80,6 +80,9 @@ extern void NSR_RemoveAllSources(void);
|
||||
/* Procedure to try to find a replacement for a bad source */
|
||||
extern void NSR_HandleBadSource(IPAddr *address);
|
||||
|
||||
/* Procedure to resolve all names again */
|
||||
extern void NSR_RefreshAddresses(void);
|
||||
|
||||
/* This routine is called by ntp_io when a new packet arrives off the network */
|
||||
extern void NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length);
|
||||
|
||||
|
||||
@@ -150,6 +150,8 @@ command_unpadded_length(CMD_Request *r)
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
case REQ_SMOOTHTIME:
|
||||
return offsetof(CMD_Request, data.smoothtime.EOR);
|
||||
case REQ_REFRESH:
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
default:
|
||||
/* If we fall through the switch, it most likely means we've forgotten to implement a new case */
|
||||
assert(0);
|
||||
@@ -304,6 +306,8 @@ PKL_CommandPaddingLength(CMD_Request *r)
|
||||
return PADDING_LENGTH(data.null.EOR, data.smoothing.EOR);
|
||||
case REQ_SMOOTHTIME:
|
||||
return PADDING_LENGTH(data.smoothtime.EOR, data.null.EOR);
|
||||
case REQ_REFRESH:
|
||||
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
|
||||
default:
|
||||
/* If we fall through the switch, it most likely means we've forgotten to implement a new case */
|
||||
assert(0);
|
||||
|
||||
@@ -789,7 +789,7 @@ update_leap_status(NTP_Leap leap, time_t now, int reset)
|
||||
}
|
||||
}
|
||||
|
||||
if (reset || (leap_sec != our_leap_sec && !REF_IsLeapSecondClose())) {
|
||||
if (leap_sec != our_leap_sec && !REF_IsLeapSecondClose()) {
|
||||
our_leap_sec = leap_sec;
|
||||
|
||||
switch (leap_mode) {
|
||||
@@ -805,6 +805,8 @@ update_leap_status(NTP_Leap leap, time_t now, int reset)
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
} else if (reset) {
|
||||
set_leap_timeout(now);
|
||||
}
|
||||
|
||||
our_leap_status = leap;
|
||||
|
||||
@@ -1051,6 +1051,8 @@ RTC_Linux_TimePreInit(void)
|
||||
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not convert RTC reading to seconds since 1/1/1970");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
43
sources.c
43
sources.c
@@ -44,7 +44,6 @@
|
||||
#include "logging.h"
|
||||
#include "reports.h"
|
||||
#include "nameserv.h"
|
||||
#include "mkdirpp.h"
|
||||
#include "sched.h"
|
||||
#include "regress.h"
|
||||
|
||||
@@ -71,6 +70,7 @@ typedef enum {
|
||||
SRC_OK, /* OK so far, not a final status! */
|
||||
SRC_UNSELECTABLE, /* Has noselect option set */
|
||||
SRC_BAD_STATS, /* Doesn't have valid stats data */
|
||||
SRC_BAD_DISTANCE, /* Has root distance longer than allowed maximum */
|
||||
SRC_WAITS_STATS, /* Others have bad stats, selection postponed */
|
||||
SRC_STALE, /* Has older samples than others */
|
||||
SRC_FALSETICKER, /* Doesn't agree with others */
|
||||
@@ -156,6 +156,7 @@ static int selected_source_index; /* Which source index is currently
|
||||
/* Number of updates needed to reset the distant status */
|
||||
#define DISTANT_PENALTY 32
|
||||
|
||||
static double max_distance;
|
||||
static double reselect_distance;
|
||||
static double stratum_weight;
|
||||
static double combine_limit;
|
||||
@@ -180,6 +181,7 @@ void SRC_Initialise(void) {
|
||||
n_sources = 0;
|
||||
max_n_sources = 0;
|
||||
selected_source_index = INVALID_SOURCE;
|
||||
max_distance = CNF_GetMaxDistance();
|
||||
reselect_distance = CNF_GetReselectDistance();
|
||||
stratum_weight = CNF_GetStratumWeight();
|
||||
combine_limit = CNF_GetCombineLimit();
|
||||
@@ -654,6 +656,12 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Require the root distance to be below the allowed maximum */
|
||||
if (si->root_distance > max_distance) {
|
||||
sources[i]->status = SRC_BAD_DISTANCE;
|
||||
continue;
|
||||
}
|
||||
|
||||
sources[i]->status = SRC_OK; /* For now */
|
||||
|
||||
if (sources[i]->reachability && max_reach_sample_ago < first_sample_ago)
|
||||
@@ -1093,25 +1101,23 @@ SRC_DumpSources(void)
|
||||
direc_len = strlen(direc);
|
||||
file_len = direc_len + 24;
|
||||
filename = MallocArray(char, file_len); /* a bit of slack */
|
||||
if (mkdir_and_parents(direc)) {
|
||||
for (i=0; i<n_sources; i++) {
|
||||
a = (sources[i]->ref_id) >> 24;
|
||||
b = ((sources[i]->ref_id) >> 16) & 0xff;
|
||||
c = ((sources[i]->ref_id) >> 8) & 0xff;
|
||||
d = ((sources[i]->ref_id)) & 0xff;
|
||||
|
||||
snprintf(filename, file_len-1, "%s/%d.%d.%d.%d.dat", direc, a, b, c, d);
|
||||
out = fopen(filename, "w");
|
||||
if (!out) {
|
||||
LOG(LOGS_WARN, LOGF_Sources, "Could not open dump file %s", filename);
|
||||
} else {
|
||||
SST_SaveToFile(sources[i]->stats, out);
|
||||
fclose(out);
|
||||
}
|
||||
|
||||
for (i = 0; i < n_sources; i++) {
|
||||
a = (sources[i]->ref_id) >> 24;
|
||||
b = ((sources[i]->ref_id) >> 16) & 0xff;
|
||||
c = ((sources[i]->ref_id) >> 8) & 0xff;
|
||||
d = ((sources[i]->ref_id)) & 0xff;
|
||||
|
||||
snprintf(filename, file_len - 1, "%s/%d.%d.%d.%d.dat", direc, a, b, c, d);
|
||||
out = fopen(filename, "w");
|
||||
if (!out) {
|
||||
LOG(LOGS_WARN, LOGF_Sources, "Could not open dump file %s", filename);
|
||||
} else {
|
||||
SST_SaveToFile(sources[i]->stats, out);
|
||||
fclose(out);
|
||||
}
|
||||
} else {
|
||||
LOG(LOGS_ERR, LOGF_Sources, "Could not create directory %s", direc);
|
||||
}
|
||||
|
||||
Free(filename);
|
||||
}
|
||||
|
||||
@@ -1219,6 +1225,7 @@ SRC_ReportSource(int index, RPT_SourceReport *report, struct timeval *now)
|
||||
switch (src->status) {
|
||||
case SRC_UNSELECTABLE:
|
||||
case SRC_BAD_STATS:
|
||||
case SRC_BAD_DISTANCE:
|
||||
case SRC_STALE:
|
||||
case SRC_WAITS_STATS:
|
||||
report->state = RPT_UNREACH;
|
||||
|
||||
38
strerror.c
38
strerror.c
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Replacement strerror function for systems that don't have it
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef SUNOS
|
||||
|
||||
#include <errno.h>
|
||||
extern char *sys_errlist[];
|
||||
|
||||
char *strerror(int n) {
|
||||
return sys_errlist[n];
|
||||
}
|
||||
|
||||
#endif /* SUNOS */
|
||||
47
stubs.c
47
stubs.c
@@ -2,7 +2,7 @@
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2014
|
||||
* Copyright (C) Miroslav Lichvar 2014-2015
|
||||
*
|
||||
* 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
|
||||
@@ -32,12 +32,14 @@
|
||||
#include "keys.h"
|
||||
#include "logging.h"
|
||||
#include "manual.h"
|
||||
#include "memory.h"
|
||||
#include "nameserv.h"
|
||||
#include "nameserv_async.h"
|
||||
#include "ntp_core.h"
|
||||
#include "ntp_io.h"
|
||||
#include "ntp_sources.h"
|
||||
#include "refclock.h"
|
||||
#include "sched.h"
|
||||
|
||||
#ifndef FEAT_ASYNCDNS
|
||||
|
||||
@@ -45,20 +47,43 @@
|
||||
|
||||
/* This is a blocking implementation used when asynchronous resolving is not available */
|
||||
|
||||
void
|
||||
DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *anything)
|
||||
struct DNS_Async_Instance {
|
||||
const char *name;
|
||||
DNS_NameResolveHandler handler;
|
||||
void *arg;
|
||||
};
|
||||
|
||||
static void
|
||||
resolve_name(void *anything)
|
||||
{
|
||||
struct DNS_Async_Instance *inst;
|
||||
IPAddr addrs[MAX_ADDRESSES];
|
||||
DNS_Status status;
|
||||
int i;
|
||||
|
||||
status = DNS_Name2IPAddress(name, addrs, MAX_ADDRESSES);
|
||||
inst = (struct DNS_Async_Instance *)anything;
|
||||
status = DNS_Name2IPAddress(inst->name, addrs, MAX_ADDRESSES);
|
||||
|
||||
for (i = 0; status == DNS_Success && i < MAX_ADDRESSES &&
|
||||
addrs[i].family != IPADDR_UNSPEC; i++)
|
||||
addrs[i].family != IPADDR_UNSPEC; i++)
|
||||
;
|
||||
|
||||
(handler)(status, i, addrs, anything);
|
||||
(inst->handler)(status, i, addrs, inst->arg);
|
||||
|
||||
Free(inst);
|
||||
}
|
||||
|
||||
void
|
||||
DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *anything)
|
||||
{
|
||||
struct DNS_Async_Instance *inst;
|
||||
|
||||
inst = MallocNew(struct DNS_Async_Instance);
|
||||
inst->name = name;
|
||||
inst->handler = handler;
|
||||
inst->arg = anything;
|
||||
|
||||
SCH_AddTimeoutByDelay(0.0, resolve_name, inst);
|
||||
}
|
||||
|
||||
#endif /* !FEAT_ASYNCDNS */
|
||||
@@ -75,6 +100,11 @@ CAM_Finalise(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CAM_OpenUnixSocket(void)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
CAM_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all)
|
||||
{
|
||||
@@ -169,6 +199,11 @@ NSR_HandleBadSource(IPAddr *address)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NSR_RefreshAddresses(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NSR_SetSourceResolvingEndHandler(NSR_SourceResolvingEndHandler handler)
|
||||
{
|
||||
|
||||
78
sys.c
78
sys.c
@@ -27,26 +27,20 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "sys.h"
|
||||
#include "logging.h"
|
||||
|
||||
#if defined (LINUX)
|
||||
#if defined(LINUX)
|
||||
#include "sys_linux.h"
|
||||
#endif
|
||||
|
||||
#if defined (SOLARIS)
|
||||
#elif defined(SOLARIS)
|
||||
#include "sys_solaris.h"
|
||||
#endif
|
||||
|
||||
#if defined (SUNOS)
|
||||
#elif defined(SUNOS)
|
||||
#include "sys_sunos.h"
|
||||
#endif
|
||||
|
||||
#if defined (__NetBSD__)
|
||||
#elif defined(NETBSD) || defined(FREEBSD)
|
||||
#include "sys_netbsd.h"
|
||||
#endif
|
||||
|
||||
#if defined (MACOSX)
|
||||
#elif defined(MACOSX)
|
||||
#include "sys_macosx.h"
|
||||
#endif
|
||||
|
||||
@@ -55,27 +49,19 @@
|
||||
void
|
||||
SYS_Initialise(void)
|
||||
{
|
||||
|
||||
#if defined(LINUX)
|
||||
SYS_Linux_Initialise();
|
||||
#endif
|
||||
|
||||
#if defined(SOLARIS)
|
||||
#elif defined(SOLARIS)
|
||||
SYS_Solaris_Initialise();
|
||||
#endif
|
||||
|
||||
#if defined(SUNOS)
|
||||
#elif defined(SUNOS)
|
||||
SYS_SunOS_Initialise();
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
#elif defined(NETBSD) || defined(FREEBSD)
|
||||
SYS_NetBSD_Initialise();
|
||||
#endif
|
||||
|
||||
#if defined(MACOSX)
|
||||
#elif defined(MACOSX)
|
||||
SYS_MacOSX_Initialise();
|
||||
#else
|
||||
#error Unknown system
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -83,34 +69,29 @@ SYS_Initialise(void)
|
||||
void
|
||||
SYS_Finalise(void)
|
||||
{
|
||||
|
||||
#if defined(LINUX)
|
||||
SYS_Linux_Finalise();
|
||||
#endif
|
||||
|
||||
#if defined(SOLARIS)
|
||||
#elif defined(SOLARIS)
|
||||
SYS_Solaris_Finalise();
|
||||
#endif
|
||||
|
||||
#if defined(SUNOS)
|
||||
#elif defined(SUNOS)
|
||||
SYS_SunOS_Finalise();
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
#elif defined(NETBSD) || defined(FREEBSD)
|
||||
SYS_NetBSD_Finalise();
|
||||
#endif
|
||||
|
||||
#if defined(MACOSX)
|
||||
#elif defined(MACOSX)
|
||||
SYS_MacOSX_Finalise();
|
||||
#else
|
||||
#error Unknown system
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void SYS_DropRoot(char *user)
|
||||
void SYS_DropRoot(uid_t uid, gid_t gid)
|
||||
{
|
||||
#if defined(LINUX) && defined (FEAT_PRIVDROP)
|
||||
SYS_Linux_DropRoot(user);
|
||||
SYS_Linux_DropRoot(uid, gid);
|
||||
#elif defined(NETBSD) && defined(FEAT_PRIVDROP)
|
||||
SYS_NetBSD_DropRoot(uid, gid);
|
||||
#else
|
||||
LOG_FATAL(LOGF_Sys, "dropping root privileges not supported");
|
||||
#endif
|
||||
@@ -118,10 +99,23 @@ void SYS_DropRoot(char *user)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void SYS_EnableSystemCallFilter(int level)
|
||||
{
|
||||
#if defined(LINUX) && defined(FEAT_SCFILTER)
|
||||
SYS_Linux_EnableSystemCallFilter(level);
|
||||
#else
|
||||
LOG_FATAL(LOGF_Sys, "system call filter not supported");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void SYS_SetScheduler(int SchedPriority)
|
||||
{
|
||||
#if defined(LINUX) && defined(HAVE_SCHED_SETSCHEDULER)
|
||||
SYS_Linux_SetScheduler(SchedPriority);
|
||||
#elif defined(MACOSX)
|
||||
SYS_MacOSX_SetScheduler(SchedPriority);
|
||||
#else
|
||||
LOG_FATAL(LOGF_Sys, "scheduler priority setting not supported");
|
||||
#endif
|
||||
|
||||
8
sys.h
8
sys.h
@@ -35,8 +35,12 @@ extern void SYS_Initialise(void);
|
||||
/* Called at the end of the run to do final clean-up */
|
||||
extern void SYS_Finalise(void);
|
||||
|
||||
/* Drop root privileges to the specified user */
|
||||
extern void SYS_DropRoot(char *user);
|
||||
/* Drop root privileges to the specified user and group */
|
||||
extern void SYS_DropRoot(uid_t uid, gid_t gid);
|
||||
|
||||
/* Enable a system call filter to allow only system calls
|
||||
which chronyd normally needs after initialization */
|
||||
extern void SYS_EnableSystemCallFilter(int level);
|
||||
|
||||
extern void SYS_SetScheduler(int SchedPriority);
|
||||
extern void SYS_LockMemory(void);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2014
|
||||
* Copyright (C) Miroslav Lichvar 2014-2015
|
||||
*
|
||||
* 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
|
||||
@@ -43,6 +43,8 @@
|
||||
static lcl_ReadFrequencyDriver drv_read_freq;
|
||||
static lcl_SetFrequencyDriver drv_set_freq;
|
||||
static lcl_SetSyncStatusDriver drv_set_sync_status;
|
||||
static lcl_AccrueOffsetDriver drv_accrue_offset;
|
||||
static lcl_OffsetCorrectionDriver drv_get_offset_correction;
|
||||
|
||||
/* Current frequency as requested by the local module (in ppm) */
|
||||
static double base_freq;
|
||||
@@ -85,6 +87,16 @@ static double correction_rate;
|
||||
real frequency of the clock */
|
||||
static double slew_error;
|
||||
|
||||
/* Minimum offset that the system driver can slew faster than the maximum
|
||||
frequency offset that it allows to be set directly */
|
||||
static double fastslew_min_offset;
|
||||
|
||||
/* Maximum slew rate of the system driver */
|
||||
static double fastslew_max_rate;
|
||||
|
||||
/* Flag indicating that the system driver is currently slewing */
|
||||
static int fastslew_active;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void handle_end_of_slew(void *anything);
|
||||
@@ -109,6 +121,38 @@ handle_step(struct timeval *raw, struct timeval *cooked, double dfreq,
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
start_fastslew(void)
|
||||
{
|
||||
if (!drv_accrue_offset)
|
||||
return;
|
||||
|
||||
drv_accrue_offset(offset_register, 0.0);
|
||||
|
||||
DEBUG_LOG(LOGF_SysGeneric, "fastslew offset=%e", offset_register);
|
||||
|
||||
offset_register = 0.0;
|
||||
fastslew_active = 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
stop_fastslew(struct timeval *now)
|
||||
{
|
||||
double corr;
|
||||
|
||||
if (!drv_get_offset_correction || !fastslew_active)
|
||||
return;
|
||||
|
||||
/* Cancel the remaining offset */
|
||||
drv_get_offset_correction(now, &corr, NULL);
|
||||
drv_accrue_offset(corr, 0.0);
|
||||
offset_register -= corr;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static double
|
||||
clamp_freq(double freq)
|
||||
{
|
||||
@@ -138,6 +182,8 @@ update_slew(void)
|
||||
UTI_DiffTimevalsToDouble(&duration, &now, &slew_start);
|
||||
offset_register -= slew_freq * duration;
|
||||
|
||||
stop_fastslew(&now);
|
||||
|
||||
/* Estimate how long should the next slew take */
|
||||
if (fabs(offset_register) < MIN_OFFSET_CORRECTION) {
|
||||
duration = MAX_SLEW_TIMEOUT;
|
||||
@@ -155,6 +201,14 @@ update_slew(void)
|
||||
else if (corr_freq > max_corr_freq)
|
||||
corr_freq = max_corr_freq;
|
||||
|
||||
/* Let the system driver perform the slew if the requested frequency
|
||||
offset is too large for the frequency driver */
|
||||
if (drv_accrue_offset && fabs(corr_freq) >= fastslew_max_rate &&
|
||||
fabs(offset_register) > fastslew_min_offset) {
|
||||
start_fastslew();
|
||||
corr_freq = 0.0;
|
||||
}
|
||||
|
||||
/* Get the new real frequency and clamp it */
|
||||
total_freq = clamp_freq(base_freq + corr_freq * (1.0e6 - base_freq));
|
||||
|
||||
@@ -175,8 +229,8 @@ update_slew(void)
|
||||
|
||||
/* Compute the duration of the slew and clamp it. If the slewing frequency
|
||||
is zero or has wrong sign (e.g. due to rounding in the frequency driver or
|
||||
when base_freq is larger than max_freq), use maximum timeout and try again
|
||||
on the next update. */
|
||||
when base_freq is larger than max_freq, or fast slew is active), use the
|
||||
maximum timeout and try again on the next update. */
|
||||
if (fabs(offset_register) < MIN_OFFSET_CORRECTION ||
|
||||
offset_register * slew_freq <= 0.0) {
|
||||
duration = MAX_SLEW_TIMEOUT;
|
||||
@@ -246,13 +300,25 @@ static void
|
||||
offset_convert(struct timeval *raw,
|
||||
double *corr, double *err)
|
||||
{
|
||||
double duration;
|
||||
double duration, fastslew_corr, fastslew_err;
|
||||
|
||||
UTI_DiffTimevalsToDouble(&duration, raw, &slew_start);
|
||||
|
||||
*corr = slew_freq * duration - offset_register;
|
||||
if (err)
|
||||
*err = fabs(duration) <= max_freq_change_delay ? slew_error : 0.0;
|
||||
if (drv_get_offset_correction && fastslew_active) {
|
||||
drv_get_offset_correction(raw, &fastslew_corr, &fastslew_err);
|
||||
if (fastslew_corr == 0.0 && fastslew_err == 0.0)
|
||||
fastslew_active = 0;
|
||||
} else {
|
||||
fastslew_corr = fastslew_err = 0.0;
|
||||
}
|
||||
|
||||
*corr = slew_freq * duration + fastslew_corr - offset_register;
|
||||
|
||||
if (err) {
|
||||
*err = fastslew_err;
|
||||
if (fabs(duration) <= max_freq_change_delay)
|
||||
*err += slew_error;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -303,6 +369,9 @@ SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_set_freq_dela
|
||||
lcl_ReadFrequencyDriver sys_read_freq,
|
||||
lcl_SetFrequencyDriver sys_set_freq,
|
||||
lcl_ApplyStepOffsetDriver sys_apply_step_offset,
|
||||
double min_fastslew_offset, double max_fastslew_rate,
|
||||
lcl_AccrueOffsetDriver sys_accrue_offset,
|
||||
lcl_OffsetCorrectionDriver sys_get_offset_correction,
|
||||
lcl_SetLeapDriver sys_set_leap,
|
||||
lcl_SetSyncStatusDriver sys_set_sync_status)
|
||||
{
|
||||
@@ -310,6 +379,8 @@ SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_set_freq_dela
|
||||
max_freq_change_delay = max_set_freq_delay * (1.0 + max_freq / 1.0e6);
|
||||
drv_read_freq = sys_read_freq;
|
||||
drv_set_freq = sys_set_freq;
|
||||
drv_accrue_offset = sys_accrue_offset;
|
||||
drv_get_offset_correction = sys_get_offset_correction;
|
||||
drv_set_sync_status = sys_set_sync_status;
|
||||
|
||||
base_freq = (*drv_read_freq)();
|
||||
@@ -318,6 +389,10 @@ SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_set_freq_dela
|
||||
|
||||
max_corr_freq = CNF_GetMaxSlewRate() / 1.0e6;
|
||||
|
||||
fastslew_min_offset = min_fastslew_offset;
|
||||
fastslew_max_rate = max_fastslew_rate / 1.0e6;
|
||||
fastslew_active = 0;
|
||||
|
||||
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
|
||||
accrue_offset, sys_apply_step_offset ?
|
||||
sys_apply_step_offset : apply_step_offset,
|
||||
@@ -331,6 +406,8 @@ SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_set_freq_dela
|
||||
void
|
||||
SYS_Generic_Finalise(void)
|
||||
{
|
||||
struct timeval now;
|
||||
|
||||
/* Must *NOT* leave a slew running - clock could drift way off
|
||||
if the daemon is not restarted */
|
||||
if (slew_timer_running) {
|
||||
@@ -339,6 +416,9 @@ SYS_Generic_Finalise(void)
|
||||
}
|
||||
|
||||
(*drv_set_freq)(clamp_freq(base_freq));
|
||||
|
||||
LCL_ReadRawTime(&now);
|
||||
stop_fastslew(&now);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -35,6 +35,9 @@ extern void SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_s
|
||||
lcl_ReadFrequencyDriver sys_read_freq,
|
||||
lcl_SetFrequencyDriver sys_set_freq,
|
||||
lcl_ApplyStepOffsetDriver sys_apply_step_offset,
|
||||
double min_fastslew_offset, double max_fastslew_rate,
|
||||
lcl_AccrueOffsetDriver sys_accrue_offset,
|
||||
lcl_OffsetCorrectionDriver sys_get_offset_correction,
|
||||
lcl_SetLeapDriver sys_set_leap,
|
||||
lcl_SetSyncStatusDriver sys_set_sync_status);
|
||||
|
||||
|
||||
361
sys_linux.c
361
sys_linux.c
@@ -4,7 +4,7 @@
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) John G. Hasler 2009
|
||||
* Copyright (C) Miroslav Lichvar 2009-2012, 2014
|
||||
* Copyright (C) Miroslav Lichvar 2009-2012, 2014-2015
|
||||
*
|
||||
* 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
|
||||
@@ -35,31 +35,48 @@
|
||||
|
||||
#if defined(HAVE_SCHED_SETSCHEDULER)
|
||||
# include <sched.h>
|
||||
int SchedPriority = 0;
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_MLOCKALL)
|
||||
# include <sys/mman.h>
|
||||
#include <sys/resource.h>
|
||||
int LockAll = 0;
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_PRIVDROP
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/capability.h>
|
||||
#include <grp.h>
|
||||
#endif
|
||||
|
||||
#include "sys_generic.h"
|
||||
#ifdef FEAT_SCFILTER
|
||||
#include <sys/prctl.h>
|
||||
#include <seccomp.h>
|
||||
#ifdef FEAT_PHC
|
||||
#include <linux/ptp_clock.h>
|
||||
#endif
|
||||
#ifdef FEAT_PPS
|
||||
#include <linux/pps.h>
|
||||
#endif
|
||||
#ifdef FEAT_RTC
|
||||
#include <linux/rtc.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "sys_linux.h"
|
||||
#include "sys_timex.h"
|
||||
#include "conf.h"
|
||||
#include "logging.h"
|
||||
#include "wrap_adjtimex.h"
|
||||
|
||||
/* The threshold for adjtimex maxerror when the kernel sets the UNSYNC flag */
|
||||
#define UNSYNC_MAXERROR 16.0
|
||||
/* Frequency scale to convert from ppm to the timex freq */
|
||||
#define FREQ_SCALE (double)(1 << 16)
|
||||
|
||||
/* Definitions used if missed in the system headers */
|
||||
#ifndef ADJ_SETOFFSET
|
||||
#define ADJ_SETOFFSET 0x0100 /* add 'time' to current time */
|
||||
#endif
|
||||
#ifndef ADJ_NANO
|
||||
#define ADJ_NANO 0x2000 /* select nanosecond resolution */
|
||||
#endif
|
||||
|
||||
/* This is the uncompensated system tick value */
|
||||
static int nominal_tick;
|
||||
@@ -103,11 +120,19 @@ our_round(double x)
|
||||
static int
|
||||
apply_step_offset(double offset)
|
||||
{
|
||||
if (TMX_ApplyStepOffset(-offset) < 0) {
|
||||
DEBUG_LOG(LOGF_SysLinux, "adjtimex() failed");
|
||||
return 0;
|
||||
struct timex txc;
|
||||
|
||||
txc.modes = ADJ_SETOFFSET | ADJ_NANO;
|
||||
txc.time.tv_sec = -offset;
|
||||
txc.time.tv_usec = 1.0e9 * (-offset - txc.time.tv_sec);
|
||||
if (txc.time.tv_usec < 0) {
|
||||
txc.time.tv_sec--;
|
||||
txc.time.tv_usec += 1000000000;
|
||||
}
|
||||
|
||||
if (SYS_Timex_Adjust(&txc, 1) < 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -121,6 +146,7 @@ apply_step_offset(double offset)
|
||||
static double
|
||||
set_frequency(double freq_ppm)
|
||||
{
|
||||
struct timex txc;
|
||||
long required_tick;
|
||||
double required_freq;
|
||||
int required_delta_tick;
|
||||
@@ -144,14 +170,15 @@ set_frequency(double freq_ppm)
|
||||
required_freq = -(freq_ppm - dhz * required_delta_tick);
|
||||
required_tick = nominal_tick - required_delta_tick;
|
||||
|
||||
if (TMX_SetFrequency(&required_freq, required_tick) < 0) {
|
||||
LOG_FATAL(LOGF_SysLinux, "adjtimex failed for set_frequency, freq_ppm=%10.4e required_freq=%10.4e required_tick=%ld",
|
||||
freq_ppm, required_freq, required_tick);
|
||||
}
|
||||
txc.modes = ADJ_TICK | ADJ_FREQUENCY;
|
||||
txc.freq = required_freq * FREQ_SCALE;
|
||||
txc.tick = required_tick;
|
||||
|
||||
SYS_Timex_Adjust(&txc, 0);
|
||||
|
||||
current_delta_tick = required_delta_tick;
|
||||
|
||||
return dhz * current_delta_tick - required_freq;
|
||||
return dhz * current_delta_tick - txc.freq / FREQ_SCALE;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -160,61 +187,15 @@ set_frequency(double freq_ppm)
|
||||
static double
|
||||
read_frequency(void)
|
||||
{
|
||||
long tick;
|
||||
double freq;
|
||||
struct timex txc;
|
||||
|
||||
if (TMX_GetFrequency(&freq, &tick) < 0) {
|
||||
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
|
||||
}
|
||||
txc.modes = 0;
|
||||
|
||||
current_delta_tick = nominal_tick - tick;
|
||||
|
||||
return dhz * current_delta_tick - freq;
|
||||
}
|
||||
SYS_Timex_Adjust(&txc, 0);
|
||||
|
||||
/* ================================================== */
|
||||
current_delta_tick = nominal_tick - txc.tick;
|
||||
|
||||
static void
|
||||
set_leap(int leap)
|
||||
{
|
||||
int current_leap;
|
||||
|
||||
if (TMX_GetLeap(¤t_leap) < 0) {
|
||||
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed in set_leap");
|
||||
}
|
||||
|
||||
if (current_leap == leap)
|
||||
return;
|
||||
|
||||
if (TMX_SetLeap(leap) < 0) {
|
||||
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed in set_leap");
|
||||
}
|
||||
|
||||
LOG(LOGS_INFO, LOGF_SysLinux, "System clock status set to %s leap second",
|
||||
leap ? (leap > 0 ? "insert" : "delete") : "not insert/delete");
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
set_sync_status(int synchronised, double est_error, double max_error)
|
||||
{
|
||||
if (synchronised) {
|
||||
if (est_error > UNSYNC_MAXERROR)
|
||||
est_error = UNSYNC_MAXERROR;
|
||||
if (max_error >= UNSYNC_MAXERROR) {
|
||||
max_error = UNSYNC_MAXERROR;
|
||||
synchronised = 0;
|
||||
}
|
||||
} else {
|
||||
est_error = max_error = UNSYNC_MAXERROR;
|
||||
}
|
||||
|
||||
/* Clear the UNSYNC flag only if rtcsync is enabled */
|
||||
if (!CNF_GetRtcSync())
|
||||
synchronised = 0;
|
||||
|
||||
TMX_SetSync(synchronised, est_error, max_error);
|
||||
return dhz * current_delta_tick - txc.freq / FREQ_SCALE;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -225,10 +206,16 @@ set_sync_status(int synchronised, double est_error, double max_error)
|
||||
* a +/- 10% movement of tick away from the nominal value 1e6/USER_HZ. */
|
||||
|
||||
static int
|
||||
guess_hz(int tick)
|
||||
guess_hz(void)
|
||||
{
|
||||
int i, tick_lo, tick_hi, ihz;
|
||||
struct timex txc;
|
||||
int i, tick, tick_lo, tick_hi, ihz;
|
||||
double tick_nominal;
|
||||
|
||||
txc.modes = 0;
|
||||
SYS_Timex_Adjust(&txc, 0);
|
||||
tick = txc.tick;
|
||||
|
||||
/* Pick off the hz=100 case first */
|
||||
if (tick >= 9000 && tick <= 11000) {
|
||||
return 100;
|
||||
@@ -246,6 +233,8 @@ guess_hz(int tick)
|
||||
}
|
||||
|
||||
/* oh dear. doomed. */
|
||||
LOG_FATAL(LOGF_SysLinux, "Can't determine hz from tick %d", tick);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -287,21 +276,12 @@ static void
|
||||
get_version_specific_details(void)
|
||||
{
|
||||
int major, minor, patch;
|
||||
long tick;
|
||||
double freq;
|
||||
struct utsname uts;
|
||||
|
||||
hz = get_hz();
|
||||
|
||||
if (!hz) {
|
||||
if (TMX_GetFrequency(&freq, &tick) < 0)
|
||||
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
|
||||
|
||||
hz = guess_hz(tick);
|
||||
|
||||
if (!hz)
|
||||
LOG_FATAL(LOGF_SysLinux, "Can't determine hz from tick %ld", tick);
|
||||
}
|
||||
if (!hz)
|
||||
hz = guess_hz();
|
||||
|
||||
dhz = (double) hz;
|
||||
nominal_tick = (1000000L + (hz/2))/hz; /* Mirror declaration in kernel */
|
||||
@@ -344,6 +324,48 @@ get_version_specific_details(void)
|
||||
hz, nominal_tick, max_tick_bias);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
reset_adjtime_offset(void)
|
||||
{
|
||||
struct timex txc;
|
||||
|
||||
/* Reset adjtime() offset */
|
||||
txc.modes = ADJ_OFFSET_SINGLESHOT;
|
||||
txc.offset = 0;
|
||||
|
||||
SYS_Timex_Adjust(&txc, 0);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
test_step_offset(void)
|
||||
{
|
||||
struct timex txc;
|
||||
|
||||
/* Zero maxerror and check it's reset to a maximum after ADJ_SETOFFSET.
|
||||
This seems to be the only way how to verify that the kernel really
|
||||
supports the ADJ_SETOFFSET mode as it doesn't return an error on unknown
|
||||
mode. */
|
||||
|
||||
txc.modes = MOD_MAXERROR;
|
||||
txc.maxerror = 0;
|
||||
|
||||
if (SYS_Timex_Adjust(&txc, 1) < 0 || txc.maxerror != 0)
|
||||
return 0;
|
||||
|
||||
txc.modes = ADJ_SETOFFSET | ADJ_NANO;
|
||||
txc.time.tv_sec = 0;
|
||||
txc.time.tv_usec = 0;
|
||||
|
||||
if (SYS_Timex_Adjust(&txc, 1) < 0 || txc.maxerror < 100000)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Initialisation code for this module */
|
||||
|
||||
@@ -352,20 +374,18 @@ SYS_Linux_Initialise(void)
|
||||
{
|
||||
get_version_specific_details();
|
||||
|
||||
if (TMX_ResetOffset() < 0) {
|
||||
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
|
||||
}
|
||||
reset_adjtime_offset();
|
||||
|
||||
if (have_setoffset && TMX_TestStepOffset() < 0) {
|
||||
if (have_setoffset && !test_step_offset()) {
|
||||
LOG(LOGS_INFO, LOGF_SysLinux, "adjtimex() doesn't support ADJ_SETOFFSET");
|
||||
have_setoffset = 0;
|
||||
}
|
||||
|
||||
SYS_Generic_CompleteFreqDriver(1.0e6 * max_tick_bias / nominal_tick,
|
||||
1.0 / tick_update_hz,
|
||||
read_frequency, set_frequency,
|
||||
have_setoffset ? apply_step_offset : NULL,
|
||||
set_leap, set_sync_status);
|
||||
SYS_Timex_InitialiseWithFunctions(1.0e6 * max_tick_bias / nominal_tick,
|
||||
1.0 / tick_update_hz,
|
||||
read_frequency, set_frequency,
|
||||
have_setoffset ? apply_step_offset : NULL,
|
||||
0.0, 0.0, NULL, NULL);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -374,25 +394,17 @@ SYS_Linux_Initialise(void)
|
||||
void
|
||||
SYS_Linux_Finalise(void)
|
||||
{
|
||||
SYS_Generic_Finalise();
|
||||
SYS_Timex_Finalise();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#ifdef FEAT_PRIVDROP
|
||||
void
|
||||
SYS_Linux_DropRoot(char *user)
|
||||
SYS_Linux_DropRoot(uid_t uid, gid_t gid)
|
||||
{
|
||||
struct passwd *pw;
|
||||
cap_t cap;
|
||||
|
||||
if (user == NULL)
|
||||
return;
|
||||
|
||||
if ((pw = getpwnam(user)) == NULL) {
|
||||
LOG_FATAL(LOGF_SysLinux, "getpwnam(%s) failed", user);
|
||||
}
|
||||
|
||||
if (prctl(PR_SET_KEEPCAPS, 1)) {
|
||||
LOG_FATAL(LOGF_SysLinux, "prctl() failed");
|
||||
}
|
||||
@@ -401,12 +413,12 @@ SYS_Linux_DropRoot(char *user)
|
||||
LOG_FATAL(LOGF_SysLinux, "setgroups() failed");
|
||||
}
|
||||
|
||||
if (setgid(pw->pw_gid)) {
|
||||
LOG_FATAL(LOGF_SysLinux, "setgid(%d) failed", pw->pw_gid);
|
||||
if (setgid(gid)) {
|
||||
LOG_FATAL(LOGF_SysLinux, "setgid(%d) failed", gid);
|
||||
}
|
||||
|
||||
if (setuid(pw->pw_uid)) {
|
||||
LOG_FATAL(LOGF_SysLinux, "setuid(%d) failed", pw->pw_uid);
|
||||
if (setuid(uid)) {
|
||||
LOG_FATAL(LOGF_SysLinux, "setuid(%d) failed", uid);
|
||||
}
|
||||
|
||||
if ((cap = cap_from_text("cap_net_bind_service,cap_sys_time=ep")) == NULL) {
|
||||
@@ -419,7 +431,146 @@ SYS_Linux_DropRoot(char *user)
|
||||
|
||||
cap_free(cap);
|
||||
|
||||
DEBUG_LOG(LOGF_SysLinux, "Privileges dropped to user %s", user);
|
||||
DEBUG_LOG(LOGF_SysLinux, "Root dropped to uid %d gid %d", uid, gid);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#ifdef FEAT_SCFILTER
|
||||
static
|
||||
void check_seccomp_applicability(void)
|
||||
{
|
||||
int mail_enabled;
|
||||
double mail_threshold;
|
||||
char *mail_user;
|
||||
|
||||
CNF_GetMailOnChange(&mail_enabled, &mail_threshold, &mail_user);
|
||||
if (mail_enabled)
|
||||
LOG_FATAL(LOGF_SysLinux, "mailonchange directive cannot be used with -F enabled");
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SYS_Linux_EnableSystemCallFilter(int level)
|
||||
{
|
||||
const int syscalls[] = {
|
||||
/* Clock */
|
||||
SCMP_SYS(adjtimex), SCMP_SYS(gettimeofday), SCMP_SYS(settimeofday),
|
||||
SCMP_SYS(time),
|
||||
/* Process */
|
||||
SCMP_SYS(clone), SCMP_SYS(exit), SCMP_SYS(exit_group),
|
||||
SCMP_SYS(rt_sigreturn), SCMP_SYS(sigreturn),
|
||||
/* Memory */
|
||||
SCMP_SYS(brk), SCMP_SYS(madvise), SCMP_SYS(mmap), SCMP_SYS(mmap2),
|
||||
SCMP_SYS(mprotect), SCMP_SYS(munmap), SCMP_SYS(shmdt),
|
||||
/* Filesystem */
|
||||
SCMP_SYS(chmod), SCMP_SYS(chown), SCMP_SYS(chown32), SCMP_SYS(fstat),
|
||||
SCMP_SYS(fstat64), SCMP_SYS(lseek), SCMP_SYS(rename), SCMP_SYS(stat),
|
||||
SCMP_SYS(stat64), SCMP_SYS(unlink),
|
||||
/* Socket */
|
||||
SCMP_SYS(bind), SCMP_SYS(connect), SCMP_SYS(getsockname),
|
||||
SCMP_SYS(recvfrom), SCMP_SYS(recvmsg), 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(pipe),
|
||||
SCMP_SYS(poll), SCMP_SYS(read), SCMP_SYS(futex), SCMP_SYS(select),
|
||||
SCMP_SYS(set_robust_list), SCMP_SYS(write),
|
||||
/* Miscellaneous */
|
||||
SCMP_SYS(uname),
|
||||
};
|
||||
|
||||
const int socket_domains[] = {
|
||||
AF_NETLINK, AF_UNIX, AF_INET,
|
||||
#ifdef FEAT_IPV6
|
||||
AF_INET6,
|
||||
#endif
|
||||
};
|
||||
|
||||
const static int socket_options[][2] = {
|
||||
{ SOL_IP, IP_PKTINFO }, { SOL_IP, IP_FREEBIND },
|
||||
#ifdef FEAT_IPV6
|
||||
{ SOL_IPV6, IPV6_V6ONLY }, { SOL_IPV6, IPV6_RECVPKTINFO },
|
||||
#endif
|
||||
{ SOL_SOCKET, SO_BROADCAST }, { SOL_SOCKET, SO_REUSEADDR },
|
||||
{ SOL_SOCKET, SO_TIMESTAMP },
|
||||
};
|
||||
|
||||
const static int fcntls[] = { F_GETFD, F_SETFD };
|
||||
|
||||
const static unsigned long ioctls[] = {
|
||||
FIONREAD,
|
||||
#ifdef FEAT_PPS
|
||||
PTP_SYS_OFFSET,
|
||||
#endif
|
||||
#ifdef FEAT_PPS
|
||||
PPS_FETCH,
|
||||
#endif
|
||||
#ifdef FEAT_RTC
|
||||
RTC_RD_TIME, RTC_SET_TIME, RTC_UIE_ON, RTC_UIE_OFF,
|
||||
#endif
|
||||
};
|
||||
|
||||
scmp_filter_ctx *ctx;
|
||||
int i;
|
||||
|
||||
/* Check if the chronyd configuration is supported */
|
||||
check_seccomp_applicability();
|
||||
|
||||
ctx = seccomp_init(level > 0 ? SCMP_ACT_KILL : SCMP_ACT_TRAP);
|
||||
if (ctx == NULL)
|
||||
LOG_FATAL(LOGF_SysLinux, "Failed to initialize seccomp");
|
||||
|
||||
/* Add system calls that are always allowed */
|
||||
for (i = 0; i < (sizeof (syscalls) / sizeof (*syscalls)); i++) {
|
||||
if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, syscalls[i], 0) < 0)
|
||||
goto add_failed;
|
||||
}
|
||||
|
||||
/* Allow sockets to be created only in selected domains */
|
||||
for (i = 0; i < sizeof (socket_domains) / sizeof (*socket_domains); i++) {
|
||||
if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 1,
|
||||
SCMP_A0(SCMP_CMP_EQ, socket_domains[i])) < 0)
|
||||
goto add_failed;
|
||||
}
|
||||
|
||||
/* Allow setting only selected sockets options */
|
||||
for (i = 0; i < sizeof (socket_options) / sizeof (*socket_options); i++) {
|
||||
if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt), 3,
|
||||
SCMP_A1(SCMP_CMP_EQ, socket_options[i][0]),
|
||||
SCMP_A2(SCMP_CMP_EQ, socket_options[i][1]),
|
||||
SCMP_A4(SCMP_CMP_LE, sizeof (int))) < 0)
|
||||
goto add_failed;
|
||||
}
|
||||
|
||||
/* Allow only selected fcntl calls */
|
||||
for (i = 0; i < sizeof (fcntls) / sizeof (*fcntls); i++) {
|
||||
if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl), 1,
|
||||
SCMP_A1(SCMP_CMP_EQ, fcntls[i])) < 0 ||
|
||||
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl64), 1,
|
||||
SCMP_A1(SCMP_CMP_EQ, fcntls[i])) < 0)
|
||||
goto add_failed;
|
||||
}
|
||||
|
||||
/* Allow only selected ioctls */
|
||||
for (i = 0; i < sizeof (ioctls) / sizeof (*ioctls); i++) {
|
||||
if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
|
||||
SCMP_A1(SCMP_CMP_EQ, ioctls[i])) < 0)
|
||||
goto add_failed;
|
||||
}
|
||||
|
||||
if (seccomp_load(ctx) < 0)
|
||||
LOG(LOGS_INFO, LOGF_SysLinux, "Failed to load seccomp rules");
|
||||
|
||||
LOG(LOGS_INFO, LOGF_SysLinux, "Loaded seccomp filter");
|
||||
seccomp_release(ctx);
|
||||
return;
|
||||
|
||||
add_failed:
|
||||
LOG_FATAL(LOGF_SysLinux, "Failed to add seccomp rules");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -31,7 +31,9 @@ extern void SYS_Linux_Initialise(void);
|
||||
|
||||
extern void SYS_Linux_Finalise(void);
|
||||
|
||||
extern void SYS_Linux_DropRoot(char *user);
|
||||
extern void SYS_Linux_DropRoot(uid_t uid, gid_t gid);
|
||||
|
||||
extern void SYS_Linux_EnableSystemCallFilter(int level);
|
||||
|
||||
extern void SYS_Linux_MemLockAll(int LockAll);
|
||||
|
||||
|
||||
204
sys_macosx.c
204
sys_macosx.c
@@ -42,8 +42,13 @@
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_time.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "sys_macosx.h"
|
||||
#include "localp.h"
|
||||
#include "sched.h"
|
||||
#include "logging.h"
|
||||
#include "util.h"
|
||||
|
||||
@@ -69,10 +74,27 @@ static double current_freq;
|
||||
|
||||
static double adjustment_requested;
|
||||
|
||||
/* Kernel parameters to calculate adjtime error. */
|
||||
/* Interval in seconds between adjustments to cancel systematic drift */
|
||||
|
||||
static int kern_tickadj;
|
||||
static long kern_bigadj;
|
||||
#define DRIFT_REMOVAL_INTERVAL (4.0)
|
||||
#define DRIFT_REMOVAL_INTERVAL_MIN (0.5)
|
||||
|
||||
/* If current_drift_removal_interval / drift_removal_interval exceeds this
|
||||
ratio, then restart the drift removal timer */
|
||||
|
||||
#define DRIFT_REMOVAL_RESTART_RATIO (8.0)
|
||||
|
||||
static double drift_removal_interval;
|
||||
static double current_drift_removal_interval;
|
||||
static struct timeval Tdrift;
|
||||
|
||||
/* weighting applied to error in calculating drift_removal_interval */
|
||||
#define ERROR_WEIGHT (0.5)
|
||||
|
||||
/* minimum resolution of current_frequency */
|
||||
#define FREQUENCY_RES (1.0e-9)
|
||||
|
||||
#define NANOS_PER_MSEC (1000000ULL)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -84,10 +106,13 @@ clock_initialise(void)
|
||||
offset_register = 0.0;
|
||||
adjustment_requested = 0.0;
|
||||
current_freq = 0.0;
|
||||
drift_removal_interval = DRIFT_REMOVAL_INTERVAL;
|
||||
current_drift_removal_interval = DRIFT_REMOVAL_INTERVAL;
|
||||
|
||||
if (gettimeofday(&T0, NULL) < 0) {
|
||||
LOG_FATAL(LOGF_SysMacOSX, "gettimeofday() failed");
|
||||
}
|
||||
Tdrift = T0;
|
||||
|
||||
newadj.tv_sec = 0;
|
||||
newadj.tv_usec = 0;
|
||||
@@ -112,10 +137,8 @@ start_adjust(void)
|
||||
{
|
||||
struct timeval newadj, oldadj;
|
||||
struct timeval T1;
|
||||
double elapsed, accrued_error;
|
||||
double elapsed, accrued_error, predicted_error, drift_removal_elapsed;
|
||||
double adjust_required;
|
||||
struct timeval exact_newadj;
|
||||
long delta, tickdelta;
|
||||
double rounding_error;
|
||||
double old_adjust_remaining;
|
||||
|
||||
@@ -127,26 +150,24 @@ start_adjust(void)
|
||||
UTI_DiffTimevalsToDouble(&elapsed, &T1, &T0);
|
||||
accrued_error = elapsed * current_freq;
|
||||
|
||||
adjust_required = - (accrued_error + offset_register);
|
||||
UTI_DiffTimevalsToDouble(&drift_removal_elapsed, &T1, &Tdrift);
|
||||
|
||||
UTI_DoubleToTimeval(adjust_required, &exact_newadj);
|
||||
/* To allow for the clock being stepped either forward or backwards, clamp
|
||||
the elapsed time to bounds [ 0.0, current_drift_removal_interval ] */
|
||||
drift_removal_elapsed = MIN(MAX(0.0, drift_removal_elapsed), current_drift_removal_interval);
|
||||
|
||||
/* At this point, we need to round the required adjustment the
|
||||
same way the kernel does. */
|
||||
predicted_error = (current_drift_removal_interval - drift_removal_elapsed) / 2.0 * current_freq;
|
||||
|
||||
delta = exact_newadj.tv_sec * 1000000 + exact_newadj.tv_usec;
|
||||
if (delta > kern_bigadj || delta < -kern_bigadj)
|
||||
tickdelta = 10 * kern_tickadj;
|
||||
else
|
||||
tickdelta = kern_tickadj;
|
||||
if (delta % tickdelta)
|
||||
delta = delta / tickdelta * tickdelta;
|
||||
newadj.tv_sec = 0;
|
||||
newadj.tv_usec = (int)delta;
|
||||
UTI_NormaliseTimeval(&newadj);
|
||||
DEBUG_LOG(LOGF_SysMacOSX, "drift_removal_elapsed: %.3f current_drift_removal_interval: %.3f predicted_error: %.3f",
|
||||
1.0e6 * drift_removal_elapsed,
|
||||
1.0e6 * current_drift_removal_interval,
|
||||
1.0e6 * predicted_error);
|
||||
|
||||
/* Add rounding error back onto offset register. */
|
||||
UTI_DiffTimevalsToDouble(&rounding_error, &newadj, &exact_newadj);
|
||||
adjust_required = - (accrued_error + offset_register + predicted_error);
|
||||
|
||||
UTI_DoubleToTimeval(adjust_required, &newadj);
|
||||
UTI_TimevalToDouble(&newadj, &adjustment_requested);
|
||||
rounding_error = adjust_required - adjustment_requested;
|
||||
|
||||
if (adjtime(&newadj, &oldadj) < 0) {
|
||||
LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed");
|
||||
@@ -154,10 +175,9 @@ start_adjust(void)
|
||||
|
||||
UTI_TimevalToDouble(&oldadj, &old_adjust_remaining);
|
||||
|
||||
offset_register = rounding_error - old_adjust_remaining;
|
||||
offset_register = rounding_error - old_adjust_remaining - predicted_error;
|
||||
|
||||
T0 = T1;
|
||||
UTI_TimevalToDouble(&newadj, &adjustment_requested);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -272,33 +292,129 @@ get_offset_correction(struct timeval *raw,
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Cancel systematic drift */
|
||||
|
||||
static int drift_removal_running = 0;
|
||||
static SCH_TimeoutID drift_removal_id;
|
||||
|
||||
/* ================================================== */
|
||||
/* This is the timer callback routine which is called periodically to
|
||||
invoke a time adjustment to take out the machine's drift.
|
||||
Otherwise, times reported through this software (e.g. by running
|
||||
ntpdate from another machine) show the machine being correct (since
|
||||
they correct for drift build-up), but any program on this machine
|
||||
that reads the system time will be given an erroneous value, the
|
||||
degree of error depending on how long it is since
|
||||
get_offset_correction was last called. */
|
||||
|
||||
static void
|
||||
drift_removal_timeout(SCH_ArbitraryArgument not_used)
|
||||
{
|
||||
|
||||
stop_adjust();
|
||||
|
||||
if (gettimeofday(&Tdrift, NULL) < 0) {
|
||||
LOG_FATAL(LOGF_SysMacOSX, "gettimeofday() failed");
|
||||
}
|
||||
|
||||
current_drift_removal_interval = drift_removal_interval;
|
||||
|
||||
start_adjust();
|
||||
|
||||
drift_removal_id = SCH_AddTimeoutByDelay(drift_removal_interval, drift_removal_timeout, NULL);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* use est_error to calculate the drift_removal_interval */
|
||||
|
||||
static void
|
||||
set_sync_status(int synchronised, double est_error, double max_error)
|
||||
{
|
||||
double interval;
|
||||
|
||||
if (!synchronised) {
|
||||
drift_removal_interval = MAX(drift_removal_interval, DRIFT_REMOVAL_INTERVAL);
|
||||
} else {
|
||||
interval = ERROR_WEIGHT * est_error / (fabs(current_freq) + FREQUENCY_RES);
|
||||
drift_removal_interval = MAX(interval, DRIFT_REMOVAL_INTERVAL_MIN);
|
||||
|
||||
DEBUG_LOG(LOGF_SysMacOSX, "est_error: %.3f current_freq: %.3f est drift_removal_interval: %.3f act drift_removal_interval: %.3f",
|
||||
est_error * 1.0e6, current_freq * 1.0e6, interval, drift_removal_interval);
|
||||
}
|
||||
|
||||
if (current_drift_removal_interval / drift_removal_interval > DRIFT_REMOVAL_RESTART_RATIO) {
|
||||
/* recover from a large est_error by resetting the timer */
|
||||
SCH_ArbitraryArgument unused;
|
||||
SCH_RemoveTimeout(drift_removal_id);
|
||||
unused = NULL;
|
||||
drift_removal_timeout(unused);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/*
|
||||
Give chronyd real time priority so that time critical calculations
|
||||
are not pre-empted by the kernel.
|
||||
*/
|
||||
|
||||
static int
|
||||
set_realtime(void)
|
||||
{
|
||||
/* https://developer.apple.com/library/ios/technotes/tn2169/_index.html */
|
||||
|
||||
mach_timebase_info_data_t timebase_info;
|
||||
double clock2abs;
|
||||
thread_time_constraint_policy_data_t policy;
|
||||
int kr;
|
||||
|
||||
mach_timebase_info(&timebase_info);
|
||||
clock2abs = ((double)timebase_info.denom / (double)timebase_info.numer) * NANOS_PER_MSEC;
|
||||
|
||||
policy.period = 0;
|
||||
policy.computation = (uint32_t)(5 * clock2abs); /* 5 ms of work */
|
||||
policy.constraint = (uint32_t)(10 * clock2abs);
|
||||
policy.preemptible = 0;
|
||||
|
||||
kr = thread_policy_set(
|
||||
pthread_mach_thread_np(pthread_self()),
|
||||
THREAD_TIME_CONSTRAINT_POLICY,
|
||||
(thread_policy_t)&policy,
|
||||
THREAD_TIME_CONSTRAINT_POLICY_COUNT);
|
||||
|
||||
if (kr != KERN_SUCCESS) {
|
||||
LOG(LOGS_WARN, LOGF_SysMacOSX, "Cannot set real-time priority: %d", kr);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SYS_MacOSX_SetScheduler(int SchedPriority)
|
||||
{
|
||||
if (SchedPriority) {
|
||||
set_realtime();
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SYS_MacOSX_Initialise(void)
|
||||
{
|
||||
int result;
|
||||
size_t len;
|
||||
struct clockinfo clockinfo;
|
||||
int mib[2];
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_CLOCKRATE;
|
||||
|
||||
len = sizeof(clockinfo);
|
||||
result = sysctl(mib, 2, &clockinfo, &len, NULL, 0);
|
||||
|
||||
if(result < 0) {
|
||||
LOG_FATAL(LOGF_SysMacOSX, "Cannot read clockinfo");
|
||||
}
|
||||
kern_tickadj = clockinfo.tickadj;
|
||||
kern_bigadj = clockinfo.tick;
|
||||
|
||||
clock_initialise();
|
||||
|
||||
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
|
||||
accrue_offset, apply_step_offset,
|
||||
get_offset_correction,
|
||||
NULL /* set_leap */,
|
||||
NULL /* set_sync_status */);
|
||||
set_sync_status);
|
||||
|
||||
|
||||
drift_removal_id = SCH_AddTimeoutByDelay(drift_removal_interval, drift_removal_timeout, NULL);
|
||||
drift_removal_running = 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -306,6 +422,10 @@ SYS_MacOSX_Initialise(void)
|
||||
void
|
||||
SYS_MacOSX_Finalise(void)
|
||||
{
|
||||
if (drift_removal_running) {
|
||||
SCH_RemoveTimeout(drift_removal_id);
|
||||
}
|
||||
|
||||
clock_finalise();
|
||||
}
|
||||
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
#ifndef GOT_SYS_MACOSX_H
|
||||
#define GOT_SYS_MACOSX_H
|
||||
|
||||
void SYS_MacOSX_SetScheduler(int SchedPriority);
|
||||
void SYS_MacOSX_Initialise(void);
|
||||
|
||||
void SYS_MacOSX_Finalise(void);
|
||||
|
||||
#endif
|
||||
|
||||
316
sys_netbsd.c
316
sys_netbsd.c
@@ -4,6 +4,7 @@
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2001
|
||||
* Copyright (C) J. Hannken-Illjes 2001
|
||||
* Copyright (C) Miroslav Lichvar 2015
|
||||
*
|
||||
* 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
|
||||
@@ -27,171 +28,27 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef __NetBSD__
|
||||
|
||||
#include <kvm.h>
|
||||
#include <nlist.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "sys_netbsd.h"
|
||||
#include "localp.h"
|
||||
#include "sys_timex.h"
|
||||
#include "logging.h"
|
||||
#include "util.h"
|
||||
|
||||
/* ================================================== */
|
||||
/* Maximum frequency offset accepted by the kernel (in ppm) */
|
||||
#define MAX_FREQ 500.0
|
||||
|
||||
/* This register contains the number of seconds by which the local
|
||||
clock was estimated to be fast of reference time at the epoch when
|
||||
gettimeofday() returned T0 */
|
||||
/* Minimum assumed rate at which the kernel updates the clock frequency */
|
||||
#define MIN_TICK_RATE 100
|
||||
|
||||
static double offset_register;
|
||||
/* Interval between kernel updates of the adjtime() offset */
|
||||
#define ADJTIME_UPDATE_INTERVAL 1.0
|
||||
|
||||
/* This register contains the epoch to which the offset is referenced */
|
||||
/* Maximum adjtime() slew rate (in ppm) */
|
||||
#define MAX_ADJTIME_SLEWRATE 5000.0
|
||||
|
||||
static struct timeval T0;
|
||||
|
||||
/* This register contains the current estimate of the system
|
||||
frequency, in absolute (NOT ppm) */
|
||||
|
||||
static double current_freq;
|
||||
|
||||
/* This register contains the number of seconds of adjustment that
|
||||
were passed to adjtime last time it was called. */
|
||||
|
||||
static double adjustment_requested;
|
||||
|
||||
/* Kernel parameters to calculate adjtime error. */
|
||||
|
||||
static int kern_tickadj;
|
||||
static long kern_bigadj;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
clock_initialise(void)
|
||||
{
|
||||
struct timeval newadj, oldadj;
|
||||
|
||||
offset_register = 0.0;
|
||||
adjustment_requested = 0.0;
|
||||
current_freq = 0.0;
|
||||
|
||||
if (gettimeofday(&T0, NULL) < 0) {
|
||||
LOG_FATAL(LOGF_SysNetBSD, "gettimeofday() failed");
|
||||
}
|
||||
|
||||
newadj.tv_sec = 0;
|
||||
newadj.tv_usec = 0;
|
||||
|
||||
if (adjtime(&newadj, &oldadj) < 0) {
|
||||
LOG_FATAL(LOGF_SysNetBSD, "adjtime() failed");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
clock_finalise(void)
|
||||
{
|
||||
/* Nothing to do yet */
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
start_adjust(void)
|
||||
{
|
||||
struct timeval newadj, oldadj;
|
||||
struct timeval T1;
|
||||
double elapsed, accrued_error;
|
||||
double adjust_required;
|
||||
struct timeval exact_newadj;
|
||||
long delta, tickdelta;
|
||||
double rounding_error;
|
||||
double old_adjust_remaining;
|
||||
|
||||
/* Determine the amount of error built up since the last adjustment */
|
||||
if (gettimeofday(&T1, NULL) < 0) {
|
||||
LOG_FATAL(LOGF_SysNetBSD, "gettimeofday() failed");
|
||||
}
|
||||
|
||||
UTI_DiffTimevalsToDouble(&elapsed, &T1, &T0);
|
||||
accrued_error = elapsed * current_freq;
|
||||
|
||||
adjust_required = - (accrued_error + offset_register);
|
||||
|
||||
UTI_DoubleToTimeval(adjust_required, &exact_newadj);
|
||||
|
||||
/* At this point, we need to round the required adjustment the
|
||||
same way the kernel does. */
|
||||
|
||||
delta = exact_newadj.tv_sec * 1000000 + exact_newadj.tv_usec;
|
||||
if (delta > kern_bigadj || delta < -kern_bigadj)
|
||||
tickdelta = 10 * kern_tickadj;
|
||||
else
|
||||
tickdelta = kern_tickadj;
|
||||
if (delta % tickdelta)
|
||||
delta = delta / tickdelta * tickdelta;
|
||||
newadj.tv_sec = 0;
|
||||
newadj.tv_usec = delta;
|
||||
UTI_NormaliseTimeval(&newadj);
|
||||
|
||||
/* Add rounding error back onto offset register. */
|
||||
UTI_DiffTimevalsToDouble(&rounding_error, &newadj, &exact_newadj);
|
||||
|
||||
if (adjtime(&newadj, &oldadj) < 0) {
|
||||
LOG_FATAL(LOGF_SysNetBSD, "adjtime() failed");
|
||||
}
|
||||
|
||||
UTI_TimevalToDouble(&oldadj, &old_adjust_remaining);
|
||||
|
||||
offset_register = rounding_error - old_adjust_remaining;
|
||||
|
||||
T0 = T1;
|
||||
UTI_TimevalToDouble(&newadj, &adjustment_requested);
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
stop_adjust(void)
|
||||
{
|
||||
struct timeval T1;
|
||||
struct timeval zeroadj, remadj;
|
||||
double adjustment_remaining, adjustment_achieved;
|
||||
double elapsed, elapsed_plus_adjust;
|
||||
|
||||
zeroadj.tv_sec = 0;
|
||||
zeroadj.tv_usec = 0;
|
||||
|
||||
if (adjtime(&zeroadj, &remadj) < 0) {
|
||||
LOG_FATAL(LOGF_SysNetBSD, "adjtime() failed");
|
||||
}
|
||||
|
||||
if (gettimeofday(&T1, NULL) < 0) {
|
||||
LOG_FATAL(LOGF_SysNetBSD, "gettimeofday() failed");
|
||||
}
|
||||
|
||||
UTI_DiffTimevalsToDouble(&elapsed, &T1, &T0);
|
||||
UTI_TimevalToDouble(&remadj, &adjustment_remaining);
|
||||
|
||||
adjustment_achieved = adjustment_requested - adjustment_remaining;
|
||||
elapsed_plus_adjust = elapsed - adjustment_achieved;
|
||||
|
||||
offset_register += current_freq * elapsed_plus_adjust - adjustment_remaining;
|
||||
|
||||
adjustment_requested = 0.0;
|
||||
T0 = T1;
|
||||
|
||||
}
|
||||
/* Minimum offset adjtime() slews faster than MAX_FREQ */
|
||||
#define MIN_FASTSLEW_OFFSET 1.0
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -201,61 +58,20 @@ stop_adjust(void)
|
||||
static void
|
||||
accrue_offset(double offset, double corr_rate)
|
||||
{
|
||||
stop_adjust();
|
||||
offset_register += offset;
|
||||
start_adjust();
|
||||
struct timeval newadj, oldadj;
|
||||
|
||||
}
|
||||
UTI_DoubleToTimeval(-offset, &newadj);
|
||||
|
||||
/* ================================================== */
|
||||
if (adjtime(&newadj, &oldadj) < 0)
|
||||
LOG_FATAL(LOGF_SysNetBSD, "adjtime() failed");
|
||||
|
||||
/* Positive offset means system clock is fast of true time, therefore
|
||||
step backwards */
|
||||
|
||||
static int
|
||||
apply_step_offset(double offset)
|
||||
{
|
||||
struct timeval old_time, new_time, T1;
|
||||
|
||||
stop_adjust();
|
||||
|
||||
if (gettimeofday(&old_time, NULL) < 0) {
|
||||
LOG_FATAL(LOGF_SysNetBSD, "gettimeofday() failed");
|
||||
/* Add the old remaining adjustment if not zero */
|
||||
UTI_TimevalToDouble(&oldadj, &offset);
|
||||
if (offset != 0.0) {
|
||||
UTI_AddDoubleToTimeval(&newadj, offset, &newadj);
|
||||
if (adjtime(&newadj, NULL) < 0)
|
||||
LOG_FATAL(LOGF_SysNetBSD, "adjtime() failed");
|
||||
}
|
||||
|
||||
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
|
||||
|
||||
if (settimeofday(&new_time, NULL) < 0) {
|
||||
DEBUG_LOG(LOGF_SysNetBSD, "settimeofday() failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
UTI_AddDoubleToTimeval(&T0, offset, &T1);
|
||||
T0 = T1;
|
||||
|
||||
start_adjust();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static double
|
||||
set_frequency(double new_freq_ppm)
|
||||
{
|
||||
stop_adjust();
|
||||
current_freq = new_freq_ppm * 1.0e-6;
|
||||
start_adjust();
|
||||
|
||||
return current_freq * 1.0e6;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static double
|
||||
read_frequency(void)
|
||||
{
|
||||
return current_freq * 1.0e6;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -264,11 +80,21 @@ static void
|
||||
get_offset_correction(struct timeval *raw,
|
||||
double *corr, double *err)
|
||||
{
|
||||
stop_adjust();
|
||||
*corr = -offset_register;
|
||||
start_adjust();
|
||||
if (err)
|
||||
*err = 0.0;
|
||||
struct timeval remadj;
|
||||
double adjustment_remaining;
|
||||
|
||||
if (adjtime(NULL, &remadj) < 0)
|
||||
LOG_FATAL(LOGF_SysNetBSD, "adjtime() failed");
|
||||
|
||||
UTI_TimevalToDouble(&remadj, &adjustment_remaining);
|
||||
|
||||
*corr = adjustment_remaining;
|
||||
if (err) {
|
||||
if (*corr != 0.0)
|
||||
*err = 1.0e-6 * MAX_ADJTIME_SLEWRATE / ADJTIME_UPDATE_INTERVAL;
|
||||
else
|
||||
*err = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -276,42 +102,10 @@ get_offset_correction(struct timeval *raw,
|
||||
void
|
||||
SYS_NetBSD_Initialise(void)
|
||||
{
|
||||
static struct nlist nl[] = {
|
||||
{"_tickadj"},
|
||||
{"_bigadj"},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
kvm_t *kt;
|
||||
|
||||
kt = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);
|
||||
if (!kt) {
|
||||
LOG_FATAL(LOGF_SysNetBSD, "Cannot open kvm");
|
||||
}
|
||||
|
||||
if (kvm_nlist(kt, nl) < 0) {
|
||||
LOG_FATAL(LOGF_SysNetBSD, "Cannot read kernel symbols");
|
||||
}
|
||||
|
||||
if (kvm_read(kt, nl[0].n_value, (char *)(&kern_tickadj), sizeof(int)) < 0) {
|
||||
LOG_FATAL(LOGF_SysNetBSD, "Cannot read from _tickadj");
|
||||
}
|
||||
|
||||
if (kvm_read(kt, nl[1].n_value, (char *)(&kern_bigadj), sizeof(long)) < 0) {
|
||||
/* kernel doesn't have the symbol, use one second instead */
|
||||
kern_bigadj = 1000000;
|
||||
}
|
||||
|
||||
kvm_close(kt);
|
||||
|
||||
clock_initialise();
|
||||
|
||||
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
|
||||
accrue_offset, apply_step_offset,
|
||||
get_offset_correction,
|
||||
NULL /* set_leap */,
|
||||
NULL /* set_sync_status */);
|
||||
|
||||
SYS_Timex_InitialiseWithFunctions(MAX_FREQ, 1.0 / MIN_TICK_RATE,
|
||||
NULL, NULL, NULL,
|
||||
MIN_FASTSLEW_OFFSET, MAX_ADJTIME_SLEWRATE,
|
||||
accrue_offset, get_offset_correction);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -319,10 +113,32 @@ SYS_NetBSD_Initialise(void)
|
||||
void
|
||||
SYS_NetBSD_Finalise(void)
|
||||
{
|
||||
clock_finalise();
|
||||
SYS_Timex_Finalise();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#ifdef FEAT_PRIVDROP
|
||||
void
|
||||
SYS_NetBSD_DropRoot(uid_t uid, gid_t gid)
|
||||
{
|
||||
int fd;
|
||||
|
||||
#endif /* __NetBSD__ */
|
||||
if (setgroups(0, NULL))
|
||||
LOG_FATAL(LOGF_SysNetBSD, "setgroups() failed : %s", strerror(errno));
|
||||
|
||||
if (setgid(gid))
|
||||
LOG_FATAL(LOGF_SysNetBSD, "setgid(%d) failed : %s", gid, strerror(errno));
|
||||
|
||||
if (setuid(uid))
|
||||
LOG_FATAL(LOGF_SysNetBSD, "setuid(%d) failed : %s", uid, strerror(errno));
|
||||
|
||||
DEBUG_LOG(LOGF_SysNetBSD, "Root dropped to uid %d gid %d", uid, gid);
|
||||
|
||||
/* Check if we have write access to /dev/clockctl */
|
||||
fd = open("/dev/clockctl", O_WRONLY);
|
||||
if (fd < 0)
|
||||
LOG_FATAL(LOGF_SysNetBSD, "Can't write to /dev/clockctl");
|
||||
close(fd);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -32,4 +32,6 @@ void SYS_NetBSD_Initialise(void);
|
||||
|
||||
void SYS_NetBSD_Finalise(void);
|
||||
|
||||
void SYS_NetBSD_DropRoot(uid_t uid, gid_t gid);
|
||||
|
||||
#endif
|
||||
|
||||
428
sys_solaris.c
428
sys_solaris.c
@@ -26,420 +26,18 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef SOLARIS
|
||||
|
||||
#include <kvm.h>
|
||||
#include <fcntl.h>
|
||||
#include <nlist.h>
|
||||
#include <assert.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "sys_solaris.h"
|
||||
#include "localp.h"
|
||||
#include "sched.h"
|
||||
#include "logging.h"
|
||||
#include "util.h"
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* This register contains the number of seconds by which the local
|
||||
clock was estimated to be fast of reference time at the epoch when
|
||||
gettimeofday() returned T0 */
|
||||
|
||||
static double offset_register;
|
||||
|
||||
/* This register contains the epoch to which the offset is referenced */
|
||||
|
||||
static struct timeval T0;
|
||||
|
||||
/* This register contains the current estimate of the system
|
||||
frequency, in absolute (NOT ppm) */
|
||||
|
||||
static double current_freq;
|
||||
|
||||
/* This register contains the number of seconds of adjustment that
|
||||
were passed to adjtime last time it was called. */
|
||||
|
||||
static double adjustment_requested;
|
||||
|
||||
/* ================================================== */
|
||||
/* On Solaris 2.5 & 2.5.1, passing an argument of zero as the new
|
||||
delta to adjtime does not zero out the adjustment - the remaining
|
||||
adjustment is returned as the old delta arg, but the adjustment keeps
|
||||
running. To get round this, we set adjustments of +/-1us when we
|
||||
really want zero. Alternate adjustments are used to avoid a drift
|
||||
from building up. */
|
||||
|
||||
static struct timeval zeroes[2] = {
|
||||
{0, 1},
|
||||
{-1, 999999}
|
||||
};
|
||||
|
||||
static int index=0;
|
||||
|
||||
/* If 1, need to run dosynctodr(). If 0, don't */
|
||||
static int need_dosynctodr = -1;
|
||||
|
||||
|
||||
#define GET_ZERO (zeroes[index^=1])
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
clock_initialise(void)
|
||||
{
|
||||
struct timeval newadj, oldadj;
|
||||
|
||||
offset_register = 0.0;
|
||||
adjustment_requested = 0.0;
|
||||
current_freq = 0.0;
|
||||
|
||||
if (gettimeofday(&T0, NULL) < 0) {
|
||||
LOG_FATAL(LOGF_SysSolaris, "gettimeofday() failed");
|
||||
}
|
||||
|
||||
newadj = GET_ZERO;
|
||||
|
||||
if (adjtime(&newadj, &oldadj) < 0) {
|
||||
LOG_FATAL(LOGF_SysSolaris, "adjtime() failed");
|
||||
}
|
||||
|
||||
if (adjtime(&newadj, &oldadj) < 0) {
|
||||
LOG_FATAL(LOGF_SysSolaris, "adjtime() failed");
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
clock_finalise(void)
|
||||
{
|
||||
/* Nothing to do yet */
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
start_adjust(void)
|
||||
{
|
||||
struct timeval newadj, oldadj;
|
||||
struct timeval T1;
|
||||
double elapsed, accrued_error;
|
||||
double adjust_required;
|
||||
struct timeval exact_newadj;
|
||||
double rounding_error;
|
||||
double old_adjust_remaining;
|
||||
|
||||
/* Determine the amount of error built up since the last adjustment */
|
||||
if (gettimeofday(&T1, NULL) < 0) {
|
||||
LOG_FATAL(LOGF_SysSolaris, "gettimeofday() failed");
|
||||
}
|
||||
|
||||
UTI_DiffTimevalsToDouble(&elapsed, &T1, &T0);
|
||||
accrued_error = elapsed * current_freq;
|
||||
|
||||
adjust_required = - (accrued_error + offset_register);
|
||||
|
||||
UTI_DoubleToTimeval(adjust_required, &exact_newadj);
|
||||
|
||||
/* At this point, we will need to call the adjustment rounding
|
||||
algorithm in the system-specific layer. For now, just assume the
|
||||
adjustment can be applied exactly. */
|
||||
|
||||
newadj = exact_newadj;
|
||||
|
||||
/* Want to *add* rounding error back onto offset register */
|
||||
UTI_DiffTimevalsToDouble(&rounding_error, &exact_newadj, &newadj);
|
||||
|
||||
if (adjtime(&newadj, &oldadj) < 0) {
|
||||
LOG_FATAL(LOGF_SysSolaris, "adjtime() failed");
|
||||
}
|
||||
|
||||
UTI_TimevalToDouble(&oldadj, &old_adjust_remaining);
|
||||
|
||||
offset_register = rounding_error - old_adjust_remaining;
|
||||
|
||||
T0 = T1;
|
||||
UTI_TimevalToDouble(&newadj, &adjustment_requested);
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
stop_adjust(void)
|
||||
{
|
||||
struct timeval T1;
|
||||
struct timeval zeroadj, remadj;
|
||||
double adjustment_remaining, adjustment_achieved;
|
||||
double elapsed, elapsed_plus_adjust;
|
||||
|
||||
|
||||
zeroadj = GET_ZERO;
|
||||
|
||||
if (adjtime(&zeroadj, &remadj) < 0) {
|
||||
LOG_FATAL(LOGF_SysSolaris, "adjtime() failed");
|
||||
}
|
||||
|
||||
if (gettimeofday(&T1, NULL) < 0) {
|
||||
LOG_FATAL(LOGF_SysSolaris, "gettimeofday() failed");
|
||||
}
|
||||
|
||||
UTI_DiffTimevalsToDouble(&elapsed, &T1, &T0);
|
||||
UTI_TimevalToDouble(&remadj, &adjustment_remaining);
|
||||
|
||||
adjustment_achieved = adjustment_requested - adjustment_remaining;
|
||||
elapsed_plus_adjust = elapsed - adjustment_achieved;
|
||||
|
||||
offset_register += current_freq * elapsed_plus_adjust - adjustment_remaining;
|
||||
|
||||
adjustment_requested = 0.0;
|
||||
T0 = T1;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Positive offset means system clock is fast of true time, therefore
|
||||
slew backwards */
|
||||
|
||||
static void
|
||||
accrue_offset(double offset, double corr_rate)
|
||||
{
|
||||
stop_adjust();
|
||||
offset_register += offset;
|
||||
start_adjust();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Positive offset means system clock is fast of true time, therefore
|
||||
step backwards */
|
||||
|
||||
static int
|
||||
apply_step_offset(double offset)
|
||||
{
|
||||
struct timeval old_time, new_time, rounded_new_time, T1;
|
||||
double rounding_error;
|
||||
|
||||
stop_adjust();
|
||||
if (gettimeofday(&old_time, NULL) < 0) {
|
||||
LOG_FATAL(LOGF_SysSolaris, "gettimeofday() failed");
|
||||
}
|
||||
|
||||
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
|
||||
|
||||
/* The settimeofday function (on Solaris 2.5/Sparc20 at least) does
|
||||
not work quite as we would want. The time we want to set is
|
||||
rounded to the nearest second and that time is used. Also, the
|
||||
clock appears to start from that second boundary plus about 4ms.
|
||||
For now we'll tolerate this small error. */
|
||||
|
||||
rounded_new_time.tv_usec = 0;
|
||||
if (new_time.tv_usec >= 500000) {
|
||||
rounded_new_time.tv_sec = new_time.tv_sec + 1;
|
||||
} else {
|
||||
rounded_new_time.tv_sec = new_time.tv_sec;
|
||||
}
|
||||
|
||||
UTI_DiffTimevalsToDouble(&rounding_error, &rounded_new_time, &new_time);
|
||||
|
||||
if (settimeofday(&new_time, NULL) < 0) {
|
||||
DEBUG_LOG(LOGF_SysSolaris, "settimeofday() failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
UTI_AddDoubleToTimeval(&T0, offset, &T1);
|
||||
T0 = T1;
|
||||
|
||||
offset_register += rounding_error;
|
||||
|
||||
start_adjust();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static double
|
||||
set_frequency(double new_freq_ppm)
|
||||
{
|
||||
stop_adjust();
|
||||
current_freq = new_freq_ppm * 1.0e-6;
|
||||
start_adjust();
|
||||
|
||||
return current_freq * 1.0e6;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static double
|
||||
read_frequency(void)
|
||||
{
|
||||
return current_freq * 1.0e6;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
get_offset_correction(struct timeval *raw,
|
||||
double *corr, double *err)
|
||||
{
|
||||
stop_adjust();
|
||||
*corr = -offset_register;
|
||||
start_adjust();
|
||||
if (err)
|
||||
*err = 0.0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
immediate_step(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Interval in seconds between adjustments to cancel systematic drift */
|
||||
#define DRIFT_REMOVAL_INTERVAL (4.0)
|
||||
|
||||
static int drift_removal_running = 0;
|
||||
static SCH_TimeoutID drift_removal_id;
|
||||
|
||||
/* ================================================== */
|
||||
/* This is the timer callback routine which is called periodically to
|
||||
invoke a time adjustment to take out the machine's drift.
|
||||
Otherwise, times reported through this software (e.g. by running
|
||||
ntpdate from another machine) show the machine being correct (since
|
||||
they correct for drift build-up), but any program on this machine
|
||||
that reads the system time will be given an erroneous value, the
|
||||
degree of error depending on how long it is since
|
||||
get_offset_correction was last called. */
|
||||
|
||||
static void
|
||||
drift_removal_timeout(SCH_ArbitraryArgument not_used)
|
||||
{
|
||||
stop_adjust();
|
||||
start_adjust();
|
||||
drift_removal_id = SCH_AddTimeoutByDelay(DRIFT_REMOVAL_INTERVAL, drift_removal_timeout, NULL);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
check_need_dosynctodr(void)
|
||||
{
|
||||
struct utsname name;
|
||||
int result;
|
||||
int major, minor, veryminor, n_fields;
|
||||
|
||||
result = uname(&name);
|
||||
if (result < 0) {
|
||||
LOG(LOGS_ERR, LOGF_SysSolaris, "Cannot use uname to detect Solaris version");
|
||||
need_dosynctodr = 0; /* Assume recent Solaris where it isn't needed */
|
||||
return;
|
||||
}
|
||||
|
||||
n_fields = sscanf(name.release, "%d.%d.%d\n", &major, &minor, &veryminor);
|
||||
|
||||
if (n_fields < 2) {
|
||||
LOG(LOGS_ERR, LOGF_SysSolaris, "Solaris version doesn't appear to be of the form X.Y[.Z]");
|
||||
need_dosynctodr = 0; /* Assume recent Solaris where it isn't needed */
|
||||
return;
|
||||
}
|
||||
|
||||
if (major != 5) {
|
||||
LOG(LOGS_ERR, LOGF_SysSolaris, "Solaris major version doesn't appear to be 5");
|
||||
need_dosynctodr = 0; /* Assume recent Solaris where it isn't needed */
|
||||
return;
|
||||
}
|
||||
|
||||
/* The 'rule of thumb' is that from Solaris 2.6 onwards, dosynctodr() doesn't
|
||||
* need to be called, and in fact it is counter-productive to do so. For
|
||||
* earlier versions, it is required. */
|
||||
|
||||
if (minor < 6) {
|
||||
need_dosynctodr = 1;
|
||||
} else {
|
||||
need_dosynctodr = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
set_dosynctodr(unsigned long on_off)
|
||||
{
|
||||
static struct nlist nl[] = {
|
||||
{"dosynctodr"},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
kvm_t *kt;
|
||||
unsigned long read_back;
|
||||
|
||||
assert(on_off == 1 || on_off == 0);
|
||||
|
||||
kt = kvm_open(NULL, NULL, NULL, O_RDWR, NULL);
|
||||
if (!kt) {
|
||||
LOG(LOGS_ERR, LOGF_SysSolaris, "Cannot open kvm to change dosynctodr");
|
||||
return;
|
||||
}
|
||||
|
||||
if (kvm_nlist(kt, nl) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_SysSolaris, "Cannot read dosynctodr in nlist");
|
||||
kvm_close(kt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (kvm_write(kt, nl[0].n_value, (char *)(&on_off), sizeof(unsigned long)) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_SysSolaris, "Cannot write to dosynctodr");
|
||||
kvm_close(kt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (kvm_read(kt, nl[0].n_value, (char *)(&read_back), sizeof(unsigned long)) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_SysSolaris, "Cannot read from dosynctodr");
|
||||
kvm_close(kt);
|
||||
return;
|
||||
}
|
||||
|
||||
kvm_close(kt);
|
||||
|
||||
assert(read_back == on_off);
|
||||
}
|
||||
#include "sys_timex.h"
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SYS_Solaris_Initialise(void)
|
||||
{
|
||||
|
||||
check_need_dosynctodr();
|
||||
|
||||
/* Need to do KVM stuff to turn off dosynctodr. */
|
||||
|
||||
clock_initialise();
|
||||
|
||||
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
|
||||
accrue_offset, apply_step_offset,
|
||||
get_offset_correction,
|
||||
NULL /* set_leap */,
|
||||
NULL /* set_sync_status */);
|
||||
|
||||
/* Turn off the kernel switch that keeps the system clock in step
|
||||
with the non-volatile clock */
|
||||
if (need_dosynctodr) {
|
||||
set_dosynctodr(0);
|
||||
}
|
||||
|
||||
drift_removal_id = SCH_AddTimeoutByDelay(DRIFT_REMOVAL_INTERVAL, drift_removal_timeout, NULL);
|
||||
drift_removal_running = 1;
|
||||
/* The kernel allows the frequency to be set in the full range off int32_t */
|
||||
SYS_Timex_InitialiseWithFunctions(32500, 1.0 / 100, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -447,21 +45,5 @@ SYS_Solaris_Initialise(void)
|
||||
void
|
||||
SYS_Solaris_Finalise(void)
|
||||
{
|
||||
|
||||
if (drift_removal_running) {
|
||||
SCH_RemoveTimeout(drift_removal_id);
|
||||
}
|
||||
|
||||
clock_finalise();
|
||||
|
||||
/* When exiting, we want to return the machine to its 'autonomous'
|
||||
tracking mode */
|
||||
if (need_dosynctodr) {
|
||||
set_dosynctodr(1);
|
||||
}
|
||||
SYS_Timex_Finalise();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#endif /* SOLARIS */
|
||||
|
||||
|
||||
418
sys_sunos.c
418
sys_sunos.c
@@ -1,418 +0,0 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Driver file for the SunOS 4.1.x operating system.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef SUNOS
|
||||
|
||||
#include <kvm.h>
|
||||
#include <fcntl.h>
|
||||
#include <nlist.h>
|
||||
#include <assert.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "sys_sunos.h"
|
||||
#include "localp.h"
|
||||
#include "logging.h"
|
||||
#include "util.h"
|
||||
#include "sched.h"
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* This register contains the number of seconds by which the local
|
||||
clock was estimated to be fast of reference time at the epoch when
|
||||
gettimeofday() returned T0 */
|
||||
|
||||
static double offset_register;
|
||||
|
||||
/* This register contains the epoch to which the offset is referenced */
|
||||
|
||||
static struct timeval T0;
|
||||
|
||||
/* This register contains the current estimate of the system
|
||||
frequency, in absolute (NOT ppm) */
|
||||
|
||||
static double current_freq;
|
||||
|
||||
/* This register contains the number of seconds of adjustment that
|
||||
were passed to adjtime last time it was called. */
|
||||
|
||||
static double adjustment_requested;
|
||||
|
||||
/* Eventually, this needs to be a user-defined parameter - e.g. user
|
||||
might want 5 to get much finer resolution like xntpd. We stick
|
||||
with a reasonable number so that slewing can work.
|
||||
|
||||
This value has to be a factor of 1 million, otherwise the noddy
|
||||
method we use for rounding an adjustment to the nearest multiple of
|
||||
this value won't work!!
|
||||
|
||||
*/
|
||||
static unsigned long our_tickadj = 100;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
clock_initialise(void)
|
||||
{
|
||||
struct timeval newadj, oldadj;
|
||||
|
||||
offset_register = 0.0;
|
||||
adjustment_requested = 0.0;
|
||||
current_freq = 0.0;
|
||||
|
||||
if (gettimeofday(&T0, NULL) < 0) {
|
||||
LOG_FATAL(LOGF_SysSunOS, "gettimeofday() failed");
|
||||
}
|
||||
|
||||
newadj.tv_sec = 0;
|
||||
newadj.tv_usec = 0;
|
||||
|
||||
if (adjtime(&newadj, &oldadj) < 0) {
|
||||
LOG_FATAL(LOGF_SysSunOS, "adjtime() failed");
|
||||
}
|
||||
|
||||
if (adjtime(&newadj, &oldadj) < 0) {
|
||||
LOG_FATAL(LOGF_SysSunOS, "adjtime() failed");
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
clock_finalise(void)
|
||||
{
|
||||
/* Nothing to do yet */
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
start_adjust(void)
|
||||
{
|
||||
struct timeval newadj, oldadj;
|
||||
struct timeval T1;
|
||||
double elapsed, accrued_error;
|
||||
double adjust_required;
|
||||
struct timeval exact_newadj;
|
||||
double rounding_error;
|
||||
double old_adjust_remaining;
|
||||
long remainder, multiplier;
|
||||
|
||||
/* Determine the amount of error built up since the last adjustment */
|
||||
if (gettimeofday(&T1, NULL) < 0) {
|
||||
LOG_FATAL(LOGF_SysSunOS, "gettimeofday() failed");
|
||||
}
|
||||
|
||||
UTI_DiffTimevalsToDouble(&elapsed, &T1, &T0);
|
||||
accrued_error = elapsed * current_freq;
|
||||
|
||||
adjust_required = - (accrued_error + offset_register);
|
||||
|
||||
UTI_DoubleToTimeval(adjust_required, &exact_newadj);
|
||||
|
||||
/* At this point, we need to round the required adjustment to the
|
||||
closest multiple of _tickadj --- because SunOS can't process
|
||||
other adjustments exactly and will silently discard the residual.
|
||||
Obviously such behaviour can't be tolerated for us. */
|
||||
|
||||
newadj = exact_newadj;
|
||||
remainder = newadj.tv_usec % our_tickadj;
|
||||
multiplier = newadj.tv_usec / our_tickadj;
|
||||
if (remainder >= (our_tickadj >> 1)) {
|
||||
newadj.tv_usec = (multiplier + 1) * our_tickadj;
|
||||
} else {
|
||||
newadj.tv_usec = multiplier * our_tickadj;
|
||||
}
|
||||
|
||||
UTI_NormaliseTimeval(&newadj);
|
||||
|
||||
/* Want to *add* rounding error back onto offset register. Note
|
||||
that the exact adjustment was the offset register *negated* */
|
||||
UTI_DiffTimevalsToDouble(&rounding_error, &newadj, &exact_newadj);
|
||||
|
||||
if (adjtime(&newadj, &oldadj) < 0) {
|
||||
LOG_FATAL(LOGF_SysSunOS, "adjtime() failed");
|
||||
}
|
||||
|
||||
UTI_TimevalToDouble(&oldadj, &old_adjust_remaining);
|
||||
|
||||
offset_register = rounding_error - old_adjust_remaining;
|
||||
|
||||
T0 = T1;
|
||||
UTI_TimevalToDouble(&newadj, &adjustment_requested);
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
stop_adjust(void)
|
||||
{
|
||||
struct timeval T1;
|
||||
struct timeval zeroadj, remadj;
|
||||
double adjustment_remaining, adjustment_achieved;
|
||||
double gap;
|
||||
double elapsed, elapsed_plus_adjust;
|
||||
|
||||
zeroadj.tv_sec = 0;
|
||||
zeroadj.tv_usec = 0;
|
||||
|
||||
if (adjtime(&zeroadj, &remadj) < 0) {
|
||||
LOG_FATAL(LOGF_SysSunOS, "adjtime() failed");
|
||||
}
|
||||
|
||||
if (gettimeofday(&T1, NULL) < 0) {
|
||||
LOG_FATAL(LOGF_SysSunOS, "gettimeofday() failed");
|
||||
}
|
||||
|
||||
UTI_DiffTimevalsToDouble(&elapsed, &T1, &T0);
|
||||
UTI_TimevalToDouble(&remadj, &adjustment_remaining);
|
||||
|
||||
adjustment_achieved = adjustment_requested - adjustment_remaining;
|
||||
elapsed_plus_adjust = elapsed - adjustment_achieved;
|
||||
|
||||
offset_register += current_freq * elapsed_plus_adjust - adjustment_remaining;
|
||||
|
||||
adjustment_requested = 0.0;
|
||||
T0 = T1;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Positive offset means system clock is fast of true time, therefore
|
||||
slew backwards */
|
||||
|
||||
static void
|
||||
accrue_offset(double offset, double corr_rate)
|
||||
{
|
||||
stop_adjust();
|
||||
offset_register += offset;
|
||||
start_adjust();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Positive offset means system clock is fast of true time, therefore
|
||||
step backwards */
|
||||
|
||||
static int
|
||||
apply_step_offset(double offset)
|
||||
{
|
||||
struct timeval old_time, new_time, T1;
|
||||
|
||||
stop_adjust();
|
||||
if (gettimeofday(&old_time, NULL) < 0) {
|
||||
LOG_FATAL(LOGF_SysSunOS, "gettimeofday() failed");
|
||||
}
|
||||
|
||||
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
|
||||
|
||||
if (settimeofday(&new_time, NULL) < 0) {
|
||||
DEBUG_LOG(LOGF_SysSunOS, "settimeofday() failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
UTI_AddDoubleToTimeval(&T0, offset, &T1);
|
||||
T0 = T1;
|
||||
|
||||
start_adjust();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static double
|
||||
set_frequency(double new_freq_ppm)
|
||||
{
|
||||
stop_adjust();
|
||||
current_freq = new_freq_ppm * 1.0e-6;
|
||||
start_adjust();
|
||||
|
||||
return current_freq * 1.0e6;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static double
|
||||
read_frequency(void)
|
||||
{
|
||||
return current_freq * 1.0e6;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
get_offset_correction(struct timeval *raw,
|
||||
double *corr, double *err)
|
||||
{
|
||||
stop_adjust();
|
||||
*corr = -offset_register;
|
||||
start_adjust();
|
||||
if (err)
|
||||
*err = 0.0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
immediate_step(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Interval in seconds between adjustments to cancel systematic drift */
|
||||
#define DRIFT_REMOVAL_INTERVAL (4.0)
|
||||
|
||||
static int drift_removal_running = 0;
|
||||
static SCH_TimeoutID drift_removal_id;
|
||||
|
||||
/* ================================================== */
|
||||
/* This is the timer callback routine which is called periodically to
|
||||
invoke a time adjustment to take out the machine's drift.
|
||||
Otherwise, times reported through this software (e.g. by running
|
||||
ntpdate from another machine) show the machine being correct (since
|
||||
they correct for drift build-up), but any program on this machine
|
||||
that reads the system time will be given an erroneous value, the
|
||||
degree of error depending on how long it is since
|
||||
get_offset_correction was last called. */
|
||||
|
||||
static void
|
||||
drift_removal_timeout(SCH_ArbitraryArgument not_used)
|
||||
{
|
||||
stop_adjust();
|
||||
start_adjust();
|
||||
drift_removal_id = SCH_AddTimeoutByDelay(DRIFT_REMOVAL_INTERVAL, drift_removal_timeout, NULL);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
setup_kernel(unsigned long on_off)
|
||||
{
|
||||
static struct nlist nl[] = {
|
||||
{"_dosynctodr"},
|
||||
{"_tick"},
|
||||
{"_tickadj"},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
kvm_t *kt;
|
||||
unsigned long read_back;
|
||||
unsigned long our_tick = 10000;
|
||||
unsigned long default_tickadj = 625;
|
||||
|
||||
assert(on_off == 1 || on_off == 0);
|
||||
|
||||
kt = kvm_open(NULL, NULL, NULL, O_RDWR, NULL);
|
||||
if (!kt) {
|
||||
LOG(LOGS_ERR, LOGF_SysSunOS, "Cannot open kvm");
|
||||
return;
|
||||
}
|
||||
|
||||
if (kvm_nlist(kt, nl) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_SysSunOS, "Cannot read kernel symbols");
|
||||
kvm_close(kt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (kvm_write(kt, nl[0].n_value, (char *)(&on_off), sizeof(unsigned long)) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_SysSunOS, "Cannot write to _dosynctodr");
|
||||
kvm_close(kt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (kvm_write(kt, nl[1].n_value, (char *)(&our_tick), sizeof(unsigned long)) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_SysSunOS, "Cannot write to _tick");
|
||||
kvm_close(kt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (kvm_write(kt, nl[2].n_value,
|
||||
(char *)(on_off ? &default_tickadj : &our_tickadj),
|
||||
sizeof(unsigned long)) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_SysSunOS, "Cannot write to _tickadj");
|
||||
kvm_close(kt);
|
||||
return;
|
||||
}
|
||||
|
||||
kvm_close(kt);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SYS_SunOS_Initialise(void)
|
||||
{
|
||||
|
||||
/* Need to do KVM stuff to turn off dosynctodr. */
|
||||
|
||||
clock_initialise();
|
||||
|
||||
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
|
||||
accrue_offset, apply_step_offset,
|
||||
get_offset_correction,
|
||||
NULL /* set_leap */,
|
||||
NULL /* set_sync_status */);
|
||||
|
||||
/* Turn off the kernel switch that keeps the system clock in step
|
||||
with the non-volatile clock */
|
||||
setup_kernel(0);
|
||||
|
||||
drift_removal_id = SCH_AddTimeoutByDelay(DRIFT_REMOVAL_INTERVAL, drift_removal_timeout, NULL);
|
||||
drift_removal_running = 1;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SYS_SunOS_Finalise(void)
|
||||
{
|
||||
|
||||
if (drift_removal_running) {
|
||||
SCH_RemoveTimeout(drift_removal_id);
|
||||
}
|
||||
|
||||
/* Turn dosynctodr back on?? */
|
||||
|
||||
clock_finalise();
|
||||
|
||||
/* When exiting, we want to return the machine to its 'autonomous'
|
||||
tracking mode */
|
||||
setup_kernel(1);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
|
||||
#endif /* SUNOS */
|
||||
34
sys_sunos.h
34
sys_sunos.h
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header file for Solaris driver
|
||||
*/
|
||||
|
||||
#ifndef GOT_SYS_SUNOS_H
|
||||
#define GOT_SYS_SUNOS_H
|
||||
|
||||
void SYS_SunOS_Initialise(void);
|
||||
|
||||
void SYS_SunOS_Finalise(void);
|
||||
|
||||
#endif
|
||||
243
sys_timex.c
Normal file
243
sys_timex.c
Normal file
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2009-2012, 2014-2015
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Driver for systems that implement the adjtimex()/ntp_adjtime() system call
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "conf.h"
|
||||
#include "sys_generic.h"
|
||||
#include "sys_timex.h"
|
||||
#include "logging.h"
|
||||
|
||||
#ifdef LINUX
|
||||
#define NTP_ADJTIME adjtimex
|
||||
#define NTP_ADJTIME_NAME "adjtimex"
|
||||
#else
|
||||
#define NTP_ADJTIME ntp_adjtime
|
||||
#define NTP_ADJTIME_NAME "ntp_adjtime"
|
||||
#endif
|
||||
|
||||
/* Maximum frequency offset accepted by the kernel (in ppm) */
|
||||
#define MAX_FREQ 500.0
|
||||
|
||||
/* Frequency scale to convert from ppm to the timex freq */
|
||||
#define FREQ_SCALE (double)(1 << 16)
|
||||
|
||||
/* Threshold for the timex maxerror when the kernel sets the UNSYNC flag */
|
||||
#define MAX_SYNC_ERROR 16.0
|
||||
|
||||
/* Minimum assumed rate at which the kernel updates the clock frequency */
|
||||
#define MIN_TICK_RATE 100
|
||||
|
||||
/* Saved timex status */
|
||||
static int status;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static double
|
||||
read_frequency(void)
|
||||
{
|
||||
struct timex txc;
|
||||
|
||||
txc.modes = 0;
|
||||
|
||||
SYS_Timex_Adjust(&txc, 0);
|
||||
|
||||
return txc.freq / -FREQ_SCALE;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static double
|
||||
set_frequency(double freq_ppm)
|
||||
{
|
||||
struct timex txc;
|
||||
|
||||
txc.modes = MOD_FREQUENCY;
|
||||
txc.freq = freq_ppm * -FREQ_SCALE;
|
||||
|
||||
SYS_Timex_Adjust(&txc, 0);
|
||||
|
||||
return txc.freq / -FREQ_SCALE;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
set_leap(int leap)
|
||||
{
|
||||
struct timex txc;
|
||||
int applied;
|
||||
|
||||
applied = 0;
|
||||
if (!leap) {
|
||||
txc.modes = 0;
|
||||
if (SYS_Timex_Adjust(&txc, 1) == TIME_WAIT)
|
||||
applied = 1;
|
||||
}
|
||||
|
||||
status &= ~(STA_INS | STA_DEL);
|
||||
|
||||
if (leap > 0)
|
||||
status |= STA_INS;
|
||||
else if (leap < 0)
|
||||
status |= STA_DEL;
|
||||
|
||||
txc.modes = MOD_STATUS;
|
||||
txc.status = status;
|
||||
|
||||
SYS_Timex_Adjust(&txc, 0);
|
||||
|
||||
LOG(LOGS_INFO, LOGF_SysTimex, "System clock status %s leap second",
|
||||
leap ? (leap > 0 ? "set to insert" : "set to delete") :
|
||||
(applied ? "reset after" : "set to not insert/delete"));
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
set_sync_status(int synchronised, double est_error, double max_error)
|
||||
{
|
||||
struct timex txc;
|
||||
|
||||
if (synchronised) {
|
||||
if (est_error > MAX_SYNC_ERROR)
|
||||
est_error = MAX_SYNC_ERROR;
|
||||
if (max_error >= MAX_SYNC_ERROR) {
|
||||
max_error = MAX_SYNC_ERROR;
|
||||
synchronised = 0;
|
||||
}
|
||||
} else {
|
||||
est_error = max_error = MAX_SYNC_ERROR;
|
||||
}
|
||||
|
||||
#ifdef LINUX
|
||||
/* On Linux clear the UNSYNC flag only if rtcsync is enabled */
|
||||
if (!CNF_GetRtcSync())
|
||||
synchronised = 0;
|
||||
#endif
|
||||
|
||||
if (synchronised)
|
||||
status &= ~STA_UNSYNC;
|
||||
else
|
||||
status |= STA_UNSYNC;
|
||||
|
||||
txc.modes = MOD_STATUS | MOD_ESTERROR | MOD_MAXERROR;
|
||||
txc.status = status;
|
||||
txc.esterror = est_error * 1.0e6;
|
||||
txc.maxerror = max_error * 1.0e6;
|
||||
|
||||
SYS_Timex_Adjust(&txc, 1);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
initialise_timex(void)
|
||||
{
|
||||
struct timex txc;
|
||||
|
||||
status = STA_UNSYNC;
|
||||
|
||||
/* Reset PLL offset */
|
||||
txc.modes = MOD_OFFSET | MOD_STATUS;
|
||||
txc.status = STA_PLL | status;
|
||||
txc.offset = 0;
|
||||
SYS_Timex_Adjust(&txc, 0);
|
||||
|
||||
/* Turn PLL off */
|
||||
txc.modes = MOD_STATUS;
|
||||
txc.status = status;
|
||||
SYS_Timex_Adjust(&txc, 0);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SYS_Timex_Initialise(void)
|
||||
{
|
||||
SYS_Timex_InitialiseWithFunctions(MAX_FREQ, 1.0 / MIN_TICK_RATE, NULL, NULL, NULL,
|
||||
0.0, 0.0, NULL, NULL);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SYS_Timex_InitialiseWithFunctions(double max_set_freq_ppm, double max_set_freq_delay,
|
||||
lcl_ReadFrequencyDriver sys_read_freq,
|
||||
lcl_SetFrequencyDriver sys_set_freq,
|
||||
lcl_ApplyStepOffsetDriver sys_apply_step_offset,
|
||||
double min_fastslew_offset, double max_fastslew_rate,
|
||||
lcl_AccrueOffsetDriver sys_accrue_offset,
|
||||
lcl_OffsetCorrectionDriver sys_get_offset_correction)
|
||||
{
|
||||
initialise_timex();
|
||||
|
||||
SYS_Generic_CompleteFreqDriver(max_set_freq_ppm, max_set_freq_delay,
|
||||
sys_read_freq ? sys_read_freq : read_frequency,
|
||||
sys_set_freq ? sys_set_freq : set_frequency,
|
||||
sys_apply_step_offset,
|
||||
min_fastslew_offset, max_fastslew_rate,
|
||||
sys_accrue_offset, sys_get_offset_correction,
|
||||
set_leap, set_sync_status);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SYS_Timex_Finalise(void)
|
||||
{
|
||||
SYS_Generic_Finalise();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SYS_Timex_Adjust(struct timex *txc, int ignore_error)
|
||||
{
|
||||
int state;
|
||||
|
||||
#ifdef SOLARIS
|
||||
/* The kernel seems to check the constant even when it's not being set */
|
||||
if (!(txc->modes & MOD_TIMECONST))
|
||||
txc->constant = 10;
|
||||
#endif
|
||||
|
||||
state = NTP_ADJTIME(txc);
|
||||
|
||||
if (state < 0) {
|
||||
if (!ignore_error)
|
||||
LOG_FATAL(LOGF_SysTimex, NTP_ADJTIME_NAME"(0x%x) failed : %s",
|
||||
txc->modes, strerror(errno));
|
||||
else
|
||||
DEBUG_LOG(LOGF_SysTimex, NTP_ADJTIME_NAME"(0x%x) failed : %s",
|
||||
txc->modes, strerror(errno));
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
50
sys_timex.h
Normal file
50
sys_timex.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2015
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header file for a driver based on the adjtimex()/ntp_adjtime() function
|
||||
*/
|
||||
|
||||
#ifndef GOT_SYS_TIMEX_H
|
||||
#define GOT_SYS_TIMEX_H
|
||||
|
||||
#include <sys/timex.h>
|
||||
|
||||
#include "localp.h"
|
||||
|
||||
extern void SYS_Timex_Initialise(void);
|
||||
|
||||
/* Initialise with some driver functions replaced with special versions */
|
||||
extern void SYS_Timex_InitialiseWithFunctions(double max_set_freq_ppm, double max_set_freq_delay,
|
||||
lcl_ReadFrequencyDriver sys_read_freq,
|
||||
lcl_SetFrequencyDriver sys_set_freq,
|
||||
lcl_ApplyStepOffsetDriver sys_apply_step_offset,
|
||||
double min_fastslew_offset, double max_fastslew_rate,
|
||||
lcl_AccrueOffsetDriver sys_accrue_offset,
|
||||
lcl_OffsetCorrectionDriver sys_get_offset_correction);
|
||||
|
||||
extern void SYS_Timex_Finalise(void);
|
||||
|
||||
/* Wrapper for adjtimex()/ntp_adjtime() */
|
||||
extern int SYS_Timex_Adjust(struct timex *txc, int ignore_error);
|
||||
|
||||
#endif /* GOT_SYS_GENERIC_H */
|
||||
64
sysincl.h
64
sysincl.h
@@ -29,22 +29,16 @@
|
||||
#ifndef GOT_SYSINCL_H
|
||||
#define GOT_SYSINCL_H
|
||||
|
||||
#if defined (SOLARIS) || defined(SUNOS) || defined(LINUX) || defined(__NetBSD__) || defined (MACOSX)
|
||||
|
||||
#if !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(MACOSX)
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <float.h>
|
||||
#if !defined(__FreeBSD__) && !defined(MACOSX)
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#include <glob.h>
|
||||
#include <math.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <pwd.h>
|
||||
#include <resolv.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
@@ -61,6 +55,7 @@
|
||||
#include <sys/shm.h>
|
||||
#include <syslog.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
@@ -70,62 +65,9 @@
|
||||
/* Tough */
|
||||
#endif
|
||||
|
||||
/* One or other of these to make getsid() visible */
|
||||
#define __EXTENSIONS__ 1
|
||||
#define __USE_XOPEN_EXTENDED 1
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_IPV6
|
||||
/* For inet_ntop() */
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#if defined (SOLARIS) || defined(SUNOS)
|
||||
/* Only needed on these platforms, and doesn't exist on some Linux
|
||||
versions. */
|
||||
#include <nlist.h>
|
||||
#endif
|
||||
|
||||
#if defined (WINNT)
|
||||
|
||||
/* Designed to work with the GCC from the GNAT-3.10 for Win32
|
||||
distribution */
|
||||
|
||||
#define Win32_Winsock
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#if 1
|
||||
/* Cheat and inline the necessary bits from <errno.h>. We don't
|
||||
include it directly because it redefines some EXXX constants that
|
||||
conflict with <windows32/sockets.h> (included by <windows.h>) */
|
||||
|
||||
int* _errno();
|
||||
int* __doserrno();
|
||||
|
||||
#define errno (*_errno())
|
||||
#define _doserrno (*__doserrno())
|
||||
|
||||
#define ENOENT 2
|
||||
#else
|
||||
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#endif /* GOT_SYSINCL_H */
|
||||
|
||||
@@ -5,8 +5,14 @@
|
||||
cd ../..
|
||||
|
||||
for opts in \
|
||||
"--enable-debug" \
|
||||
"--disable-asyncdns" \
|
||||
"--disable-ipv6" \
|
||||
"--disable-privdrop" \
|
||||
"--disable-readline" \
|
||||
"--disable-rtc" \
|
||||
"--disable-scfilter" \
|
||||
"--disable-sechash" \
|
||||
"--disable-cmdmon" \
|
||||
"--disable-ntp" \
|
||||
"--disable-refclock" \
|
||||
@@ -15,5 +21,5 @@ for opts in \
|
||||
"--disable-cmdmon --disable-ntp --disable-refclock"
|
||||
do
|
||||
./configure $opts
|
||||
make || exit 1
|
||||
make "$@" || exit 1
|
||||
done
|
||||
|
||||
7
test/kernel/Makefile
Normal file
7
test/kernel/Makefile
Normal file
@@ -0,0 +1,7 @@
|
||||
CFLAGS=-O2 -Wall
|
||||
PROGS=adjtime ntpadjtime
|
||||
|
||||
all: $(PROGS)
|
||||
|
||||
clean:
|
||||
rm -f $(PROGS)
|
||||
185
test/kernel/adjtime.c
Normal file
185
test/kernel/adjtime.c
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (C) Miroslav Lichvar 2015
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Test the system adjtime() function. Check the range of supported offset,
|
||||
support for readonly operation, and slew rate with different update
|
||||
intervals and offsets. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static int
|
||||
diff_tv(struct timeval *tv1, struct timeval *tv2)
|
||||
{
|
||||
return 1000000 * (tv1->tv_sec - tv2->tv_sec) + (tv1->tv_usec - tv2->tv_usec);
|
||||
}
|
||||
|
||||
static struct timeval
|
||||
usec_to_tv(int usec)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
tv.tv_sec = usec / 1000000;
|
||||
tv.tv_usec = usec % 1000000;
|
||||
|
||||
return tv;
|
||||
}
|
||||
|
||||
static int
|
||||
try_adjtime(struct timeval *new, struct timeval *old)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = adjtime(new, old);
|
||||
if (r)
|
||||
printf("adjtime() failed : %s ", strerror(errno));
|
||||
return r;
|
||||
}
|
||||
|
||||
static void
|
||||
reset_adjtime(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
tv = usec_to_tv(0);
|
||||
try_adjtime(&tv, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
test_range(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
int i;
|
||||
|
||||
printf("range:\n");
|
||||
|
||||
for (i = 0; i < sizeof (time_t) * 8; i++) {
|
||||
tv.tv_usec = 0;
|
||||
tv.tv_sec = (1ULL << i) - 1;
|
||||
printf("%20lld s : ", (long long)tv.tv_sec);
|
||||
printf("%s\n", !try_adjtime(&tv, NULL) ? "ok" : "");
|
||||
tv.tv_sec = ~tv.tv_sec;
|
||||
printf("%20lld s : ", (long long)tv.tv_sec);
|
||||
printf("%s\n", !try_adjtime(&tv, NULL) ? "ok" : "");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_readonly(void)
|
||||
{
|
||||
struct timeval tv1, tv2;
|
||||
int i, r;
|
||||
|
||||
printf("readonly:\n");
|
||||
|
||||
for (i = 0; i <= 20; i++) {
|
||||
tv1 = usec_to_tv(1 << i);
|
||||
|
||||
printf("%9d us : ", 1 << i);
|
||||
try_adjtime(&tv1, NULL);
|
||||
r = !try_adjtime(NULL, &tv2) && !diff_tv(&tv1, &tv2);
|
||||
printf("%s\n", r ? "ok" : "fail");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_readwrite(void)
|
||||
{
|
||||
struct timeval tv1, tv2, tv3;
|
||||
int i, r;
|
||||
|
||||
printf("readwrite:\n");
|
||||
|
||||
for (i = 0; i <= 20; i++) {
|
||||
tv1 = usec_to_tv(1 << i);
|
||||
tv3 = usec_to_tv(0);
|
||||
|
||||
printf("%9d us : ", 1 << i);
|
||||
try_adjtime(&tv1, NULL);
|
||||
r = !try_adjtime(&tv3, &tv2) && !diff_tv(&tv1, &tv2);
|
||||
printf("%s\n", r ? "ok" : "fail");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xusleep(int usec)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
tv = usec_to_tv(usec);
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
}
|
||||
|
||||
static void
|
||||
test_slew(void)
|
||||
{
|
||||
struct timeval tv1, tv2, tv3;
|
||||
int i, j, k, diff, min, has_min;
|
||||
|
||||
printf("slew:\n");
|
||||
|
||||
for (i = 9; i <= 20; i++) {
|
||||
printf("%9d us : ", 1 << i);
|
||||
for (j = 4; j <= 20; j += 4) {
|
||||
for (min = has_min = 0, k = 4; k < 16; k += 2) {
|
||||
|
||||
tv1 = usec_to_tv(1 << j);
|
||||
tv3 = usec_to_tv(0);
|
||||
|
||||
xusleep(1 << i);
|
||||
reset_adjtime();
|
||||
|
||||
xusleep(1 << i);
|
||||
if (try_adjtime(&tv1, NULL))
|
||||
continue;
|
||||
|
||||
xusleep(1 << i);
|
||||
if (try_adjtime(&tv3, &tv2))
|
||||
continue;
|
||||
|
||||
diff = diff_tv(&tv1, &tv2);
|
||||
if (!has_min || min > diff) {
|
||||
min = diff;
|
||||
has_min = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_min)
|
||||
continue;
|
||||
|
||||
printf(" %5d (%d)", min, 1 << j);
|
||||
fflush(stdout);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
test_range();
|
||||
test_readonly();
|
||||
test_readwrite();
|
||||
test_slew();
|
||||
|
||||
reset_adjtime();
|
||||
|
||||
return 0;
|
||||
}
|
||||
75
test/kernel/ntpadjtime.c
Normal file
75
test/kernel/ntpadjtime.c
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) Miroslav Lichvar 2015
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Check the frequency range of the system ntp_adjtime() implementation */
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/timex.h>
|
||||
|
||||
static int
|
||||
try_ntpadjtime(struct timex *t)
|
||||
{
|
||||
int r;
|
||||
r = ntp_adjtime(t);
|
||||
if (r < 0)
|
||||
printf("ntp_adjtime() failed : %s ", strerror(errno));
|
||||
return r;
|
||||
}
|
||||
|
||||
static void
|
||||
reset_ntpadjtime(void)
|
||||
{
|
||||
struct timex t;
|
||||
|
||||
t.modes = MOD_OFFSET | MOD_FREQUENCY;
|
||||
t.offset = 0;
|
||||
t.freq = 0;
|
||||
try_ntpadjtime(&t);
|
||||
}
|
||||
|
||||
static void
|
||||
test_freqrange(void)
|
||||
{
|
||||
struct timex t;
|
||||
int i;
|
||||
|
||||
printf("freq range:\n");
|
||||
|
||||
for (i = 0; i <= 1000; i += 50) {
|
||||
t.modes = MOD_FREQUENCY;
|
||||
t.freq = i << 16;
|
||||
printf("%4d ppm => ", i);
|
||||
if (try_ntpadjtime(&t) < 0)
|
||||
continue;
|
||||
|
||||
printf("%4ld ppm : ", t.freq / (1 << 16));
|
||||
printf("%s\n", t.freq == i << 16 ? "ok" : "fail");
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
test_freqrange();
|
||||
|
||||
reset_ntpadjtime();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -6,6 +6,7 @@ test_start "presend option"
|
||||
min_sync_time=140
|
||||
max_sync_time=260
|
||||
client_server_options="presend 6 maxdelay 16"
|
||||
client_conf="maxdistance 10"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
|
||||
259
util.c
259
util.c
@@ -29,12 +29,14 @@
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "logging.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
#include "hash.h"
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
INLINE_STATIC void
|
||||
void
|
||||
UTI_TimevalToDouble(struct timeval *a, double *b)
|
||||
{
|
||||
*b = (double)(a->tv_sec) + 1.0e-6 * (double)(a->tv_usec);
|
||||
@@ -43,20 +45,22 @@ UTI_TimevalToDouble(struct timeval *a, double *b)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
INLINE_STATIC void
|
||||
void
|
||||
UTI_DoubleToTimeval(double a, struct timeval *b)
|
||||
{
|
||||
long int_part, frac_part;
|
||||
long int_part;
|
||||
double frac_part;
|
||||
int_part = (long)(a);
|
||||
frac_part = (long)(0.5 + 1.0e6 * (a - (double)(int_part)));
|
||||
frac_part = 1.0e6 * (a - (double)(int_part));
|
||||
frac_part = frac_part > 0 ? frac_part + 0.5 : frac_part - 0.5;
|
||||
b->tv_sec = int_part;
|
||||
b->tv_usec = frac_part;
|
||||
b->tv_usec = (long)frac_part;
|
||||
UTI_NormaliseTimeval(b);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
INLINE_STATIC int
|
||||
int
|
||||
UTI_CompareTimevals(struct timeval *a, struct timeval *b)
|
||||
{
|
||||
if (a->tv_sec < b->tv_sec) {
|
||||
@@ -76,7 +80,7 @@ UTI_CompareTimevals(struct timeval *a, struct timeval *b)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
INLINE_STATIC void
|
||||
void
|
||||
UTI_NormaliseTimeval(struct timeval *x)
|
||||
{
|
||||
/* Reduce tv_usec to within +-1000000 of zero. JGH */
|
||||
@@ -95,7 +99,7 @@ UTI_NormaliseTimeval(struct timeval *x)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
INLINE_STATIC void
|
||||
void
|
||||
UTI_DiffTimevals(struct timeval *result,
|
||||
struct timeval *a,
|
||||
struct timeval *b)
|
||||
@@ -112,7 +116,7 @@ UTI_DiffTimevals(struct timeval *result,
|
||||
/* ================================================== */
|
||||
|
||||
/* Calculate result = a - b and return as a double */
|
||||
INLINE_STATIC void
|
||||
void
|
||||
UTI_DiffTimevalsToDouble(double *result,
|
||||
struct timeval *a,
|
||||
struct timeval *b)
|
||||
@@ -123,7 +127,7 @@ UTI_DiffTimevalsToDouble(double *result,
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
INLINE_STATIC void
|
||||
void
|
||||
UTI_AddDoubleToTimeval(struct timeval *start,
|
||||
double increment,
|
||||
struct timeval *end)
|
||||
@@ -147,7 +151,7 @@ UTI_AddDoubleToTimeval(struct timeval *start,
|
||||
/* ================================================== */
|
||||
|
||||
/* Calculate the average and difference (as a double) of two timevals */
|
||||
INLINE_STATIC void
|
||||
void
|
||||
UTI_AverageDiffTimevals (struct timeval *earlier,
|
||||
struct timeval *later,
|
||||
struct timeval *average,
|
||||
@@ -485,6 +489,55 @@ UTI_IPAndPortToSockaddr(IPAddr *ip, unsigned short port, struct sockaddr *sa)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
char *UTI_SockaddrToString(struct sockaddr *sa)
|
||||
{
|
||||
unsigned short port;
|
||||
IPAddr ip;
|
||||
char *result;
|
||||
|
||||
result = NEXT_BUFFER;
|
||||
|
||||
switch (sa->sa_family) {
|
||||
case AF_INET:
|
||||
#ifdef AF_INET6
|
||||
case AF_INET6:
|
||||
#endif
|
||||
UTI_SockaddrToIPAndPort(sa, &ip, &port);
|
||||
snprintf(result, BUFFER_LENGTH, "%s:%hu", UTI_IPToString(&ip), port);
|
||||
break;
|
||||
case AF_UNIX:
|
||||
snprintf(result, BUFFER_LENGTH, "%s", ((struct sockaddr_un *)sa)->sun_path);
|
||||
break;
|
||||
default:
|
||||
snprintf(result, BUFFER_LENGTH, "[UNKNOWN]");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
const char *
|
||||
UTI_SockaddrFamilyToString(int family)
|
||||
{
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
return "IPv4";
|
||||
#ifdef AF_INET6
|
||||
case AF_INET6:
|
||||
return "IPv6";
|
||||
#endif
|
||||
case AF_UNIX:
|
||||
return "Unix";
|
||||
case AF_UNSPEC:
|
||||
return "UNSPEC";
|
||||
default:
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
char *
|
||||
UTI_TimeToLogForm(time_t t)
|
||||
{
|
||||
@@ -649,11 +702,11 @@ UTI_Log2ToDouble(int l)
|
||||
if (l >= 0) {
|
||||
if (l > 31)
|
||||
l = 31;
|
||||
return 1 << l;
|
||||
return (uint32_t)1 << l;
|
||||
} else {
|
||||
if (l < -31)
|
||||
l = -31;
|
||||
return 1.0 / (1 << -l);
|
||||
return 1.0 / ((uint32_t)1 << -l);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -837,3 +890,183 @@ UTI_DecodePasswordFromText(char *key)
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
UTI_SetQuitSignalsHandler(void (*handler)(int))
|
||||
{
|
||||
struct sigaction sa;
|
||||
|
||||
sa.sa_handler = handler;
|
||||
sa.sa_flags = SA_RESTART;
|
||||
if (sigemptyset(&sa.sa_mask) < 0)
|
||||
return 0;
|
||||
|
||||
#ifdef SIGINT
|
||||
if (sigaction(SIGINT, &sa, NULL) < 0)
|
||||
return 0;
|
||||
#endif
|
||||
#ifdef SIGTERM
|
||||
if (sigaction(SIGTERM, &sa, NULL) < 0)
|
||||
return 0;
|
||||
#endif
|
||||
#ifdef SIGQUIT
|
||||
if (sigaction(SIGQUIT, &sa, NULL) < 0)
|
||||
return 0;
|
||||
#endif
|
||||
#ifdef SIGHUP
|
||||
if (sigaction(SIGHUP, &sa, NULL) < 0)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
char *
|
||||
UTI_PathToDir(const char *path)
|
||||
{
|
||||
char *dir, *slash;
|
||||
|
||||
slash = strrchr(path, '/');
|
||||
|
||||
if (!slash)
|
||||
return Strdup(".");
|
||||
|
||||
if (slash == path)
|
||||
return Strdup("/");
|
||||
|
||||
dir = Malloc(slash - path + 1);
|
||||
snprintf(dir, slash - path + 1, "%s", path);
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
create_dir(char *p, mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
int status;
|
||||
struct stat buf;
|
||||
|
||||
/* See if directory exists */
|
||||
status = stat(p, &buf);
|
||||
|
||||
if (status < 0) {
|
||||
if (errno != ENOENT) {
|
||||
LOG(LOGS_ERR, LOGF_Util, "Could not access %s : %s", p, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (S_ISDIR(buf.st_mode))
|
||||
return 1;
|
||||
LOG(LOGS_ERR, LOGF_Util, "%s is not directory", p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create the directory */
|
||||
if (mkdir(p, mode) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_Util, "Could not create directory %s : %s", p, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set its owner */
|
||||
if (chown(p, uid, gid) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_Util, "Could not change ownership of %s : %s", p, strerror(errno));
|
||||
/* Don't leave it there with incorrect ownership */
|
||||
rmdir(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Return 0 if the directory couldn't be created, 1 if it could (or
|
||||
already existed) */
|
||||
int
|
||||
UTI_CreateDirAndParents(const char *path, mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
char *p;
|
||||
int i, j, k, last;
|
||||
|
||||
/* Don't try to create current directory */
|
||||
if (!strcmp(path, "."))
|
||||
return 1;
|
||||
|
||||
p = (char *)Malloc(1 + strlen(path));
|
||||
|
||||
i = k = 0;
|
||||
while (1) {
|
||||
p[i++] = path[k++];
|
||||
|
||||
if (path[k] == '/' || !path[k]) {
|
||||
/* Check whether its end of string, a trailing / or group of / */
|
||||
last = 1;
|
||||
j = k;
|
||||
while (path[j]) {
|
||||
if (path[j] != '/') {
|
||||
/* Pick up a / into p[] thru the assignment at the top of the loop */
|
||||
k = j - 1;
|
||||
last = 0;
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
|
||||
p[i] = 0;
|
||||
|
||||
if (!create_dir(p, last ? mode : 0755, last ? uid : 0, last ? gid : 0)) {
|
||||
Free(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (last)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!path[k])
|
||||
break;
|
||||
}
|
||||
|
||||
Free(p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
UTI_CheckDirPermissions(const char *path, mode_t perm, uid_t uid, gid_t gid)
|
||||
{
|
||||
struct stat buf;
|
||||
|
||||
if (stat(path, &buf)) {
|
||||
LOG(LOGS_ERR, LOGF_Util, "Could not access %s : %s", path, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!S_ISDIR(buf.st_mode)) {
|
||||
LOG(LOGS_ERR, LOGF_Util, "%s is not directory", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((buf.st_mode & 0777) & ~perm) {
|
||||
LOG(LOGS_ERR, LOGF_Util, "Wrong permissions on %s", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (buf.st_uid != uid) {
|
||||
LOG(LOGS_ERR, LOGF_Util, "Wrong owner of %s (%s != %d)", path, "UID", uid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (buf.st_gid != gid) {
|
||||
LOG(LOGS_ERR, LOGF_Util, "Wrong owner of %s (%s != %d)", path, "GID", gid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
22
util.h
22
util.h
@@ -88,6 +88,8 @@ extern int UTI_CompareIPs(IPAddr *a, IPAddr *b, IPAddr *mask);
|
||||
|
||||
extern void UTI_SockaddrToIPAndPort(struct sockaddr *sa, IPAddr *ip, unsigned short *port);
|
||||
extern int UTI_IPAndPortToSockaddr(IPAddr *ip, unsigned short port, struct sockaddr *sa);
|
||||
extern char *UTI_SockaddrToString(struct sockaddr *sa);
|
||||
extern const char *UTI_SockaddrFamilyToString(int family);
|
||||
|
||||
extern char *UTI_TimeToLogForm(time_t t);
|
||||
|
||||
@@ -127,11 +129,19 @@ extern int UTI_CheckNTPAuth(int hash_id, const unsigned char *key, int key_len,
|
||||
/* Decode password encoded in ASCII or HEX */
|
||||
extern int UTI_DecodePasswordFromText(char *key);
|
||||
|
||||
#if defined (INLINE_UTILITIES)
|
||||
#define INLINE_STATIC inline static
|
||||
#include "util.c"
|
||||
#else
|
||||
#define INLINE_STATIC
|
||||
#endif /* defined (INLINE_UTILITIES) */
|
||||
extern int UTI_SetQuitSignalsHandler(void (*handler)(int));
|
||||
|
||||
/* Get directory (as an allocated string) for a path */
|
||||
extern char *UTI_PathToDir(const char *path);
|
||||
|
||||
/* Create a directory with a specified mode (umasked) and set its uid/gid.
|
||||
Create also any parent directories that don't exist with mode 755 and
|
||||
default uid/gid. Returns 1 if created or already exists (even with
|
||||
different mode/uid/gid), 0 otherwise. */
|
||||
extern int UTI_CreateDirAndParents(const char *path, mode_t mode, uid_t uid, gid_t gid);
|
||||
|
||||
/* Check if a directory is secure. It must not have other than the specified
|
||||
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);
|
||||
|
||||
#endif /* GOT_UTIL_H */
|
||||
|
||||
204
wrap_adjtimex.c
204
wrap_adjtimex.c
@@ -1,204 +0,0 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
* Copyright (C) Miroslav Lichvar 2011-2012, 2014
|
||||
*
|
||||
* 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 is a wrapper around the Linux adjtimex system call.
|
||||
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "wrap_adjtimex.h"
|
||||
|
||||
#include <sys/timex.h>
|
||||
|
||||
/* Definitions used if missing in the system headers */
|
||||
#ifndef ADJ_TAI
|
||||
#define ADJ_TAI 0x0080 /* set TAI offset */
|
||||
#endif
|
||||
#ifndef ADJ_SETOFFSET
|
||||
#define ADJ_SETOFFSET 0x0100 /* add 'time' to current time */
|
||||
#endif
|
||||
#ifndef ADJ_NANO
|
||||
#define ADJ_NANO 0x2000 /* select nanosecond resolution */
|
||||
#endif
|
||||
#ifndef ADJ_OFFSET_SS_READ
|
||||
#define ADJ_OFFSET_SS_READ 0xa001 /* read-only adjtime */
|
||||
#endif
|
||||
|
||||
/* Frequency offset scale (shift) */
|
||||
#define SHIFT_USEC 16
|
||||
|
||||
static int status = 0;
|
||||
|
||||
int
|
||||
TMX_ResetOffset(void)
|
||||
{
|
||||
struct timex txc;
|
||||
|
||||
/* Reset adjtime() offset */
|
||||
txc.modes = ADJ_OFFSET_SINGLESHOT;
|
||||
txc.offset = 0;
|
||||
if (adjtimex(&txc) < 0)
|
||||
return -1;
|
||||
|
||||
/* Reset PLL offset */
|
||||
txc.modes = ADJ_OFFSET | ADJ_STATUS;
|
||||
txc.status = STA_PLL;
|
||||
txc.offset = 0;
|
||||
if (adjtimex(&txc) < 0)
|
||||
return -1;
|
||||
|
||||
/* Set status back */
|
||||
txc.modes = ADJ_STATUS;
|
||||
txc.status = status;
|
||||
if (adjtimex(&txc) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
TMX_SetFrequency(double *freq, long tick)
|
||||
{
|
||||
struct timex txc;
|
||||
|
||||
txc.modes = ADJ_TICK | ADJ_FREQUENCY;
|
||||
|
||||
txc.freq = (long)(*freq * (double)(1 << SHIFT_USEC));
|
||||
*freq = txc.freq / (double)(1 << SHIFT_USEC);
|
||||
txc.tick = tick;
|
||||
|
||||
return adjtimex(&txc);
|
||||
}
|
||||
|
||||
int
|
||||
TMX_GetFrequency(double *freq, long *tick)
|
||||
{
|
||||
struct timex txc;
|
||||
int result;
|
||||
txc.modes = 0; /* pure read */
|
||||
result = adjtimex(&txc);
|
||||
*freq = txc.freq / (double)(1 << SHIFT_USEC);
|
||||
*tick = txc.tick;
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
TMX_SetLeap(int leap)
|
||||
{
|
||||
struct timex txc;
|
||||
|
||||
status &= ~(STA_INS | STA_DEL);
|
||||
|
||||
if (leap > 0) {
|
||||
status |= STA_INS;
|
||||
} else if (leap < 0) {
|
||||
status |= STA_DEL;
|
||||
}
|
||||
|
||||
txc.modes = ADJ_STATUS;
|
||||
txc.status = status;
|
||||
|
||||
return adjtimex(&txc);
|
||||
}
|
||||
|
||||
int
|
||||
TMX_GetLeap(int *leap)
|
||||
{
|
||||
struct timex txc;
|
||||
|
||||
txc.modes = 0;
|
||||
if (adjtimex(&txc) < 0)
|
||||
return -1;
|
||||
|
||||
status &= ~(STA_INS | STA_DEL);
|
||||
status |= txc.status & (STA_INS | STA_DEL);
|
||||
|
||||
if (status & STA_INS)
|
||||
*leap = 1;
|
||||
else if (status & STA_DEL)
|
||||
*leap = -1;
|
||||
else
|
||||
*leap = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TMX_SetSync(int sync, double est_error, double max_error)
|
||||
{
|
||||
struct timex txc;
|
||||
|
||||
if (sync) {
|
||||
status &= ~STA_UNSYNC;
|
||||
} else {
|
||||
status |= STA_UNSYNC;
|
||||
}
|
||||
|
||||
txc.modes = ADJ_STATUS | ADJ_ESTERROR | ADJ_MAXERROR;
|
||||
txc.status = status;
|
||||
txc.esterror = est_error * 1.0e6;
|
||||
txc.maxerror = max_error * 1.0e6;
|
||||
|
||||
return adjtimex(&txc);
|
||||
}
|
||||
|
||||
int
|
||||
TMX_TestStepOffset(void)
|
||||
{
|
||||
struct timex txc;
|
||||
|
||||
/* Zero maxerror and check it's reset to a maximum after ADJ_SETOFFSET.
|
||||
This seems to be the only way how to verify that the kernel really
|
||||
supports the ADJ_SETOFFSET mode as it doesn't return an error on unknown
|
||||
mode. */
|
||||
|
||||
txc.modes = ADJ_MAXERROR;
|
||||
txc.maxerror = 0;
|
||||
if (adjtimex(&txc) < 0 || txc.maxerror != 0)
|
||||
return -1;
|
||||
|
||||
txc.modes = ADJ_SETOFFSET | ADJ_NANO;
|
||||
txc.time.tv_sec = 0;
|
||||
txc.time.tv_usec = 0;
|
||||
if (adjtimex(&txc) < 0 || txc.maxerror < 100000)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
TMX_ApplyStepOffset(double offset)
|
||||
{
|
||||
struct timex txc;
|
||||
|
||||
txc.modes = ADJ_SETOFFSET | ADJ_NANO;
|
||||
if (offset >= 0) {
|
||||
txc.time.tv_sec = offset;
|
||||
} else {
|
||||
txc.time.tv_sec = offset - 1;
|
||||
}
|
||||
txc.time.tv_usec = 1.0e9 * (offset - txc.time.tv_sec);
|
||||
|
||||
return adjtimex(&txc);
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* 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 the adjtimex wrapper
|
||||
*/
|
||||
|
||||
#ifndef GOT_WRAP_ADJTIMEX_H
|
||||
#define GOT_WRAP_ADJTIMEX_H
|
||||
|
||||
int TMX_ResetOffset(void);
|
||||
int TMX_SetFrequency(double *freq, long tick);
|
||||
int TMX_GetFrequency(double *freq, long *tick);
|
||||
int TMX_SetLeap(int leap);
|
||||
int TMX_GetLeap(int *leap);
|
||||
int TMX_SetSync(int sync, double est_error, double max_error);
|
||||
int TMX_TestStepOffset(void);
|
||||
int TMX_ApplyStepOffset(double offset);
|
||||
|
||||
#endif /* GOT_WRAP_ADJTIMEX_H */
|
||||
|
||||
Reference in New Issue
Block a user