/* ltdl.c -- system independent dlopen wrapper Copyright (C) 1998-1999 Free Software Foundation, Inc. Originally by Thomas Tanner <tanner@gmx.de> This file is part of GNU Libtool. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #define _LTDL_COMPILE_ #if HAVE_CONFIG_H #include <config.h> #endif #if HAVE_STRING_H #include <string.h> #endif #if HAVE_STRINGS_H #include <strings.h> #endif #if HAVE_CTYPE_H #include <ctype.h> #endif #if HAVE_MALLOC_H #include <malloc.h> #endif #if HAVE_MEMORY_H #include <memory.h> #endif #if HAVE_STDLIB_H #include <stdlib.h> #endif #if HAVE_STDIO_H #include <stdio.h> #endif #include "ltdl.h" /* max. filename length */ #ifndef LTDL_FILENAME_MAX #define LTDL_FILENAME_MAX 1024 #endif #undef LTDL_READTEXT_MODE /* fopen() mode flags for reading a text file */ #ifdef _WIN32 #define LTDL_READTEXT_MODE "rt" #else #define LTDL_READTEXT_MODE "r" #endif #undef LTDL_SYMBOL_LENGTH /* This is the maximum symbol size that won't require malloc/free */ #define LTDL_SYMBOL_LENGTH 128 #undef LTDL_SYMBOL_OVERHEAD /* This accounts for the _LTX_ separator */ #define LTDL_SYMBOL_OVERHEAD 5 static const char objdir[] = LTDL_OBJDIR; static const char shlib_ext[] = LTDL_SHLIB_EXT; static const char unknown_error[] = "unknown error"; static const char dlopen_not_supported_error[] = "dlopen support not available"; static const char file_not_found_error[] = "file not found"; static const char no_symbols_error[] = "no symbols defined"; static const char symbol_error[] = "symbol not found"; static const char memory_error[] = "not enough memory"; static const char invalid_handle_error[] = "invalid handle"; static const char buffer_overflow_error[] = "internal buffer overflow"; static const char shutdown_error[] = "library already shutdown"; #ifndef HAVE_PRELOADED_SYMBOLS /* If libtool won't define it, we'd better do */ const lt_dlsymlist lt_preloaded_symbols[1] = { { 0, 0 } }; #endif static const char *last_error = 0; lt_ptr_t (*lt_dlmalloc) __P((size_t size)) = malloc; void (*lt_dlfree) __P((lt_ptr_t ptr)) = free; typedef struct lt_dltype_t { struct lt_dltype_t *next; const char *sym_prefix; /* prefix for symbols */ int (*mod_init) __P((void)); int (*mod_exit) __P((void)); int (*lib_open) __P((lt_dlhandle handle, const char *filename)); int (*lib_close) __P((lt_dlhandle handle)); lt_ptr_t (*find_sym) __P((lt_dlhandle handle, const char *symbol)); } lt_dltype_t; #define LTDL_TYPE_TOP 0 typedef struct lt_dlhandle_t { struct lt_dlhandle_t *next; lt_dltype_t *type; /* dlopening interface */ char *filename; /* file name */ char *name; /* module name */ int usage; /* usage */ int depcount; /* number of dependencies */ lt_dlhandle *deplibs; /* dependencies */ lt_ptr_t handle; /* system handle */ lt_ptr_t system; /* system specific data */ } lt_dlhandle_t; #undef strdup #define strdup xstrdup static inline char * strdup(str) const char *str; { char *tmp; if (!str) return 0; tmp = (char*) lt_dlmalloc(strlen(str)+1); if (tmp) strcpy(tmp, str); return tmp; } #if ! HAVE_STRCHR # if HAVE_INDEX # define strchr index # else # define strchr xstrchr static inline const char* strchr(str, ch) const char *str; int ch; { const char *p; for (p = str; *p != (char)ch && p != '\0'; p++) /*NOWORK*/; return (*p == (char)ch) ? p : 0; } # endif #endif #if ! HAVE_STRRCHR # if HAVE_RINDEX # define strrchr rindex # else # define strrchr xstrrchr static inline const char* strrchr(str, ch) const char *str; int ch; { const char *p; for (p = str; p != '\0'; p++) /*NOWORK*/; while (*p != (char)ch && p >= str) p--; return (*p == (char)ch) ? p : 0; } # endif #endif #if HAVE_LIBDL /* dynamic linking with dlopen/dlsym */ #if HAVE_DLFCN_H # include <dlfcn.h> #endif #if ! HAVE_DLERROR /* not all platforms have dlerror() */ #define dlerror() unknown_error #endif #ifdef RTLD_GLOBAL # define LTDL_GLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LTDL_GLOBAL DL_GLOBAL # else # define LTDL_GLOBAL 0 # endif #endif /* We may have to define LTDL_LAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LTDL_LAZY_OR_NOW # ifdef RTLD_LAZY # define LTDL_LAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LTDL_LAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LTDL_LAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LTDL_LAZY_OR_NOW DL_NOW # else # define LTDL_LAZY_OR_NOW 0 # endif # endif # endif # endif #endif static int dl_init () { return 0; } static int dl_exit () { return 0; } static int dl_open (handle, filename) lt_dlhandle handle; const char *filename; { handle->handle = dlopen(filename, LTDL_GLOBAL | LTDL_LAZY_OR_NOW); if (!handle->handle) { last_error = dlerror(); return 1; } return 0; } static int dl_close (handle) lt_dlhandle handle; { if (dlclose(handle->handle) != 0) { last_error = dlerror(); return 1; } return 0; } static lt_ptr_t dl_sym (handle, symbol) lt_dlhandle handle; const char *symbol; { lt_ptr_t address = dlsym(handle->handle, symbol); if (!address) last_error = dlerror(); return address; } static lt_dltype_t #ifdef NEED_USCORE dl = { LTDL_TYPE_TOP, "_", dl_init, dl_exit, dl_open, dl_close, dl_sym }; #else dl = { LTDL_TYPE_TOP, 0, dl_init, dl_exit, dl_open, dl_close, dl_sym }; #endif #undef LTDL_TYPE_TOP #define LTDL_TYPE_TOP &dl #endif #if HAVE_SHL_LOAD /* dynamic linking with shl_load (HP-UX) (comments from gmodule) */ #ifdef HAVE_DL_H #include <dl.h> #endif /* some flags are missing on some systems, so we provide * harmless defaults. * * Mandatory: * BIND_IMMEDIATE - Resolve symbol references when the library is loaded. * BIND_DEFERRED - Delay code symbol resolution until actual reference. * * Optionally: * BIND_FIRST - Place the library at the head of the symbol search order. * BIND_NONFATAL - The default BIND_IMMEDIATE behavior is to treat all unsatisfied * symbols as fatal. This flag allows binding of unsatisfied code * symbols to be deferred until use. * [Perl: For certain libraries, like DCE, deferred binding often * causes run time problems. Adding BIND_NONFATAL to BIND_IMMEDIATE * still allows unresolved references in situations like this.] * BIND_NOSTART - Do not call the initializer for the shared library when the * library is loaded, nor on a future call to shl_unload(). * BIND_VERBOSE - Print verbose messages concerning possible unsatisfied symbols. * * hp9000s700/hp9000s800: * BIND_RESTRICTED - Restrict symbols visible by the library to those present at * library load time. * DYNAMIC_PATH - Allow the loader to dynamically search for the library specified * by the path argument. */ #ifndef DYNAMIC_PATH #define DYNAMIC_PATH 0 #endif /* DYNAMIC_PATH */ #ifndef BIND_RESTRICTED #define BIND_RESTRICTED 0 #endif /* BIND_RESTRICTED */ #define LTDL_BIND_FLAGS (BIND_IMMEDIATE | BIND_NONFATAL | BIND_VERBOSE | DYNAMIC_PATH) static int shl_init () { return 0; } static int shl_exit () { return 0; } static int shl_open (handle, filename) lt_dlhandle handle; const char *filename; { handle->handle = shl_load(filename, LTDL_BIND_FLAGS, 0L); if (!handle->handle) { last_error = unknown_error; return 1; } return 0; } static int shl_close (handle) lt_dlhandle handle; { if (shl_unload((shl_t) (handle->handle)) != 0) { last_error = unknown_error; return 1; } return 0; } static lt_ptr_t shl_sym (handle, symbol) lt_dlhandle handle; const char *symbol; { lt_ptr_t address; if (shl_findsym((shl_t) (handle->handle), symbol, TYPE_UNDEFINED, &address) != 0 || !(handle->handle) || !address) { last_error = unknown_error; return 0; } return address; } static lt_dltype_t shl = { LTDL_TYPE_TOP, 0, shl_init, shl_exit, shl_open, shl_close, shl_sym }; #undef LTDL_TYPE_TOP #define LTDL_TYPE_TOP &shl #endif #if HAVE_DLD /* dynamic linking with dld */ #if HAVE_DLD_H #include <dld.h> #endif static int dld_init () { return 0; } static int dld_exit () { return 0; } static int dld_open (handle, filename) lt_dlhandle handle; const char *filename; { handle->handle = strdup(filename); if (!handle->handle) { last_error = memory_error; return 1; } if (dld_link(filename) != 0) { last_error = unknown_error; lt_dlfree(handle->handle); return 1; } return 0; } static int dld_close (handle) lt_dlhandle handle; { if (dld_unlink_by_file((char*)(handle->handle), 1) != 0) { last_error = unknown_error; return 1; } lt_dlfree(handle->filename); return 0; } static lt_ptr_t dld_sym (handle, symbol) lt_dlhandle handle; const char *symbol; { lt_ptr_t address = dld_get_func(symbol); if (!address) last_error = unknown_error; return address; } static lt_dltype_t dld = { LTDL_TYPE_TOP, 0, dld_init, dld_exit, dld_open, dld_close, dld_sym }; #undef LTDL_TYPE_TOP #define LTDL_TYPE_TOP &dld #endif #ifdef _WIN32 /* dynamic linking for Win32 */ #include <windows.h> static int wll_init () { return 0; } static int wll_exit () { return 0; } static int wll_open (handle, filename) lt_dlhandle handle; const char *filename; { handle->handle = LoadLibrary(filename); if (!handle->handle) { last_error = unknown_error; return 1; } return 0; } static int wll_close (handle) lt_dlhandle handle; { if (FreeLibrary(handle->handle) != 0) { last_error = unknown_error; return 1; } return 0; } static lt_ptr_t wll_sym (handle, symbol) lt_dlhandle handle; const char *symbol; { lt_ptr_t address = GetProcAddress(handle->handle, symbol); if (!address) last_error = unknown_error; return address; } static lt_dltype_t wll = { LTDL_TYPE_TOP, 0, wll_init, wll_exit, wll_open, wll_close, wll_sym }; #undef LTDL_TYPE_TOP #define LTDL_TYPE_TOP &wll #endif /* emulate dynamic linking using preloaded_symbols */ typedef struct lt_dlsymlists_t { struct lt_dlsymlists_t *next; const lt_dlsymlist *syms; } lt_dlsymlists_t; static const lt_dlsymlist *default_preloaded_symbols = 0; static lt_dlsymlists_t *preloaded_symbols = 0; static int presym_init () { preloaded_symbols = 0; if (default_preloaded_symbols) return lt_dlpreload(default_preloaded_symbols); return 0; } static int presym_free_symlists () { lt_dlsymlists_t *lists = preloaded_symbols; while (lists) { lt_dlsymlists_t *tmp = lists; lists = lists->next; lt_dlfree(tmp); } preloaded_symbols = 0; return 0; } static int presym_exit () { presym_free_symlists(); return 0; } static int presym_add_symlist (preloaded) const lt_dlsymlist *preloaded; { lt_dlsymlists_t *tmp; lt_dlsymlists_t *lists = preloaded_symbols; while (lists) { if (lists->syms == preloaded) return 0; lists = lists->next; } tmp = (lt_dlsymlists_t*) lt_dlmalloc(sizeof(lt_dlsymlists_t)); if (!tmp) { last_error = memory_error; return 1; } tmp->syms = preloaded; tmp->next = 0; if (!preloaded_symbols) preloaded_symbols = tmp; else { /* append to the end */ lists = preloaded_symbols; while (lists->next) lists = lists->next; lists->next = tmp; } return 0; } static int presym_open (handle, filename) lt_dlhandle handle; const char *filename; { lt_dlsymlists_t *lists = preloaded_symbols; if (!lists) { last_error = no_symbols_error; return 1; } if (!filename) filename = "@PROGRAM@"; while (lists) { const lt_dlsymlist *syms = lists->syms; while (syms->name) { if (!syms->address && strcmp(syms->name, filename) == 0) { handle->handle = (lt_ptr_t) syms; return 0; } syms++; } lists = lists->next; } last_error = file_not_found_error; return 1; } static int presym_close (handle) lt_dlhandle handle; { return 0; } static lt_ptr_t presym_sym (handle, symbol) lt_dlhandle handle; const char *symbol; { lt_dlsymlist *syms = (lt_dlsymlist*)(handle->handle); syms++; while (syms->address) { if (strcmp(syms->name, symbol) == 0) return syms->address; syms++; } last_error = symbol_error; return 0; } static lt_dltype_t presym = { LTDL_TYPE_TOP, 0, presym_init, presym_exit, presym_open, presym_close, presym_sym }; #undef LTDL_TYPE_TOP #define LTDL_TYPE_TOP &presym static char *user_search_path = 0; static lt_dlhandle handles = 0; static int initialized = 0; static lt_dltype_t *types = LTDL_TYPE_TOP; #undef LTDL_TYPE_TOP int lt_dlinit () { /* initialize libltdl */ lt_dltype_t **type = &types; int typecount = 0; if (initialized) { /* Initialize only at first call. */ initialized++; return 0; } handles = 0; user_search_path = 0; /* empty search path */ while (*type) { if ((*type)->mod_init()) *type = (*type)->next; /* Remove it from the list */ else { type = &(*type)->next; /* Keep it */ typecount++; } } if (typecount == 0) { last_error = dlopen_not_supported_error; return 1; } last_error = 0; initialized = 1; return 0; } int lt_dlpreload (preloaded) const lt_dlsymlist *preloaded; { if (preloaded) return presym_add_symlist(preloaded); presym_free_symlists(); if (default_preloaded_symbols) return lt_dlpreload(default_preloaded_symbols); return 0; } int lt_dlpreload_default (preloaded) const lt_dlsymlist *preloaded; { default_preloaded_symbols = preloaded; return 0; } int lt_dlexit () { /* shut down libltdl */ lt_dltype_t *type = types; int errors; if (!initialized) { last_error = shutdown_error; return 1; } if (initialized != 1) { /* shut down only at last call. */ initialized--; return 0; } /* close all modules */ errors = 0; while (handles) { /* FIXME: what if a module depends on another one? */ if (lt_dlclose(handles)) errors++; } initialized = 0; while (type) { if (type->mod_exit()) errors++; type = type->next; } return errors; } static int tryall_dlopen (handle, filename) lt_dlhandle *handle; const char *filename; { lt_dlhandle cur; lt_dltype_t *type = types; const char *saved_error = last_error; /* check whether the module was already opened */ cur = handles; while (cur) { if (!cur->filename && !filename) break; if (cur->filename && filename && strcmp(cur->filename, filename) == 0) break; cur = cur->next; } if (cur) { cur->usage++; *handle = cur; return 0; } cur = *handle; if (filename) { cur->filename = strdup(filename); if (!cur->filename) { last_error = memory_error; return 1; } } else cur->filename = 0; while (type) { if (type->lib_open(cur, filename) == 0) break; type = type->next; } if (!type) { if (cur->filename) lt_dlfree(cur->filename); return 1; } cur->type = type; last_error = saved_error; return 0; } static int find_module (handle, dir, libdir, dlname, old_name, installed) lt_dlhandle *handle; const char *dir; const char *libdir; const char *dlname; const char *old_name; int installed; { int error; char *filename; /* 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) == 0) return 0; /* try to open the dynamic library */ if (dlname) { /* try to open the installed module */ if (installed && libdir) { filename = (char*) lt_dlmalloc(strlen(libdir)+1+strlen(dlname)+1); if (!filename) { last_error = memory_error; return 1; } strcpy(filename, libdir); strcat(filename, "/"); strcat(filename, dlname); error = tryall_dlopen(handle, filename) == 0; lt_dlfree(filename); if (error) return 0; } /* try to open the not-installed module */ if (!installed) { filename = (char*) lt_dlmalloc((dir ? strlen(dir) : 0) + strlen(objdir) + strlen(dlname) + 1); if (!filename) { last_error = memory_error; return 1; } if (dir) strcpy(filename, dir); else *filename = 0; strcat(filename, objdir); strcat(filename, dlname); error = tryall_dlopen(handle, filename) == 0; lt_dlfree(filename); if (error) return 0; } /* hmm, maybe it was moved to another directory */ { filename = (char*) lt_dlmalloc((dir ? strlen(dir) : 0) + strlen(dlname) + 1); if (dir) strcpy(filename, dir); else *filename = 0; strcat(filename, dlname); error = tryall_dlopen(handle, filename) == 0; lt_dlfree(filename); if (error) return 0; } } last_error = file_not_found_error; return 1; } static lt_ptr_t find_file (basename, search_path, pdir, handle) const char *basename; const char *search_path; char **pdir; lt_dlhandle *handle; { /* when handle != NULL search a library, otherwise a file */ /* return NULL on failure, otherwise the file/handle */ char *filename = 0; int filenamesize = 0; const char *next = search_path; int lenbase = strlen(basename); if (!next || !*next) { last_error = file_not_found_error; return 0; } while (next) { int lendir; const char *cur = next; next = strchr(cur, ':'); if (!next) next = cur + strlen(cur); lendir = next - cur; if (*next == ':') ++next; else next = 0; if (lendir == 0) continue; if (lendir + 1 + lenbase >= filenamesize) { if (filename) lt_dlfree(filename); filenamesize = lendir + 1 + lenbase + 1; filename = (char*) lt_dlmalloc(filenamesize); if (!filename) { last_error = memory_error; return 0; } } strncpy(filename, cur, lendir); if (filename[lendir-1] != '/') filename[lendir++] = '/'; strcpy(filename+lendir, basename); if (handle) { if (tryall_dlopen(handle, filename) == 0) { lt_dlfree(filename); return (lt_ptr_t) handle; } } else { FILE *file = fopen(filename, LTDL_READTEXT_MODE); if (file) { if (*pdir) lt_dlfree(*pdir); filename[lendir] = '\0'; *pdir = strdup(filename); if (!*pdir) { /* We could have even avoided the strdup, but there would be some memory overhead. */ *pdir = filename; } else lt_dlfree(filename); return (lt_ptr_t) file; } } } if (filename) lt_dlfree(filename); last_error = file_not_found_error; return 0; } static int load_deplibs(handle, deplibs) lt_dlhandle handle; const char *deplibs; { /* FIXME: load deplibs */ handle->depcount = 0; handle->deplibs = 0; return 0; } static int unload_deplibs(handle) lt_dlhandle handle; { /* FIXME: unload deplibs */ return 0; } static inline int trim (dest, str) char **dest; const char *str; { /* remove the leading and trailing "'" from str and store the result in dest */ char *tmp; char *end = strrchr(str, '\''); int len = strlen(str); if (*dest) lt_dlfree(*dest); if (len > 3 && str[0] == '\'') { tmp = (char*) lt_dlmalloc(end - str); if (!tmp) { last_error = memory_error; return 1; } strncpy(tmp, &str[1], (end - str) - 1); tmp[len-3] = '\0'; *dest = tmp; } else *dest = 0; return 0; } static inline int free_vars(dir, name, dlname, oldname, libdir, deplibs) char *dir; char *name; char *dlname; char *oldname; char *libdir; char *deplibs; { if (dir) lt_dlfree(dir); if (name) lt_dlfree(name); if (dlname) lt_dlfree(dlname); if (oldname) lt_dlfree(oldname); if (libdir) lt_dlfree(libdir); if (deplibs) lt_dlfree(deplibs); return 0; } lt_dlhandle lt_dlopen (filename) const char *filename; { lt_dlhandle handle, newhandle; const char *basename, *ext; const char *saved_error = last_error; char *dir = 0, *name = 0; if (!filename) { handle = (lt_dlhandle) lt_dlmalloc(sizeof(lt_dlhandle_t)); if (!handle) { last_error = memory_error; return 0; } handle->usage = 0; handle->depcount = 0; handle->deplibs = 0; newhandle = handle; if (tryall_dlopen(&newhandle, 0) != 0) { lt_dlfree(handle); return 0; } goto register_handle; } basename = strrchr(filename, '/'); if (basename) { basename++; dir = (char*) lt_dlmalloc(basename - filename + 1); if (!dir) { last_error = memory_error; return 0; } strncpy(dir, filename, basename - filename); dir[basename - filename] = '\0'; } else basename = filename; /* check whether we open a libtool module (.la extension) */ ext = strrchr(basename, '.'); if (ext && strcmp(ext, ".la") == 0) { /* this seems to be a libtool module */ FILE *file; int i; char *dlname = 0, *old_name = 0; char *libdir = 0, *deplibs = 0; char *line; int error = 0; /* if we can't find the installed flag, it is probably an installed libtool archive, produced with an old version of libtool */ int installed = 1; /* extract the module name from the file name */ name = (char*) lt_dlmalloc(ext - basename + 1); if (!name) { last_error = memory_error; if (dir) lt_dlfree(dir); return 0; } /* canonicalize the module name */ for (i = 0; i < ext - basename; i++) if (isalnum(basename[i])) name[i] = basename[i]; else name[i] = '_'; name[ext - basename] = '\0'; /* now try to open the .la file */ file = fopen(filename, LTDL_READTEXT_MODE); if (!file) last_error = file_not_found_error; if (!file && !dir) { /* try other directories */ file = (FILE*) find_file(basename, user_search_path, &dir, 0); if (!file) file = (FILE*) find_file(basename, getenv("LTDL_LIBRARY_PATH"), &dir, 0); #ifdef LTDL_SHLIBPATH_VAR if (!file) file = (FILE*) find_file(basename, getenv(LTDL_SHLIBPATH_VAR), &dir, 0); #endif } if (!file) { if (name) lt_dlfree(name); if (dir) lt_dlfree(dir); return 0; } line = (char*) lt_dlmalloc(LTDL_FILENAME_MAX); if (!line) { fclose(file); last_error = memory_error; return 0; } /* read the .la file */ while (!feof(file)) { if (!fgets(line, LTDL_FILENAME_MAX, file)) break; if (line[0] == '\n' || line[0] == '#') continue; # undef STR_DLNAME # define STR_DLNAME "dlname=" if (strncmp(line, STR_DLNAME, sizeof(STR_DLNAME) - 1) == 0) error = trim(&dlname, &line[sizeof(STR_DLNAME) - 1]); else # undef STR_OLD_LIBRARY # define STR_OLD_LIBRARY "old_library=" if (strncmp(line, STR_OLD_LIBRARY, sizeof(STR_OLD_LIBRARY) - 1) == 0) error = trim(&old_name, &line[sizeof(STR_OLD_LIBRARY) - 1]); else # undef STR_LIBDIR # define STR_LIBDIR "libdir=" if (strncmp(line, STR_LIBDIR, sizeof(STR_LIBDIR) - 1) == 0) error = trim(&libdir, &line[sizeof(STR_LIBDIR) - 1]); else # undef STR_DL_DEPLIBS # define STR_DL_DEPLIBS "dl_dependency_libs=" if (strncmp(line, STR_DL_DEPLIBS, sizeof(STR_DL_DEPLIBS) - 1) == 0) error = trim(&deplibs, &line[sizeof(STR_DL_DEPLIBS) - 1]); else if (strcmp(line, "installed=yes\n") == 0) installed = 1; else if (strcmp(line, "installed=no\n") == 0) installed = 0; if (error) break; } fclose(file); lt_dlfree(line); /* allocate the handle */ handle = (lt_dlhandle) lt_dlmalloc(sizeof(lt_dlhandle_t)); if (!handle || error) { if (handle) lt_dlfree(handle); if (!error) last_error = memory_error; free_vars(name, dir, dlname, old_name, libdir, deplibs); return 0; } handle->usage = 0; if (load_deplibs(handle, deplibs) == 0) { newhandle = handle; /* find_module may replace newhandle */ if (find_module(&newhandle, dir, libdir, dlname, old_name, installed)) { unload_deplibs(handle); error = 1; } } else error = 1; if (error) { lt_dlfree(handle); free_vars(name, dir, dlname, old_name, libdir, deplibs); return 0; } if (handle != newhandle) { unload_deplibs(handle); } } else { /* not a libtool module */ handle = (lt_dlhandle) lt_dlmalloc(sizeof(lt_dlhandle_t)); if (!handle) { last_error = memory_error; if (dir) lt_dlfree(dir); return 0; } handle->usage = 0; /* non-libtool modules don't have dependencies */ handle->depcount = 0; handle->deplibs = 0; newhandle = handle; if (tryall_dlopen(&newhandle, filename) && (!dir || (!find_file(basename, user_search_path, 0, &newhandle) && !find_file(basename, getenv("LTDL_LIBRARY_PATH"), 0, &newhandle) #ifdef LTDL_SHLIBPATH_VAR && !find_file(basename, getenv(LTDL_SHLIBPATH_VAR), 0, &newhandle) #endif ))) { lt_dlfree(handle); if (dir) lt_dlfree(dir); return 0; } } register_handle: if (newhandle != handle) { lt_dlfree(handle); handle = newhandle; } if (!handle->usage) { handle->usage = 1; handle->name = name; handle->next = handles; handles = handle; } else if (name) lt_dlfree(name); if (dir) lt_dlfree(dir); last_error = saved_error; return handle; } lt_dlhandle lt_dlopenext (filename) const char *filename; { lt_dlhandle handle; char *tmp; int len; const char *saved_error = last_error; if (!filename) return lt_dlopen(filename); len = strlen(filename); if (!len) { last_error = file_not_found_error; return 0; } /* try the normal file name */ handle = lt_dlopen(filename); if (handle) return handle; /* try "filename.la" */ tmp = (char*) lt_dlmalloc(len+4); if (!tmp) { last_error = memory_error; return 0; } strcpy(tmp, filename); strcat(tmp, ".la"); handle = lt_dlopen(tmp); if (handle) { last_error = saved_error; lt_dlfree(tmp); return handle; } #ifdef LTDL_SHLIB_EXT /* try "filename.EXT" */ if (strlen(shlib_ext) > 3) { lt_dlfree(tmp); tmp = (char*) lt_dlmalloc(len + strlen(shlib_ext) + 1); if (!tmp) { last_error = memory_error; return 0; } strcpy(tmp, filename); } else tmp[len] = '\0'; strcat(tmp, shlib_ext); handle = lt_dlopen(tmp); if (handle) { last_error = saved_error; lt_dlfree(tmp); return handle; } #endif last_error = file_not_found_error; lt_dlfree(tmp); return 0; } int lt_dlclose (handle) lt_dlhandle handle; { lt_dlhandle cur, last; /* check whether the handle is valid */ last = cur = handles; while (cur && handle != cur) { last = cur; cur = cur->next; } if (!cur) { last_error = invalid_handle_error; return 1; } handle->usage--; if (!handle->usage) { int error; if (handle != handles) last->next = handle->next; else handles = handle->next; error = handle->type->lib_close(handle); error += unload_deplibs(handle); if (handle->filename) lt_dlfree(handle->filename); if (handle->name) lt_dlfree(handle->name); lt_dlfree(handle); return error; } return 0; } lt_ptr_t lt_dlsym (handle, symbol) lt_dlhandle handle; const char *symbol; { int lensym; char lsym[LTDL_SYMBOL_LENGTH]; char *sym; lt_ptr_t address; if (!handle) { last_error = invalid_handle_error; return 0; } if (!symbol) { last_error = symbol_error; return 0; } lensym = strlen(symbol); if (handle->type->sym_prefix) lensym += strlen(handle->type->sym_prefix); if (handle->name) lensym += strlen(handle->name); if (lensym + LTDL_SYMBOL_OVERHEAD < LTDL_SYMBOL_LENGTH) sym = lsym; else sym = (char*) lt_dlmalloc(lensym + LTDL_SYMBOL_OVERHEAD + 1); if (!sym) { last_error = buffer_overflow_error; return 0; } if (handle->name) { /* this is a libtool module */ if (handle->type->sym_prefix) { strcpy(sym, handle->type->sym_prefix); strcat(sym, handle->name); } else strcpy(sym, handle->name); strcat(sym, "_LTX_"); strcat(sym, symbol); /* try "modulename_LTX_symbol" */ address = handle->type->find_sym(handle, sym); if (address) { if (sym != lsym) lt_dlfree(sym); return address; } } /* otherwise try "symbol" */ if (handle->type->sym_prefix) { strcpy(sym, handle->type->sym_prefix); strcat(sym, symbol); } else strcpy(sym, symbol); address = handle->type->find_sym(handle, sym); if (sym != lsym) lt_dlfree(sym); return address; } const char * lt_dlerror () { const char *error = last_error; last_error = 0; return error; } int lt_dladdsearchdir (search_dir) const char *search_dir; { if (!search_dir || !strlen(search_dir)) return 0; if (!user_search_path) { user_search_path = strdup(search_dir); if (!user_search_path) { last_error = memory_error; return 1; } } else { char *new_search_path = (char*) lt_dlmalloc(strlen(user_search_path) + strlen(search_dir) + 1); if (!new_search_path) { last_error = memory_error; return 1; } strcat(new_search_path, ":"); strcat(new_search_path, search_dir); lt_dlfree(user_search_path); user_search_path = new_search_path; } return 0; } int lt_dlsetsearchpath (search_path) const char *search_path; { if (user_search_path) lt_dlfree(user_search_path); user_search_path = 0; /* reset the search path */ if (!search_path || !strlen(search_path)) return 0; user_search_path = strdup(search_path); if (!user_search_path) return 1; return 0; } const char * lt_dlgetsearchpath () { return user_search_path; }