--- sql/pgsql/libltdl/ltdl.c 2001/09/21 15:44:38 1.1 +++ sql/pgsql/libltdl/ltdl.c 2012/06/08 15:25:55 1.4 @@ -1,1619 +1,2464 @@ /* ltdl.c -- system independent dlopen wrapper - Copyright (C) 1998-1999 Free Software Foundation, Inc. - Originally by Thomas Tanner - 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 + Copyright (C) 1998, 1999, 2000, 2004, 2005, 2006, + 2007, 2008, 2011 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/or +modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. -As a special exception to the GNU Library General Public License, -if you distribute this file as part of a program that uses GNU libtool -to create libraries and programs, you may include it under the same -distribution terms that you use for the rest of that program. +As a special exception to the GNU Lesser General Public License, +if you distribute this file as part of a program or library that +is built using GNU Libtool, you may include this file under the +same distribution terms that you use for the rest of that program. -This library is distributed in the hope that it will be useful, +GNU Libltdl 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. +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser 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., 59 Temple Place, Suite 330, Boston, MA -02111-1307 USA +You should have received a copy of the GNU Lesser General Public +License along with GNU Libltdl; see the file COPYING.LIB. If not, a +copy 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. */ -#define _LTDL_COMPILE_ +#include "lt__private.h" +#include "lt_system.h" +#include "lt_dlloader.h" -#include "config.h" -#if HAVE_STRING_H -#include -#endif +/* --- MANIFEST CONSTANTS --- */ -#if HAVE_STRINGS_H -#include -#endif -#if HAVE_CTYPE_H -#include -#endif +/* Standard libltdl search path environment variable name */ +#undef LTDL_SEARCHPATH_VAR +#define LTDL_SEARCHPATH_VAR "LTDL_LIBRARY_PATH" -#if HAVE_MALLOC_H -#include -#endif +/* Standard libtool archive file extension. */ +#undef LT_ARCHIVE_EXT +#define LT_ARCHIVE_EXT ".la" -#if HAVE_MEMORY_H -#include +/* max. filename length */ +#if !defined(LT_FILENAME_MAX) +# define LT_FILENAME_MAX 1024 #endif -#if HAVE_STDLIB_H -#include +#if !defined(LT_LIBEXT) +# define LT_LIBEXT "a" #endif -#if HAVE_STDIO_H -#include +#if !defined(LT_LIBPREFIX) +# define LT_LIBPREFIX "lib" #endif -#include "ltdl.h" +/* This is the maximum symbol size that won't require malloc/free */ +#undef LT_SYMBOL_LENGTH +#define LT_SYMBOL_LENGTH 128 -/* max. filename length */ -#ifndef LTDL_FILENAME_MAX -#define LTDL_FILENAME_MAX 1024 -#endif +/* This accounts for the _LTX_ separator */ +#undef LT_SYMBOL_OVERHEAD +#define LT_SYMBOL_OVERHEAD 5 -#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" +/* Various boolean flags can be stored in the flags field of an + lt_dlhandle... */ +#define LT_DLIS_RESIDENT(handle) ((handle)->info.is_resident) +#define LT_DLIS_SYMGLOBAL(handle) ((handle)->info.is_symglobal) +#define LT_DLIS_SYMLOCAL(handle) ((handle)->info.is_symlocal) + + +static const char objdir[] = LT_OBJDIR; +static const char archive_ext[] = LT_ARCHIVE_EXT; +static const char libext[] = LT_LIBEXT; +static const char libprefix[] = LT_LIBPREFIX; +#if defined(LT_MODULE_EXT) +static const char shlib_ext[] = LT_MODULE_EXT; +#endif +/* If the loadable module suffix is not the same as the linkable + * shared library suffix, this will be defined. */ +#if defined(LT_SHARED_EXT) +static const char shared_ext[] = LT_SHARED_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_LIBDLLOADER +static 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!!). */ +void +lt__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 int +loader_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 int +loader_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_DECLS +LT_SCOPE const lt_dlvtable * get_vtable (lt_user_data data); +LT_END_C_DECLS +#ifdef HAVE_LIBDLLOADER +extern LT_DLSYM_CONST lt_dlsymlist preloaded_symbols[]; #endif -#undef LTDL_SYMBOL_LENGTH -/* This is the maximum symbol size that won't require malloc/free */ -#define LTDL_SYMBOL_LENGTH 128 +/* Initialize libltdl. */ +int +lt_dlinit (void) +{ + int errors = 0; -#undef LTDL_SYMBOL_OVERHEAD -/* This accounts for the _LTX_ separator */ -#define LTDL_SYMBOL_OVERHEAD 5 + /* 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); + } -static const char objdir[] = LTDL_OBJDIR; -#ifdef LTDL_SHLIB_EXT -static const char shlib_ext[] = LTDL_SHLIB_EXT; + if (!errors) + { + errors += lt_dlpreload_open (LT_STR(LTDLOPEN), loader_init_callback); + } +#endif /* HAVE_LIBDLLOADER */ + } + +#ifdef LT_DEBUG_LOADERS + lt_dlloader_dump(); #endif -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 cannot_open_error[] = "can't open the module"; -static const char cannot_close_error[] = "can't close the module"; -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"; + return errors; +} + +int +lt_dlexit (void) +{ + /* shut down libltdl */ + lt_dlloader *loader = 0; + lt_dlhandle 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 = handles->next; + } + + /* close all modules */ + for (level = 1; handle; ++level) + { + lt_dlhandle cur = handles; + int saw_nonresident = 0; + + while (cur) + { + lt_dlhandle 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 = handles; tmp; tmp = tmp->next) + if (tmp == cur) + break; + if (! tmp) + cur = handles; + } + } + } + } + /* done if only resident modules are left */ + if (!saw_nonresident) + break; + } + + /* When removing loaders, we can only find out failure by testing + the error string, so avoid a spurious one from an earlier + failed command. */ + if (!errors) + LT__SETERRORSTR (0); + + /* 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 + { + /* ignore errors due to resident modules */ + const char *err; + LT__GETERROR (err); + if (err) + ++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 int +tryall_dlopen (lt_dlhandle *phandle, const char *filename, + lt_dladvise advise, const lt_dlvtable *vtable) +{ + lt_dlhandle handle = handles; + const char * saved_error = 0; + int errors = 0; + +#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 = *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); -#ifndef HAVE_PRELOADED_SYMBOLS -/* If libtool won't define it, we'd better do */ -const lt_dlsymlist lt_preloaded_symbols[1] = { { 0, 0 } }; +#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 -static const char *last_error = 0; + 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))); -lt_ptr_t (*lt_dlmalloc) LTDL_PARAMS((size_t size)) = (lt_ptr_t(*)LTDL_PARAMS((size_t)))malloc; -void (*lt_dlfree) LTDL_PARAMS((lt_ptr_t ptr)) = (void(*)LTDL_PARAMS((lt_ptr_t)))free; + /* 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; + } -typedef struct lt_dltype_t { - struct lt_dltype_t *next; - const char *sym_prefix; /* prefix for symbols */ - int (*mod_init) LTDL_PARAMS((void)); - int (*mod_exit) LTDL_PARAMS((void)); - int (*lib_open) LTDL_PARAMS((lt_dlhandle handle, const char *filename)); - int (*lib_close) LTDL_PARAMS((lt_dlhandle handle)); - lt_ptr_t (*find_sym) LTDL_PARAMS((lt_dlhandle handle, const char *symbol)); -} lt_dltype_t; + handle->vtable = loader_vtable; + } -#define LTDL_TYPE_TOP 0 + LT__SETERRORSTR (saved_error); -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; + done: + return errors; +} -#undef strdup -#define strdup xstrdup -static inline char * -strdup(str) - const char *str; +static int +tryall_dlopen_module (lt_dlhandle *handle, const char *prefix, + const char *dirname, const char *dlname, + lt_dladvise advise) { - char *tmp; + int error = 0; + char *filename = 0; + size_t filename_len = 0; + size_t dirname_len = LT_STRLEN (dirname); - if (!str) - return 0; - tmp = (char*) lt_dlmalloc(strlen(str)+1); - if (tmp) - strcpy(tmp, str); - return tmp; -} + 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 ! HAVE_STRCHR + if (dirname_len > 0) + if (dirname[dirname_len -1] == '/') + --dirname_len; + filename_len = dirname_len + 1 + LT_STRLEN (dlname); -# if HAVE_INDEX + /* Allocate memory, and combine DIRNAME and MODULENAME into it. + The PREFIX (if any) is handled below. */ + filename = MALLOC (char, filename_len + 1); + if (!filename) + return 1; -# define strchr index + sprintf (filename, "%.*s/%s", (int) dirname_len, dirname, dlname); -# else + /* 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; + } -# define strchr xstrchr + FREE (filename); + return error; +} -static inline const char* -strchr(str, ch) - const char *str; - int ch; +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) { - const char *p; + /* 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, lt_dlloader_find ("lt_preopen") ) == 0) + { + return 0; + } - for (p = str; *p != (char)ch && *p != '\0'; p++) - /*NOWORK*/; + /* 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; + } - return (*p == (char)ch) ? p : 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; } -# endif -#endif +static int +canonicalize_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; -#if ! HAVE_STRRCHR + { + 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; + } -# if HAVE_RINDEX + /* 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) +#endif + && (path[1+ src] != '/')) + { + canonical[dest++] = '/'; + } + } -# define strrchr rindex + /* Add an end-of-string marker at the end. */ + canonical[dest] = LT_EOS_CHAR; + } -# else + /* Assign new value. */ + *pcanonical = canonical; -# define strrchr xstrrchr + return 0; +} -static inline const char* -strrchr(str, ch) - const char *str; - int ch; +static int +argzize_path (const char *path, char **pargz, size_t *pargz_len) { - const char *p; + error_t error; + + assert (path); + assert (pargz); + assert (pargz_len); - for (p = str; *p != '\0'; p++) - /*NOWORK*/; + if ((error = argz_create_sep (path, LT_PATHSEP_CHAR, pargz, pargz_len))) + { + switch (error) + { + case ENOMEM: + LT__SETERROR (NO_MEMORY); + break; + default: + LT__SETERROR (UNKNOWN); + break; + } - while (*p != (char)ch && p >= str) - p--; + return 1; + } - return (*p == (char)ch) ? p : 0; + return 0; } -# endif +/* Repeatedly call FUNC with each LT_PATHSEP_CHAR delimited element + of SEARCH_PATH and references to DATA1 and DATA2, until FUNC returns + non-zero or all elements are exhausted. If BASE_NAME is non-NULL, + it is appended to each SEARCH_PATH element before FUNC is called. */ +static int +foreach_dirinpath (const char *search_path, const char *base_name, + foreach_callback_func *func, void *data1, void *data2) +{ + int result = 0; + size_t filenamesize = 0; + size_t lenbase = LT_STRLEN (base_name); + size_t argz_len = 0; + char *argz = 0; + char *filename = 0; + char *canonical = 0; -#endif + if (!search_path || !*search_path) + { + LT__SETERROR (FILE_NOT_FOUND); + goto cleanup; + } -#if HAVE_LIBDL + if (canonicalize_path (search_path, &canonical) != 0) + goto cleanup; -/* dynamic linking with dlopen/dlsym */ + if (argzize_path (canonical, &argz, &argz_len) != 0) + goto cleanup; -#if HAVE_DLFCN_H -# include -#endif + { + char *dir_name = 0; + while ((dir_name = argz_next (argz, argz_len, dir_name))) + { + size_t lendir = LT_STRLEN (dir_name); -#ifdef RTLD_GLOBAL -# define LTDL_GLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LTDL_GLOBAL DL_GLOBAL -# else -# define LTDL_GLOBAL 0 -# endif -#endif + if (1+ lendir + lenbase >= filenamesize) + { + FREE (filename); + filenamesize = 1+ lendir + 1+ lenbase; /* "/d" + '/' + "f" + '\0' */ + filename = MALLOC (char, filenamesize); + if (!filename) + goto cleanup; + } -/* 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 + assert (filenamesize > lendir); + strcpy (filename, dir_name); -static int -sys_dl_init LTDL_PARAMS((void)) -{ - return 0; + if (base_name && *base_name) + { + if (filename[lendir -1] != '/') + filename[lendir++] = '/'; + strcpy (filename +lendir, base_name); + } + + if ((result = (*func) (filename, data1, data2))) + { + break; + } + } + } + + cleanup: + FREE (argz); + FREE (canonical); + FREE (filename); + + return result; } +/* If FILEPATH can be opened, store the name of the directory component + in DATA1, and the opened FILE* structure address in DATA2. Otherwise + DATA1 is unchanged, but DATA2 is set to a pointer to NULL. */ static int -sys_dl_exit LTDL_PARAMS((void)) +find_file_callback (char *filename, void *data1, void *data2) { - return 0; -} + char **pdir = (char **) data1; + FILE **pfile = (FILE **) data2; + int is_done = 0; -static int -sys_dl_open (handle, filename) - lt_dlhandle handle; - const char *filename; -{ - handle->handle = dlopen(filename, LTDL_GLOBAL | LTDL_LAZY_OR_NOW); - if (!handle->handle) { -#if HAVE_DLERROR - last_error = dlerror(); -#else - last_error = cannot_open_error; -#endif - return 1; - } - return 0; + assert (filename && *filename); + assert (pdir); + assert (pfile); + + if ((*pfile = fopen (filename, LT_READTEXT_MODE))) + { + char *dirend = strrchr (filename, '/'); + + if (dirend > filename) + *dirend = LT_EOS_CHAR; + + FREE (*pdir); + *pdir = lt__strdup (filename); + is_done = (*pdir == 0) ? -1 : 1; + } + + return is_done; } -static int -sys_dl_close (handle) - lt_dlhandle handle; +static FILE * +find_file (const char *search_path, const char *base_name, char **pdir) { - if (dlclose(handle->handle) != 0) { -#if HAVE_DLERROR - last_error = dlerror(); -#else - last_error = cannot_close_error; -#endif - return 1; - } - return 0; -} + FILE *file = 0; -static lt_ptr_t -sys_dl_sym (handle, symbol) - lt_dlhandle handle; - const char *symbol; -{ - lt_ptr_t address = dlsym(handle->handle, symbol); - - if (!address) -#if HAVE_DLERROR - last_error = dlerror(); -#else - last_error = symbol_error; -#endif - return address; -} - -static -lt_dltype_t -#ifdef NEED_USCORE -sys_dl = { LTDL_TYPE_TOP, "_", sys_dl_init, sys_dl_exit, - sys_dl_open, sys_dl_close, sys_dl_sym }; -#else -sys_dl = { LTDL_TYPE_TOP, 0, sys_dl_init, sys_dl_exit, - sys_dl_open, sys_dl_close, sys_dl_sym }; -#endif - -#undef LTDL_TYPE_TOP -#define LTDL_TYPE_TOP &sys_dl - -#endif - -#if HAVE_SHL_LOAD - -/* dynamic linking with shl_load (HP-UX) (comments from gmodule) */ - -#ifdef HAVE_DL_H -#include -#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 */ + foreach_dirinpath (search_path, base_name, find_file_callback, pdir, &file); -#define LTDL_BIND_FLAGS (BIND_IMMEDIATE | BIND_NONFATAL | DYNAMIC_PATH) + return file; +} static int -sys_shl_init LTDL_PARAMS((void)) +find_handle_callback (char *filename, void *data, void *data2) { - return 0; + lt_dlhandle *phandle = (lt_dlhandle *) data; + int notfound = access (filename, R_OK); + lt_dladvise advise = (lt_dladvise) data2; + + /* Bail out if file cannot be read... */ + if (notfound) + return 0; + + /* Try to dlopen the file, but do not continue searching in any + case. */ + if (tryall_dlopen (phandle, filename, advise, 0) != 0) + *phandle = 0; + + return 1; } -static int -sys_shl_exit LTDL_PARAMS((void)) +/* If HANDLE was found return it, otherwise return 0. If HANDLE was + found but could not be opened, *HANDLE will be set to 0. */ +static lt_dlhandle * +find_handle (const char *search_path, const char *base_name, + lt_dlhandle *phandle, lt_dladvise advise) { - return 0; + if (!search_path) + return 0; + + if (!foreach_dirinpath (search_path, base_name, find_handle_callback, + phandle, advise)) + return 0; + + return phandle; } +#if !defined(LTDL_DLOPEN_DEPLIBS) static int -sys_shl_open (handle, filename) - lt_dlhandle handle; - const char *filename; -{ - handle->handle = shl_load(filename, LTDL_BIND_FLAGS, 0L); - if (!handle->handle) { - last_error = cannot_open_error; - return 1; - } - return 0; +load_deplibs (lt_dlhandle handle, char * LT__UNUSED deplibs) +{ + handle->depcount = 0; + return 0; } +#else /* defined(LTDL_DLOPEN_DEPLIBS) */ static int -sys_shl_close (handle) - lt_dlhandle handle; +load_deplibs (lt_dlhandle handle, char *deplibs) { - if (shl_unload((shl_t) (handle->handle)) != 0) { - last_error = cannot_close_error; - return 1; + char *p, *save_search_path = 0; + int depcount = 0; + int i; + char **names = 0; + int errors = 0; + + handle->depcount = 0; + + if (!deplibs) + { + return errors; + } + ++errors; + + if (user_search_path) + { + save_search_path = lt__strdup (user_search_path); + if (!save_search_path) + goto cleanup; + } + + /* extract search paths and count deplibs */ + p = deplibs; + while (*p) + { + if (!isspace ((unsigned char) *p)) + { + char *end = p+1; + while (*end && !isspace((unsigned char) *end)) + { + ++end; + } + + if (strncmp(p, "-L", 2) == 0 || strncmp(p, "-R", 2) == 0) + { + char save = *end; + *end = 0; /* set a temporary string terminator */ + if (lt_dladdsearchdir(p+2)) + { + goto cleanup; + } + *end = save; + } + else + { + ++depcount; + } + + p = end; + } + else + { + ++p; + } + } + + + if (!depcount) + { + errors = 0; + goto cleanup; + } + + names = MALLOC (char *, depcount); + if (!names) + goto cleanup; + + /* now only extract the actual deplibs */ + depcount = 0; + p = deplibs; + while (*p) + { + if (isspace ((unsigned char) *p)) + { + ++p; + } + else + { + char *end = p+1; + while (*end && !isspace ((unsigned char) *end)) + { + ++end; + } + + if (strncmp(p, "-L", 2) != 0 && strncmp(p, "-R", 2) != 0) + { + char *name; + char save = *end; + *end = 0; /* set a temporary string terminator */ + if (strncmp(p, "-l", 2) == 0) + { + size_t name_len = 3+ /* "lib" */ LT_STRLEN (p + 2); + name = MALLOC (char, 1+ name_len); + if (name) + sprintf (name, "lib%s", p+2); + } + else + name = lt__strdup(p); + + if (!name) + goto cleanup_names; + + names[depcount++] = name; + *end = save; + } + p = end; } - return 0; -} + } -static lt_ptr_t -sys_shl_sym (handle, symbol) - lt_dlhandle handle; - const char *symbol; -{ - lt_ptr_t address; - - if (handle->handle && shl_findsym((shl_t*) &(handle->handle), - symbol, TYPE_UNDEFINED, &address) == 0) - if (address) - return address; - last_error = symbol_error; - return 0; -} + /* load the deplibs (in reverse order) + At this stage, don't worry if the deplibs do not load correctly, + they may already be statically linked into the loading application + for instance. There will be a more enlightening error message + later on if the loaded module cannot resolve all of its symbols. */ + if (depcount) + { + lt_dlhandle cur = handle; + int j = 0; -static -lt_dltype_t -sys_shl = { LTDL_TYPE_TOP, 0, sys_shl_init, sys_shl_exit, - sys_shl_open, sys_shl_close, sys_shl_sym }; + cur->deplibs = MALLOC (lt_dlhandle, depcount); + if (!cur->deplibs) + goto cleanup_names; -#undef LTDL_TYPE_TOP -#define LTDL_TYPE_TOP &sys_shl + for (i = 0; i < depcount; ++i) + { + cur->deplibs[j] = lt_dlopenext(names[depcount-1-i]); + if (cur->deplibs[j]) + { + ++j; + } + } -#endif + cur->depcount = j; /* Number of successfully loaded deplibs */ + errors = 0; + } -#if HAVE_DLD + cleanup_names: + for (i = 0; i < depcount; ++i) + { + FREE (names[i]); + } -/* dynamic linking with dld */ + cleanup: + FREE (names); + /* restore the old search path */ + if (save_search_path) { + MEMREASSIGN (user_search_path, save_search_path); + } -#if HAVE_DLD_H -#include -#endif + return errors; +} +#endif /* defined(LTDL_DLOPEN_DEPLIBS) */ static int -sys_dld_init LTDL_PARAMS((void)) +unload_deplibs (lt_dlhandle handle) { - return 0; + int i; + int errors = 0; + lt_dlhandle cur = handle; + + if (cur->depcount) + { + for (i = 0; i < cur->depcount; ++i) + { + if (!LT_DLIS_RESIDENT (cur->deplibs[i])) + { + errors += lt_dlclose (cur->deplibs[i]); + } + } + FREE (cur->deplibs); + } + + return errors; } static int -sys_dld_exit LTDL_PARAMS((void)) +trim (char **dest, const char *str) { - return 0; -} + /* remove the leading and trailing "'" from str + and store the result in dest */ + const char *end = strrchr (str, '\''); + size_t len = LT_STRLEN (str); + char *tmp; -static int -sys_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 = cannot_open_error; - lt_dlfree(handle->handle); - return 1; + FREE (*dest); + + if (!end || end == str) + return 1; + + if (len > 3 && str[0] == '\'') + { + tmp = MALLOC (char, end - str); + if (!tmp) + return 1; + + memcpy(tmp, &str[1], (end - str) - 1); + tmp[(end - str) - 1] = LT_EOS_CHAR; + *dest = tmp; + } + else + { + *dest = 0; + } + + return 0; +} + +/* Read the .la file FILE. */ +static int +parse_dotla_file(FILE *file, char **dlname, char **libdir, char **deplibs, + char **old_name, int *installed) +{ + int errors = 0; + size_t line_len = LT_FILENAME_MAX; + char * line = MALLOC (char, line_len); + + if (!line) + { + LT__SETERROR (FILE_NOT_FOUND); + return 1; + } + + while (!feof (file)) + { + line[line_len-2] = '\0'; + if (!fgets (line, (int) line_len, file)) + { + break; + } + + /* Handle the case where we occasionally need to read a line + that is longer than the initial buffer size. + Behave even if the file contains NUL bytes due to corruption. */ + while (line[line_len-2] != '\0' && line[line_len-2] != '\n' && !feof (file)) + { + line = REALLOC (char, line, line_len *2); + if (!line) + { + ++errors; + goto cleanup; + } + line[line_len * 2 - 2] = '\0'; + if (!fgets (&line[line_len -1], (int) line_len +1, file)) + { + break; + } + line_len *= 2; + } + + if (line[0] == '\n' || line[0] == '#') + { + continue; + } + +#undef STR_DLNAME +#define STR_DLNAME "dlname=" + if (strncmp (line, STR_DLNAME, sizeof (STR_DLNAME) - 1) == 0) + { + errors += trim (dlname, &line[sizeof (STR_DLNAME) - 1]); + } + +#undef STR_OLD_LIBRARY +#define STR_OLD_LIBRARY "old_library=" + else if (strncmp (line, STR_OLD_LIBRARY, + sizeof (STR_OLD_LIBRARY) - 1) == 0) + { + errors += trim (old_name, &line[sizeof (STR_OLD_LIBRARY) - 1]); + } + + /* Windows native tools do not understand the POSIX paths we store + in libdir. */ +#undef STR_LIBDIR +#define STR_LIBDIR "libdir=" + else if (strncmp (line, STR_LIBDIR, sizeof (STR_LIBDIR) - 1) == 0) + { + errors += trim (libdir, &line[sizeof(STR_LIBDIR) - 1]); +#ifdef __WINDOWS__ + /* Disallow following unix-style paths on MinGW. */ + if (*libdir && (**libdir == '/' || **libdir == '\\')) + **libdir = '\0'; +#endif + } + +#undef STR_DL_DEPLIBS +#define STR_DL_DEPLIBS "dependency_libs=" + else if (strncmp (line, STR_DL_DEPLIBS, + sizeof (STR_DL_DEPLIBS) - 1) == 0) + { + errors += trim (deplibs, &line[sizeof (STR_DL_DEPLIBS) - 1]); + } + else if (streq (line, "installed=yes\n")) + { + *installed = 1; + } + else if (streq (line, "installed=no\n")) + { + *installed = 0; + } + +#undef STR_LIBRARY_NAMES +#define STR_LIBRARY_NAMES "library_names=" + else if (!*dlname && strncmp (line, STR_LIBRARY_NAMES, + sizeof (STR_LIBRARY_NAMES) - 1) == 0) + { + char *last_libname; + errors += trim (dlname, &line[sizeof (STR_LIBRARY_NAMES) - 1]); + if (!errors + && *dlname + && (last_libname = strrchr (*dlname, ' ')) != 0) + { + last_libname = lt__strdup (last_libname + 1); + if (!last_libname) + { + ++errors; + goto cleanup; + } + MEMREASSIGN (*dlname, last_libname); + } } - return 0; + + if (errors) + break; + } +cleanup: + FREE (line); + return errors; } + +/* Try to open FILENAME as a module. */ static int -sys_dld_close (handle) - lt_dlhandle handle; +try_dlopen (lt_dlhandle *phandle, const char *filename, const char *ext, + lt_dladvise advise) { - if (dld_unlink_by_file((char*)(handle->handle), 1) != 0) { - last_error = cannot_close_error; - return 1; + const char * saved_error = 0; + char * archive_name = 0; + char * canonical = 0; + char * base_name = 0; + char * dir = 0; + char * name = 0; + char * attempt = 0; + int errors = 0; + lt_dlhandle newhandle; + + assert (phandle); + assert (*phandle == 0); + +#ifdef LT_DEBUG_LOADERS + fprintf (stderr, "try_dlopen (%s, %s)\n", + filename ? filename : "(null)", + ext ? ext : "(null)"); +#endif + + LT__GETERROR (saved_error); + + /* dlopen self? */ + if (!filename) + { + *phandle = (lt_dlhandle) lt__zalloc (sizeof (struct lt__handle)); + if (*phandle == 0) + return 1; + + newhandle = *phandle; + + /* lt_dlclose()ing yourself is very bad! Disallow it. */ + newhandle->info.is_resident = 1; + + if (tryall_dlopen (&newhandle, 0, advise, 0) != 0) + { + FREE (*phandle); + return 1; } - lt_dlfree(handle->filename); - return 0; -} -static lt_ptr_t -sys_dld_sym (handle, symbol) - lt_dlhandle handle; - const char *symbol; -{ - lt_ptr_t address = dld_get_func(symbol); - - if (!address) - last_error = symbol_error; - return address; -} + goto register_handle; + } -static -lt_dltype_t -sys_dld = { LTDL_TYPE_TOP, 0, sys_dld_init, sys_dld_exit, - sys_dld_open, sys_dld_close, sys_dld_sym }; + assert (filename && *filename); -#undef LTDL_TYPE_TOP -#define LTDL_TYPE_TOP &sys_dld + if (ext) + { + attempt = MALLOC (char, LT_STRLEN (filename) + LT_STRLEN (ext) + 1); + if (!attempt) + return 1; -#endif + sprintf(attempt, "%s%s", filename, ext); + } + else + { + attempt = lt__strdup (filename); + if (!attempt) + return 1; + } + + /* Doing this immediately allows internal functions to safely + assume only canonicalized paths are passed. */ + if (canonicalize_path (attempt, &canonical) != 0) + { + ++errors; + goto cleanup; + } + + /* If the canonical module name is a path (relative or absolute) + then split it into a directory part and a name part. */ + base_name = strrchr (canonical, '/'); + if (base_name) + { + size_t dirlen = (1+ base_name) - canonical; + + dir = MALLOC (char, 1+ dirlen); + if (!dir) + { + ++errors; + goto cleanup; + } + + strncpy (dir, canonical, dirlen); + dir[dirlen] = LT_EOS_CHAR; + + ++base_name; + } + else + MEMREASSIGN (base_name, canonical); + + assert (base_name && *base_name); + + ext = strrchr (base_name, '.'); + if (!ext) + { + ext = base_name + LT_STRLEN (base_name); + } + + /* extract the module name from the file name */ + name = MALLOC (char, ext - base_name + 1); + if (!name) + { + ++errors; + goto cleanup; + } + + /* canonicalize the module name */ + { + int i; + for (i = 0; i < ext - base_name; ++i) + { + if (isalnum ((unsigned char)(base_name[i]))) + { + name[i] = base_name[i]; + } + else + { + name[i] = '_'; + } + } + name[ext - base_name] = LT_EOS_CHAR; + } + + /* Before trawling through the filesystem in search of a module, + check whether we are opening a preloaded module. */ + if (!dir) + { + const lt_dlvtable *vtable = lt_dlloader_find ("lt_preopen"); + + if (vtable) + { + /* libprefix + name + "." + libext + NULL */ + archive_name = MALLOC (char, strlen (libprefix) + LT_STRLEN (name) + strlen (libext) + 2); + *phandle = (lt_dlhandle) lt__zalloc (sizeof (struct lt__handle)); + + if ((*phandle == NULL) || (archive_name == NULL)) + { + ++errors; + goto cleanup; + } + newhandle = *phandle; + + /* Preloaded modules are always named according to their old + archive name. */ + if (strncmp(name, "lib", 3) == 0) + { + sprintf (archive_name, "%s%s.%s", libprefix, name + 3, libext); + } + else + { + sprintf (archive_name, "%s.%s", name, libext); + } + + if (tryall_dlopen (&newhandle, archive_name, advise, vtable) == 0) + { + goto register_handle; + } + + /* If we're still here, there was no matching preloaded module, + so put things back as we found them, and continue searching. */ + FREE (*phandle); + newhandle = NULL; + } + } + + /* If we are allowing only preloaded modules, and we didn't find + anything yet, give up on the search here. */ + if (advise && advise->try_preload_only) + { + goto cleanup; + } + + /* Check whether we are opening a libtool module (.la extension). */ + if (ext && streq (ext, archive_ext)) + { + /* this seems to be a libtool module */ + FILE * file = 0; + char * dlname = 0; + char * old_name = 0; + char * libdir = 0; + char * deplibs = 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; + + /* Now try to open the .la file. If there is no directory name + component, try to find it first in user_search_path and then other + prescribed paths. Otherwise (or in any case if the module was not + yet found) try opening just the module name as passed. */ + if (!dir) + { + const char *search_path = user_search_path; + + if (search_path) + file = find_file (user_search_path, base_name, &dir); + + if (!file) + { + search_path = getenv (LTDL_SEARCHPATH_VAR); + if (search_path) + file = find_file (search_path, base_name, &dir); + } + +#if defined(LT_MODULE_PATH_VAR) + if (!file) + { + search_path = getenv (LT_MODULE_PATH_VAR); + if (search_path) + file = find_file (search_path, base_name, &dir); + } +#endif +#if defined(LT_DLSEARCH_PATH) + if (!file && *sys_dlsearch_path) + { + file = find_file (sys_dlsearch_path, base_name, &dir); + } +#endif + } + else + { + file = fopen (attempt, LT_READTEXT_MODE); + } + + /* If we didn't find the file by now, it really isn't there. Set + the status flag, and bail out. */ + if (!file) + { + LT__SETERROR (FILE_NOT_FOUND); + ++errors; + goto cleanup; + } + + /* read the .la file */ + if (parse_dotla_file(file, &dlname, &libdir, &deplibs, + &old_name, &installed) != 0) + ++errors; + + fclose (file); + + /* allocate the handle */ + *phandle = (lt_dlhandle) lt__zalloc (sizeof (struct lt__handle)); + if (*phandle == 0) + ++errors; + + if (errors) + { + FREE (dlname); + FREE (old_name); + FREE (libdir); + FREE (deplibs); + FREE (*phandle); + goto cleanup; + } + + assert (*phandle); + + if (load_deplibs (*phandle, deplibs) == 0) + { + newhandle = *phandle; + /* find_module may replace newhandle */ + if (find_module (&newhandle, dir, libdir, dlname, old_name, + installed, advise)) + { + unload_deplibs (*phandle); + ++errors; + } + } + else + { + ++errors; + } + + FREE (dlname); + FREE (old_name); + FREE (libdir); + FREE (deplibs); + + if (errors) + { + FREE (*phandle); + goto cleanup; + } + + if (*phandle != newhandle) + { + unload_deplibs (*phandle); + } + } + else + { + /* not a libtool module */ + *phandle = (lt_dlhandle) lt__zalloc (sizeof (struct lt__handle)); + if (*phandle == 0) + { + ++errors; + goto cleanup; + } + + newhandle = *phandle; + + /* If the module has no directory name component, try to find it + first in user_search_path and then other prescribed paths. + Otherwise (or in any case if the module was not yet found) try + opening just the module name as passed. */ + if ((dir || (!find_handle (user_search_path, base_name, + &newhandle, advise) + && !find_handle (getenv (LTDL_SEARCHPATH_VAR), base_name, + &newhandle, advise) +#if defined(LT_MODULE_PATH_VAR) + && !find_handle (getenv (LT_MODULE_PATH_VAR), base_name, + &newhandle, advise) +#endif +#if defined(LT_DLSEARCH_PATH) + && !find_handle (sys_dlsearch_path, base_name, + &newhandle, advise) +#endif + ))) + { + if (tryall_dlopen (&newhandle, attempt, advise, 0) != 0) + { + newhandle = NULL; + } + } + + if (!newhandle) + { + FREE (*phandle); + ++errors; + goto cleanup; + } + } + + register_handle: + MEMREASSIGN (*phandle, newhandle); + + if ((*phandle)->info.ref_count == 0) + { + (*phandle)->info.ref_count = 1; + MEMREASSIGN ((*phandle)->info.name, name); + + (*phandle)->next = handles; + handles = *phandle; + } + + LT__SETERRORSTR (saved_error); + + cleanup: + FREE (dir); + FREE (attempt); + FREE (name); + if (!canonical) /* was MEMREASSIGNed */ + FREE (base_name); + FREE (canonical); + FREE (archive_name); + + return errors; +} + + +/* If the last error message stored was `FILE_NOT_FOUND', then return + non-zero. */ +static int +file_not_found (void) +{ + const char *error = 0; + + LT__GETERROR (error); + if (error == LT__STRERROR (FILE_NOT_FOUND)) + return 1; + + return 0; +} + + +/* Unless FILENAME already bears a suitable library extension, then + return 0. */ +static int +has_library_ext (const char *filename) +{ + const char * ext = 0; + + assert (filename); + + ext = strrchr (filename, '.'); + + if (ext && ((streq (ext, archive_ext)) +#if defined(LT_MODULE_EXT) + || (streq (ext, shlib_ext)) +#endif +#if defined(LT_SHARED_EXT) + || (streq (ext, shared_ext)) +#endif + )) + { + return 1; + } -#ifdef _WIN32 + return 0; +} -/* dynamic linking for Win32 */ -#include +/* Initialise and configure a user lt_dladvise opaque object. */ -static int -sys_wll_init LTDL_PARAMS((void)) +int +lt_dladvise_init (lt_dladvise *padvise) { - return 0; + lt_dladvise advise = (lt_dladvise) lt__zalloc (sizeof (struct lt__advise)); + *padvise = advise; + return (advise ? 0 : 1); } -static int -sys_wll_exit LTDL_PARAMS((void)) +int +lt_dladvise_destroy (lt_dladvise *padvise) { - return 0; + if (padvise) + FREE(*padvise); + return 0; } -/* Forward declaration; required to implement handle search below. */ -static lt_dlhandle handles; - -static int -sys_wll_open (handle, filename) - lt_dlhandle handle; - const char *filename; -{ - lt_dlhandle cur; - char *searchname = NULL; - char *ext = strrchr(filename, '.'); - - if (ext) { - /* FILENAME already has an extension. */ - searchname = strdup(filename); - } else { - /* Append a `.' to stop Windows from adding an - implicit `.dll' extension. */ - searchname = (char*)lt_dlmalloc(2+ strlen(filename)); - strcpy(searchname, filename); - strcat(searchname, "."); - } - - handle->handle = LoadLibrary(searchname); - lt_dlfree(searchname); - - /* libltdl expects this function to fail if it is unable - to physically load the library. Sadly, LoadLibrary - will search the loaded libraries for a match and return - one of them if the path search load fails. - - We check whether LoadLibrary is returning a handle to - an already loaded module, and simulate failure if we - find one. */ - cur = handles; - while (cur) { - if (!cur->handle) { - cur = 0; - break; - } - if (cur->handle == handle->handle) - break; - cur = cur->next; - } +int +lt_dladvise_ext (lt_dladvise *padvise) +{ + assert (padvise && *padvise); + (*padvise)->try_ext = 1; + return 0; +} - if (cur || !handle->handle) { - last_error = cannot_open_error; - return 1; - } +int +lt_dladvise_resident (lt_dladvise *padvise) +{ + assert (padvise && *padvise); + (*padvise)->is_resident = 1; + return 0; +} - return 0; +int +lt_dladvise_local (lt_dladvise *padvise) +{ + assert (padvise && *padvise); + (*padvise)->is_symlocal = 1; + return 0; } -static int -sys_wll_close (handle) - lt_dlhandle handle; +int +lt_dladvise_global (lt_dladvise *padvise) { - if (FreeLibrary(handle->handle) == 0) { - last_error = cannot_close_error; - return 1; - } - return 0; + assert (padvise && *padvise); + (*padvise)->is_symglobal = 1; + return 0; } -static lt_ptr_t -sys_wll_sym (handle, symbol) - lt_dlhandle handle; - const char *symbol; +int +lt_dladvise_preload (lt_dladvise *padvise) { - lt_ptr_t address = GetProcAddress(handle->handle, symbol); - - if (!address) - last_error = symbol_error; - return address; + assert (padvise && *padvise); + (*padvise)->try_preload_only = 1; + return 0; } -static -lt_dltype_t -sys_wll = { LTDL_TYPE_TOP, 0, sys_wll_init, sys_wll_exit, - sys_wll_open, sys_wll_close, sys_wll_sym }; +/* Libtool-1.5.x interface for loading a new module named FILENAME. */ +lt_dlhandle +lt_dlopen (const char *filename) +{ + return lt_dlopenadvise (filename, NULL); +} -#undef LTDL_TYPE_TOP -#define LTDL_TYPE_TOP &sys_wll -#endif +/* If FILENAME has an ARCHIVE_EXT or MODULE_EXT extension, try to + open the FILENAME as passed. Otherwise try appending ARCHIVE_EXT, + and if a file is still not found try again with MODULE_EXT appended + instead. */ +lt_dlhandle +lt_dlopenext (const char *filename) +{ + lt_dlhandle handle = 0; + lt_dladvise advise; -#ifdef __BEOS__ + if (!lt_dladvise_init (&advise) && !lt_dladvise_ext (&advise)) + handle = lt_dlopenadvise (filename, advise); -/* dynamic linking for BeOS */ + lt_dladvise_destroy (&advise); + return handle; +} -#include -static int -sys_bedl_init LTDL_PARAMS((void)) +lt_dlhandle +lt_dlopenadvise (const char *filename, lt_dladvise advise) { - return 0; + lt_dlhandle handle = 0; + int errors = 0; + const char * saved_error = 0; + + LT__GETERROR (saved_error); + + /* Can't have symbols hidden and visible at the same time! */ + if (advise && advise->is_symlocal && advise->is_symglobal) + { + LT__SETERROR (CONFLICTING_FLAGS); + return 0; + } + + if (!filename + || !advise + || !advise->try_ext + || has_library_ext (filename)) + { + /* Just incase we missed a code path in try_dlopen() that reports + an error, but forgot to reset handle... */ + if (try_dlopen (&handle, filename, NULL, advise) != 0) + return 0; + + return handle; + } + else if (filename && *filename) + { + + /* First try appending ARCHIVE_EXT. */ + errors += try_dlopen (&handle, filename, archive_ext, advise); + + /* If we found FILENAME, stop searching -- whether we were able to + load the file as a module or not. If the file exists but loading + failed, it is better to return an error message here than to + report FILE_NOT_FOUND when the alternatives (foo.so etc) are not + in the module search path. */ + if (handle || ((errors > 0) && !file_not_found ())) + return handle; + +#if defined(LT_MODULE_EXT) + /* Try appending SHLIB_EXT. */ + LT__SETERRORSTR (saved_error); + errors = try_dlopen (&handle, filename, shlib_ext, advise); + + /* As before, if the file was found but loading failed, return now + with the current error message. */ + if (handle || ((errors > 0) && !file_not_found ())) + return handle; +#endif + +#if defined(LT_SHARED_EXT) + /* Try appending SHARED_EXT. */ + LT__SETERRORSTR (saved_error); + errors = try_dlopen (&handle, filename, shared_ext, advise); + + /* As before, if the file was found but loading failed, return now + with the current error message. */ + if (handle || ((errors > 0) && !file_not_found ())) + return handle; +#endif + } + + /* Still here? Then we really did fail to locate any of the file + names we tried. */ + LT__SETERROR (FILE_NOT_FOUND); + return 0; } + static int -sys_bedl_exit LTDL_PARAMS((void)) +lt_argz_insert (char **pargz, size_t *pargz_len, char *before, + const char *entry) { - return 0; -} + error_t error; -static int -sys_bedl_open (handle, filename) - lt_dlhandle handle; - const char *filename; -{ - image_id image = 0; - - if (filename) { - image = load_add_on(filename); - } else { - image_info info; - int32 cookie = 0; - if (get_next_image_info(0, &cookie, &info) == B_OK) - image = load_add_on(info.name); - } - if (image <= 0) { - last_error = cannot_open_error; - return 1; + /* Prior to Sep 8, 2005, newlib had a bug where argz_insert(pargz, + pargz_len, NULL, entry) failed with EINVAL. */ + if (before) + error = argz_insert (pargz, pargz_len, before, entry); + else + error = argz_append (pargz, pargz_len, entry, 1 + strlen (entry)); + + if (error) + { + switch (error) + { + case ENOMEM: + LT__SETERROR (NO_MEMORY); + break; + default: + LT__SETERROR (UNKNOWN); + break; } - handle->handle = (void*) image; - return 0; + return 1; + } + + return 0; } static int -sys_bedl_close (handle) - lt_dlhandle handle; +lt_argz_insertinorder (char **pargz, size_t *pargz_len, const char *entry) { - if (unload_add_on((image_id)handle->handle) != B_OK) { - last_error = cannot_close_error; - return 1; - } - return 0; + char *before = 0; + + assert (pargz); + assert (pargz_len); + assert (entry && *entry); + + if (*pargz) + while ((before = argz_next (*pargz, *pargz_len, before))) + { + int cmp = strcmp (entry, before); + + if (cmp < 0) break; + if (cmp == 0) return 0; /* No duplicates! */ + } + + return lt_argz_insert (pargz, pargz_len, before, entry); } -static lt_ptr_t -sys_bedl_sym (handle, symbol) - lt_dlhandle handle; - const char *symbol; +static int +lt_argz_insertdir (char **pargz, size_t *pargz_len, const char *dirnam, + struct dirent *dp) { - lt_ptr_t address = 0; - image_id image = (image_id)handle->handle; - - if (get_image_symbol(image, symbol, B_SYMBOL_TYPE_ANY, - &address) != B_OK) { - last_error = symbol_error; - return 0; + char *buf = 0; + size_t buf_len = 0; + char *end = 0; + size_t end_offset = 0; + size_t dir_len = 0; + int errors = 0; + + assert (pargz); + assert (pargz_len); + assert (dp); + + dir_len = LT_STRLEN (dirnam); + end = dp->d_name + D_NAMLEN(dp); + + /* Ignore version numbers. */ + { + char *p; + for (p = end; p -1 > dp->d_name; --p) + if (strchr (".0123456789", p[-1]) == 0) + break; + + if (*p == '.') + end = p; + } + + /* Ignore filename extension. */ + { + char *p; + for (p = end -1; p > dp->d_name; --p) + if (*p == '.') + { + end = p; + break; } - return address; -} + } -static -lt_dltype_t -sys_bedl = { LTDL_TYPE_TOP, 0, sys_bedl_init, sys_bedl_exit, - sys_bedl_open, sys_bedl_close, sys_bedl_sym }; + /* Prepend the directory name. */ + end_offset = end - dp->d_name; + buf_len = dir_len + 1+ end_offset; + buf = MALLOC (char, 1+ buf_len); + if (!buf) + return ++errors; -#undef LTDL_TYPE_TOP -#define LTDL_TYPE_TOP &sys_bedl + assert (buf); -#endif + strcpy (buf, dirnam); + strcat (buf, "/"); + strncat (buf, dp->d_name, end_offset); + buf[buf_len] = LT_EOS_CHAR; -/* emulate dynamic linking using preloaded_symbols */ + /* Try to insert (in order) into ARGZ/ARGZ_LEN. */ + if (lt_argz_insertinorder (pargz, pargz_len, buf) != 0) + ++errors; -typedef struct lt_dlsymlists_t { - struct lt_dlsymlists_t *next; - const lt_dlsymlist *syms; -} lt_dlsymlists_t; + FREE (buf); -static const lt_dlsymlist *default_preloaded_symbols = 0; -static lt_dlsymlists_t *preloaded_symbols = 0; + return errors; +} static int -presym_init LTDL_PARAMS((void)) +list_files_by_dir (const char *dirnam, char **pargz, size_t *pargz_len) { - preloaded_symbols = 0; - if (default_preloaded_symbols) - return lt_dlpreload(default_preloaded_symbols); - return 0; + DIR *dirp = 0; + int errors = 0; + + assert (dirnam && *dirnam); + assert (pargz); + assert (pargz_len); + assert (dirnam[LT_STRLEN(dirnam) -1] != '/'); + + dirp = opendir (dirnam); + if (dirp) + { + struct dirent *dp = 0; + + while ((dp = readdir (dirp))) + if (dp->d_name[0] != '.') + if (lt_argz_insertdir (pargz, pargz_len, dirnam, dp)) + { + ++errors; + break; + } + + closedir (dirp); + } + else + ++errors; + + return errors; } + +/* If there are any files in DIRNAME, call the function passed in + DATA1 (with the name of each file and DATA2 as arguments). */ static int -presym_free_symlists LTDL_PARAMS((void)) +foreachfile_callback (char *dirname, void *data1, void *data2) { - lt_dlsymlists_t *lists = preloaded_symbols; - - while (lists) { - lt_dlsymlists_t *tmp = lists; - - lists = lists->next; - lt_dlfree(tmp); + file_worker_func *func = *(file_worker_func **) data1; + + int is_done = 0; + char *argz = 0; + size_t argz_len = 0; + + if (list_files_by_dir (dirname, &argz, &argz_len) != 0) + goto cleanup; + if (!argz) + goto cleanup; + + { + char *filename = 0; + while ((filename = argz_next (argz, argz_len, filename))) + if ((is_done = (*func) (filename, data2))) + break; + } + + cleanup: + FREE (argz); + + return is_done; +} + + +/* Call FUNC for each unique extensionless file in SEARCH_PATH, along + with DATA. The filenames passed to FUNC would be suitable for + passing to lt_dlopenext. The extensions are stripped so that + individual modules do not generate several entries (e.g. libfoo.la, + libfoo.so, libfoo.so.1, libfoo.so.1.0.0). If SEARCH_PATH is NULL, + then the same directories that lt_dlopen would search are examined. */ +int +lt_dlforeachfile (const char *search_path, + int (*func) (const char *filename, void *data), + void *data) +{ + int is_done = 0; + file_worker_func **fpptr = &func; + + if (search_path) + { + /* If a specific path was passed, search only the directories + listed in it. */ + is_done = foreach_dirinpath (search_path, 0, + foreachfile_callback, fpptr, data); + } + else + { + /* Otherwise search the default paths. */ + is_done = foreach_dirinpath (user_search_path, 0, + foreachfile_callback, fpptr, data); + if (!is_done) + { + is_done = foreach_dirinpath (getenv(LTDL_SEARCHPATH_VAR), 0, + foreachfile_callback, fpptr, data); + } + +#if defined(LT_MODULE_PATH_VAR) + if (!is_done) + { + is_done = foreach_dirinpath (getenv(LT_MODULE_PATH_VAR), 0, + foreachfile_callback, fpptr, data); + } +#endif +#if defined(LT_DLSEARCH_PATH) + if (!is_done && *sys_dlsearch_path) + { + is_done = foreach_dirinpath (sys_dlsearch_path, 0, + foreachfile_callback, fpptr, data); } - preloaded_symbols = 0; - return 0; +#endif + } + + return is_done; } -static int -presym_exit LTDL_PARAMS((void)) +int +lt_dlclose (lt_dlhandle handle) { - presym_free_symlists(); - return 0; + lt_dlhandle cur, last; + int errors = 0; + + /* check whether the handle is valid */ + last = cur = handles; + while (cur && handle != cur) + { + last = cur; + cur = cur->next; + } + + if (!cur) + { + LT__SETERROR (INVALID_HANDLE); + ++errors; + goto done; + } + + cur = handle; + cur->info.ref_count--; + + /* Note that even with resident modules, we must track the ref_count + correctly incase the user decides to reset the residency flag + later (even though the API makes no provision for that at the + moment). */ + if (cur->info.ref_count <= 0 && !LT_DLIS_RESIDENT (cur)) + { + lt_user_data data = cur->vtable->dlloader_data; + + if (cur != handles) + { + last->next = cur->next; + } + else + { + handles = cur->next; + } + + errors += cur->vtable->module_close (data, cur->module); + errors += unload_deplibs (handle); + + /* It is up to the callers to free the data itself. */ + FREE (cur->interface_data); + + FREE (cur->info.filename); + FREE (cur->info.name); + FREE (cur); + + goto done; + } + + if (LT_DLIS_RESIDENT (handle)) + { + LT__SETERROR (CLOSE_RESIDENT_MODULE); + ++errors; + } + + done: + return errors; +} + +void * +lt_dlsym (lt_dlhandle place, const char *symbol) +{ + size_t lensym; + char lsym[LT_SYMBOL_LENGTH]; + char *sym; + void *address; + lt_user_data data; + lt_dlhandle handle; + + if (!place) + { + LT__SETERROR (INVALID_HANDLE); + return 0; + } + + handle = place; + + if (!symbol) + { + LT__SETERROR (SYMBOL_NOT_FOUND); + return 0; + } + + lensym = LT_STRLEN (symbol) + LT_STRLEN (handle->vtable->sym_prefix) + + LT_STRLEN (handle->info.name); + + if (lensym + LT_SYMBOL_OVERHEAD < LT_SYMBOL_LENGTH) + { + sym = lsym; + } + else + { + sym = MALLOC (char, lensym + LT_SYMBOL_OVERHEAD + 1); + if (!sym) + { + LT__SETERROR (BUFFER_OVERFLOW); + return 0; + } + } + + data = handle->vtable->dlloader_data; + if (handle->info.name) + { + const char *saved_error; + + LT__GETERROR (saved_error); + + /* this is a libtool module */ + if (handle->vtable->sym_prefix) + { + strcpy(sym, handle->vtable->sym_prefix); + strcat(sym, handle->info.name); + } + else + { + strcpy(sym, handle->info.name); + } + + strcat(sym, "_LTX_"); + strcat(sym, symbol); + + /* try "modulename_LTX_symbol" */ + address = handle->vtable->find_sym (data, handle->module, sym); + if (address) + { + if (sym != lsym) + { + FREE (sym); + } + return address; + } + LT__SETERRORSTR (saved_error); + } + + /* otherwise try "symbol" */ + if (handle->vtable->sym_prefix) + { + strcpy(sym, handle->vtable->sym_prefix); + strcat(sym, symbol); + } + else + { + strcpy(sym, symbol); + } + + address = handle->vtable->find_sym (data, handle->module, sym); + if (sym != lsym) + { + FREE (sym); + } + + return address; } -static int -presym_add_symlist (preloaded) - const lt_dlsymlist *preloaded; +const char * +lt_dlerror (void) { - 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; -} + const char *error; -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; + LT__GETERROR (error); + LT__SETERRORSTR (0); + + return error; } static int -presym_close (handle) - lt_dlhandle handle; +lt_dlpath_insertdir (char **ppath, char *before, const char *dir) { - /* Just to silence gcc -Wall */ - handle = 0; - return 0; -} + int errors = 0; + char *canonical = 0; + char *argz = 0; + size_t argz_len = 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; + assert (ppath); + assert (dir && *dir); + + if (canonicalize_path (dir, &canonical) != 0) + { + ++errors; + goto cleanup; + } + + assert (canonical && *canonical); + + /* If *PPATH is empty, set it to DIR. */ + if (*ppath == 0) + { + assert (!before); /* BEFORE cannot be set without PPATH. */ + assert (dir); /* Without DIR, don't call this function! */ + + *ppath = lt__strdup (dir); + if (*ppath == 0) + ++errors; + + goto cleanup; + } + + assert (ppath && *ppath); + + if (argzize_path (*ppath, &argz, &argz_len) != 0) + { + ++errors; + goto cleanup; + } + + /* Convert BEFORE into an equivalent offset into ARGZ. This only works + if *PPATH is already canonicalized, and hence does not change length + with respect to ARGZ. We canonicalize each entry as it is added to + the search path, and don't call this function with (uncanonicalized) + user paths, so this is a fair assumption. */ + if (before) + { + assert (*ppath <= before); + assert ((int) (before - *ppath) <= (int) strlen (*ppath)); + + before = before - *ppath + argz; + } + + if (lt_argz_insert (&argz, &argz_len, before, dir) != 0) + { + ++errors; + goto cleanup; + } + + argz_stringify (argz, argz_len, LT_PATHSEP_CHAR); + MEMREASSIGN(*ppath, argz); + + cleanup: + FREE (argz); + FREE (canonical); + + return errors; } -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; +int +lt_dladdsearchdir (const char *search_dir) +{ + int errors = 0; + + if (search_dir && *search_dir) + { + if (lt_dlpath_insertdir (&user_search_path, 0, search_dir) != 0) + ++errors; + } -static lt_dltype_t *types = LTDL_TYPE_TOP; -#undef LTDL_TYPE_TOP + return errors; +} int -lt_dlinit LTDL_PARAMS((void)) +lt_dlinsertsearchdir (const char *before, const char *search_dir) { - /* 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; + int errors = 0; + + if (before) + { + if ((before < user_search_path) + || (before >= user_search_path + LT_STRLEN (user_search_path))) + { + LT__SETERROR (INVALID_POSITION); + return 1; + } + } + + if (search_dir && *search_dir) + { + if (lt_dlpath_insertdir (&user_search_path, + (char *) before, search_dir) != 0) + { + ++errors; } - last_error = 0; - initialized = 1; - return 0; + } + + return errors; } int -lt_dlpreload (preloaded) - const lt_dlsymlist *preloaded; +lt_dlsetsearchpath (const char *search_path) { - if (preloaded) - return presym_add_symlist(preloaded); - presym_free_symlists(); - if (default_preloaded_symbols) - return lt_dlpreload(default_preloaded_symbols); - return 0; + int errors = 0; + + FREE (user_search_path); + + if (!search_path || !LT_STRLEN (search_path)) + { + return errors; + } + + if (canonicalize_path (search_path, &user_search_path) != 0) + ++errors; + + return errors; } -int -lt_dlpreload_default (preloaded) - const lt_dlsymlist *preloaded; +const char * +lt_dlgetsearchpath (void) { - default_preloaded_symbols = preloaded; - return 0; + const char *saved_path; + + saved_path = user_search_path; + + return saved_path; } int -lt_dlexit LTDL_PARAMS((void)) +lt_dlmakeresident (lt_dlhandle handle) { - /* 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; -} + int errors = 0; -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; -} + if (!handle) + { + LT__SETERROR (INVALID_HANDLE); + ++errors; + } + else + { + handle->info.is_resident = 1; + } -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; + return errors; } -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; -} +int +lt_dlisresident (lt_dlhandle handle) +{ + if (!handle) + { + LT__SETERROR (INVALID_HANDLE); + return -1; + } -static int -load_deplibs(handle, deplibs) - lt_dlhandle handle; - const char *deplibs; -{ - /* FIXME: load deplibs */ - handle->depcount = 0; - handle->deplibs = 0; - /* Just to silence gcc -Wall */ - deplibs = 0; - return 0; + return LT_DLIS_RESIDENT (handle); } -static int -unload_deplibs(handle) - lt_dlhandle handle; + + +/* --- MODULE INFORMATION --- */ + +typedef struct { + const char *id_string; + lt_dlhandle_interface *iface; +} lt__interface_id; + +lt_dlinterface_id +lt_dlinterface_register (const char *id_string, lt_dlhandle_interface *iface) { - /* FIXME: unload deplibs */ - /* Just to silence gcc -Wall */ - handle = 0; - return 0; -} + lt__interface_id *interface_id = (lt__interface_id *) lt__malloc (sizeof *interface_id); -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; - const 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; + /* If lt__malloc fails, it will LT__SETERROR (NO_MEMORY), which + can then be detected with lt_dlerror() if we return 0. */ + if (interface_id) + { + interface_id->id_string = lt__strdup (id_string); + if (!interface_id->id_string) + FREE (interface_id); + else + interface_id->iface = iface; + } + + return (lt_dlinterface_id) interface_id; } -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; +void lt_dlinterface_free (lt_dlinterface_id key) +{ + lt__interface_id *interface_id = (lt__interface_id *)key; + FREE (interface_id->id_string); + FREE (interface_id); } -lt_dlhandle -lt_dlopen (filename) - const char *filename; +void * +lt_dlcaller_set_data (lt_dlinterface_id key, lt_dlhandle handle, void *data) { - 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; + int n_elements = 0; + void *stale = (void *) 0; + lt_dlhandle cur = handle; + int i; + + if (cur->interface_data) + while (cur->interface_data[n_elements].key) + ++n_elements; + + for (i = 0; i < n_elements; ++i) + { + if (cur->interface_data[i].key == key) + { + stale = cur->interface_data[i].data; + break; } - 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((int)(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; - } + } + + /* Ensure that there is enough room in this handle's interface_data + array to accept a new element (and an empty end marker). */ + if (i == n_elements) + { + lt_interface_data *temp + = REALLOC (lt_interface_data, cur->interface_data, 2+ n_elements); + + if (!temp) + { + stale = 0; + goto done; } -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; + cur->interface_data = temp; + + /* We only need this if we needed to allocate a new interface_data. */ + cur->interface_data[i].key = key; + cur->interface_data[1+ i].key = 0; + } + + cur->interface_data[i].data = data; + + done: + return stale; } -int -lt_dlclose (handle) - lt_dlhandle handle; +void * +lt_dlcaller_get_data (lt_dlinterface_id key, 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; -} + void *result = (void *) 0; + lt_dlhandle cur = handle; -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) { - const char *saved_error = last_error; - - /* 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; - } - last_error = saved_error; + /* Locate the index of the element with a matching KEY. */ + if (cur->interface_data) + { + int i; + for (i = 0; cur->interface_data[i].key; ++i) + { + if (cur->interface_data[i].key == key) + { + result = cur->interface_data[i].data; + break; + } } - /* 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; + } + + return result; } -const char * -lt_dlerror LTDL_PARAMS((void)) +const lt_dlinfo * +lt_dlgetinfo (lt_dlhandle handle) { - const char *error = last_error; - - last_error = 0; - return error; + if (!handle) + { + LT__SETERROR (INVALID_HANDLE); + return 0; + } + + return &(handle->info); } -int -lt_dladdsearchdir (search_dir) - const char *search_dir; + +lt_dlhandle +lt_dlhandle_iterate (lt_dlinterface_id iface, lt_dlhandle place) { - 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) + 2); /* ':' + '\0' == 2 */ - if (!new_search_path) { - last_error = memory_error; - return 1; - } - strcpy(new_search_path, user_search_path); - strcat(new_search_path, ":"); - strcat(new_search_path, search_dir); - lt_dlfree(user_search_path); - user_search_path = new_search_path; - } - return 0; + lt_dlhandle handle = place; + lt__interface_id *iterator = (lt__interface_id *) iface; + + assert (iface); /* iface is a required argument */ + + if (!handle) + handle = handles; + else + handle = handle->next; + + /* advance while the interface check fails */ + while (handle && iterator->iface + && ((*iterator->iface) (handle, iterator->id_string) != 0)) + { + handle = handle->next; + } + + return handle; } -int -lt_dlsetsearchpath (search_path) - const char *search_path; + +lt_dlhandle +lt_dlhandle_fetch (lt_dlinterface_id iface, const char *module_name) { - 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; + lt_dlhandle handle = 0; + + assert (iface); /* iface is a required argument */ + + while ((handle = lt_dlhandle_iterate (iface, handle))) + { + lt_dlhandle cur = handle; + if (cur && cur->info.name && streq (cur->info.name, module_name)) + break; + } + + return handle; } -const char * -lt_dlgetsearchpath LTDL_PARAMS((void)) + +int +lt_dlhandle_map (lt_dlinterface_id iface, + int (*func) (lt_dlhandle handle, void *data), void *data) { - return user_search_path; + lt__interface_id *iterator = (lt__interface_id *) iface; + lt_dlhandle cur = handles; + + assert (iface); /* iface is a required argument */ + + while (cur) + { + int errorcode = 0; + + /* advance while the interface check fails */ + while (cur && iterator->iface + && ((*iterator->iface) (cur, iterator->id_string) != 0)) + { + cur = cur->next; + } + + if ((errorcode = (*func) (cur, data)) != 0) + return errorcode; + } + + return 0; }