Mercurial > minori
view dep/animone/src/util/osx.cc @ 258:862d0d8619f6
*: HUUUGE changes
animia has been renamed to animone, so instead of thinking of a
health condition, you think of a beautiful flower :)
I've also edited some of the code for animone, but I have no idea
if it even works or not because I don't have a mac or windows
machine lying around. whoops!
... anyway, all of the changes divergent from Anisthesia are now
licensed under BSD. it's possible that I could even rewrite most
of the code to where I don't even have to keep the MIT license,
but that's thinking too far into the future
I've been slacking off on implementing the anime seasons page,
mostly out of laziness. I think I'd have to create another db file
specifically for the seasons
anyway, this code is being pushed *primarily* because the hard drive
it's on is failing! yay :)
author | Paper <paper@paper.us.eu.org> |
---|---|
date | Mon, 01 Apr 2024 02:43:44 -0400 |
parents | |
children | 382b50754fe4 |
line wrap: on
line source
#include "animone/util/osx.h" #include <memory> #include <string> #include <libproc.h> #include <sys/sysctl.h> namespace animone::internal::osx::util { typedef CFTypeRef (*LSASNCreateWithPidSpec)(CFAllocatorRef, pid_t); typedef CFDictionaryRef (*LSCopyApplicationInformationSpec)(int, CFTypeRef, CFArrayRef); /* retrieved dynamically from launchservices */ static LSCopyApplicationInformationSpec LSCopyApplicationInformation = nullptr; static LSASNCreateWithPidSpec LSASNCreateWithPid = nullptr; static CFStringRef kLSDisplayNameKey = nullptr; static CFStringRef kLSPIDKey = nullptr; /* retrieved from LaunchServicesSPI.h in WebKit */ static constexpr int kLSDefaultSessionID = -2; static const CFStringRef kLaunchServicesBundleID = CFSTR("com.apple.LaunchServices"); static bool GetLaunchServicesPrivateSymbols() { CFBundleRef launch_services_bundle = CFBundleGetBundleWithIdentifier(kLaunchServicesBundleID); if (!launch_services_bundle) return false; LSCopyApplicationInformation = reinterpret_cast<LSCopyApplicationInformationSpec>( CFBundleGetFunctionPointerForName(launch_services_bundle, CFSTR("_LSCopyApplicationInformation"))); if (!LSCopyApplicationInformation) return false; LSASNCreateWithPid = reinterpret_cast<LSASNCreateWithPidSpec>( CFBundleGetFunctionPointerForName(launch_services_bundle, CFSTR("_LSASNCreateWithPid"))); if (!LSASNCreateWithPid) return false; CFStringRef* ptr_kLSDisplayNameKey = reinterpret_cast<CFStringRef*>( CFBundleGetDataPointerForName(launch_services_bundle, CFSTR("_kLSDisplayNameKey"))); if (!ptr_kLSDisplayNameKey) return false; kLSDisplayNameKey = *ptr_kLSDisplayNameKey; CFStringRef* ptr_kLSPIDKey = reinterpret_cast<CFStringRef*>(CFBundleGetDataPointerForName(launch_services_bundle, CFSTR("_kLSPIDKey"))); if (!ptr_kLSPIDKey) return false; kLSPIDKey = *ptr_kLSPIDKey; return true; } static bool LaunchServicesGetProcessName(pid_t pid, std::string& result) { if (!LSCopyApplicationInformation || !LSASNCreateWithPid || !kLSDisplayNameKey || !kLSPIDKey) if (!GetLaunchServicesPrivateSymbols()) return false; /* what the hell is an `asn`? */ CFPtr<CFTypeRef> asn = LSASNCreateWithPid(kCFAllocatorDefault, pid); if (!asn) return false; CFPtr<CFArrayRef> request_array = CFArrayCreate(NULL, (const void**)kLSDisplayNameKey, 1, NULL); if (!request_array) return false; CFPtr<CFDictionaryRef> dictionary = LSCopyApplicationInformation(kLSDefaultSessionID, asn.get(), request_array.get()); if (!dictionary) return false; { /* this doesn't need to be free'd */ CFStringRef rstr; if (!CFDictionaryGetValueIfPresent(dictionary, kLSDisplayNameKey, (CFTypeRef*)&rstr) || !rstr) return false; if (!StringFromCFString(rstr, result)) return false; } 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; } static bool GetProcessArgs(pid_t pid, std::string& args) { /* sysctl shouldn't touch these, so we define them as 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. :) * * is that really true, though? these should be constant values. but are * argc and argv *really* constant? */ 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 = 0; memcpy(&argc, &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) { if (LaunchServicesGetProcessName(pid, result)) return true; /* 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; } } // namespace animone::internal::osx::util