]> git.saurik.com Git - apple/dyld.git/blame - dyld3/PathOverrides.cpp
dyld-551.3.tar.gz
[apple/dyld.git] / dyld3 / PathOverrides.cpp
CommitLineData
10b92d3b
A
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
40namespace dyld3 {
41
42#if BUILDING_LIBDYLD
43PathOverrides gPathOverrides;
44#endif
45
46
47// based on ANSI-C strstr()
48static 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
60void PathOverrides::setEnvVars(const char* envp[])
61{
62 for (const char** p = envp; *p != NULL; p++) {
63 addEnvVar(*p);
64 }
65}
66
67#else
68PathOverrides::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
78PathOverrides::~PathOverrides()
79{
80 freeArray(_dylibPathOverrides);
81 freeArray(_frameworkPathOverrides);
82 freeArray(_frameworkPathFallbacks);
83 freeArray(_dylibPathFallbacks);
84}
85#endif
86
87
88void 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
100void 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
120void 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
131uint32_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
151void 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
159void 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
192void 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
208const 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
223void 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
234void 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
265void 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
295void 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//
388const 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
422const 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