chiark / gitweb /
fsckd: the error code is actually returned in 'fd'
[elogind.git] / src / timesync / timesyncd.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2014 Kay Sievers, Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include "sd-event.h"
23 #include "sd-daemon.h"
24 #include "capability.h"
25 #include "clock-util.h"
26 #include "network-util.h"
27
28 #include "timesyncd-manager.h"
29 #include "timesyncd-conf.h"
30
31 static int load_clock_timestamp(uid_t uid, gid_t gid) {
32         _cleanup_close_ int fd = -1;
33         usec_t min = TIME_EPOCH * USEC_PER_SEC;
34         usec_t ct;
35         int r;
36
37         /* Let's try to make sure that the clock is always
38          * monotonically increasing, by saving the clock whenever we
39          * have a new NTP time, or when we shut down, and restoring it
40          * when we start again. This is particularly helpful on
41          * systems lacking a battery backed RTC. We also will adjust
42          * the time to at least the build time of systemd. */
43
44         fd = open("/var/lib/systemd/clock", O_RDWR|O_CLOEXEC, 0644);
45         if (fd >= 0) {
46                 struct stat st;
47                 usec_t stamp;
48
49                 /* check if the recorded time is later than the compiled-in one */
50                 r = fstat(fd, &st);
51                 if (r >= 0) {
52                         stamp = timespec_load(&st.st_mtim);
53                         if (stamp > min)
54                                 min = stamp;
55                 }
56
57                 /* Try to fix the access mode, so that we can still
58                    touch the file after dropping priviliges */
59                 fchmod(fd, 0644);
60                 fchown(fd, uid, gid);
61
62         } else
63                 /* create stamp file with the compiled-in date */
64                 touch_file("/var/lib/systemd/clock", true, min, uid, gid, 0644);
65
66         ct = now(CLOCK_REALTIME);
67         if (ct < min) {
68                 struct timespec ts;
69                 char date[FORMAT_TIMESTAMP_MAX];
70
71                 log_info("System clock time unset or jumped backwards, restoring from recorded timestamp: %s",
72                          format_timestamp(date, sizeof(date), min));
73
74                 if (clock_settime(CLOCK_REALTIME, timespec_store(&ts, min)) < 0)
75                         log_error_errno(errno, "Failed to restore system clock: %m");
76         }
77
78         return 0;
79 }
80
81 int main(int argc, char *argv[]) {
82         _cleanup_(manager_freep) Manager *m = NULL;
83         const char *user = "systemd-timesync";
84         uid_t uid;
85         gid_t gid;
86         int r;
87
88         log_set_target(LOG_TARGET_AUTO);
89         log_set_facility(LOG_CRON);
90         log_parse_environment();
91         log_open();
92
93         umask(0022);
94
95         if (argc != 1) {
96                 log_error("This program does not take arguments.");
97                 r = -EINVAL;
98                 goto finish;
99         }
100
101         r = get_user_creds(&user, &uid, &gid, NULL, NULL);
102         if (r < 0) {
103                 log_error_errno(r, "Cannot resolve user name %s: %m", user);
104                 goto finish;
105         }
106
107         r = load_clock_timestamp(uid, gid);
108         if (r < 0)
109                 goto finish;
110
111         r = drop_privileges(uid, gid, (1ULL << CAP_SYS_TIME));
112         if (r < 0)
113                 goto finish;
114
115         /* We need one process for ourselves, plus one thread for the asynchronous resolver */
116         if (setrlimit(RLIMIT_NPROC, &RLIMIT_MAKE_CONST(2)) < 0)
117                 log_warning_errno(errno, "Failed to lower RLIMIT_NPROC to 2: %m");
118
119         assert_se(sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1) == 0);
120
121         r = manager_new(&m);
122         if (r < 0) {
123                 log_error_errno(r, "Failed to allocate manager: %m");
124                 goto finish;
125         }
126
127         if (clock_is_localtime() > 0) {
128                 log_info("The system is configured to read the RTC time in the local time zone. "
129                          "This mode can not be fully supported. All system time to RTC updates are disabled.");
130                 m->rtc_local_time = true;
131         }
132
133         r = manager_parse_config_file(m);
134         if (r < 0)
135                 log_warning_errno(r, "Failed to parse configuration file: %m");
136
137         log_debug("systemd-timesyncd running as pid %lu", (unsigned long) getpid());
138         sd_notify(false,
139                   "READY=1\n"
140                   "STATUS=Daemon is running");
141
142         if (network_is_online()) {
143                 r = manager_connect(m);
144                 if (r < 0)
145                         goto finish;
146         }
147
148         r = sd_event_loop(m->event);
149         if (r < 0) {
150                 log_error_errno(r, "Failed to run event loop: %m");
151                 goto finish;
152         }
153
154         /* if we got an authoritative time, store it in the file system */
155         if (m->sync)
156                 touch("/var/lib/systemd/clock");
157
158         sd_event_get_exit_code(m->event, &r);
159
160 finish:
161         sd_notify(false,
162                   "STOPPING=1\n"
163                   "STATUS=Shutting down...");
164
165         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
166 }