]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/timesync/timesyncd.c
src/basic: rename audit.[ch] → audit-util.[ch] and capability.[ch] → capability-util...
[thirdparty/systemd.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-daemon.h"
23 #include "sd-event.h"
24
25 #include "capability-util.h"
26 #include "clock-util.h"
27 #include "fd-util.h"
28 #include "fs-util.h"
29 #include "network-util.h"
30 #include "signal-util.h"
31 #include "timesyncd-conf.h"
32 #include "timesyncd-manager.h"
33 #include "user-util.h"
34
35 static int load_clock_timestamp(uid_t uid, gid_t gid) {
36 _cleanup_close_ int fd = -1;
37 usec_t min = TIME_EPOCH * USEC_PER_SEC;
38 usec_t ct;
39 int r;
40
41 /* Let's try to make sure that the clock is always
42 * monotonically increasing, by saving the clock whenever we
43 * have a new NTP time, or when we shut down, and restoring it
44 * when we start again. This is particularly helpful on
45 * systems lacking a battery backed RTC. We also will adjust
46 * the time to at least the build time of systemd. */
47
48 fd = open("/var/lib/systemd/clock", O_RDWR|O_CLOEXEC, 0644);
49 if (fd >= 0) {
50 struct stat st;
51 usec_t stamp;
52
53 /* check if the recorded time is later than the compiled-in one */
54 r = fstat(fd, &st);
55 if (r >= 0) {
56 stamp = timespec_load(&st.st_mtim);
57 if (stamp > min)
58 min = stamp;
59 }
60
61 /* Try to fix the access mode, so that we can still
62 touch the file after dropping priviliges */
63 (void) fchmod(fd, 0644);
64 (void) fchown(fd, uid, gid);
65
66 } else
67 /* create stamp file with the compiled-in date */
68 (void) touch_file("/var/lib/systemd/clock", true, min, uid, gid, 0644);
69
70 ct = now(CLOCK_REALTIME);
71 if (ct < min) {
72 struct timespec ts;
73 char date[FORMAT_TIMESTAMP_MAX];
74
75 log_info("System clock time unset or jumped backwards, restoring from recorded timestamp: %s",
76 format_timestamp(date, sizeof(date), min));
77
78 if (clock_settime(CLOCK_REALTIME, timespec_store(&ts, min)) < 0)
79 log_error_errno(errno, "Failed to restore system clock: %m");
80 }
81
82 return 0;
83 }
84
85 int main(int argc, char *argv[]) {
86 _cleanup_(manager_freep) Manager *m = NULL;
87 const char *user = "systemd-timesync";
88 uid_t uid;
89 gid_t gid;
90 int r;
91
92 log_set_target(LOG_TARGET_AUTO);
93 log_set_facility(LOG_CRON);
94 log_parse_environment();
95 log_open();
96
97 umask(0022);
98
99 if (argc != 1) {
100 log_error("This program does not take arguments.");
101 r = -EINVAL;
102 goto finish;
103 }
104
105 r = get_user_creds(&user, &uid, &gid, NULL, NULL);
106 if (r < 0) {
107 log_error_errno(r, "Cannot resolve user name %s: %m", user);
108 goto finish;
109 }
110
111 r = load_clock_timestamp(uid, gid);
112 if (r < 0)
113 goto finish;
114
115 r = drop_privileges(uid, gid, (1ULL << CAP_SYS_TIME));
116 if (r < 0)
117 goto finish;
118
119 assert_se(sigprocmask_many(SIG_BLOCK, NULL, 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 " PID_FMT, 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 (void) 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 }