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