X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Ftimedated.c;h=b2a56e7cb0d7b1f39a0f9f527443b74602f115df;hp=4bde0355a55e391949693ffe8598c88f4d72adec;hb=ad740100d108282d0244d5739d4dcc86fe4c5fde;hpb=4c12626c8e3491570b395d68380543e10c98ad33 diff --git a/src/timedated.c b/src/timedated.c index 4bde0355a..b2a56e7cb 100644 --- a/src/timedated.c +++ b/src/timedated.c @@ -29,6 +29,7 @@ #include "strv.h" #include "dbus-common.h" #include "polkit.h" +#include "def.h" #define NULL_ADJTIME_UTC "0.0 0 0\n0\nUTC\n" #define NULL_ADJTIME_LOCAL "0.0 0 0\n0\nLOCAL\n" @@ -37,6 +38,7 @@ " \n" \ " \n" \ " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -51,6 +53,10 @@ " \n" \ " \n" \ " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ " \n" #define INTROSPECTION \ @@ -70,6 +76,9 @@ const char timedate_interface[] _introspect_("timedate1") = INTERFACE; static char *zone = NULL; static bool local_rtc = false; +static int use_ntp = -1; + +static usec_t remain_until = 0; static void free_data(void) { free(zone); @@ -271,6 +280,213 @@ static int write_data_local_rtc(void) { return r; } +static int read_ntp(DBusConnection *bus) { + DBusMessage *m = NULL, *reply = NULL; + const char *name = "ntpd.service", *s; + DBusError error; + int r; + + assert(bus); + + dbus_error_init(&error); + + m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "GetUnitFileState"); + + if (!m) { + log_error("Out of memory"); + r = -ENOMEM; + goto finish; + } + + if (!dbus_message_append_args(m, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID)) { + log_error("Could not append arguments to message."); + r = -ENOMEM; + goto finish; + } + + reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); + if (!reply) { + log_error("Failed to issue method call: %s", bus_error_message(&error)); + r = -EIO; + goto finish; + } + + if (!dbus_message_get_args(reply, &error, + DBUS_TYPE_STRING, &s, + DBUS_TYPE_INVALID)) { + log_error("Failed to parse reply: %s", bus_error_message(&error)); + r = -EIO; + goto finish; + } + + use_ntp = + streq(s, "enabled") || + streq(s, "enabled-runtime"); + r = 0; + +finish: + if (m) + dbus_message_unref(m); + + if (reply) + dbus_message_unref(reply); + + dbus_error_free(&error); + + return r; +} + +static int start_ntp(DBusConnection *bus, DBusError *error) { + DBusMessage *m = NULL, *reply = NULL; + const char *name = "ntpd.service", *mode = "replace"; + int r; + + assert(bus); + assert(error); + + m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + use_ntp ? "StartUnit" : "StopUnit"); + if (!m) { + log_error("Could not allocate message."); + r = -ENOMEM; + goto finish; + } + + if (!dbus_message_append_args(m, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_STRING, &mode, + DBUS_TYPE_INVALID)) { + log_error("Could not append arguments to message."); + r = -ENOMEM; + goto finish; + } + + reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error); + if (!reply) { + log_error("Failed to issue method call: %s", bus_error_message(error)); + r = -EIO; + goto finish; + } + + r = 0; + +finish: + if (m) + dbus_message_unref(m); + + if (reply) + dbus_message_unref(reply); + + return r; +} + +static int enable_ntp(DBusConnection *bus, DBusError *error) { + DBusMessage *m = NULL, *reply = NULL; + const char * const names[] = { "ntpd.service", NULL }; + int r; + DBusMessageIter iter; + dbus_bool_t f = FALSE, t = TRUE; + + assert(bus); + assert(error); + + m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + use_ntp ? "EnableUnitFiles" : "DisableUnitFiles"); + + if (!m) { + log_error("Could not allocate message."); + r = -ENOMEM; + goto finish; + } + + dbus_message_iter_init_append(m, &iter); + + r = bus_append_strv_iter(&iter, (char**) names); + if (r < 0) { + log_error("Failed to append unit files."); + goto finish; + } + /* send runtime bool */ + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &f)) { + log_error("Failed to append runtime boolean."); + r = -ENOMEM; + goto finish; + } + + if (use_ntp) { + /* send force bool */ + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &t)) { + log_error("Failed to append force boolean."); + r = -ENOMEM; + goto finish; + } + } + + reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error); + if (!reply) { + log_error("Failed to issue method call: %s", bus_error_message(error)); + r = -EIO; + goto finish; + } + + dbus_message_unref(m); + m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "Reload"); + if (!m) { + log_error("Could not allocate message."); + r = -ENOMEM; + goto finish; + } + + dbus_message_unref(reply); + reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error); + if (!reply) { + log_error("Failed to issue method call: %s", bus_error_message(error)); + r = -EIO; + goto finish; + } + + r = 0; + +finish: + if (m) + dbus_message_unref(m); + + if (reply) + dbus_message_unref(reply); + + return r; +} + +static int property_append_ntp(DBusMessageIter *i, const char *property, void *data) { + dbus_bool_t db; + + assert(i); + assert(property); + + db = use_ntp > 0; + + if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db)) + return -ENOMEM; + + return 0; +} + static DBusHandlerResult timedate_message_handler( DBusConnection *connection, DBusMessage *message, @@ -279,6 +495,7 @@ static DBusHandlerResult timedate_message_handler( const BusProperty properties[] = { { "org.freedesktop.timedate1", "Timezone", bus_property_append_string, "s", zone }, { "org.freedesktop.timedate1", "LocalRTC", bus_property_append_bool, "b", &local_rtc }, + { "org.freedesktop.timedate1", "NTP", property_append_ntp, "b", NULL }, { NULL, NULL, NULL, NULL, NULL } }; @@ -427,7 +644,7 @@ static DBusHandlerResult timedate_message_handler( hwclock_set_time(tm); } - log_error("RTC configured to %s time.", local_rtc ? "local" : "UTC"); + log_info("RTC configured to %s time.", local_rtc ? "local" : "UTC"); changed = bus_properties_changed_new( "/org/freedesktop/timedate1", @@ -483,6 +700,43 @@ static DBusHandlerResult timedate_message_handler( log_info("Changed local time to %s", ctime(&ts.tv_sec)); } + } else if (dbus_message_is_method_call(message, "org.freedesktop.timedate1", "SetNTP")) { + dbus_bool_t ntp; + dbus_bool_t interactive; + + if (!dbus_message_get_args( + message, + &error, + DBUS_TYPE_BOOLEAN, &ntp, + DBUS_TYPE_BOOLEAN, &interactive, + DBUS_TYPE_INVALID)) + return bus_send_error_reply(connection, message, &error, -EINVAL); + + if (ntp != !!use_ntp) { + + r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-ntp", interactive, &error); + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + + use_ntp = !!ntp; + + r = enable_ntp(connection, &error); + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + + r = start_ntp(connection, &error); + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + + log_info("Set NTP to %s", use_ntp ? "enabled" : "disabled"); + + changed = bus_properties_changed_new( + "/org/freedesktop/timedate1", + "org.freedesktop.timedate1", + "NTP\0"); + if (!changed) + goto oom; + } } else return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties); @@ -537,7 +791,10 @@ static int connect_bus(DBusConnection **_bus) { goto fail; } - if (!dbus_connection_register_object_path(bus, "/org/freedesktop/timedate1", &timedate_vtable, NULL)) { + dbus_connection_set_exit_on_disconnect(bus, FALSE); + + if (!dbus_connection_register_object_path(bus, "/org/freedesktop/timedate1", &timedate_vtable, NULL) || + !dbus_connection_add_filter(bus, bus_exit_idle_filter, &remain_until, NULL)) { log_error("Not enough memory"); r = -ENOMEM; goto fail; @@ -573,6 +830,7 @@ fail: int main(int argc, char *argv[]) { int r; DBusConnection *bus = NULL; + bool exiting = false; log_set_target(LOG_TARGET_AUTO); log_parse_environment(); @@ -604,8 +862,23 @@ int main(int argc, char *argv[]) { if (r < 0) goto finish; - while (dbus_connection_read_write_dispatch(bus, -1)) - ; + r = read_ntp(bus); + if (r < 0) { + log_error("Failed to determine whether NTP is enabled: %s", strerror(-r)); + goto finish; + } + + remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC; + for (;;) { + + if (!dbus_connection_read_write_dispatch(bus, exiting ? -1 : (int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC))) + break; + + if (!exiting && remain_until < now(CLOCK_MONOTONIC)) { + exiting = true; + bus_async_unregister_and_exit(bus, "org.freedesktop.hostname1"); + } + } r = 0;