Mercurial > libanimone
comparison src/util/osx.cc @ 0:a76fa32bdc92
*: 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 | cce3a81b03bf |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:a76fa32bdc92 |
|---|---|
| 1 #include "animone/util/osx.h" | |
| 2 | |
| 3 #include <memory> | |
| 4 #include <string> | |
| 5 | |
| 6 #include <libproc.h> | |
| 7 #include <sys/sysctl.h> | |
| 8 | |
| 9 namespace animone::internal::osx::util { | |
| 10 | |
| 11 typedef CFTypeRef (*LSASNCreateWithPidSpec)(CFAllocatorRef, pid_t); | |
| 12 typedef CFDictionaryRef (*LSCopyApplicationInformationSpec)(int, CFTypeRef, CFArrayRef); | |
| 13 | |
| 14 /* retrieved dynamically from launchservices */ | |
| 15 static LSCopyApplicationInformationSpec LSCopyApplicationInformation = nullptr; | |
| 16 static LSASNCreateWithPidSpec LSASNCreateWithPid = nullptr; | |
| 17 | |
| 18 static CFStringRef kLSDisplayNameKey = nullptr; | |
| 19 static CFStringRef kLSPIDKey = nullptr; | |
| 20 | |
| 21 /* retrieved from LaunchServicesSPI.h in WebKit */ | |
| 22 static constexpr int kLSDefaultSessionID = -2; | |
| 23 | |
| 24 static const CFStringRef kLaunchServicesBundleID = CFSTR("com.apple.LaunchServices"); | |
| 25 | |
| 26 static bool GetLaunchServicesPrivateSymbols() { | |
| 27 CFBundleRef launch_services_bundle = CFBundleGetBundleWithIdentifier(kLaunchServicesBundleID); | |
| 28 if (!launch_services_bundle) | |
| 29 return false; | |
| 30 | |
| 31 LSCopyApplicationInformation = reinterpret_cast<LSCopyApplicationInformationSpec>( | |
| 32 CFBundleGetFunctionPointerForName(launch_services_bundle, CFSTR("_LSCopyApplicationInformation"))); | |
| 33 if (!LSCopyApplicationInformation) | |
| 34 return false; | |
| 35 | |
| 36 LSASNCreateWithPid = reinterpret_cast<LSASNCreateWithPidSpec>( | |
| 37 CFBundleGetFunctionPointerForName(launch_services_bundle, CFSTR("_LSASNCreateWithPid"))); | |
| 38 if (!LSASNCreateWithPid) | |
| 39 return false; | |
| 40 | |
| 41 CFStringRef* ptr_kLSDisplayNameKey = reinterpret_cast<CFStringRef*>( | |
| 42 CFBundleGetDataPointerForName(launch_services_bundle, CFSTR("_kLSDisplayNameKey"))); | |
| 43 if (!ptr_kLSDisplayNameKey) | |
| 44 return false; | |
| 45 kLSDisplayNameKey = *ptr_kLSDisplayNameKey; | |
| 46 | |
| 47 CFStringRef* ptr_kLSPIDKey = | |
| 48 reinterpret_cast<CFStringRef*>(CFBundleGetDataPointerForName(launch_services_bundle, CFSTR("_kLSPIDKey"))); | |
| 49 if (!ptr_kLSPIDKey) | |
| 50 return false; | |
| 51 kLSPIDKey = *ptr_kLSPIDKey; | |
| 52 | |
| 53 return true; | |
| 54 } | |
| 55 | |
| 56 static bool LaunchServicesGetProcessName(pid_t pid, std::string& result) { | |
| 57 if (!LSCopyApplicationInformation || !LSASNCreateWithPid || !kLSDisplayNameKey || !kLSPIDKey) | |
| 58 if (!GetLaunchServicesPrivateSymbols()) | |
| 59 return false; | |
| 60 | |
| 61 /* what the hell is an `asn`? */ | |
| 62 CFPtr<CFTypeRef> asn = LSASNCreateWithPid(kCFAllocatorDefault, pid); | |
| 63 if (!asn) | |
| 64 return false; | |
| 65 | |
| 66 CFPtr<CFArrayRef> request_array = CFArrayCreate(NULL, (const void**)kLSDisplayNameKey, 1, NULL); | |
| 67 if (!request_array) | |
| 68 return false; | |
| 69 | |
| 70 CFPtr<CFDictionaryRef> dictionary = | |
| 71 LSCopyApplicationInformation(kLSDefaultSessionID, asn.get(), request_array.get()); | |
| 72 if (!dictionary) | |
| 73 return false; | |
| 74 | |
| 75 { | |
| 76 /* this doesn't need to be free'd */ | |
| 77 CFStringRef rstr; | |
| 78 | |
| 79 if (!CFDictionaryGetValueIfPresent(dictionary, kLSDisplayNameKey, (CFTypeRef*)&rstr) || !rstr) | |
| 80 return false; | |
| 81 | |
| 82 if (!StringFromCFString(rstr, result)) | |
| 83 return false; | |
| 84 } | |
| 85 | |
| 86 result.resize(result.find('\0')); | |
| 87 | |
| 88 return true; | |
| 89 } | |
| 90 | |
| 91 bool StringFromCFString(CFStringRef string, std::string& result) { | |
| 92 if (!string) | |
| 93 return false; | |
| 94 | |
| 95 result.resize(CFStringGetMaximumSizeForEncoding(CFStringGetLength(string), kCFStringEncodingUTF8) + 1); | |
| 96 if (!CFStringGetCString(string, &result.front(), result.length(), kCFStringEncodingUTF8)) | |
| 97 return false; | |
| 98 | |
| 99 return true; | |
| 100 } | |
| 101 | |
| 102 static bool GetProcessArgs(pid_t pid, std::string& args) { | |
| 103 /* sysctl shouldn't touch these, so we define them as const */ | |
| 104 int mib[3] = {CTL_KERN, KERN_PROCARGS2, static_cast<int>(pid)}; | |
| 105 const size_t mib_size = sizeof(mib) / sizeof(*mib); | |
| 106 | |
| 107 /* Get the initial size of the array | |
| 108 * | |
| 109 * NOTE: it IS possible for this value to change inbetween calls to sysctl(). | |
| 110 * Unfortunately, I couldn't care less about handling this. :) | |
| 111 * | |
| 112 * is that really true, though? these should be constant values. but are | |
| 113 * argc and argv *really* constant? | |
| 114 */ | |
| 115 size_t size; | |
| 116 { | |
| 117 int ret = sysctl((int*)mib, mib_size, nullptr, &size, nullptr, 0); | |
| 118 if (ret) | |
| 119 return false; | |
| 120 } | |
| 121 | |
| 122 /* Reserve the space for it in args */ | |
| 123 args.resize(size); | |
| 124 | |
| 125 /* Get the contents of argc and argv */ | |
| 126 { | |
| 127 int ret = sysctl((int*)mib, mib_size, &args.front(), &size, NULL, 0); | |
| 128 if (ret) | |
| 129 return false; | |
| 130 } | |
| 131 | |
| 132 /* Is the size big enough to hold at least argc? */ | |
| 133 if (size < sizeof(int)) | |
| 134 return false; | |
| 135 | |
| 136 args.resize(size); | |
| 137 return true; | |
| 138 } | |
| 139 | |
| 140 static bool GetProcessNameFromArgs(pid_t pid, std::string& result) { | |
| 141 if (!GetProcessArgs(pid, result)) | |
| 142 return false; | |
| 143 | |
| 144 /* Get argc using memcpy */ | |
| 145 int argc = 0; | |
| 146 memcpy(&argc, &result.front(), sizeof(argc)); | |
| 147 | |
| 148 /* Do we even have argv[0]? */ | |
| 149 if (argc < 1) | |
| 150 return false; | |
| 151 | |
| 152 /* Find the first null character */ | |
| 153 size_t null_pos = result.find('\0', sizeof(argc)); | |
| 154 if (null_pos == std::string::npos) | |
| 155 return false; | |
| 156 | |
| 157 /* Find the last slash */ | |
| 158 size_t last_slash = result.rfind('/', null_pos); | |
| 159 if (last_slash == std::string::npos) | |
| 160 return false; | |
| 161 | |
| 162 /* Return our result */ | |
| 163 result = result.substr(last_slash + 1, null_pos - last_slash - 1); | |
| 164 return true; | |
| 165 } | |
| 166 | |
| 167 static bool GetProcessNameFromKernel(pid_t pid, std::string& result) { | |
| 168 result.resize(2 * MAXCOMLEN); | |
| 169 | |
| 170 int size = proc_name(pid, &result.front(), result.length()); | |
| 171 if (!size) | |
| 172 return false; | |
| 173 | |
| 174 result.resize(size); | |
| 175 return true; | |
| 176 } | |
| 177 | |
| 178 bool GetProcessName(pid_t pid, std::string& result) { | |
| 179 if (LaunchServicesGetProcessName(pid, result)) | |
| 180 return true; | |
| 181 | |
| 182 /* Try parsing the arguments, this prevents the process name being | |
| 183 * cut off to 2*MAXCOMLEN (32 chars) */ | |
| 184 if (GetProcessNameFromArgs(pid, result)) | |
| 185 return true; | |
| 186 | |
| 187 /* Then attempt getting it from the kernel, which results in the | |
| 188 * process name being cut to 32 chars (worse, 16 chars if p_name is | |
| 189 * unavailable) */ | |
| 190 if (GetProcessNameFromKernel(pid, result)) | |
| 191 return true; | |
| 192 | |
| 193 return false; | |
| 194 } | |
| 195 | |
| 196 } // namespace animone::internal::osx::util |
