timesyncd: read server settings from a configuration file

Also, allow compiling in a default server list via a configure command
line item.
This commit is contained in:
Lennart Poettering 2014-05-06 17:02:11 +02:00
parent 16c058ba01
commit e8af69739a
8 changed files with 254 additions and 81 deletions

View File

@ -128,6 +128,7 @@ polkitpolicy_in_files =
polkitpolicy_files =
dist_udevrules_DATA =
nodist_udevrules_DATA =
nodist_pkgsysconf_DATA =
dist_pkgsysconf_DATA =
dist_pkgdata_DATA =
dist_dbuspolicy_DATA =
@ -4017,7 +4018,17 @@ EXTRA_DIST += \
# ------------------------------------------------------------------------------
if ENABLE_TIMESYNCD
systemd_timesyncd_SOURCES = \
src/timesync/timesyncd.c
src/timesync/timesyncd.c \
src/timesync/timesyncd.h
nodist_systemd_timesyncd_SOURCES = \
src/timesync/timesyncd-gperf.c
EXTRA_DIST += \
src/timesync/timesyncd-gperf.gperf
CLEANFILES += \
src/timesync/timesyncd-gperf.c
systemd_timesyncd_LDADD = \
libsystemd-label.la \
@ -4034,6 +4045,16 @@ nodist_systemunit_DATA += \
EXTRA_DIST += \
units/systemd-timesyncd.service.in
nodist_pkgsysconf_DATA += \
src/timesync/timesyncd.conf
EXTRA_DIST += \
src/timesync/timesyncd.conf.in
CLEANFILES += \
src/timesync/timesyncd.conf
endif
# ------------------------------------------------------------------------------
@ -4763,7 +4784,8 @@ substitutions = \
'|RC_LOCAL_SCRIPT_PATH_START=$(RC_LOCAL_SCRIPT_PATH_START)|' \
'|RC_LOCAL_SCRIPT_PATH_STOP=$(RC_LOCAL_SCRIPT_PATH_STOP)|' \
'|PYTHON=$(PYTHON)|' \
'|PYTHON_BINARY=$(PYTHON_BINARY)|'
'|PYTHON_BINARY=$(PYTHON_BINARY)|' \
'|NTP_SERVERS=$(NTP_SERVERS)|'
SED_PROCESS = \
$(AM_V_GEN)$(MKDIR_P) $(dir $@) && \
@ -4791,6 +4813,9 @@ src/%.policy.in: src/%.policy.in.in
%.rules: %.rules.in
$(SED_PROCESS)
%.conf: %.conf.in
$(SED_PROCESS)
%.sh: %.sh.in
$(SED_PROCESS)
$(AM_V_GEN)chmod +x $@

View File

