From fb14081f0f2e08ad8a6fc805efdc0489f4356a5e Mon Sep 17 00:00:00 2001 From: Stefan Schake Date: Tue, 26 Sep 2017 00:40:52 +0200 Subject: [PATCH] GarminServiceHelper implementation for MacOS --- src/Train/GarminServiceHelper.cpp | 70 ++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/src/Train/GarminServiceHelper.cpp b/src/Train/GarminServiceHelper.cpp index 609f9c413..1694f543a 100644 --- a/src/Train/GarminServiceHelper.cpp +++ b/src/Train/GarminServiceHelper.cpp @@ -16,9 +16,9 @@ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "GarminServiceHelper.h" -#include #if defined(_MSC_VER) + #pragma comment(lib, "advapi32.lib") #include @@ -114,6 +114,74 @@ bool GarminServiceHelper::stopService() return false; } +#elif defined(__APPLE__) + +#include +#include + +#include +#include +#include + +static pid_t findProcess(const std::string& pattern) +{ + int queryArgMax[] = { CTL_KERN, KERN_ARGMAX }; + int queryProcAll[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL }; + + int maxArgSize = 0; + size_t size = sizeof(maxArgSize); + if (sysctl(queryArgMax, 2, &maxArgSize, &size, nullptr, 0) == -1) + return -1; + + size_t processInfoSize; + if (sysctl(queryProcAll, 3, nullptr, &processInfoSize, nullptr, 0) < 0) + return -1; + + std::vector processInfo(processInfoSize / sizeof(struct kinfo_proc)); + if (sysctl(queryProcAll, 3, processInfo.data(), &processInfoSize, nullptr, 0) < 0) + return -1; + + std::vector argumentsBuffer(maxArgSize); + for (auto& process : processInfo) + { + pid_t pid = process.kp_proc.p_pid; + if (pid == 0) + continue; + + size = maxArgSize; + int queryProcArgs2[] = { CTL_KERN, KERN_PROCARGS2, pid }; + if (sysctl(queryProcArgs2, 3, argumentsBuffer.data(), &size, nullptr, 0) < 0) + { + // this generally happens if we don't have enough privileges + // therefore not a fatal error + continue; + } + + // the KERN_PROCARGS2 data is first an int (argc), then all of argv + // argv[0] is the path to the executable of the process we're interested in + std::string executablePath(&argumentsBuffer[sizeof(int)]); + if (executablePath.find(pattern) != std::string::npos) + return pid; + } + + return -1; +} + +static const char* GARMIN_SERVICE_EXECUTABLE = "/Garmin Express Service.app/Contents/MacOS/Garmin Express Service"; + +bool GarminServiceHelper::isServiceRunning() +{ + return findProcess(GARMIN_SERVICE_EXECUTABLE) != -1; +} + +bool GarminServiceHelper::stopService() +{ + pid_t pid = findProcess(GARMIN_SERVICE_EXECUTABLE); + if (pid != -1) + return killpg(getpgid(pid), SIGTERM) != -1; + return false; +} + #else bool GarminServiceHelper::isServiceRunning()