]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/timesync/timesyncd.c
Merge pull request #8552 from keszybz/test-improvements
[thirdparty/systemd.git] / src / timesync / timesyncd.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2014 Kay Sievers, Lennart Poettering
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
21 #include "sd-daemon.h"
22 #include "sd-event.h"
23
24 #include "capability-util.h"
25 #include "clock-util.h"
26 #include "fd-util.h"
27 #include "fs-util.h"
28 #include "mkdir.h"
29 #include "network-util.h"
30 #include "process-util.h"
31 #include "signal-util.h"
32 #include "timesyncd-conf.h"
33 #include "timesyncd-manager.h"
34 #include "user-util.h"
35
36 static int load_clock_timestamp(uid_t uid, gid_t gid) {
37 _cleanup_close_ int fd = -1;
38 usec_t min = TIME_EPOCH * USEC_PER_SEC;
39 usec_t ct;
40 int r;
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
49 fd = open("/var/lib/systemd/timesync/clock", O_RDWR|O_CLOEXEC, 0644);
50 if (fd >= 0) {
51 struct stat st;
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;
60 }
61
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);
69 if (r < 0)
70 return log_error_errno(errno, "Failed to change file owner: %m");
71 }
72
73 } else {
74 r = mkdir_safe_label("/var/lib/systemd/timesync", 0755, uid, gid,
75 MKDIR_FOLLOW_SYMLINK | MKDIR_WARN_MODE);
76 if (r < 0)
77 return log_error_errno(r, "Failed to create state directory: %m");
78
79 /* create stamp file with the compiled-in date */
80 (void) touch_file("/var/lib/systemd/timesync/clock", false, min, uid, gid, 0644);
81 }
82
83 ct = now(CLOCK_REALTIME);
84 if (ct < min) {
85 struct timespec ts;
86 char date[FORMAT_TIMESTAMP_MAX];
87
88 log_info("System clock time unset or jumped backwards, restoring from recorded timestamp: %s",
89 format_timestamp(date, sizeof(date), min));
90
91 if (clock_settime(CLOCK_REALTIME, timespec_store(&ts, min)) < 0)
92 log_error_errno(errno, "Failed to restore system clock: %m");
93 }
94
95 return 0;
96 }
97
98 int main(int argc, char *argv[]) {
99 _cleanup_(manager_freep) Manager *m = NULL;
100 const char *user = "systemd-timesync";
101 uid_t uid, uid_current;
102 gid_t gid;
103 int r;
104
105 log_set_target(LOG_TARGET_AUTO);
106 log_set_facility(LOG_CRON);
107 log_parse_environment();
108 log_open();
109
110 umask(0022);
111
112 if (argc != 1) {
113 log_error("This program does not take arguments.");
114 r = -EINVAL;
115 goto finish;
116 }
117
118 uid = uid_current = geteuid();
119 gid = getegid();
120
121 if (uid_current == 0) {
122 r = get_user_creds(&user, &uid, &gid, NULL, NULL);
123 if (r < 0) {
124 log_error_errno(r, "Cannot resolve user name %s: %m", user);
125 goto finish;
126 }
127 }
128
129 r = load_clock_timestamp(uid, gid);
130 if (r < 0)
131 goto finish;
132
133 /* Drop privileges, but only if we have been started as root. If we are not running as root we assume all
134 * privileges are already dropped. */
135 if (uid_current == 0) {
136 r = drop_privileges(uid, gid, (1ULL << CAP_SYS_TIME));
137 if (r < 0)
138 goto finish;
139 }
140
141 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
142
143 r = manager_new(&m);
144 if (r < 0) {
145 log_error_errno(r, "Failed to allocate manager: %m");
146 goto finish;
147 }
148
149 if (clock_is_localtime(NULL) > 0) {
150 log_info("The system is configured to read the RTC time in the local time zone. "
151 "This mode cannot be fully supported. All system time to RTC updates are disabled.");
152 m->rtc_local_time = true;
153 }
154
155 r = manager_parse_config_file(m);
156 if (r < 0)
157 log_warning_errno(r, "Failed to parse configuration file: %m");
158
159 r = manager_parse_fallback_string(m, NTP_SERVERS);
160 if (r < 0) {
161 log_error_errno(r, "Failed to parse fallback server strings: %m");
162 goto finish;
163 }
164
165 log_debug("systemd-timesyncd running as pid " PID_FMT, getpid_cached());
166 sd_notify(false,
167 "READY=1\n"
168 "STATUS=Daemon is running");
169
170 if (network_is_online()) {
171 r = manager_connect(m);
172 if (r < 0)
173 goto finish;
174 }
175
176 r = sd_event_loop(m->event);
177 if (r < 0) {
178 log_error_errno(r, "Failed to run event loop: %m");
179 goto finish;
180 }
181
182 /* if we got an authoritative time, store it in the file system */
183 if (m->sync)
184 (void) touch("/var/lib/systemd/timesync/clock");
185
186 sd_event_get_exit_code(m->event, &r);
187
188 finish:
189 sd_notify(false,
190 "STOPPING=1\n"
191 "STATUS=Shutting down...");
192
193 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
194 }