timedated: handle UTC specially, when generating /etc/localtime
authorLennart Poettering <lennart@poettering.net>
Wed, 13 Nov 2019 09:32:44 +0000 (10:32 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 13 Nov 2019 09:39:14 +0000 (10:39 +0100)
src/timedate/timedated.c

index 97a0868..eb585b8 100644 (file)
@@ -277,20 +277,35 @@ static int context_read_data(Context *c) {
 
 static int context_write_data_timezone(Context *c) {
         _cleanup_free_ char *p = NULL;
+        const char *source;
 
         assert(c);
 
-        if (isempty(c->zone)) {
-                if (unlink("/etc/localtime") < 0 && errno != ENOENT)
-                        return -errno;
-                return 0;
-        }
+        /* No timezone is very similar to UTC. Hence in either of these cases link the UTC file in. Except if
+         * it isn't installed, in which case we remove the symlink altogether. Since glibc defaults to an
+         * internal version of UTC in that case behaviour is mostly equivalent. We still prefer creating the
+         * symlink though, since things are more self explanatory then. */
 
-        p = path_join("../usr/share/zoneinfo", c->zone);
-        if (!p)
-                return log_oom();
+        if (isempty(c->zone) || streq(c->zone, "UTC")) {
+
+                if (access("/usr/share/zoneinfo/UTC", F_OK) < 0) {
+
+                        if (unlink("/etc/localtime") < 0 && errno != ENOENT)
+                                return -errno;
+
+                        return 0;
+                }
+
+                source = "../usr/share/zoneinfo/UTC";
+        } else {
+                p = path_join("../usr/share/zoneinfo", c->zone);
+                if (!p)
+                        return -ENOMEM;
+
+                source = p;
+        }
 
-        return symlink_atomic(p, "/etc/localtime");
+        return symlink_atomic(source, "/etc/localtime");
 }
 
 static int context_write_data_local_rtc(Context *c) {