]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/timedated.c
stdout-bridge: set facility of messages with no facility to configured facility inste...
[thirdparty/systemd.git] / src / timedated.c
CommitLineData
f401e48c
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <dbus/dbus.h>
23
24#include <errno.h>
25#include <string.h>
26#include <unistd.h>
27
28#include "util.h"
29#include "strv.h"
30#include "dbus-common.h"
31#include "polkit.h"
32
33#define NULL_ADJTIME_UTC "0.0 0 0\n0\nUTC\n"
34#define NULL_ADJTIME_LOCAL "0.0 0 0\n0\nLOCAL\n"
35
91f9dcaf 36#define INTERFACE \
f401e48c
LP
37 " <interface name=\"org.freedesktop.timedate1\">\n" \
38 " <property name=\"Timezone\" type=\"s\" access=\"read\"/>\n" \
39 " <property name=\"LocalRTC\" type=\"b\" access=\"read\"/>\n" \
c5f0532f 40 " <property name=\"NTP\" type=\"b\" access=\"read\"/>\n" \
f401e48c
LP
41 " <method name=\"SetTime\">\n" \
42 " <arg name=\"usec_utc\" type=\"x\" direction=\"in\"/>\n" \
43 " <arg name=\"relative\" type=\"b\" direction=\"in\"/>\n" \
44 " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
45 " </method>\n" \
46 " <method name=\"SetTimezone\">\n" \
47 " <arg name=\"timezone\" type=\"s\" direction=\"in\"/>\n" \
48 " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
49 " </method>\n" \
50 " <method name=\"SetLocalRTC\">\n" \
51 " <arg name=\"local_rtc\" type=\"b\" direction=\"in\"/>\n" \
91f9dcaf 52 " <arg name=\"fix_system\" type=\"b\" direction=\"in\"/>\n" \
f401e48c
LP
53 " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
54 " </method>\n" \
c5f0532f
LP
55 " <method name=\"SetNTP\">\n" \
56 " <arg name=\"use_ntp\" type=\"b\" direction=\"in\"/>\n" \
57 " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
58 " </method>\n" \
91f9dcaf
LP
59 " </interface>\n"
60
61#define INTROSPECTION \
62 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
63 "<node>\n" \
64 INTERFACE \
f401e48c
LP
65 BUS_PROPERTIES_INTERFACE \
66 BUS_INTROSPECTABLE_INTERFACE \
67 BUS_PEER_INTERFACE \
68 "</node>\n"
69
70#define INTERFACES_LIST \
71 BUS_GENERIC_INTERFACES_LIST \
72 "org.freedesktop.locale1\0"
73
91f9dcaf
LP
74const char timedate_interface[] _introspect_("timedate1") = INTERFACE;
75
f401e48c
LP
76static char *zone = NULL;
77static bool local_rtc = false;
c5f0532f 78static int use_ntp = -1;
f401e48c
LP
79
80static void free_data(void) {
81 free(zone);
82 zone = NULL;
83
84 local_rtc = false;
85}
86
87static bool valid_timezone(const char *name) {
88 const char *p;
89 char *t;
90 bool slash = false;
91 int r;
92 struct stat st;
93
94 assert(name);
95
96 if (*name == '/' || *name == 0)
97 return false;
98
99 for (p = name; *p; p++) {
100 if (!(*p >= '0' && *p <= '9') &&
101 !(*p >= 'a' && *p <= 'z') &&
102 !(*p >= 'A' && *p <= 'Z') &&
103 !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
104 return false;
105
106 if (*p == '/') {
107
108 if (slash)
109 return false;
110
111 slash = true;
112 } else
113 slash = false;
114 }
115
116 if (slash)
117 return false;
118
119 t = strappend("/usr/share/zoneinfo/", name);
120 if (!t)
121 return false;
122
123 r = stat(t, &st);
124 free(t);
125
126 if (r < 0)
127 return false;
128
129 if (!S_ISREG(st.st_mode))
130 return false;
131
132 return true;
133}
134
135static void verify_timezone(void) {
136 char *p, *a = NULL, *b = NULL;
137 size_t l, q;
138 int j, k;
139
140 if (!zone)
141 return;
142
143 p = strappend("/usr/share/zoneinfo/", zone);
144 if (!p) {
145 log_error("Out of memory");
146 return;
147 }
148
149 j = read_full_file("/etc/localtime", &a, &l);
150 k = read_full_file(p, &b, &q);
151
152 free(p);
153
154 if (j < 0 || k < 0 || l != q || memcmp(a, b, l)) {
155 log_warning("/etc/localtime and /etc/timezone out of sync.");
156 free(zone);
157 zone = NULL;
158 }
159
160 free(a);
161 free(b);
162}
163
164static int read_data(void) {
165 int r;
f401e48c
LP
166
167 free_data();
168
169 r = read_one_line_file("/etc/timezone", &zone);
170 if (r < 0 && r != -ENOENT)
171 return r;
172
173 verify_timezone();
174
2076cf88 175 local_rtc = hwclock_is_localtime() > 0;
f401e48c
LP
176
177 return 0;
178}
179
180static int write_data_timezone(void) {
181 int r = 0;
182 char *p;
183
184 if (!zone) {
185 if (unlink("/etc/timezone") < 0 && errno != ENOENT)
186 r = -errno;
187
188 if (unlink("/etc/localtime") < 0 && errno != ENOENT)
189 r = -errno;
190
191 return r;
192 }
193
194 p = strappend("/usr/share/zoneinfo/", zone);
195 if (!p) {
196 log_error("Out of memory");
197 return -ENOMEM;
198 }
199
200 r = symlink_or_copy_atomic(p, "/etc/localtime");
201 free(p);
202
203 if (r < 0)
204 return r;
205
206 r = write_one_line_file_atomic("/etc/timezone", zone);
207 if (r < 0)
208 return r;
209
210 return 0;
211}
212
213static int write_data_local_rtc(void) {
214 int r;
215 char *s, *w;
216
217 r = read_full_file("/etc/adjtime", &s, NULL);
218 if (r < 0) {
219 if (r != -ENOENT)
220 return r;
221
222 if (!local_rtc)
223 return 0;
224
225 w = strdup(NULL_ADJTIME_LOCAL);
226 if (!w)
227 return -ENOMEM;
228 } else {
229 char *p, *e;
230 size_t a, b;
231
232 p = strchr(s, '\n');
233 if (!p) {
234 free(s);
235 return -EIO;
236 }
237
238 p = strchr(p+1, '\n');
239 if (!p) {
240 free(s);
241 return -EIO;
242 }
243
244 p++;
245 e = strchr(p, '\n');
246 if (!p) {
247 free(s);
248 return -EIO;
249 }
250
251 a = p - s;
252 b = strlen(e);
253
254 w = new(char, a + (local_rtc ? 5 : 3) + b + 1);
255 if (!w) {
256 free(s);
257 return -ENOMEM;
258 }
259
260 *(char*) mempcpy(stpcpy(mempcpy(w, s, a), local_rtc ? "LOCAL" : "UTC"), e, b) = 0;
261
262 if (streq(w, NULL_ADJTIME_UTC)) {
263 free(w);
264
265 if (unlink("/etc/adjtime") < 0) {
266 if (errno != ENOENT)
267 return -errno;
268 }
269
270 return 0;
271 }
272 }
273
274 r = write_one_line_file_atomic("/etc/adjtime", w);
275 free(w);
276
277 return r;
278}
279
c5f0532f
LP
280static int read_ntp(DBusConnection *bus) {
281 DBusMessage *m = NULL, *reply = NULL;
282 const char *name = "ntpd.service", *s;
283 DBusError error;
284 int r;
285
286 assert(bus);
287
288 dbus_error_init(&error);
289
290 m = dbus_message_new_method_call(
291 "org.freedesktop.systemd1",
292 "/org/freedesktop/systemd1",
293 "org.freedesktop.systemd1.Manager",
294 "GetUnitFileState");
295
296 if (!m) {
297 log_error("Out of memory");
298 r = -ENOMEM;
299 goto finish;
300 }
301
302 if (!dbus_message_append_args(m,
303 DBUS_TYPE_STRING, &name,
304 DBUS_TYPE_INVALID)) {
305 log_error("Could not append arguments to message.");
306 r = -ENOMEM;
307 goto finish;
308 }
309
310 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
311 if (!reply) {
312 log_error("Failed to issue method call: %s", bus_error_message(&error));
313 r = -EIO;
314 goto finish;
315 }
316
317 if (!dbus_message_get_args(reply, &error,
318 DBUS_TYPE_STRING, &s,
319 DBUS_TYPE_INVALID)) {
320 log_error("Failed to parse reply: %s", bus_error_message(&error));
321 r = -EIO;
322 goto finish;
323 }
324
325 use_ntp =
326 streq(s, "enabled") ||
327 streq(s, "enabled-runtime");
328 r = 0;
329
330finish:
331 if (m)
332 dbus_message_unref(m);
333
334 if (reply)
335 dbus_message_unref(reply);
336
337 dbus_error_free(&error);
338
339 return r;
340}
341
342static int start_ntp(DBusConnection *bus, DBusError *error) {
343 DBusMessage *m = NULL, *reply = NULL;
344 const char *name = "ntpd.service", *mode = "replace";
345 int r;
346
347 assert(bus);
348 assert(error);
349
350 m = dbus_message_new_method_call(
351 "org.freedesktop.systemd1",
352 "/org/freedesktop/systemd1",
353 "org.freedesktop.systemd1.Manager",
354 use_ntp ? "StartUnit" : "StopUnit");
355 if (!m) {
356 log_error("Could not allocate message.");
357 r = -ENOMEM;
358 goto finish;
359 }
360
361 if (!dbus_message_append_args(m,
362 DBUS_TYPE_STRING, &name,
363 DBUS_TYPE_STRING, &mode,
364 DBUS_TYPE_INVALID)) {
365 log_error("Could not append arguments to message.");
366 r = -ENOMEM;
367 goto finish;
368 }
369
370 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error);
371 if (!reply) {
372 log_error("Failed to issue method call: %s", bus_error_message(error));
373 r = -EIO;
374 goto finish;
375 }
376
377 r = 0;
378
379finish:
380 if (m)
381 dbus_message_unref(m);
382
383 if (reply)
384 dbus_message_unref(reply);
385
386 return r;
387}
388
389static int enable_ntp(DBusConnection *bus, DBusError *error) {
390 DBusMessage *m = NULL, *reply = NULL;
391 const char * const names[] = { "ntpd.service", NULL };
392 int r;
393 DBusMessageIter iter;
394 dbus_bool_t f = FALSE, t = TRUE;
395
396 assert(bus);
397 assert(error);
398
399 m = dbus_message_new_method_call(
400 "org.freedesktop.systemd1",
401 "/org/freedesktop/systemd1",
402 "org.freedesktop.systemd1.Manager",
403 use_ntp ? "EnableUnitFiles" : "DisableUnitFiles");
404
405 if (!m) {
406 log_error("Could not allocate message.");
407 r = -ENOMEM;
408 goto finish;
409 }
410
411 dbus_message_iter_init_append(m, &iter);
412
413 r = bus_append_strv_iter(&iter, (char**) names);
414 if (r < 0) {
415 log_error("Failed to append unit files.");
416 goto finish;
417 }
418 /* send runtime bool */
419 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &f)) {
420 log_error("Failed to append runtime boolean.");
421 r = -ENOMEM;
422 goto finish;
423 }
424
425 if (use_ntp) {
426 /* send force bool */
427 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &t)) {
428 log_error("Failed to append force boolean.");
429 r = -ENOMEM;
430 goto finish;
431 }
432 }
433
434 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error);
435 if (!reply) {
436 log_error("Failed to issue method call: %s", bus_error_message(error));
437 r = -EIO;
438 goto finish;
439 }
440
441 dbus_message_unref(m);
442 m = dbus_message_new_method_call(
443 "org.freedesktop.systemd1",
444 "/org/freedesktop/systemd1",
445 "org.freedesktop.systemd1.Manager",
446 "Reload");
447 if (!m) {
448 log_error("Could not allocate message.");
449 r = -ENOMEM;
450 goto finish;
451 }
452
453 dbus_message_unref(reply);
454 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error);
455 if (!reply) {
456 log_error("Failed to issue method call: %s", bus_error_message(error));
457 r = -EIO;
458 goto finish;
459 }
460
461 r = 0;
462
463finish:
464 if (m)
465 dbus_message_unref(m);
466
467 if (reply)
468 dbus_message_unref(reply);
469
470 return r;
471}
472
473static int property_append_ntp(DBusMessageIter *i, const char *property, void *data) {
474 dbus_bool_t db;
475
476 assert(i);
477 assert(property);
478
479 db = use_ntp > 0;
480
481 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
482 return -ENOMEM;
483
484 return 0;
485}
486
f401e48c
LP
487static DBusHandlerResult timedate_message_handler(
488 DBusConnection *connection,
489 DBusMessage *message,
490 void *userdata) {
491
492 const BusProperty properties[] = {
493 { "org.freedesktop.timedate1", "Timezone", bus_property_append_string, "s", zone },
494 { "org.freedesktop.timedate1", "LocalRTC", bus_property_append_bool, "b", &local_rtc },
c5f0532f 495 { "org.freedesktop.timedate1", "NTP", property_append_ntp, "b", NULL },
f401e48c
LP
496 { NULL, NULL, NULL, NULL, NULL }
497 };
498
499 DBusMessage *reply = NULL, *changed = NULL;
500 DBusError error;
501 int r;
502
503 assert(connection);
504 assert(message);
505
506 dbus_error_init(&error);
507
508 if (dbus_message_is_method_call(message, "org.freedesktop.timedate1", "SetTimezone")) {
509 const char *z;
510 dbus_bool_t interactive;
511
512 if (!dbus_message_get_args(
513 message,
514 &error,
515 DBUS_TYPE_STRING, &z,
516 DBUS_TYPE_BOOLEAN, &interactive,
517 DBUS_TYPE_INVALID))
518 return bus_send_error_reply(connection, message, &error, -EINVAL);
519
520 if (!valid_timezone(z))
521 return bus_send_error_reply(connection, message, NULL, -EINVAL);
522
523 if (!streq_ptr(z, zone)) {
524 char *t;
525
526 r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-timezone", interactive, &error);
527 if (r < 0)
528 return bus_send_error_reply(connection, message, &error, r);
529
530 t = strdup(z);
531 if (!t)
532 goto oom;
533
534 free(zone);
535 zone = t;
536
2076cf88 537 /* 1. Write new configuration file */
f401e48c
LP
538 r = write_data_timezone();
539 if (r < 0) {
540 log_error("Failed to set timezone: %s", strerror(-r));
541 return bus_send_error_reply(connection, message, NULL, r);
542 }
543
2076cf88
LP
544 if (local_rtc) {
545 struct timespec ts;
546 struct tm *tm;
547
548 /* 2. Teach kernel new timezone */
ff4daf5a 549 hwclock_apply_localtime_delta(NULL);
2076cf88
LP
550
551 /* 3. Sync RTC from system clock, with the new delta */
552 assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
553 assert_se(tm = localtime(&ts.tv_sec));
554 hwclock_set_time(tm);
555 }
556
f401e48c
LP
557 log_info("Changed timezone to '%s'.", zone);
558
559 changed = bus_properties_changed_new(
560 "/org/freedesktop/timedate1",
561 "org.freedesktop.timedate1",
562 "Timezone\0");
563 if (!changed)
564 goto oom;
565 }
566
567 } else if (dbus_message_is_method_call(message, "org.freedesktop.timedate1", "SetLocalRTC")) {
568 dbus_bool_t lrtc;
05a4abb9 569 dbus_bool_t fix_system;
f401e48c
LP
570 dbus_bool_t interactive;
571
572 if (!dbus_message_get_args(
573 message,
574 &error,
575 DBUS_TYPE_BOOLEAN, &lrtc,
05a4abb9 576 DBUS_TYPE_BOOLEAN, &fix_system,
f401e48c
LP
577 DBUS_TYPE_BOOLEAN, &interactive,
578 DBUS_TYPE_INVALID))
579 return bus_send_error_reply(connection, message, &error, -EINVAL);
580
581 if (lrtc != local_rtc) {
2076cf88
LP
582 struct timespec ts;
583
f401e48c
LP
584 r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-local-rtc", interactive, &error);
585 if (r < 0)
586 return bus_send_error_reply(connection, message, &error, r);
587
588 local_rtc = lrtc;
589
2076cf88 590 /* 1. Write new configuration file */
f401e48c
LP
591 r = write_data_local_rtc();
592 if (r < 0) {
593 log_error("Failed to set RTC to local/UTC: %s", strerror(-r));
594 return bus_send_error_reply(connection, message, NULL, r);
595 }
596
2076cf88
LP
597 /* 2. Teach kernel new timezone */
598 if (local_rtc)
ff4daf5a 599 hwclock_apply_localtime_delta(NULL);
2076cf88
LP
600 else
601 hwclock_reset_localtime_delta();
602
603 /* 3. Synchronize clocks */
604 assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
605
05a4abb9 606 if (fix_system) {
2076cf88
LP
607 struct tm tm;
608
609 /* Sync system clock from RTC; first,
610 * initialize the timezone fields of
611 * struct tm. */
612 if (local_rtc)
613 tm = *localtime(&ts.tv_sec);
614 else
615 tm = *gmtime(&ts.tv_sec);
616
617 /* Override the main fields of
618 * struct tm, but not the timezone
619 * fields */
620 if (hwclock_get_time(&tm) >= 0) {
621
622 /* And set the system clock
623 * with this */
624 if (local_rtc)
625 ts.tv_sec = mktime(&tm);
626 else
627 ts.tv_sec = timegm(&tm);
628
629 clock_settime(CLOCK_REALTIME, &ts);
630 }
631
632 } else {
633 struct tm *tm;
634
635 /* Sync RTC from system clock */
636 if (local_rtc)
637 tm = localtime(&ts.tv_sec);
638 else
639 tm = gmtime(&ts.tv_sec);
640
641 hwclock_set_time(tm);
642 }
643
c5f0532f 644 log_info("RTC configured to %s time.", local_rtc ? "local" : "UTC");
f401e48c
LP
645
646 changed = bus_properties_changed_new(
647 "/org/freedesktop/timedate1",
648 "org.freedesktop.timedate1",
649 "LocalRTC\0");
650 if (!changed)
651 goto oom;
652 }
653
654 } else if (dbus_message_is_method_call(message, "org.freedesktop.timedate1", "SetTime")) {
655 int64_t utc;
656 dbus_bool_t relative;
657 dbus_bool_t interactive;
658
659 if (!dbus_message_get_args(
660 message,
661 &error,
662 DBUS_TYPE_INT64, &utc,
663 DBUS_TYPE_BOOLEAN, &relative,
664 DBUS_TYPE_BOOLEAN, &interactive,
665 DBUS_TYPE_INVALID))
666 return bus_send_error_reply(connection, message, &error, -EINVAL);
667
668 if (!relative && utc <= 0)
669 return bus_send_error_reply(connection, message, NULL, -EINVAL);
670
671 if (!relative || utc != 0) {
672 struct timespec ts;
2076cf88 673 struct tm* tm;
f401e48c
LP
674
675 r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-time", interactive, &error);
676 if (r < 0)
677 return bus_send_error_reply(connection, message, &error, r);
678
679 if (relative)
680 timespec_store(&ts, now(CLOCK_REALTIME) + utc);
681 else
682 timespec_store(&ts, utc);
683
2076cf88 684 /* Set system clock */
f401e48c
LP
685 if (clock_settime(CLOCK_REALTIME, &ts) < 0) {
686 log_error("Failed to set local time: %m");
687 return bus_send_error_reply(connection, message, NULL, -errno);
688 }
689
2076cf88
LP
690 /* Sync down to RTC */
691 if (local_rtc)
692 tm = localtime(&ts.tv_sec);
693 else
694 tm = gmtime(&ts.tv_sec);
695
696 hwclock_set_time(tm);
697
f401e48c
LP
698 log_info("Changed local time to %s", ctime(&ts.tv_sec));
699 }
c5f0532f
LP
700 } else if (dbus_message_is_method_call(message, "org.freedesktop.timedate1", "SetNTP")) {
701 dbus_bool_t ntp;
702 dbus_bool_t interactive;
703
704 if (!dbus_message_get_args(
705 message,
706 &error,
707 DBUS_TYPE_BOOLEAN, &ntp,
708 DBUS_TYPE_BOOLEAN, &interactive,
709 DBUS_TYPE_INVALID))
710 return bus_send_error_reply(connection, message, &error, -EINVAL);
711
712 if (ntp != !!use_ntp) {
713
714 r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-ntp", interactive, &error);
715 if (r < 0)
716 return bus_send_error_reply(connection, message, &error, r);
717
718 use_ntp = !!ntp;
719
720 r = enable_ntp(connection, &error);
721 if (r < 0)
722 return bus_send_error_reply(connection, message, &error, r);
723
724 r = start_ntp(connection, &error);
725 if (r < 0)
726 return bus_send_error_reply(connection, message, &error, r);
727
728 log_info("Set NTP to %s", use_ntp ? "enabled" : "disabled");
729
730 changed = bus_properties_changed_new(
731 "/org/freedesktop/timedate1",
732 "org.freedesktop.timedate1",
733 "NTP\0");
734 if (!changed)
735 goto oom;
736 }
f401e48c
LP
737
738 } else
739 return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
740
741 if (!(reply = dbus_message_new_method_return(message)))
742 goto oom;
743
744 if (!dbus_connection_send(connection, reply, NULL))
745 goto oom;
746
747 dbus_message_unref(reply);
748 reply = NULL;
749
750 if (changed) {
751
752 if (!dbus_connection_send(connection, changed, NULL))
753 goto oom;
754
755 dbus_message_unref(changed);
756 }
757
758 return DBUS_HANDLER_RESULT_HANDLED;
759
760oom:
761 if (reply)
762 dbus_message_unref(reply);
763
764 if (changed)
765 dbus_message_unref(changed);
766
767 dbus_error_free(&error);
768
769 return DBUS_HANDLER_RESULT_NEED_MEMORY;
770}
771
772static int connect_bus(DBusConnection **_bus) {
773 static const DBusObjectPathVTable timedate_vtable = {
774 .message_function = timedate_message_handler
775 };
776 DBusError error;
777 DBusConnection *bus = NULL;
778 int r;
779
780 assert(_bus);
781
782 dbus_error_init(&error);
783
784 bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
785 if (!bus) {
a2e52832 786 log_error("Failed to get system D-Bus connection: %s", bus_error_message(&error));
f401e48c
LP
787 r = -ECONNREFUSED;
788 goto fail;
789 }
790
791 if (!dbus_connection_register_object_path(bus, "/org/freedesktop/timedate1", &timedate_vtable, NULL)) {
792 log_error("Not enough memory");
793 r = -ENOMEM;
794 goto fail;
795 }
796
add10b5a
LP
797 r = dbus_bus_request_name(bus, "org.freedesktop.timedate1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error);
798 if (dbus_error_is_set(&error)) {
799 log_error("Failed to register name on bus: %s", bus_error_message(&error));
800 r = -EEXIST;
801 goto fail;
802 }
803
804 if (r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
805 log_error("Failed to acquire name.");
f401e48c
LP
806 r = -EEXIST;
807 goto fail;
808 }
809
810 if (_bus)
811 *_bus = bus;
812
813 return 0;
814
815fail:
816 dbus_connection_close(bus);
817 dbus_connection_unref(bus);
818
819 dbus_error_free(&error);
820
821 return r;
822}
823
824int main(int argc, char *argv[]) {
825 int r;
826 DBusConnection *bus = NULL;
827
828 log_set_target(LOG_TARGET_AUTO);
829 log_parse_environment();
830 log_open();
831
4c12626c
LP
832 umask(0022);
833
91f9dcaf
LP
834 if (argc == 2 && streq(argv[1], "--introspect")) {
835 fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
836 "<node>\n", stdout);
837 fputs(timedate_interface, stdout);
838 fputs("</node>\n", stdout);
839 return 0;
840 }
841
f401e48c
LP
842 if (argc != 1) {
843 log_error("This program takes no arguments.");
844 r = -EINVAL;
845 goto finish;
846 }
847
f401e48c
LP
848 r = read_data();
849 if (r < 0) {
850 log_error("Failed to read timezone data: %s", strerror(-r));
851 goto finish;
852 }
853
854 r = connect_bus(&bus);
855 if (r < 0)
856 goto finish;
857
c5f0532f
LP
858 r = read_ntp(bus);
859 if (r < 0) {
860 log_error("Failed to determine whether NTP is enabled: %s", strerror(-r));
861 goto finish;
862 }
863
f401e48c
LP
864 while (dbus_connection_read_write_dispatch(bus, -1))
865 ;
866
867 r = 0;
868
869finish:
870 free_data();
871
872 if (bus) {
873 dbus_connection_flush(bus);
874 dbus_connection_close(bus);
875 dbus_connection_unref(bus);
876 }
877
878 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
879}