#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"
" <interface name=\"org.freedesktop.timedate1\">\n" \
" <property name=\"Timezone\" type=\"s\" access=\"read\"/>\n" \
" <property name=\"LocalRTC\" type=\"b\" access=\"read\"/>\n" \
+ " <property name=\"CanNTP\" type=\"b\" access=\"read\"/>\n" \
" <property name=\"NTP\" type=\"b\" access=\"read\"/>\n" \
" <method name=\"SetTime\">\n" \
" <arg name=\"usec_utc\" type=\"x\" direction=\"in\"/>\n" \
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,
};
if (slash)
return false;
- t = strappend(ZONEINFO_PATH, name);
+ t = strappend("/usr/share/zoneinfo/", name);
if (!t)
return false;
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;
- 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);
+ e = path_startswith(t, "/usr/share/zoneinfo/");
+ if (!e)
+ e = path_startswith(t, "../usr/share/zoneinfo/");
+
+ 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();
}
}
- 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;
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;
}
return 0;
}
}
-
- r = write_one_line_file_atomic("/etc/adjtime", w);
+ label_init("/etc");
+ r = write_one_line_file_atomic_label("/etc/adjtime", w);
free(w);
return r;
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",
goto finish;
}
+ tz.can_ntp = 1;
tz.use_ntp =
streq(s, "enabled") ||
streq(s, "enabled-runtime");
}
/* NTP is not installed. */
+ tz.can_ntp = 0;
tz.use_ntp = 0;
r = 0;
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;
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, }
};
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));
}
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);
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);
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);
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);
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);
fail:
dbus_connection_close(bus);
dbus_connection_unref(bus);
-
+fail2:
dbus_error_free(&error);
return r;
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");
}
}