]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/timesync/timesyncd.c
Merge pull request #7042 from vcaputo/iteratedcache
[thirdparty/systemd.git] / src / timesync / timesyncd.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
bcdbbd7e
KS
2/***
3 This file is part of systemd.
4
e8af6973 5 Copyright 2014 Kay Sievers, Lennart Poettering
bcdbbd7e
KS
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
687ed123 21#include "sd-daemon.h"
3ffd4af2
LP
22#include "sd-event.h"
23
430f0182 24#include "capability-util.h"
84e51726 25#include "clock-util.h"
3ffd4af2 26#include "fd-util.h"
f4f15635 27#include "fs-util.h"
53d133ea 28#include "mkdir.h"
84e51726 29#include "network-util.h"
df0ff127 30#include "process-util.h"
24882e06 31#include "signal-util.h"
84e51726 32#include "timesyncd-conf.h"
3ffd4af2 33#include "timesyncd-manager.h"
b1d4f8e1 34#include "user-util.h"
d636d376
KS
35
36static int load_clock_timestamp(uid_t uid, gid_t gid) {
ece6e766 37 _cleanup_close_ int fd = -1;
d636d376
KS
38 usec_t min = TIME_EPOCH * USEC_PER_SEC;
39 usec_t ct;
40 int r;
ece6e766
LP
41
42 /* Let's try to make sure that the clock is always
43 * monotonically increasing, by saving the clock whenever we
44 * have a new NTP time, or when we shut down, and restoring it
45 * when we start again. This is particularly helpful on
46 * systems lacking a battery backed RTC. We also will adjust
47 * the time to at least the build time of systemd. */
48
53d133ea 49 fd = open("/var/lib/systemd/timesync/clock", O_RDWR|O_CLOEXEC, 0644);
d636d376 50 if (fd >= 0) {
ece6e766 51 struct stat st;
d636d376
KS
52 usec_t stamp;
53
54 /* check if the recorded time is later than the compiled-in one */
55 r = fstat(fd, &st);
56 if (r >= 0) {
57 stamp = timespec_load(&st.st_mtim);
58 if (stamp > min)
59 min = stamp;
ece6e766
LP
60 }
61
53d133ea
YW
62 if (geteuid() == 0) {
63 /* Try to fix the access mode, so that we can still
64 touch the file after dropping priviliges */
65 r = fchmod(fd, 0644);
66 if (r < 0)
67 return log_error_errno(errno, "Failed to change file access mode: %m");
68 r = fchown(fd, uid, gid);
d1c2774b 69 if (r < 0)
53d133ea
YW
70 return log_error_errno(errno, "Failed to change file owner: %m");
71 }
72
73 } else {
48d3e88c 74 r = mkdir_safe_label("/var/lib/systemd/timesync", 0755, uid, gid, true);
53d133ea
YW
75 if (r < 0)
76 return log_error_errno(r, "Failed to create state directory: %m");
d636d376 77
d636d376 78 /* create stamp file with the compiled-in date */
53d133ea
YW
79 (void) touch_file("/var/lib/systemd/timesync/clock", false, min, uid, gid, 0644);
80 }
ece6e766
LP
81
82 ct = now(CLOCK_REALTIME);
d636d376 83 if (ct < min) {
ece6e766 84 struct timespec ts;
d636d376 85 char date[FORMAT_TIMESTAMP_MAX];
ece6e766 86
d636d376
KS
87 log_info("System clock time unset or jumped backwards, restoring from recorded timestamp: %s",
88 format_timestamp(date, sizeof(date), min));
ece6e766 89
d636d376 90 if (clock_settime(CLOCK_REALTIME, timespec_store(&ts, min)) < 0)
56f64d95 91 log_error_errno(errno, "Failed to restore system clock: %m");
ece6e766
LP
92 }
93
94 return 0;
95}
96
687ed123 97int main(int argc, char *argv[]) {
84e51726 98 _cleanup_(manager_freep) Manager *m = NULL;
cedc8c44 99 const char *user = "systemd-timesync";
444c1915 100 uid_t uid, uid_current;
ece6e766 101 gid_t gid;
687ed123
KS
102 int r;
103
104 log_set_target(LOG_TARGET_AUTO);
e8af6973 105 log_set_facility(LOG_CRON);
687ed123
KS
106 log_parse_environment();
107 log_open();
108
e8af6973
LP
109 umask(0022);
110
84e51726
LP
111 if (argc != 1) {
112 log_error("This program does not take arguments.");
113 r = -EINVAL;
114 goto finish;
115 }
116
444c1915
YW
117 uid = uid_current = geteuid();
118 gid = getegid();
119
120 if (uid_current == 0) {
121 r = get_user_creds(&user, &uid, &gid, NULL, NULL);
122 if (r < 0) {
123 log_error_errno(r, "Cannot resolve user name %s: %m", user);
124 goto finish;
125 }
ece6e766
LP
126 }
127
d636d376 128 r = load_clock_timestamp(uid, gid);
ece6e766 129 if (r < 0)
84e51726 130 goto finish;
ece6e766 131
87a85e25
YW
132 /* Drop privileges, but only if we have been started as root. If we are not running as root we assume all
133 * privileges are already dropped. */
444c1915 134 if (uid_current == 0) {
87a85e25
YW
135 r = drop_privileges(uid, gid, (1ULL << CAP_SYS_TIME));
136 if (r < 0)
137 goto finish;
138 }
a349eb10 139
72c0a2c2 140 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
856a5a7d 141
687ed123 142 r = manager_new(&m);
856a5a7d 143 if (r < 0) {
da927ba9 144 log_error_errno(r, "Failed to allocate manager: %m");
84e51726 145 goto finish;
856a5a7d 146 }
687ed123 147
6369641d 148 if (clock_is_localtime(NULL) > 0) {
c264aeab
KS
149 log_info("The system is configured to read the RTC time in the local time zone. "
150 "This mode can not be fully supported. All system time to RTC updates are disabled.");
151 m->rtc_local_time = true;
152 }
153
84e51726
LP
154 r = manager_parse_config_file(m);
155 if (r < 0)
da927ba9 156 log_warning_errno(r, "Failed to parse configuration file: %m");
e0e5ce23 157
c4c06912
LP
158 r = manager_parse_fallback_string(m, NTP_SERVERS);
159 if (r < 0) {
160 log_error_errno(r, "Failed to parse fallback server strings: %m");
161 goto finish;
162 }
3745770a 163
df0ff127 164 log_debug("systemd-timesyncd running as pid " PID_FMT, getpid_cached());
af4ec430
LP
165 sd_notify(false,
166 "READY=1\n"
167 "STATUS=Daemon is running");
39594d49 168
e0e5ce23
TG
169 if (network_is_online()) {
170 r = manager_connect(m);
171 if (r < 0)
84e51726 172 goto finish;
e0e5ce23 173 }
678522cf 174
687ed123 175 r = sd_event_loop(m->event);
856a5a7d 176 if (r < 0) {
da927ba9 177 log_error_errno(r, "Failed to run event loop: %m");
84e51726 178 goto finish;
856a5a7d
LP
179 }
180
d636d376
KS
181 /* if we got an authoritative time, store it in the file system */
182 if (m->sync)
53d133ea 183 (void) touch("/var/lib/systemd/timesync/clock");
687ed123 184
84e51726
LP
185 sd_event_get_exit_code(m->event, &r);
186
187finish:
af4ec430
LP
188 sd_notify(false,
189 "STOPPING=1\n"
190 "STATUS=Shutting down...");
e8af6973 191
687ed123 192 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
bcdbbd7e 193}