Fix various issues with systemd user sessions (#13101)

* Save state

* Save state

* Add test coverage

* Remove useless condition

* Update localized strings

* Update test distro
This commit is contained in:
Blue 2025-06-13 16:31:57 -07:00 committed by GitHub
parent 1f0e66d25c
commit 02ca6d3d2d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 275 additions and 116 deletions

View File

@ -787,6 +787,10 @@ For information please visit https://aka.ms/wslinstall</value>
<data name="MessageWarningDuringStartup" xml:space="preserve">
<value>Errors occurred during WSL startup</value>
</data>
<data name="MessageSystemdUserSessionFailed" xml:space="preserve">
<value>Failed to start the systemd user session for '{}'. See journalctl for more details.</value>
<comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
</data>
<data name="MessageOpenEventViewer" xml:space="preserve">
<value>Open EventViewer</value>
</data>

View File

@ -23,7 +23,7 @@
<package id="Microsoft.WSL.LinuxSdk" version="1.20.0" targetFramework="native" />
<package id="Microsoft.WSL.LxUtil.amd64fre" version="10.0.26100.1-240331-1435.ge-release" />
<package id="Microsoft.WSL.LxUtil.arm64fre" version="10.0.26100.1-240331-1435.ge-release" />
<package id="Microsoft.WSL.TestDistro" version="2.4.8-116" />
<package id="Microsoft.WSL.TestDistro" version="2.5.7-47" />
<package id="Microsoft.WSLg" version="1.0.66" />
<package id="Microsoft.Xaml.Behaviors.WinUI.Managed" version="3.0.0" />
<package id="StrawberryPerl" version="5.28.0.1" />

View File

@ -24,7 +24,7 @@ WslDistributionConfig::WslDistributionConfig(const char* configFilePath)
std::vector<ConfigKey> keys = {
ConfigKey(c_ConfigAutoMountOption, AutoMount),
ConfigKey("automount.root", DrvFsPrefix),
ConfigKey(c_ConfigAutoMountRoot, DrvFsPrefix),
ConfigKey("automount.options", DrvFsOptions),
ConfigKey(c_ConfigMountFsTabOption, MountFsTab),
ConfigKey(c_ConfigLinkOsLibsOption, LinkOsLibs),

View File

@ -36,6 +36,7 @@ constexpr auto c_ConfigPlan9EnabledOption = "fileServer.enabled";
constexpr auto c_ConfigAppendGpuLibPathOption = "gpu.appendLibPath";
constexpr auto c_ConfigGpuEnabledOption = "gpu.enabled";
constexpr auto c_ConfigLinkOsLibsOption = "automount.ldconfig";
constexpr auto c_ConfigAutoMountRoot = "automount.root";
struct WslDistributionConfig
{

View File

@ -75,6 +75,8 @@ Abstract:
static void ConfigApplyWindowsLibPath(const wsl::linux::WslDistributionConfig& Config);
static bool CreateLoginSession(const wsl::linux::WslDistributionConfig& Config, const char* Username, uid_t Uid);
class RemoveMountAndEnvironmentOnScopeExit
{
public:
@ -414,81 +416,18 @@ try
return;
}
bool success = false;
auto sendResponse = wil::scope_exit([&]() { ResponseChannel.SendResultMessage<bool>(success); });
if (!Config.BootInit || Config.InitPid.value_or(0) != getpid())
{
LOG_ERROR("Unexpected LxInitMessageCreateLoginSession message");
return;
}
static std::mutex LoginSessionsLock;
static std::map<uid_t, int> LoginSessions;
// Keep track of login sessions that have been created.
LoginSessionsLock.lock();
auto Unlock = wil::scope_exit([&]() { LoginSessionsLock.unlock(); });
if (LoginSessions.contains(CreateSession->Uid))
else
{
return;
success = CreateLoginSession(Config, CreateSession->Buffer, CreateSession->Uid);
}
// Symlink the content of the WSLG XDG runtime dir onto the user's runtime path and
// create a login session to initialize PAM for the user.
if (Config.GuiAppsEnabled)
{
auto* RuntimeDir = getenv(XDG_RUNTIME_DIR_ENV);
if (RuntimeDir)
{
// Create a tmpfs mount point for the user directory.
auto userFolder = std::format("/run/user/{}", CreateSession->Uid);
UtilMount("tmpfs", userFolder.c_str(), "tmpfs", (MS_NOSUID | MS_NODEV | MS_NOEXEC), "mode=755");
// Create the directory structure for wslg's symlinks.
for (const auto* e : {"/", "/dbus-1", "/dbus-1/service", "/pulse"})
{
auto target = userFolder + e;
UtilMkdir(target.c_str(), 0777);
if (chown(target.c_str(), CreateSession->Uid, CreateSession->Gid) < 0)
{
LOG_ERROR("chown({}, {}, {}) failed {}", target, CreateSession->Uid, CreateSession->Gid, errno);
}
}
// Create the actual symlinks.
for (const auto* e : {"wayland-0", "wayland-0.lock", "pulse/native", "pulse/pid"})
{
auto link = std::format("{}/{}", userFolder, e);
if (unlink(link.c_str()) < 0 && errno != ENOENT)
{
LOG_ERROR("unlink({}) failed {}", link, errno);
}
auto target = RuntimeDir + std::string("/") + e;
if (symlink(target.c_str(), link.c_str()) < 0)
{
LOG_ERROR("symlink({}, {}) failed {}", target, link, errno);
}
}
}
else
{
LOG_ERROR("getenv({}) failed {}", XDG_RUNTIME_DIR_ENV, errno);
}
}
int LoginLeader;
const int Result = forkpty(&LoginLeader, nullptr, nullptr, nullptr);
if (Result < 0)
{
LOG_ERROR("forkpty failed {}", errno);
return;
}
else if (Result == 0)
{
Unlock.reset();
_exit(execl("/bin/login", "/bin/login", "-f", CreateSession->Buffer, nullptr));
}
LoginSessions.emplace(CreateSession->Uid, LoginLeader);
break;
}
@ -576,6 +515,11 @@ Return Value:
wsl::linux::WslDistributionConfig Config{CONFIG_FILE};
if (getenv(LX_WSL2_SYSTEM_DISTRO_SHARE_ENV) != nullptr)
{
Config.GuiAppsEnabled = true;
}
//
// Initialize the static entries.
//
@ -2703,3 +2647,96 @@ try
}
}
CATCH_LOG()
bool CreateLoginSession(const wsl::linux::WslDistributionConfig& Config, const char* Username, uid_t Uid)
/*++
Routine Description:
Create a systemd login session for the given user.
Arguments:
Config - Supplies the WSL distribution configuration.
Username - Supplies session username.
Uid - Supplies the session UID.
Return Value:
true on success, false on failure.
--*/
try
{
static std::mutex LoginSessionsLock;
static std::map<uid_t, int> LoginSessions;
// Keep track of login sessions that have been created.
LoginSessionsLock.lock();
auto Unlock = wil::scope_exit([&]() { LoginSessionsLock.unlock(); });
if (LoginSessions.contains(Uid))
{
return true;
}
int LoginLeader;
const int Result = forkpty(&LoginLeader, nullptr, nullptr, nullptr);
if (Result < 0)
{
LOG_ERROR("forkpty failed {}", errno);
return false;
}
else if (Result == 0)
{
Unlock.reset();
_exit(execl("/bin/login", "/bin/login", "-f", Username, nullptr));
}
LoginSessions.emplace(Uid, LoginLeader);
//
// N.B. Init needs to not ignore SIGCHLD so it can wait for the child process.
//
signal(SIGCHLD, SIG_DFL);
auto restoreDisposition = wil::scope_exit([]() { signal(SIGCHLD, SIG_IGN); });
if (Config.BootInitTimeout > 0)
{
auto cmd = std::format("/usr/bin/systemctl is-active user@{}.service", Uid);
try
{
return wsl::shared::retry::RetryWithTimeout<bool>(
[&]() {
std::string Output;
auto exitCode = UtilExecCommandLine(cmd.c_str(), &Output, 0, false);
if (exitCode == 0) // is-active returns 0 if the unit is active.
{
return true;
}
else if (Output == "failed\n")
{
LOG_ERROR("{} returned: {}", cmd, Output);
return false;
}
THROW_ERRNO(EAGAIN);
},
std::chrono::milliseconds{250},
std::chrono::milliseconds{Config.BootInitTimeout});
}
catch (...)
{
LOG_ERROR("Timed out waiting for user session for uid={}", Uid);
return false;
}
}
return true;
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
return false;
}

