X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Ftimedated.c;h=16f54b59d263ecdd9b43cc9919b2fa1550a8fb5b;hb=7210bfb3706f8cbb2b35403f916dace1824c516c;hp=097e0a00c27e6abfe58b29fc5d124a55516d5453;hpb=a2e5283217b9e1e636ab3272e8d36e724a78cf6a;p=elogind.git
diff --git a/src/timedated.c b/src/timedated.c
index 097e0a00c..16f54b59d 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 \
@@ -64,12 +70,15 @@
#define INTERFACES_LIST \
BUS_GENERIC_INTERFACES_LIST \
- "org.freedesktop.locale1\0"
+ "org.freedesktop.timedate1\0"
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);
@@ -161,8 +170,24 @@ static int read_data(void) {
free_data();
r = read_one_line_file("/etc/timezone", &zone);
- if (r < 0 && r != -ENOENT)
- return r;
+ if (r < 0) {
+ if (r != -ENOENT)
+ log_warning("Failed to read /etc/timezone: %s", strerror(-r));
+
+#ifdef TARGET_FEDORA
+ r = parse_env_file("/etc/sysconfig/clock", NEWLINE,
+ "ZONE", &zone,
+ NULL);
+
+ if (r < 0 && r != -ENOENT)
+ log_warning("Failed to read /etc/sysconfig/clock: %s", strerror(-r));
+#endif
+ }
+
+ if (isempty(zone)) {
+ free(zone);
+ zone = NULL;
+ }
verify_timezone();
@@ -237,7 +262,7 @@ static int write_data_local_rtc(void) {
p++;
e = strchr(p, '\n');
- if (!p) {
+ if (!e) {
free(s);
return -EIO;
}
@@ -271,6 +296,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 +511,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 }
};
@@ -332,7 +565,7 @@ static DBusHandlerResult timedate_message_handler(
struct tm *tm;
/* 2. Teach kernel new timezone */
- hwclock_apply_localtime_delta();
+ hwclock_apply_localtime_delta(NULL);
/* 3. Sync RTC from system clock, with the new delta */
assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
@@ -382,7 +615,7 @@ static DBusHandlerResult timedate_message_handler(
/* 2. Teach kernel new timezone */
if (local_rtc)
- hwclock_apply_localtime_delta();
+ hwclock_apply_localtime_delta(NULL);
else
hwclock_reset_localtime_delta();
@@ -427,7 +660,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 +716,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,14 +807,24 @@ 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;
}
- if (dbus_bus_request_name(bus, "org.freedesktop.timedate1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error) < 0) {
- log_error("Failed to register name on bus: %s", error.message);
+ r = dbus_bus_request_name(bus, "org.freedesktop.timedate1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error);
+ if (dbus_error_is_set(&error)) {
+ log_error("Failed to register name on bus: %s", bus_error_message(&error));
+ r = -EEXIST;
+ goto fail;
+ }
+
+ if (r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+ log_error("Failed to acquire name.");
r = -EEXIST;
goto fail;
}
@@ -566,11 +846,14 @@ fail:
int main(int argc, char *argv[]) {
int r;
DBusConnection *bus = NULL;
+ bool exiting = false;
log_set_target(LOG_TARGET_AUTO);
log_parse_environment();
log_open();
+ umask(0022);
+
if (argc == 2 && streq(argv[1], "--introspect")) {
fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
"\n", stdout);
@@ -585,8 +868,6 @@ int main(int argc, char *argv[]) {
goto finish;
}
- umask(0022);
-
r = read_data();
if (r < 0) {
log_error("Failed to read timezone data: %s", strerror(-r));
@@ -597,8 +878,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;