X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Ftimedate%2Ftimedated.c;h=e068724903f57bd85758c77f919cdd3e95b1e079;hp=9ca2eec5a8aa18ea3ae7ad0443c8c5721a3f14ff;hb=574d5f2dfc25226afc718aa5ba1a145fe5cad221;hpb=92c4ef2d357baeef78b6f82f119b92f7ed12ac77 diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index 9ca2eec5a..e06872490 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -34,6 +34,9 @@ #include "def.h" #include "hwclock.h" #include "conf-files.h" +#include "path-util.h" +#include "fileio-label.h" +#include "label.h" #define NULL_ADJTIME_UTC "0.0 0 0\n0\nUTC\n" #define NULL_ADJTIME_LOCAL "0.0 0 0\n0\nLOCAL\n" @@ -42,6 +45,7 @@ " \n" \ " \n" \ " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -76,18 +80,17 @@ BUS_GENERIC_INTERFACES_LIST \ "org.freedesktop.timedate1\0" -/* Must start and end with '/' */ -#define ZONEINFO_PATH "/usr/share/zoneinfo/" - const char timedate_interface[] _introspect_("timedate1") = INTERFACE; typedef struct TZ { char *zone; bool local_rtc; + int can_ntp; int use_ntp; } TZ; static TZ tz = { + .can_ntp = -1, .use_ntp = -1, }; @@ -132,7 +135,7 @@ static bool valid_timezone(const char *name) { if (slash) return false; - t = strappend(ZONEINFO_PATH, name); + t = strappend("/usr/share/zoneinfo/", name); if (!t) return false; @@ -148,56 +151,29 @@ static bool valid_timezone(const char *name) { return true; } -static void verify_timezone(void) { - char *p, *a = NULL, *b = NULL; - size_t l, q; - int j, k; - - if (!tz.zone) - return; - - p = strappend(ZONEINFO_PATH, tz.zone); - if (!p) { - log_oom(); - return; - } - - k = read_full_file(p, &b, &q); - free(p); - - j = read_full_file("/etc/localtime", &a, &l); - - if (j < 0 || k < 0 || l != q || memcmp(a, b, l)) { - log_warning("/etc/localtime and /etc/timezone out of sync."); - free(tz.zone); - tz.zone = NULL; - } - - free(a); - free(b); -} - static int read_data(void) { int r; - char *t = NULL; + _cleanup_free_ char *t = NULL; free_data(); r = readlink_malloc("/etc/localtime", &t); if (r < 0) { if (r == -EINVAL) - log_warning("/etc/localtime should be a symbolic link to a timezone data file in " ZONEINFO_PATH); + log_warning("/etc/localtime should be a symbolic link to a timezone data file in /usr/share/zoneinfo/."); else - log_warning("Failed to get target of %s: %s", "/etc/localtime", strerror(-r)); + log_warning("Failed to get target of /etc/localtime: %s", strerror(-r)); } else { - /* we only support the trivial relative link of (/etc/)..$ABSOLUTE */ - int rel_link_offset = startswith(t, "..") ? strlen("..") : 0; + const char *e; + + e = path_startswith(t, "/usr/share/zoneinfo/"); + if (!e) + e = path_startswith(t, "../usr/share/zoneinfo/"); - if (!startswith(t + rel_link_offset, ZONEINFO_PATH)) - log_warning("/etc/localtime should be a symbolic link to a timezone data file in " ZONEINFO_PATH); + if (!e) + log_warning("/etc/localtime should be a symbolic link to a timezone data file in /usr/share/zoneinfo/."); else { - tz.zone = strdup(t + rel_link_offset + strlen(ZONEINFO_PATH)); - free(t); + tz.zone = strdup(e); if (!tz.zone) return log_oom(); @@ -205,31 +181,12 @@ static int read_data(void) { } } - free(t); - - r = read_one_line_file("/etc/timezone", &tz.zone); - 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", &tz.zone, - NULL); - - if (r < 0 && r != -ENOENT) - log_warning("Failed to read /etc/sysconfig/clock: %s", strerror(-r)); -#endif - } - have_timezone: if (isempty(tz.zone)) { free(tz.zone); tz.zone = NULL; } - verify_timezone(); - tz.local_rtc = hwclock_is_localtime() > 0; return 0; @@ -237,34 +194,22 @@ have_timezone: static int write_data_timezone(void) { int r = 0; - char *p; - struct stat st; + _cleanup_free_ char *p = NULL; if (!tz.zone) { - if (unlink("/etc/timezone") < 0 && errno != ENOENT) - r = -errno; - if (unlink("/etc/localtime") < 0 && errno != ENOENT) r = -errno; return r; } - p = strappend(ZONEINFO_PATH, tz.zone); + p = strappend("../usr/share/zoneinfo/", tz.zone); if (!p) return log_oom(); - r = symlink(p, "/etc/localtime"); - free(p); - + r = symlink_atomic(p, "/etc/localtime"); if (r < 0) - return -errno; - - if (stat("/etc/timezone", &st) == 0 && S_ISREG(st.st_mode)) { - r = write_one_line_file_atomic("/etc/timezone", tz.zone); - if (r < 0) - return r; - } + return r; return 0; } @@ -329,8 +274,8 @@ static int write_data_local_rtc(void) { return 0; } } - - r = write_one_line_file_atomic("/etc/adjtime", w); + label_init("/etc"); + r = write_string_file_atomic_label("/etc/adjtime", w); free(w); return r; @@ -340,7 +285,7 @@ static char** get_ntp_services(void) { char **r = NULL, **files, **i; int k; - k = conf_files_list(&files, ".list", + k = conf_files_list(&files, ".list", NULL, "/etc/systemd/ntp-units.d", "/run/systemd/ntp-units.d", "/usr/local/lib/systemd/ntp-units.d", @@ -422,8 +367,6 @@ static int read_ntp(DBusConnection *bus) { goto finish; } - if (reply) - dbus_message_unref(reply); reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); if (!reply) { if (streq(error.name, "org.freedesktop.DBus.Error.FileNotFound")) { @@ -445,6 +388,7 @@ static int read_ntp(DBusConnection *bus) { goto finish; } + tz.can_ntp = 1; tz.use_ntp = streq(s, "enabled") || streq(s, "enabled-runtime"); @@ -453,6 +397,7 @@ static int read_ntp(DBusConnection *bus) { } /* NTP is not installed. */ + tz.can_ntp = 0; tz.use_ntp = 0; r = 0; @@ -503,8 +448,6 @@ static int start_ntp(DBusConnection *bus, DBusError *error) { goto finish; } - if (reply) - dbus_message_unref(reply); reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error); if (!reply) { if (streq(error->name, "org.freedesktop.DBus.Error.FileNotFound") || @@ -593,8 +536,6 @@ static int enable_ntp(DBusConnection *bus, DBusError *error) { } } - if (reply) - dbus_message_unref(reply); reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error); if (!reply) { if (streq(error->name, "org.freedesktop.DBus.Error.FileNotFound")) { @@ -646,6 +587,20 @@ finish: return r; } +static int property_append_can_ntp(DBusMessageIter *i, const char *property, void *data) { + dbus_bool_t db; + + assert(i); + assert(property); + + db = tz.can_ntp > 0; + + if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db)) + return -ENOMEM; + + return 0; +} + static int property_append_ntp(DBusMessageIter *i, const char *property, void *data) { dbus_bool_t db; @@ -663,6 +618,7 @@ static int property_append_ntp(DBusMessageIter *i, const char *property, void *d static const BusProperty bus_timedate_properties[] = { { "Timezone", bus_property_append_string, "s", offsetof(TZ, zone), true }, { "LocalRTC", bus_property_append_bool, "b", offsetof(TZ, local_rtc) }, + { "CanNTP", property_append_can_ntp, "b", offsetof(TZ, can_ntp) }, { "NTP", property_append_ntp, "b", offsetof(TZ, use_ntp) }, { NULL, } }; @@ -722,13 +678,13 @@ static DBusHandlerResult timedate_message_handler( return bus_send_error_reply(connection, message, NULL, r); } + /* 2. Tell the kernel our time zone */ + hwclock_set_timezone(NULL); + if (tz.local_rtc) { struct timespec ts; struct tm *tm; - /* 2. Teach kernel new timezone */ - hwclock_apply_localtime_delta(NULL); - /* 3. Sync RTC from system clock, with the new delta */ assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0); assert_se(tm = localtime(&ts.tv_sec)); @@ -736,7 +692,7 @@ static DBusHandlerResult timedate_message_handler( } log_struct(LOG_INFO, - "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(SD_MESSAGE_TIMEZONE_CHANGE), + MESSAGE_ID(SD_MESSAGE_TIMEZONE_CHANGE), "TIMEZONE=%s", tz.zone, "MESSAGE=Changed timezone to '%s'.", tz.zone, NULL); @@ -779,11 +735,8 @@ static DBusHandlerResult timedate_message_handler( return bus_send_error_reply(connection, message, NULL, r); } - /* 2. Teach kernel new timezone */ - if (tz.local_rtc) - hwclock_apply_localtime_delta(NULL); - else - hwclock_reset_localtime_delta(); + /* 2. Tell the kernel our time zone */ + hwclock_set_timezone(NULL); /* 3. Synchronize clocks */ assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0); @@ -857,15 +810,24 @@ static DBusHandlerResult timedate_message_handler( struct timespec ts; struct tm* tm; + if (relative) { + usec_t n, x; + + n = now(CLOCK_REALTIME); + x = n + utc; + + if ((utc > 0 && x < n) || + (utc < 0 && x > n)) + return bus_send_error_reply(connection, message, NULL, -EOVERFLOW); + + timespec_store(&ts, x); + } else + timespec_store(&ts, (usec_t) utc); + r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-time", interactive, NULL, &error); if (r < 0) return bus_send_error_reply(connection, message, &error, r); - if (relative) - timespec_store(&ts, now(CLOCK_REALTIME) + utc); - else - timespec_store(&ts, utc); - /* Set system clock */ if (clock_settime(CLOCK_REALTIME, &ts) < 0) { log_error("Failed to set local time: %m"); @@ -881,7 +843,7 @@ static DBusHandlerResult timedate_message_handler( hwclock_set_time(tm); log_struct(LOG_INFO, - "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(SD_MESSAGE_TIME_CHANGE), + MESSAGE_ID(SD_MESSAGE_TIME_CHANGE), "REALTIME=%llu", (unsigned long long) timespec_load(&ts), "MESSAGE=Changed local time to %s", ctime(&ts.tv_sec), NULL); @@ -930,7 +892,7 @@ static DBusHandlerResult timedate_message_handler( if (!(reply = dbus_message_new_method_return(message))) goto oom; - if (!dbus_connection_send(connection, reply, NULL)) + if (!bus_maybe_send_reply(connection, message, reply)) goto oom; dbus_message_unref(reply); @@ -974,7 +936,7 @@ static int connect_bus(DBusConnection **_bus) { if (!bus) { log_error("Failed to get system D-Bus connection: %s", bus_error_message(&error)); r = -ECONNREFUSED; - goto fail; + goto fail2; } dbus_connection_set_exit_on_disconnect(bus, FALSE); @@ -1006,7 +968,7 @@ static int connect_bus(DBusConnection **_bus) { fail: dbus_connection_close(bus); dbus_connection_unref(bus); - +fail2: dbus_error_free(&error); return r; @@ -1061,7 +1023,7 @@ int main(int argc, char *argv[]) { if (!exiting && remain_until < now(CLOCK_MONOTONIC)) { exiting = true; - bus_async_unregister_and_exit(bus, "org.freedesktop.hostname1"); + bus_async_unregister_and_exit(bus, "org.freedesktop.timedated1"); } }