View File

@ -138,6 +138,8 @@ void InstallSystemdUnit(const char* Path, const std::string& Name, const char* C
int GenerateSystemdUnits(int Argc, char** Argv);
int GenerateUserSystemdUnits(int Argc, char** Argv);
void HardenMirroredNetworkingSettingsAgainstSystemd();
void PostProcessImportedDistribution(wsl::shared::MessageWriter<LX_MINI_INIT_IMPORT_RESULT>& Message, const char* ExtractedPath);
@ -214,6 +216,10 @@ int WslEntryPoint(int Argc, char* Argv[])
{
ExitCode = GenerateSystemdUnits(Argc, Argv);
}
else if (strcmp(BaseName, LX_INIT_WSL_USER_GENERATOR) == 0)
{
ExitCode = GenerateUserSystemdUnits(Argc, Argv);
}
else
{
// Handle the special case for import result messages, everything else is sent to the binfmt interpreter.
@ -236,6 +242,61 @@ int WslEntryPoint(int Argc, char* Argv[])
return ExitCode;
}
int GenerateUserSystemdUnits(int Argc, char** Argv)
{
if (Argc < 2)
{
LOG_ERROR("Unit folder missing");
return 1;
}
const auto* installPath = Argv[1];
try
{
std::string automountRoot = "/mnt";
wil::unique_file File{fopen("/etc/wsl.conf", "r")};
if (File)
{
std::vector<ConfigKey> ConfigKeys = {
ConfigKey(wsl::linux::c_ConfigAutoMountRoot, automountRoot),
};
ParseConfigFile(ConfigKeys, File.get(), CFG_SKIP_UNKNOWN_VALUES, STRING_TO_WSTRING(CONFIG_FILE));
File.reset();
}
// TODO: handle quotes in path
auto unitContent = std::format(
R"(# Note: This file is generated by WSL to configure wslg.
[Unit]
Description=WSLg user service
DefaultDependencies=no
[Service]
Type=oneshot
Environment=WSLG_RUNTIME_DIR={}/{}/{}
ExecStart=/bin/sh -c 'mkdir -p -m 00755 "$XDG_RUNTIME_DIR/pulse"'
ExecStart=/bin/sh -c 'ln -sf "$WSLG_RUNTIME_DIR/wayland-0" "$XDG_RUNTIME_DIR/wayland-0"'
ExecStart=/bin/sh -c 'ln -sf "$WSLG_RUNTIME_DIR/wayland-0.lock" "$XDG_RUNTIME_DIR/wayland-0.lock"'
ExecStart=/bin/sh -c 'ln -sf "$WSLG_RUNTIME_DIR/pulse/native" "$XDG_RUNTIME_DIR/pulse/native"'
ExecStart=/bin/sh -c 'ln -sf "$WSLG_RUNTIME_DIR/pulse/pid" "$XDG_RUNTIME_DIR/pulse/pid"'
)",
automountRoot,
WSLG_SHARED_FOLDER,
WAYLAND_RUNTIME_DIR);
InstallSystemdUnit(installPath, "wslg-session", unitContent.c_str());
return 0;
}
CATCH_LOG()
return 1;
}
int GenerateSystemdUnits(int Argc, char** Argv)
{
if (Argc < 2)
@ -253,6 +314,8 @@ int GenerateSystemdUnits(int Argc, char** Argv)
bool enableGuiApps = true;
bool protectBinfmt = true;
bool interopEnabled = true;
std::string automountRoot = "/mnt";
wil::unique_file File{fopen("/etc/wsl.conf", "r")};
if (File)
{
@ -260,6 +323,7 @@ int GenerateSystemdUnits(int Argc, char** Argv)
ConfigKey(wsl::linux::c_ConfigEnableGuiAppsOption, enableGuiApps),
ConfigKey(wsl::linux::c_ConfigBootProtectBinfmtOption, protectBinfmt),
ConfigKey(wsl::linux::c_ConfigInteropEnabledOption, interopEnabled),
ConfigKey(wsl::linux::c_ConfigAutoMountRoot, automountRoot),
};
ParseConfigFile(ConfigKeys, File.get(), CFG_SKIP_UNKNOWN_VALUES, STRING_TO_WSTRING(CONFIG_FILE));
@ -616,7 +680,12 @@ try
CreateSession->Gid = PasswordEntry->pw_gid;
CreateSession.WriteString(PasswordEntry->pw_name);
InteropChannel.SendMessage<LX_INIT_CREATE_LOGIN_SESSION>(CreateSession.Span());
auto result = InteropChannel.Transaction<LX_INIT_CREATE_LOGIN_SESSION>(CreateSession.Span());
if (!result.Result)
{
fprintf(stderr, "wsl: %s\n", wsl::shared::Localization::MessageSystemdUserSessionFailed(PasswordEntry->pw_name).c_str());
}
Common->Environment.AddVariable("DBUS_SESSION_BUS_ADDRESS", std::format("unix:path=/run/user/{}/bus", PasswordEntry->pw_uid));
Common->Environment.AddVariable(XDG_RUNTIME_DIR_ENV, std::format("/run/user/{}/", PasswordEntry->pw_uid));
@ -2791,6 +2860,14 @@ try
THROW_LAST_ERROR_IF(UtilMkdirPath(folder, 0755) < 0);
THROW_LAST_ERROR_IF(symlink("/init", std::format("{}/{}", folder, LX_INIT_WSL_GENERATOR).c_str()));
if (Config.GuiAppsEnabled)
{
constexpr auto folder = "/run/systemd/user-generators";
THROW_LAST_ERROR_IF(UtilMkdirPath(folder, 0755) < 0);
THROW_LAST_ERROR_IF(symlink("/init", std::format("{}/{}", folder, LX_INIT_WSL_USER_GENERATOR).c_str()));
}
}
CATCH_LOG();

