📄 ltdl.c
字号:
/* ltdl.c -- system independent dlopen wrapper Copyright (C) 1998, 1999, 2000, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. Written by Thomas Tanner, 1998 NOTE: The canonical source of this file is maintained with the GNU Libtool package. Report bugs to bug-libtool@gnu.org.GNU Libltdl is free software; you can redistribute it and/ormodify it under the terms of the GNU Lesser General PublicLicense as published by the Free Software Foundation; eitherversion 2 of the License, or (at your option) any later version.As a special exception to the GNU Lesser General Public License,if you distribute this file as part of a program or library thatis built using GNU Libtool, you may include this file under thesame distribution terms that you use for the rest of that program.GNU Libltdl is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU Lesser General Public License for more details.You should have received a copy of the GNU Lesser General PublicLicense along with GNU Libltdl; see the file COPYING.LIB. If not, acopy can be downloaded from http://www.gnu.org/licenses/lgpl.html,or obtained by writing to the Free Software Foundation, Inc.,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.*/#include "lt__private.h"#include "lt_system.h"#include "lt_dlloader.h"/* --- MANIFEST CONSTANTS --- *//* Standard libltdl search path environment variable name */#undef LTDL_SEARCHPATH_VAR#define LTDL_SEARCHPATH_VAR "LTDL_LIBRARY_PATH"/* Standard libtool archive file extension. */#undef LT_ARCHIVE_EXT#define LT_ARCHIVE_EXT ".la"/* max. filename length */#if !defined(LT_FILENAME_MAX)# define LT_FILENAME_MAX 1024#endif/* This is the maximum symbol size that won't require malloc/free */#undef LT_SYMBOL_LENGTH#define LT_SYMBOL_LENGTH 128/* This accounts for the _LTX_ separator */#undef LT_SYMBOL_OVERHEAD#define LT_SYMBOL_OVERHEAD 5/* Various boolean flags can be stored in the flags field of an lt_dlhandle... */#define LT_DLIS_RESIDENT(handle) (((lt__handle*)handle)->info.is_resident)#define LT_DLIS_SYMGLOBAL(handle) (((lt__handle*)handle)->info.is_symglobal)#define LT_DLIS_SYMLOCAL(handle) (((lt__handle*)handle)->info.is_symlocal)static const char objdir[] = LT_OBJDIR;static const char archive_ext[] = LT_ARCHIVE_EXT;#if defined(LT_MODULE_EXT)static const char shlib_ext[] = LT_MODULE_EXT;#endif#if defined(LT_DLSEARCH_PATH)static const char sys_dlsearch_path[] = LT_DLSEARCH_PATH;#endif/* --- DYNAMIC MODULE LOADING --- *//* The type of a function used at each iteration of foreach_dirinpath(). */typedef int foreach_callback_func (char *filename, void *data1, void *data2);/* foreachfile_callback itself calls a function of this type: */typedef int file_worker_func (const char *filename, void *data);static int foreach_dirinpath (const char *search_path, const char *base_name, foreach_callback_func *func, void *data1, void *data2);static int find_file_callback (char *filename, void *data1, void *data2);static int find_handle_callback (char *filename, void *data, void *ignored);static int foreachfile_callback (char *filename, void *data1, void *data2);static int canonicalize_path (const char *path, char **pcanonical);static int argzize_path (const char *path, char **pargz, size_t *pargz_len);static FILE *find_file (const char *search_path, const char *base_name, char **pdir);static lt_dlhandle *find_handle (const char *search_path, const char *base_name, lt_dlhandle *handle, lt_dladvise advise);static int find_module (lt_dlhandle *handle, const char *dir, const char *libdir, const char *dlname, const char *old_name, int installed, lt_dladvise advise);static int has_library_ext (const char *filename);static int load_deplibs (lt_dlhandle handle, char *deplibs);static int trim (char **dest, const char *str);static int try_dlopen (lt_dlhandle *handle, const char *filename, const char *ext, lt_dladvise advise);static int tryall_dlopen (lt_dlhandle *handle, const char *filename, lt_dladvise padvise, const lt_dlvtable *vtable);static int unload_deplibs (lt_dlhandle handle);static int lt_argz_insert (char **pargz, size_t *pargz_len, char *before, const char *entry);static int lt_argz_insertinorder (char **pargz, size_t *pargz_len, const char *entry);static int lt_argz_insertdir (char **pargz, size_t *pargz_len, const char *dirnam, struct dirent *dp);static int lt_dlpath_insertdir (char **ppath, char *before, const char *dir);static int list_files_by_dir (const char *dirnam, char **pargz, size_t *pargz_len);static int file_not_found (void);#ifdef HAVE_LIBDLLOADERstatic int loader_init_callback (lt_dlhandle handle);#endif /* HAVE_LIBDLLOADER */static int loader_init (lt_get_vtable *vtable_func, lt_user_data data);static char *user_search_path= 0;static lt_dlhandle handles = 0;static int initialized = 0;/* Our memory failure callback sets the error message to be passed back up to the client, so we must be careful to return from mallocation callers if allocation fails (as this callback returns!!). */voidlt__alloc_die_callback (void){ LT__SETERROR (NO_MEMORY);}#ifdef HAVE_LIBDLLOADER/* This function is called to initialise each preloaded module loader, and hook it into the list of loaders to be used when attempting to dlopen an application module. */static intloader_init_callback (lt_dlhandle handle){ lt_get_vtable *vtable_func = (lt_get_vtable *) lt_dlsym (handle, "get_vtable"); return loader_init (vtable_func, 0);}#endif /* HAVE_LIBDLLOADER */static intloader_init (lt_get_vtable *vtable_func, lt_user_data data){ const lt_dlvtable *vtable = 0; int errors = 0; if (vtable_func) { vtable = (*vtable_func) (data); } /* lt_dlloader_add will LT__SETERROR if it fails. */ errors += lt_dlloader_add (vtable); assert (errors || vtable); if ((!errors) && vtable->dlloader_init) { if ((*vtable->dlloader_init) (vtable->dlloader_data)) { LT__SETERROR (INIT_LOADER); ++errors; } } return errors;}/* Bootstrap the loader loading with the preopening loader. */#define get_vtable preopen_LTX_get_vtable#define preloaded_symbols LT_CONC3(lt_, LTDLOPEN, _LTX_preloaded_symbols)LT_BEGIN_C_DECLSLT_SCOPE const lt_dlvtable * get_vtable (lt_user_data data);LT_END_C_DECLS#ifdef HAVE_LIBDLLOADERextern lt_dlsymlist preloaded_symbols;#endif/* Initialize libltdl. */intlt_dlinit (void){ int errors = 0; /* Initialize only at first call. */ if (++initialized == 1) { lt__alloc_die = lt__alloc_die_callback; handles = 0; user_search_path = 0; /* empty search path */ /* First set up the statically loaded preload module loader, so we can use it to preopen the other loaders we linked in at compile time. */ errors += loader_init (get_vtable, 0); /* Now open all the preloaded module loaders, so the application can use _them_ to lt_dlopen its own modules. */#ifdef HAVE_LIBDLLOADER if (!errors) { errors += lt_dlpreload (&preloaded_symbols); } if (!errors) { errors += lt_dlpreload_open (LT_STR(LTDLOPEN), loader_init_callback); }#endif /* HAVE_LIBDLLOADER */ }#ifdef LT_DEBUG_LOADERS lt_dlloader_dump();#endif return errors;}intlt_dlexit (void){ /* shut down libltdl */ lt_dlloader *loader = 0; lt__handle *handle = (lt__handle *) handles; int errors = 0; if (!initialized) { LT__SETERROR (SHUTDOWN); ++errors; goto done; } /* shut down only at last call. */ if (--initialized == 0) { int level; while (handles && LT_DLIS_RESIDENT (handles)) { handles = ((lt__handle *) handles)->next; } /* close all modules */ for (level = 1; handle; ++level) { lt__handle *cur = (lt__handle *) handles; int saw_nonresident = 0; while (cur) { lt__handle *tmp = cur; cur = cur->next; if (!LT_DLIS_RESIDENT (tmp)) { saw_nonresident = 1; if (tmp->info.ref_count <= level) { if (lt_dlclose (tmp)) { ++errors; } /* Make sure that the handle pointed to by 'cur' still exists. lt_dlclose recursively closes dependent libraries which removes them from the linked list. One of these might be the one pointed to by 'cur'. */ if (cur) { for (tmp = (lt__handle *) handles; tmp; tmp = tmp->next) if (tmp == cur) break; if (! tmp) cur = (lt__handle *) handles; } } } } /* done if only resident modules are left */ if (!saw_nonresident) break; } /* close all loaders */ for (loader = (lt_dlloader *) lt_dlloader_next (NULL); loader;) { lt_dlloader *next = (lt_dlloader *) lt_dlloader_next (loader); lt_dlvtable *vtable = (lt_dlvtable *) lt_dlloader_get (loader); if ((vtable = lt_dlloader_remove ((char *) vtable->name))) { FREE (vtable); } else { ++errors; } loader = next; } FREE(user_search_path); } done: return errors;}/* Try VTABLE or, if VTABLE is NULL, all available loaders for FILENAME. If the library is not successfully loaded, return non-zero. Otherwise, the dlhandle is stored at the address given in PHANDLE. */static inttryall_dlopen (lt_dlhandle *phandle, const char *filename, lt_dladvise padvise, const lt_dlvtable *vtable){ lt__handle * handle = (lt__handle *) handles; const char * saved_error = 0; int errors = 0; lt__advise * advise = (lt__advise *) padvise;#ifdef LT_DEBUG_LOADERS fprintf (stderr, "tryall_dlopen (%s, %s)\n", filename ? filename : "(null)", vtable ? vtable->name : "(ALL)");#endif LT__GETERROR (saved_error); /* check whether the module was already opened */ for (;handle; handle = handle->next) { if ((handle->info.filename == filename) /* dlopen self: 0 == 0 */ || (handle->info.filename && filename && streq (handle->info.filename, filename))) { break; } } if (handle) { ++handle->info.ref_count; *phandle = handle; goto done; } handle = (lt__handle *) *phandle; if (filename) { /* Comment out the check of file permissions using access. This call seems to always return -1 with error EACCES. */ /* We need to catch missing file errors early so that file_not_found() can detect what happened. if (access (filename, R_OK) != 0) { LT__SETERROR (FILE_NOT_FOUND); ++errors; goto done; } */ handle->info.filename = lt__strdup (filename); if (!handle->info.filename) { ++errors; goto done; } } else { handle->info.filename = 0; } { lt_dlloader loader = lt_dlloader_next (0); const lt_dlvtable *loader_vtable; do { if (vtable) loader_vtable = vtable; else loader_vtable = lt_dlloader_get (loader);#ifdef LT_DEBUG_LOADERS fprintf (stderr, "Calling %s->module_open (%s)\n", (loader_vtable && loader_vtable->name) ? loader_vtable->name : "(null)", filename ? filename : "(null)");#endif handle->module = (*loader_vtable->module_open) (loader_vtable->dlloader_data, filename, advise);#ifdef LT_DEBUG_LOADERS fprintf (stderr, " Result: %s\n", handle->module ? "Success" : "Failed");#endif if (handle->module != 0) { if (advise) { handle->info.is_resident = advise->is_resident; handle->info.is_symglobal = advise->is_symglobal; handle->info.is_symlocal = advise->is_symlocal; } break; } } while (!vtable && (loader = lt_dlloader_next (loader))); /* If VTABLE was given but couldn't open the module, or VTABLE wasn't given but we exhausted all loaders without opening the module, bail out! */ if ((vtable && !handle->module) || (!vtable && !loader)) { FREE (handle->info.filename); ++errors; goto done; } handle->vtable = loader_vtable; } LT__SETERRORSTR (saved_error); done: return errors;}static inttryall_dlopen_module (lt_dlhandle *handle, const char *prefix, const char *dirname, const char *dlname, lt_dladvise advise){ int error = 0; char *filename = 0; size_t filename_len = 0; size_t dirname_len = LT_STRLEN (dirname); assert (handle); assert (dirname); assert (dlname);#if defined(LT_DIRSEP_CHAR) /* Only canonicalized names (i.e. with DIRSEP chars already converted) should make it into this function: */ assert (strchr (dirname, LT_DIRSEP_CHAR) == 0);#endif if (dirname_len > 0) if (dirname[dirname_len -1] == '/') --dirname_len; filename_len = dirname_len + 1 + LT_STRLEN (dlname); /* Allocate memory, and combine DIRNAME and MODULENAME into it. The PREFIX (if any) is handled below. */ filename = MALLOC (char, dirname_len + 1 + filename_len + 1); if (!filename) return 1; sprintf (filename, "%.*s/%s", (int) dirname_len, dirname, dlname); /* Now that we have combined DIRNAME and MODULENAME, if there is also a PREFIX to contend with, simply recurse with the arguments shuffled. Otherwise, attempt to open FILENAME as a module. */ if (prefix) { error += tryall_dlopen_module (handle, (const char *) 0, prefix, filename, advise); } else if (tryall_dlopen (handle, filename, advise, 0) != 0) { ++error; } FREE (filename); return error;}static intfind_module (lt_dlhandle *handle, const char *dir, const char *libdir, const char *dlname, const char *old_name, int installed, lt_dladvise advise){ /* Try to open the old library first; if it was dlpreopened, we want the preopened version of it, even if a dlopenable module is available. */ if (old_name && tryall_dlopen (handle, old_name, advise, 0) == 0) { return 0; } /* Try to open the dynamic library. */ if (dlname) { /* try to open the installed module */ if (installed && libdir) { if (tryall_dlopen_module (handle, (const char *) 0, libdir, dlname, advise) == 0) return 0; } /* try to open the not-installed module */ if (!installed) { if (tryall_dlopen_module (handle, dir, objdir, dlname, advise) == 0) return 0; } /* maybe it was moved to another directory */ { if (dir && (tryall_dlopen_module (handle, (const char *) 0, dir, dlname, advise) == 0)) return 0; } } return 1;}static intcanonicalize_path (const char *path, char **pcanonical){ char *canonical = 0; assert (path && *path); assert (pcanonical); canonical = MALLOC (char, 1+ LT_STRLEN (path)); if (!canonical) return 1; { size_t dest = 0; size_t src; for (src = 0; path[src] != LT_EOS_CHAR; ++src) { /* Path separators are not copied to the beginning or end of the destination, or if another separator would follow immediately. */ if (path[src] == LT_PATHSEP_CHAR) { if ((dest == 0) || (path[1+ src] == LT_PATHSEP_CHAR) || (path[1+ src] == LT_EOS_CHAR)) continue; } /* Anything other than a directory separator is copied verbatim. */ if ((path[src] != '/')#if defined(LT_DIRSEP_CHAR) && (path[src] != LT_DIRSEP_CHAR)#endif ) { canonical[dest++] = path[src]; } /* Directory separators are converted and copied only if they are not at the end of a path -- i.e. before a path separator or NULL terminator. */ else if ((path[1+ src] != LT_PATHSEP_CHAR) && (path[1+ src] != LT_EOS_CHAR)#if defined(LT_DIRSEP_CHAR) && (path[1+ src] != LT_DIRSEP_CHAR)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -