chiark / gitweb /
log: introduce a macro to format message id
[elogind.git] / src / timedate / timedated.c
index 34d287b2a14c6f85328db0f805e4315fdf7bd009..40ba25509059036ee359839da07a4da36f8ecd70 100644 (file)
@@ -34,6 +34,7 @@
 #include "def.h"
 #include "hwclock.h"
 #include "conf-files.h"
+#include "path-util.h"
 
 #define NULL_ADJTIME_UTC "0.0 0 0\n0\nUTC\n"
 #define NULL_ADJTIME_LOCAL "0.0 0 0\n0\nLOCAL\n"
@@ -145,62 +146,50 @@ 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;
+static int read_data(void) {
+        int r;
+        _cleanup_free_ char *t = NULL;
 
-        if (!tz.zone)
-                return;
+        free_data();
 
-        p = strappend("/usr/share/zoneinfo/", tz.zone);
-        if (!p) {
-                log_oom();
-                return;
-        }
+        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 /usr/share/zoneinfo/.");
+                else
+                        log_warning("Failed to get target of /etc/localtime: %s", strerror(-r));
+        } else {
+                const char *e;
 
-        j = read_full_file("/etc/localtime", &a, &l);
-        k = read_full_file(p, &b, &q);
+                e = path_startswith(t, "/usr/share/zoneinfo/");
+                if (!e)
+                        e = path_startswith(t, "../usr/share/zoneinfo/");
 
-        free(p);
+                if (!e)
+                        log_warning("/etc/localtime should be a symbolic link to a timezone data file in /usr/share/zoneinfo/.");
+                else {
+                        tz.zone = strdup(e);
+                        if (!tz.zone)
+                                return log_oom();
 
-        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;
+                        goto have_timezone;
+                }
         }
 
-        free(a);
-        free(b);
-}
-
-static int read_data(void) {
-        int r;
-
-        free_data();
-
+#ifdef HAVE_DEBIAN
         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
         }
+#endif
 
+have_timezone:
         if (isempty(tz.zone)) {
                 free(tz.zone);
                 tz.zone = NULL;
         }
 
-        verify_timezone();
-
         tz.local_rtc = hwclock_is_localtime() > 0;
 
         return 0;
@@ -208,31 +197,39 @@ static int read_data(void) {
 
 static int write_data_timezone(void) {
         int r = 0;
-        char *p;
+        _cleanup_free_ char *p = NULL;
+
+#ifdef TARGET_DEBIAN
+        struct stat st;
+#endif
 
         if (!tz.zone) {
-                if (unlink("/etc/timezone") < 0 && errno != ENOENT)
+                if (unlink("/etc/localtime") < 0 && errno != ENOENT)
                         r = -errno;
 
-                if (unlink("/etc/localtime") < 0 && errno != ENOENT)
+#ifdef TARGET_DEBIAN
+                if (unlink("/etc/timezone") < 0 && errno != ENOENT)
                         r = -errno;
+#endif
 
                 return r;
         }
 
-        p = strappend("/usr/share/zoneinfo/", tz.zone);
+        p = strappend("../usr/share/zoneinfo/", tz.zone);
         if (!p)
                 return log_oom();
 
-        r = symlink_or_copy_atomic(p, "/etc/localtime");
-        free(p);
-
+        r = symlink_atomic(p, "/etc/localtime");
         if (r < 0)
                 return r;
 
-        r = write_one_line_file_atomic("/etc/timezone", tz.zone);
-        if (r < 0)
-                return r;
+#ifdef TARGET_DEBIAN
+        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;
+        }
+#endif
 
         return 0;
 }
@@ -690,13 +687,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));
@@ -704,7 +701,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);
@@ -747,11 +744,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);
@@ -849,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);
@@ -1029,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");
                 }
         }