View File

@ -239,6 +239,8 @@ Abstract:
#define LX_INIT_WSL_GENERATOR "wsl-generator"
#define LX_INIT_WSL_USER_GENERATOR "wsl-user-generator"
//
// WSL2-specific environment variables.
//
@ -681,6 +683,7 @@ typedef struct _LX_INIT_NETWORK_INFORMATION
typedef struct _LX_INIT_CREATE_LOGIN_SESSION
{
static inline auto Type = LxInitMessageCreateLoginSession;
using TResponse = RESULT_MESSAGE<bool>;
MESSAGE_HEADER Header;
unsigned int Uid;

View File

@ -202,8 +202,6 @@ class UnitTests
{
WSL2_TEST_ONLY();
SKIP_TEST_UNSTABLE(); // TODO: Re-enable when this issue is solved in main.
auto cleanup = wil::scope_exit([] {
// clean up wsl.conf file
const std::wstring disableSystemdCmd(LXSST_REMOVE_DISTRO_CONF_COMMAND_LINE);
@ -219,8 +217,6 @@ class UnitTests
{
WSL2_TEST_ONLY();
SKIP_TEST_UNSTABLE(); // TODO: Re-enable when this issue is solved in main.
// enable systemd before creating the user.
// if not called first, the runtime directories needed for --user will not have been created
auto cleanup = EnableSystemd();
@ -231,45 +227,79 @@ class UnitTests
CreateUser(LXSST_TEST_USERNAME, &TestUid, &TestGid);
auto userCleanup = wil::scope_exit([]() { LxsstuLaunchWsl(L"userdel " LXSST_TEST_USERNAME); });
// verify that the user service is running
const std::wstring isServiceActiveCmd = std::format(L"-u {} systemctl is-active user@{}.service", LXSST_TEST_USERNAME, TestUid);
std::wstring out;
std::wstring err;
auto validateUserSesssion = [&]() {
// verify that the user service is running
const std::wstring isServiceActiveCmd =
std::format(L"-u {} systemctl is-active user@{}.service ; exit 0", LXSST_TEST_USERNAME, TestUid);
std::wstring out;
std::wstring err;
try
try
{
std::tie(out, err) = LxsstuLaunchWslAndCaptureOutput(isServiceActiveCmd.data());
}
CATCH_LOG();
Trim(out);
if (out.compare(L"active") != 0)
{
LogError(
"Unexpected output from systemd: %ls. Stderr: %ls, cmd: %ls", out.c_str(), err.c_str(), isServiceActiveCmd.c_str());
VERIFY_FAIL();
}
// Verify that /run/user/<uid> is a writable tmpfs mount visible in both mount namespaces.
VERIFY_ARE_EQUAL(LxsstuLaunchWsl(L"touch /run/user/" + std::to_wstring(TestUid) + L"/dummy-test-file"), 0u);
auto command = L"mount | grep -iF 'tmpfs on /run/user/" + std::to_wstring(TestUid) + L" type tmpfs (rw'";
VERIFY_ARE_EQUAL(LxsstuLaunchWsl(command), 0u);
const auto nonElevatedToken = GetNonElevatedToken();
VERIFY_ARE_EQUAL(LxsstuLaunchWsl(command, nullptr, nullptr, nullptr, nonElevatedToken.get()), 0u);
};
// Validate user sessions state with gui apps disabled.
{
std::tie(out, err) = LxsstuLaunchWslAndCaptureOutput(isServiceActiveCmd.data());
}
CATCH_LOG();
validateUserSesssion();
Trim(out);
if (out.compare(L"active") != 0)
{
LogError("Unexpected output from systemd: %ls. Stderr: %ls, cmd: %ls", out.c_str(), err.c_str(), isServiceActiveCmd.c_str());
VERIFY_FAIL();
auto [out, err] = LxsstuLaunchWslAndCaptureOutput(std::format(L"echo $DISPLAY", LXSST_TEST_USERNAME));
VERIFY_ARE_EQUAL(out, L"\n");
}
// Verify that /run/user/<uid> is a writable tmpfs mount visible in both mount namespaces.
VERIFY_ARE_EQUAL(LxsstuLaunchWsl(L"touch /run/user/" + std::to_wstring(TestUid) + L"/dummy-test-file"), 0u);
auto command = L"mount | grep -iF 'tmpfs on /run/user/" + std::to_wstring(TestUid) + L" type tmpfs (rw'";
VERIFY_ARE_EQUAL(LxsstuLaunchWsl(command), 0u);
// Validate user sessions state with gui apps enabled.
{
WslConfigChange config(LxssGenerateTestConfig({.guiApplications = true}));
const auto nonElevatedToken = GetNonElevatedToken();
VERIFY_ARE_EQUAL(LxsstuLaunchWsl(command, nullptr, nullptr, nullptr, nonElevatedToken.get()), 0u);
validateUserSesssion();
auto [out, err] = LxsstuLaunchWslAndCaptureOutput(std::format(L"echo $DISPLAY", LXSST_TEST_USERNAME));
VERIFY_ARE_EQUAL(out, L":0\n");
}
// Create a 'broken' /run/user and validate that the warning is correctly displayed.
{
TerminateDistribution();
VERIFY_ARE_EQUAL(LxsstuLaunchWsl(L"chmod 000 /run/user"), 0L);
auto [out, err] = LxsstuLaunchWslAndCaptureOutput(std::format(L"-u {} echo OK", LXSST_TEST_USERNAME));
VERIFY_ARE_EQUAL(out, L"OK\n");
VERIFY_ARE_EQUAL(
err, L"wsl: Failed to start the systemd user session for 'kerneltest'. See journalctl for more details.\n");
}
}
static bool IsSystemdRunning(const std::wstring& SystemdScope, int ExpectedExitCode = 0)
{
// run and check the output of systemctl --system
const std::wstring systemctlCmd(L"systemctl " + SystemdScope + L" is-system-running");
const auto systemctlCmd = std::format(L"systemctl '{}' is-system-running ; exit 0", SystemdScope);
std::wstring out;
std::wstring error;
// capture the output of systemctl and trim for good measure
try
{
std::tie(out, error) = LxsstuLaunchWslAndCaptureOutput(systemctlCmd.data(), ExpectedExitCode);
std::tie(out, error) = LxsstuLaunchWslAndCaptureOutput(systemctlCmd.c_str(), ExpectedExitCode);
}
CATCH_LOG()
Trim(out);
@ -809,7 +839,8 @@ class UnitTests
VERIFY_ARE_EQUAL(out, L"");
VERIFY_ARE_EQUAL(
err,
L"Invalid command line argument: --invalid\nPlease use 'wslinfo --help' to get a list of supported arguments.\n");
L"Invalid command line argument: --invalid\nPlease use 'wslinfo --help' to get a list of supported "
L"arguments.\n");
}
}
@ -1217,7 +1248,8 @@ class UnitTests
ValidateErrorMessage(
L"-d DummyBrokenDistro",
L"Failed to attach disk 'C:\\DoesNotExit\\ext4.vhdx' to WSL2: The system cannot find the path specified. ",
L"Failed to attach disk 'C:\\DoesNotExit\\ext4.vhdx' to WSL2: The system cannot find the path "
L"specified. ",
L"Wsl/Service/CreateInstance/MountDisk/HCS/ERROR_PATH_NOT_FOUND");
// Purposefully set an incorrect value type to validate registry error handling.
@ -1230,7 +1262,8 @@ class UnitTests
ValidateErrorMessage(
L"-d DummyBrokenDistro",
L"An error occurred accessing the registry. Path: '\\REGISTRY\\USER\\" + Sid +
L"\\Software\\Microsoft\\Windows\\CurrentVersion\\Lxss\\{baa405ef-1822-4bbe-84e2-30e4c6330d42}\\Version'."
L"\\Software\\Microsoft\\Windows\\CurrentVersion\\Lxss\\{baa405ef-1822-4bbe-84e2-30e4c6330d42}"
L"\\Version'."
L" "
L"Error: Data of this type is not supported. ",
L"Wsl/Service/ReadDistroConfig/ERROR_UNSUPPORTED_TYPE",
@ -2234,7 +2267,8 @@ Error code: Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND
// Keys that are created by the optional component and the service.
const std::vector<LPCWSTR> inboxKeys{
L"SOFTWARE\\Classes\\CLSID\\{B2B4A4D1-2754-4140-A2EB-9A76D9D7CDC6}",
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Desktop\\NameSpace\\{B2B4A4D1-2754-4140-A2EB-9A76D9D7CDC6}",
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Desktop\\NameSpace\\{B2B4A4D1-2754-4140-A2EB-"
L"9A76D9D7CDC6}",
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\IdListAliasTranslations\\WSL",
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\IdListAliasTranslations\\WSLLegacy",
L"SOFTWARE\\Classes\\Directory\\shell\\WSL",
@ -2782,7 +2816,8 @@ Error code: Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND
VERIFY_ARE_EQUAL(
out,
L"The supplied install location is already in use.\r\nError code: Wsl/Service/MoveDistro/ERROR_FILE_EXISTS\r\n");
L"The supplied install location is already in use.\r\nError code: "
L"Wsl/Service/MoveDistro/ERROR_FILE_EXISTS\r\n");
// Validate that the distribution still starts and that the vhd hasn't moved.
validateDistro();
VERIFY_IS_TRUE(std::filesystem::exists(std::format(L"{}\\ext4.vhdx", absolutePath)));
@ -2837,7 +2872,8 @@ Error code: Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND
WslKeepAlive keepAlive;
auto [out, _] = LxsstuLaunchWslAndCaptureOutput(L"--manage test_distro --resize 1500GB", -1);
VERIFY_ARE_EQUAL(
L"The operation could not be completed because the vhdx is currently in use. To force WSL to stop use: wsl.exe "
L"The operation could not be completed because the vhdx is currently in use. To force WSL to stop use: "
L"wsl.exe "
L"--shutdown\r\nError code: Wsl/Service/WSL_E_DISTRO_NOT_STOPPED\r\n",
out);
}
@ -3400,8 +3436,8 @@ localhostForwarding=true
}
{
// This test verifies removal of a setting from the .wslconfig when a default value for the particular setting is set.
// This gives wsl control over the default value.
// This test verifies removal of a setting from the .wslconfig when a default value for the particular setting is
// set. This gives wsl control over the default value.
std::wstring customWslConfigContentOut{
LR"(
[wsl2]
@ -4517,7 +4553,8 @@ Error code: Wsl/Service/RegisterDistro/E_INVALIDARG\r\n";
std::format(L"--name {}", distroName).c_str(),
0,
nullptr,
L"wsl: Failed to parse terminal profile while registering distribution: [json.exception.parse_error.101] parse "
L"wsl: Failed to parse terminal profile while registering distribution: [json.exception.parse_error.101] "
L"parse "
L"error at line 1, column 1: syntax error while parsing value - invalid literal; last read: 'b'\r\n");
ValidateDistributionStarts(distroName);

View File

@ -1,14 +1,14 @@
<#
.SYNOPSIS
Takes in an exported distribution, installs dependencies for testing, cleans unnecessary components, and exports it for later use.
.PARAMETER InputTarPath
Path to the .tar/.tar.gz to build the test distro from.
.PARAMETER Base
Base distribution to use.
.PARAMETER OutputTarPath
Path to write the test distro .tar to.
#>
[CmdletBinding()]
Param ($InputTarPath)
Param ($Base)
$ErrorActionPreference = "Stop"
Set-StrictMode -Version Latest
@ -37,20 +37,20 @@ $version = "$($git_version[0])-$($git_version[1])"
echo "Building test_distro version: $version"
Run { wsl.exe --import test_distro . $InputTarPath --version 2 }
Run { wsl.exe --install $Base --name test_distro --version 2 --no-launch }
RunInDistro("apt update")
RunInDistro("apt install daemonize libmount-dev genisoimage dosfstools make gcc socat systemd libpam-systemd dnsutils xz-utils bzip2 -f -y --no-install-recommends")
RunInDistro("apt purge cpio isc-dhcp-client isc-dhcp-common nftables rsyslog vim whiptail xxd init genisoimage tasksel -y -f --allow-remove-essential")
RunInDistro("apt install daemonize libmount-dev genisoimage dosfstools make gcc socat systemd libpam-systemd bind9-dnsutils xz-utils bzip2 -f -y --no-install-recommends")
RunInDistro("apt purge cpio isc-dhcp-client isc-dhcp-common nftables rsyslog vim vim-tiny vim-common whiptail xxd init genisoimage tasksel kmod mawk udev cron -y -f --allow-remove-essential")
RunInDistro("apt-get autopurge -y")
RunInDistro("apt clean")
RunInDistro("umount /usr/lib/wsl/drivers")
RunInDistro("umount /usr/lib/wsl/lib")
RunInDistro("rm -rf /etc/wsl-distribution.conf /etc/wsl.conf /usr/share/doc/* /var/lib/apt/lists/* /var/log/* /var/cache/debconf/* /var/cache/ldconfig/* /usr/lib/wsl")
RunInDistro("rm -rf /etc/wsl-distribution.conf /etc/wsl.conf /usr/share/doc/* /var/lib/apt/lists/* /var/log/* /var/cache/debconf/* /var/cache/ldconfig/* /usr/lib/wsl /usr/share/{gdb,vim,zsh,man}")
RunInDistro('rm -rf -- $(ls /usr/share/locale ^| grep -vE "en|locale.alias")')
RunInDistro("rm /usr/lib/systemd/user/{systemd-tmpfiles-setup.service,systemd-tmpfiles-clean.timer,systemd-tmpfiles-clean.service}")
RunInDistro("rm /usr/lib/systemd/system/{systemd-tmpfiles-setup-dev.service,systemd-tmpfiles-setup.service,systemd-tmpfiles-clean.timer,systemd-tmpfiles-clean.service}")
RunInDistro("rm /usr/lib/systemd/system/user-runtime-dir@.service")
RunInDistro("rm /usr/lib/systemd/system/{systemd-tmpfiles-setup-dev.service,systemd-tmpfiles-setup.service,systemd-tmpfiles-clean.timer,systemd-tmpfiles-clean.service} /lib/systemd/system/{kmod-static-nodes.service,kmod.service,sysinit.target.wants/kmod-static-nodes.service}")
Run { wsl.exe --export test_distro "test_distro.tar" }
Run { wsl.exe xz -9 "test_distro.tar" }
Run { wsl.exe xz -e9 "test_distro.tar" }
& "$PSScriptRoot/../../_deps/nuget.exe" pack Microsoft.WSL.TestDistro.nuspec -Properties version=$version