Mercurial > minori
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dep/animone/src/util/osx.cc Mon Apr 01 02:43:44 2024 -0400 @@ -0,0 +1,196 @@ +#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