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