]> git.saurik.com Git - apple/dyld.git/blob - dyld3/PathOverrides.cpp
dyld-519.2.2.tar.gz
[apple/dyld.git] / dyld3 / PathOverrides.cpp
1 /*
2 * Copyright (c) 2017 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25
26 #include <stdint.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <uuid/uuid.h>
30 #include <mach/mach.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <sys/errno.h>
34 #include <unistd.h>
35
36 #include "PathOverrides.h"
37
38
39
40 namespace dyld3 {
41
42 #if BUILDING_LIBDYLD
43 PathOverrides gPathOverrides;
44 #endif
45
46
47 // based on ANSI-C strstr()
48 static const char* strrstr(const char* str, const char* sub)
49 {
50 const size_t sublen = strlen(sub);
51 for(const char* p = &str[strlen(str)]; p != str; --p) {
52 if ( strncmp(p, sub, sublen) == 0 )
53 return p;
54 }
55 return NULL;
56 }
57
58
59 #if DYLD_IN_PROCESS
60 void PathOverrides::setEnvVars(const char* envp[])
61 {
62 for (const char** p = envp; *p != NULL; p++) {
63 addEnvVar(*p);
64 }
65 }
66
67 #else
68 PathOverrides::PathOverrides(const std::vector<std::string>& env)
69 {
70 for (const std::string& envVar : env) {
71 addEnvVar(envVar.c_str());
72 }
73 }
74 #endif
75
76 #if !BUILDING_LIBDYLD
77 // libdyld is never unloaded
78 PathOverrides::~PathOverrides()
79 {
80 freeArray(_dylibPathOverrides);
81 freeArray(_frameworkPathOverrides);
82 freeArray(_frameworkPathFallbacks);
83 freeArray(_dylibPathFallbacks);
84 }
85 #endif
86
87
88 void PathOverrides::handleEnvVar(const char* key, const char* value, void (^handler)(const char* envVar)) const
89 {
90 if ( value == nullptr )
91 return;
92 size_t allocSize = strlen(key) + strlen(value) + 2;
93 char buffer[allocSize];
94 strlcpy(buffer, key, allocSize);
95 strlcat(buffer, "=", allocSize);
96 strlcat(buffer, value, allocSize);
97 handler(buffer);
98 }
99
100 void PathOverrides::handleListEnvVar(const char* key, const char** list, void (^handler)(const char* envVar)) const
101 {
102 if ( list == nullptr )
103 return;
104 size_t allocSize = strlen(key) + 2;
105 for (const char** lp=list; *lp != nullptr; ++lp)
106 allocSize += strlen(*lp)+1;
107 char buffer[allocSize];
108 strlcpy(buffer, key, allocSize);
109 strlcat(buffer, "=", allocSize);
110 bool needColon = false;
111 for (const char** lp=list; *lp != nullptr; ++lp) {
112 if ( needColon )
113 strlcat(buffer, ":", allocSize);
114 strlcat(buffer, *lp, allocSize);
115 needColon = true;
116 }
117 handler(buffer);
118 }
119
120 void PathOverrides::forEachEnvVar(void (^handler)(const char* envVar)) const
121 {
122 handleListEnvVar("DYLD_LIBRARY_PATH", _dylibPathOverrides, handler);
123 handleListEnvVar("DYLD_FRAMEWORK_PATH", _frameworkPathOverrides, handler);
124 handleListEnvVar("DYLD_FALLBACK_FRAMEWORK_PATH", _frameworkPathFallbacks, handler);
125 handleListEnvVar("DYLD_FALLBACK_LIBRARY_PATH", _dylibPathFallbacks, handler);
126 handleListEnvVar("DYLD_INSERT_LIBRARIES", _insertedDylibs, handler);
127 handleEnvVar( "DYLD_IMAGE_SUFFIX", _imageSuffix, handler);
128 handleEnvVar( "DYLD_ROOT_PATH", _rootPath, handler);
129 }
130
131 uint32_t PathOverrides::envVarCount() const
132 {
133 uint32_t count = 0;
134 if ( _dylibPathOverrides != nullptr )
135 ++count;
136 if ( _frameworkPathOverrides != nullptr )
137 ++count;
138 if ( _frameworkPathFallbacks != nullptr )
139 ++count;
140 if ( _dylibPathFallbacks != nullptr )
141 ++count;
142 if ( _insertedDylibs != nullptr )
143 ++count;
144 if ( _imageSuffix != nullptr )
145 ++count;
146 if ( _rootPath != nullptr )
147 ++count;
148 return count;
149 }
150
151 void PathOverrides::forEachInsertedDylib(void (^handler)(const char* dylibPath)) const
152 {
153 if ( _insertedDylibs == nullptr )
154 return;
155 for (const char** lp=_insertedDylibs; *lp != nullptr; ++lp)
156 handler(*lp);
157 }
158
159 void PathOverrides::addEnvVar(const char* keyEqualsValue)
160 {
161 const char* equals = strchr(keyEqualsValue, '=');
162 if ( equals != NULL ) {
163 const char* value = &equals[1];
164 const size_t keyLen = equals-keyEqualsValue;
165 char key[keyLen+1];
166 strncpy(key, keyEqualsValue, keyLen);
167 key[keyLen] = '\0';
168 if ( strcmp(key, "DYLD_LIBRARY_PATH") == 0 ) {
169 _dylibPathOverrides = parseColonListIntoArray(value);
170 }
171 else if ( strcmp(key, "DYLD_FRAMEWORK_PATH") == 0 ) {
172 _frameworkPathOverrides = parseColonListIntoArray(value);
173 }
174 else if ( strcmp(key, "DYLD_FALLBACK_FRAMEWORK_PATH") == 0 ) {
175 _frameworkPathFallbacks = parseColonListIntoArray(value);
176 }
177 else if ( strcmp(key, "DYLD_FALLBACK_LIBRARY_PATH") == 0 ) {
178 _dylibPathFallbacks = parseColonListIntoArray(value);
179 }
180 else if ( strcmp(key, "DYLD_INSERT_LIBRARIES") == 0 ) {
181 _insertedDylibs = parseColonListIntoArray(value);
182 }
183 else if ( strcmp(key, "DYLD_IMAGE_SUFFIX") == 0 ) {
184 _imageSuffix = value;
185 }
186 else if ( strcmp(key, "DYLD_ROOT_PATH") == 0 ) {
187 _rootPath = value;
188 }
189 }
190 }
191
192 void PathOverrides::forEachInColonList(const char* list, void (^handler)(const char* path))
193 {
194 char buffer[strlen(list)+1];
195 const char* t = list;
196 for (const char* s=list; *s != '\0'; ++s) {
197 if (*s != ':')
198 continue;
199 size_t len = s - t;
200 memcpy(buffer, t, len);
201 buffer[len] = '\0';
202 handler(buffer);
203 t = s+1;
204 }
205 handler(t);
206 }
207
208 const char** PathOverrides::parseColonListIntoArray(const char* list)
209 {
210 __block int count = 1;
211 forEachInColonList(list, ^(const char* path) {
212 ++count;
213 });
214 const char** array = (const char**)malloc(count*sizeof(char*));
215 __block const char** p = array;
216 forEachInColonList(list, ^(const char* path) {
217 *p++ = strdup(path);
218 });
219 *p = nullptr;
220 return array;
221 }
222
223 void PathOverrides::freeArray(const char** array)
224 {
225 if ( array == nullptr )
226 return;
227
228 for (const char** p=array; *p != nullptr; ++p) {
229 free((void*)*p);
230 }
231 free(array);
232 }
233
234 void PathOverrides::forEachDylibFallback(Platform platform, void (^handler)(const char* fallbackDir, bool& stop)) const
235 {
236 bool stop = false;
237 if ( _dylibPathFallbacks != nullptr ) {
238 for (const char** fp=_dylibPathFallbacks; *fp != nullptr; ++fp) {
239 handler(*fp, stop);
240 if ( stop )
241 return;
242 }
243 }
244 else {
245 switch ( platform ) {
246 case Platform::macOS:
247 // "$HOME/lib"
248 handler("/usr/local/lib", stop); // FIXME: not for restricted processes
249 if ( !stop )
250 handler("/usr/lib", stop);
251 break;
252 case Platform::iOS:
253 case Platform::watchOS:
254 case Platform::tvOS:
255 case Platform::bridgeOS:
256 case Platform::unknown:
257 handler("/usr/local/lib", stop);
258 if ( !stop )
259 handler("/usr/lib", stop);
260 break;
261 }
262 }
263 }
264
265 void PathOverrides::forEachFrameworkFallback(Platform platform, void (^handler)(const char* fallbackDir, bool& stop)) const
266 {
267 bool stop = false;
268 if ( _frameworkPathFallbacks != nullptr ) {
269 for (const char** fp=_frameworkPathFallbacks; *fp != nullptr; ++fp) {
270 handler(*fp, stop);
271 if ( stop )
272 return;
273 }
274 }
275 else {
276 switch ( platform ) {
277 case Platform::macOS:
278 // "$HOME/Library/Frameworks"
279 handler("/Library/Frameworks", stop); // FIXME: not for restricted processes
280 // "/Network/Library/Frameworks"
281 if ( !stop )
282 handler("/System/Library/Frameworks", stop);
283 break;
284 case Platform::iOS:
285 case Platform::watchOS:
286 case Platform::tvOS:
287 case Platform::bridgeOS:
288 case Platform::unknown:
289 handler("/System/Library/Frameworks", stop);
290 break;
291 }
292 }
293 }
294
295 void PathOverrides::forEachPathVariant(const char* initialPath,
296 #if !DYLD_IN_PROCESS
297 Platform platform,
298 #endif
299 void (^handler)(const char* possiblePath, bool& stop)) const
300 {
301 #if DYLD_IN_PROCESS
302 Platform platform = MachOParser::currentPlatform();
303 #endif
304 __block bool stop = false;
305
306 // check for overrides
307 const char* frameworkPartialPath = getFrameworkPartialPath(initialPath);
308 if ( frameworkPartialPath != nullptr ) {
309 const size_t frameworkPartialPathLen = strlen(frameworkPartialPath);
310 // look at each DYLD_FRAMEWORK_PATH directory
311 if ( _frameworkPathOverrides != nullptr ) {
312 for (const char** fp=_frameworkPathOverrides; *fp != nullptr; ++fp) {
313 char npath[strlen(*fp)+frameworkPartialPathLen+8];
314 strcpy(npath, *fp);
315 strcat(npath, "/");
316 strcat(npath, frameworkPartialPath);
317 handler(npath, stop);
318 if ( stop )
319 return;
320 }
321 }
322 }
323 else {
324 const char* libraryLeafName = getLibraryLeafName(initialPath);
325 const size_t libraryLeafNameLen = strlen(libraryLeafName);
326 // look at each DYLD_LIBRARY_PATH directory
327 if ( _dylibPathOverrides != nullptr ) {
328 for (const char** lp=_dylibPathOverrides; *lp != nullptr; ++lp) {
329 char libpath[strlen(*lp)+libraryLeafNameLen+8];
330 strcpy(libpath, *lp);
331 strcat(libpath, "/");
332 strcat(libpath, libraryLeafName);
333 handler(libpath, stop);
334 if ( stop )
335 return;
336 }
337 }
338 }
339
340 // try original path
341 handler(initialPath, stop);
342 if ( stop )
343 return;
344
345 // check fallback paths
346 if ( frameworkPartialPath != nullptr ) {
347 const size_t frameworkPartialPathLen = strlen(frameworkPartialPath);
348 // look at each DYLD_FALLBACK_FRAMEWORK_PATH directory
349 forEachFrameworkFallback(platform, ^(const char* dir, bool& innerStop) {
350 char npath[strlen(dir)+frameworkPartialPathLen+8];
351 strcpy(npath, dir);
352 strcat(npath, "/");
353 strcat(npath, frameworkPartialPath);
354 handler(npath, innerStop);
355 if ( innerStop )
356 stop = innerStop;
357 });
358
359 }
360 else {
361 const char* libraryLeafName = getLibraryLeafName(initialPath);
362 const size_t libraryLeafNameLen = strlen(libraryLeafName);
363 // look at each DYLD_FALLBACK_LIBRARY_PATH directory
364 forEachDylibFallback(platform, ^(const char* dir, bool& innerStop) {
365 char libpath[strlen(dir)+libraryLeafNameLen+8];
366 strcpy(libpath, dir);
367 strcat(libpath, "/");
368 strcat(libpath, libraryLeafName);
369 handler(libpath, innerStop);
370 if ( innerStop )
371 stop = innerStop;
372 });
373 }
374 }
375
376
377 //
378 // Find framework path
379 //
380 // /path/foo.framework/foo => foo.framework/foo
381 // /path/foo.framework/Versions/A/foo => foo.framework/Versions/A/foo
382 // /path/foo.framework/Frameworks/bar.framework/bar => bar.framework/bar
383 // /path/foo.framework/Libraries/bar.dylb => NULL
384 // /path/foo.framework/bar => NULL
385 //
386 // Returns nullptr if not a framework path
387 //
388 const char* PathOverrides::getFrameworkPartialPath(const char* path) const
389 {
390 const char* dirDot = strrstr(path, ".framework/");
391 if ( dirDot != nullptr ) {
392 const char* dirStart = dirDot;
393 for ( ; dirStart >= path; --dirStart) {
394 if ( (*dirStart == '/') || (dirStart == path) ) {
395 const char* frameworkStart = &dirStart[1];
396 if ( dirStart == path )
397 --frameworkStart;
398 size_t len = dirDot - frameworkStart;
399 char framework[len+1];
400 strncpy(framework, frameworkStart, len);
401 framework[len] = '\0';
402 const char* leaf = strrchr(path, '/');
403 if ( leaf != nullptr ) {
404 if ( strcmp(framework, &leaf[1]) == 0 ) {
405 return frameworkStart;
406 }
407 if ( _imageSuffix != nullptr ) {
408 // some debug frameworks have install names that end in _debug
409 if ( strncmp(framework, &leaf[1], len) == 0 ) {
410 if ( strcmp( _imageSuffix, &leaf[len+1]) == 0 )
411 return frameworkStart;
412 }
413 }
414 }
415 }
416 }
417 }
418 return nullptr;
419 }
420
421
422 const char* PathOverrides::getLibraryLeafName(const char* path)
423 {
424 const char* start = strrchr(path, '/');
425 if ( start != nullptr )
426 return &start[1];
427 else
428 return path;
429 }
430
431 } // namespace dyld3
432
433
434
435
436