diff --git a/src/linux/init/config.cpp b/src/linux/init/config.cpp index 5f6d29db2..b4a554b1c 100644 --- a/src/linux/init/config.cpp +++ b/src/linux/init/config.cpp @@ -2137,7 +2137,7 @@ Return Value: // const char* const Argv[] = {MOUNT_COMMAND, MOUNT_FSTAB_ARG, nullptr}; - if (UtilCreateProcessAndWait(Argv[0], Argv, nullptr, {{WSL_DRVFS_ELEVATED_ENV, Elevated ? "1" : "0"}}) < 0) + if (UtilCreateProcessAndWait(Argv[0], Argv, nullptr, {{WSL_DRVFS_ELEVATED_ENV, Elevated ? "1" : "0"}}, true) < 0) { auto message = wsl::shared::Localization::MessageFstabMountFailed(); LOG_ERROR("{}", message.c_str()); diff --git a/src/linux/init/util.cpp b/src/linux/init/util.cpp index 3cc0ae4c2..c67d69462 100644 --- a/src/linux/init/util.cpp +++ b/src/linux/init/util.cpp @@ -613,7 +613,7 @@ Return Value: return SocketFd; } -int UtilCreateProcessAndWait(const char* const File, const char* const Argv[], int* Status, const std::map& Env) +int UtilCreateProcessAndWait(const char* const File, const char* const Argv[], int* Status, const std::map& Env, bool DetachTerminal) /*++ @@ -630,6 +630,9 @@ Routine Description: Status - Supplies an optional pointer that receives the exit status of the process. + DetachTerminal - Supplies a boolean that, when true, calls setsid() in the + child process to detach it from the controlling terminal. + Return Value: 0 on success, -1 on failure. @@ -664,7 +667,7 @@ Return Value: if (UtilSetSignalHandlers(g_SavedSignalActions, false) < 0 || UtilRestoreBlockedSignals() < 0) { - exit(-1); + _exit(-1); } // @@ -676,6 +679,19 @@ Return Value: setenv(e.first.c_str(), e.second.c_str(), 1); } + // + // Detach from the controlling terminal if requested. + // + + if (DetachTerminal) + { + if (setsid() == -1) + { + LOG_ERROR("setsid failed {}", errno); + _exit(-1); + } + } + // // Invoke the executable. // @@ -686,7 +702,7 @@ Return Value: // with std::string anyway. execv(File, const_cast(Argv)); LOG_ERROR("execv({}) failed with {}", File, errno); - exit(-1); + _exit(-1); } if (Status == nullptr) diff --git a/src/linux/init/util.h b/src/linux/init/util.h index 892500b12..1fa5414d5 100644 --- a/src/linux/init/util.h +++ b/src/linux/init/util.h @@ -191,7 +191,8 @@ Return Value: _exit(1); } -int UtilCreateProcessAndWait(const char* File, const char* const Argv[], int* Status = nullptr, const std::map& Env = {}); +int UtilCreateProcessAndWait( + const char* File, const char* const Argv[], int* Status = nullptr, const std::map& Env = {}, bool DetachTerminal = false); template void UtilCreateWorkerThread(const char* Name, TMethod&& ThreadFunction) diff --git a/test/windows/UnitTests.cpp b/test/windows/UnitTests.cpp index 68e760813..f97e96455 100644 --- a/test/windows/UnitTests.cpp +++ b/test/windows/UnitTests.cpp @@ -6539,5 +6539,28 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n", VERIFY_ARE_EQUAL(err, L""); } + TEST_METHOD(InteractiveMount) + { + WSL2_TEST_ONLY(); + + // Add a fake interactive mount helper. + DistroFileChange mountHelper(L"/sbin/mount.hang", false); + mountHelper.SetContent( + L"#!/bin/sh\n" + L"read pass < /dev/tty\n"); + VERIFY_ARE_EQUAL(LxsstuLaunchWsl(L"chmod +x /sbin/mount.hang"), (DWORD)0); + + // Don't keep the original fstab as it can be missing on the pipeline. + DistroFileChange fstab(L"/etc/fstab", false); + fstab.SetContent(L"none /mnt/ttytest hang 0 0\n"); + + // Restart the distro with this mount. + WslShutdown(); + wsl::windows::common::SubProcess process(nullptr, LxssGenerateWslCommandLine(L"echo booted").c_str()); + auto result = process.RunAndCaptureOutput(60 * 1000); + VERIFY_ARE_EQUAL(result.Stdout, L"booted\n"); + VERIFY_ARE_EQUAL(result.ExitCode, 0); + } + }; // namespace UnitTests } // namespace UnitTests