|
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 /* |
|
6 * This file is meant to be included by other .c files. |
|
7 * This file takes a "parameter", the scope which includes this |
|
8 * code shall declare this variable: |
|
9 * const char *NameOfThisSharedLib; |
|
10 * |
|
11 * NameOfThisSharedLib: |
|
12 * The file name of the shared library that shall be used as the |
|
13 * "reference library". The loader will attempt to load the requested |
|
14 * library from the same directory as the reference library. |
|
15 */ |
|
16 |
|
17 #ifdef XP_UNIX |
|
18 #include <unistd.h> |
|
19 #define BL_MAXSYMLINKS 20 |
|
20 |
|
21 /* |
|
22 * If 'link' is a symbolic link, this function follows the symbolic links |
|
23 * and returns the pathname of the ultimate source of the symbolic links. |
|
24 * If 'link' is not a symbolic link, this function returns NULL. |
|
25 * The caller should call PR_Free to free the string returned by this |
|
26 * function. |
|
27 */ |
|
28 static char* loader_GetOriginalPathname(const char* link) |
|
29 { |
|
30 #ifdef __GLIBC__ |
|
31 char* tmp = realpath(link, NULL); |
|
32 char* resolved; |
|
33 if (! tmp) |
|
34 return NULL; |
|
35 resolved = PR_Malloc(strlen(tmp) + 1); |
|
36 strcpy(resolved, tmp); /* This is necessary because PR_Free might not be using free() */ |
|
37 free(tmp); |
|
38 return resolved; |
|
39 #else |
|
40 char* resolved = NULL; |
|
41 char* input = NULL; |
|
42 PRUint32 iterations = 0; |
|
43 PRInt32 len = 0, retlen = 0; |
|
44 if (!link) { |
|
45 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); |
|
46 return NULL; |
|
47 } |
|
48 len = PR_MAX(1024, strlen(link) + 1); |
|
49 resolved = PR_Malloc(len); |
|
50 input = PR_Malloc(len); |
|
51 if (!resolved || !input) { |
|
52 if (resolved) { |
|
53 PR_Free(resolved); |
|
54 } |
|
55 if (input) { |
|
56 PR_Free(input); |
|
57 } |
|
58 return NULL; |
|
59 } |
|
60 strcpy(input, link); |
|
61 while ( (iterations++ < BL_MAXSYMLINKS) && |
|
62 ( (retlen = readlink(input, resolved, len - 1)) > 0) ) { |
|
63 char* tmp = input; |
|
64 resolved[retlen] = '\0'; /* NULL termination */ |
|
65 input = resolved; |
|
66 resolved = tmp; |
|
67 } |
|
68 PR_Free(resolved); |
|
69 if (iterations == 1 && retlen < 0) { |
|
70 PR_Free(input); |
|
71 input = NULL; |
|
72 } |
|
73 return input; |
|
74 #endif |
|
75 } |
|
76 #endif /* XP_UNIX */ |
|
77 |
|
78 /* |
|
79 * Load the library with the file name 'name' residing in the same |
|
80 * directory as the reference library, whose pathname is 'referencePath'. |
|
81 */ |
|
82 static PRLibrary * |
|
83 loader_LoadLibInReferenceDir(const char *referencePath, const char *name) |
|
84 { |
|
85 PRLibrary *dlh = NULL; |
|
86 char *fullName = NULL; |
|
87 char* c; |
|
88 PRLibSpec libSpec; |
|
89 |
|
90 /* Remove the trailing filename from referencePath and add the new one */ |
|
91 c = strrchr(referencePath, PR_GetDirectorySeparator()); |
|
92 if (c) { |
|
93 size_t referencePathSize = 1 + c - referencePath; |
|
94 fullName = (char*) PORT_Alloc(strlen(name) + referencePathSize + 1); |
|
95 if (fullName) { |
|
96 memcpy(fullName, referencePath, referencePathSize); |
|
97 strcpy(fullName + referencePathSize, name); |
|
98 #ifdef DEBUG_LOADER |
|
99 PR_fprintf(PR_STDOUT, "\nAttempting to load fully-qualified %s\n", |
|
100 fullName); |
|
101 #endif |
|
102 libSpec.type = PR_LibSpec_Pathname; |
|
103 libSpec.value.pathname = fullName; |
|
104 dlh = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL); |
|
105 PORT_Free(fullName); |
|
106 } |
|
107 } |
|
108 return dlh; |
|
109 } |
|
110 |
|
111 /* |
|
112 * We use PR_GetLibraryFilePathname to get the pathname of the loaded |
|
113 * shared lib that contains this function, and then do a PR_LoadLibrary |
|
114 * with an absolute pathname for the softoken shared library. |
|
115 */ |
|
116 |
|
117 static PRLibrary * |
|
118 loader_LoadLibrary(const char *nameToLoad) |
|
119 { |
|
120 PRLibrary *lib = NULL; |
|
121 char* fullPath = NULL; |
|
122 PRLibSpec libSpec; |
|
123 |
|
124 /* Get the pathname for nameOfAlreadyLoadedLib, i.e. /usr/lib/libnss3.so |
|
125 * PR_GetLibraryFilePathname works with either the base library name or a |
|
126 * function pointer, depending on the platform. We can't query an exported |
|
127 * symbol such as NSC_GetFunctionList, because on some platforms we can't |
|
128 * find symbols in loaded implicit dependencies. |
|
129 * But we can just get the address of this function ! |
|
130 */ |
|
131 fullPath = PR_GetLibraryFilePathname(NameOfThisSharedLib, |
|
132 (PRFuncPtr)&loader_LoadLibrary); |
|
133 |
|
134 if (fullPath) { |
|
135 lib = loader_LoadLibInReferenceDir(fullPath, nameToLoad); |
|
136 #ifdef XP_UNIX |
|
137 if (!lib) { |
|
138 /* |
|
139 * If fullPath is a symbolic link, resolve the symbolic |
|
140 * link and try again. |
|
141 */ |
|
142 char* originalfullPath = loader_GetOriginalPathname(fullPath); |
|
143 if (originalfullPath) { |
|
144 PR_Free(fullPath); |
|
145 fullPath = originalfullPath; |
|
146 lib = loader_LoadLibInReferenceDir(fullPath, nameToLoad); |
|
147 } |
|
148 } |
|
149 #endif |
|
150 PR_Free(fullPath); |
|
151 } |
|
152 if (!lib) { |
|
153 #ifdef DEBUG_LOADER |
|
154 PR_fprintf(PR_STDOUT, "\nAttempting to load %s\n", nameToLoad); |
|
155 #endif |
|
156 libSpec.type = PR_LibSpec_Pathname; |
|
157 libSpec.value.pathname = nameToLoad; |
|
158 lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL); |
|
159 } |
|
160 if (NULL == lib) { |
|
161 #ifdef DEBUG_LOADER |
|
162 PR_fprintf(PR_STDOUT, "\nLoading failed : %s.\n", nameToLoad); |
|
163 #endif |
|
164 } |
|
165 return lib; |
|
166 } |
|
167 |