mirror of
https://github.com/microsoft/WSL.git
synced 2025-12-10 00:44:55 -06:00
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:
parent
1f0e66d25c
commit
02ca6d3d2d
@ -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>
|
||||
|
||||
@ -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" />
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
Loading…
x
Reference in New Issue
Block a user