Mercurial > minori
comparison 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 |
comparison
equal
deleted
inserted
replaced
257:699a20c57dc8 | 258:862d0d8619f6 |
---|---|
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 |