From bc9ecd484f1ebfe0de8b567c90f6cd867fbd5894 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 13 Nov 2019 10:32:26 +0100 Subject: [PATCH 1/4] time-util: treat /etc/localtime missing as UTC --- src/basic/time-util.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/basic/time-util.c b/src/basic/time-util.c index f5be619ad6..9e123d88c0 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -1387,13 +1387,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 */ @@ -1408,7 +1417,7 @@ int get_timezone(char **tz) { if (!z) return -ENOMEM; - *tz = z; + *ret = z; return 0; } From 9193af0f059538f4e5ca06502a998e9cc02819a1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 13 Nov 2019 10:32:44 +0100 Subject: [PATCH 2/4] timedated: handle UTC specially, when generating /etc/localtime --- src/timedate/timedated.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index 97a0868bc1..eb585b86c3 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -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. */ + + 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; } - p = path_join("../usr/share/zoneinfo", c->zone); - if (!p) - return log_oom(); - - return symlink_atomic(p, "/etc/localtime"); + return symlink_atomic(source, "/etc/localtime"); } static int context_write_data_local_rtc(Context *c) { From 5322db0651e1c29b61e2b42764b538722106522c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 13 Nov 2019 10:39:09 +0100 Subject: [PATCH 3/4] timedated: it might be that tzinfo files are just not installed --- src/timedate/timedated.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index eb585b86c3..4ec3b50359 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -653,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); From 60c20e242ce9d30fd9acb3660c83068752ed876e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 13 Nov 2019 09:42:58 +0000 Subject: [PATCH 4/4] update TODO --- TODO | 3 --- 1 file changed, 3 deletions(-) diff --git a/TODO b/TODO index 4d18b9aebd..a7bc74975d 100644 --- 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