chiark / gitweb /
timesyncd: read server settings from a configuration file
authorLennart Poettering <lennart@poettering.net>
Tue, 6 May 2014 15:02:11 +0000 (17:02 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 6 May 2014 15:02:11 +0000 (17:02 +0200)
Also, allow compiling in a default server list via a configure command
line item.

Makefile.am
configure.ac
src/timesync/.gitignore [new file with mode: 0644]
src/timesync/Makefile [new symlink]
src/timesync/timesyncd-gperf.gperf [new file with mode: 0644]
src/timesync/timesyncd.c
src/timesync/timesyncd.conf.in [new file with mode: 0644]
src/timesync/timesyncd.h [new file with mode: 0644]

index cbb405b..dc5737e 100644 (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 $@
index ead697b..318d77b 100644 (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}
diff --git a/src/timesync/.gitignore b/src/timesync/.gitignore
new file mode 100644 (file)
index 0000000..35f4d76
--- /dev/null
@@ -0,0 +1,2 @@
+/timesyncd.conf
+/timesyncd-gperf.c
diff --git a/src/timesync/Makefile b/src/timesync/Makefile
new file mode 120000 (symlink)
index 0000000..d0b0e8e
--- /dev/null
@@ -0,0 +1 @@
+../Makefile
\ No newline at end of file
diff --git a/src/timesync/timesyncd-gperf.gperf b/src/timesync/timesyncd-gperf.gperf
new file mode 100644 (file)
index 0000000..887dc68
--- /dev/null
@@ -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
index f2206cc..6e38a2c 100644 (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
 #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 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;
-        const char *x;
         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;
 }
diff --git a/src/timesync/timesyncd.conf.in b/src/timesync/timesyncd.conf.in
new file mode 100644 (file)
index 0000000..a0caa1d
--- /dev/null
@@ -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@
diff --git a/src/timesync/timesyncd.h b/src/timesync/timesyncd.h
new file mode 100644 (file)
index 0000000..6dd1388
--- /dev/null
@@ -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);