]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #14010 from poettering/localtime-symlink
authorLennart Poettering <lennart@poettering.net>
Wed, 13 Nov 2019 15:38:41 +0000 (16:38 +0100)
committerGitHub <noreply@github.com>
Wed, 13 Nov 2019 15:38:41 +0000 (16:38 +0100)
tweaks to /etc/localtime management

TODO
src/basic/time-util.c
src/timedate/timedated.c

diff --git a/TODO b/TODO
index 4d18b9aebddb4f2580c3ee2dc4f407d9d85f7fce..a7bc74975deee353e9187b7bc24f26c4f5226f87 100644 (file)
--- a/TODO
+++ b/TODO
@@ -30,9 +30,6 @@ Before v244:
 
 Features:
 
-* localed: if UTC is selected but timezone file for it doesn't exist, delete
-  /etc/localtime instead of creating a symlink
-
 * socket units: allow creating a udev monitor socket with ListenDevices= or so,
   with matches, then actviate app thorugh that passing socket oveer
 
index e2c9c47e572dd5be20966c490a23e8501716ec11..bfe2c60da173171e0ae333afe5f4cc314cc57722 100644 (file)
@@ -1391,13 +1391,22 @@ bool clock_supported(clockid_t clock) {
         }
 }
 
-int get_timezone(char **tz) {
+int get_timezone(char **ret) {
         _cleanup_free_ char *t = NULL;
         const char *e;
         char *z;
         int r;
 
         r = readlink_malloc("/etc/localtime", &t);
+        if (r == -ENOENT) {
+                /* If the symlink does not exist, assume "UTC", like glibc does*/
+                z = strdup("UTC");
+                if (!z)
+                        return -ENOMEM;
+
+                *ret = z;
+                return 0;
+        }
         if (r < 0)
                 return r; /* returns EINVAL if not a symlink */
 
@@ -1412,7 +1421,7 @@ int get_timezone(char **tz) {
         if (!z)
                 return -ENOMEM;
 
-        *tz = z;
+        *ret = z;
         return 0;
 }
 
index 97a0868bc1b1e057414290719ac8ad565c100188..4ec3b503592555a3de5e25fd56be4a30e116bf16 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) {
@@ -638,7 +653,7 @@ static int method_set_timezone(sd_bus_message *m, void *userdata, sd_bus_error *
                 return r;
 
         if (!timezone_is_valid(z, LOG_DEBUG))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid time zone '%s'", z);
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid or not installed time zone '%s'", z);
 
         if (streq_ptr(z, c->zone))
                 return sd_bus_reply_method_return(m, NULL);