Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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/. */
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 */
17 #ifdef XP_UNIX
18 #include <unistd.h>
19 #define BL_MAXSYMLINKS 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 */
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;
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 }
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 */
117 static PRLibrary *
118 loader_LoadLibrary(const char *nameToLoad)
119 {
120 PRLibrary *lib = NULL;
121 char* fullPath = NULL;
122 PRLibSpec libSpec;
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);
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 }