aboutsummaryrefslogtreecommitdiff
path: root/src/zenutil/service.cpp
diff options
context:
space:
mode:
authorDan Engelbrecht <[email protected]>2025-01-13 11:04:53 +0100
committerDan Engelbrecht <[email protected]>2025-01-13 11:04:53 +0100
commit5ba659f322823445ff22573b580206ec6464898e (patch)
treef64d1ee76b1c0a75bd900b28799a6600da9dcb82 /src/zenutil/service.cpp
parenttypo fix (diff)
downloadzen-5ba659f322823445ff22573b580206ec6464898e.tar.xz
zen-5ba659f322823445ff22573b580206ec6464898e.zip
linux service
Diffstat (limited to 'src/zenutil/service.cpp')
-rw-r--r--src/zenutil/service.cpp199
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