diff options
| author | Dan Engelbrecht <[email protected]> | 2025-01-13 11:04:53 +0100 |
|---|---|---|
| committer | Dan Engelbrecht <[email protected]> | 2025-01-13 11:04:53 +0100 |
| commit | 5ba659f322823445ff22573b580206ec6464898e (patch) | |
| tree | f64d1ee76b1c0a75bd900b28799a6600da9dcb82 /src/zenutil/service.cpp | |
| parent | typo fix (diff) | |
| download | zen-5ba659f322823445ff22573b580206ec6464898e.tar.xz zen-5ba659f322823445ff22573b580206ec6464898e.zip | |
linux service
Diffstat (limited to 'src/zenutil/service.cpp')
| -rw-r--r-- | src/zenutil/service.cpp | 199 |
1 files changed, 198 insertions, 1 deletions
diff --git a/src/zenutil/service.cpp b/src/zenutil/service.cpp index cfb19e9a9..8926accb3 100644 --- a/src/zenutil/service.cpp +++ b/src/zenutil/service.cpp @@ -351,7 +351,9 @@ namespace { } #endif // ZEN_PLATFORM_MAC || ZEN_PLATFORM_LINUX - +#if ZEN_PLATFORM_LINUX + const char* SystemInstallFolder = "/etc/systemd/system/"; +#endif // ZEN_PLATFORM_LINUX } // namespace std::string_view @@ -880,4 +882,199 @@ StopService(std::string_view ServiceName) #endif // ZEN_PLATFORM_MAC +#if ZEN_PLATFORM_LINUX + +std::error_code +InstallService(std::string_view ServiceName, const ServiceSpec& Spec) +{ + const std::string DaemonName = GetDaemonName(ServiceName); + std::string PList = BuildPlist(ServiceName, Spec.ExecutablePath, Spec.CommandLineOptions, DaemonName, true); + + const std::filesystem::path PListPath = GetPListPath(DaemonName); + ZEN_INFO("Writing launchd plist to {}", PListPath.string()); + try + { + zen::WriteFile(PListPath, IoBuffer(IoBuffer::Wrap, PList.data(), PList.size())); + } + catch (const std::system_error& Ex) + { + return MakeErrorCode(Ex.code().value()); + } + + ZEN_INFO("Changing permissions to 644 for {}", PListPath.string()); + if (chmod(PListPath.string().c_str(), 0644) == -1) + { + return MakeErrorCodeFromLastError(); + } + return {}; +} + +std::error_code +UninstallService(std::string_view ServiceName) +{ + 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; +} + +std::error_code +QueryInstalledService(std::string_view ServiceName, ServiceInfo& OutInfo) +{ + ZEN_UNUSED(ServiceName, OutInfo); + + OutInfo.Status = ServiceStatus::NotInstalled; + const std::string DaemonName = GetDaemonName(ServiceName); + + const std::filesystem::path PListPath = GetPListPath(DaemonName); + if (std::filesystem::is_regular_file(PListPath)) + { + OutInfo.Status = ServiceStatus::Stopped; + + { + // Parse plist :( + IoBuffer Buffer = ReadFile(PListPath).Flatten(); + MemoryView Data = Buffer.GetView(); + std::string PList((const char*)Data.GetData(), Data.GetSize()); + + 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()) + { + ForEachStrTok(Res.second, '\n', [&](std::string_view Line) { + if (Line.find("\"PID\"") != std::string_view::npos) + { + std::string_view::size_type PidStart = Line.find('='); + std::string_view::size_type PidEnd = Line.find(';'); + std::string_view PidString = Line.substr(PidStart + 2, PidEnd - (PidStart + 2)); + if (ParseInt<int>(PidString).has_value()) + { + OutInfo.Status = ServiceStatus::Running; + } + return false; + } + return true; + }); + // Parse installed info + } + } + } + + return {}; +} + +std::error_code +StartService(std::string_view ServiceName) +{ + ZEN_UNUSED(ServiceName); + + 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) + { + return MakeErrorCode(Res.first); + } + + return {}; +} + +std::error_code +StopService(std::string_view ServiceName) +{ + ZEN_UNUSED(ServiceName); + + 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) + { + return MakeErrorCode(Res.first); + } + + return {}; +} + +#endif // ZEN_PLATFORM_LINUX + } // namespace zen |