@ -827,6 +827,15 @@ if test "x$enable_timesyncd" != "xno"; then
fi
AM_CONDITIONAL(ENABLE_TIMESYNCD, [test "$have_timesyncd" = "yes"])
AC_ARG_WITH(ntp-servers,
AS_HELP_STRING([--with-ntp-servers=NTPSERVERS],
[Space-separated list of default NTP servers]),
[NTP_SERVERS="$withval"],
[NTP_SERVERS="time1.google.com time2.google.com time3.google.com time4.google.com"])
AC_DEFINE_UNQUOTED(NTP_SERVERS, ["$NTP_SERVERS"], [Default NTP Servers])
AC_SUBST(NTP_SERVERS)
# ------------------------------------------------------------------------------
have_localed=no
AC_ARG_ENABLE(localed, AS_HELP_STRING([--disable-localed], [disable locale daemon]))
@ -1159,6 +1168,7 @@ AC_MSG_RESULT([
hostnamed: ${have_hostnamed}
timedated: ${have_timedated}
timesyncd: ${have_timesyncd}
default NTP servers: ${NTP_SERVERS}
localed: ${have_localed}
networkd: ${have_networkd}
coredump: ${have_coredump}

2
src/timesync/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/timesyncd.conf
/timesyncd-gperf.c

1
src/timesync/Makefile Symbolic link
View File

@ -0,0 +1 @@
../Makefile

View File

@ -0,0 +1,17 @@
%{
#include <stddef.h>
#include "conf-parser.h"
#include "timesyncd.h"
%}
struct ConfigPerfItem;
%null_strings
%language=ANSI-C
%define slot-name section_and_lvalue
%define hash-function-name timesyncdd_gperf_hash
%define lookup-function-name timesyncd_gperf_lookup
%readonly-tables
%omit-struct-type
%struct-type
%includes
%%
Time.Servers, config_parse_servers, 0, 0

View File

@ -3,7 +3,7 @@
/***
This file is part of systemd.
Copyright 2014 Kay Sievers
Copyright 2014 Kay Sievers, Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
@ -42,9 +42,11 @@
#include "list.h"
#include "ratelimit.h"
#include "strv.h"
#include "conf-parser.h"
#include "sd-event.h"
#include "sd-resolve.h"
#include "sd-daemon.h"
#include "timesyncd.h"
#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
@ -116,73 +118,6 @@ struct ntp_msg {
struct ntp_ts trans_time;
} _packed_;
typedef struct Manager Manager;
typedef struct ServerAddress ServerAddress;
typedef struct ServerName ServerName;
struct ServerAddress {
union sockaddr_union sockaddr;
socklen_t socklen;
LIST_FIELDS(ServerAddress, addresses);
};
struct ServerName {
char *string;
LIST_HEAD(ServerAddress, addresses);
LIST_FIELDS(ServerName, names);
};
struct Manager {
sd_event *event;
sd_resolve *resolve;
LIST_HEAD(ServerName, servers);
RateLimit ratelimit;
/* peer */
sd_resolve_query *resolve_query;
sd_event_source *event_receive;
ServerName *current_server_name;
ServerAddress *current_server_address;
int server_socket;
uint64_t packet_count;
sd_event_source *event_timeout;
/* last sent packet */
struct timespec trans_time_mon;
struct timespec trans_time;
usec_t retry_interval;
bool pending;
/* poll timer */
sd_event_source *event_timer;
usec_t poll_interval_usec;
bool poll_resync;
/* history data */
struct {
double offset;
double delay;
} samples[8];
unsigned int samples_idx;
double samples_jitter;
/* last change */
bool jumped;
int drift_ppm;
/* watch for time changes */
sd_event_source *event_clock_watch;
int clock_watch_fd;
/* Retry connections */
sd_event_source *event_retry;
/* Handle SIGINT/SIGTERM */
sd_event_source *sigterm, *sigint;
};
static void manager_free(Manager *m);
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
#define _cleanup_manager_free_ _cleanup_(manager_freep)
@ -974,6 +909,28 @@ static int manager_add_server(Manager *m, const char *server) {
return 0;
}
static int manager_add_server_string(Manager *m, const char *string) {
char *w, *state;
size_t l;
int r;
assert(m);
assert(string);
FOREACH_WORD_QUOTED(w, l, string, state) {
char t[l+1];
memcpy(t, w, l);
t[l] = 0;
r = manager_add_server(m, t);
if (r < 0)
log_error("Failed to add server %s to configuration, ignoring: %s", t, strerror(-r));
}
return 0;
}
static void manager_disconnect(Manager *m) {
assert(m);
@ -1047,15 +1004,70 @@ static void manager_free(Manager *m) {
free(m);
}
int main(int argc, char *argv[]) {
_cleanup_manager_free_ Manager *m = NULL;
const char *x;
int config_parse_servers(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
Manager *m = userdata;
assert(filename);
assert(lvalue);
assert(rvalue);
manager_flush_names(m);
manager_add_server_string(m, rvalue);
return 0;
}
static int manager_parse_config_file(Manager *m) {
static const char fn[] = "/etc/systemd/timesyncd.conf";
_cleanup_fclose_ FILE *f = NULL;
int r;
assert(m);
f = fopen(fn, "re");
if (!f) {
if (errno == ENOENT)
return 0;
log_warning("Failed to open configuration file %s: %m", fn);
return -errno;
}
r = config_parse(NULL, fn, f, "Time\0", config_item_perf_lookup,
(void*) timesyncd_gperf_lookup, false, false, m);
if (r < 0)
log_warning("Failed to parse configuration file: %s", strerror(-r));
return r;
}
int main(int argc, char *argv[]) {
_cleanup_manager_free_ Manager *m = NULL;
int r;
if (argc > 1) {
log_error("This program does not take arguments.");
return EXIT_FAILURE;
}
log_set_target(LOG_TARGET_AUTO);
log_set_facility(LOG_CRON);
log_parse_environment();
log_open();
umask(0022);
assert_se(sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1) == 0);
r = manager_new(&m);
@ -1064,15 +1076,11 @@ int main(int argc, char *argv[]) {
goto out;
}
sd_notify(false, "READY=1");
manager_add_server_string(m, NTP_SERVERS);
manager_parse_config_file(m);
FOREACH_STRING(x, "8.8.8.8", "172.31.0.1", "time1.google.com", "time2.google.com", "time3.google.com", "time4.google.com", "0.fedora.pool.ntp.org") {
r = manager_add_server(m, x);
if (r < 0) {
log_error("Failed to add server %s: %s", x, strerror(-r));
goto out;
}
}
log_debug("systemd-timesyncd running as pid %lu", (unsigned long) getpid());
sd_notify(false, "READY=1");
r = manager_connect(m);
if (r < 0)
@ -1087,5 +1095,7 @@ int main(int argc, char *argv[]) {
sd_event_get_exit_code(m->event, &r);
out:
sd_notify(false, "STATUS=Shutting down...");
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}

View File

@ -0,0 +1,11 @@
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# See timesyncd.conf(5) for details
[Time]
#Servers=@NTP_SERVERS@

97
src/timesync/timesyncd.h Normal file
View File

@ -0,0 +1,97 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2014 Kay Sievers, Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "list.h"
#include "socket-util.h"
#include "ratelimit.h"
#include "sd-event.h"
#include "sd-resolve.h"
typedef struct Manager Manager;
typedef struct ServerAddress ServerAddress;
typedef struct ServerName ServerName;
struct ServerAddress {
union sockaddr_union sockaddr;
socklen_t socklen;
LIST_FIELDS(ServerAddress, addresses);
};
struct ServerName {
char *string;
LIST_HEAD(ServerAddress, addresses);
LIST_FIELDS(ServerName, names);
};
struct Manager {
sd_event *event;
sd_resolve *resolve;
LIST_HEAD(ServerName, servers);
RateLimit ratelimit;
/* peer */
sd_resolve_query *resolve_query;
sd_event_source *event_receive;
ServerName *current_server_name;
ServerAddress *current_server_address;
int server_socket;
uint64_t packet_count;
sd_event_source *event_timeout;
/* last sent packet */
struct timespec trans_time_mon;
struct timespec trans_time;
usec_t retry_interval;
bool pending;
/* poll timer */
sd_event_source *event_timer;
usec_t poll_interval_usec;
bool poll_resync;
/* history data */
struct {
double offset;
double delay;
} samples[8];
unsigned int samples_idx;
double samples_jitter;
/* last change */
bool jumped;
int drift_ppm;
/* watch for time changes */
sd_event_source *event_clock_watch;
int clock_watch_fd;
/* Retry connections */
sd_event_source *event_retry;
/* Handle SIGINT/SIGTERM */
sd_event_source *sigterm, *sigint;
};
const struct ConfigPerfItem* timesyncd_gperf_lookup(const char *key, unsigned length);
int config_parse_servers(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);