Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 24 additions & 7 deletions src/linux/init/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Module Name:
#define HOSTS_FILE_PATH ETC_FOLDER "hosts"
#define LANG_ENV "LANG"
#define LOCALE_FILE_PATH ETC_DEFAULT_FOLDER "locale"
#define LOCALE_CONF_FILE_PATH ETC_FOLDER "locale.conf"
#define PATH_ENV "PATH"
#define RESOLV_CONF_DIRECTORY_MODE 0755
#define RESOLV_CONF_FILE_MODE 0644
Expand Down Expand Up @@ -2514,9 +2515,14 @@ void ConfigUpdateLanguage(EnvironmentBlock& Environment)

Routine Description:

This routine queries the contents of the /etc/default/locale text file and
This routine queries the contents of the locale configuration file and
if present updates the $LANG environment variable in the environment block.

Different distributions store this file in different locations:
- /etc/default/locale
- /etc/locale.conf
Both share the same "LANG=" line format, so the first file that exists is used.

Arguments:

Environment - Supplies the environment block pointer to update.
Expand All @@ -2530,22 +2536,33 @@ Return Value:
try
{
//
// Attempt to open the /etc/default/locale file. If the file does not exist
// then the $LANG environment variable will not be updated.
// Attempt to open the locale configuration file, trying each known path in turn.
// If none of the files exist then the $LANG environment variable will not be updated.
//
// N.B. This file is being opened by root. The only user-visible content
// N.B. These files are being opened by root. The only user-visible content
// will be the contents of the last line of the file that contains
// "LANG=".
//

wil::unique_file LocaleFile{fopen(LOCALE_FILE_PATH, "r")};
if (!LocaleFile)
constexpr const char* LocaleFilePaths[] = {LOCALE_FILE_PATH, LOCALE_CONF_FILE_PATH};

wil::unique_file LocaleFile;
for (const auto* Path : LocaleFilePaths)
{
LocaleFile.reset(fopen(Path, "r"));
if (LocaleFile)
{
break;
}

if (errno != ENOENT)
{
LOG_ERROR("fopen({}) failed {}", LOCALE_FILE_PATH, errno);
LOG_ERROR("fopen({}) failed {}", Path, errno);
}
Comment thread
benhillis marked this conversation as resolved.
}

if (!LocaleFile)
{
return;
}

Expand Down
40 changes: 40 additions & 0 deletions test/windows/UnitTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,46 @@ class UnitTests
}
}

WSL2_TEST_METHOD(ConfigUpdateLanguage)
{
// Validates that init populates $LANG from the distro locale configuration file.
// ConfigUpdateLanguage reads /etc/default/locale first, then /etc/locale.conf, and uses
// the first file that exists. See ConfigUpdateLanguage in src/linux/init/config.cpp.

DistroFileChange defaultLocale(L"/etc/default/locale", LxsstuLaunchWsl(L"test -f /etc/default/locale") == 0);
DistroFileChange localeConf(L"/etc/locale.conf", LxsstuLaunchWsl(L"test -f /etc/locale.conf") == 0);

const auto readLang = []() { return LxsstuLaunchWslAndCaptureOutput(L"echo $LANG").first; };

// Only /etc/default/locale is present (Debian/Ubuntu).
{
defaultLocale.Delete();
localeConf.Delete();
defaultLocale.SetContent(L"LANG=de_DE.UTF-8\n");
TerminateDistribution();
VERIFY_ARE_EQUAL(readLang(), L"de_DE.UTF-8\n");
}

// Only /etc/locale.conf is present (Fedora, Arch, openSUSE, ...).
{
defaultLocale.Delete();
localeConf.Delete();
localeConf.SetContent(L"LANG=fr_FR.UTF-8\n");
TerminateDistribution();
VERIFY_ARE_EQUAL(readLang(), L"fr_FR.UTF-8\n");
}

// Both files are present: /etc/default/locale takes precedence because it is read first.
{
defaultLocale.Delete();
localeConf.Delete();
defaultLocale.SetContent(L"LANG=ja_JP.UTF-8\n");
localeConf.SetContent(L"LANG=en_US.UTF-8\n");
TerminateDistribution();
VERIFY_ARE_EQUAL(readLang(), L"ja_JP.UTF-8\n");
}
}

TEST_METHOD(Dup)
{
VERIFY_NO_THROW(LxsstuRunTest(L"/data/test/wsl_unit_tests dup", L"Dup"));
Expand Down