comparison dep/animia/src/util/osx.cc @ 202:71832ffe425a

animia: re-add kvm fd source this is all being merged from my wildly out-of-date laptop. SORRY! in other news, I edited the CI file to install the wayland client as well, so the linux CI build might finally get wayland stuff.
author Paper <paper@paper.us.eu.org>
date Tue, 02 Jan 2024 06:05:06 -0500
parents 8548dc425697
children a7d0d543b334
comparison
equal deleted inserted replaced
201:8f6f8dd2eb23 202:71832ffe425a
1 #include "animia/util/osx.h" 1 #include "animia/util/osx.h"
2 2
3 #include <string> 3 #include <string>
4 #include <memory> 4 #include <memory>
5 5
6 #include <sys/sysctl.h>
7 #include <libproc.h>
8
9 namespace animia::internal::osx::util {
10
6 #ifdef HAVE_COREFOUNDATION 11 #ifdef HAVE_COREFOUNDATION
7 #include <CoreFoundation/CoreFoundation.h>
8 #endif
9
10 namespace animia::internal::osx::util {
11
12 #ifdef HAVE_COREFOUNDATION
13 /* I don't want to have to call CFRelease */
14 template<typename T>
15 struct CFDeleter {
16 using pointer = T;
17 void operator()(pointer p) { CFRelease(p); }
18 }
19
20 template<typename T>
21 typedef CFReference = std::unique_ptr<T, CFDeleter>;
22
23 /* all of these LaunchServices things use *internal functions* that are subject 12 /* all of these LaunchServices things use *internal functions* that are subject
24 * to change. Granted, it's not very likely that these will change very much 13 * to change. Granted, it's not very likely that these will change very much
25 * because I'm fairly sure Apple uses them lots in their own internal code. 14 * because I'm fairly sure Apple uses them lots in their own internal code.
26 */ 15 */
27 typedef CFTypeRef (*LSASNCreateWithPidSpec)(CFAllocatorRef, pid_t); 16 typedef CFTypeRef (*LSASNCreateWithPidSpec)(CFAllocatorRef, pid_t);
66 static bool LaunchServicesGetProcessName(pid_t pid, std::string& result) { 55 static bool LaunchServicesGetProcessName(pid_t pid, std::string& result) {
67 if (!LSCopyApplicationInformation || !LSASNCreateWithPid) 56 if (!LSCopyApplicationInformation || !LSASNCreateWithPid)
68 if (!GetLaunchServicesPrivateSymbols()) 57 if (!GetLaunchServicesPrivateSymbols())
69 return false; 58 return false;
70 59
71 CFReference<CFTypeRef> asn = LSASNCreateWithPid(kCFAllocatorDefault, pid); 60 CFTypeRef asn = LSASNCreateWithPid(kCFAllocatorDefault, pid);
72 61 if (!asn)
73 CFReference<CFArrayRef> request_array = CFArrayCreate(NULL, (const void **)kLSDisplayNameKey, 1, NULL); 62 return false;
74 63
75 CFReference<CFDictionaryRef> dictionary = LSCopyApplicationInformation(kLaunchServicesMagicConstant, asn, request_array.get()); 64 CFArrayRef request_array = CFArrayCreate(NULL, (const void **)kLSDisplayNameKey, 1, NULL);
76 if (!dictionary.get()) 65 if (!request_array) {
77 return false; 66 CFRelease(asn);
78 67 return false;
79 CFReference<CFStringRef> str; 68 }
69
70 CFDictionaryRef dictionary = LSCopyApplicationInformation(kLSDefaultSessionID, asn, request_array);
71
72 CFRelease(request_array);
73 CFRelease(asn);
74
75 if (!dictionary)
76 return false;
77
80 { 78 {
81 CFStringRef rstr; 79 CFStringRef rstr;
80
82 if (!CFDictionaryGetValueIfPresent(dictionary, kLSDisplayNameKey, (CFTypeRef*)&rstr) || !rstr) 81 if (!CFDictionaryGetValueIfPresent(dictionary, kLSDisplayNameKey, (CFTypeRef*)&rstr) || !rstr)
83 return false; 82 return false;
84 str.reset(rstr); 83
85 } 84 if (!StringFromCFString(rstr, result)) {
86 85 CFRelease(rstr);
87 result.reserve(CFStringGetMaximumSizeForEncoding(CFStringGetLength(str.get()), kCFStringEncodingUTF8) + 1); 86 return false;
88 87 }
89 if (!CFStringGetCString(str.get(), &result.front(), result.length(), result.length())) 88
89 CFRelease(rstr);
90 }
91
92 result.resize(result.find('\0'));
93
94 return true;
95 }
96
97 bool StringFromCFString(CFStringRef string, std::string& result) {
98 if (!string)
99 return false;
100
101 result.resize(CFStringGetMaximumSizeForEncoding(CFStringGetLength(string), kCFStringEncodingUTF8) + 1);
102 if (!CFStringGetCString(string, &result.front(), result.length(), kCFStringEncodingUTF8))
90 return false; 103 return false;
91 104
92 return true; 105 return true;
93 } 106 }
94 #endif // HAVE_COREFOUNDATION 107 #endif // HAVE_COREFOUNDATION
96 static bool GetProcessArgs(pid_t pid, std::string& args) { 109 static bool GetProcessArgs(pid_t pid, std::string& args) {
97 /* sysctl shouldn't touch these, so we define them as const */ 110 /* sysctl shouldn't touch these, so we define them as const */
98 const int mib[3] = {CTL_KERN, KERN_PROCARGS2, static_cast<int>(pid)}; 111 const int mib[3] = {CTL_KERN, KERN_PROCARGS2, static_cast<int>(pid)};
99 const size_t mib_size = sizeof(mib)/sizeof(*mib); 112 const size_t mib_size = sizeof(mib)/sizeof(*mib);
100 113
101 /* Get the initial size of the array */ 114 /* Get the initial size of the array
115 *
116 * NOTE: it IS possible for this value to change inbetween calls to sysctl().
117 * Unfortunately, I couldn't care less about handling this. :)
118 */
102 size_t size; 119 size_t size;
103 { 120 {
104 int ret = sysctl((int*)mib, mib_size, nullptr, &size, nullptr, 0); 121 int ret = sysctl((int*)mib, mib_size, nullptr, &size, nullptr, 0);
105 if (ret) 122 if (ret)
106 return false; 123 return false;
119 /* Is the size big enough to hold at least argc? */ 136 /* Is the size big enough to hold at least argc? */
120 if (size < sizeof(int)) 137 if (size < sizeof(int))
121 return false; 138 return false;
122 139
123 args.resize(size); 140 args.resize(size);
141 return true;
124 } 142 }
125 143
126 static bool GetProcessNameFromArgs(pid_t pid, std::string& result) { 144 static bool GetProcessNameFromArgs(pid_t pid, std::string& result) {
127 if (!GetProcessArgs(pid, result)) 145 if (!GetProcessArgs(pid, result))
128 return false; 146 return false;
129 147
130 /* Get argc using memcpy */ 148 /* Get argc using memcpy */
131 int argc; 149 int argc;
132 memcpy(&argc, &args.front(), sizeof(argc)); 150 memcpy(&result, &result.front(), sizeof(argc));
133 151
134 /* Do we even have argv[0]? */ 152 /* Do we even have argv[0]? */
135 if (argc < 1) 153 if (argc < 1)
136 return false; 154 return false;
137 155
138 /* Find the first null character */ 156 /* Find the first null character */
139 size_t null_pos = args.find('\0', sizeof(argc)); 157 size_t null_pos = result.find('\0', sizeof(argc));
140 if (null_pos == std::string::npos) 158 if (null_pos == std::string::npos)
141 return false; 159 return false;
142 160
143 /* Find the last slash */ 161 /* Find the last slash */
144 size_t last_slash = args.rfind('/', null_pos); 162 size_t last_slash = result.rfind('/', null_pos);
145 if (last_slash == std::string::npos) 163 if (last_slash == std::string::npos)
146 return false; 164 return false;
147 165
148 /* Return our result */ 166 /* Return our result */
149 result = args.substr(last_slash + 1, null_pos - last_slash - 1); 167 result = result.substr(last_slash + 1, null_pos - last_slash - 1);
150 return true; 168 return true;
151 } 169 }
152 170
153 static bool GetProcessNameFromKernel(pid_t pid, std::string& result) { 171 static bool GetProcessNameFromKernel(pid_t pid, std::string& result) {
154 result.resize(2 * MAXCOMLEN); 172 result.resize(2 * MAXCOMLEN);
159 177
160 result.resize(size); 178 result.resize(size);
161 return true; 179 return true;
162 } 180 }
163 181
164 static bool GetProcessName(pid_t pid, std::string& result) { 182 bool GetProcessName(pid_t pid, std::string& result) {
165 #ifdef HAVE_COREFOUNDATION 183 #ifdef HAVE_COREFOUNDATION
166 if (LaunchServicesGetProcessName(pid, result)) 184 if (LaunchServicesGetProcessName(pid, result))
167 return true; 185 return true;
168 #endif // HAVE_COREFOUNDATION 186 #endif // HAVE_COREFOUNDATION
169 187