Mercurial > minori
view dep/animia/src/util/osx.cc @ 230:2f5a9247e501
torrents: implement download button
erg
author | Paper <paper@paper.us.eu.org> |
---|---|
date | Sat, 13 Jan 2024 09:42:02 -0500 |
parents | 8548dc425697 |
children | a7d0d543b334 |
line wrap: on
line source
#include "animia/util/osx.h" #include <string> #include <memory> #include <sys/sysctl.h> #include <libproc.h> namespace animia::internal::osx::util { #ifdef HAVE_COREFOUNDATION /* all of these LaunchServices things use *internal functions* that are subject * to change. Granted, it's not very likely that these will change very much * because I'm fairly sure Apple uses them lots in their own internal code. */ typedef CFTypeRef (*LSASNCreateWithPidSpec)(CFAllocatorRef, pid_t); typedef CFDictionaryRef (*LSCopyApplicationInformationSpec)(int, CFTypeRef, CFArrayRef); static LSCopyApplicationInformationSpec LSCopyApplicationInformation = nullptr; static LSASNCreateWithPidSpec LSASNCreateWithPid = nullptr; /* retrieved from LaunchServicesSPI.h in WebKit */ static constexpr int kLSDefaultSessionID = -2; static const CFStringRef kLaunchServicesBundleID = CFSTR("com.apple.LaunchServices"); /* retrieved dynamically */ static CFStringRef kLSDisplayNameKey = nullptr; static CFStringRef kLSPIDKey = nullptr; static bool GetLaunchServicesPrivateSymbols() { CFBundleRef launch_services_bundle = CFBundleGetBundleWithIdentifier(kLaunchServicesBundleID); if (!launch_services_bundle) return false; LSCopyApplicationInformation = (LSCopyApplicationInformationSpec)CFBundleGetFunctionPointerForName(launch_services_bundle, CFSTR("_LSCopyApplicationInformation")); if (!LSCopyApplicationInformation) return false; LSASNCreateWithPid = (LSASNCreateWithPidSpec)CFBundleGetFunctionPointerForName(launch_services_bundle, CFSTR("_LSASNCreateWithPid")); if (!LSASNCreateWithPid) return false; kLSDisplayNameKey = *(CFStringRef*)CFBundleGetDataPointerForName(launch_services_bundle, CFSTR("_kLSDisplayNameKey")); if (!kLSDisplayNameKey) return false; kLSPIDKey = *(CFStringRef*)CFBundleGetDataPointerForName(launch_services_bundle, CFSTR("_kLSPIDKey")); if (!kLSPIDKey) return false; return true; } static bool LaunchServicesGetProcessName(pid_t pid, std::string& result) { if (!LSCopyApplicationInformation || !LSASNCreateWithPid) if (!GetLaunchServicesPrivateSymbols()) return false; CFTypeRef asn = LSASNCreateWithPid(kCFAllocatorDefault, pid); if (!asn) return false; CFArrayRef request_array = CFArrayCreate(NULL, (const void **)kLSDisplayNameKey, 1, NULL); if (!request_array) { CFRelease(asn); return false; } CFDictionaryRef dictionary = LSCopyApplicationInformation(kLSDefaultSessionID, asn, request_array); CFRelease(request_array); CFRelease(asn); if (!dictionary) return false; { CFStringRef rstr; if (!CFDictionaryGetValueIfPresent(dictionary, kLSDisplayNameKey, (CFTypeRef*)&rstr) || !rstr) return false; if (!StringFromCFString(rstr, result)) { CFRelease(rstr); return false; } CFRelease(rstr); } result.resize(result.find('\0')); return true; } bool StringFromCFString(CFStringRef string, std::string& result) { if (!string) return false; result.resize(CFStringGetMaximumSizeForEncoding(CFStringGetLength(string), kCFStringEncodingUTF8) + 1); if (!CFStringGetCString(string, &result.front(), result.length(), kCFStringEncodingUTF8)) return false; return true; } #endif // HAVE_COREFOUNDATION static bool GetProcessArgs(pid_t pid, std::string& args) { /* sysctl shouldn't touch these, so we define them as const */ const int mib[3] = {CTL_KERN, KERN_PROCARGS2, static_cast<int>(pid)}; const size_t mib_size = sizeof(mib)/sizeof(*mib); /* Get the initial size of the array * * NOTE: it IS possible for this value to change inbetween calls to sysctl(). * Unfortunately, I couldn't care less about handling this. :) */ size_t size; { int ret = sysctl((int*)mib, mib_size, nullptr, &size, nullptr, 0); if (ret) return false; } /* Reserve the space for it in args */ args.resize(size); /* Get the contents of argc and argv */ { int ret = sysctl((int*)mib, mib_size, &args.front(), &size, NULL, 0); if (ret) return false; } /* Is the size big enough to hold at least argc? */ if (size < sizeof(int)) return false; args.resize(size); return true; } static bool GetProcessNameFromArgs(pid_t pid, std::string& result) { if (!GetProcessArgs(pid, result)) return false; /* Get argc using memcpy */ int argc; memcpy(&result, &result.front(), sizeof(argc)); /* Do we even have argv[0]? */ if (argc < 1) return false; /* Find the first null character */ size_t null_pos = result.find('\0', sizeof(argc)); if (null_pos == std::string::npos) return false; /* Find the last slash */ size_t last_slash = result.rfind('/', null_pos); if (last_slash == std::string::npos) return false; /* Return our result */ result = result.substr(last_slash + 1, null_pos - last_slash - 1); return true; } static bool GetProcessNameFromKernel(pid_t pid, std::string& result) { result.resize(2 * MAXCOMLEN); int size = proc_name(pid, &result.front(), result.length()); if (!size) return false; result.resize(size); return true; } bool GetProcessName(pid_t pid, std::string& result) { #ifdef HAVE_COREFOUNDATION if (LaunchServicesGetProcessName(pid, result)) return true; #endif // HAVE_COREFOUNDATION /* Try parsing the arguments, this prevents the process name being cut off to 2*MAXCOMLEN (32 chars) */ if (GetProcessNameFromArgs(pid, result)) return true; /* Then attempt getting it from the kernel, which results in the process name being cut to 32 chars (worse, 16 chars if p_name is unavailable) */ if (GetProcessNameFromKernel(pid, result)) return true; return false; } }