chiark / gitweb /
timedated: make sure GetAll() succeeds in systems lacking /dev/rtc (such as containers)
[elogind.git] / src / timedate / timedated.c
index 809c80bad11297acc1fdd6342f79d05f542fef97..e3421c24a9ac16a53782f6220771b7e9fdc1a386 100644 (file)
@@ -458,8 +458,8 @@ static int property_get_rtc_time(
                 const char *interface,
                 const char *property,
                 sd_bus_message *reply,
-                sd_bus_error *error,
-                void *userdata) {
+                void *userdata,
+                sd_bus_error *error) {
 
         struct tm tm;
         usec_t t;
@@ -467,18 +467,18 @@ static int property_get_rtc_time(
 
         zero(tm);
         r = hwclock_get_time(&tm);
-        if (r < 0) {
-                sd_bus_error_set_errnof(error, -r, "Failed to read RTC: %s", strerror(-r));
-                return r;
-        }
-
-        t = (usec_t) mktime(&tm) * USEC_PER_SEC;
-
-        r = sd_bus_message_append(reply, "t", t);
-        if (r < 0)
-                return r;
+        if (r == -EBUSY) {
+                log_warning("/dev/rtc is busy, is somebody keeping it open continously? That's not a good idea... Returning a bogus RTC timestamp.");
+                t = 0;
+        } else if (r == -ENOENT) {
+                log_debug("Not /dev/rtc found.");
+                t = 0; /* no RTC found */
+        } else if (r < 0)
+                return sd_bus_error_set_errnof(error, r, "Failed to read RTC: %s", strerror(-r));
+        else
+                t = (usec_t) timegm(&tm) * USEC_PER_SEC;
 
-        return 1;
+        return sd_bus_message_append(reply, "t", t);
 }
 
 static int property_get_time(
@@ -487,16 +487,10 @@ static int property_get_time(
                 const char *interface,
                 const char *property,
                 sd_bus_message *reply,
-                sd_bus_error *error,
-                void *userdata) {
+                void *userdata,
+                sd_bus_error *error) {
 
-        int r;
-
-        r = sd_bus_message_append(reply, "t", now(CLOCK_REALTIME));
-        if (r < 0)
-                return r;
-
-        return 1;
+        return sd_bus_message_append(reply, "t", now(CLOCK_REALTIME));
 }
 
 static int property_get_ntp_sync(
@@ -505,23 +499,16 @@ static int property_get_ntp_sync(
                 const char *interface,
                 const char *property,
                 sd_bus_message *reply,
-                sd_bus_error *error,
-                void *userdata) {
+                void *userdata,
+                sd_bus_error *error) {
 
-        int r;
-
-        r = sd_bus_message_append(reply, "b", ntp_synced());
-        if (r < 0)
-                return r;
-
-        return 1;
+        return sd_bus_message_append(reply, "b", ntp_synced());
 }
 
-static int method_set_timezone(sd_bus *bus, sd_bus_message *m, void *userdata) {
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+static int method_set_timezone(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
         Context *c = userdata;
         const char *z;
-        unsigned interactive;
+        int interactive;
         char *t;
         int r;
 
@@ -531,23 +518,23 @@ static int method_set_timezone(sd_bus *bus, sd_bus_message *m, void *userdata) {
 
         r = sd_bus_message_read(m, "sb", &z, &interactive);
         if (r < 0)
-                return sd_bus_reply_method_errno(bus, m, r, NULL);
+                return r;
 
         if (!valid_timezone(z))
-                return sd_bus_reply_method_errorf(bus, m, SD_BUS_ERROR_INVALID_ARGS, "Invalid time zone '%s'", z);
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid time zone '%s'", z);
 
         if (streq_ptr(z, c->zone))
-                return sd_bus_reply_method_return(bus, m, NULL);
+                return sd_bus_reply_method_return(m, NULL);
 
-        r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.timedate1.set-timezone", interactive, &error, method_set_timezone, c);
+        r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.timedate1.set-timezone", interactive, error, method_set_timezone, c);
         if (r < 0)
-                return sd_bus_reply_method_errno(bus, m, r, &error);
+                return r;
         if (r == 0)
                 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
 
         t = strdup(z);
         if (!t)
-                return log_oom();
+                return -ENOMEM;
 
         free(c->zone);
         c->zone = t;
@@ -556,7 +543,7 @@ static int method_set_timezone(sd_bus *bus, sd_bus_message *m, void *userdata) {
         r = context_write_data_timezone(c);
         if (r < 0) {
                 log_error("Failed to set timezone: %s", strerror(-r));
-                return sd_bus_reply_method_errnof(bus, m, r, "Failed to set timezone: %s", strerror(-r));
+                return sd_bus_error_set_errnof(error, r, "Failed to set timezone: %s", strerror(-r));
         }
 
         /* 2. Tell the kernel our timezone */
@@ -580,12 +567,11 @@ static int method_set_timezone(sd_bus *bus, sd_bus_message *m, void *userdata) {
 
         sd_bus_emit_properties_changed(bus, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "Timezone", NULL);
 
-        return sd_bus_reply_method_return(bus, m, NULL);
+        return sd_bus_reply_method_return(m, NULL);
 }
 
-static int method_set_local_rtc(sd_bus *bus, sd_bus_message *m, void *userdata) {
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        unsigned lrtc, fix_system, interactive;
+static int method_set_local_rtc(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+        int lrtc, fix_system, interactive;
         Context *c = userdata;
         struct timespec ts;
         int r;
@@ -596,14 +582,14 @@ static int method_set_local_rtc(sd_bus *bus, sd_bus_message *m, void *userdata)
 
         r = sd_bus_message_read(m, "bbb", &lrtc, &fix_system, &interactive);
         if (r < 0)
-                return sd_bus_reply_method_errno(bus, m, r, NULL);
+                return r;
 
         if (lrtc == c->local_rtc)
-                return sd_bus_reply_method_return(bus, m, NULL);
+                return sd_bus_reply_method_return(m, NULL);
 
-        r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.timedate1.set-local-rtc", interactive, &error, method_set_local_rtc, c);
+        r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.timedate1.set-local-rtc", interactive, error, method_set_local_rtc, c);
         if (r < 0)
-                return sd_bus_reply_method_errno(bus, m, r, &error);
+                return r;
         if (r == 0)
                 return 1;
 
@@ -613,7 +599,7 @@ static int method_set_local_rtc(sd_bus *bus, sd_bus_message *m, void *userdata)
         r = context_write_data_local_rtc(c);
         if (r < 0) {
                 log_error("Failed to set RTC to local/UTC: %s", strerror(-r));
-                return sd_bus_reply_method_errnof(bus, m, r, "Failed to set RTC to local/UTC: %s", strerror(-r));
+                return sd_bus_error_set_errnof(error, r, "Failed to set RTC to local/UTC: %s", strerror(-r));
         }
 
         /* 2. Tell the kernel our timezone */
@@ -664,12 +650,11 @@ static int method_set_local_rtc(sd_bus *bus, sd_bus_message *m, void *userdata)
 
         sd_bus_emit_properties_changed(bus, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "LocalRTC", NULL);
 
-        return sd_bus_reply_method_return(bus, m, NULL);
+        return sd_bus_reply_method_return(m, NULL);
 }
 
-static int method_set_time(sd_bus *bus, sd_bus_message *m, void *userdata) {
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        unsigned relative, interactive;
+static int method_set_time(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+        int relative, interactive;
         Context *c = userdata;
         int64_t utc;
         struct timespec ts;
@@ -682,13 +667,13 @@ static int method_set_time(sd_bus *bus, sd_bus_message *m, void *userdata) {
 
         r = sd_bus_message_read(m, "xbb", &utc, &relative, &interactive);
         if (r < 0)
-                return sd_bus_reply_method_errno(bus, m, r, NULL);
+                return r;
 
         if (!relative && utc <= 0)
-                return sd_bus_reply_method_errorf(bus, m, SD_BUS_ERROR_INVALID_ARGS, "Invalid absolute time");
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid absolute time");
 
         if (relative && utc == 0)
-                return sd_bus_reply_method_return(bus, m, NULL);
+                return sd_bus_reply_method_return(m, NULL);
 
         if (relative) {
                 usec_t n, x;
@@ -698,22 +683,22 @@ static int method_set_time(sd_bus *bus, sd_bus_message *m, void *userdata) {
 
                 if ((utc > 0 && x < n) ||
                     (utc < 0 && x > n))
-                        return sd_bus_reply_method_errorf(bus, m, SD_BUS_ERROR_INVALID_ARGS, "Time value overflow");
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Time value overflow");
 
                 timespec_store(&ts, x);
         } else
                 timespec_store(&ts, (usec_t) utc);
 
-        r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.timedate1.set-time", interactive, &error, method_set_time, c);
+        r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.timedate1.set-time", interactive, error, method_set_time, c);
         if (r < 0)
-                return sd_bus_reply_method_errno(bus, m, r, &error);
+                return r;
         if (r == 0)
                 return 1;
 
         /* Set system clock */
         if (clock_settime(CLOCK_REALTIME, &ts) < 0) {
                 log_error("Failed to set local time: %m");
-                return sd_bus_reply_method_errnof(bus, m, errno, "Failed to set local time: %m");
+                return sd_bus_error_set_errnof(error, errno, "Failed to set local time: %m");
         }
 
         /* Sync down to RTC */
@@ -730,45 +715,46 @@ static int method_set_time(sd_bus *bus, sd_bus_message *m, void *userdata) {
                    "MESSAGE=Changed local time to %s", ctime(&ts.tv_sec),
                    NULL);
 
-        return sd_bus_reply_method_return(bus, m, NULL);
+        return sd_bus_reply_method_return(m, NULL);
 }
 
-static int method_set_ntp(sd_bus *bus, sd_bus_message *m, void *userdata) {
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        unsigned ntp, interactive;
+static int method_set_ntp(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+        int ntp, interactive;
         Context *c = userdata;
         int r;
 
         r = sd_bus_message_read(m, "bb", &ntp, &interactive);
         if (r < 0)
-                return sd_bus_reply_method_errno(bus, m, r, NULL);
+                return r;
 
-        if (ntp == c->use_ntp)
-                return sd_bus_reply_method_return(bus, m, NULL);
+        if ((bool)ntp == c->use_ntp)
+                return sd_bus_reply_method_return(m, NULL);
 
-        r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.timedate1.set-ntp", interactive, &error, method_set_ntp, c);
+        r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.timedate1.set-ntp", interactive, error, method_set_ntp, c);
         if (r < 0)
-                return sd_bus_reply_method_errno(bus, m, r, &error);
+                return r;
         if (r == 0)
                 return 1;
 
         c->use_ntp = ntp;
 
-        r = context_enable_ntp(c, bus, &error);
+        r = context_enable_ntp(c, bus, error);
         if (r < 0)
-                return sd_bus_reply_method_errno(bus, m, r, &error);
+                return r;
 
-        r = context_start_ntp(c, bus, &error);
+        r = context_start_ntp(c, bus, error);
         if (r < 0)
-                return sd_bus_reply_method_errno(bus, m, r, &error);
+                return r;
 
         log_info("Set NTP to %s", c->use_ntp ? "enabled" : "disabled");
 
         sd_bus_emit_properties_changed(bus, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "NTP", NULL);
 
-        return sd_bus_reply_method_return(bus, m, NULL);
+        return sd_bus_reply_method_return(m, NULL);
 }
 
+#include <sys/capability.h>
+
 static const sd_bus_vtable timedate_vtable[] = {
         SD_BUS_VTABLE_START(0),
         SD_BUS_PROPERTY("Timezone", "s", NULL, offsetof(Context, zone), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
@@ -778,10 +764,10 @@ static const sd_bus_vtable timedate_vtable[] = {
         SD_BUS_PROPERTY("NTPSynchronized", "b", property_get_ntp_sync, 0, 0),
         SD_BUS_PROPERTY("TimeUSec", "t", property_get_time, 0, 0),
         SD_BUS_PROPERTY("RTCTimeUSec", "t", property_get_rtc_time, 0, 0),
-        SD_BUS_METHOD("SetTime", "xbb", NULL, method_set_time, 0),
-        SD_BUS_METHOD("SetTimezone", "sb", NULL, method_set_timezone, 0),
-        SD_BUS_METHOD("SetLocalRTC", "bbb", NULL, method_set_local_rtc, 0),
-        SD_BUS_METHOD("SetNTP", "bb", NULL, method_set_ntp, 0),
+        SD_BUS_METHOD("SetTime", "xbb", NULL, method_set_time, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetTimezone", "sb", NULL, method_set_timezone, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetLocalRTC", "bbb", NULL, method_set_local_rtc, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetNTP", "bb", NULL, method_set_ntp, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_VTABLE_END,
 };
 
@@ -793,7 +779,7 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
         assert(event);
         assert(_bus);
 
-        r = sd_bus_open_system(&bus);
+        r = sd_bus_default_system(&bus);
         if (r < 0) {
                 log_error("Failed to get system bus connection: %s", strerror(-r));
                 return r;
@@ -805,17 +791,12 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
                 return r;
         }
 
-        r = sd_bus_request_name(bus, "org.freedesktop.timedate1", SD_BUS_NAME_DO_NOT_QUEUE);
+        r = sd_bus_request_name(bus, "org.freedesktop.timedate1", SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_DO_NOT_QUEUE);
         if (r < 0) {
                 log_error("Failed to register name: %s", strerror(-r));
                 return r;
         }
 
-        if (r != SD_BUS_NAME_PRIMARY_OWNER) {
-                log_error("Failed to acquire name.");
-                return -EEXIST;
-        }
-
         r = sd_bus_attach_event(bus, event, 0);
         if (r < 0) {
                 log_error("Failed to attach bus to event loop: %s", strerror(-r));
@@ -852,12 +833,14 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
 
-        r = sd_event_new(&event);
+        r = sd_event_default(&event);
         if (r < 0) {
                 log_error("Failed to allocate event loop: %s", strerror(-r));
                 goto finish;
         }
 
+        sd_event_set_watchdog(event, true);
+
         r = connect_bus(&context, event, &bus);
         if (r < 0)
                 goto finish;