diff options
| author | Dan Engelbrecht <[email protected]> | 2025-01-10 15:40:04 +0100 |
|---|---|---|
| committer | Dan Engelbrecht <[email protected]> | 2025-01-10 15:40:04 +0100 |
| commit | 782745c3eaf0514172deccd37e443e109d779d5d (patch) | |
| tree | 03581ea711135942441aa7d15fa7c962d0ce6746 /src/zenutil/service.cpp | |
| parent | partially working service commands for macos (diff) | |
| download | zen-782745c3eaf0514172deccd37e443e109d779d5d.tar.xz zen-782745c3eaf0514172deccd37e443e109d779d5d.zip | |
cleanups
Diffstat (limited to 'src/zenutil/service.cpp')
| -rw-r--r-- | src/zenutil/service.cpp | 264 |
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 |