]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/timedate/timedated.c
Merge pull request #18007 from fw-strlen/ipv6_masq_and_dnat
[thirdparty/systemd.git] / src / timedate / timedated.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4 #include <sys/stat.h>
5 #include <sys/types.h>
6 #include <unistd.h>
7
8 #include "sd-bus.h"
9 #include "sd-event.h"
10 #include "sd-messages.h"
11
12 #include "alloc-util.h"
13 #include "bus-common-errors.h"
14 #include "bus-error.h"
15 #include "bus-get-properties.h"
16 #include "bus-locator.h"
17 #include "bus-log-control-api.h"
18 #include "bus-map-properties.h"
19 #include "bus-polkit.h"
20 #include "clock-util.h"
21 #include "conf-files.h"
22 #include "def.h"
23 #include "fd-util.h"
24 #include "fileio-label.h"
25 #include "fileio.h"
26 #include "fs-util.h"
27 #include "hashmap.h"
28 #include "list.h"
29 #include "main-func.h"
30 #include "memory-util.h"
31 #include "missing_capability.h"
32 #include "path-util.h"
33 #include "selinux-util.h"
34 #include "service-util.h"
35 #include "signal-util.h"
36 #include "string-util.h"
37 #include "strv.h"
38 #include "unit-def.h"
39 #include "unit-name.h"
40 #include "user-util.h"
41
42 #define NULL_ADJTIME_UTC "0.0 0 0\n0\nUTC\n"
43 #define NULL_ADJTIME_LOCAL "0.0 0 0\n0\nLOCAL\n"
44
45 #define UNIT_LIST_DIRS (const char* const*) CONF_PATHS_STRV("systemd/ntp-units.d")
46
47 typedef struct UnitStatusInfo {
48 char *name;
49 char *load_state;
50 char *unit_file_state;
51 char *active_state;
52 char *path;
53
54 LIST_FIELDS(struct UnitStatusInfo, units);
55 } UnitStatusInfo;
56
57 typedef struct Context {
58 char *zone;
59 bool local_rtc;
60 Hashmap *polkit_registry;
61 sd_bus_message *cache;
62
63 sd_bus_slot *slot_job_removed;
64
65 LIST_HEAD(UnitStatusInfo, units);
66 } Context;
67
68 #define log_unit_full(unit, level, error, ...) \
69 ({ \
70 const UnitStatusInfo *_u = (unit); \
71 log_object_internal(level, error, PROJECT_FILE, __LINE__, __func__, \
72 "UNIT=", _u->name, NULL, NULL, ##__VA_ARGS__); \
73 })
74
75 #define log_unit_debug(unit, ...) log_unit_full(unit, LOG_DEBUG, 0, ##__VA_ARGS__)
76 #define log_unit_info(unit, ...) log_unit_full(unit, LOG_INFO, 0, ##__VA_ARGS__)
77 #define log_unit_notice(unit, ...) log_unit_full(unit, LOG_NOTICE, 0, ##__VA_ARGS__)
78 #define log_unit_warning(unit, ...) log_unit_full(unit, LOG_WARNING, 0, ##__VA_ARGS__)
79 #define log_unit_error(unit, ...) log_unit_full(unit, LOG_ERR, 0, ##__VA_ARGS__)
80
81 #define log_unit_debug_errno(unit, error, ...) log_unit_full(unit, LOG_DEBUG, error, ##__VA_ARGS__)
82 #define log_unit_info_errno(unit, error, ...) log_unit_full(unit, LOG_INFO, error, ##__VA_ARGS__)
83 #define log_unit_notice_errno(unit, error, ...) log_unit_full(unit, LOG_NOTICE, error, ##__VA_ARGS__)
84 #define log_unit_warning_errno(unit, error, ...) log_unit_full(unit, LOG_WARNING, error, ##__VA_ARGS__)
85 #define log_unit_error_errno(unit, error, ...) log_unit_full(unit, LOG_ERR, error, ##__VA_ARGS__)
86
87 static void unit_status_info_clear(UnitStatusInfo *p) {
88 assert(p);
89
90 p->load_state = mfree(p->load_state);
91 p->unit_file_state = mfree(p->unit_file_state);
92 p->active_state = mfree(p->active_state);
93 }
94
95 static void unit_status_info_free(UnitStatusInfo *p) {
96 assert(p);
97
98 unit_status_info_clear(p);
99 free(p->name);
100 free(p->path);
101 free(p);
102 }
103
104 static void context_clear(Context *c) {
105 UnitStatusInfo *p;
106
107 assert(c);
108
109 free(c->zone);
110 bus_verify_polkit_async_registry_free(c->polkit_registry);
111 sd_bus_message_unref(c->cache);
112
113 sd_bus_slot_unref(c->slot_job_removed);
114
115 while ((p = c->units)) {
116 LIST_REMOVE(units, c->units, p);
117 unit_status_info_free(p);
118 }
119 }
120
121 static int context_add_ntp_service(Context *c, const char *s, const char *source) {
122 UnitStatusInfo *u;
123
124 if (!unit_name_is_valid(s, UNIT_NAME_PLAIN))
125 return -EINVAL;
126
127 /* Do not add this if it is already listed */
128 LIST_FOREACH(units, u, c->units)
129 if (streq(u->name, s))
130 return 0;
131
132 u = new0(UnitStatusInfo, 1);
133 if (!u)
134 return -ENOMEM;
135
136 u->name = strdup(s);
137 if (!u->name) {
138 free(u);
139 return -ENOMEM;
140 }
141
142 LIST_APPEND(units, c->units, u);
143 log_unit_debug(u, "added from %s.", source);
144
145 return 0;
146 }
147
148 static int context_parse_ntp_services_from_environment(Context *c) {
149 const char *env, *p;
150 int r;
151
152 assert(c);
153
154 env = getenv("SYSTEMD_TIMEDATED_NTP_SERVICES");
155 if (!env)
156 return 0;
157
158 log_debug("Using list of ntp services from environment variable $SYSTEMD_TIMEDATED_NTP_SERVICES=%s.", env);
159
160 for (p = env;;) {
161 _cleanup_free_ char *word = NULL;
162
163 r = extract_first_word(&p, &word, ":", 0);
164 if (r == 0)
165 break;
166 if (r == -ENOMEM)
167 return log_oom();
168 if (r < 0) {
169 log_error("Invalid syntax, ignoring: %s", env);
170 break;
171 }
172
173 r = context_add_ntp_service(c, word, "$SYSTEMD_TIMEDATED_NTP_SERVICES");
174 if (r < 0)
175 log_warning_errno(r, "Failed to add NTP service \"%s\", ignoring: %m", word);
176 }
177
178 return 1;
179 }
180
181 static int context_parse_ntp_services_from_disk(Context *c) {
182 _cleanup_strv_free_ char **files = NULL;
183 char **f;
184 int r;
185
186 r = conf_files_list_strv(&files, ".list", NULL, CONF_FILES_FILTER_MASKED, UNIT_LIST_DIRS);
187 if (r < 0)
188 return log_error_errno(r, "Failed to enumerate .list files: %m");
189
190 STRV_FOREACH(f, files) {
191 _cleanup_fclose_ FILE *file = NULL;
192
193 log_debug("Reading file '%s'", *f);
194
195 r = fopen_unlocked(*f, "re", &file);
196 if (r < 0) {
197 log_error_errno(r, "Failed to open %s, ignoring: %m", *f);
198 continue;
199 }
200
201 for (;;) {
202 _cleanup_free_ char *line = NULL;
203 const char *word;
204
205 r = read_line(file, LINE_MAX, &line);
206 if (r < 0) {
207 log_error_errno(r, "Failed to read %s, ignoring: %m", *f);
208 continue;
209 }
210 if (r == 0)
211 break;
212
213 word = strstrip(line);
214 if (isempty(word) || startswith("#", word))
215 continue;
216
217 r = context_add_ntp_service(c, word, *f);
218 if (r < 0)
219 log_warning_errno(r, "Failed to add NTP service \"%s\", ignoring: %m", word);
220 }
221 }
222
223 return 1;
224 }
225
226 static int context_parse_ntp_services(Context *c) {
227 int r;
228
229 r = context_parse_ntp_services_from_environment(c);
230 if (r != 0)
231 return r;
232
233 return context_parse_ntp_services_from_disk(c);
234 }
235
236 static int context_ntp_service_is_active(Context *c) {
237 UnitStatusInfo *info;
238 int count = 0;
239
240 assert(c);
241
242 /* Call context_update_ntp_status() to update UnitStatusInfo before calling this. */
243
244 LIST_FOREACH(units, info, c->units)
245 count += !STRPTR_IN_SET(info->active_state, "inactive", "failed");
246
247 return count;
248 }
249
250 static int context_ntp_service_exists(Context *c) {
251 UnitStatusInfo *info;
252 int count = 0;
253
254 assert(c);
255
256 /* Call context_update_ntp_status() to update UnitStatusInfo before calling this. */
257
258 LIST_FOREACH(units, info, c->units)
259 count += streq_ptr(info->load_state, "loaded");
260
261 return count;
262 }
263
264 static int context_read_data(Context *c) {
265 _cleanup_free_ char *t = NULL;
266 int r;
267
268 assert(c);
269
270 r = get_timezone(&t);
271 if (r == -EINVAL)
272 log_warning_errno(r, "/etc/localtime should be a symbolic link to a time zone data file in /usr/share/zoneinfo/.");
273 else if (r < 0)
274 log_warning_errno(r, "Failed to get target of /etc/localtime: %m");
275
276 free_and_replace(c->zone, t);
277
278 c->local_rtc = clock_is_localtime(NULL) > 0;
279
280 return 0;
281 }
282
283 static int context_write_data_timezone(Context *c) {
284 _cleanup_free_ char *p = NULL;
285 const char *source;
286
287 assert(c);
288
289 /* No timezone is very similar to UTC. Hence in either of these cases link the UTC file in. Except if
290 * it isn't installed, in which case we remove the symlink altogether. Since glibc defaults to an
291 * internal version of UTC in that case behaviour is mostly equivalent. We still prefer creating the
292 * symlink though, since things are more self explanatory then. */
293
294 if (isempty(c->zone) || streq(c->zone, "UTC")) {
295
296 if (access("/usr/share/zoneinfo/UTC", F_OK) < 0) {
297
298 if (unlink("/etc/localtime") < 0 && errno != ENOENT)
299 return -errno;
300
301 return 0;
302 }
303
304 source = "../usr/share/zoneinfo/UTC";
305 } else {
306 p = path_join("../usr/share/zoneinfo", c->zone);
307 if (!p)
308 return -ENOMEM;
309
310 source = p;
311 }
312
313 return symlink_atomic(source, "/etc/localtime");
314 }
315
316 static int context_write_data_local_rtc(Context *c) {
317 _cleanup_free_ char *s = NULL, *w = NULL;
318 int r;
319
320 assert(c);
321
322 r = read_full_file("/etc/adjtime", &s, NULL);
323 if (r < 0) {
324 if (r != -ENOENT)
325 return r;
326
327 if (!c->local_rtc)
328 return 0;
329
330 w = strdup(NULL_ADJTIME_LOCAL);
331 if (!w)
332 return -ENOMEM;
333 } else {
334 char *p;
335 const char *e = "\n"; /* default if there is less than 3 lines */
336 const char *prepend = "";
337 size_t a, b;
338
339 p = strchrnul(s, '\n');
340 if (*p == '\0')
341 /* only one line, no \n terminator */
342 prepend = "\n0\n";
343 else if (p[1] == '\0') {
344 /* only one line, with \n terminator */
345 ++p;
346 prepend = "0\n";
347 } else {
348 p = strchr(p+1, '\n');
349 if (!p) {
350 /* only two lines, no \n terminator */
351 prepend = "\n";
352 p = s + strlen(s);
353 } else {
354 char *end;
355 /* third line might have a \n terminator or not */
356 p++;
357 end = strchr(p, '\n');
358 /* if we actually have a fourth line, use that as suffix "e", otherwise the default \n */
359 if (end)
360 e = end;
361 }
362 }
363
364 a = p - s;
365 b = strlen(e);
366
367 w = new(char, a + (c->local_rtc ? 5 : 3) + strlen(prepend) + b + 1);
368 if (!w)
369 return -ENOMEM;
370
371 *(char*) mempcpy(stpcpy(stpcpy(mempcpy(w, s, a), prepend), c->local_rtc ? "LOCAL" : "UTC"), e, b) = 0;
372
373 if (streq(w, NULL_ADJTIME_UTC)) {
374 if (unlink("/etc/adjtime") < 0)
375 if (errno != ENOENT)
376 return -errno;
377
378 return 0;
379 }
380 }
381
382 r = mac_selinux_init();
383 if (r < 0)
384 return r;
385
386 return write_string_file_atomic_label("/etc/adjtime", w);
387 }
388
389 static int context_update_ntp_status(Context *c, sd_bus *bus, sd_bus_message *m) {
390 static const struct bus_properties_map map[] = {
391 { "LoadState", "s", NULL, offsetof(UnitStatusInfo, load_state) },
392 { "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state) },
393 { "UnitFileState", "s", NULL, offsetof(UnitStatusInfo, unit_file_state) },
394 {}
395 };
396 UnitStatusInfo *u;
397 int r;
398
399 assert(c);
400 assert(bus);
401
402 /* Suppress calling context_update_ntp_status() multiple times within single DBus transaction. */
403 if (m) {
404 if (m == c->cache)
405 return 0;
406
407 sd_bus_message_unref(c->cache);
408 c->cache = sd_bus_message_ref(m);
409 }
410
411 LIST_FOREACH(units, u, c->units) {
412 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
413 _cleanup_free_ char *path = NULL;
414
415 unit_status_info_clear(u);
416
417 path = unit_dbus_path_from_name(u->name);
418 if (!path)
419 return -ENOMEM;
420
421 r = bus_map_all_properties(
422 bus,
423 "org.freedesktop.systemd1",
424 path,
425 map,
426 BUS_MAP_STRDUP,
427 &error,
428 NULL,
429 u);
430 if (r < 0)
431 return log_unit_error_errno(u, r, "Failed to get properties: %s", bus_error_message(&error, r));
432 }
433
434 return 0;
435 }
436
437 static int match_job_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
438 Context *c = userdata;
439 UnitStatusInfo *u;
440 const char *path;
441 unsigned n = 0;
442 int r;
443
444 assert(c);
445 assert(m);
446
447 r = sd_bus_message_read(m, "uoss", NULL, &path, NULL, NULL);
448 if (r < 0) {
449 bus_log_parse_error(r);
450 return 0;
451 }
452
453 LIST_FOREACH(units, u, c->units)
454 if (streq_ptr(path, u->path))
455 u->path = mfree(u->path);
456 else
457 n += !!u->path;
458
459 if (n == 0) {
460 c->slot_job_removed = sd_bus_slot_unref(c->slot_job_removed);
461
462 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m),
463 "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "NTP",
464 NULL);
465 }
466
467 return 0;
468 }
469
470 static int unit_start_or_stop(UnitStatusInfo *u, sd_bus *bus, sd_bus_error *error, bool start) {
471 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
472 const char *path;
473 int r;
474
475 assert(u);
476 assert(bus);
477 assert(error);
478
479 r = bus_call_method(
480 bus,
481 bus_systemd_mgr,
482 start ? "StartUnit" : "StopUnit",
483 error,
484 &reply,
485 "ss",
486 u->name,
487 "replace");
488 log_unit_full(u, r < 0 ? LOG_WARNING : LOG_DEBUG, r,
489 "%s unit: %m", start ? "Starting" : "Stopping");
490 if (r < 0)
491 return r;
492
493 r = sd_bus_message_read(reply, "o", &path);
494 if (r < 0)
495 return bus_log_parse_error(r);
496
497 r = free_and_strdup(&u->path, path);
498 if (r < 0)
499 return log_oom();
500
501 return 0;
502 }
503
504 static int unit_enable_or_disable(UnitStatusInfo *u, sd_bus *bus, sd_bus_error *error, bool enable) {
505 int r;
506
507 assert(u);
508 assert(bus);
509 assert(error);
510
511 /* Call context_update_ntp_status() to update UnitStatusInfo before calling this. */
512
513 if (streq(u->unit_file_state, "enabled") == enable) {
514 log_unit_debug(u, "already %sd.", enable_disable(enable));
515 return 0;
516 }
517
518 log_unit_info(u, "%s unit.", enable ? "Enabling" : "Disabling");
519
520 if (enable)
521 r = bus_call_method(
522 bus,
523 bus_systemd_mgr,
524 "EnableUnitFiles",
525 error,
526 NULL,
527 "asbb", 1,
528 u->name,
529 false, true);
530 else
531 r = bus_call_method(
532 bus,
533 bus_systemd_mgr,
534 "DisableUnitFiles",
535 error,
536 NULL,
537 "asb", 1,
538 u->name,
539 false);
540 if (r < 0)
541 return r;
542
543 r = bus_call_method(bus, bus_systemd_mgr, "Reload", error, NULL, NULL);
544 if (r < 0)
545 return r;
546
547 return 0;
548 }
549
550 static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_time, "t", now(CLOCK_REALTIME));
551 static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_ntp_sync, "b", ntp_synced());
552
553 static int property_get_rtc_time(
554 sd_bus *bus,
555 const char *path,
556 const char *interface,
557 const char *property,
558 sd_bus_message *reply,
559 void *userdata,
560 sd_bus_error *error) {
561
562 struct tm tm = {};
563 usec_t t = 0;
564 int r;
565
566 r = clock_get_hwclock(&tm);
567 if (r == -EBUSY)
568 log_warning("/dev/rtc is busy. Is somebody keeping it open continuously? That's not a good idea... Returning a bogus RTC timestamp.");
569 else if (r == -ENOENT)
570 log_debug("/dev/rtc not found.");
571 else if (r < 0)
572 return sd_bus_error_set_errnof(error, r, "Failed to read RTC: %m");
573 else
574 t = (usec_t) timegm(&tm) * USEC_PER_SEC;
575
576 return sd_bus_message_append(reply, "t", t);
577 }
578
579 static int property_get_can_ntp(
580 sd_bus *bus,
581 const char *path,
582 const char *interface,
583 const char *property,
584 sd_bus_message *reply,
585 void *userdata,
586 sd_bus_error *error) {
587
588 Context *c = userdata;
589 int r;
590
591 assert(c);
592 assert(bus);
593 assert(property);
594 assert(reply);
595 assert(error);
596
597 if (c->slot_job_removed)
598 /* When the previous request is not finished, then assume NTP is enabled. */
599 return sd_bus_message_append(reply, "b", true);
600
601 r = context_update_ntp_status(c, bus, reply);
602 if (r < 0)
603 return r;
604
605 return sd_bus_message_append(reply, "b", context_ntp_service_exists(c) > 0);
606 }
607
608 static int property_get_ntp(
609 sd_bus *bus,
610 const char *path,
611 const char *interface,
612 const char *property,
613 sd_bus_message *reply,
614 void *userdata,
615 sd_bus_error *error) {
616
617 Context *c = userdata;
618 int r;
619
620 assert(c);
621 assert(bus);
622 assert(property);
623 assert(reply);
624 assert(error);
625
626 if (c->slot_job_removed)
627 /* When the previous request is not finished, then assume NTP is active. */
628 return sd_bus_message_append(reply, "b", true);
629
630 r = context_update_ntp_status(c, bus, reply);
631 if (r < 0)
632 return r;
633
634 return sd_bus_message_append(reply, "b", context_ntp_service_is_active(c) > 0);
635 }
636
637 static int method_set_timezone(sd_bus_message *m, void *userdata, sd_bus_error *error) {
638 Context *c = userdata;
639 int interactive, r;
640 const char *z;
641
642 assert(m);
643 assert(c);
644
645 r = sd_bus_message_read(m, "sb", &z, &interactive);
646 if (r < 0)
647 return r;
648
649 if (!timezone_is_valid(z, LOG_DEBUG))
650 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid or not installed time zone '%s'", z);
651
652 if (streq_ptr(z, c->zone))
653 return sd_bus_reply_method_return(m, NULL);
654
655 r = bus_verify_polkit_async(
656 m,
657 CAP_SYS_TIME,
658 "org.freedesktop.timedate1.set-timezone",
659 NULL,
660 interactive,
661 UID_INVALID,
662 &c->polkit_registry,
663 error);
664 if (r < 0)
665 return r;
666 if (r == 0)
667 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
668
669 r = free_and_strdup(&c->zone, z);
670 if (r < 0)
671 return r;
672
673 /* 1. Write new configuration file */
674 r = context_write_data_timezone(c);
675 if (r < 0) {
676 log_error_errno(r, "Failed to set time zone: %m");
677 return sd_bus_error_set_errnof(error, r, "Failed to set time zone: %m");
678 }
679
680 /* 2. Make glibc notice the new timezone */
681 tzset();
682
683 /* 3. Tell the kernel our timezone */
684 r = clock_set_timezone(NULL);
685 if (r < 0)
686 log_debug_errno(r, "Failed to tell kernel about timezone, ignoring: %m");
687
688 if (c->local_rtc) {
689 struct timespec ts;
690 struct tm tm;
691
692 /* 4. Sync RTC from system clock, with the new delta */
693 assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
694 assert_se(localtime_r(&ts.tv_sec, &tm));
695
696 r = clock_set_hwclock(&tm);
697 if (r < 0)
698 log_debug_errno(r, "Failed to sync time to hardware clock, ignoring: %m");
699 }
700
701 log_struct(LOG_INFO,
702 "MESSAGE_ID=" SD_MESSAGE_TIMEZONE_CHANGE_STR,
703 "TIMEZONE=%s", c->zone,
704 "TIMEZONE_SHORTNAME=%s", tzname[daylight],
705 "DAYLIGHT=%i", daylight,
706 LOG_MESSAGE("Changed time zone to '%s' (%s).", c->zone, tzname[daylight]));
707
708 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m),
709 "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "Timezone",
710 NULL);
711
712 return sd_bus_reply_method_return(m, NULL);
713 }
714
715 static int method_set_local_rtc(sd_bus_message *m, void *userdata, sd_bus_error *error) {
716 int lrtc, fix_system, interactive;
717 Context *c = userdata;
718 struct timespec ts;
719 int r;
720
721 assert(m);
722 assert(c);
723
724 r = sd_bus_message_read(m, "bbb", &lrtc, &fix_system, &interactive);
725 if (r < 0)
726 return r;
727
728 if (lrtc == c->local_rtc)
729 return sd_bus_reply_method_return(m, NULL);
730
731 r = bus_verify_polkit_async(
732 m,
733 CAP_SYS_TIME,
734 "org.freedesktop.timedate1.set-local-rtc",
735 NULL,
736 interactive,
737 UID_INVALID,
738 &c->polkit_registry,
739 error);
740 if (r < 0)
741 return r;
742 if (r == 0)
743 return 1;
744
745 c->local_rtc = lrtc;
746
747 /* 1. Write new configuration file */
748 r = context_write_data_local_rtc(c);
749 if (r < 0) {
750 log_error_errno(r, "Failed to set RTC to %s: %m", lrtc ? "local" : "UTC");
751 return sd_bus_error_set_errnof(error, r, "Failed to set RTC to %s: %m", lrtc ? "local" : "UTC");
752 }
753
754 /* 2. Tell the kernel our timezone */
755 r = clock_set_timezone(NULL);
756 if (r < 0)
757 log_debug_errno(r, "Failed to tell kernel about timezone, ignoring: %m");
758
759 /* 3. Synchronize clocks */
760 assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
761
762 if (fix_system) {
763 struct tm tm;
764
765 /* Sync system clock from RTC; first, initialize the timezone fields of struct tm. */
766 localtime_or_gmtime_r(&ts.tv_sec, &tm, !c->local_rtc);
767
768 /* Override the main fields of struct tm, but not the timezone fields */
769 r = clock_get_hwclock(&tm);
770 if (r < 0)
771 log_debug_errno(r, "Failed to get hardware clock, ignoring: %m");
772 else {
773 /* And set the system clock with this */
774 ts.tv_sec = mktime_or_timegm(&tm, !c->local_rtc);
775
776 if (clock_settime(CLOCK_REALTIME, &ts) < 0)
777 log_debug_errno(errno, "Failed to update system clock, ignoring: %m");
778 }
779
780 } else {
781 struct tm tm;
782
783 /* Sync RTC from system clock */
784 localtime_or_gmtime_r(&ts.tv_sec, &tm, !c->local_rtc);
785
786 r = clock_set_hwclock(&tm);
787 if (r < 0)
788 log_debug_errno(r, "Failed to sync time to hardware clock, ignoring: %m");
789 }
790
791 log_info("RTC configured to %s time.", c->local_rtc ? "local" : "UTC");
792
793 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m),
794 "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "LocalRTC",
795 NULL);
796
797 return sd_bus_reply_method_return(m, NULL);
798 }
799
800 static int method_set_time(sd_bus_message *m, void *userdata, sd_bus_error *error) {
801 sd_bus *bus = sd_bus_message_get_bus(m);
802 int relative, interactive, r;
803 Context *c = userdata;
804 int64_t utc;
805 struct timespec ts;
806 usec_t start;
807 struct tm tm;
808
809 assert(m);
810 assert(c);
811
812 if (c->slot_job_removed)
813 return sd_bus_error_set(error, BUS_ERROR_AUTOMATIC_TIME_SYNC_ENABLED, "Previous request is not finished, refusing.");
814
815 r = context_update_ntp_status(c, bus, m);
816 if (r < 0)
817 return sd_bus_error_set_errnof(error, r, "Failed to update context: %m");
818
819 if (context_ntp_service_is_active(c) > 0)
820 return sd_bus_error_set(error, BUS_ERROR_AUTOMATIC_TIME_SYNC_ENABLED, "Automatic time synchronization is enabled");
821
822 /* this only gets used if dbus does not provide a timestamp */
823 start = now(CLOCK_MONOTONIC);
824
825 r = sd_bus_message_read(m, "xbb", &utc, &relative, &interactive);
826 if (r < 0)
827 return r;
828
829 if (!relative && utc <= 0)
830 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid absolute time");
831
832 if (relative && utc == 0)
833 return sd_bus_reply_method_return(m, NULL);
834
835 if (relative) {
836 usec_t n, x;
837
838 n = now(CLOCK_REALTIME);
839 x = n + utc;
840
841 if ((utc > 0 && x < n) ||
842 (utc < 0 && x > n))
843 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Time value overflow");
844
845 timespec_store(&ts, x);
846 } else
847 timespec_store(&ts, (usec_t) utc);
848
849 r = bus_verify_polkit_async(
850 m,
851 CAP_SYS_TIME,
852 "org.freedesktop.timedate1.set-time",
853 NULL,
854 interactive,
855 UID_INVALID,
856 &c->polkit_registry,
857 error);
858 if (r < 0)
859 return r;
860 if (r == 0)
861 return 1;
862
863 /* adjust ts for time spent in program */
864 r = sd_bus_message_get_monotonic_usec(m, &start);
865 /* when sd_bus_message_get_monotonic_usec() returns -ENODATA it does not modify &start */
866 if (r < 0 && r != -ENODATA)
867 return r;
868
869 timespec_store(&ts, timespec_load(&ts) + (now(CLOCK_MONOTONIC) - start));
870
871 /* Set system clock */
872 if (clock_settime(CLOCK_REALTIME, &ts) < 0) {
873 log_error_errno(errno, "Failed to set local time: %m");
874 return sd_bus_error_set_errnof(error, errno, "Failed to set local time: %m");
875 }
876
877 /* Sync down to RTC */
878 localtime_or_gmtime_r(&ts.tv_sec, &tm, !c->local_rtc);
879
880 r = clock_set_hwclock(&tm);
881 if (r < 0)
882 log_debug_errno(r, "Failed to update hardware clock, ignoring: %m");
883
884 log_struct(LOG_INFO,
885 "MESSAGE_ID=" SD_MESSAGE_TIME_CHANGE_STR,
886 "REALTIME="USEC_FMT, timespec_load(&ts),
887 LOG_MESSAGE("Changed local time to %s", ctime(&ts.tv_sec)));
888
889 return sd_bus_reply_method_return(m, NULL);
890 }
891
892 static int method_set_ntp(sd_bus_message *m, void *userdata, sd_bus_error *error) {
893 _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL;
894 sd_bus *bus = sd_bus_message_get_bus(m);
895 Context *c = userdata;
896 UnitStatusInfo *u;
897 const UnitStatusInfo *selected = NULL;
898 int enable, interactive, q, r;
899
900 assert(m);
901 assert(bus);
902 assert(c);
903
904 r = sd_bus_message_read(m, "bb", &enable, &interactive);
905 if (r < 0)
906 return r;
907
908 r = context_update_ntp_status(c, bus, m);
909 if (r < 0)
910 return r;
911
912 if (context_ntp_service_exists(c) <= 0)
913 return sd_bus_error_set(error, BUS_ERROR_NO_NTP_SUPPORT, "NTP not supported");
914
915 r = bus_verify_polkit_async(
916 m,
917 CAP_SYS_TIME,
918 "org.freedesktop.timedate1.set-ntp",
919 NULL,
920 interactive,
921 UID_INVALID,
922 &c->polkit_registry,
923 error);
924 if (r < 0)
925 return r;
926 if (r == 0)
927 return 1;
928
929 /* This method may be called frequently. Forget the previous job if it has not completed yet. */
930 LIST_FOREACH(units, u, c->units)
931 u->path = mfree(u->path);
932
933 if (!c->slot_job_removed) {
934 r = bus_match_signal_async(
935 bus,
936 &slot,
937 bus_systemd_mgr,
938 "JobRemoved",
939 match_job_removed, NULL, c);
940 if (r < 0)
941 return r;
942 }
943
944 if (enable)
945 LIST_FOREACH(units, u, c->units) {
946 bool enable_this_one = !selected;
947
948 if (!streq(u->load_state, "loaded"))
949 continue;
950
951 r = unit_enable_or_disable(u, bus, error, enable_this_one);
952 if (r < 0)
953 /* If enablement failed, don't start this unit. */
954 enable_this_one = false;
955
956 r = unit_start_or_stop(u, bus, error, enable_this_one);
957 if (r < 0)
958 log_unit_warning_errno(u, r, "Failed to %s %sd NTP unit, ignoring: %m",
959 enable_this_one ? "start" : "stop",
960 enable_disable(enable_this_one));
961 if (enable_this_one)
962 selected = u;
963 }
964 else
965 LIST_FOREACH(units, u, c->units) {
966 if (!streq(u->load_state, "loaded"))
967 continue;
968
969 q = unit_enable_or_disable(u, bus, error, false);
970 if (q < 0)
971 r = q;
972
973 q = unit_start_or_stop(u, bus, error, false);
974 if (q < 0)
975 r = q;
976 }
977
978 if (r < 0)
979 return r;
980 if (enable && !selected)
981 return log_error_errno(SYNTHETIC_ERRNO(ENOENT), "No NTP service found to enable.");
982
983 if (slot)
984 c->slot_job_removed = TAKE_PTR(slot);
985
986 if (selected)
987 log_info("Set NTP to enabled (%s).", selected->name);
988 else
989 log_info("Set NTP to disabled.");
990
991 return sd_bus_reply_method_return(m, NULL);
992 }
993
994 static int method_list_timezones(sd_bus_message *m, void *userdata, sd_bus_error *error) {
995 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
996 _cleanup_strv_free_ char **zones = NULL;
997 int r;
998
999 assert(m);
1000
1001 r = get_timezones(&zones);
1002 if (r < 0)
1003 return sd_bus_error_set_errnof(error, r, "Failed to read list of time zones: %m");
1004
1005 r = sd_bus_message_new_method_return(m, &reply);
1006 if (r < 0)
1007 return r;
1008
1009 r = sd_bus_message_append_strv(reply, zones);
1010 if (r < 0)
1011 return r;
1012
1013 return sd_bus_send(NULL, reply, NULL);
1014 }
1015
1016 static const sd_bus_vtable timedate_vtable[] = {
1017 SD_BUS_VTABLE_START(0),
1018
1019 SD_BUS_PROPERTY("Timezone", "s", NULL, offsetof(Context, zone), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1020 SD_BUS_PROPERTY("LocalRTC", "b", bus_property_get_bool, offsetof(Context, local_rtc), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1021 SD_BUS_PROPERTY("CanNTP", "b", property_get_can_ntp, 0, 0),
1022 SD_BUS_PROPERTY("NTP", "b", property_get_ntp, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1023 SD_BUS_PROPERTY("NTPSynchronized", "b", property_get_ntp_sync, 0, 0),
1024 SD_BUS_PROPERTY("TimeUSec", "t", property_get_time, 0, 0),
1025 SD_BUS_PROPERTY("RTCTimeUSec", "t", property_get_rtc_time, 0, 0),
1026
1027 SD_BUS_METHOD_WITH_NAMES("SetTime",
1028 "xbb",
1029 SD_BUS_PARAM(usec_utc)
1030 SD_BUS_PARAM(relative)
1031 SD_BUS_PARAM(interactive),
1032 NULL,,
1033 method_set_time,
1034 SD_BUS_VTABLE_UNPRIVILEGED),
1035 SD_BUS_METHOD_WITH_NAMES("SetTimezone",
1036 "sb",
1037 SD_BUS_PARAM(timezone)
1038 SD_BUS_PARAM(interactive),
1039 NULL,,
1040 method_set_timezone,
1041 SD_BUS_VTABLE_UNPRIVILEGED),
1042 SD_BUS_METHOD_WITH_NAMES("SetLocalRTC",
1043 "bbb",
1044 SD_BUS_PARAM(local_rtc)
1045 SD_BUS_PARAM(fix_system)
1046 SD_BUS_PARAM(interactive),
1047 NULL,,
1048 method_set_local_rtc,
1049 SD_BUS_VTABLE_UNPRIVILEGED),
1050 SD_BUS_METHOD_WITH_NAMES("SetNTP",
1051 "bb",
1052 SD_BUS_PARAM(use_ntp)
1053 SD_BUS_PARAM(interactive),
1054 NULL,,
1055 method_set_ntp,
1056 SD_BUS_VTABLE_UNPRIVILEGED),
1057 SD_BUS_METHOD_WITH_NAMES("ListTimezones",
1058 NULL,,
1059 "as",
1060 SD_BUS_PARAM(timezones),
1061 method_list_timezones,
1062 SD_BUS_VTABLE_UNPRIVILEGED),
1063
1064 SD_BUS_VTABLE_END,
1065 };
1066
1067 const BusObjectImplementation manager_object = {
1068 "/org/freedesktop/timedate1",
1069 "org.freedesktop.timedate1",
1070 .vtables = BUS_VTABLES(timedate_vtable),
1071 };
1072
1073 static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
1074 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1075 int r;
1076
1077 assert(c);
1078 assert(event);
1079 assert(_bus);
1080
1081 r = sd_bus_default_system(&bus);
1082 if (r < 0)
1083 return log_error_errno(r, "Failed to get system bus connection: %m");
1084
1085 r = bus_add_implementation(bus, &manager_object, c);
1086 if (r < 0)
1087 return r;
1088
1089 r = bus_log_control_api_register(bus);
1090 if (r < 0)
1091 return r;
1092
1093 r = sd_bus_request_name_async(bus, NULL, "org.freedesktop.timedate1", 0, NULL, NULL);
1094 if (r < 0)
1095 return log_error_errno(r, "Failed to request name: %m");
1096
1097 r = sd_bus_attach_event(bus, event, 0);
1098 if (r < 0)
1099 return log_error_errno(r, "Failed to attach bus to event loop: %m");
1100
1101 *_bus = TAKE_PTR(bus);
1102
1103 return 0;
1104 }
1105
1106 static int run(int argc, char *argv[]) {
1107 _cleanup_(context_clear) Context context = {};
1108 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
1109 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1110 int r;
1111
1112 log_setup();
1113
1114 r = service_parse_argv("systemd-timedated.service",
1115 "Manage the system clock and timezone and NTP enablement.",
1116 BUS_IMPLEMENTATIONS(&manager_object,
1117 &log_control_object),
1118 argc, argv);
1119 if (r <= 0)
1120 return r;
1121
1122 umask(0022);
1123
1124 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
1125
1126 r = sd_event_default(&event);
1127 if (r < 0)
1128 return log_error_errno(r, "Failed to allocate event loop: %m");
1129
1130 (void) sd_event_set_watchdog(event, true);
1131
1132 r = sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
1133 if (r < 0)
1134 return log_error_errno(r, "Failed to install SIGINT handler: %m");
1135
1136 r = sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
1137 if (r < 0)
1138 return log_error_errno(r, "Failed to install SIGTERM handler: %m");
1139
1140 r = connect_bus(&context, event, &bus);
1141 if (r < 0)
1142 return r;
1143
1144 (void) sd_bus_negotiate_timestamp(bus, true);
1145
1146 r = context_read_data(&context);
1147 if (r < 0)
1148 return log_error_errno(r, "Failed to read time zone data: %m");
1149
1150 r = context_parse_ntp_services(&context);
1151 if (r < 0)
1152 return r;
1153
1154 r = bus_event_loop_with_idle(event, bus, "org.freedesktop.timedate1", DEFAULT_EXIT_USEC, NULL, NULL);
1155 if (r < 0)
1156 return log_error_errno(r, "Failed to run event loop: %m");
1157
1158 return 0;
1159 }
1160
1161 DEFINE_MAIN_FUNCTION(run);