|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 #include "secport.h" |
|
6 #include "nspr.h" |
|
7 |
|
8 #ifdef XP_UNIX |
|
9 #include <unistd.h> |
|
10 #define BL_MAXSYMLINKS 20 |
|
11 |
|
12 /* |
|
13 * If 'link' is a symbolic link, this function follows the symbolic links |
|
14 * and returns the pathname of the ultimate source of the symbolic links. |
|
15 * If 'link' is not a symbolic link, this function returns NULL. |
|
16 * The caller should call PR_Free to free the string returned by this |
|
17 * function. |
|
18 */ |
|
19 static char* loader_GetOriginalPathname(const char* link) |
|
20 { |
|
21 char* resolved = NULL; |
|
22 char* input = NULL; |
|
23 PRUint32 iterations = 0; |
|
24 PRInt32 len = 0, retlen = 0; |
|
25 if (!link) { |
|
26 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); |
|
27 return NULL; |
|
28 } |
|
29 len = PR_MAX(1024, strlen(link) + 1); |
|
30 resolved = PR_Malloc(len); |
|
31 input = PR_Malloc(len); |
|
32 if (!resolved || !input) { |
|
33 if (resolved) { |
|
34 PR_Free(resolved); |
|
35 } |
|
36 if (input) { |
|
37 PR_Free(input); |
|
38 } |
|
39 return NULL; |
|
40 } |
|
41 strcpy(input, link); |
|
42 while ( (iterations++ < BL_MAXSYMLINKS) && |
|
43 ( (retlen = readlink(input, resolved, len - 1)) > 0) ) { |
|
44 char* tmp = input; |
|
45 resolved[retlen] = '\0'; /* NULL termination */ |
|
46 input = resolved; |
|
47 resolved = tmp; |
|
48 } |
|
49 PR_Free(resolved); |
|
50 if (iterations == 1 && retlen < 0) { |
|
51 PR_Free(input); |
|
52 input = NULL; |
|
53 } |
|
54 return input; |
|
55 } |
|
56 #endif /* XP_UNIX */ |
|
57 |
|
58 /* |
|
59 * Load the library with the file name 'name' residing in the same |
|
60 * directory as the reference library, whose pathname is 'referencePath'. |
|
61 */ |
|
62 static PRLibrary * |
|
63 loader_LoadLibInReferenceDir(const char *referencePath, const char *name) |
|
64 { |
|
65 PRLibrary *dlh = NULL; |
|
66 char *fullName = NULL; |
|
67 char* c; |
|
68 PRLibSpec libSpec; |
|
69 |
|
70 /* Remove the trailing filename from referencePath and add the new one */ |
|
71 c = strrchr(referencePath, PR_GetDirectorySeparator()); |
|
72 if (c) { |
|
73 size_t referencePathSize = 1 + c - referencePath; |
|
74 fullName = (char*) PORT_Alloc(strlen(name) + referencePathSize + 1); |
|
75 if (fullName) { |
|
76 memcpy(fullName, referencePath, referencePathSize); |
|
77 strcpy(fullName + referencePathSize, name); |
|
78 #ifdef DEBUG_LOADER |
|
79 PR_fprintf(PR_STDOUT, "\nAttempting to load fully-qualified %s\n", |
|
80 fullName); |
|
81 #endif |
|
82 libSpec.type = PR_LibSpec_Pathname; |
|
83 libSpec.value.pathname = fullName; |
|
84 dlh = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL |
|
85 #ifdef PR_LD_ALT_SEARCH_PATH |
|
86 /* allow library's dependencies to be found in the same directory |
|
87 * on Windows even if PATH is not set. Requires NSPR 4.8.1 . */ |
|
88 | PR_LD_ALT_SEARCH_PATH |
|
89 #endif |
|
90 ); |
|
91 PORT_Free(fullName); |
|
92 } |
|
93 } |
|
94 return dlh; |
|
95 } |
|
96 |
|
97 /* |
|
98 * Load a shared library called "newShLibName" in the same directory as |
|
99 * a shared library that is already loaded, called existingShLibName. |
|
100 * A pointer to a static function in that shared library, |
|
101 * staticShLibFunc, is required. |
|
102 * |
|
103 * existingShLibName: |
|
104 * The file name of the shared library that shall be used as the |
|
105 * "reference library". The loader will attempt to load the requested |
|
106 * library from the same directory as the reference library. |
|
107 * |
|
108 * staticShLibFunc: |
|
109 * Pointer to a static function in the "reference library". |
|
110 * |
|
111 * newShLibName: |
|
112 * The simple file name of the new shared library to be loaded. |
|
113 * |
|
114 * We use PR_GetLibraryFilePathname to get the pathname of the loaded |
|
115 * shared lib that contains this function, and then do a |
|
116 * PR_LoadLibraryWithFlags with an absolute pathname for the shared |
|
117 * library to be loaded. |
|
118 * |
|
119 * On Windows, the "alternate search path" strategy is employed, if available. |
|
120 * On Unix, if existingShLibName is a symbolic link, and no link exists for the |
|
121 * new library, the original link will be resolved, and the new library loaded |
|
122 * from the resolved location. |
|
123 * |
|
124 * If the new shared library is not found in the same location as the reference |
|
125 * library, it will then be loaded from the normal system library path. |
|
126 * |
|
127 */ |
|
128 |
|
129 PRLibrary * |
|
130 PORT_LoadLibraryFromOrigin(const char* existingShLibName, |
|
131 PRFuncPtr staticShLibFunc, |
|
132 const char *newShLibName) |
|
133 { |
|
134 PRLibrary *lib = NULL; |
|
135 char* fullPath = NULL; |
|
136 PRLibSpec libSpec; |
|
137 |
|
138 /* Get the pathname for existingShLibName, e.g. /usr/lib/libnss3.so |
|
139 * PR_GetLibraryFilePathname works with either the base library name or a |
|
140 * function pointer, depending on the platform. |
|
141 * We require the address of a function in the "reference library", |
|
142 * provided by the caller. To avoid getting the address of the stub/thunk |
|
143 * of an exported function by accident, use the address of a static |
|
144 * function rather than an exported function. |
|
145 */ |
|
146 fullPath = PR_GetLibraryFilePathname(existingShLibName, |
|
147 staticShLibFunc); |
|
148 |
|
149 if (fullPath) { |
|
150 lib = loader_LoadLibInReferenceDir(fullPath, newShLibName); |
|
151 #ifdef XP_UNIX |
|
152 if (!lib) { |
|
153 /* |
|
154 * If fullPath is a symbolic link, resolve the symbolic |
|
155 * link and try again. |
|
156 */ |
|
157 char* originalfullPath = loader_GetOriginalPathname(fullPath); |
|
158 if (originalfullPath) { |
|
159 PR_Free(fullPath); |
|
160 fullPath = originalfullPath; |
|
161 lib = loader_LoadLibInReferenceDir(fullPath, newShLibName); |
|
162 } |
|
163 } |
|
164 #endif |
|
165 PR_Free(fullPath); |
|
166 } |
|
167 if (!lib) { |
|
168 #ifdef DEBUG_LOADER |
|
169 PR_fprintf(PR_STDOUT, "\nAttempting to load %s\n", newShLibName); |
|
170 #endif |
|
171 libSpec.type = PR_LibSpec_Pathname; |
|
172 libSpec.value.pathname = newShLibName; |
|
173 lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL); |
|
174 } |
|
175 if (NULL == lib) { |
|
176 #ifdef DEBUG_LOADER |
|
177 PR_fprintf(PR_STDOUT, "\nLoading failed : %s.\n", newShLibName); |
|
178 #endif |
|
179 } |
|
180 return lib; |
|
181 } |
|
182 |