aboutsummaryrefslogtreecommitdiff
path: root/src/zenutil/service.cpp
diff options
context:
space:
mode:
authorDan Engelbrecht <[email protected]>2025-01-10 15:40:04 +0100
committerDan Engelbrecht <[email protected]>2025-01-10 15:40:04 +0100
commit782745c3eaf0514172deccd37e443e109d779d5d (patch)
tree03581ea711135942441aa7d15fa7c962d0ce6746 /src/zenutil/service.cpp
parentpartially working service commands for macos (diff)
downloadzen-782745c3eaf0514172deccd37e443e109d779d5d.tar.xz
zen-782745c3eaf0514172deccd37e443e109d779d5d.zip
cleanups
Diffstat (limited to 'src/zenutil/service.cpp')
-rw-r--r--src/zenutil/service.cpp264
1 files changed, 105 insertions, 159 deletions
diff --git a/src/zenutil/service.cpp b/src/zenutil/service.cpp
index feebeb7f4..08ccac512 100644
--- a/src/zenutil/service.cpp
+++ b/src/zenutil/service.cpp
@@ -173,14 +173,26 @@ namespace {
}
}
+ std::string GetDaemonName(std::string_view ServiceName)
+ {
+ return fmt::format("com.epicgames.unreal.{}", ServiceName);
+ }
+
+ std::filesystem::path GetPListPath(const std::string& DaemonName)
+ {
+ const std::filesystem::path PListFolder = "/Library/LaunchDaemons";
+ return PListFolder / (DaemonName + ".plist");
+ }
+
std::string BuildPlist(std::string_view ServiceName,
const std::filesystem::path& ExecutablePath,
std::string_view CommandLineOptions,
std::string_view DaemonName,
- std::string_view /*ServiceDisplayName*/,
- std::string_view /*ServiceDescription*/,
+ std::string_view ServiceDisplayName,
+ std::string_view ServiceDescription,
bool Debug)
{
+ ZEN_UNUSED(ServiceDisplayName, ServiceDescription);
std::vector<std::string_view> Arguments = SplitArguments(CommandLineOptions);
ExtendableStringBuilder<256> ProgramArguments;
for (const std::string_view Argument : Arguments)
@@ -678,76 +690,18 @@ StopService(std::string_view ServiceName)
return {};
}
-#else
-
-# if 0
-static int CopyFile(std::filesystem::path source, std::filesystem::path dest)
-{
+#endif
- int childExitStatus;
- pid_t pid;
- int status;
-
- pid = fork();
-
- if (pid == 0) { /* child */
- execl("/bin/cp", "/bin/cp", source.string().c_str(), dest.string().c_str(), (char *)0);
- return 0;
- }
- else if (pid < 0) {
- return -1;
- }
- else {
- /* parent - wait for child - this has all error handling, you
- * could just call wait() as long as you are only expecting to
- * have one child process at a time.
- */
- pid_t ws = waitpid( pid, &childExitStatus, WNOHANG);
- if (ws == -1)
- {
- return -1;
- }
-
- if( WIFEXITED(childExitStatus)) /* exit code in childExitStatus */
- {
- status = WEXITSTATUS(childExitStatus); /* zero is normal exit */
- return status;
- }
- else if (WIFSIGNALED(childExitStatus)) /* killed */
- {
- return -1;
- }
- else if (WIFSTOPPED(childExitStatus)) /* stopped */
- {
- return -1;
- }
- return -1;
- }
-}
-# endif
+#if ZEN_PLATFORM_MAC
std::error_code
InstallService(std::string_view ServiceName, const ServiceSpec& Spec)
{
- // std::filesystem::path ServicePath = std::filesystem::path("/usr/local/libexec") / ServiceName;
- // ZEN_INFO("Attempting to copy service from {} to {}", Spec.ExecutablePath.string(), ServicePath.string());
- // if (false && CopyFile(Spec.ExecutablePath, ServicePath) == -1)
- //// if (symlink(Spec.ExecutablePath.c_str(), ServicePath.c_str()) == -1)
- // {
- // return MakeErrorCodeFromLastError();
- // }
-
- // System: /Library/LaunchDaemon
- // All users: /Library/LaunchAgents
- // Current user: ~/Library/LaunchAgents
-
- std::string DaemonName = fmt::format("com.epicgames.unreal.{}", ServiceName);
+ const std::string DaemonName = GetDaemonName(ServiceName);
std::string PList =
BuildPlist(ServiceName, Spec.ExecutablePath, Spec.CommandLineOptions, DaemonName, Spec.DisplayName, Spec.Description, true);
- std::filesystem::path PListFolder = "/Library/LaunchDaemon";
-
- std::filesystem::path PListPath = PListFolder / (DaemonName + ".plist");
+ const std::filesystem::path PListPath = GetPListPath(DaemonName);
ZEN_INFO("Writing launchd plist to {}", PListPath.string());
try
{
@@ -758,8 +712,8 @@ InstallService(std::string_view ServiceName, const ServiceSpec& Spec)
return MakeErrorCode(Ex.code().value());
}
- ZEN_INFO("Changing permissions to 600 for {}", PListPath.string());
- if (chmod(PListPath.string().c_str(), 0600) == -1)
+ ZEN_INFO("Changing permissions to 644 for {}", PListPath.string());
+ if (chmod(PListPath.string().c_str(), 0644) == -1)
{
return MakeErrorCodeFromLastError();
}
@@ -769,25 +723,12 @@ InstallService(std::string_view ServiceName, const ServiceSpec& Spec)
std::error_code
UninstallService(std::string_view ServiceName)
{
-// std::filesystem::path ServicePath = std::filesystem::path("/usr/local/libexec") / ServiceName;
-// ZEN_INFO("Attempting to remove service from {}", ServicePath.string());
-// if (unlink(ServicePath.string().c_str()) == -1)
-// {
-// return MakeErrorCodeFromLastError();
-// }
- std::string DaemonName = fmt::format("com.epicgames.unreal.{}", ServiceName);
- std::filesystem::path PListPath = std::filesystem::path("/Library/LaunchDaemon") / (DaemonName + ".plist");
+ const std::string DaemonName = GetDaemonName(ServiceName);
+ const std::filesystem::path PListPath = GetPListPath(DaemonName);
ZEN_INFO("Attempting to remove launchd plist from {}", PListPath.string());
std::error_code Ec;
std::filesystem::remove(PListPath, Ec);
return Ec;
-
-// if (unlink(PListPath.string().c_str()) == -1)
-// {
-// return MakeErrorCodeFromLastError();
-// }
-
-// return {};
}
std::error_code
@@ -796,11 +737,9 @@ QueryInstalledService(std::string_view ServiceName, ServiceInfo& OutInfo)
ZEN_UNUSED(ServiceName, OutInfo);
OutInfo.Status = ServiceStatus::NotInstalled;
- std::string DaemonName = fmt::format("com.epicgames.unreal.{}", ServiceName);
-
- std::filesystem::path PListFolder = "/Library/LaunchDaemon";
+ const std::string DaemonName = GetDaemonName(ServiceName);
- std::filesystem::path PListPath = PListFolder / (DaemonName + ".plist");
+ const std::filesystem::path PListPath = GetPListPath(DaemonName);
if (std::filesystem::is_regular_file(PListPath))
{
OutInfo.Status = ServiceStatus::Stopped;
@@ -810,34 +749,88 @@ QueryInstalledService(std::string_view ServiceName, ServiceInfo& OutInfo)
IoBuffer Buffer = ReadFile(PListPath).Flatten();
MemoryView Data = Buffer.GetView();
std::string PList((const char*)Data.GetData(), Data.GetSize());
- ZEN_INFO("{}", PList);
+
+ enum class ParseMode
+ {
+ None,
+ ExpectingProgramArgumentsArray,
+ ExpectingProgramExecutablePath,
+ ExpectingCommandLineOption
+ };
+
+ ParseMode Mode = ParseMode::None;
+
+ ForEachStrTok(PList, '\n', [&](std::string_view Line){
+ switch (Mode)
+ {
+ case ParseMode::None:
+ {
+ if (Line.find("<key>ProgramArguments</key>") != std::string_view::npos)
+ {
+ Mode = ParseMode::ExpectingProgramArgumentsArray;
+ return true;
+ }
+ }
+ break;
+ case ParseMode::ExpectingProgramArgumentsArray:
+ {
+ if (Line.find("<array>") != std::string_view::npos)
+ {
+ Mode = ParseMode::ExpectingProgramExecutablePath;
+ return true;
+ }
+ Mode = ParseMode::None;
+ }
+ break;
+ case ParseMode::ExpectingProgramExecutablePath:
+ {
+ if (std::string_view::size_type ArgStart = Line.find("<string>"); ArgStart != std::string_view::npos)
+ {
+ ArgStart += 8;
+ if (std::string_view::size_type ArgEnd = Line.find("</string>", ArgStart); ArgEnd != std::string_view::npos)
+ {
+ std::string_view ProgramString = Line.substr(ArgStart, ArgEnd - ArgStart);
+ OutInfo.Spec.ExecutablePath = ProgramString;
+ Mode = ParseMode::ExpectingCommandLineOption;
+ return true;
+ }
+ }
+ Mode = ParseMode::None;
+ }
+ break;
+ case ParseMode::ExpectingCommandLineOption:
+ {
+ if (std::string_view::size_type ArgStart = Line.find("</array>"); ArgStart != std::string_view::npos)
+ {
+ Mode = ParseMode::None;
+ return true;
+ }
+ else if (std::string_view::size_type ArgStart = Line.find("<string>"); ArgStart != std::string_view::npos)
+ {
+ ArgStart += 8;
+ if (std::string_view::size_type ArgEnd = Line.find("</string>", ArgStart); ArgEnd != std::string_view::npos)
+ {
+ std::string_view ArgumentString = Line.substr(ArgStart, ArgEnd - ArgStart);
+ if (!OutInfo.Spec.CommandLineOptions.empty())
+ {
+ OutInfo.Spec.CommandLineOptions += " ";
+ }
+ OutInfo.Spec.CommandLineOptions += ArgumentString;
+ return true;
+ }
+ }
+ Mode = ParseMode::None;
+ }
+ break;
+ }
+ return true;
+ });
}
{
std::pair<int, std::string> Res = ExecuteProgram(std::string("launchctl list ") + DaemonName);
if (Res.first == 0 && !Res.second.empty())
{
-// bool IsParsingArguments = false;
ForEachStrTok(Res.second, '\n', [&](std::string_view Line){
-// if (IsParsingArguments)
-// {
-// if (Line.find(");") == Line.length() - 2)
-// {
-// IsParsingArguments = false;
-// return true;
-// }
-// std::string_view::size_type ProgramArgumentsEnd = Line.find_last_of('\"');
-// std::string_view::size_type ProgramArgumentsStart = Line.find('\"') + 1;
-// std::string_view ProgramArgumentsString = Line.substr(ProgramArgumentsStart, ProgramArgumentsEnd - ProgramArgumentsStart);
-// if (ProgramArgumentsString != OutInfo.Spec.ExecutablePath)
-// {
-// if (!OutInfo.Spec.CommandLineOptions.empty())
-// {
-// OutInfo.Spec.CommandLineOptions += " ";
-// }
-// OutInfo.Spec.CommandLineOptions += ProgramArgumentsString;
-// }
-// return true;
-// }
if (Line.find("\"PID\"") != std::string_view::npos)
{
std::string_view::size_type PidStart = Line.find('=');
@@ -849,56 +842,11 @@ QueryInstalledService(std::string_view ServiceName, ServiceInfo& OutInfo)
}
return false;
}
-// if (Line.find("\"Program\"") != std::string_view::npos)
-// {
-// std::string_view::size_type ProgramEnd = Line.find_last_of('\"');
-// std::string_view::size_type ProgramStart = Line.find_last_of('\"', ProgramEnd - 1) + 1;
-// std::string_view ProgramString = Line.substr(ProgramStart, ProgramEnd - ProgramStart);
-// OutInfo.Spec.ExecutablePath = ProgramString;
-// return true;
-// }
-// if (Line.find("\"ProgramArguments\"") != std::string_view::npos)
-// {
-// IsParsingArguments = true;
-// return true;
-// }
return true;
});
// Parse installed info
}
}
-#if 0
- {
- std::pair<int, std::string> Res = ExecuteProgram("launchctl list");
- if (Res.first != 0)
- {
- return MakeErrorCode(Res.first);
- }
- std::string ZenServerLine;
- ForEachStrTok(Res.second, '\n', [&](std::string_view Line){
- if (Line.find(DaemonName) != std::string_view::npos)
- {
- ZenServerLine = Line;
- }
- return true;
- });
- if (!ZenServerLine.empty())
- {
- std::vector<std::string_view> Parts;
- ForEachStrTok(ZenServerLine, '\t', [&](std::string_view Line){
- Parts.push_back(Line);
- return true;
- });
- if (Parts.size() == 3)
- {
- if (Parts[0] != "-" && ParseInt<int>(Parts[0]).has_value())
- {
- OutInfo.Status = ServiceStatus::Running;
- }
- }
- }
- }
-#endif // 0
}
return {};
@@ -909,9 +857,8 @@ StartService(std::string_view ServiceName)
{
ZEN_UNUSED(ServiceName);
- std::string DaemonName = fmt::format("com.epicgames.unreal.{}", ServiceName);
- std::filesystem::path PListFolder = "/Library/LaunchDaemon";
- std::filesystem::path PListPath = PListFolder / (DaemonName + ".plist");
+ const std::string DaemonName = GetDaemonName(ServiceName);
+ const std::filesystem::path PListPath = GetPListPath(DaemonName);
std::pair<int, std::string> Res = ExecuteProgram(std::string("launchctl bootstrap system ") + PListPath.string());
if (Res.first != 0)
@@ -927,9 +874,8 @@ StopService(std::string_view ServiceName)
{
ZEN_UNUSED(ServiceName);
- std::string DaemonName = fmt::format("com.epicgames.unreal.{}", ServiceName);
- std::filesystem::path PListFolder = "/Library/LaunchDaemon";
- std::filesystem::path PListPath = PListFolder / (DaemonName + ".plist");
+ const std::string DaemonName = GetDaemonName(ServiceName);
+ const std::filesystem::path PListPath = GetPListPath(DaemonName);
std::pair<int, std::string> Res = ExecuteProgram(std::string("launchctl bootout system ") + PListPath.string());
if (Res.first != 0)
@@ -940,6 +886,6 @@ StopService(std::string_view ServiceName)
return {};
}
-#endif // ZEN_PLATFORM_WINDOWS
+#endif // ZEN_PLATFORM_MAC
} // namespace zen