]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/timedate/timedated.c
Merge pull request #18886 from anitazha/shutdownconsole
[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 && !fix_system)
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 if (lrtc != c->local_rtc) {
746 c->local_rtc = lrtc;
747
748 /* 1. Write new configuration file */
749 r = context_write_data_local_rtc(c);
750 if (r < 0) {
751 log_error_errno(r, "Failed to set RTC to %s: %m", lrtc ? "local" : "UTC");
752 return sd_bus_error_set_errnof(error, r, "Failed to set RTC to %s: %m", lrtc ? "local" : "UTC");
753 }
754 }
755
756 /* 2. Tell the kernel our timezone */
757 r = clock_set_timezone(NULL);
758 if (r < 0)
759 log_debug_errno(r, "Failed to tell kernel about timezone, ignoring: %m");
760
761 /* 3. Synchronize clocks */
762 assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
763
764 if (fix_system) {
765 struct tm tm;
766
767 /* Sync system clock from RTC; first, initialize the timezone fields of struct tm. */
768 localtime_or_gmtime_r(&ts.tv_sec, &tm, !c->local_rtc);
769
770 /* Override the main fields of struct tm, but not the timezone fields */
771 r = clock_get_hwclock(&tm);
772 if (r < 0)
773 log_debug_errno(r, "Failed to get hardware clock, ignoring: %m");
774 else {
775 /* And set the system clock with this */
776 ts.tv_sec = mktime_or_timegm(&tm, !c->local_rtc);
777
778 if (clock_settime(CLOCK_REALTIME, &ts) < 0)
779 log_debug_errno(errno, "Failed to update system clock, ignoring: %m");
780 }
781
782 } else {
783 struct tm tm;
784
785 /* Sync RTC from system clock */
786 localtime_or_gmtime_r(&ts.tv_sec, &tm, !c->local_rtc);
787
788 r = clock_set_hwclock(&tm);
789 if (r < 0)
790 log_debug_errno(r, "Failed to sync time to hardware clock, ignoring: %m");
791 }
792
793 log_info("RTC configured to %s time.", c->local_rtc ? "local" : "UTC");
794
795 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m),
796 "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "LocalRTC",
797 NULL);
798
799 return sd_bus_reply_method_return(m, NULL);
800 }
801
802 static int method_set_time(sd_bus_message *m, void *userdata, sd_bus_error *error) {
803 sd_bus *bus = sd_bus_message_get_bus(m);
804 int relative, interactive, r;
805 Context *c = userdata;
806 int64_t utc;
807 struct timespec ts;
808 usec_t start;
809 struct tm tm;
810
811 assert(m);
812 assert(c);
813
814 if (c->slot_job_removed)
815 return sd_bus_error_set(error, BUS_ERROR_AUTOMATIC_TIME_SYNC_ENABLED, "Previous request is not finished, refusing.");
816
817 r = context_update_ntp_status(c, bus, m);
818 if (r < 0)
819 return sd_bus_error_set_errnof(error, r, "Failed to update context: %m");
820
821 if (context_ntp_service_is_active(c) > 0)
822 return sd_bus_error_set(error, BUS_ERROR_AUTOMATIC_TIME_SYNC_ENABLED, "Automatic time synchronization is enabled");
823
824 /* this only gets used if dbus does not provide a timestamp */
825 start = now(CLOCK_MONOTONIC);
826
827 r = sd_bus_message_read(m, "xbb", &utc, &relative, &interactive);
828 if (r < 0)
829 return r;
830
831 if (!relative && utc <= 0)
832 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid absolute time");
833
834 if (relative && utc == 0)
835 return sd_bus_reply_method_return(m, NULL);
836
837 if (relative) {
838 usec_t n, x;
839
840 n = now(CLOCK_REALTIME);
841 x = n + utc;
842
843 if ((utc > 0 && x < n) ||
844 (utc < 0 && x > n))
845 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Time value overflow");
846
847 timespec_store(&ts, x);
848 } else
849 timespec_store(&ts, (usec_t) utc);
850
851 r = bus_verify_polkit_async(
852 m,
853 CAP_SYS_TIME,
854 "org.freedesktop.timedate1.set-time",
855 NULL,
856 interactive,
857 UID_INVALID,
858 &c->polkit_registry,
859 error);
860 if (r < 0)
861 return r;
862 if (r == 0)
863 return 1;
864
865 /* adjust ts for time spent in program */
866 r = sd_bus_message_get_monotonic_usec(m, &start);
867 /* when sd_bus_message_get_monotonic_usec() returns -ENODATA it does not modify &start */
868 if (r < 0 && r != -ENODATA)
869 return r;
870
871 timespec_store(&ts, timespec_load(&ts) + (now(CLOCK_MONOTONIC) - start));
872
873 /* Set system clock */
874 if (clock_settime(CLOCK_REALTIME, &ts) < 0) {
875 log_error_errno(errno, "Failed to set local time: %m");
876 return sd_bus_error_set_errnof(error, errno, "Failed to set local time: %m");
877 }
878
879 /* Sync down to RTC */
880 localtime_or_gmtime_r(&ts.tv_sec, &tm, !c->local_rtc);
881
882 r = clock_set_hwclock(&tm);
883 if (r < 0)
884 log_debug_errno(r, "Failed to update hardware clock, ignoring: %m");
885
886 log_struct(LOG_INFO,
887 "MESSAGE_ID=" SD_MESSAGE_TIME_CHANGE_STR,
888 "REALTIME="USEC_FMT, timespec_load(&ts),
889 LOG_MESSAGE("Changed local time to %s", ctime(&ts.tv_sec)));
890
891 return sd_bus_reply_method_return(m, NULL);
892 }
893
894 static int method_set_ntp(sd_bus_message *m, void *userdata, sd_bus_error *error) {
895 _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL;
896 sd_bus *bus = sd_bus_message_get_bus(m);
897 Context *c = userdata;
898 UnitStatusInfo *u;
899 const UnitStatusInfo *selected = NULL;
900 int enable, interactive, q, r;
901
902 assert(m);
903 assert(bus);
904 assert(c);
905
906 r = sd_bus_message_read(m, "bb", &enable, &interactive);
907 if (r < 0)
908 return r;
909
910 r = context_update_ntp_status(c, bus, m);
911 if (r < 0)
912 return r;
913
914 if (context_ntp_service_exists(c) <= 0)
915 return sd_bus_error_set(error, BUS_ERROR_NO_NTP_SUPPORT, "NTP not supported");
916
917 r = bus_verify_polkit_async(
918 m,
919 CAP_SYS_TIME,
920 "org.freedesktop.timedate1.set-ntp",
921 NULL,
922 interactive,
923 UID_INVALID,
924 &c->polkit_registry,
925 error);
926 if (r < 0)
927 return r;
928 if (r == 0)
929 return 1;
930
931 /* This method may be called frequently. Forget the previous job if it has not completed yet. */
932 LIST_FOREACH(units, u, c->units)
933 u->path = mfree(u->path);
934
935 if (!c->slot_job_removed) {
936 r = bus_match_signal_async(
937 bus,
938 &slot,
939 bus_systemd_mgr,
940 "JobRemoved",
941 match_job_removed, NULL, c);
942 if (r < 0)
943 return r;
944 }
945
946 if (enable)
947 LIST_FOREACH(units, u, c->units) {
948 bool enable_this_one = !selected;
949
950 if (!streq(u->load_state, "loaded"))
951 continue;
952
953 r = unit_enable_or_disable(u, bus, error, enable_this_one);
954 if (r < 0)
955 /* If enablement failed, don't start this unit. */
956 enable_this_one = false;
957
958 r = unit_start_or_stop(u, bus, error, enable_this_one);
959 if (r < 0)
960 log_unit_warning_errno(u, r, "Failed to %s %sd NTP unit, ignoring: %m",
961 enable_this_one ? "start" : "stop",
962 enable_disable(enable_this_one));
963 if (enable_this_one)
964 selected = u;
965 }
966 else
967 LIST_FOREACH(units, u, c->units) {
968 if (!streq(u->load_state, "loaded"))
969 continue;
970
971 q = unit_enable_or_disable(u, bus, error, false);
972 if (q < 0)
973 r = q;
974
975 q = unit_start_or_stop(u, bus, error, false);
976 if (q < 0)
977 r = q;
978 }
979
980 if (r < 0)
981 return r;
982 if (enable && !selected)
983 return log_error_errno(SYNTHETIC_ERRNO(ENOENT), "No NTP service found to enable.");
984
985 if (slot)
986 c->slot_job_removed = TAKE_PTR(slot);
987
988 if (selected)
989 log_info("Set NTP to enabled (%s).", selected->name);
990 else
991 log_info("Set NTP to disabled.");
992
993 return sd_bus_reply_method_return(m, NULL);
994 }
995
996 static int method_list_timezones(sd_bus_message *m, void *userdata, sd_bus_error *error) {
997 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
998 _cleanup_strv_free_ char **zones = NULL;
999 int r;
1000
1001 assert(m);
1002
1003 r = get_timezones(&zones);
1004 if (r < 0)
1005 return sd_bus_error_set_errnof(error, r, "Failed to read list of time zones: %m");
1006
1007 r = sd_bus_message_new_method_return(m, &reply);
1008 if (r < 0)
1009 return r;
1010
1011 r = sd_bus_message_append_strv(reply, zones);
1012 if (r < 0)
1013 return r;
1014
1015 return sd_bus_send(NULL, reply, NULL);
1016 }
1017
1018 static const sd_bus_vtable timedate_vtable[] = {
1019 SD_BUS_VTABLE_START(0),
1020
1021 SD_BUS_PROPERTY("Timezone", "s", NULL, offsetof(Context, zone), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1022 SD_BUS_PROPERTY("LocalRTC", "b", bus_property_get_bool, offsetof(Context, local_rtc), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1023 SD_BUS_PROPERTY("CanNTP", "b", property_get_can_ntp, 0, 0),
1024 SD_BUS_PROPERTY("NTP", "b", property_get_ntp, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1025 SD_BUS_PROPERTY("NTPSynchronized", "b", property_get_ntp_sync, 0, 0),
1026 SD_BUS_PROPERTY("TimeUSec", "t", property_get_time, 0, 0),
1027 SD_BUS_PROPERTY("RTCTimeUSec", "t", property_get_rtc_time, 0, 0),
1028
1029 SD_BUS_METHOD_WITH_NAMES("SetTime",
1030 "xbb",
1031 SD_BUS_PARAM(usec_utc)
1032 SD_BUS_PARAM(relative)
1033 SD_BUS_PARAM(interactive),
1034 NULL,,
1035 method_set_time,
1036 SD_BUS_VTABLE_UNPRIVILEGED),
1037 SD_BUS_METHOD_WITH_NAMES("SetTimezone",
1038 "sb",
1039 SD_BUS_PARAM(timezone)
1040 SD_BUS_PARAM(interactive),
1041 NULL,,
1042 method_set_timezone,
1043 SD_BUS_VTABLE_UNPRIVILEGED),
1044 SD_BUS_METHOD_WITH_NAMES("SetLocalRTC",
1045 "bbb",
1046 SD_BUS_PARAM(local_rtc)
1047 SD_BUS_PARAM(fix_system)
1048 SD_BUS_PARAM(interactive),
1049 NULL,,
1050 method_set_local_rtc,
1051 SD_BUS_VTABLE_UNPRIVILEGED),
1052 SD_BUS_METHOD_WITH_NAMES("SetNTP",
1053 "bb",
1054 SD_BUS_PARAM(use_ntp)
1055 SD_BUS_PARAM(interactive),
1056 NULL,,
1057 method_set_ntp,
1058 SD_BUS_VTABLE_UNPRIVILEGED),
1059 SD_BUS_METHOD_WITH_NAMES("ListTimezones",
1060 NULL,,
1061 "as",
1062 SD_BUS_PARAM(timezones),
1063 method_list_timezones,
1064 SD_BUS_VTABLE_UNPRIVILEGED),
1065
1066 SD_BUS_VTABLE_END,
1067 };
1068
1069 const BusObjectImplementation manager_object = {
1070 "/org/freedesktop/timedate1",
1071 "org.freedesktop.timedate1",
1072 .vtables = BUS_VTABLES(timedate_vtable),
1073 };
1074
1075 static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
1076 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1077 int r;
1078
1079 assert(c);
1080 assert(event);
1081 assert(_bus);
1082
1083 r = sd_bus_default_system(&bus);
1084 if (r < 0)
1085 return log_error_errno(r, "Failed to get system bus connection: %m");
1086
1087 r = bus_add_implementation(bus, &manager_object, c);
1088 if (r < 0)
1089 return r;
1090
1091 r = bus_log_control_api_register(bus);
1092 if (r < 0)
1093 return r;
1094
1095 r = sd_bus_request_name_async(bus, NULL, "org.freedesktop.timedate1", 0, NULL, NULL);
1096 if (r < 0)
1097 return log_error_errno(r, "Failed to request name: %m");
1098
1099 r = sd_bus_attach_event(bus, event, 0);
1100 if (r < 0)
1101 return log_error_errno(r, "Failed to attach bus to event loop: %m");
1102
1103 *_bus = TAKE_PTR(bus);
1104
1105 return 0;
1106 }
1107
1108 static int run(int argc, char *argv[]) {
1109 _cleanup_(context_clear) Context context = {};
1110 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
1111 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1112 int r;
1113
1114 log_setup();
1115
1116 r = service_parse_argv("systemd-timedated.service",
1117 "Manage the system clock and timezone and NTP enablement.",
1118 BUS_IMPLEMENTATIONS(&manager_object,
1119 &log_control_object),
1120 argc, argv);
1121 if (r <= 0)
1122 return r;
1123
1124 umask(0022);
1125
1126 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
1127
1128 r = sd_event_default(&event);
1129 if (r < 0)
1130 return log_error_errno(r, "Failed to allocate event loop: %m");
1131
1132 (void) sd_event_set_watchdog(event, true);
1133
1134 r = sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
1135 if (r < 0)
1136 return log_error_errno(r, "Failed to install SIGINT handler: %m");
1137
1138 r = sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
1139 if (r < 0)
1140 return log_error_errno(r, "Failed to install SIGTERM handler: %m");
1141
1142 r = connect_bus(&context, event, &bus);
1143 if (r < 0)
1144 return r;
1145
1146 (void) sd_bus_negotiate_timestamp(bus, true);
1147
1148 r = context_read_data(&context);
1149 if (r < 0)
1150 return log_error_errno(r, "Failed to read time zone data: %m");
1151
1152 r = context_parse_ntp_services(&context);
1153 if (r < 0)
1154 return r;
1155
1156 r = bus_event_loop_with_idle(event, bus, "org.freedesktop.timedate1", DEFAULT_EXIT_USEC, NULL, NULL);
1157 if (r < 0)
1158 return log_error_errno(r, "Failed to run event loop: %m");
1159
1160 return 0;
1161 }
1162
1163 DEFINE_MAIN_FUNCTION(run);