Mercurial > minori
comparison dep/animia/src/util/osx.cc @ 163:44c5e6dd9488
dep/animia/osx: move GetProcessName to util/osx so we can use it in quartz
| author | Paper <mrpapersonic@gmail.com> |
|---|---|
| date | Sat, 18 Nov 2023 00:47:40 -0500 |
| parents | 61b76c7b656a |
| children | 8937fb7f2d66 |
comparison
equal
deleted
inserted
replaced
| 162:61b76c7b656a | 163:44c5e6dd9488 |
|---|---|
| 1 /* A wrapper around multiple LaunchServices things */ | |
| 2 | |
| 3 #include "animia/util/osx.h" | 1 #include "animia/util/osx.h" |
| 4 | 2 |
| 3 #ifdef HAVE_COREFOUNDATION | |
| 5 #include <CoreFoundation/CoreFoundation.h> | 4 #include <CoreFoundation/CoreFoundation.h> |
| 6 | 5 #endif |
| 7 #include <iostream> | |
| 8 | 6 |
| 9 namespace animia::internal::osx::util { | 7 namespace animia::internal::osx::util { |
| 10 | 8 |
| 11 #define RDSymbolNameStr(symbol) (CFSTR("_"#symbol)) | 9 #ifdef HAVE_COREFOUNDATION |
| 10 /* All of these LaunchServices things use *internal functions* that are subject | |
| 11 ** to change. Granted, it's not very likely that these will change very much | |
| 12 ** because I'm fairly sure Apple uses them lots in their own internal code. | |
| 13 */ | |
| 12 | 14 |
| 13 static constexpr int kLaunchServicesMagicConstant = -2; // or -1, dunno the difference | 15 /* from RDProcess */ |
| 14 | |
| 15 typedef CFTypeRef (*LSASNCreateWithPidSpec)(CFAllocatorRef, pid_t); | 16 typedef CFTypeRef (*LSASNCreateWithPidSpec)(CFAllocatorRef, pid_t); |
| 16 typedef CFDictionaryRef (*LSCopyApplicationInformationSpec)(int, CFTypeRef, CFArrayRef); | 17 typedef CFDictionaryRef (*LSCopyApplicationInformationSpec)(int, CFTypeRef, CFArrayRef); |
| 17 | 18 |
| 18 static LSCopyApplicationInformationSpec LSCopyApplicationInformation = nullptr; | 19 static LSCopyApplicationInformationSpec LSCopyApplicationInformation = nullptr; |
| 19 static LSASNCreateWithPidSpec LSASNCreateWithPid = nullptr; | 20 static LSASNCreateWithPidSpec LSASNCreateWithPid = nullptr; |
| 20 | 21 |
| 21 static CFStringRef (kLSDisplayNameKey) = nullptr; | 22 /* retrieved from LaunchServicesSPI.h in WebKit */ |
| 22 static CFStringRef (kLSPIDKey) = nullptr; | 23 static constexpr int kLSDefaultSessionID = -2; |
| 24 static const CFStringRef kLaunchServicesBundleID = CFSTR("com.apple.LaunchServices"); | |
| 23 | 25 |
| 24 static CFStringRef (kLaunchServicesBundleID) = CFSTR("com.apple.LaunchServices"); | 26 /* retrieved dynamically */ |
| 27 static CFStringRef kLSDisplayNameKey = nullptr; | |
| 28 static CFStringRef kLSPIDKey = nullptr; | |
| 25 | 29 |
| 26 static bool FindLaunchServicesPrivateSymbols() { | 30 static bool GetLaunchServicesPrivateSymbols() { |
| 27 CFBundleRef launch_services_bundle = CFBundleGetBundleWithIdentifier(kLaunchServicesBundleID); | 31 CFBundleRef launch_services_bundle = CFBundleGetBundleWithIdentifier(kLaunchServicesBundleID); |
| 28 if (!launch_services_bundle) | 32 if (!launch_services_bundle) |
| 29 return false; | 33 return false; |
| 30 | 34 |
| 31 LSCopyApplicationInformation = (LSCopyApplicationInformationSpec)CFBundleGetFunctionPointerForName(launch_services_bundle, RDSymbolNameStr(LSCopyApplicationInformation)); | 35 LSCopyApplicationInformation = (LSCopyApplicationInformationSpec)CFBundleGetFunctionPointerForName(launch_services_bundle, CFSTR("_LSCopyApplicationInformation")); |
| 32 if (!LSCopyApplicationInformation) | 36 if (!LSCopyApplicationInformation) |
| 33 return false; | 37 return false; |
| 34 | 38 |
| 35 LSASNCreateWithPid = (LSASNCreateWithPidSpec)CFBundleGetFunctionPointerForName(launch_services_bundle, RDSymbolNameStr(LSASNCreateWithPid)); | 39 LSASNCreateWithPid = (LSASNCreateWithPidSpec)CFBundleGetFunctionPointerForName(launch_services_bundle, CFSTR("_LSASNCreateWithPid")); |
| 36 if (!LSASNCreateWithPid) | 40 if (!LSASNCreateWithPid) |
| 37 return false; | 41 return false; |
| 38 | 42 |
| 39 kLSDisplayNameKey = *(CFStringRef*)CFBundleGetDataPointerForName(launch_services_bundle, RDSymbolNameStr(kLSDisplayNameKey)); | 43 kLSDisplayNameKey = *(CFStringRef*)CFBundleGetDataPointerForName(launch_services_bundle, CFSTR("_kLSDisplayNameKey")); |
| 40 if (!kLSDisplayNameKey) | 44 if (!kLSDisplayNameKey) |
| 41 return false; | 45 return false; |
| 42 | 46 |
| 43 kLSPIDKey = *(CFStringRef*)CFBundleGetDataPointerForName(launch_services_bundle, RDSymbolNameStr(kLSPIDKey)); | 47 kLSPIDKey = *(CFStringRef*)CFBundleGetDataPointerForName(launch_services_bundle, CFSTR("_kLSPIDKey")); |
| 44 if (!kLSPIDKey) | 48 if (!kLSPIDKey) |
| 45 return false; | 49 return false; |
| 46 | 50 |
| 47 return true; | 51 return true; |
| 48 } | 52 } |
| 49 | 53 |
| 50 bool LaunchServicesGetProcessName(pid_t pid, std::string& result) { | 54 static bool LaunchServicesGetProcessName(pid_t pid, std::string& result) { |
| 51 if (!LSCopyApplicationInformation || !LSASNCreateWithPid) | 55 if (!LSCopyApplicationInformation || !LSASNCreateWithPid) |
| 52 if (!FindLaunchServicesPrivateSymbols()) | 56 if (!GetLaunchServicesPrivateSymbols()) |
| 53 return false; | 57 return false; |
| 54 | 58 |
| 55 CFTypeRef asn = LSASNCreateWithPid(kCFAllocatorDefault, pid); | 59 CFTypeRef asn = LSASNCreateWithPid(kCFAllocatorDefault, pid); |
| 56 | 60 |
| 57 CFArrayRef request_array = CFArrayCreate(NULL, (const void **)kLSDisplayNameKey, 1, NULL); | 61 CFArrayRef request_array = CFArrayCreate(NULL, (const void **)kLSDisplayNameKey, 1, NULL); |
| 80 | 84 |
| 81 CFRelease(str); | 85 CFRelease(str); |
| 82 | 86 |
| 83 return true; | 87 return true; |
| 84 } | 88 } |
| 89 #endif // HAVE_COREFOUNDATION | |
| 90 | |
| 91 static bool GetProcessArgs(pid_t pid, std::string& args) { | |
| 92 /* sysctl shouldn't touch these, so we define them as const */ | |
| 93 const int mib[3] = {CTL_KERN, KERN_PROCARGS2, static_cast<int>(pid)}; | |
| 94 const size_t mib_size = sizeof(mib)/sizeof(*mib); | |
| 95 | |
| 96 /* Get the initial size of the array */ | |
| 97 size_t size; | |
| 98 { | |
| 99 int ret = sysctl((int*)mib, mib_size, nullptr, &size, nullptr, 0); | |
| 100 if (ret) | |
| 101 return false; | |
| 102 } | |
| 103 | |
| 104 /* Reserve the space for it in args */ | |
| 105 args.resize(size); | |
| 106 | |
| 107 /* Get the contents of argc and argv */ | |
| 108 { | |
| 109 int ret = sysctl((int*)mib, mib_size, &args.front(), &size, NULL, 0); | |
| 110 if (ret) | |
| 111 return false; | |
| 112 } | |
| 113 | |
| 114 /* Is the size big enough to hold at least argc? */ | |
| 115 if (size < sizeof(int)) | |
| 116 return false; | |
| 117 | |
| 118 args.resize(size); | |
| 119 } | |
| 120 | |
| 121 static bool GetProcessNameFromArgs(pid_t pid, std::string& result) { | |
| 122 if (!GetProcessArgs(pid, result)) | |
| 123 return false; | |
| 124 | |
| 125 /* Get argc using memcpy */ | |
| 126 int argc; | |
| 127 memcpy(&argc, &args.front(), sizeof(argc)); | |
| 128 | |
| 129 /* Do we even have argv[0]? */ | |
| 130 if (argc < 1) | |
| 131 return false; | |
| 132 | |
| 133 /* Find the first null character */ | |
| 134 size_t null_pos = args.find('\0', sizeof(argc)); | |
| 135 if (null_pos == std::string::npos) | |
| 136 return false; | |
| 137 | |
| 138 /* Find the last slash */ | |
| 139 size_t last_slash = args.rfind('/', null_pos); | |
| 140 if (last_slash == std::string::npos) | |
| 141 return false; | |
| 142 | |
| 143 /* Return our result */ | |
| 144 result = args.substr(last_slash + 1, null_pos - last_slash - 1); | |
| 145 return true; | |
| 146 } | |
| 147 | |
| 148 static bool GetProcessNameFromKernel(pid_t pid, std::string& result) { | |
| 149 result.reserve(2*MAXCOMLEN); | |
| 150 if (!proc_name(pid, &result.front(), result.length())) | |
| 151 return false; | |
| 152 | |
| 153 result.shrink_to_fit(); | |
| 154 return true; | |
| 155 } | |
| 156 | |
| 157 static bool GetProcessName(pid_t pid, std::string& result) { | |
| 158 #ifdef HAVE_COREFOUNDATION | |
| 159 if (LaunchServicesGetProcessName(pid, result)) | |
| 160 return true; | |
| 161 #endif // HAVE_COREFOUNDATION | |
| 162 | |
| 163 /* Try parsing the arguments, this prevents the process name being | |
| 164 cut off to 2*MAXCOMLEN (32 chars) */ | |
| 165 if (GetProcessNameFromArgs(pid, result)) | |
| 166 return true; | |
| 167 | |
| 168 /* Then attempt getting it from the kernel, which results in the | |
| 169 process name being cut to 32 chars (worse, 16 chars if p_name is | |
| 170 unavailable) */ | |
| 171 if (GetProcessNameFromKernel(pid, result)) | |
| 172 return true; | |
| 173 | |
| 174 return false; | |
| 175 } | |
| 85 | 176 |
| 86 } | 177 } |
