michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: * This file is meant to be included by other .c files. michael@0: * This file takes a "parameter", the scope which includes this michael@0: * code shall declare this variable: michael@0: * const char *NameOfThisSharedLib; michael@0: * michael@0: * NameOfThisSharedLib: michael@0: * The file name of the shared library that shall be used as the michael@0: * "reference library". The loader will attempt to load the requested michael@0: * library from the same directory as the reference library. michael@0: */ michael@0: michael@0: #ifdef XP_UNIX michael@0: #include michael@0: #define BL_MAXSYMLINKS 20 michael@0: michael@0: /* michael@0: * If 'link' is a symbolic link, this function follows the symbolic links michael@0: * and returns the pathname of the ultimate source of the symbolic links. michael@0: * If 'link' is not a symbolic link, this function returns NULL. michael@0: * The caller should call PR_Free to free the string returned by this michael@0: * function. michael@0: */ michael@0: static char* loader_GetOriginalPathname(const char* link) michael@0: { michael@0: #ifdef __GLIBC__ michael@0: char* tmp = realpath(link, NULL); michael@0: char* resolved; michael@0: if (! tmp) michael@0: return NULL; michael@0: resolved = PR_Malloc(strlen(tmp) + 1); michael@0: strcpy(resolved, tmp); /* This is necessary because PR_Free might not be using free() */ michael@0: free(tmp); michael@0: return resolved; michael@0: #else michael@0: char* resolved = NULL; michael@0: char* input = NULL; michael@0: PRUint32 iterations = 0; michael@0: PRInt32 len = 0, retlen = 0; michael@0: if (!link) { michael@0: PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); michael@0: return NULL; michael@0: } michael@0: len = PR_MAX(1024, strlen(link) + 1); michael@0: resolved = PR_Malloc(len); michael@0: input = PR_Malloc(len); michael@0: if (!resolved || !input) { michael@0: if (resolved) { michael@0: PR_Free(resolved); michael@0: } michael@0: if (input) { michael@0: PR_Free(input); michael@0: } michael@0: return NULL; michael@0: } michael@0: strcpy(input, link); michael@0: while ( (iterations++ < BL_MAXSYMLINKS) && michael@0: ( (retlen = readlink(input, resolved, len - 1)) > 0) ) { michael@0: char* tmp = input; michael@0: resolved[retlen] = '\0'; /* NULL termination */ michael@0: input = resolved; michael@0: resolved = tmp; michael@0: } michael@0: PR_Free(resolved); michael@0: if (iterations == 1 && retlen < 0) { michael@0: PR_Free(input); michael@0: input = NULL; michael@0: } michael@0: return input; michael@0: #endif michael@0: } michael@0: #endif /* XP_UNIX */ michael@0: michael@0: /* michael@0: * Load the library with the file name 'name' residing in the same michael@0: * directory as the reference library, whose pathname is 'referencePath'. michael@0: */ michael@0: static PRLibrary * michael@0: loader_LoadLibInReferenceDir(const char *referencePath, const char *name) michael@0: { michael@0: PRLibrary *dlh = NULL; michael@0: char *fullName = NULL; michael@0: char* c; michael@0: PRLibSpec libSpec; michael@0: michael@0: /* Remove the trailing filename from referencePath and add the new one */ michael@0: c = strrchr(referencePath, PR_GetDirectorySeparator()); michael@0: if (c) { michael@0: size_t referencePathSize = 1 + c - referencePath; michael@0: fullName = (char*) PORT_Alloc(strlen(name) + referencePathSize + 1); michael@0: if (fullName) { michael@0: memcpy(fullName, referencePath, referencePathSize); michael@0: strcpy(fullName + referencePathSize, name); michael@0: #ifdef DEBUG_LOADER michael@0: PR_fprintf(PR_STDOUT, "\nAttempting to load fully-qualified %s\n", michael@0: fullName); michael@0: #endif michael@0: libSpec.type = PR_LibSpec_Pathname; michael@0: libSpec.value.pathname = fullName; michael@0: dlh = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL); michael@0: PORT_Free(fullName); michael@0: } michael@0: } michael@0: return dlh; michael@0: } michael@0: michael@0: /* michael@0: * We use PR_GetLibraryFilePathname to get the pathname of the loaded michael@0: * shared lib that contains this function, and then do a PR_LoadLibrary michael@0: * with an absolute pathname for the softoken shared library. michael@0: */ michael@0: michael@0: static PRLibrary * michael@0: loader_LoadLibrary(const char *nameToLoad) michael@0: { michael@0: PRLibrary *lib = NULL; michael@0: char* fullPath = NULL; michael@0: PRLibSpec libSpec; michael@0: michael@0: /* Get the pathname for nameOfAlreadyLoadedLib, i.e. /usr/lib/libnss3.so michael@0: * PR_GetLibraryFilePathname works with either the base library name or a michael@0: * function pointer, depending on the platform. We can't query an exported michael@0: * symbol such as NSC_GetFunctionList, because on some platforms we can't michael@0: * find symbols in loaded implicit dependencies. michael@0: * But we can just get the address of this function ! michael@0: */ michael@0: fullPath = PR_GetLibraryFilePathname(NameOfThisSharedLib, michael@0: (PRFuncPtr)&loader_LoadLibrary); michael@0: michael@0: if (fullPath) { michael@0: lib = loader_LoadLibInReferenceDir(fullPath, nameToLoad); michael@0: #ifdef XP_UNIX michael@0: if (!lib) { michael@0: /* michael@0: * If fullPath is a symbolic link, resolve the symbolic michael@0: * link and try again. michael@0: */ michael@0: char* originalfullPath = loader_GetOriginalPathname(fullPath); michael@0: if (originalfullPath) { michael@0: PR_Free(fullPath); michael@0: fullPath = originalfullPath; michael@0: lib = loader_LoadLibInReferenceDir(fullPath, nameToLoad); michael@0: } michael@0: } michael@0: #endif michael@0: PR_Free(fullPath); michael@0: } michael@0: if (!lib) { michael@0: #ifdef DEBUG_LOADER michael@0: PR_fprintf(PR_STDOUT, "\nAttempting to load %s\n", nameToLoad); michael@0: #endif michael@0: libSpec.type = PR_LibSpec_Pathname; michael@0: libSpec.value.pathname = nameToLoad; michael@0: lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL); michael@0: } michael@0: if (NULL == lib) { michael@0: #ifdef DEBUG_LOADER michael@0: PR_fprintf(PR_STDOUT, "\nLoading failed : %s.\n", nameToLoad); michael@0: #endif michael@0: } michael@0: return lib; michael@0: } michael@0: