From 13f45806268bca2c20caee4d042f12dfe68f5a1f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 12 Jul 2019 13:37:13 +0200 Subject: [PATCH 1/2] locale-util: normalize UTF-8 locale names Let's generate out lists in the format people expect. --- src/basic/locale-util.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c index ce9daffa7b..17302abf58 100644 --- a/src/basic/locale-util.c +++ b/src/basic/locale-util.c @@ -27,6 +27,40 @@ #include "strv.h" #include "utf8.h" +static char *normalize_locale(const char *name) { + const char *e; + + /* Locale names are weird: glibc has some magic rules when looking for the charset name on disk: it + * lowercases everything, and removes most special chars. This means the official .UTF-8 suffix + * becomes .utf8 when looking things up on disk. When enumerating locales, let's do the reverse + * operation, and go back to ".UTF-8" which appears to be the more commonly accepted name. We only do + * that for UTF-8 however, since it's kinda the only charset that matters. */ + + e = endswith(name, ".utf8"); + if (e) { + _cleanup_free_ char *prefix = NULL; + + prefix = strndup(name, e - name); + if (!prefix) + return NULL; + + return strjoin(prefix, ".UTF-8"); + } + + e = strstr(name, ".utf8@"); + if (e) { + _cleanup_free_ char *prefix = NULL; + + prefix = strndup(name, e - name); + if (!prefix) + return NULL; + + return strjoin(prefix, ".UTF-8@", e + 6); + } + + return strdup(name); +} + static int add_locales_from_archive(Set *locales) { /* Stolen from glibc... */ @@ -107,7 +141,7 @@ static int add_locales_from_archive(Set *locales) { if (!utf8_is_valid((char*) p + e[i].name_offset)) continue; - z = strdup((char*) p + e[i].name_offset); + z = normalize_locale((char*) p + e[i].name_offset); if (!z) { r = -ENOMEM; goto finish; @@ -144,7 +178,7 @@ static int add_locales_from_libdir (Set *locales) { if (entry->d_type != DT_DIR) continue; - z = strdup(entry->d_name); + z = normalize_locale(entry->d_name); if (!z) return -ENOMEM; From a7d9fccd0e15bed540bed897569d8d9e00f09125 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 12 Jul 2019 13:38:43 +0200 Subject: [PATCH 2/2] locale-util: suppress non-UTF-8 locales when enumerating them Let's hide non-UTF-8 locales by default. It's 2019 after all. Let's add an undocumented env var to reenable listing them though. This should substantially shorten the list of choices we offer users, and only show realistic choices. note that only firstboot and localectl make use of this information, and both allow configuration of values outside of these lists, hence all this change does is hide legacy options, but they are still available if you know what you do, and that's how it should be. --- docs/ENVIRONMENT.md | 6 ++++++ src/basic/locale-util.c | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md index e81eaf2a35..838cc7e4cf 100644 --- a/docs/ENVIRONMENT.md +++ b/docs/ENVIRONMENT.md @@ -222,3 +222,9 @@ systemd-remount-fs: directory is remounted writable. This is primarily used by systemd-gpt-auto-generator to ensure the root partition is mounted writable in accordance to the GPT partition flags. + +systemd-firstboot and localectl: + +* `SYSTEMD_LIST_NON_UTF8_LOCALES=1` – if set non-UTF-8 locales are listed among + the installed ones. By default non-UTF-8 locales are suppressed from the + selection, since we are living in the 21st century. diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c index 17302abf58..039e965bc4 100644 --- a/src/basic/locale-util.c +++ b/src/basic/locale-util.c @@ -211,6 +211,25 @@ int get_locales(char ***ret) { if (!l) return -ENOMEM; + r = getenv_bool("SYSTEMD_LIST_NON_UTF8_LOCALES"); + if (r == -ENXIO || r == 0) { + char **a, **b; + + /* Filter out non-UTF-8 locales, because it's 2019, by default */ + for (a = b = l; *a; a++) { + + if (endswith(*a, "UTF-8") || + strstr(*a, ".UTF-8@")) + *(b++) = *a; + else + free(*a); + } + + *b = NULL; + + } else if (r < 0) + log_debug_errno(r, "Failed to parse $SYSTEMD_LIST_NON_UTF8_LOCALES as boolean"); + strv_sort(l); *ret = TAKE_PTR(l);