mirror of
https://gitlab.com/chrony/chrony.git
synced 2025-12-03 17:45:07 -05:00
Compare commits
180 Commits
2.0
...
2.2-securi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
beb275a769 | ||
|
|
86c21a3a85 | ||
|
|
05236a4f23 | ||
|
|
a78bf9725a | ||
|
|
a030ed4f39 | ||
|
|
9fc15394de | ||
|
|
34ea8770d0 | ||
|
|
a5897840a0 | ||
|
|
59087dd0ff | ||
|
|
1924481077 | ||
|
|
da1f7563e9 | ||
|
|
7496a14d2d | ||
|
|
6e6dead680 | ||
|
|
55dbbab5eb | ||
|
|
d6b6461658 | ||
|
|
85f7a4054d | ||
|
|
01965d147a | ||
|
|
6a84126c28 | ||
|
|
32f8bec92d | ||
|
|
00a6394b48 | ||
|
|
ca5a791d09 | ||
|
|
6a9c756cf0 | ||
|
|
1714d3e8ae | ||
|
|
25b7d47b34 | ||
|
|
9e8b4bae11 | ||
|
|
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 | ||
|
|
1f0e6296c6 | ||
|
|
ab1f01bacd | ||
|
|
b9b896d8e7 | ||
|
|
6be54f366c | ||
|
|
802cdb3230 | ||
|
|
7e27880cb6 | ||
|
|
d3ad85aa43 | ||
|
|
59192fc695 | ||
|
|
9095b80c5b | ||
|
|
ed5b78bf09 | ||
|
|
d6aafa3f64 | ||
|
|
8de04a808d | ||
|
|
2a299233b3 | ||
|
|
64f83c8861 | ||
|
|
1009fe3d9c | ||
|
|
ba341fe81a | ||
|
|
36e8cb6530 | ||
|
|
273da62aec | ||
|
|
41788184a7 | ||
|
|
fb9c2c7dc8 | ||
|
|
43116be122 | ||
|
|
ee038d5de5 | ||
|
|
ea7fae5277 | ||
|
|
70b108ab69 | ||
|
|
08b152d6a2 | ||
|
|
83c6213c67 | ||
|
|
4253075a97 | ||
|
|
0abdc2a350 | ||
|
|
31669f343a | ||
|
|
438b881ab4 | ||
|
|
27863146a3 | ||
|
|
cd4b73612b | ||
|
|
3c217a9e37 | ||
|
|
cde3a003ea | ||
|
|
2c35f56612 | ||
|
|
4295db25d7 | ||
|
|
3c06e57f24 | ||
|
|
e949cf5967 | ||
|
|
4eeaf34295 | ||
|
|
2212a90698 |
31
.gitignore
vendored
31
.gitignore
vendored
@@ -2,20 +2,23 @@
|
||||
.vimrc
|
||||
*.o
|
||||
*.swp
|
||||
RELEASES
|
||||
Makefile
|
||||
chrony.conf.5
|
||||
chrony.info
|
||||
chrony.html
|
||||
chrony.texi
|
||||
chrony.txt
|
||||
chronyc
|
||||
chronyc.1
|
||||
chronyd
|
||||
chronyd.8
|
||||
config.h
|
||||
config.log
|
||||
*.dSYM
|
||||
*.DS_Store
|
||||
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
|
||||
|
||||
26
Makefile.in
26
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)
|
||||
@@ -73,14 +73,16 @@ $(HASH_OBJ) : $(patsubst %.o,%.c,$(HASH_OBJ))
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) @HASH_COMPILE@ -c $<
|
||||
|
||||
distclean : clean
|
||||
-rm -f .DS_Store
|
||||
-rm -f Makefile
|
||||
-rm -f chrony.conf.5 chrony.texi chronyc.1 chronyd.8
|
||||
|
||||
clean :
|
||||
-rm -f *.o *.s chronyc chronyd core *~ chrony.info chrony.html chrony.txt
|
||||
-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
|
||||
@@ -90,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
|
||||
@@ -106,14 +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 chrony.1 $(DESTDIR)$(MANDIR)/man1
|
||||
chmod 644 $(DESTDIR)$(MANDIR)/man1/chrony.1
|
||||
cp chronyc.1 $(DESTDIR)$(MANDIR)/man1
|
||||
chmod 644 $(DESTDIR)$(MANDIR)/man1/chronyc.1
|
||||
cp chronyd.8 $(DESTDIR)$(MANDIR)/man8
|
||||
@@ -152,6 +144,12 @@ chrony.html : chrony.texi
|
||||
chrony.info : chrony.texi
|
||||
makeinfo chrony.texi
|
||||
|
||||
Makefile : Makefile.in configure
|
||||
@echo
|
||||
@echo Makefile needs to be regenerated, run ./configure
|
||||
@echo
|
||||
@exit 1
|
||||
|
||||
.deps:
|
||||
@mkdir .deps
|
||||
|
||||
|
||||
69
NEWS
69
NEWS
@@ -1,3 +1,72 @@
|
||||
New in version 2.2.1
|
||||
====================
|
||||
|
||||
Security fixes
|
||||
--------------
|
||||
* Restrict authentication of NTP server/peer to specified key (CVE-2016-1567)
|
||||
|
||||
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 (experimental)
|
||||
* 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
|
||||
(3 seconds by default)
|
||||
* Add refresh command to get new addresses of NTP sources
|
||||
* Allow wildcard patterns in include directive
|
||||
* Restore time from driftfile with -s option if later than RTC time
|
||||
* Add configure option to set default hwclockfile
|
||||
* 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
|
||||
* Make check interval in waitsync command configurable
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix building on NetBSD, 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
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add support for Mac OS X
|
||||
* Try to replace unreachable and falseticker servers/peers specified
|
||||
by name like pool sources
|
||||
* Add leaponly option to smoothtime directive to allow synchronised
|
||||
leap smear between multiple servers
|
||||
* Use specific reference ID when smoothing served time
|
||||
* Add smoothing command to report time smoothing status
|
||||
* Add smoothtime command to activate or reset time smoothing
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix crash in source selection with preferred sources
|
||||
* Fix resetting of time smoothing
|
||||
* Include packet precision in peer dispersion
|
||||
* Fix crash in chronyc on invalid command syntax
|
||||
|
||||
New in version 2.0
|
||||
==================
|
||||
|
||||
|
||||
19
README
19
README
@@ -27,11 +27,11 @@ operating parameters whilst it is running.
|
||||
What will chrony run on?
|
||||
========================
|
||||
|
||||
The software is known to work on Linux, FreeBSD, NetBSD and Solaris.
|
||||
Closely related systems may work too. Any other system will likely
|
||||
require a porting exercise. You would need to start from one of the
|
||||
existing system-specific drivers and look into the quirks of certain
|
||||
system calls and the kernel on your target system.
|
||||
The software is known to work on Linux, FreeBSD, NetBSD, Mac OS X and
|
||||
Solaris. Closely related systems may work too. Any other system will
|
||||
likely require a porting exercise. You would need to start from one
|
||||
of the existing system-specific drivers and look into the quirks of
|
||||
certain system calls and the kernel on your target system.
|
||||
|
||||
How do I set it up?
|
||||
===================
|
||||
@@ -128,6 +128,9 @@ Stephan I. Boettcher <stephan@nevis1.columbia.edu>
|
||||
Erik Bryer <ebryer@spots.ab.ca>
|
||||
Entries in contrib directory
|
||||
|
||||
Bryan Christianson <bryan@whatroute.net>
|
||||
Support for Mac OS X
|
||||
|
||||
Juliusz Chroboczek <jch@pps.jussieu.fr>
|
||||
Fix install rule in Makefile if chronyd file is in use.
|
||||
|
||||
@@ -142,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
|
||||
@@ -201,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
|
||||
|
||||
|
||||
12
array.c
12
array.c
@@ -44,6 +44,8 @@ ARR_CreateInstance(unsigned int elem_size)
|
||||
{
|
||||
ARR_Instance array;
|
||||
|
||||
assert(elem_size > 0);
|
||||
|
||||
array = MallocNew(struct ARR_Instance_Record);
|
||||
|
||||
array->data = NULL;
|
||||
@@ -64,6 +66,9 @@ ARR_DestroyInstance(ARR_Instance array)
|
||||
static void
|
||||
realloc_array(ARR_Instance array, unsigned int min_size)
|
||||
{
|
||||
size_t data_size;
|
||||
|
||||
assert(min_size <= 2 * min_size);
|
||||
if (array->allocated >= min_size && array->allocated <= 2 * min_size)
|
||||
return;
|
||||
|
||||
@@ -74,7 +79,10 @@ realloc_array(ARR_Instance array, unsigned int min_size)
|
||||
array->allocated = min_size;
|
||||
}
|
||||
|
||||
array->data = Realloc(array->data, array->elem_size * array->allocated);
|
||||
data_size = (size_t)array->elem_size * array->allocated;
|
||||
assert(data_size / array->elem_size == array->allocated);
|
||||
|
||||
array->data = Realloc(array->data, data_size);
|
||||
}
|
||||
|
||||
void *
|
||||
@@ -89,7 +97,7 @@ void *
|
||||
ARR_GetElement(ARR_Instance array, unsigned int index)
|
||||
{
|
||||
assert(index < array->used);
|
||||
return (void *)((char *)array->data + index * array->elem_size);
|
||||
return (void *)((char *)array->data + (size_t)index * array->elem_size);
|
||||
}
|
||||
|
||||
void *
|
||||
|
||||
119
candm.h
119
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 */
|
||||
@@ -89,7 +88,10 @@
|
||||
#define REQ_RESELECT 48
|
||||
#define REQ_RESELECTDISTANCE 49
|
||||
#define REQ_MODIFY_MAKESTEP 50
|
||||
#define N_REQUEST_TYPES 51
|
||||
#define REQ_SMOOTHING 51
|
||||
#define REQ_SMOOTHTIME 52
|
||||
#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) */
|
||||
@@ -116,6 +118,10 @@ typedef struct {
|
||||
pktlength.c, to get the number of bytes that ought to be
|
||||
transmitted for each packet type. */
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Null;
|
||||
|
||||
typedef struct {
|
||||
IPAddr mask;
|
||||
IPAddr address;
|
||||
@@ -215,19 +221,11 @@ typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Manual;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_N_Sources;
|
||||
|
||||
typedef struct {
|
||||
int32_t index;
|
||||
int32_t EOR;
|
||||
} REQ_Source_Data;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Rekey;
|
||||
|
||||
typedef struct {
|
||||
IPAddr ip;
|
||||
int32_t subnet_bits;
|
||||
@@ -264,10 +262,6 @@ typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Del_Source;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_WriteRtc;
|
||||
|
||||
typedef struct {
|
||||
Float dfreq;
|
||||
int32_t EOR;
|
||||
@@ -279,27 +273,11 @@ typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Doffset;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Tracking;
|
||||
|
||||
typedef struct {
|
||||
uint32_t index;
|
||||
int32_t EOR;
|
||||
} REQ_Sourcestats;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_RTCReport;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_TrimRTC;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_CycleLogs;
|
||||
|
||||
/* This is based on the response size rather than the
|
||||
request size */
|
||||
#define MAX_CLIENT_ACCESSES 8
|
||||
@@ -310,32 +288,24 @@ typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_ClientAccessesByIndex;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_ManualList;
|
||||
|
||||
typedef struct {
|
||||
int32_t index;
|
||||
int32_t EOR;
|
||||
} REQ_ManualDelete;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_MakeStep;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Activity;
|
||||
|
||||
typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Reselect;
|
||||
|
||||
typedef struct {
|
||||
Float distance;
|
||||
int32_t EOR;
|
||||
} REQ_ReselectDistance;
|
||||
|
||||
#define REQ_SMOOTHTIME_RESET 0
|
||||
#define REQ_SMOOTHTIME_ACTIVATE 1
|
||||
|
||||
typedef struct {
|
||||
int32_t option;
|
||||
int32_t EOR;
|
||||
} REQ_SmoothTime;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#define PKT_TYPE_CMD_REQUEST 1
|
||||
@@ -365,7 +335,9 @@ 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
|
||||
makestep, smoothing report, smoothtime command
|
||||
|
||||
Authentication was removed later in version 6.
|
||||
*/
|
||||
|
||||
#define PROTO_VERSION_NUMBER 6
|
||||
@@ -394,10 +366,11 @@ 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;
|
||||
REQ_Online online;
|
||||
REQ_Offline offline;
|
||||
REQ_Burst burst;
|
||||
@@ -415,39 +388,24 @@ typedef struct {
|
||||
REQ_Settime settime;
|
||||
REQ_Local local;
|
||||
REQ_Manual manual;
|
||||
REQ_N_Sources n_sources;
|
||||
REQ_Source_Data source_data;
|
||||
REQ_Rekey rekey;
|
||||
REQ_Allow_Deny allow_deny;
|
||||
REQ_Ac_Check ac_check;
|
||||
REQ_NTP_Source ntp_source;
|
||||
REQ_Del_Source del_source;
|
||||
REQ_WriteRtc writertc;
|
||||
REQ_Dfreq dfreq;
|
||||
REQ_Doffset doffset;
|
||||
REQ_Tracking tracking;
|
||||
REQ_Sourcestats sourcestats;
|
||||
REQ_RTCReport rtcreport;
|
||||
REQ_TrimRTC trimrtc;
|
||||
REQ_CycleLogs cyclelogs;
|
||||
REQ_ClientAccessesByIndex client_accesses_by_index;
|
||||
REQ_ManualList manual_list;
|
||||
REQ_ManualDelete manual_delete;
|
||||
REQ_MakeStep make_step;
|
||||
REQ_Activity activity;
|
||||
REQ_Reselect reselect;
|
||||
REQ_ReselectDistance reselect_distance;
|
||||
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;
|
||||
|
||||
/* ================================================== */
|
||||
@@ -472,7 +430,8 @@ typedef struct {
|
||||
#define RPY_CLIENT_ACCESSES_BY_INDEX 10
|
||||
#define RPY_MANUAL_LIST 11
|
||||
#define RPY_ACTIVITY 12
|
||||
#define N_REPLY_TYPES 13
|
||||
#define RPY_SMOOTHING 13
|
||||
#define N_REPLY_TYPES 14
|
||||
|
||||
/* Status codes */
|
||||
#define STT_SUCCESS 0
|
||||
@@ -627,6 +586,19 @@ typedef struct {
|
||||
int32_t EOR;
|
||||
} RPY_Activity;
|
||||
|
||||
#define RPY_SMT_FLAG_ACTIVE 0x1
|
||||
#define RPY_SMT_FLAG_LEAPONLY 0x2
|
||||
|
||||
typedef struct {
|
||||
uint32_t flags;
|
||||
Float offset;
|
||||
Float freq_ppm;
|
||||
Float wander_ppm;
|
||||
Float last_update_ago;
|
||||
Float remaining_time;
|
||||
int32_t EOR;
|
||||
} RPY_Smoothing;
|
||||
|
||||
typedef struct {
|
||||
uint8_t version;
|
||||
uint8_t pkt_type;
|
||||
@@ -639,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;
|
||||
@@ -653,12 +625,9 @@ typedef struct {
|
||||
RPY_ClientAccessesByIndex client_accesses_by_index;
|
||||
RPY_ManualList manual_list;
|
||||
RPY_Activity activity;
|
||||
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;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
72
chrony.1
72
chrony.1
@@ -1,72 +0,0 @@
|
||||
.TH CHRONY 1 "@MAN_DATE@" "chrony @VERSION@" "User's Manual"
|
||||
.SH NAME
|
||||
chrony \- programs for keeping computer clocks accurate
|
||||
|
||||
.SH SYNOPSIS
|
||||
\fBchronyc\fR [\fIOPTIONS\fR]
|
||||
|
||||
\fBchronyd\fR [\fIOPTIONS\fR]
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBchrony\fR is a pair of programs for keeping computer clocks accurate.
|
||||
\fIchronyd\fR is a background (daemon) program and \fIchronyc\fR is a
|
||||
command-line interface to it. Time reference sources for chronyd can be
|
||||
NTP servers, human (via keyboard and \fIchronyc\fR), or the computer's
|
||||
real-time clock at boot time (Linux only). chronyd can determine the rate at
|
||||
which the computer gains or loses time and compensate for it while no external
|
||||
reference is present. Its use of NTP servers can be switched on and off
|
||||
(through \fIchronyc\fR) to support computers with dial-up/intermittent access
|
||||
to the Internet, and it can also act as an NTP server.
|
||||
|
||||
.SH USAGE
|
||||
\fIchronyc\fR is a command-line interface program which can be used to
|
||||
monitor \fIchronyd\fR's performance and to change various operating
|
||||
parameters whilst it is running.
|
||||
|
||||
\fIchronyd\fR's main function is to obtain measurements of the true (UTC)
|
||||
time from one of several sources, and correct the system clock
|
||||
accordingly. It also works out the rate at which the system clock
|
||||
gains or loses time and uses this information to keep it accurate
|
||||
between measurements from the reference.
|
||||
|
||||
The reference time can be derived from either Network Time Protocol
|
||||
(NTP) servers, reference clocks, or wristwatch-and-keyboard (via \fIchronyc\fR).
|
||||
The main source of information about the Network Time Protocol is
|
||||
\fIhttp://www.ntp.org\fR.
|
||||
|
||||
It is designed so that it can work on computers which only have
|
||||
intermittent access to reference sources, for example computers which
|
||||
use a dial-up account to access the Internet or laptops. Of course, it
|
||||
will work well on computers with permanent connections too.
|
||||
|
||||
In addition, on Linux it can monitor the system's real time clock
|
||||
performance, so the system can maintain accurate time even across
|
||||
reboots.
|
||||
|
||||
Typical accuracies available between 2 machines are
|
||||
|
||||
On an ethernet LAN : 100-200 microseconds, often much better
|
||||
On a V32bis dial-up modem connection : 10's of milliseconds (from one
|
||||
session to the next)
|
||||
|
||||
With a good reference clock the accuracy can reach one microsecond.
|
||||
|
||||
\fIchronyd\fR can also operate as an NTPv4 (RFC 5905) server, peer and
|
||||
broadcast server.
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.BR chronyc(1),
|
||||
.BR chrony.conf(5),
|
||||
.BR chronyd(8)
|
||||
|
||||
.I http://chrony.tuxfamily.org/
|
||||
|
||||
.SH AUTHOR
|
||||
Richard Curnow <rc@rc0.org.uk>
|
||||
|
||||
This man-page was written by Jan Schaumann <jschauma@netmeister.org> as part
|
||||
of "The Missing Man Pages Project". Please see
|
||||
\fIhttp://www.netmeister.org/misc/m2p2/index.html\fR for details.
|
||||
|
||||
The complete chrony documentation is supplied in texinfo format.
|
||||
|
||||
@@ -34,25 +34,23 @@ useful configuration file would look something like
|
||||
server bar.example.net iburst
|
||||
server baz.example.net iburst
|
||||
driftfile @CHRONYVARDIR@/drift
|
||||
makestep 10 3
|
||||
makestep 1.0 3
|
||||
rtcsync
|
||||
.EE
|
||||
|
||||
When using a pool of NTP servers (one name is used for multiple servers which
|
||||
may change over time), it's better to specify them with the `pool' directive
|
||||
instead of multiple `server' directives in order to allow \fIchronyd\fR to
|
||||
replace unreachable or bad servers automatically. The configuration file could
|
||||
in this case look like
|
||||
instead of multiple `server' directives. The configuration file could in this
|
||||
case look like
|
||||
|
||||
.EX
|
||||
pool pool.ntp.org iburst
|
||||
driftfile @CHRONYVARDIR@/drift
|
||||
makestep 10 3
|
||||
makestep 1.0 3
|
||||
rtcsync
|
||||
.EE
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.BR chrony(1),
|
||||
.BR chronyc(1),
|
||||
.BR chronyd(8)
|
||||
|
||||
|
||||
1190
chrony.texi.in
1190
chrony.texi.in
File diff suppressed because it is too large
Load Diff
17
chronyc.1.in
17
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
|
||||
@@ -60,8 +60,7 @@ interactively.
|
||||
To report bugs, please visit \fIhttp://chrony.tuxfamily.org\fR
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.BR chronyd(8),
|
||||
.BR chrony(1)
|
||||
.BR chronyd(8)
|
||||
|
||||
.I http://chrony.tuxfamily.org/
|
||||
|
||||
|
||||
47
chronyd.8.in
47
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
|
||||
@@ -79,13 +80,9 @@ option is useful when restarting \fBchronyd\fR and can be used in conjunction
|
||||
with the \fB-r\fR option.
|
||||
.TP
|
||||
.B \-s
|
||||
This option will set the system clock from the computer's real-time
|
||||
clock. This is analogous to supplying the \fI-s\fR flag to the
|
||||
\fI/sbin/hwclock\fR program during the Linux boot sequence.
|
||||
|
||||
Support for real-time clocks is limited at present - the criteria
|
||||
are described in the section on the \fIrtcfile\fR directive in the
|
||||
documentation supplied with the distribution.
|
||||
This option will set the system clock from the computer's real-time clock or
|
||||
to the last modification time of the file specified by the \fIdriftfile\fR
|
||||
directive. Real-time clocks are supported only on Linux.
|
||||
|
||||
If used in conjunction with the \fB-r\fR flag, \fBchronyd\fR will attempt
|
||||
to preserve the old samples after setting the system clock from
|
||||
@@ -96,16 +93,23 @@ not in use. For this to work well, it relies on \fBchronyd\fR having
|
||||
been able to determine accurate statistics for the difference
|
||||
between the RTC and system clock last time the computer was on.
|
||||
|
||||
If \fBchronyd\fR doesn't support the RTC on your computer or there is no RTC
|
||||
installed, the system clock will be set with this option forward to the time of
|
||||
the last modification of the drift file (specified by the \fIdriftfile\fR
|
||||
directive) to restore the system time at which \fBchronyd\fR was previously
|
||||
stopped.
|
||||
If the last modification time of the drift file is later than the current time
|
||||
and the RTC time, the system time will be set to it to restore the time when
|
||||
\fBchronyd\fR was previously stopped. This is useful on computers that have no
|
||||
RTC or the RTC is broken (e.g. it has no battery).
|
||||
.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
|
||||
@@ -134,7 +138,6 @@ To report bugs, please visit \fIhttp://chrony.tuxfamily.org/\fR
|
||||
\fBchronyd\fR is documented in detail in the documentation supplied with the
|
||||
distribution (\fIchrony.txt\fR and \fIchrony.texi\fR).
|
||||
|
||||
.BR chrony(1),
|
||||
.BR chronyc(1),
|
||||
.BR chrony.conf(5),
|
||||
.BR hwclock(8),
|
||||
|
||||
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;
|
||||
|
||||
|
||||
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);
|
||||
|
||||
|
||||
145
conf.c
145
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;
|
||||
@@ -126,7 +124,7 @@ static int enable_manual=0;
|
||||
static int rtc_on_utc = 0;
|
||||
|
||||
/* Filename used to read the hwclock(8) LOCAL/UTC setting */
|
||||
static char *hwclock_file = NULL;
|
||||
static char *hwclock_file;
|
||||
|
||||
/* Flag set if the RTC should be automatically synchronised by kernel */
|
||||
static int rtc_sync = 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;
|
||||
@@ -189,6 +190,7 @@ static char *pidfile;
|
||||
/* Smoothing constants */
|
||||
static double smooth_max_freq = 0.0; /* in ppm */
|
||||
static double smooth_max_wander = 0.0; /* in ppm/s */
|
||||
static int smooth_leap_only = 0;
|
||||
|
||||
/* Temperature sensor, update interval and compensation coefficients */
|
||||
static char *tempcomp_sensor_file = NULL;
|
||||
@@ -319,8 +321,10 @@ 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");
|
||||
hwclock_file = Strdup(DEFAULT_HWCLOCK_FILE);
|
||||
user = Strdup(DEFAULT_USER);
|
||||
}
|
||||
|
||||
@@ -348,6 +352,7 @@ CNF_Finalise(void)
|
||||
Free(keys_file);
|
||||
Free(leapsec_tz);
|
||||
Free(logdir);
|
||||
Free(bind_cmd_path);
|
||||
Free(pidfile);
|
||||
Free(rtc_device);
|
||||
Free(rtc_file);
|
||||
@@ -369,10 +374,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);
|
||||
}
|
||||
@@ -425,8 +433,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")) {
|
||||
@@ -439,8 +445,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")) {
|
||||
@@ -453,10 +457,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")) {
|
||||
@@ -479,6 +479,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")) {
|
||||
@@ -525,6 +527,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");
|
||||
}
|
||||
@@ -556,19 +563,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)
|
||||
{
|
||||
@@ -1112,7 +1106,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)
|
||||
@@ -1174,11 +1175,23 @@ parse_broadcast(char *line)
|
||||
static void
|
||||
parse_smoothtime(char *line)
|
||||
{
|
||||
check_number_of_args(line, 2);
|
||||
if (get_number_of_args(line) != 3)
|
||||
check_number_of_args(line, 2);
|
||||
|
||||
if (sscanf(line, "%lf %lf", &smooth_max_freq, &smooth_max_wander) != 2) {
|
||||
smooth_max_freq = 0.0;
|
||||
command_parse_error();
|
||||
}
|
||||
|
||||
line = CPS_SplitWord(CPS_SplitWord(line));
|
||||
smooth_leap_only = 0;
|
||||
|
||||
if (*line) {
|
||||
if (!strcasecmp(line, "leaponly"))
|
||||
smooth_leap_only = 1;
|
||||
else
|
||||
command_parse_error();
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1227,8 +1240,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);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1436,22 +1488,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)
|
||||
{
|
||||
@@ -1492,6 +1528,14 @@ CNF_GetMaxSlewRate(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
double
|
||||
CNF_GetMaxDistance(void)
|
||||
{
|
||||
return max_distance;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
double
|
||||
CNF_GetReselectDistance(void)
|
||||
{
|
||||
@@ -1684,6 +1728,14 @@ CNF_GetBindAcquisitionAddress(int family, IPAddr *addr)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
char *
|
||||
CNF_GetBindCommandPath(void)
|
||||
{
|
||||
return bind_cmd_path;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
CNF_GetBindCommandAddress(int family, IPAddr *addr)
|
||||
{
|
||||
@@ -1738,10 +1790,11 @@ CNF_GetLockMemory(void)
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
CNF_GetSmooth(double *max_freq, double *max_wander)
|
||||
CNF_GetSmooth(double *max_freq, double *max_wander, int *leap_only)
|
||||
{
|
||||
*max_freq = smooth_max_freq;
|
||||
*max_wander = smooth_max_wander;
|
||||
*leap_only = smooth_leap_only;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
8
conf.h
8
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);
|
||||
@@ -96,7 +98,7 @@ extern void CNF_SetupAccessRestrictions(void);
|
||||
extern int CNF_GetSchedPriority(void);
|
||||
extern int CNF_GetLockMemory(void);
|
||||
|
||||
extern void CNF_GetSmooth(double *max_freq, double *max_wander);
|
||||
extern void CNF_GetSmooth(double *max_freq, double *max_wander, int *leap_only);
|
||||
extern void CNF_GetTempComp(char **file, double *interval, char **point_file, double *T0, double *k0, double *k1, double *k2);
|
||||
|
||||
extern char *CNF_GetUser(void);
|
||||
|
||||
232
configure
vendored
232
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,12 +93,16 @@ 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
|
||||
--enable-scfilter Enable 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
|
||||
since 1970-01-01 [50*365 days ago]
|
||||
--with-user=USER Specify default chronyd user [root]
|
||||
--with-hwclockfile=PATH Specify default path to hwclock(8) adjtime file
|
||||
--with-sendmail=PATH Path to sendmail binary [/usr/lib/sendmail]
|
||||
--enable-debug Enable debugging support
|
||||
|
||||
@@ -131,6 +115,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 +159,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 +198,10 @@ try_tomcrypt=1
|
||||
feat_rtc=1
|
||||
try_rtc=0
|
||||
feat_droproot=1
|
||||
try_libcap=0
|
||||
try_libcap=-1
|
||||
try_clockctl=0
|
||||
feat_scfilter=0
|
||||
try_seccomp=-1
|
||||
readline_lib=""
|
||||
readline_inc=""
|
||||
ncurses_lib=""
|
||||
@@ -227,6 +215,7 @@ feat_asyncdns=1
|
||||
feat_forcednsretry=1
|
||||
ntp_era_split=""
|
||||
default_user="root"
|
||||
default_hwclockfile=""
|
||||
mail_program="/usr/lib/sendmail"
|
||||
|
||||
for option
|
||||
@@ -283,6 +272,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 +299,21 @@ do
|
||||
--disable-pps)
|
||||
feat_pps=0
|
||||
;;
|
||||
--disable-linuxcaps)
|
||||
--disable-privdrop)
|
||||
feat_droproot=0
|
||||
;;
|
||||
--without-libcap|--disable-linuxcaps)
|
||||
try_libcap=0
|
||||
;;
|
||||
--enable-scfilter)
|
||||
feat_scfilter=1
|
||||
;;
|
||||
--disable-scfilter)
|
||||
feat_scfilter=0
|
||||
;;
|
||||
--without-seccomp)
|
||||
try_seccomp=0
|
||||
;;
|
||||
--disable-asyncdns)
|
||||
feat_asyncdns=0
|
||||
;;
|
||||
@@ -322,6 +326,9 @@ do
|
||||
--with-user=* )
|
||||
default_user=`echo $option | sed -e 's/^.*=//;'`
|
||||
;;
|
||||
--with-hwclockfile=* )
|
||||
default_hwclockfile=`echo $option | sed -e 's/^.*=//;'`
|
||||
;;
|
||||
--with-sendmail=* )
|
||||
mail_program=`echo $option | sed -e 's/^.*=//;'`
|
||||
;;
|
||||
@@ -356,71 +363,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"
|
||||
;;
|
||||
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"
|
||||
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)
|
||||
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
|
||||
@@ -453,6 +439,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];'
|
||||
@@ -465,7 +480,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))
|
||||
@@ -494,7 +509,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
|
||||
@@ -507,21 +522,28 @@ if test_code '<inttypes.h>' 'inttypes.h' '' '' ''; then
|
||||
add_def HAVE_INTTYPES_H
|
||||
fi
|
||||
|
||||
if test_code 'struct in_pktinfo' 'sys/socket.h netinet/in.h' '' '' '
|
||||
struct in_pktinfo ipi;
|
||||
return sizeof (ipi.ipi_spec_dst.s_addr) + IP_PKTINFO;'
|
||||
then
|
||||
add_def HAVE_IN_PKTINFO
|
||||
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;
|
||||
return !inet_ntop(AF_INET6, &n.sin6_addr.s6_addr, p, sizeof(p));'
|
||||
then
|
||||
add_def FEAT_IPV6
|
||||
if test_code 'in6_pktinfo' 'sys/socket.h netinet/in.h' '' '' '
|
||||
return sizeof(struct in6_pktinfo);'
|
||||
if test_code 'struct in6_pktinfo' 'sys/socket.h netinet/in.h' '' '' '
|
||||
return sizeof (struct in6_pktinfo) + IPV6_PKTINFO;'
|
||||
then
|
||||
add_def HAVE_IN6_PKTINFO
|
||||
else
|
||||
if test_code 'in6_pktinfo with _GNU_SOURCE' 'sys/socket.h netinet/in.h' \
|
||||
'-D_GNU_SOURCE' '' 'return sizeof(struct in6_pktinfo);'
|
||||
if test_code 'struct in6_pktinfo with _GNU_SOURCE' 'sys/socket.h netinet/in.h' \
|
||||
'-D_GNU_SOURCE' '' 'return sizeof (struct in6_pktinfo) + IPV6_PKTINFO;'
|
||||
then
|
||||
add_def _GNU_SOURCE
|
||||
add_def HAVE_IN6_PKTINFO
|
||||
@@ -529,7 +551,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
|
||||
@@ -579,6 +601,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);'
|
||||
@@ -752,28 +788,37 @@ 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
|
||||
fi
|
||||
|
||||
add_def DEFAULT_CONF_FILE "\"$SYSCONFDIR/chrony.conf\""
|
||||
add_def DEFAULT_HWCLOCK_FILE "\"$default_hwclockfile\""
|
||||
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"
|
||||
|
||||
if [ -f version.txt ]; then
|
||||
add_def CHRONY_VERSION "\"`cat version.txt`\""
|
||||
CHRONY_VERSION="`cat version.txt`"
|
||||
else
|
||||
add_def CHRONY_VERSION "\"DEVELOPMENT\""
|
||||
CHRONY_VERSION="DEVELOPMENT"
|
||||
fi
|
||||
|
||||
add_def CHRONY_VERSION "\"${CHRONY_VERSION}\""
|
||||
|
||||
for f in Makefile chrony.conf.5 chrony.texi chronyc.1 chronyd.8
|
||||
do
|
||||
echo Creating $f
|
||||
@@ -795,8 +840,11 @@ do
|
||||
s%@MANDIR@%${MANDIR}%;\
|
||||
s%@INFODIR@%${INFODIR}%;\
|
||||
s%@LOCALSTATEDIR@%${LOCALSTATEDIR}%;\
|
||||
s%@CHRONYSOCKDIR@%${CHRONYSOCKDIR}%;\
|
||||
s%@CHRONYVARDIR@%${CHRONYVARDIR}%;\
|
||||
s%@DEFAULT_USER@%${default_user}%;"\
|
||||
s%@DEFAULT_HWCLOCK_FILE@%${default_hwclockfile}%;\
|
||||
s%@DEFAULT_USER@%${default_user}%;\
|
||||
s%@CHRONY_VERSION@%${CHRONY_VERSION}%;" \
|
||||
< ${f}.in > $f
|
||||
done
|
||||
|
||||
|
||||
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>
|
||||
379
doc/faq.adoc
Normal file
379
doc/faq.adoc
Normal file
@@ -0,0 +1,379 @@
|
||||
:toc:
|
||||
:numbered:
|
||||
|
||||
Frequently Asked Questions
|
||||
==========================
|
||||
|
||||
== +chrony+ compared to other programs
|
||||
|
||||
=== How does +chrony+ compare to +ntpd+?
|
||||
|
||||
+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] section in the manual.
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
* slew the time to correct it when going online and NTP servers
|
||||
become visible
|
||||
* determine the rate at which the computer gains or loses time and
|
||||
use this information to keep it reasonably correct between connects
|
||||
to the 'net. This has to be done using a method that does not care
|
||||
about the intermittent availability of the references or the fact
|
||||
the computer is turned off between groups of measurements.
|
||||
* maintain the time across reboots, by working out the error and
|
||||
drift rate of the computer's real-time clock and using this
|
||||
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
|
||||
on the NTP master node (which was set from watch). Some automated support was
|
||||
added to +chrony+ to deal with this.
|
||||
|
||||
== Configuration issues
|
||||
|
||||
=== What is the minimum recommended configuration for an NTP client?
|
||||
|
||||
First, the client needs to know which NTP servers it should ask for the current
|
||||
time. They are specified by the +server+ or +pool+ directive. The +pool+
|
||||
directive can be used for names that resolve to multiple addresses. For good
|
||||
reliability the client should have at least three servers. The +iburst+ option
|
||||
speeds up the initial synchronisation.
|
||||
|
||||
To stabilize the initial synchronisation on the next start, the estimated drift
|
||||
of the system clock is saved by adding the +driftfile+ directive.
|
||||
|
||||
If the system clock can be far from the true time after boot for any reason,
|
||||
+chronyd+ should be allowed to correct it quickly by stepping instead of
|
||||
slewing, which would take a very long time. The +makestep+ directive does
|
||||
that.
|
||||
|
||||
In order to keep the real-time clock (RTC) close to the true time on Linux, so
|
||||
the system time is reasonably close to the true time when it's initialized on
|
||||
the next boot from the RTC, the +rtcsync+ directive enables a kernel mode in
|
||||
which the system time is copied to the RTC every 11 minutes.
|
||||
|
||||
If you want to use public NTP servers from the
|
||||
http://www.pool.ntp.org/[pool.ntp.org] project, the minimal 'chrony.conf' file
|
||||
could be:
|
||||
|
||||
----
|
||||
pool pool.ntp.org iburst
|
||||
driftfile /var/lib/chrony/drift
|
||||
makestep 1 3
|
||||
rtcsync
|
||||
----
|
||||
|
||||
=== How do I make an NTP server from an NTP client?
|
||||
|
||||
You need to add an +allow+ directive to the 'chrony.conf' file in order to open
|
||||
the NTP port and allow +chronyd+ to reply to client requests. +allow+ with no
|
||||
specified subnet allows all IPv4 and IPv6 addresses.
|
||||
|
||||
=== I have several computers on a LAN. Should be all clients of an external server?
|
||||
|
||||
The best configuration is usually to make one computer the master, with
|
||||
the others as clients of it. Add a +local+ directive to the master's
|
||||
'chrony.conf' file. This configuration will be better because
|
||||
|
||||
* the load on the external connection is less
|
||||
* the load on the external NTP server(s) is less
|
||||
* if your external connection goes down, the computers on the LAN
|
||||
will maintain a common time with each other.
|
||||
|
||||
=== Must I specify servers by IP address if DNS is not available on chronyd start?
|
||||
|
||||
No. Starting from version 1.25, +chronyd+ will keep trying to resolve
|
||||
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?
|
||||
|
||||
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
|
||||
and prevent NTP requests from reaching +chronyd+. Starting from version 2.0,
|
||||
the NTP server port is open only when client access is allowed by the +allow+
|
||||
directive or command, an NTP peer is configured, or the +broadcast+ directive
|
||||
is used.
|
||||
|
||||
If you don't need to use +chronyc+ remotely, you can add the following
|
||||
directives to the configuration file to bind the command sockets to the
|
||||
loopback interface. This is done by default since version 2.0.
|
||||
|
||||
----
|
||||
bindcmdaddress 127.0.0.1
|
||||
bindcmdaddress ::1
|
||||
----
|
||||
|
||||
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), 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?
|
||||
|
||||
Select NTP servers that are well synchronised, stable and close to your
|
||||
network. It's better to use more than one server, three or four is usually
|
||||
recommended as the minimum, so +chronyd+ can detect falsetickers and combine
|
||||
measurements from multiple sources.
|
||||
|
||||
There are also useful options which can be set in the +server+ directive, they
|
||||
are +minpoll+, +maxpoll+, +polltarget+, +maxdelay+, +maxdelayratio+ and
|
||||
+maxdelaydevratio+.
|
||||
|
||||
The first three options set the minimum and maximum allowed polling interval,
|
||||
and how should be the actual interval adjusted in the specified range. Their
|
||||
default values are 6 (64 seconds) for +minpoll+, 10 (1024 seconds) for
|
||||
+maxpoll+ and 6 (samples) for +polltarget+. The default values should be used
|
||||
for general servers on the internet. With your own NTP servers or if have
|
||||
permission to poll some servers more frequently, setting these options for
|
||||
shorter polling intervals may significantly improve the accuracy of the system
|
||||
clock.
|
||||
|
||||
The optimal polling interval depends on many factors, including the ratio
|
||||
between the wander of the clock and the network jitter (sometimes expressed in
|
||||
NTP documents as the Allan intercept), the temperature sensitivity of the
|
||||
crystal oscillator and the maximum rate of change of the temperature.
|
||||
|
||||
An example of the directive for an NTP server on the internet that you are
|
||||
allowed to poll frequently could be
|
||||
|
||||
----
|
||||
server foo.example.net minpoll 4 maxpoll 6 polltarget 16
|
||||
----
|
||||
|
||||
An example using very short polling intervals for a server located in the same
|
||||
LAN could be
|
||||
|
||||
----
|
||||
server ntp.local minpoll 2 maxpoll 4 polltarget 30
|
||||
----
|
||||
|
||||
The maxdelay options are useful to ignore measurements with larger delay (e.g.
|
||||
due to congestion in the network) and improve the stability of the
|
||||
synchronisation. The +maxdelaydevratio+ option could be added to the example
|
||||
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
|
||||
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
|
||||
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 +chronyd+ has
|
||||
been running for a short period. See if any measurements appear.
|
||||
|
||||
=== Are NTP servers specified with the +offline+ option?
|
||||
|
||||
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+
|
||||
|
||||
When accessing +chronyd+ remotely, make sure that the 'chrony.conf' file (on
|
||||
the computer where +chronyd+ is running) has a 'cmdallow' entry for the
|
||||
computer you are running +chronyc+ on and an appropriate 'bindcmdaddress'
|
||||
directive. This isn't necessary for localhost.
|
||||
|
||||
Perhaps +chronyd+ is not running. Try using the +ps+ command (e.g. on Linux,
|
||||
+ps -auxw+) to see if it's running. Or try +netstat -a+ and see if the ports
|
||||
123/udp and 323/udp are listening. If +chronyd+ is not running, you may have a
|
||||
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'
|
||||
(+chronyc+ side).
|
||||
|
||||
== Real-time clock issues
|
||||
|
||||
=== What is the real-time clock (RTC)?
|
||||
|
||||
This is the clock which keeps the time even when your computer is turned off.
|
||||
It is used to initialize the system clock on boot. It normally doesn't drift
|
||||
more than few seconds per day.
|
||||
|
||||
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 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.
|
||||
|
||||
=== 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
|
||||
|
||||
For the real time clock support to work, you need the following three
|
||||
things
|
||||
|
||||
* a kernel that is supported (e.g. 2.2 onwards)
|
||||
* enhanced RTC support compiled into the kernel
|
||||
* an +rtcfile+ directive in your 'chrony.conf' file
|
||||
|
||||
== NTP-specific issues
|
||||
|
||||
=== Can +chronyd+ be driven from broadcast NTP servers?
|
||||
|
||||
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?
|
||||
|
||||
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 +chronyd+ keep the system clock a fixed offset away from real time?
|
||||
|
||||
This is not possible as the program currently stands.
|
||||
|
||||
=== What happens if the network connection is dropped without using +chronyc+'s +offline+ command first?
|
||||
|
||||
+chronyd+ will keep trying to access the server(s) that it thinks are online.
|
||||
When the network is connected again, it will take some time (on average half of
|
||||
the current polling interval) before new measurements are made and the clock is
|
||||
corrected. If the servers were set to offline and the +online+ command was
|
||||
issued when the network was connected, +chronyd+ would make new measurements
|
||||
immediately.
|
||||
|
||||
The +auto_offline+ option to the +server+ entry in the 'chrony.conf' file may
|
||||
be useful to switch the servers to the offline state automatically.
|
||||
|
||||
== Linux-specific issues
|
||||
|
||||
=== I get +Could not open /dev/rtc, Device or resource busy+ in my syslog file
|
||||
|
||||
Some other program running on the system may be using the device.
|
||||
|
||||
== 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.
|
||||
@@ -9,7 +9,7 @@ Wants=time-sync.target
|
||||
Type=oneshot
|
||||
# Wait up to ~10 minutes for chronyd to synchronize and the remaining
|
||||
# clock correction to be less than 0.1 seconds
|
||||
ExecStart=/usr/bin/chronyc waitsync 60 0.1
|
||||
ExecStart=/usr/bin/chronyc waitsync 600 0.1 0.0 1
|
||||
RemainAfterExit=yes
|
||||
StandardOutput=null
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ pool pool.ntp.org iburst
|
||||
driftfile /var/lib/chrony/drift
|
||||
|
||||
# In first three updates step the system clock instead of slew
|
||||
# if the adjustment is larger than 10 seconds.
|
||||
makestep 10 3
|
||||
# if the adjustment is larger than 1 second.
|
||||
makestep 1.0 3
|
||||
|
||||
# Enable kernel synchronization of the real-time clock (RTC).
|
||||
rtcsync
|
||||
|
||||
@@ -6,8 +6,8 @@ pool pool.ntp.org iburst
|
||||
driftfile /var/lib/chrony/drift
|
||||
|
||||
# In first three updates step the system clock instead of slew
|
||||
# if the adjustment is larger than 10 seconds.
|
||||
makestep 10 3
|
||||
# if the adjustment is larger than 1 second.
|
||||
makestep 1.0 3
|
||||
|
||||
# Enable kernel synchronization of the real-time clock (RTC).
|
||||
rtcsync
|
||||
@@ -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:
|
||||
@@ -142,15 +128,15 @@ generatecommandkey
|
||||
#######################################################################
|
||||
### INITIAL CLOCK CORRECTION
|
||||
# This option is useful to quickly correct the clock on start if it's
|
||||
# off by a large amount. The value '10' means that if the error is less
|
||||
# than 10 seconds, it will be gradually removed by speeding up or
|
||||
# slowing down your computer's clock until it is correct. If the error
|
||||
# is above 10 seconds, an immediate time jump will be applied to correct
|
||||
# it. The value '1' means the step is allowed only on the first update
|
||||
# of the clock. Some software can get upset if the system clock jumps
|
||||
# off by a large amount. The value '1.0' means that if the error is less
|
||||
# than 1 second, it will be gradually removed by speeding up or slowing
|
||||
# down your computer's clock until it is correct. If the error is above
|
||||
# 1 second, an immediate time jump will be applied to correct it. The
|
||||
# value '3' means the step is allowed only in the first three updates of
|
||||
# the clock. Some software can get upset if the system clock jumps
|
||||
# (especially backwards), so be careful!
|
||||
|
||||
! makestep 10 1
|
||||
! makestep 1.0 3
|
||||
|
||||
#######################################################################
|
||||
### LOGGING
|
||||
@@ -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
|
||||
|
||||
@@ -45,7 +45,6 @@ cp chrony.info* $RPM_BUILD_ROOT%{_infodir}
|
||||
%{_sbindir}/chronyd
|
||||
%{_bindir}/chronyc
|
||||
%{_infodir}/chrony.info*
|
||||
%{_mandir}/man1/chrony.1.gz
|
||||
%{_mandir}/man1/chronyc.1.gz
|
||||
%{_mandir}/man5/chrony.conf.5.gz
|
||||
%{_mandir}/man8/chronyd.8.gz
|
||||
|
||||
@@ -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);
|
||||
|
||||
3
local.c
3
local.c
@@ -564,6 +564,9 @@ LCL_NotifyLeap(int leap)
|
||||
LCL_ReadRawTime(&raw);
|
||||
LCL_CookTime(&raw, &cooked, NULL);
|
||||
|
||||
/* Smooth the leap second out */
|
||||
SMT_Leap(&cooked, leap);
|
||||
|
||||
/* Dispatch to all handlers as if the clock was stepped */
|
||||
invoke_parameter_change_handlers(&raw, &cooked, 0.0, -leap, LCL_ChangeStep);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
27
logging.h
27
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(severity, 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,
|
||||
@@ -94,9 +105,11 @@ typedef enum {
|
||||
LOGF_Sys,
|
||||
LOGF_SysGeneric,
|
||||
LOGF_SysLinux,
|
||||
LOGF_SysMacOSX,
|
||||
LOGF_SysNetBSD,
|
||||
LOGF_SysSolaris,
|
||||
LOGF_SysSunOS,
|
||||
LOGF_SysTimex,
|
||||
LOGF_SysWinnt,
|
||||
LOGF_TempComp,
|
||||
LOGF_RtcLinux,
|
||||
@@ -111,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
|
||||
@@ -141,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();
|
||||
|
||||
20
make_release
20
make_release
@@ -39,16 +39,13 @@ echo $version > version.txt
|
||||
|
||||
sed -i -e "s%@@VERSION@@%${version}%" examples/chrony.spec
|
||||
|
||||
for m in chrony.1 chronyc.1.in chrony.conf.5.in chronyd.8.in; do
|
||||
for m in chronyc.1.in chrony.conf.5.in chronyd.8.in; do
|
||||
sed -e "s%@VERSION@%${version}%;s%@MAN_DATE@%${mandate}%" \
|
||||
< $m > ${m}_
|
||||
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 | \
|
||||
@@ -59,16 +56,11 @@ if [ $(wc -l < INSTALL) -gt 100 -o $(wc -l < INSTALL) -lt 85 ]; then
|
||||
exit 3
|
||||
fi
|
||||
|
||||
awk '/^[1-9] Frequently asked questions$/{p=1}
|
||||
/^Appendix A GNU General Public License$/{exit}; p' chrony.txt | \
|
||||
tail -n +4 | sed 's/^[1-9]\.\([1-9]\)/\1/' | sed 's/^----/--/' | \
|
||||
sed 's/^====/==/' > FAQ
|
||||
|
||||
if [ $(wc -l < FAQ) -gt 400 -o $(wc -l < FAQ) -lt 200 ]; then
|
||||
echo "FAQ generated incorrectly?"
|
||||
exit 3
|
||||
fi
|
||||
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
|
||||
|
||||
5
ntp.h
5
ntp.h
@@ -109,4 +109,9 @@ typedef struct {
|
||||
#define NTP_LVM(leap, version, mode) \
|
||||
((((leap) << 6) & 0xc0) | (((version) << 3) & 0x38) | ((mode) & 0x07))
|
||||
|
||||
/* Special NTP reference IDs */
|
||||
#define NTP_REFID_UNSYNC 0x0UL
|
||||
#define NTP_REFID_LOCAL 0x7F7F0101UL /* 127.127.1.1 */
|
||||
#define NTP_REFID_SMOOTH 0x7F7F01FFUL /* 127.127.1.255 */
|
||||
|
||||
#endif /* GOT_NTP_H */
|
||||
|
||||
38
ntp_core.c
38
ntp_core.c
@@ -316,7 +316,7 @@ NCR_Initialise(void)
|
||||
do_time_checks();
|
||||
|
||||
logfileid = CNF_GetLogMeasurements() ? LOG_FileOpen("measurements",
|
||||
" Date (UTC) Time IP Address L St 123 567 ABCD LP RP Score Offset Peer del. Peer disp. Root del. Root disp.")
|
||||
" Date (UTC) Time IP Address L St 123 567 ABCD LP RP Score Offset Peer del. Peer disp. Root del. Root disp.")
|
||||
: -1;
|
||||
|
||||
access_auth_table = ADF_CreateTable();
|
||||
@@ -789,8 +789,8 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||
|
||||
/* Get current smoothing offset when sending packet to a client */
|
||||
if (SMT_IsEnabled() && (my_mode == MODE_SERVER || my_mode == MODE_BROADCAST)) {
|
||||
smooth_time = 1;
|
||||
smooth_offset = SMT_GetOffset(&local_transmit);
|
||||
smooth_time = fabs(smooth_offset) > LCL_GetSysPrecisionAsQuantum();
|
||||
|
||||
/* Suppress leap second when smoothing and slew mode are enabled */
|
||||
if (REF_GetLeapMode() == REF_LeapModeSlew &&
|
||||
@@ -801,6 +801,14 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||
smooth_offset = 0.0;
|
||||
}
|
||||
|
||||
if (smooth_time) {
|
||||
our_ref_id = NTP_REFID_SMOOTH;
|
||||
UTI_AddDoubleToTimeval(&our_ref_time, smooth_offset, &our_ref_time);
|
||||
UTI_AddDoubleToTimeval(local_rx, smooth_offset, &local_receive);
|
||||
} else {
|
||||
local_receive = *local_rx;
|
||||
}
|
||||
|
||||
if (are_we_synchronised) {
|
||||
leap = (int) leap_status;
|
||||
} else {
|
||||
@@ -824,17 +832,10 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||
message.root_delay = UTI_DoubleToInt32(our_root_delay);
|
||||
message.root_dispersion = UTI_DoubleToInt32(our_root_dispersion);
|
||||
|
||||
message.reference_id = htonl((NTP_int32) our_ref_id);
|
||||
message.reference_id = htonl(our_ref_id);
|
||||
|
||||
/* Now fill in timestamps */
|
||||
|
||||
if (smooth_time) {
|
||||
UTI_AddDoubleToTimeval(&our_ref_time, smooth_offset, &our_ref_time);
|
||||
UTI_AddDoubleToTimeval(local_rx, smooth_offset, &local_receive);
|
||||
} else {
|
||||
local_receive = *local_rx;
|
||||
}
|
||||
|
||||
UTI_TimevalToInt64(&our_ref_time, &message.reference_ts, 0);
|
||||
|
||||
/* Originate - this comes from the last packet the source sent us */
|
||||
@@ -1098,7 +1099,7 @@ static int
|
||||
receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance inst, NTP_Local_Address *local_addr, int length)
|
||||
{
|
||||
int pkt_leap;
|
||||
uint32_t pkt_refid;
|
||||
uint32_t pkt_refid, pkt_key_id;
|
||||
double pkt_root_delay;
|
||||
double pkt_root_dispersion;
|
||||
|
||||
@@ -1189,11 +1190,13 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
|
||||
function is called only for known sources. */
|
||||
|
||||
/* Test 5 checks for authentication failure. If we expect authenticated info
|
||||
from this peer/server and the packet doesn't have it or the authentication
|
||||
is bad, it's got to fail. If the peer or server sends us an authenticated
|
||||
frame, but we're not bothered about whether he authenticates or not, just
|
||||
ignore the test. */
|
||||
test5 = inst->do_auth ? check_packet_auth(message, length, NULL, NULL) : 1;
|
||||
from this peer/server and the packet doesn't have it, the authentication
|
||||
is bad, or it's authenticated with a different key than expected, it's got
|
||||
to fail. If we don't expect the packet to be authenticated, just ignore
|
||||
the test. */
|
||||
test5 = !inst->do_auth ||
|
||||
(check_packet_auth(message, length, NULL, &pkt_key_id) &&
|
||||
pkt_key_id == inst->auth_key_id);
|
||||
|
||||
/* Test 6 checks for unsynchronised server */
|
||||
test6 = pkt_leap != LEAP_Unsynchronised &&
|
||||
@@ -1230,7 +1233,8 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
|
||||
inst->local_ntp_tx.hi = inst->local_ntp_tx.lo = 0;
|
||||
|
||||
if (valid_packet) {
|
||||
precision = LCL_GetSysPrecisionAsQuantum();
|
||||
precision = LCL_GetSysPrecisionAsQuantum() +
|
||||
UTI_Log2ToDouble(message->precision);
|
||||
|
||||
SRC_GetFrequencyRange(inst->source, &source_freq_lo, &source_freq_hi);
|
||||
|
||||
|
||||
20
ntp_io.c
20
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;
|
||||
}
|
||||
@@ -189,7 +189,7 @@ prepare_socket(int family, int port_number, int client_only)
|
||||
#endif
|
||||
|
||||
if (family == AF_INET) {
|
||||
#ifdef IP_PKTINFO
|
||||
#ifdef HAVE_IN_PKTINFO
|
||||
/* We want the local IP info on server sockets */
|
||||
if (setsockopt(sock_fd, IPPROTO_IP, IP_PKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set packet info socket option");
|
||||
@@ -206,14 +206,16 @@ prepare_socket(int family, int port_number, int client_only)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IN6_PKTINFO
|
||||
#ifdef IPV6_RECVPKTINFO
|
||||
if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set IPv6 packet info socket option");
|
||||
}
|
||||
#elif defined(IPV6_PKTINFO)
|
||||
#else
|
||||
if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_PKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set IPv6 packet info socket option");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
@@ -221,7 +223,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;
|
||||
}
|
||||
@@ -531,7 +533,7 @@ read_from_socket(void *anything)
|
||||
local_addr.sock_fd = sock_fd;
|
||||
|
||||
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
||||
#ifdef IP_PKTINFO
|
||||
#ifdef HAVE_IN_PKTINFO
|
||||
if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
|
||||
struct in_pktinfo ipi;
|
||||
|
||||
@@ -541,7 +543,7 @@ read_from_socket(void *anything)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(IPV6_PKTINFO) && defined(HAVE_IN6_PKTINFO)
|
||||
#ifdef HAVE_IN6_PKTINFO
|
||||
if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
|
||||
struct in6_pktinfo ipi;
|
||||
|
||||
@@ -629,7 +631,7 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr, NTP_Lo
|
||||
msg.msg_flags = 0;
|
||||
cmsglen = 0;
|
||||
|
||||
#ifdef IP_PKTINFO
|
||||
#ifdef HAVE_IN_PKTINFO
|
||||
if (local_addr->ip_addr.family == IPADDR_INET4) {
|
||||
struct cmsghdr *cmsg;
|
||||
struct in_pktinfo *ipi;
|
||||
@@ -647,7 +649,7 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr, NTP_Lo
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(IPV6_PKTINFO) && defined(HAVE_IN6_PKTINFO)
|
||||
#ifdef HAVE_IN6_PKTINFO
|
||||
if (local_addr->ip_addr.family == IPADDR_INET6) {
|
||||
struct cmsghdr *cmsg;
|
||||
struct in6_pktinfo *ipi;
|
||||
|
||||
@@ -49,6 +49,7 @@ typedef struct {
|
||||
NTP_Remote_Address *remote_addr; /* The address of this source, non-NULL
|
||||
means this slot in table is in use */
|
||||
NCR_Instance data; /* Data for the protocol engine for this source */
|
||||
char *name; /* Name of the source, may be NULL */
|
||||
int pool; /* Number of the pool from which was this source
|
||||
added or INVALID_POOL */
|
||||
int tentative; /* Flag indicating there was no valid response
|
||||
@@ -85,6 +86,7 @@ struct UnresolvedSource {
|
||||
#define RESOLVE_INTERVAL_UNIT 7
|
||||
#define MIN_RESOLVE_INTERVAL 2
|
||||
#define MAX_RESOLVE_INTERVAL 9
|
||||
#define MIN_REPLACEMENT_INTERVAL 8
|
||||
|
||||
static struct UnresolvedSource *unresolved_sources = NULL;
|
||||
static int resolving_interval = 0;
|
||||
@@ -92,15 +94,11 @@ static SCH_TimeoutID resolving_id;
|
||||
static struct UnresolvedSource *resolving_source = NULL;
|
||||
static NSR_SourceResolvingEndHandler resolving_end_handler = NULL;
|
||||
|
||||
#define MIN_POOL_RESOLVE_INTERVAL 5
|
||||
#define MAX_POOL_SOURCES 16
|
||||
#define INVALID_POOL (-1)
|
||||
|
||||
/* Pool of sources, the name is expected to resolve to multiple addresses
|
||||
which change over time */
|
||||
/* Pool of sources with the same name */
|
||||
struct SourcePool {
|
||||
char *name;
|
||||
int port;
|
||||
/* Number of sources added from this pool (ignoring tentative sources) */
|
||||
int sources;
|
||||
/* Maximum number of sources */
|
||||
@@ -115,6 +113,7 @@ static ARR_Instance pools;
|
||||
|
||||
static void resolve_sources(void *arg);
|
||||
static void rehash_records(void);
|
||||
static void clean_source_record(SourceRecord *record);
|
||||
|
||||
static void
|
||||
slew_sources(struct timeval *raw,
|
||||
@@ -162,16 +161,12 @@ NSR_Finalise(void)
|
||||
struct UnresolvedSource *us;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARR_GetSize(pools); i++)
|
||||
Free(((struct SourcePool *)ARR_GetElement(pools, i))->name);
|
||||
ARR_DestroyInstance(pools);
|
||||
|
||||
for (i = 0; i < ARR_GetSize(records); i++) {
|
||||
record = get_record(i);
|
||||
if (!record->remote_addr)
|
||||
continue;
|
||||
record->remote_addr = NULL;
|
||||
NCR_DestroyInstance(record->data);
|
||||
if (record->remote_addr)
|
||||
clean_source_record(record);
|
||||
}
|
||||
|
||||
ARR_DestroyInstance(records);
|
||||
@@ -296,7 +291,7 @@ rehash_records(void)
|
||||
|
||||
/* Procedure to add a new source */
|
||||
static NSR_Status
|
||||
add_source(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params, int pool)
|
||||
add_source(NTP_Remote_Address *remote_addr, char *name, NTP_Source_Type type, SourceParameters *params, int pool)
|
||||
{
|
||||
SourceRecord *record;
|
||||
int slot, found;
|
||||
@@ -323,6 +318,7 @@ add_source(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParamete
|
||||
record = get_record(slot);
|
||||
record->data = NCR_GetInstance(remote_addr, type, params);
|
||||
record->remote_addr = NCR_GetRemoteAddress(record->data);
|
||||
record->name = name ? Strdup(name) : NULL;
|
||||
record->pool = pool;
|
||||
record->tentative = pool != INVALID_POOL ? 1 : 0;
|
||||
|
||||
@@ -373,7 +369,7 @@ process_resolved_name(struct UnresolvedSource *us, IPAddr *ip_addrs, int n_addrs
|
||||
int i, added;
|
||||
|
||||
for (i = added = 0; i < n_addrs; i++) {
|
||||
DEBUG_LOG(LOGF_NtpSources, "%s resolved to %s", us->name, UTI_IPToString(&ip_addrs[i]));
|
||||
DEBUG_LOG(LOGF_NtpSources, "(%d) %s", i + 1, UTI_IPToString(&ip_addrs[i]));
|
||||
|
||||
address.ip_addr = ip_addrs[i];
|
||||
address.port = us->port;
|
||||
@@ -382,7 +378,7 @@ process_resolved_name(struct UnresolvedSource *us, IPAddr *ip_addrs, int n_addrs
|
||||
if (replace_source(&us->replace_source, &address) != NSR_AlreadyInUse)
|
||||
break;
|
||||
} else {
|
||||
if (add_source(&address, us->new_source.type, &us->new_source.params,
|
||||
if (add_source(&address, us->name, us->new_source.type, &us->new_source.params,
|
||||
us->new_source.pool) == NSR_Success)
|
||||
added++;
|
||||
|
||||
@@ -403,6 +399,8 @@ name_resolve_handler(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *any
|
||||
|
||||
assert(us == resolving_source);
|
||||
|
||||
DEBUG_LOG(LOGF_NtpSources, "%s resolved to %d addrs", us->name, n_addrs);
|
||||
|
||||
switch (status) {
|
||||
case DNS_TryAgain:
|
||||
break;
|
||||
@@ -495,7 +493,7 @@ append_unresolved_source(struct UnresolvedSource *us)
|
||||
NSR_Status
|
||||
NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params)
|
||||
{
|
||||
return add_source(remote_addr, type, params, INVALID_POOL);
|
||||
return add_source(remote_addr, NULL, type, params, INVALID_POOL);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -505,6 +503,15 @@ NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, Source
|
||||
{
|
||||
struct UnresolvedSource *us;
|
||||
struct SourcePool *sp;
|
||||
NTP_Remote_Address remote_addr;
|
||||
|
||||
/* If the name is an IP address, don't bother with full resolving now
|
||||
or later when trying to replace the source */
|
||||
if (UTI_StringToIP(name, &remote_addr.ip_addr)) {
|
||||
remote_addr.port = port;
|
||||
NSR_AddSource(&remote_addr, type, params);
|
||||
return;
|
||||
}
|
||||
|
||||
us = MallocNew(struct UnresolvedSource);
|
||||
us->name = Strdup(name);
|
||||
@@ -518,8 +525,6 @@ NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, Source
|
||||
us->new_source.max_new_sources = 1;
|
||||
} else {
|
||||
sp = (struct SourcePool *)ARR_GetNewElement(pools);
|
||||
sp->name = Strdup(name);
|
||||
sp->port = port;
|
||||
sp->sources = 0;
|
||||
sp->max_sources = params->max_sources;
|
||||
us->new_source.pool = ARR_GetSize(pools) - 1;
|
||||
@@ -587,6 +592,8 @@ clean_source_record(SourceRecord *record)
|
||||
assert(record->remote_addr);
|
||||
record->remote_addr = NULL;
|
||||
NCR_DestroyInstance(record->data);
|
||||
if (record->name)
|
||||
Free(record->name);
|
||||
|
||||
n_sources--;
|
||||
}
|
||||
@@ -640,15 +647,18 @@ NSR_RemoveAllSources(void)
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
resolve_pool_replacement(struct SourcePool *sp, NTP_Remote_Address *addr)
|
||||
resolve_source_replacement(SourceRecord *record)
|
||||
{
|
||||
struct UnresolvedSource *us;
|
||||
|
||||
DEBUG_LOG(LOGF_NtpSources, "trying to replace %s",
|
||||
UTI_IPToString(&record->remote_addr->ip_addr));
|
||||
|
||||
us = MallocNew(struct UnresolvedSource);
|
||||
us->name = Strdup(sp->name);
|
||||
us->port = sp->port;
|
||||
us->name = Strdup(record->name);
|
||||
us->port = record->remote_addr->port;
|
||||
us->replacement = 1;
|
||||
us->replace_source = *addr;
|
||||
us->replace_source = *record->remote_addr;
|
||||
|
||||
append_unresolved_source(us);
|
||||
NSR_ResolveSources();
|
||||
@@ -662,32 +672,50 @@ NSR_HandleBadSource(IPAddr *address)
|
||||
static struct timeval last_replacement;
|
||||
struct timeval now;
|
||||
NTP_Remote_Address remote_addr;
|
||||
struct SourcePool *pool;
|
||||
int pool_index, slot, found;
|
||||
SourceRecord *record;
|
||||
int slot, found;
|
||||
double diff;
|
||||
|
||||
remote_addr.ip_addr = *address;
|
||||
remote_addr.port = 0;
|
||||
|
||||
/* Only sources from a pool can be replaced */
|
||||
find_slot(&remote_addr, &slot, &found);
|
||||
if (!found || (pool_index = get_record(slot)->pool) == INVALID_POOL)
|
||||
if (!found)
|
||||
return;
|
||||
|
||||
pool = (struct SourcePool *)ARR_GetElement(pools, pool_index);
|
||||
record = get_record(slot);
|
||||
|
||||
/* Don't resolve the pool name too frequently */
|
||||
/* Only sources with a name can be replaced */
|
||||
if (!record->name)
|
||||
return;
|
||||
|
||||
/* Don't resolve names too frequently */
|
||||
SCH_GetLastEventTime(NULL, NULL, &now);
|
||||
UTI_DiffTimevalsToDouble(&diff, &now, &last_replacement);
|
||||
if (fabs(diff) < RESOLVE_INTERVAL_UNIT * (1 << MIN_POOL_RESOLVE_INTERVAL)) {
|
||||
if (fabs(diff) < RESOLVE_INTERVAL_UNIT * (1 << MIN_REPLACEMENT_INTERVAL)) {
|
||||
DEBUG_LOG(LOGF_NtpSources, "replacement postponed");
|
||||
return;
|
||||
}
|
||||
last_replacement = now;
|
||||
|
||||
DEBUG_LOG(LOGF_NtpSources, "pool replacement for %s", UTI_IPToString(address));
|
||||
resolve_source_replacement(record);
|
||||
}
|
||||
|
||||
resolve_pool_replacement(pool, &remote_addr);
|
||||
/* ================================================== */
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -741,7 +769,7 @@ NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP
|
||||
pool->sources++;
|
||||
|
||||
DEBUG_LOG(LOGF_NtpSources, "pool %s has %d confirmed sources",
|
||||
pool->name, pool->sources);
|
||||
record->name, pool->sources);
|
||||
|
||||
/* If the number of sources reached the configured maximum, remove
|
||||
the tentative sources added from this pool */
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
62
pktlength.c
62
pktlength.c
@@ -44,9 +44,8 @@ command_unpadded_length(CMD_Request *r)
|
||||
return 0;
|
||||
} else {
|
||||
switch (type) {
|
||||
|
||||
case REQ_NULL:
|
||||
return offsetof(CMD_Request, data);
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
case REQ_ONLINE:
|
||||
return offsetof(CMD_Request, data.online.EOR);
|
||||
case REQ_OFFLINE:
|
||||
@@ -78,11 +77,11 @@ command_unpadded_length(CMD_Request *r)
|
||||
case REQ_MANUAL :
|
||||
return offsetof(CMD_Request, data.manual.EOR);
|
||||
case REQ_N_SOURCES :
|
||||
return offsetof(CMD_Request, data.n_sources.EOR);
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
case REQ_SOURCE_DATA :
|
||||
return offsetof(CMD_Request, data.source_data.EOR);
|
||||
case REQ_REKEY :
|
||||
return offsetof(CMD_Request, data.rekey.EOR);
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
case REQ_ALLOW :
|
||||
return offsetof(CMD_Request, data.allow_deny.EOR);
|
||||
case REQ_ALLOWALL :
|
||||
@@ -110,21 +109,21 @@ command_unpadded_length(CMD_Request *r)
|
||||
case REQ_DEL_SOURCE :
|
||||
return offsetof(CMD_Request, data.del_source.EOR);
|
||||
case REQ_WRITERTC :
|
||||
return offsetof(CMD_Request, data.writertc.EOR);
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
case REQ_DFREQ :
|
||||
return offsetof(CMD_Request, data.dfreq.EOR);
|
||||
case REQ_DOFFSET :
|
||||
return offsetof(CMD_Request, data.doffset.EOR);
|
||||
case REQ_TRACKING :
|
||||
return offsetof(CMD_Request, data.tracking.EOR);
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
case REQ_SOURCESTATS :
|
||||
return offsetof(CMD_Request, data.sourcestats.EOR);
|
||||
case REQ_RTCREPORT :
|
||||
return offsetof(CMD_Request, data.rtcreport.EOR);
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
case REQ_TRIMRTC :
|
||||
return offsetof(CMD_Request, data.trimrtc.EOR);
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
case REQ_CYCLELOGS :
|
||||
return offsetof(CMD_Request, data.cyclelogs.EOR);
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
case REQ_SUBNETS_ACCESSED :
|
||||
case REQ_CLIENT_ACCESSES:
|
||||
/* No longer supported */
|
||||
@@ -132,21 +131,27 @@ command_unpadded_length(CMD_Request *r)
|
||||
case REQ_CLIENT_ACCESSES_BY_INDEX:
|
||||
return offsetof(CMD_Request, data.client_accesses_by_index.EOR);
|
||||
case REQ_MANUAL_LIST:
|
||||
return offsetof(CMD_Request, data.manual_list.EOR);
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
case REQ_MANUAL_DELETE:
|
||||
return offsetof(CMD_Request, data.manual_delete.EOR);
|
||||
case REQ_MAKESTEP:
|
||||
return offsetof(CMD_Request, data.make_step.EOR);
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
case REQ_ACTIVITY:
|
||||
return offsetof(CMD_Request, data.activity.EOR);
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
case REQ_RESELECT:
|
||||
return offsetof(CMD_Request, data.reselect.EOR);
|
||||
return offsetof(CMD_Request, data.null.EOR);
|
||||
case REQ_RESELECTDISTANCE:
|
||||
return offsetof(CMD_Request, data.reselect_distance.EOR);
|
||||
case REQ_MODIFY_MINSTRATUM:
|
||||
return offsetof(CMD_Request, data.modify_minstratum.EOR);
|
||||
case REQ_MODIFY_POLLTARGET:
|
||||
return offsetof(CMD_Request, data.modify_polltarget.EOR);
|
||||
case REQ_SMOOTHING:
|
||||
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);
|
||||
@@ -228,11 +233,11 @@ PKL_CommandPaddingLength(CMD_Request *r)
|
||||
case REQ_MANUAL:
|
||||
return PADDING_LENGTH(data.manual.EOR, data.null.EOR);
|
||||
case REQ_N_SOURCES:
|
||||
return PADDING_LENGTH(data.n_sources.EOR, data.n_sources.EOR);
|
||||
return PADDING_LENGTH(data.null.EOR, data.n_sources.EOR);
|
||||
case REQ_SOURCE_DATA:
|
||||
return PADDING_LENGTH(data.source_data.EOR, data.source_data.EOR);
|
||||
case REQ_REKEY:
|
||||
return PADDING_LENGTH(data.rekey.EOR, data.null.EOR);
|
||||
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
|
||||
case REQ_ALLOW:
|
||||
return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR);
|
||||
case REQ_ALLOWALL:
|
||||
@@ -260,21 +265,21 @@ PKL_CommandPaddingLength(CMD_Request *r)
|
||||
case REQ_DEL_SOURCE:
|
||||
return PADDING_LENGTH(data.del_source.EOR, data.null.EOR);
|
||||
case REQ_WRITERTC:
|
||||
return PADDING_LENGTH(data.writertc.EOR, data.null.EOR);
|
||||
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
|
||||
case REQ_DFREQ:
|
||||
return PADDING_LENGTH(data.dfreq.EOR, data.null.EOR);
|
||||
case REQ_DOFFSET:
|
||||
return PADDING_LENGTH(data.doffset.EOR, data.null.EOR);
|
||||
case REQ_TRACKING:
|
||||
return PADDING_LENGTH(data.tracking.EOR, data.tracking.EOR);
|
||||
return PADDING_LENGTH(data.null.EOR, data.tracking.EOR);
|
||||
case REQ_SOURCESTATS:
|
||||
return PADDING_LENGTH(data.sourcestats.EOR, data.sourcestats.EOR);
|
||||
case REQ_RTCREPORT:
|
||||
return PADDING_LENGTH(data.rtcreport.EOR, data.rtc.EOR);
|
||||
return PADDING_LENGTH(data.null.EOR, data.rtc.EOR);
|
||||
case REQ_TRIMRTC:
|
||||
return PADDING_LENGTH(data.trimrtc.EOR, data.null.EOR);
|
||||
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
|
||||
case REQ_CYCLELOGS:
|
||||
return PADDING_LENGTH(data.cyclelogs.EOR, data.null.EOR);
|
||||
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
|
||||
case REQ_SUBNETS_ACCESSED:
|
||||
case REQ_CLIENT_ACCESSES:
|
||||
/* No longer supported */
|
||||
@@ -282,21 +287,27 @@ PKL_CommandPaddingLength(CMD_Request *r)
|
||||
case REQ_CLIENT_ACCESSES_BY_INDEX:
|
||||
return PADDING_LENGTH(data.client_accesses_by_index.EOR, data.client_accesses_by_index.EOR);
|
||||
case REQ_MANUAL_LIST:
|
||||
return PADDING_LENGTH(data.manual_list.EOR, data.manual_list.EOR);
|
||||
return PADDING_LENGTH(data.null.EOR, data.manual_list.EOR);
|
||||
case REQ_MANUAL_DELETE:
|
||||
return PADDING_LENGTH(data.manual_delete.EOR, data.null.EOR);
|
||||
case REQ_MAKESTEP:
|
||||
return PADDING_LENGTH(data.make_step.EOR, data.null.EOR);
|
||||
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
|
||||
case REQ_ACTIVITY:
|
||||
return PADDING_LENGTH(data.activity.EOR, data.activity.EOR);
|
||||
return PADDING_LENGTH(data.null.EOR, data.activity.EOR);
|
||||
case REQ_RESELECT:
|
||||
return PADDING_LENGTH(data.reselect.EOR, data.null.EOR);
|
||||
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
|
||||
case REQ_RESELECTDISTANCE:
|
||||
return PADDING_LENGTH(data.reselect_distance.EOR, data.null.EOR);
|
||||
case REQ_MODIFY_MINSTRATUM:
|
||||
return PADDING_LENGTH(data.modify_minstratum.EOR, data.null.EOR);
|
||||
case REQ_MODIFY_POLLTARGET:
|
||||
return PADDING_LENGTH(data.modify_polltarget.EOR, data.null.EOR);
|
||||
case REQ_SMOOTHING:
|
||||
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);
|
||||
@@ -360,7 +371,8 @@ PKL_ReplyLength(CMD_Reply *r)
|
||||
}
|
||||
case RPY_ACTIVITY:
|
||||
return offsetof(CMD_Reply, data.activity.EOR);
|
||||
|
||||
case RPY_SMOOTHING:
|
||||
return offsetof(CMD_Reply, data.smoothing.EOR);
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
13
refclock.c
13
refclock.c
@@ -499,15 +499,6 @@ RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static double
|
||||
poll_interval(int poll)
|
||||
{
|
||||
if (poll >= 0)
|
||||
return 1 << poll;
|
||||
else
|
||||
return 1.0 / (1 << -poll);
|
||||
}
|
||||
|
||||
static int
|
||||
valid_sample_time(RCL_Instance instance, struct timeval *tv)
|
||||
{
|
||||
@@ -516,7 +507,7 @@ valid_sample_time(RCL_Instance instance, struct timeval *tv)
|
||||
|
||||
LCL_ReadRawTime(&raw_time);
|
||||
UTI_DiffTimevalsToDouble(&diff, &raw_time, tv);
|
||||
if (diff < 0.0 || diff > poll_interval(instance->poll + 1)) {
|
||||
if (diff < 0.0 || diff > UTI_Log2ToDouble(instance->poll + 1)) {
|
||||
DEBUG_LOG(LOGF_Refclock, "%s refclock sample not valid age=%.6f tv=%s",
|
||||
UTI_RefidToString(instance->ref_id), diff, UTI_TimevalToString(tv));
|
||||
return 0;
|
||||
@@ -595,7 +586,7 @@ poll_timeout(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
inst->timeout_id = SCH_AddTimeoutByDelay(poll_interval(poll), poll_timeout, arg);
|
||||
inst->timeout_id = SCH_AddTimeoutByDelay(UTI_Log2ToDouble(poll), poll_timeout, arg);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
25
reference.c
25
reference.c
@@ -120,11 +120,6 @@ static LOG_FileID logfileid;
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Reference ID supplied when we are locally referenced */
|
||||
#define LOCAL_REFERENCE_ID 0x7f7f0101UL
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Exponential moving averages of absolute clock frequencies
|
||||
used as a fallback when synchronisation is lost. */
|
||||
|
||||
@@ -794,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) {
|
||||
@@ -810,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;
|
||||
@@ -1109,12 +1106,10 @@ REF_SetManualReference
|
||||
double skew
|
||||
)
|
||||
{
|
||||
uint32_t manual_refid = 0x4D414E55; /* MANU */
|
||||
|
||||
/* We are not synchronised to an external source, as such. This is
|
||||
only supposed to be used with the local source option, really
|
||||
... */
|
||||
REF_SetReference(0, LEAP_Unsynchronised, 1, manual_refid, NULL,
|
||||
only supposed to be used with the local source option, really.
|
||||
Log as MANU in the tracking log, packets will have NTP_REFID_LOCAL. */
|
||||
REF_SetReference(0, LEAP_Unsynchronised, 1, 0x4D414E55UL, NULL,
|
||||
ref_time, offset, 0.0, frequency, skew, 0.0, 0.0);
|
||||
}
|
||||
|
||||
@@ -1200,7 +1195,7 @@ REF_GetReferenceParams
|
||||
*is_synchronised = 1;
|
||||
|
||||
*stratum = local_stratum;
|
||||
*ref_id = LOCAL_REFERENCE_ID;
|
||||
*ref_id = NTP_REFID_LOCAL;
|
||||
/* Make the reference time be now less a second - this will
|
||||
scarcely affect the client, but will ensure that the transmit
|
||||
timestamp cannot come before this (which would cause test 7 to
|
||||
@@ -1222,7 +1217,7 @@ REF_GetReferenceParams
|
||||
|
||||
*leap_status = LEAP_Unsynchronised;
|
||||
*stratum = NTP_MAX_STRATUM;
|
||||
*ref_id = 0;
|
||||
*ref_id = NTP_REFID_UNSYNC;
|
||||
ref_time->tv_sec = ref_time->tv_usec = 0;
|
||||
/* These values seem to be standard for a client, and
|
||||
any peer or client of ours will ignore them anyway because
|
||||
@@ -1336,7 +1331,7 @@ REF_GetTrackingReport(RPT_TrackingReport *rep)
|
||||
LCL_GetOffsetCorrection(&now_raw, &correction, NULL);
|
||||
UTI_AddDoubleToTimeval(&now_raw, correction, &now_cooked);
|
||||
|
||||
rep->ref_id = 0;
|
||||
rep->ref_id = NTP_REFID_UNSYNC;
|
||||
rep->ip_addr.family = IPADDR_UNSPEC;
|
||||
rep->stratum = 0;
|
||||
rep->leap_status = our_leap_status;
|
||||
@@ -1368,7 +1363,7 @@ REF_GetTrackingReport(RPT_TrackingReport *rep)
|
||||
|
||||
} else if (enable_local_stratum) {
|
||||
|
||||
rep->ref_id = LOCAL_REFERENCE_ID;
|
||||
rep->ref_id = NTP_REFID_LOCAL;
|
||||
rep->ip_addr.family = IPADDR_UNSPEC;
|
||||
rep->stratum = local_stratum;
|
||||
rep->ref_time = now_cooked;
|
||||
|
||||
10
reports.h
10
reports.h
@@ -112,4 +112,14 @@ typedef struct {
|
||||
int unresolved;
|
||||
} RPT_ActivityReport;
|
||||
|
||||
typedef struct {
|
||||
int active;
|
||||
int leap_only;
|
||||
double offset;
|
||||
double freq_ppm;
|
||||
double wander_ppm;
|
||||
double last_update_ago;
|
||||
double remaining_time;
|
||||
} RPT_SmoothingReport;
|
||||
|
||||
#endif /* GOT_REPORTS_H */
|
||||
|
||||
62
rtc.c
62
rtc.c
@@ -39,11 +39,12 @@
|
||||
/* ================================================== */
|
||||
|
||||
static int driver_initialised = 0;
|
||||
static int driver_preinit_ok = 0;
|
||||
|
||||
static struct {
|
||||
int (*init)(void);
|
||||
void (*fini)(void);
|
||||
int (*time_pre_init)(void);
|
||||
int (*time_pre_init)(time_t driftfile_time);
|
||||
void (*time_init)(void (*after_hook)(void*), void *anything);
|
||||
void (*start_measurements)(void);
|
||||
int (*write_parameters)(void);
|
||||
@@ -73,29 +74,37 @@ static struct {
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
/* Set the system clock to the time of last modification of driftfile
|
||||
if it's in the future */
|
||||
/* Get the last modification time of the driftfile */
|
||||
|
||||
static void
|
||||
fallback_time_init(void)
|
||||
static time_t
|
||||
get_driftfile_time(void)
|
||||
{
|
||||
struct timeval now;
|
||||
struct stat buf;
|
||||
char *drift_file;
|
||||
|
||||
drift_file = CNF_GetDriftFile();
|
||||
if (!drift_file)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
if (stat(drift_file, &buf))
|
||||
return;
|
||||
return 0;
|
||||
|
||||
return buf.st_mtime;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Set the system time to the driftfile time if it's in the future */
|
||||
|
||||
static void
|
||||
apply_driftfile_time(time_t t)
|
||||
{
|
||||
struct timeval now;
|
||||
|
||||
LCL_ReadCookedTime(&now, NULL);
|
||||
|
||||
if (now.tv_sec < buf.st_mtime) {
|
||||
if (LCL_ApplyStepOffset(now.tv_sec - buf.st_mtime))
|
||||
LOG(LOGS_INFO, LOGF_Rtc, "System clock set from driftfile %s",
|
||||
drift_file);
|
||||
if (now.tv_sec < t) {
|
||||
if (LCL_ApplyStepOffset(now.tv_sec - t))
|
||||
LOG(LOGS_INFO, LOGF_Rtc, "System time restored from driftfile");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,15 +113,24 @@ fallback_time_init(void)
|
||||
void
|
||||
RTC_Initialise(int initial_set)
|
||||
{
|
||||
time_t driftfile_time;
|
||||
char *file_name;
|
||||
|
||||
/* Do an initial read of the RTC and set the system time to it. This
|
||||
is analogous to what /sbin/hwclock -s would do on Linux. If that fails
|
||||
or RTC is not supported, set the clock to the time of the last
|
||||
modification of driftfile, so we at least get closer to the truth. */
|
||||
/* If the -s option was specified, try to do an initial read of the RTC and
|
||||
set the system time to it. Also, read the last modification time of the
|
||||
driftfile (i.e. system time when chronyd was previously stopped) and set
|
||||
the system time to it if it's in the future to bring the clock closer to
|
||||
the true time when the RTC is broken (e.g. it has no battery), is missing,
|
||||
or there is no RTC driver. */
|
||||
if (initial_set) {
|
||||
if (!driver.time_pre_init || !driver.time_pre_init()) {
|
||||
fallback_time_init();
|
||||
driftfile_time = get_driftfile_time();
|
||||
|
||||
if (driver.time_pre_init && driver.time_pre_init(driftfile_time)) {
|
||||
driver_preinit_ok = 1;
|
||||
} else {
|
||||
driver_preinit_ok = 0;
|
||||
if (driftfile_time)
|
||||
apply_driftfile_time(driftfile_time);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,9 +168,9 @@ RTC_Finalise(void)
|
||||
/* ================================================== */
|
||||
/* Start the processing to get a single measurement from the real time
|
||||
clock, and use it to trim the system time, based on knowing the
|
||||
drift rate of the RTC and the error the last time we set it. The
|
||||
TimePreInit routine has already run, so we can be sure that the
|
||||
trim required is not *too* large.
|
||||
drift rate of the RTC and the error the last time we set it. If the
|
||||
TimePreInit routine has succeeded, we can be sure that the trim required
|
||||
is not *too* large.
|
||||
|
||||
We are called with a hook to a function to be called after the
|
||||
initialisation is complete. We also call this if we cannot do the
|
||||
@@ -161,7 +179,7 @@ RTC_Finalise(void)
|
||||
void
|
||||
RTC_TimeInit(void (*after_hook)(void *), void *anything)
|
||||
{
|
||||
if (driver_initialised) {
|
||||
if (driver_initialised && driver_preinit_ok) {
|
||||
(driver.time_init)(after_hook, anything);
|
||||
} else {
|
||||
(after_hook)(anything);
|
||||
|
||||
47
rtc_linux.c
47
rtc_linux.c
@@ -367,6 +367,9 @@ t_from_rtc(struct tm *stm) {
|
||||
t2 = mktime(&temp2);
|
||||
diff = t2 - t1;
|
||||
|
||||
if (t1 - diff == -1)
|
||||
DEBUG_LOG(LOGF_RtcLinux, "Could not convert RTC time");
|
||||
|
||||
return t1 - diff;
|
||||
}
|
||||
|
||||
@@ -379,13 +382,13 @@ read_hwclock_file(const char *hwclock_file)
|
||||
char line[256];
|
||||
int i;
|
||||
|
||||
if (!hwclock_file)
|
||||
if (!hwclock_file || !hwclock_file[0])
|
||||
return;
|
||||
|
||||
in = fopen(hwclock_file, "r");
|
||||
if (!in) {
|
||||
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not open hwclockfile %s",
|
||||
hwclock_file);
|
||||
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not open %s : %s",
|
||||
hwclock_file, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -402,7 +405,7 @@ read_hwclock_file(const char *hwclock_file)
|
||||
} else if (i == 3 && !strncmp(line, "UTC", 3)) {
|
||||
rtc_on_utc = 1;
|
||||
} else {
|
||||
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not read LOCAL/UTC setting from hwclockfile %s",
|
||||
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not read RTC LOCAL/UTC setting from %s",
|
||||
hwclock_file);
|
||||
}
|
||||
}
|
||||
@@ -445,7 +448,7 @@ read_coefs_from_file(void)
|
||||
&file_ref_offset,
|
||||
&file_rate_ppm) == 4) {
|
||||
} else {
|
||||
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not read coefficients from RTC file %s",
|
||||
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not read coefficients from %s",
|
||||
coefs_file_name);
|
||||
}
|
||||
fclose(in);
|
||||
@@ -607,14 +610,16 @@ switch_interrupts(int onoff)
|
||||
if (onoff) {
|
||||
status = ioctl(fd, RTC_UIE_ON, 0);
|
||||
if (status < 0) {
|
||||
LOG(LOGS_ERR, LOGF_RtcLinux, "Could not start measurement : %s", strerror(errno));
|
||||
LOG(LOGS_ERR, LOGF_RtcLinux, "Could not %s RTC interrupt : %s",
|
||||
"enable", strerror(errno));
|
||||
return;
|
||||
}
|
||||
skip_interrupts = 1;
|
||||
} else {
|
||||
status = ioctl(fd, RTC_UIE_OFF, 0);
|
||||
if (status < 0) {
|
||||
LOG(LOGS_ERR, LOGF_RtcLinux, "Could not stop measurement : %s", strerror(errno));
|
||||
LOG(LOGS_ERR, LOGF_RtcLinux, "Could not %s RTC interrupt : %s",
|
||||
"disable", strerror(errno));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -694,10 +699,11 @@ handle_initial_trim(void)
|
||||
/* sys_error_now is positive if the system clock is fast */
|
||||
sys_error_now = rtc_error_now - coef_seconds_fast;
|
||||
|
||||
LOG(LOGS_INFO, LOGF_RtcLinux, "System trim from RTC = %f", sys_error_now);
|
||||
LCL_AccumulateOffset(sys_error_now, 0.0);
|
||||
LOG(LOGS_INFO, LOGF_RtcLinux, "System clock off from RTC by %f seconds (slew)",
|
||||
sys_error_now);
|
||||
} else {
|
||||
LOG(LOGS_WARN, LOGF_RtcLinux, "No valid file coefficients, cannot trim system time");
|
||||
LOG(LOGS_WARN, LOGF_RtcLinux, "No valid rtcfile coefficients");
|
||||
}
|
||||
|
||||
coefs_valid = 0;
|
||||
@@ -722,7 +728,7 @@ handle_relock_after_trim(void)
|
||||
if (valid) {
|
||||
write_coefs_to_file(1,ref,fast,saved_coef_gain_rate);
|
||||
} else {
|
||||
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not do regression after trim");
|
||||
DEBUG_LOG(LOGF_RtcLinux, "Could not do regression after trim");
|
||||
}
|
||||
|
||||
coefs_valid = 0;
|
||||
@@ -857,7 +863,6 @@ read_from_device(void *any)
|
||||
rtc_t = t_from_rtc(&rtc_tm);
|
||||
|
||||
if (rtc_t == (time_t)(-1)) {
|
||||
LOG(LOGS_ERR, LOGF_RtcLinux, "Could not convert RTC time to timeval");
|
||||
error = 1;
|
||||
goto turn_off_interrupt;
|
||||
}
|
||||
@@ -883,7 +888,7 @@ turn_off_interrupt:
|
||||
switch (operating_mode) {
|
||||
case OM_INITIAL:
|
||||
if (error) {
|
||||
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not complete initial step due to errors");
|
||||
DEBUG_LOG(LOGF_RtcLinux, "Could not complete initial step due to errors");
|
||||
operating_mode = OM_NORMAL;
|
||||
(after_init_hook)(after_init_hook_arg);
|
||||
|
||||
@@ -897,7 +902,7 @@ turn_off_interrupt:
|
||||
|
||||
case OM_AFTERTRIM:
|
||||
if (error) {
|
||||
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not complete after trim relock due to errors");
|
||||
DEBUG_LOG(LOGF_RtcLinux, "Could not complete after trim relock due to errors");
|
||||
operating_mode = OM_NORMAL;
|
||||
|
||||
switch_interrupts(0);
|
||||
@@ -974,7 +979,7 @@ RTC_Linux_WriteParameters(void)
|
||||
RTC behaviour than we do for the rest of the module. */
|
||||
|
||||
int
|
||||
RTC_Linux_TimePreInit(void)
|
||||
RTC_Linux_TimePreInit(time_t driftfile_time)
|
||||
{
|
||||
int fd, status;
|
||||
struct rtc_time rtc_raw, rtc_raw_retry;
|
||||
@@ -1039,18 +1044,23 @@ RTC_Linux_TimePreInit(void)
|
||||
|
||||
UTI_AddDoubleToTimeval(&new_sys_time, -accumulated_error, &new_sys_time);
|
||||
|
||||
if (new_sys_time.tv_sec < driftfile_time) {
|
||||
LOG(LOGS_WARN, LOGF_RtcLinux, "RTC time before last driftfile modification (ignored)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
UTI_DiffTimevalsToDouble(&sys_offset, &old_sys_time, &new_sys_time);
|
||||
|
||||
/* Set system time only if the step is larger than 1 second */
|
||||
if (fabs(sys_offset) >= 1.0) {
|
||||
if (LCL_ApplyStepOffset(sys_offset))
|
||||
LOG(LOGS_INFO, LOGF_RtcLinux, "Set system time, error in RTC = %f",
|
||||
accumulated_error);
|
||||
LOG(LOGS_INFO, LOGF_RtcLinux, "System time set from RTC");
|
||||
}
|
||||
} else {
|
||||
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not convert RTC reading to seconds since 1/1/1970");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -1090,7 +1100,8 @@ RTC_Linux_Trim(void)
|
||||
|
||||
if (fabs(coef_seconds_fast) > 1.0) {
|
||||
|
||||
LOG(LOGS_INFO, LOGF_RtcLinux, "Trimming RTC, error = %.3f seconds", coef_seconds_fast);
|
||||
LOG(LOGS_INFO, LOGF_RtcLinux, "RTC wrong by %.3f seconds (step)",
|
||||
coef_seconds_fast);
|
||||
|
||||
/* Do processing to set clock. Let R be the value we set the
|
||||
RTC to, then in 500ms the RTC ticks (R+1) (see comments in
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
extern int RTC_Linux_Initialise(void);
|
||||
extern void RTC_Linux_Finalise(void);
|
||||
extern int RTC_Linux_TimePreInit(void);
|
||||
extern int RTC_Linux_TimePreInit(time_t driftile_time);
|
||||
extern void RTC_Linux_TimeInit(void (*after_hook)(void *), void *anything);
|
||||
extern void RTC_Linux_StartMeasurements(void);
|
||||
|
||||
|
||||
4
sched.c
4
sched.c
@@ -330,6 +330,10 @@ SCH_AddTimeoutByDelay(double delay, SCH_TimeoutHandler handler, SCH_ArbitraryArg
|
||||
|
||||
LCL_ReadRawTime(&now);
|
||||
UTI_AddDoubleToTimeval(&now, delay, &then);
|
||||
if (UTI_CompareTimevals(&now, &then) > 0) {
|
||||
LOG_FATAL(LOGF_Scheduler, "Timeout overflow");
|
||||
}
|
||||
|
||||
return SCH_AddTimeout(&then, handler, arg);
|
||||
|
||||
}
|
||||
|
||||
111
smooth.c
111
smooth.c
@@ -77,6 +77,10 @@ static struct stage stages[NUM_STAGES];
|
||||
/* Enabled/disabled smoothing */
|
||||
static int enabled;
|
||||
|
||||
/* Enabled/disabled mode where only leap seconds are smoothed out and normal
|
||||
offset/frequency changes are ignored */
|
||||
static int leap_only_mode;
|
||||
|
||||
/* Maximum skew/max_wander ratio to start updating offset and frequency */
|
||||
#define UNLOCK_SKEW_WANDER_RATIO 10000
|
||||
|
||||
@@ -93,15 +97,17 @@ static struct timeval last_update;
|
||||
|
||||
|
||||
static void
|
||||
get_offset_freq(struct timeval *now, double *offset, double *freq)
|
||||
get_smoothing(struct timeval *now, double *poffset, double *pfreq,
|
||||
double *pwander)
|
||||
{
|
||||
double elapsed, length;
|
||||
double elapsed, length, offset, freq, wander;
|
||||
int i;
|
||||
|
||||
UTI_DiffTimevalsToDouble(&elapsed, now, &last_update);
|
||||
|
||||
*offset = smooth_offset;
|
||||
*freq = smooth_freq;
|
||||
offset = smooth_offset;
|
||||
freq = smooth_freq;
|
||||
wander = 0.0;
|
||||
|
||||
for (i = 0; i < NUM_STAGES; i++) {
|
||||
if (elapsed <= 0.0)
|
||||
@@ -111,13 +117,21 @@ get_offset_freq(struct timeval *now, double *offset, double *freq)
|
||||
if (length >= elapsed)
|
||||
length = elapsed;
|
||||
|
||||
*offset -= length * (2.0 * *freq + stages[i].wander * length) / 2.0;
|
||||
*freq += stages[i].wander * length;
|
||||
wander = stages[i].wander;
|
||||
offset -= length * (2.0 * freq + wander * length) / 2.0;
|
||||
freq += wander * length;
|
||||
elapsed -= length;
|
||||
}
|
||||
|
||||
if (elapsed > 0.0)
|
||||
*offset -= elapsed * *freq;
|
||||
if (elapsed > 0.0) {
|
||||
wander = 0.0;
|
||||
offset -= elapsed * freq;
|
||||
}
|
||||
|
||||
*poffset = offset;
|
||||
*pfreq = freq;
|
||||
if (pwander)
|
||||
*pwander = wander;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -185,14 +199,12 @@ update_smoothing(struct timeval *now, double offset, double freq)
|
||||
{
|
||||
/* Don't accept offset/frequency until the clock has stabilized */
|
||||
if (locked) {
|
||||
if (REF_GetSkew() / max_wander < UNLOCK_SKEW_WANDER_RATIO) {
|
||||
LOG(LOGS_INFO, LOGF_Smooth, "Time smoothing activated");
|
||||
locked = 0;
|
||||
}
|
||||
if (REF_GetSkew() / max_wander < UNLOCK_SKEW_WANDER_RATIO || leap_only_mode)
|
||||
SMT_Activate(now);
|
||||
return;
|
||||
}
|
||||
|
||||
get_offset_freq(now, &smooth_offset, &smooth_freq);
|
||||
get_smoothing(now, &smooth_offset, &smooth_freq, NULL);
|
||||
smooth_offset += offset;
|
||||
smooth_freq = (smooth_freq - freq) / (1.0 - freq);
|
||||
last_update = *now;
|
||||
@@ -208,15 +220,19 @@ handle_slew(struct timeval *raw, struct timeval *cooked, double dfreq,
|
||||
{
|
||||
double delta;
|
||||
|
||||
if (change_type == LCL_ChangeAdjust)
|
||||
update_smoothing(cooked, doffset, dfreq);
|
||||
if (change_type == LCL_ChangeAdjust) {
|
||||
if (leap_only_mode)
|
||||
update_smoothing(cooked, 0.0, 0.0);
|
||||
else
|
||||
update_smoothing(cooked, doffset, dfreq);
|
||||
}
|
||||
|
||||
UTI_AdjustTimeval(&last_update, cooked, &last_update, &delta, dfreq, doffset);
|
||||
}
|
||||
|
||||
void SMT_Initialise(void)
|
||||
{
|
||||
CNF_GetSmooth(&max_freq, &max_wander);
|
||||
CNF_GetSmooth(&max_freq, &max_wander, &leap_only_mode);
|
||||
if (max_freq <= 0.0 || max_wander <= 0.0) {
|
||||
enabled = 0;
|
||||
return;
|
||||
@@ -249,19 +265,78 @@ SMT_GetOffset(struct timeval *now)
|
||||
if (!enabled)
|
||||
return 0.0;
|
||||
|
||||
get_offset_freq(now, &offset, &freq);
|
||||
get_smoothing(now, &offset, &freq, NULL);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
void
|
||||
SMT_Activate(struct timeval *now)
|
||||
{
|
||||
if (!enabled || !locked)
|
||||
return;
|
||||
|
||||
LOG(LOGS_INFO, LOGF_Smooth, "Time smoothing activated%s", leap_only_mode ?
|
||||
" (leap seconds only)" : "");
|
||||
locked = 0;
|
||||
last_update = *now;
|
||||
}
|
||||
|
||||
void
|
||||
SMT_Reset(struct timeval *now)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
locked = 1;
|
||||
smooth_offset = 0.0;
|
||||
smooth_freq = 0.0;
|
||||
last_update = *now;
|
||||
|
||||
for (i = 0; i < NUM_STAGES; i++)
|
||||
stages[i].wander = stages[i].length = 0.0;
|
||||
}
|
||||
|
||||
void
|
||||
SMT_Leap(struct timeval *now, int leap)
|
||||
{
|
||||
/* When the leap-only mode is disabled, the leap second will be accumulated
|
||||
in handle_slew() as a normal offset */
|
||||
if (!enabled || !leap_only_mode)
|
||||
return;
|
||||
|
||||
update_smoothing(now, leap, 0.0);
|
||||
}
|
||||
|
||||
int
|
||||
SMT_GetSmoothingReport(RPT_SmoothingReport *report, struct timeval *now)
|
||||
{
|
||||
double length, elapsed;
|
||||
int i;
|
||||
|
||||
if (!enabled)
|
||||
return 0;
|
||||
|
||||
report->active = !locked;
|
||||
report->leap_only = leap_only_mode;
|
||||
|
||||
get_smoothing(now, &report->offset, &report->freq_ppm, &report->wander_ppm);
|
||||
|
||||
/* Convert to ppm and negate (positive values mean faster/speeding up) */
|
||||
report->freq_ppm *= -1.0e6;
|
||||
report->wander_ppm *= -1.0e6;
|
||||
|
||||
UTI_DiffTimevalsToDouble(&elapsed, now, &last_update);
|
||||
if (!locked && elapsed >= 0.0) {
|
||||
for (i = 0, length = 0.0; i < NUM_STAGES; i++)
|
||||
length += stages[i].length;
|
||||
report->last_update_ago = elapsed;
|
||||
report->remaining_time = elapsed < length ? length - elapsed : 0.0;
|
||||
} else {
|
||||
report->last_update_ago = 0.0;
|
||||
report->remaining_time = 0.0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
8
smooth.h
8
smooth.h
@@ -27,6 +27,8 @@
|
||||
#ifndef GOT_SMOOTH_H
|
||||
#define GOT_SMOOTH_H
|
||||
|
||||
#include "reports.h"
|
||||
|
||||
extern void SMT_Initialise(void);
|
||||
|
||||
extern void SMT_Finalise(void);
|
||||
@@ -35,6 +37,12 @@ extern int SMT_IsEnabled(void);
|
||||
|
||||
extern double SMT_GetOffset(struct timeval *now);
|
||||
|
||||
extern void SMT_Activate(struct timeval *now);
|
||||
|
||||
extern void SMT_Reset(struct timeval *now);
|
||||
|
||||
extern void SMT_Leap(struct timeval *now, int leap);
|
||||
|
||||
extern int SMT_GetSmoothingReport(RPT_SmoothingReport *report, struct timeval *now);
|
||||
|
||||
#endif
|
||||
|
||||
92
sources.c
92
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)
|
||||
@@ -807,43 +815,6 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* We now have a list of indices for the sources which pass the
|
||||
false-ticker test. Now go on to reject those whose variance is
|
||||
greater than the minimum distance of any other */
|
||||
|
||||
/* Find minimum distance */
|
||||
index = sel_sources[0];
|
||||
min_distance = sources[index]->sel_info.root_distance;
|
||||
for (i = 1; i < n_sel_sources; i++) {
|
||||
index = sel_sources[i];
|
||||
distance = sources[index]->sel_info.root_distance;
|
||||
if (distance < min_distance) {
|
||||
min_distance = distance;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now go through and prune any NTP sources that have excessive
|
||||
variance */
|
||||
for (i = 0; i < n_sel_sources; i++) {
|
||||
index = sel_sources[i];
|
||||
if (sources[index]->type == SRC_NTP &&
|
||||
sqrt(sources[index]->sel_info.variance) > min_distance) {
|
||||
sel_sources[i] = INVALID_SOURCE;
|
||||
sources[index]->status = SRC_JITTERY;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now crunch the list and mark all sources as selectable */
|
||||
for (i = j = 0; i < n_sel_sources; i++) {
|
||||
index = sel_sources[i];
|
||||
if (index == INVALID_SOURCE)
|
||||
continue;
|
||||
sel_sources[j++] = index;
|
||||
}
|
||||
n_sel_sources = j;
|
||||
#endif
|
||||
|
||||
if (n_sel_sources == 0 || n_sel_sources < CNF_GetMinSources()) {
|
||||
if (selected_source_index != INVALID_SOURCE) {
|
||||
log_selection_message("Can't synchronise: %s selectable sources",
|
||||
@@ -872,16 +843,18 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
|
||||
/* If there are any sources with prefer option, reduce the list again
|
||||
only to the preferred sources */
|
||||
for (i = j = 0; i < n_sel_sources; i++) {
|
||||
for (i = 0; i < n_sel_sources; i++) {
|
||||
if (sources[sel_sources[i]]->sel_option == SRC_SelectPrefer)
|
||||
sel_sources[j++] = sel_sources[i];
|
||||
break;
|
||||
}
|
||||
|
||||
if (j > 0) {
|
||||
for (i = 0; i < n_sel_sources; i++) {
|
||||
if (i < n_sel_sources) {
|
||||
for (i = j = 0; i < n_sel_sources; i++) {
|
||||
if (sources[sel_sources[i]]->sel_option != SRC_SelectPrefer)
|
||||
sources[sel_sources[i]]->status = SRC_NONPREFERRED;
|
||||
else
|
||||
sel_sources[j++] = sel_sources[i];
|
||||
}
|
||||
assert(j > 0);
|
||||
n_sel_sources = j;
|
||||
sel_prefer = 1;
|
||||
} else {
|
||||
@@ -1128,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);
|
||||
}
|
||||
|
||||
@@ -1254,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)
|
||||
{
|
||||
|
||||
72
sys.c
72
sys.c
@@ -27,23 +27,21 @@
|
||||
|
||||
#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"
|
||||
#elif defined(MACOSX)
|
||||
#include "sys_macosx.h"
|
||||
#endif
|
||||
|
||||
/* ================================================== */
|
||||
@@ -51,23 +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();
|
||||
#elif defined(MACOSX)
|
||||
SYS_MacOSX_Initialise();
|
||||
#else
|
||||
#error Unknown system
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -75,30 +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();
|
||||
#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
|
||||
@@ -106,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_FATAL(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);
|
||||
|
||||
|
||||
@@ -2,46 +2,55 @@
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
*
|
||||
* Copyright (C) Richard P. Curnow 1997-2001
|
||||
* Copyright (C) J. Hannken-Illjes 2001
|
||||
* Copyright (C) Bryan Christianson 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 file for the SunOS 4.1.x operating system.
|
||||
Driver file for the MacOS X operating system.
|
||||
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef SUNOS
|
||||
#ifdef MACOSX
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <kvm.h>
|
||||
#include <fcntl.h>
|
||||
#include <nlist.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "sys_sunos.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"
|
||||
#include "sched.h"
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -65,16 +74,27 @@ static double current_freq;
|
||||
|
||||
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.
|
||||
/* Interval in seconds between adjustments to cancel systematic drift */
|
||||
|
||||
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!!
|
||||
#define DRIFT_REMOVAL_INTERVAL (4.0)
|
||||
#define DRIFT_REMOVAL_INTERVAL_MIN (0.5)
|
||||
|
||||
*/
|
||||
static unsigned long our_tickadj = 100;
|
||||
/* 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)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -86,20 +106,19 @@ 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_SysSunOS, "gettimeofday() failed");
|
||||
LOG_FATAL(LOGF_SysMacOSX, "gettimeofday() failed");
|
||||
}
|
||||
Tdrift = T0;
|
||||
|
||||
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");
|
||||
LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,56 +137,47 @@ 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;
|
||||
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");
|
||||
LOG_FATAL(LOGF_SysMacOSX, "gettimeofday() failed");
|
||||
}
|
||||
|
||||
UTI_DiffTimevalsToDouble(&elapsed, &T1, &T0);
|
||||
accrued_error = elapsed * current_freq;
|
||||
|
||||
adjust_required = - (accrued_error + offset_register);
|
||||
|
||||
UTI_DoubleToTimeval(adjust_required, &exact_newadj);
|
||||
UTI_DiffTimevalsToDouble(&drift_removal_elapsed, &T1, &Tdrift);
|
||||
|
||||
/* 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. */
|
||||
/* 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);
|
||||
|
||||
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;
|
||||
}
|
||||
predicted_error = (current_drift_removal_interval - drift_removal_elapsed) / 2.0 * current_freq;
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
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_SysSunOS, "adjtime() failed");
|
||||
LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed");
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -178,20 +188,19 @@ 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");
|
||||
LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed");
|
||||
}
|
||||
|
||||
if (gettimeofday(&T1, NULL) < 0) {
|
||||
LOG_FATAL(LOGF_SysSunOS, "gettimeofday() failed");
|
||||
LOG_FATAL(LOGF_SysMacOSX, "gettimeofday() failed");
|
||||
}
|
||||
|
||||
|
||||
UTI_DiffTimevalsToDouble(&elapsed, &T1, &T0);
|
||||
UTI_TimevalToDouble(&remadj, &adjustment_remaining);
|
||||
|
||||
@@ -202,7 +211,6 @@ stop_adjust(void)
|
||||
|
||||
adjustment_requested = 0.0;
|
||||
T0 = T1;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -227,16 +235,17 @@ 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");
|
||||
LOG_FATAL(LOGF_SysMacOSX, "gettimeofday() failed");
|
||||
}
|
||||
|
||||
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
|
||||
|
||||
if (settimeofday(&new_time, NULL) < 0) {
|
||||
DEBUG_LOG(LOGF_SysSunOS, "settimeofday() failed");
|
||||
DEBUG_LOG(LOGF_SysMacOSX, "settimeofday() failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -283,136 +292,143 @@ get_offset_correction(struct timeval *raw,
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
immediate_step(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Interval in seconds between adjustments to cancel systematic drift */
|
||||
#define DRIFT_REMOVAL_INTERVAL (4.0)
|
||||
/* 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. */
|
||||
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);
|
||||
|
||||
drift_removal_id = SCH_AddTimeoutByDelay(drift_removal_interval, drift_removal_timeout, NULL);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* use est_error to calculate the drift_removal_interval */
|
||||
|
||||
static void
|
||||
setup_kernel(unsigned long on_off)
|
||||
set_sync_status(int synchronised, double est_error, double max_error)
|
||||
{
|
||||
static struct nlist nl[] = {
|
||||
{"_dosynctodr"},
|
||||
{"_tick"},
|
||||
{"_tickadj"},
|
||||
{NULL}
|
||||
};
|
||||
double interval;
|
||||
|
||||
kvm_t *kt;
|
||||
unsigned long read_back;
|
||||
unsigned long our_tick = 10000;
|
||||
unsigned long default_tickadj = 625;
|
||||
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);
|
||||
|
||||
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;
|
||||
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 (kvm_nlist(kt, nl) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_SysSunOS, "Cannot read kernel symbols");
|
||||
kvm_close(kt);
|
||||
return;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
/* ================================================== */
|
||||
/*
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SYS_SunOS_Initialise(void)
|
||||
SYS_MacOSX_SetScheduler(int SchedPriority)
|
||||
{
|
||||
if (SchedPriority) {
|
||||
set_realtime();
|
||||
}
|
||||
}
|
||||
|
||||
/* Need to do KVM stuff to turn off dosynctodr. */
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SYS_MacOSX_Initialise(void)
|
||||
{
|
||||
clock_initialise();
|
||||
|
||||
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
|
||||
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
|
||||
accrue_offset, apply_step_offset,
|
||||
get_offset_correction,
|
||||
NULL /* set_leap */,
|
||||
NULL /* set_sync_status */);
|
||||
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_id = SCH_AddTimeoutByDelay(drift_removal_interval, drift_removal_timeout, NULL);
|
||||
drift_removal_running = 1;
|
||||
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SYS_SunOS_Finalise(void)
|
||||
SYS_MacOSX_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 */
|
||||
#endif
|
||||
@@ -2,33 +2,36 @@
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2002
|
||||
*
|
||||
* Copyright (C) Richard P. Curnow 1997-2001
|
||||
* Copyright (C) J. Hannken-Illjes 2001
|
||||
* Copyright (C) Bryan Christianson 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 Solaris driver
|
||||
Header file for MacOS X driver
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GOT_SYS_SUNOS_H
|
||||
#define GOT_SYS_SUNOS_H
|
||||
#ifndef GOT_SYS_MACOSX_H
|
||||
#define GOT_SYS_MACOSX_H
|
||||
|
||||
void SYS_SunOS_Initialise(void);
|
||||
|
||||
void SYS_SunOS_Finalise(void);
|
||||
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 */
|
||||
|
||||
|
||||
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__)
|
||||
|
||||
#if !defined(__NetBSD__) && !defined(__FreeBSD__)
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <float.h>
|
||||
#if !defined(__FreeBSD__)
|
||||
#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" \
|
||||
"--enable-scfilter" \
|
||||
"--disable-asyncdns" \
|
||||
"--disable-ipv6" \
|
||||
"--disable-privdrop" \
|
||||
"--disable-readline" \
|
||||
"--disable-rtc" \
|
||||
"--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;
|
||||
}
|
||||
@@ -39,4 +39,24 @@ check_chronyd_exit || test_fail
|
||||
# This check must fail as the client doesn't know the key
|
||||
check_sync && test_fail
|
||||
check_packet_interval || test_fail
|
||||
|
||||
client_conf="keyfile tmp/keys"
|
||||
clients=2
|
||||
peers=2
|
||||
max_sync_time=300
|
||||
base_delay="$default_base_delay (* -1 (equal 0.1 from 3) (equal 0.1 to 1))"
|
||||
client_lpeer_options="key 1"
|
||||
client_rpeer_options="key 1"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
client_rpeer_options="key 2"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
# This check must fail as the peers are using different keys"
|
||||
check_sync && test_fail
|
||||
|
||||
test_pass
|
||||
|
||||
@@ -27,18 +27,20 @@ for leapmode in system step slew; do
|
||||
check_sync || test_fail
|
||||
done
|
||||
|
||||
server_conf="refclock SHM 0 dpoll 10 poll 10
|
||||
leapsectz right/UTC
|
||||
leapsecmode slew
|
||||
smoothtime 400 0.001"
|
||||
client_conf="leapsecmode system"
|
||||
min_sync_time=230000
|
||||
max_sync_time=240000
|
||||
for smoothmode in "" "leaponly"; do
|
||||
server_conf="refclock SHM 0 dpoll 10 poll 10
|
||||
leapsectz right/UTC
|
||||
leapsecmode slew
|
||||
smoothtime 400 0.001 $smoothmode"
|
||||
client_conf="leapsecmode system"
|
||||
min_sync_time=230000
|
||||
max_sync_time=240000
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_packet_interval || test_fail
|
||||
check_sync || test_fail
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_packet_interval || test_fail
|
||||
check_sync || test_fail
|
||||
done
|
||||
|
||||
test_pass
|
||||
|
||||
@@ -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
|
||||
|
||||
21
test/simulation/202-prefer
Executable file
21
test/simulation/202-prefer
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
. test.common
|
||||
|
||||
# Test fix in commit 4253075a97141edfa62043ab71bd0673587e6629
|
||||
|
||||
test_start "prefer option"
|
||||
|
||||
servers=3
|
||||
client_server_conf="
|
||||
server 192.168.123.1
|
||||
server 192.168.123.2
|
||||
server 192.168.123.3 prefer"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_packet_interval || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
test_pass
|
||||
@@ -18,7 +18,7 @@ export PATH=../../:$PATH
|
||||
export CLKNETSIM_PATH=clknetsim
|
||||
|
||||
# Known working clknetsim revision
|
||||
clknetsim_revision=3eb3a8d9acf60c31f5acc66617175fc748ef367e
|
||||
clknetsim_revision=1e56224dee1db69c0027e9bd63c2a202d4765959
|
||||
clknetsim_url=https://github.com/mlichvar/clknetsim/archive/$clknetsim_revision.tar.gz
|
||||
|
||||
# Only Linux is supported
|
||||
@@ -65,10 +65,15 @@ default_chronyc_start=1000.0
|
||||
default_server_step=""
|
||||
default_client_step=""
|
||||
|
||||
default_client_server_conf=""
|
||||
default_server_server_options=""
|
||||
default_client_server_options=""
|
||||
default_server_peer_options=""
|
||||
default_server_lpeer_options=""
|
||||
default_server_rpeer_options=""
|
||||
default_client_peer_options=""
|
||||
default_client_lpeer_options=""
|
||||
default_client_rpeer_options=""
|
||||
default_server_conf=""
|
||||
default_client_conf=""
|
||||
default_chronyc_conf=""
|
||||
@@ -188,16 +193,22 @@ get_chronyd_conf() {
|
||||
done
|
||||
for i in $(seq 1 $peers); do
|
||||
[ $i -eq $peer -o $i -gt $servers ] && continue
|
||||
echo "peer 192.168.123.$[$servers * ($stratum - 1) + $i] $server_peer_options"
|
||||
echo -n "peer 192.168.123.$[$servers * ($stratum - 1) + $i] $server_peer_options "
|
||||
[ $i -lt $peer ] && echo "$server_lpeer_options" || echo "$server_rpeer_options"
|
||||
done
|
||||
echo "$server_conf"
|
||||
else
|
||||
for i in $(seq 1 $servers); do
|
||||
echo "server 192.168.123.$[$servers * ($stratum - 2) + $i] $client_server_options"
|
||||
done
|
||||
if [ -n "$client_server_conf" ]; then
|
||||
echo "$client_server_conf"
|
||||
else
|
||||
for i in $(seq 1 $servers); do
|
||||
echo "server 192.168.123.$[$servers * ($stratum - 2) + $i] $client_server_options"
|
||||
done
|
||||
fi
|
||||
for i in $(seq 1 $peers); do
|
||||
[ $i -eq $peer -o $i -gt $clients ] && continue
|
||||
echo "peer 192.168.123.$[$servers * ($stratum - 1) + $i] $client_peer_options"
|
||||
echo -n "peer 192.168.123.$[$servers * ($stratum - 1) + $i] $client_peer_options "
|
||||
[ $i -lt $peer ] && echo "$client_lpeer_options" || echo "$client_rpeer_options"
|
||||
done
|
||||
echo "$client_conf"
|
||||
fi
|
||||
|
||||
277
util.c
277
util.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2009, 2012-2014
|
||||
* Copyright (C) Miroslav Lichvar 2009, 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
|
||||
@@ -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)
|
||||
{
|
||||
@@ -643,6 +696,22 @@ UTI_IsTimeOffsetSane(struct timeval *tv, double offset)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
double
|
||||
UTI_Log2ToDouble(int l)
|
||||
{
|
||||
if (l >= 0) {
|
||||
if (l > 31)
|
||||
l = 31;
|
||||
return (uint32_t)1 << l;
|
||||
} else {
|
||||
if (l < -31)
|
||||
l = -31;
|
||||
return 1.0 / ((uint32_t)1 << -l);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
UTI_TimevalNetworkToHost(Timeval *src, struct timeval *dest)
|
||||
{
|
||||
@@ -707,7 +776,11 @@ UTI_FloatHostToNetwork(double x)
|
||||
if (x < 0.0) {
|
||||
x = -x;
|
||||
neg = 1;
|
||||
} else if (x >= 0.0) {
|
||||
neg = 0;
|
||||
} else {
|
||||
/* Save NaN as zero */
|
||||
x = 0.0;
|
||||
neg = 0;
|
||||
}
|
||||
|
||||
@@ -817,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;
|
||||
}
|
||||
|
||||
25
util.h
25
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);
|
||||
|
||||
@@ -107,6 +109,9 @@ extern void UTI_Int64ToTimeval(NTP_int64 *src, struct timeval *dest);
|
||||
/* Check if time + offset is sane */
|
||||
extern int UTI_IsTimeOffsetSane(struct timeval *tv, double offset);
|
||||
|
||||
/* Get 2 raised to power of a signed integer */
|
||||
extern double UTI_Log2ToDouble(int l);
|
||||
|
||||
extern void UTI_TimevalNetworkToHost(Timeval *src, struct timeval *dest);
|
||||
extern void UTI_TimevalHostToNetwork(struct timeval *src, Timeval *dest);
|
||||
|
||||
@@ -124,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