From b1afa5a67bacd36a5a359f07c761eb1a5cfcf129 Mon Sep 17 00:00:00 2001 From: Franck Bui Date: Fri, 2 Dec 2022 12:12:07 +0100 Subject: [PATCH 1/2] test: update TEST-73-LOCALE to define several locale settings in initial PID1 environment --- test/units/testsuite-73.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/units/testsuite-73.sh b/test/units/testsuite-73.sh index f9e2dce1bf..a4fda36da0 100755 --- a/test/units/testsuite-73.sh +++ b/test/units/testsuite-73.sh @@ -92,6 +92,19 @@ test_locale() { return fi + # start with a known default environment and make sure to also give a + # default value to LC_CTYPE= since we're about to also set/unset it. We + # also reload PID1 configuration to make sure that PID1 environment itself + # is updated as it's not always been the case. + assert_rc 0 localectl set-locale "LANG=en_US.UTF-8" "LC_CTYPE=C" + systemctl daemon-reload + output=$(localectl) + assert_in "System Locale: LANG=en_US.UTF-8" "$output" + assert_in "LC_CTYPE=C" "$output" + output=$(systemctl show-environment) + assert_in "LANG=en_US.UTF-8" "$output" + assert_in "LC_CTYPE=C" "$output" + # warn when kernel command line has locale settings output=$(SYSTEMD_PROC_CMDLINE="locale.LANG=C.UTF-8 locale.LC_CTYPE=ja_JP.UTF-8" localectl 2>&1) assert_in "Warning:" "$output" From c8966e812e6dcbec95814e6e9c2ed2b351e269ac Mon Sep 17 00:00:00 2001 From: Franck Bui Date: Fri, 2 Dec 2022 08:41:25 +0100 Subject: [PATCH 2/2] localed: reload PID1 configuration after modifying /etc/locale.conf Since commit 1ad6e8b302e87b6891a2bfc35ad397b0afe3d940, unsetting an environment variable means restoring it to its default value. However this doesn't work well when localed updates locale.conf. Indeed when a variable is removed from that file, localed calls "UnsetAndSetEnvironment" method which restores the default values of the unset variables obtained by PID1 when it first read locale.conf. But since locale.conf has been updated, these default values might be outdated and localed needs to instruct PID1 to read locale.conf again. Reloading PID1 configuration is quite an heavy operation for this purpose but there's no other way unless we change again the meaning of "UnsetEnvironment" or we introduce a new method that really unset an env variable. That said given the fact that localed modifies locale.conf, it should have an effect on PID1 default environment rather than on the environment explicitly set by the user (m->client_manager). --- src/locale/localed.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/locale/localed.c b/src/locale/localed.c index a2014e3da0..9b6890ebb4 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -32,7 +32,7 @@ #include "strv.h" #include "user-util.h" -static int locale_update_system_manager(sd_bus *bus, char **l_set, char **l_unset) { +static int reload_system_manager(sd_bus *bus) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; @@ -43,21 +43,13 @@ static int locale_update_system_manager(sd_bus *bus, char **l_set, char **l_unse "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", - "UnsetAndSetEnvironment"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_strv(m, l_unset); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_strv(m, l_set); + "Reload"); if (r < 0) return bus_log_create_error(r); r = sd_bus_call(bus, m, 0, &error, NULL); if (r < 0) - return log_error_errno(r, "Failed to update the manager environment: %s", bus_error_message(&error, r)); + return log_error_errno(r, "Failed to reload system manager: %s", bus_error_message(&error, r)); return 0; } @@ -393,7 +385,11 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er return sd_bus_error_set_errnof(error, r, "Failed to set locale: %m"); } - (void) locale_update_system_manager(sd_bus_message_get_bus(m), l_set, l_unset); + /* Since we just updated the locale configuration file, ask the system manager to read it again to + * update its default locale settings. It's important to not use UnsetAndSetEnvironment or a similar + * method because in this case unsetting variables means restoring them to PID1 default values, which + * may be outdated, since locale.conf has just changed and PID1 hasn't read it */ + (void) reload_system_manager(sd_bus_message_get_bus(m)); if (!strv_isempty(l_set)) { _cleanup_free_ char *line = NULL;