aboutsummaryrefslogtreecommitdiff
path: root/src/zencore/process.cpp
diff options
context:
space:
mode:
authorLiam Mitchell <[email protected]>2025-07-26 00:01:13 +0000
committerLiam Mitchell <[email protected]>2025-07-26 00:01:13 +0000
commit10f6dc559688a650617b2e74eec039409f3d4687 (patch)
tree551160a329487d4d45cd7aa1c39ece4a4e41bee0 /src/zencore/process.cpp
parentUpload vcpkg logs as artifacts on failure (diff)
parentFix naming of service handle close guard variable (diff)
downloadzen-10f6dc559688a650617b2e74eec039409f3d4687.tar.xz
zen-10f6dc559688a650617b2e74eec039409f3d4687.zip
Merge branch 'de/zen-service-command' of https://github.ol.epicgames.net/ue-foundation/zen into de/zen-service-command
Diffstat (limited to 'src/zencore/process.cpp')
-rw-r--r--src/zencore/process.cpp167
1 files changed, 163 insertions, 4 deletions
diff --git a/src/zencore/process.cpp b/src/zencore/process.cpp
index c51e8f69d..147b00966 100644
--- a/src/zencore/process.cpp
+++ b/src/zencore/process.cpp
@@ -24,7 +24,6 @@
# include <sys/sem.h>
# include <sys/stat.h>
# include <sys/syscall.h>
-# include <sys/sysctl.h>
# include <sys/wait.h>
# include <time.h>
# include <unistd.h>
@@ -41,7 +40,9 @@ ZEN_THIRD_PARTY_INCLUDES_END
namespace zen {
#if ZEN_PLATFORM_LINUX
-const bool bNoZombieChildren = []() {
+void
+IgnoreChildSignals()
+{
// When a child process exits it is put into a zombie state until the parent
// collects its result. This doesn't fit the Windows-like model that Zen uses
// where there is a less strict familial model and no zombification. Ignoring
@@ -52,8 +53,7 @@ const bool bNoZombieChildren = []() {
sigemptyset(&Action.sa_mask);
Action.sa_handler = SIG_IGN;
sigaction(SIGCHLD, &Action, nullptr);
- return true;
-}();
+}
static char
GetPidStatus(int Pid, std::error_code& OutEc)
@@ -443,6 +443,10 @@ CreateProcNormal(const std::filesystem::path& Executable, std::string_view Comma
{
CreationFlags |= CREATE_NEW_CONSOLE;
}
+ if (Options.Flags & CreateProcOptions::Flag_NoConsole)
+ {
+ CreationFlags |= CREATE_NO_WINDOW;
+ }
const wchar_t* WorkingDir = nullptr;
if (Options.WorkingDirectory != nullptr)
@@ -588,6 +592,10 @@ CreateProcUnelevated(const std::filesystem::path& Executable, std::string_view C
{
CreateProcFlags |= CREATE_NEW_CONSOLE;
}
+ if (Options.Flags & CreateProcOptions::Flag_NoConsole)
+ {
+ CreateProcFlags |= CREATE_NO_WINDOW;
+ }
ExtendableWideStringBuilder<256> CommandLineZ;
CommandLineZ << CommandLine;
@@ -798,6 +806,11 @@ IsProcessRunning(int pid, std::error_code& OutEc)
{
return false;
}
+ if (Error == ERROR_ACCESS_DENIED)
+ {
+ // Process is running under other user probably, assume it is running
+ return true;
+ }
OutEc = MakeErrorCode(Error);
return false;
}
@@ -840,6 +853,10 @@ IsProcessRunning(int pid, std::error_code& OutEc)
{
return false;
}
+ else if (Error == EPERM)
+ {
+ return true; // Running under a user we don't have access to, assume it is live
+ }
else
{
OutEc = MakeErrorCode(Error);
@@ -1047,6 +1064,118 @@ FindProcess(const std::filesystem::path& ExecutableImage, ProcessHandle& OutHand
#endif // ZEN_PLATFORM_LINUX
}
+std::vector<std::string>
+ParseCommandLine(std::string_view CommandLine)
+{
+ auto IsWhitespaceOrEnd = [](std::string_view CommandLine, std::string::size_type Pos) {
+ if (Pos == CommandLine.length())
+ {
+ return true;
+ }
+ if (CommandLine[Pos] == ' ')
+ {
+ return true;
+ }
+ return false;
+ };
+
+ bool IsParsingArg = false;
+ bool IsInQuote = false;
+
+ std::string::size_type Pos = 0;
+ std::string::size_type ArgStart = 0;
+ std::vector<std::string> Args;
+ while (Pos < CommandLine.length())
+ {
+ if (IsInQuote)
+ {
+ if (CommandLine[Pos] == '"' && IsWhitespaceOrEnd(CommandLine, Pos + 1))
+ {
+ Args.push_back(std::string(CommandLine.substr(ArgStart, Pos - ArgStart + 1)));
+ Pos++;
+ IsInQuote = false;
+ IsParsingArg = false;
+ }
+ else
+ {
+ Pos++;
+ }
+ }
+ else if (IsParsingArg)
+ {
+ ZEN_ASSERT(Pos > ArgStart);
+ if (CommandLine[Pos] == ' ')
+ {
+ Args.push_back(std::string(CommandLine.substr(ArgStart, Pos - ArgStart)));
+ Pos++;
+ IsParsingArg = false;
+ }
+ else if (CommandLine[Pos] == '"')
+ {
+ IsInQuote = true;
+ Pos++;
+ }
+ else
+ {
+ Pos++;
+ }
+ }
+ else if (CommandLine[Pos] == '"')
+ {
+ IsInQuote = true;
+ IsParsingArg = true;
+ ArgStart = Pos;
+ Pos++;
+ }
+ else if (CommandLine[Pos] != ' ')
+ {
+ IsParsingArg = true;
+ ArgStart = Pos;
+ Pos++;
+ }
+ else
+ {
+ Pos++;
+ }
+ }
+ if (IsParsingArg)
+ {
+ ZEN_ASSERT(Pos > ArgStart);
+ Args.push_back(std::string(CommandLine.substr(ArgStart)));
+ }
+
+ return Args;
+}
+
+std::vector<char*>
+StripCommandlineQuotes(std::vector<std::string>& InOutArgs)
+{
+ std::vector<char*> RawArgs;
+ RawArgs.reserve(InOutArgs.size());
+ for (std::string& Arg : InOutArgs)
+ {
+ std::string::size_type EscapedQuotePos = Arg.find("\\\"", 1);
+ while (EscapedQuotePos != std::string::npos && Arg.rfind('\"', EscapedQuotePos - 1) != std::string::npos)
+ {
+ Arg.erase(EscapedQuotePos, 1);
+ EscapedQuotePos = Arg.find("\\\"", EscapedQuotePos);
+ }
+
+ if (Arg.starts_with("\""))
+ {
+ if (Arg.find('"', 1) == Arg.length() - 1)
+ {
+ if (Arg.find(' ', 1) == std::string::npos)
+ {
+ Arg = Arg.substr(1, Arg.length() - 2);
+ }
+ }
+ }
+ RawArgs.push_back(const_cast<char*>(Arg.c_str()));
+ }
+ return RawArgs;
+}
+
#if ZEN_WITH_TESTS
void
@@ -1123,6 +1252,36 @@ TEST_CASE("BuildArgV")
}
}
+TEST_CASE("CommandLine")
+{
+ std::vector<std::string> v1 = ParseCommandLine("c:\\my\\exe.exe \"quoted arg\" \"one\",two,\"three\\\"");
+ CHECK_EQ(v1[0], "c:\\my\\exe.exe");
+ CHECK_EQ(v1[1], "\"quoted arg\"");
+ CHECK_EQ(v1[2], "\"one\",two,\"three\\\"");
+
+ std::vector<std::string> v2 = ParseCommandLine(
+ "--tracehost 127.0.0.1 builds download --url=https://jupiter.devtools.epicgames.com --namespace=ue.oplog "
+ "--bucket=citysample.packaged-build.fortnite-main.windows \"c:\\just\\a\\path\" "
+ "--access-token-path=\"C:\\Users\\dan.engelbrecht\\jupiter-token.json\" \"D:\\Dev\\Spaced Folder\\Target\\\" "
+ "--alt-path=\"D:\\Dev\\Spaced Folder2\\Target\\\" 07dn23ifiwesnvoasjncasab --build-part-name win64,linux,ps5");
+
+ std::vector<char*> v2Stripped = StripCommandlineQuotes(v2);
+ CHECK_EQ(v2Stripped[0], std::string("--tracehost"));
+ CHECK_EQ(v2Stripped[1], std::string("127.0.0.1"));
+ CHECK_EQ(v2Stripped[2], std::string("builds"));
+ CHECK_EQ(v2Stripped[3], std::string("download"));
+ CHECK_EQ(v2Stripped[4], std::string("--url=https://jupiter.devtools.epicgames.com"));
+ CHECK_EQ(v2Stripped[5], std::string("--namespace=ue.oplog"));
+ CHECK_EQ(v2Stripped[6], std::string("--bucket=citysample.packaged-build.fortnite-main.windows"));
+ CHECK_EQ(v2Stripped[7], std::string("c:\\just\\a\\path"));
+ CHECK_EQ(v2Stripped[8], std::string("--access-token-path=\"C:\\Users\\dan.engelbrecht\\jupiter-token.json\""));
+ CHECK_EQ(v2Stripped[9], std::string("\"D:\\Dev\\Spaced Folder\\Target\""));
+ CHECK_EQ(v2Stripped[10], std::string("--alt-path=\"D:\\Dev\\Spaced Folder2\\Target\""));
+ CHECK_EQ(v2Stripped[11], std::string("07dn23ifiwesnvoasjncasab"));
+ CHECK_EQ(v2Stripped[12], std::string("--build-part-name"));
+ CHECK_EQ(v2Stripped[13], std::string("win64,linux,ps5"));
+}
+
TEST_SUITE_END(/* core.process */);
#endif