--- a/sim/ucsim/libltdl/ltdl.c +++ b/sim/ucsim/libltdl/ltdl.c @@ -1,1821 +1,267 @@ /* ltdl.c -- system independent dlopen wrapper - Copyright (C) 1998, 1999, 2000 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 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 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 it 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, -but WITHOUT ANY WARRANTY; without even the implied warranty of -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 Lesser 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 - -*/ - -#if HAVE_CONFIG_H -# include -#endif - -#if HAVE_UNISTD_H -# include -#endif - -#if HAVE_STDIO_H -# include -#endif - -#if HAVE_STDLIB_H -# include -#endif - -#if HAVE_STRING_H -# include -#else -# if HAVE_STRINGS_H -# include -# endif -#endif - -#if HAVE_CTYPE_H -# include -#endif - -#if HAVE_MALLOC_H -# include -#endif - -#if HAVE_MEMORY_H -# include -#endif - -#if HAVE_ERRNO_H -# include -#endif - -#if HAVE_DIRENT_H -# include -# define LT_D_NAMLEN(dirent) (strlen((dirent)->d_name)) -#else -# define dirent direct -# define LT_D_NAMLEN(dirent) ((dirent)->d_namlen) -# if HAVE_SYS_NDIR_H -# include -# endif -# if HAVE_SYS_DIR_H -# include -# endif -# if HAVE_NDIR_H -# include -# endif -#endif - -#if HAVE_ARGZ_H -# include -#endif - -#if HAVE_ASSERT_H -# include -#else -# define assert(arg) ((void) 0) -#endif - -#include "ltdl.h" - -#if WITH_DMALLOC -# include -#endif - - - - -/* --- WINDOWS SUPPORT --- */ - - -#ifdef DLL_EXPORT -# define LT_GLOBAL_DATA __declspec(dllexport) -#else -# define LT_GLOBAL_DATA -#endif - -/* fopen() mode flags for reading a text file */ -#undef LT_READTEXT_MODE -#ifdef __WINDOWS__ -# define LT_READTEXT_MODE "rt" -#else -# define LT_READTEXT_MODE "r" -#endif - - - - -/* --- MANIFEST CONSTANTS --- */ - - -/* Standard libltdl search path environment variable name */ -#undef LTDL_SEARCHPATH_VAR -#define LTDL_SEARCHPATH_VAR "LTDL_LIBRARY_PATH" - -/* Standard libtool archive file extension. */ -#undef LTDL_ARCHIVE_EXT -#define LTDL_ARCHIVE_EXT ".la" - -/* max. filename length */ -#ifndef LT_FILENAME_MAX -# define LT_FILENAME_MAX 1024 -#endif - -/* This is the maximum symbol size that won't require malloc/free */ -#undef LT_SYMBOL_LENGTH -#define LT_SYMBOL_LENGTH 128 - -/* This accounts for the _LTX_ separator */ -#undef LT_SYMBOL_OVERHEAD -#define LT_SYMBOL_OVERHEAD 5 - - - - -/* --- MEMORY HANDLING --- */ - - -/* These are the functions used internally. In addition to making - use of the associated function pointers above, they also perform - error handling. */ -static char *lt_estrdup LT_PARAMS((const char *str)); -static lt_ptr lt_emalloc LT_PARAMS((size_t size)); -static lt_ptr lt_erealloc LT_PARAMS((lt_ptr addr, size_t size)); - -static lt_ptr rpl_realloc LT_PARAMS((lt_ptr ptr, size_t size)); - -/* These are the pointers that can be changed by the caller: */ -LT_GLOBAL_DATA lt_ptr (*lt_dlmalloc) LT_PARAMS((size_t size)) - = (lt_ptr (*) LT_PARAMS((size_t))) malloc; -LT_GLOBAL_DATA lt_ptr (*lt_dlrealloc) LT_PARAMS((lt_ptr ptr, size_t size)) - = (lt_ptr (*) LT_PARAMS((lt_ptr, size_t))) rpl_realloc; -LT_GLOBAL_DATA void (*lt_dlfree) LT_PARAMS((lt_ptr ptr)) - = (void (*) LT_PARAMS((lt_ptr))) free; - -/* The following macros reduce the amount of typing needed to cast - assigned memory. */ -#if WITH_DMALLOC - -#define LT_DLMALLOC(tp, n) ((tp *) xmalloc ((n) * sizeof(tp))) -#define LT_DLREALLOC(tp, p, n) ((tp *) xrealloc ((p), (n) * sizeof(tp))) -#define LT_DLFREE(p) \ - LT_STMT_START { if (p) (p) = (xfree (p), (lt_ptr) 0); } LT_STMT_END - -#define LT_EMALLOC(tp, n) ((tp *) xmalloc ((n) * sizeof(tp))) -#define LT_EREALLOC(tp, p, n) ((tp *) xrealloc ((p), (n) * sizeof(tp))) - -#else - -#define LT_DLMALLOC(tp, n) ((tp *) lt_dlmalloc ((n) * sizeof(tp))) -#define LT_DLREALLOC(tp, p, n) ((tp *) rpl_realloc ((p), (n) * sizeof(tp))) -#define LT_DLFREE(p) \ - LT_STMT_START { if (p) (p) = (lt_dlfree (p), (lt_ptr) 0); } LT_STMT_END - -#define LT_EMALLOC(tp, n) ((tp *) lt_emalloc ((n) * sizeof(tp))) -#define LT_EREALLOC(tp, p, n) ((tp *) lt_erealloc ((p), (n) * sizeof(tp))) - -#endif - -#define LT_DLMEM_REASSIGN(p, q) LT_STMT_START { \ - if ((p) != (q)) { if (p) lt_dlfree (p); (p) = (q); (q) = 0; } \ - } LT_STMT_END - - -/* --- REPLACEMENT FUNCTIONS --- */ - - -#undef strdup -#define strdup rpl_strdup - -static char *strdup LT_PARAMS((const char *str)); - -static char * -strdup(str) - const char *str; -{ - char *tmp = 0; - - if (str) - { - tmp = LT_DLMALLOC (char, 1+ strlen (str)); - if (tmp) - { - strcpy(tmp, str); - } - } - - return tmp; -} - - -#if ! HAVE_STRCMP - -#undef strcmp -#define strcmp rpl_strcmp - -static int strcmp LT_PARAMS((const char *str1, const char *str2)); - -static int -strcmp (str1, str2) - const char *str1; - const char *str2; -{ - if (str1 == str2) - return 0; - if (str1 == 0) - return -1; - if (str2 == 0) - return 1; - - for (;*str1 && *str2; ++str1, ++str2) - { - if (*str1 != *str2) - break; - } - - return (int)(*str1 - *str2); -} -#endif - - -#if ! HAVE_STRCHR - -# if HAVE_INDEX -# define strchr index -# else -# define strchr rpl_strchr - -static const char *strchr LT_PARAMS((const char *str, int ch)); - -static const char* -strchr(str, ch) - const char *str; - int ch; -{ - const char *p; - - for (p = str; *p != (char)ch && *p != LT_EOS_CHAR; ++p) - /*NOWORK*/; - - return (*p == (char)ch) ? p : 0; -} - -# endif -#endif /* !HAVE_STRCHR */ - - -#if ! HAVE_STRRCHR - -# if HAVE_RINDEX -# define strrchr rindex -# else -# define strrchr rpl_strrchr - -static const char *strrchr LT_PARAMS((const char *str, int ch)); - -static const char* -strrchr(str, ch) - const char *str; - int ch; -{ - const char *p, *q = 0; - - for (p = str; *p != LT_EOS_CHAR; ++p) - { - if (*p == (char) ch) - { - q = p; - } - } - - return q; -} - -# endif -#endif - -/* NOTE: Neither bcopy nor the memcpy implementation below can - reliably handle copying in overlapping areas of memory. Use - memmove (for which there is a fallback implmentation below) - if you need that behaviour. */ -#if ! HAVE_MEMCPY - -# if HAVE_BCOPY -# define memcpy(dest, src, size) bcopy (src, dest, size) -# else -# define memcpy rpl_memcpy - -static lt_ptr memcpy LT_PARAMS((lt_ptr dest, const lt_ptr src, size_t size)); - -static lt_ptr -memcpy (dest, src, size) - lt_ptr dest; - const lt_ptr src; - size_t size; -{ - size_t i = 0; - - for (i = 0; i < size; ++i) - { - dest[i] = src[i]; - } - - return dest; -} - -# endif /* !HAVE_BCOPY */ -#endif /* !HAVE_MEMCPY */ - -#if ! HAVE_MEMMOVE -# define memmove rpl_memmove - -static lt_ptr memmove LT_PARAMS((lt_ptr dest, const lt_ptr src, size_t size)); - -static lt_ptr -memmove (dest, src, size) - lt_ptr dest; - const lt_ptr src; - size_t size; -{ - size_t i; - - if (dest < src) - for (i = 0; i < size; ++i) - { - dest[i] = src[i]; - } - else if (dest > src) - for (i = size -1; i >= 0; --i) - { - dest[i] = src[i]; - } - - return dest; -} - -#endif /* !HAVE_MEMMOVE */ - - -/* According to Alexandre Oliva , - ``realloc is not entirely portable'' - In any case we want to use the allocator supplied by the user without - burdening them with an lt_dlrealloc function pointer to maintain. - Instead implement our own version (with known boundary conditions) - using lt_dlmalloc and lt_dlfree. */ - -#undef realloc -#define realloc rpl_realloc - -static lt_ptr -realloc (ptr, size) - lt_ptr ptr; - size_t size; -{ - if (size == 0) - { - /* For zero or less bytes, free the original memory */ - if (ptr != 0) - { - lt_dlfree (ptr); - } - - return (lt_ptr) 0; - } - else if (ptr == 0) - { - /* Allow reallocation of a NULL pointer. */ - return lt_dlmalloc (size); - } - else - { - /* Allocate a new block, copy and free the old block. */ - lt_ptr mem = lt_dlmalloc (size); - - if (mem) - { - memcpy (mem, ptr, size); - lt_dlfree (ptr); - } - - /* Note that the contents of PTR are not damaged if there is - insufficient memory to realloc. */ - return mem; - } -} - - -#if ! HAVE_ARGZ_APPEND -# define argz_append rpl_argz_append - -static error_t argz_append LT_PARAMS((char **pargz, size_t *pargz_len, - const char *buf, size_t buf_len)); - -static error_t -argz_append (pargz, pargz_len, buf, buf_len) - char **pargz; - size_t *pargz_len; - const char *buf; - size_t buf_len; -{ - size_t argz_len; - char *argz; - - assert (pargz); - assert (pargz_len); - assert ((*pargz && *pargz_len) || (!*pargz && !*pargz_len)); - - /* If nothing needs to be appended, no more work is required. */ - if (buf_len == 0) - return 0; - - /* Ensure there is enough room to append BUF_LEN. */ - argz_len = *pargz_len + buf_len; - argz = LT_DLREALLOC (char, *pargz, argz_len); - if (!argz) - return ENOMEM; - - /* Copy characters from BUF after terminating '\0' in ARGZ. */ - memcpy (argz + *pargz_len, buf, buf_len); - - /* Assign new values. */ - *pargz = argz; - *pargz_len = argz_len; - - return 0; -} -#endif /* !HAVE_ARGZ_APPEND */ - - -#if ! HAVE_ARGZ_CREATE_SEP -# define argz_create_sep rpl_argz_create_sep - -static error_t argz_create_sep LT_PARAMS((const char *str, int delim, - char **pargz, size_t *pargz_len)); - -static error_t -argz_create_sep (str, delim, pargz, pargz_len) - const char *str; - int delim; - char **pargz; - size_t *pargz_len; -{ - size_t argz_len; - char *argz = 0; - - assert (str); - assert (pargz); - assert (pargz_len); - - /* Make a copy of STR, but replacing each occurence of - DELIM with '\0'. */ - argz_len = 1+ LT_STRLEN (str); - if (argz_len) - { - const char *p; - char *q; - - argz = LT_DLMALLOC (char, argz_len); - if (!argz) - return ENOMEM; - - for (p = str, q = argz; *p != LT_EOS_CHAR; ++p) - { - if (*p == delim) - { - /* Ignore leading delimiters, and fold consecutive - delimiters in STR into a single '\0' in ARGZ. */ - if ((q > argz) && (q[-1] != LT_EOS_CHAR)) - *q++ = LT_EOS_CHAR; - else - --argz_len; - } - else - *q++ = *p; - } - /* Copy terminating LT_EOS_CHAR. */ - *q = *p; - } - - /* If ARGZ_LEN has shrunk to nothing, release ARGZ's memory. */ - if (!argz_len) - LT_DLFREE (argz); - - /* Assign new values. */ - *pargz = argz; - *pargz_len = argz_len; - - return 0; -} -#endif /* !HAVE_ARGZ_CREATE_SEP */ - - -#if ! HAVE_ARGZ_INSERT -# define argz_insert rpl_argz_insert - -static error_t argz_insert LT_PARAMS((char **pargz, size_t *pargz_len, - char *before, const char *entry)); - -static error_t -argz_insert (pargz, pargz_len, before, entry) - char **pargz; - size_t *pargz_len; - char *before; - const char *entry; -{ - assert (pargz); - assert (pargz_len); - assert (entry && *entry); - - /* Either PARGZ/PARGZ_LEN is empty and BEFORE is NULL, - or BEFORE points into an address within the ARGZ vector. */ - assert ((!*pargz && !*pargz_len && !before) - || ((*pargz <= before) && (before < (*pargz + *pargz_len)))); - - /* No BEFORE address indicates ENTRY should be inserted after the - current last element. */ - if (!before) - return argz_append (pargz, pargz_len, entry, 1+ LT_STRLEN (entry)); - - /* This probably indicates a programmer error, but to preserve - semantics, scan back to the start of an entry if BEFORE points - into the middle of it. */ - while ((before >= *pargz) && (before[-1] != LT_EOS_CHAR)) - --before; - - { - size_t entry_len = 1+ LT_STRLEN (entry); - size_t argz_len = *pargz_len + entry_len; - size_t offset = before - *pargz; - char *argz = LT_DLREALLOC (char, *pargz, argz_len); - - if (!argz) - return ENOMEM; - - /* Make BEFORE point to the equivalent offset in ARGZ that it - used to have in *PARGZ incase realloc() moved the block. */ - before = argz + offset; - - /* Move the ARGZ entries starting at BEFORE up into the new - space at the end -- making room to copy ENTRY into the - resulting gap. */ - memmove (before + entry_len, before, *pargz_len - offset); - memcpy (before, entry, entry_len); - - /* Assign new values. */ - *pargz = argz; - *pargz_len = argz_len; - } - - return 0; -} -#endif /* !HAVE_ARGZ_INSERT */ - - -#if ! HAVE_ARGZ_NEXT -# define argz_next rpl_argz_next - -static char *argz_next LT_PARAMS((char *argz, size_t argz_len, - const char *entry)); - -static char * -argz_next (argz, argz_len, entry) - char *argz; - size_t argz_len; - const char *entry; -{ - assert ((argz && argz_len) || (!argz && !argz_len)); - - if (entry) - { - /* Either ARGZ/ARGZ_LEN is empty, or ENTRY points into an address - within the ARGZ vector. */ - assert ((!argz && !argz_len) - || ((argz <= entry) && (entry < (argz + argz_len)))); - - /* Move to the char immediately after the terminating - '\0' of ENTRY. */ - entry = 1+ strchr (entry, LT_EOS_CHAR); - - /* Return either the new ENTRY, or else NULL if ARGZ is - exhausted. */ - return (entry >= argz + argz_len) ? 0 : (char *) entry; - } - else - { - /* This should probably be flagged as a programmer error, - since starting an argz_next loop with the iterator set - to ARGZ is safer. To preserve semantics, handle the NULL - case by returning the start of ARGZ (if any). */ - if (argz_len > 0) - return argz; - else - return 0; - } -} -#endif /* !HAVE_ARGZ_NEXT */ - - - -#if ! HAVE_ARGZ_STRINGIFY -# define argz_stringify rpl_argz_stringify - -static void argz_stringify LT_PARAMS((char *argz, size_t argz_len, - int sep)); - -static void -argz_stringify (argz, argz_len, sep) - char *argz; - size_t argz_len; - int sep; -{ - assert ((argz && argz_len) || (!argz && !argz_len)); - - if (sep) - { - --argz_len; /* don't stringify the terminating EOS */ - while (--argz_len > 0) - { - if (argz[argz_len] == LT_EOS_CHAR) - argz[argz_len] = sep; - } - } -} -#endif /* !HAVE_ARGZ_STRINGIFY */ - - - - -/* --- TYPE DEFINITIONS -- */ - - -/* This type is used for the array of caller data sets in each handler. */ -typedef struct { - lt_dlcaller_id key; - lt_ptr data; -} lt_caller_data; - - - - -/* --- OPAQUE STRUCTURES DECLARED IN LTDL.H --- */ - - -/* Extract the diagnostic strings from the error table macro in the same - order as the enumerated indices in ltdl.h. */ - -static const char *lt_dlerror_strings[] = - { -#define LT_ERROR(name, diagnostic) (diagnostic), - lt_dlerror_table -#undef LT_ERROR - - 0 - }; - -/* This structure is used for the list of registered loaders. */ -struct lt_dlloader { - struct lt_dlloader *next; - const char *loader_name; /* identifying name for each loader */ - const char *sym_prefix; /* prefix for symbols */ - lt_module_open *module_open; - lt_module_close *module_close; - lt_find_sym *find_sym; - lt_dlloader_exit *dlloader_exit; - lt_user_data dlloader_data; -}; - -struct lt_dlhandle_struct { - struct lt_dlhandle_struct *next; - lt_dlloader *loader; /* dlopening interface */ - lt_dlinfo info; - int depcount; /* number of dependencies */ - lt_dlhandle *deplibs; /* dependencies */ - lt_module module; /* system module handle */ - lt_ptr system; /* system specific data */ - lt_caller_data *caller_data; /* per caller associated data */ - int flags; /* various boolean stats */ -}; - -/* Various boolean flags can be stored in the flags field of an - lt_dlhandle_struct... */ -#define LT_DLGET_FLAG(handle, flag) (((handle)->flags & (flag)) == (flag)) -#define LT_DLSET_FLAG(handle, flag) ((handle)->flags |= (flag)) - -#define LT_DLRESIDENT_FLAG (0x01 << 0) -/* ...add more flags here... */ - -#define LT_DLIS_RESIDENT(handle) LT_DLGET_FLAG(handle, LT_DLRESIDENT_FLAG) - - -#define LT_DLSTRERROR(name) lt_dlerror_strings[LT_CONC(LT_ERROR_,name)] - -static const char objdir[] = LTDL_OBJDIR; -static const char archive_ext[] = LTDL_ARCHIVE_EXT; -#ifdef LTDL_SHLIB_EXT -static const char shlib_ext[] = LTDL_SHLIB_EXT; -#endif -#ifdef LTDL_SYSSEARCHPATH -static const char sys_search_path[] = LTDL_SYSSEARCHPATH; -#endif - - - - -/* --- MUTEX LOCKING --- */ - - -/* Macros to make it easier to run the lock functions only if they have - been registered. The reason for the complicated lock macro is to - ensure that the stored error message from the last error is not - accidentally erased if the current function doesn't generate an - error of its own. */ -#define LT_DLMUTEX_LOCK() LT_STMT_START { \ - if (lt_dlmutex_lock_func) (*lt_dlmutex_lock_func)(); \ - } LT_STMT_END -#define LT_DLMUTEX_UNLOCK() LT_STMT_START { \ - if (lt_dlmutex_unlock_func) (*lt_dlmutex_unlock_func)();\ - } LT_STMT_END -#define LT_DLMUTEX_SETERROR(errormsg) LT_STMT_START { \ - if (lt_dlmutex_seterror_func) \ - (*lt_dlmutex_seterror_func) (errormsg); \ - else lt_dllast_error = (errormsg); } LT_STMT_END -#define LT_DLMUTEX_GETERROR(errormsg) LT_STMT_START { \ - if (lt_dlmutex_seterror_func) \ - (errormsg) = (*lt_dlmutex_geterror_func) (); \ - else (errormsg) = lt_dllast_error; } LT_STMT_END - -/* The mutex functions stored here are global, and are necessarily the - same for all threads that wish to share access to libltdl. */ -static lt_dlmutex_lock *lt_dlmutex_lock_func = 0; -static lt_dlmutex_unlock *lt_dlmutex_unlock_func = 0; -static lt_dlmutex_seterror *lt_dlmutex_seterror_func = 0; -static lt_dlmutex_geterror *lt_dlmutex_geterror_func = 0; -static const char *lt_dllast_error = 0; - - -/* Either set or reset the mutex functions. Either all the arguments must - be valid functions, or else all can be NULL to turn off locking entirely. - The registered functions should be manipulating a static global lock - from the lock() and unlock() callbacks, which needs to be reentrant. */ -int -lt_dlmutex_register (lock, unlock, seterror, geterror) - lt_dlmutex_lock *lock; - lt_dlmutex_unlock *unlock; - lt_dlmutex_seterror *seterror; - lt_dlmutex_geterror *geterror; -{ - lt_dlmutex_unlock *old_unlock = unlock; - int errors = 0; - - /* Lock using the old lock() callback, if any. */ - LT_DLMUTEX_LOCK (); - - if ((lock && unlock && seterror && geterror) - || !(lock || unlock || seterror || geterror)) - { - lt_dlmutex_lock_func = lock; - lt_dlmutex_unlock_func = unlock; - lt_dlmutex_geterror_func = geterror; - } - else - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_MUTEX_ARGS)); - ++errors; - } - - /* Use the old unlock() callback we saved earlier, if any. Otherwise - record any errors using internal storage. */ - if (old_unlock) - (*old_unlock) (); - - /* Return the number of errors encountered during the execution of - this function. */ - return errors; -} - - - - -/* --- ERROR HANDLING --- */ - - -static const char **user_error_strings = 0; -static int errorcount = LT_ERROR_MAX; - -int -lt_dladderror (diagnostic) - const char *diagnostic; -{ - int errindex = 0; - int result = -1; - const char **temp = (const char **) 0; - - assert (diagnostic); - - LT_DLMUTEX_LOCK (); - - errindex = errorcount - LT_ERROR_MAX; - temp = LT_EREALLOC (const char *, user_error_strings, 1 + errindex); - if (temp) - { - user_error_strings = temp; - user_error_strings[errindex] = diagnostic; - result = errorcount++; - } - - LT_DLMUTEX_UNLOCK (); - - return result; -} - -int -lt_dlseterror (errindex) - int errindex; -{ - int errors = 0; - - LT_DLMUTEX_LOCK (); - - if (errindex >= errorcount || errindex < 0) - { - /* Ack! Error setting the error message! */ - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_ERRORCODE)); - ++errors; - } - else if (errindex < LT_ERROR_MAX) - { - /* No error setting the error message! */ - LT_DLMUTEX_SETERROR (lt_dlerror_strings[errindex]); - } - else - { - /* No error setting the error message! */ - LT_DLMUTEX_SETERROR (user_error_strings[errindex - LT_ERROR_MAX]); - } - - LT_DLMUTEX_UNLOCK (); - - return errors; -} - -static lt_ptr -lt_emalloc (size) - size_t size; -{ - lt_ptr mem = lt_dlmalloc (size); - if (size && !mem) - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - return mem; -} - -static lt_ptr -lt_erealloc (addr, size) - lt_ptr addr; - size_t size; -{ - lt_ptr mem = realloc (addr, size); - if (size && !mem) - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - return mem; -} - -static char * -lt_estrdup (str) - const char *str; -{ - char *copy = strdup (str); - if (LT_STRLEN (str) && !copy) - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - return copy; -} - - - - -/* --- DLOPEN() INTERFACE LOADER --- */ - - -/* The Cygwin dlopen implementation prints a spurious error message to - stderr if its call to LoadLibrary() fails for any reason. We can - mitigate this by not using the Cygwin implementation, and falling - back to our own LoadLibrary() wrapper. */ -#if HAVE_LIBDL && !defined(__CYGWIN__) - -/* dynamic linking with dlopen/dlsym */ - -#if HAVE_DLFCN_H -# include -#endif - -#if HAVE_SYS_DL_H -# include -#endif - -#ifdef RTLD_GLOBAL -# define LT_GLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LT_GLOBAL DL_GLOBAL -# endif -#endif /* !RTLD_GLOBAL */ -#ifndef LT_GLOBAL -# define LT_GLOBAL 0 -#endif /* !LT_GLOBAL */ - -/* We may have to define LT_LAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LT_LAZY_OR_NOW -# ifdef RTLD_LAZY -# define LT_LAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LT_LAZY_OR_NOW DL_LAZY -# endif -# endif /* !RTLD_LAZY */ -#endif -#ifndef LT_LAZY_OR_NOW -# ifdef RTLD_NOW -# define LT_LAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LT_LAZY_OR_NOW DL_NOW -# endif -# endif /* !RTLD_NOW */ -#endif -#ifndef LT_LAZY_OR_NOW -# define LT_LAZY_OR_NOW 0 -#endif /* !LT_LAZY_OR_NOW */ - -#if HAVE_DLERROR -# define DLERROR(arg) dlerror () -#else -# define DLERROR(arg) LT_DLSTRERROR (arg) -#endif - -static lt_module -sys_dl_open (loader_data, filename) - lt_user_data loader_data; - const char *filename; -{ - lt_module module = dlopen (filename, LT_GLOBAL | LT_LAZY_OR_NOW); - - if (!module) - { - LT_DLMUTEX_SETERROR (DLERROR (CANNOT_OPEN)); - } - - return module; -} - -static int -sys_dl_close (loader_data, module) - lt_user_data loader_data; - lt_module module; -{ - int errors = 0; - - if (dlclose (module) != 0) - { - LT_DLMUTEX_SETERROR (DLERROR (CANNOT_CLOSE)); - ++errors; - } - - return errors; -} - -static lt_ptr -sys_dl_sym (loader_data, module, symbol) - lt_user_data loader_data; - lt_module module; - const char *symbol; -{ - lt_ptr address = dlsym (module, symbol); - - if (!address) - { - LT_DLMUTEX_SETERROR (DLERROR (SYMBOL_NOT_FOUND)); - } - - return address; -} - -static struct lt_user_dlloader sys_dl = - { -# ifdef NEED_USCORE - "_", -# else - 0, -# endif - sys_dl_open, sys_dl_close, sys_dl_sym, 0, 0 }; - - -#endif /* HAVE_LIBDL */ - - - -/* --- SHL_LOAD() INTERFACE LOADER --- */ - -#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 -#ifndef BIND_RESTRICTED -# define BIND_RESTRICTED 0 -#endif - -#define LT_BIND_FLAGS (BIND_IMMEDIATE | BIND_NONFATAL | DYNAMIC_PATH) - -static lt_module -sys_shl_open (loader_data, filename) - lt_user_data loader_data; - const char *filename; -{ - static shl_t self = (shl_t) 0; - lt_module module = shl_load (filename, LT_BIND_FLAGS, 0L); - - /* Since searching for a symbol against a NULL module handle will also - look in everything else that was already loaded and exported with - the -E compiler flag, we always cache a handle saved before any - modules are loaded. */ - if (!self) - { - lt_ptr address; - shl_findsym (&self, "main", TYPE_UNDEFINED, &address); - } - - if (!filename) - { - module = self; - } - else - { - module = shl_load (filename, LT_BIND_FLAGS, 0L); - - if (!module) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); - } - } - - return module; -} - -static int -sys_shl_close (loader_data, module) - lt_user_data loader_data; - lt_module module; -{ - int errors = 0; - - if (module && (shl_unload ((shl_t) (module)) != 0)) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); - ++errors; - } - - return errors; -} - -static lt_ptr -sys_shl_sym (loader_data, module, symbol) - lt_user_data loader_data; - lt_module module; - const char *symbol; -{ - lt_ptr address = 0; - - /* sys_shl_open should never return a NULL module handle */ - if (module == (lt_module) 0) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); - } - else if (!shl_findsym((shl_t*) &module, symbol, TYPE_UNDEFINED, &address)) - { - if (!address) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); - } - } - - return address; -} - -static struct lt_user_dlloader sys_shl = { - 0, sys_shl_open, sys_shl_close, sys_shl_sym, 0, 0 -}; - -#endif /* HAVE_SHL_LOAD */ - - - - -/* --- LOADLIBRARY() INTERFACE LOADER --- */ - -#ifdef __WINDOWS__ - -/* dynamic linking for Win32 */ - -#include - -/* Forward declaration; required to implement handle search below. */ -static lt_dlhandle handles; - -static lt_module -sys_wll_open (loader_data, filename) - lt_user_data loader_data; - const char *filename; -{ - lt_dlhandle cur; - lt_module module = 0; - const char *errormsg = 0; - char *searchname = 0; - char *ext; - char self_name_buf[MAX_PATH]; - - if (!filename) - { - /* Get the name of main module */ - *self_name_buf = 0; - GetModuleFileName (NULL, self_name_buf, sizeof (self_name_buf)); - filename = ext = self_name_buf; - } - else - { - ext = strrchr (filename, '.'); - } - - if (ext) - { - /* FILENAME already has an extension. */ - searchname = lt_estrdup (filename); - } - else - { - /* Append a `.' to stop Windows from adding an - implicit `.dll' extension. */ - searchname = LT_EMALLOC (char, 2+ LT_STRLEN (filename)); - if (searchname) - sprintf (searchname, "%s.", filename); - } - if (!searchname) - return 0; - -#if __CYGWIN__ - { - char wpath[MAX_PATH]; - cygwin_conv_to_full_win32_path(searchname, wpath); - module = LoadLibrary(wpath); - } -#else - module = LoadLibrary (searchname); -#endif - 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. */ - LT_DLMUTEX_LOCK (); - cur = handles; - while (cur) - { - if (!cur->module) - { - cur = 0; - break; - } - - if (cur->module == module) - { - break; - } - - cur = cur->next; - } - LT_DLMUTEX_UNLOCK (); - - if (cur || !module) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); - module = 0; - } - - return module; -} - -static int -sys_wll_close (loader_data, module) - lt_user_data loader_data; - lt_module module; -{ - int errors = 0; - - if (FreeLibrary(module) == 0) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); - ++errors; - } - - return errors; -} - -static lt_ptr -sys_wll_sym (loader_data, module, symbol) - lt_user_data loader_data; - lt_module module; - const char *symbol; -{ - lt_ptr address = GetProcAddress (module, symbol); - - if (!address) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); - } - - return address; -} - -static struct lt_user_dlloader sys_wll = { - 0, sys_wll_open, sys_wll_close, sys_wll_sym, 0, 0 -}; - -#endif /* __WINDOWS__ */ + Copyright (C) 1998, 1999, 2000, 2004, 2005, 2006, + 2007, 2008 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. - -/* --- LOAD_ADD_ON() INTERFACE LOADER --- */ - - -#ifdef __BEOS__ - -/* dynamic linking for BeOS */ - -#include - -static lt_module -sys_bedl_open (loader_data, filename) - lt_user_data loader_data; - 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) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); - image = 0; - } - - return (lt_module) image; -} - -static int -sys_bedl_close (loader_data, module) - lt_user_data loader_data; - lt_module module; -{ - int errors = 0; - - if (unload_add_on ((image_id) module) != B_OK) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); - ++errors; - } - - return errors; -} - -static lt_ptr -sys_bedl_sym (loader_data, module, symbol) - lt_user_data loader_data; - lt_module module; - const char *symbol; -{ - lt_ptr address = 0; - image_id image = (image_id) module; - - if (get_image_symbol (image, symbol, B_SYMBOL_TYPE_ANY, address) != B_OK) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); - address = 0; - } +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. - return address; -} +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. -static struct lt_user_dlloader sys_bedl = { - 0, sys_bedl_open, sys_bedl_close, sys_bedl_sym, 0, 0 -}; +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 Lesser General Public License for more details. -#endif /* __BEOS__ */ +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. +*/ +#include "lt__private.h" +#include "lt_system.h" +#include "lt_dlloader.h" - -/* --- DLD_LINK() INTERFACE LOADER --- */ +/* --- MANIFEST CONSTANTS --- */ -#if HAVE_DLD +/* Standard libltdl search path environment variable name */ +#undef LTDL_SEARCHPATH_VAR +#define LTDL_SEARCHPATH_VAR "LTDL_LIBRARY_PATH" -/* dynamic linking with dld */ +/* Standard libtool archive file extension. */ +#undef LT_ARCHIVE_EXT +#define LT_ARCHIVE_EXT ".la" -#if HAVE_DLD_H -#include +/* max. filename length */ +#if !defined(LT_FILENAME_MAX) +# define LT_FILENAME_MAX 1024 #endif -static lt_module -sys_dld_open (loader_data, filename) - lt_user_data loader_data; - const char *filename; -{ - lt_module module = strdup (filename); - - if (dld_link (filename) != 0) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); - LT_DLFREE (module); - module = 0; - } - - return module; -} - -static int -sys_dld_close (loader_data, module) - lt_user_data loader_data; - lt_module module; -{ - int errors = 0; - - if (dld_unlink_by_file ((char*)(module), 1) != 0) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); - ++errors; - } - else - { - LT_DLFREE (module); - } - - return errors; -} +#if !defined(LT_LIBEXT) +# define LT_LIBEXT "a" +#endif -static lt_ptr -sys_dld_sym (loader_data, module, symbol) - lt_user_data loader_data; - lt_module module; - const char *symbol; -{ - lt_ptr address = dld_get_func (symbol); +/* This is the maximum symbol size that won't require malloc/free */ +#undef LT_SYMBOL_LENGTH +#define LT_SYMBOL_LENGTH 128 - if (!address) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); - } +/* This accounts for the _LTX_ separator */ +#undef LT_SYMBOL_OVERHEAD +#define LT_SYMBOL_OVERHEAD 5 - return address; -} +/* 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 struct lt_user_dlloader sys_dld = { - 0, sys_dld_open, sys_dld_close, sys_dld_sym, 0, 0 -}; -#endif /* HAVE_DLD */ +static const char objdir[] = LT_OBJDIR; +static const char archive_ext[] = LT_ARCHIVE_EXT; +static const char libext[] = LT_LIBEXT; +#if defined(LT_MODULE_EXT) +static const char shlib_ext[] = LT_MODULE_EXT; +#endif +#if defined(LT_DLSEARCH_PATH) +static const char sys_dlsearch_path[] = LT_DLSEARCH_PATH; +#endif -/* --- DLPREOPEN() INTERFACE LOADER --- */ - - -/* 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 (loader_data) - lt_user_data loader_data; -{ - int errors = 0; - - LT_DLMUTEX_LOCK (); - - preloaded_symbols = 0; - if (default_preloaded_symbols) - { - errors = lt_dlpreload (default_preloaded_symbols); - } +/* --- DYNAMIC MODULE LOADING --- */ - LT_DLMUTEX_UNLOCK (); - return errors; +/* 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 -presym_free_symlists () +loader_init (lt_get_vtable *vtable_func, lt_user_data data) { - lt_dlsymlists_t *lists; - - LT_DLMUTEX_LOCK (); + const lt_dlvtable *vtable = 0; + int errors = 0; - lists = preloaded_symbols; - while (lists) + if (vtable_func) { - lt_dlsymlists_t *tmp = lists; - - lists = lists->next; - LT_DLFREE (tmp); + vtable = (*vtable_func) (data); } - preloaded_symbols = 0; - - LT_DLMUTEX_UNLOCK (); - - return 0; -} - -static int -presym_exit (loader_data) - lt_user_data loader_data; -{ - presym_free_symlists (); - return 0; -} - -static int -presym_add_symlist (preloaded) - const lt_dlsymlist *preloaded; -{ - lt_dlsymlists_t *tmp; - lt_dlsymlists_t *lists; - int errors = 0; - LT_DLMUTEX_LOCK (); + /* lt_dlloader_add will LT__SETERROR if it fails. */ + errors += lt_dlloader_add (vtable); - lists = preloaded_symbols; - while (lists) - { - if (lists->syms == preloaded) - { - goto done; - } - lists = lists->next; - } + assert (errors || vtable); - tmp = LT_EMALLOC (lt_dlsymlists_t, 1); - if (tmp) - { - memset (tmp, 0, sizeof(lt_dlsymlists_t)); - tmp->syms = preloaded; - tmp->next = preloaded_symbols; - preloaded_symbols = tmp; - } - else + if ((!errors) && vtable->dlloader_init) { - ++errors; + if ((*vtable->dlloader_init) (vtable->dlloader_data)) + { + LT__SETERROR (INIT_LOADER); + ++errors; + } } - done: - LT_DLMUTEX_UNLOCK (); return errors; } -static lt_module -presym_open (loader_data, filename) - lt_user_data loader_data; - const char *filename; -{ - lt_dlsymlists_t *lists; - lt_module module = (lt_module) 0; - - LT_DLMUTEX_LOCK (); - lists = preloaded_symbols; - - if (!lists) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_SYMBOLS)); - goto done; - } - - /* Can't use NULL as the reflective symbol header, as NULL is - used to mark the end of the entire symbol list. Self-dlpreopened - symbols follow this magic number, chosen to be an unlikely - clash with a real module name. */ - if (!filename) - { - filename = "@PROGRAM@"; - } - - while (lists) - { - const lt_dlsymlist *syms = lists->syms; - - while (syms->name) - { - if (!syms->address && strcmp(syms->name, filename) == 0) - { - module = (lt_module) syms; - goto done; - } - ++syms; - } - - lists = lists->next; - } - - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); - - done: - LT_DLMUTEX_UNLOCK (); - return module; -} - -static int -presym_close (loader_data, module) - lt_user_data loader_data; - lt_module module; -{ - /* Just to silence gcc -Wall */ - module = 0; - return 0; -} - -static lt_ptr -presym_sym (loader_data, module, symbol) - lt_user_data loader_data; - lt_module module; - const char *symbol; -{ - lt_dlsymlist *syms = (lt_dlsymlist*) module; - - ++syms; - while (syms->address) - { - if (strcmp(syms->name, symbol) == 0) - { - return syms->address; - } - - ++syms; - } - - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); - - return 0; -} - -static struct lt_user_dlloader presym = { - 0, presym_open, presym_close, presym_sym, presym_exit, 0 -}; - - - - - -/* --- DYNAMIC MODULE LOADING --- */ - - -/* The type of a function used at each iteration of foreach_dirinpath(). */ -typedef int foreach_callback_func LT_PARAMS((char *filename, lt_ptr data1, - lt_ptr data2)); +/* 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) -static int foreach_dirinpath LT_PARAMS((const char *search_path, - const char *base_name, - foreach_callback_func *func, - lt_ptr data1, lt_ptr data2)); - -static int find_file_callback LT_PARAMS((char *filename, lt_ptr data, - lt_ptr ignored)); -static int find_handle_callback LT_PARAMS((char *filename, lt_ptr data, - lt_ptr ignored)); -static int foreachfile_callback LT_PARAMS((char *filename, lt_ptr data1, - lt_ptr data2)); - - -static int canonicalize_path LT_PARAMS((const char *path, - char **pcanonical)); -static int argzize_path LT_PARAMS((const char *path, - char **pargz, - size_t *pargz_len)); -static FILE *find_file LT_PARAMS((const char *search_path, - const char *base_name, - char **pdir)); -static lt_dlhandle *find_handle LT_PARAMS((const char *search_path, - const char *base_name, - lt_dlhandle *handle)); -static int find_module LT_PARAMS((lt_dlhandle *handle, - const char *dir, - const char *libdir, - const char *dlname, - const char *old_name, - int installed)); -static int free_vars LT_PARAMS((char *dlname, char *oldname, - char *libdir, char *deplibs)); -static int load_deplibs LT_PARAMS((lt_dlhandle handle, - char *deplibs)); -static int trim LT_PARAMS((char **dest, - const char *str)); -static int try_dlopen LT_PARAMS((lt_dlhandle *handle, - const char *filename)); -static int tryall_dlopen LT_PARAMS((lt_dlhandle *handle, - const char *filename)); -static int unload_deplibs LT_PARAMS((lt_dlhandle handle)); -static int lt_argz_insert LT_PARAMS((char **pargz, - size_t *pargz_len, - char *before, - const char *entry)); -static int lt_argz_insertinorder LT_PARAMS((char **pargz, - size_t *pargz_len, - const char *entry)); -static int lt_argz_insertdir LT_PARAMS((char **pargz, - size_t *pargz_len, - const char *dirnam, - struct dirent *dp)); -static int lt_dlpath_insertdir LT_PARAMS((char **ppath, - char *before, - const char *dir)); -static int list_files_by_dir LT_PARAMS((const char *dirnam, - char **pargz, - size_t *pargz_len)); -static int file_not_found LT_PARAMS((void)); - -static char *user_search_path= 0; -static lt_dlloader *loaders = 0; -static lt_dlhandle handles = 0; -static int initialized = 0; +LT_BEGIN_C_DECLS +LT_SCOPE const lt_dlvtable * get_vtable (lt_user_data data); +LT_END_C_DECLS +#ifdef HAVE_LIBDLLOADER +extern lt_dlsymlist preloaded_symbols; +#endif /* Initialize libltdl. */ int -lt_dlinit () +lt_dlinit (void) { - int errors = 0; - - LT_DLMUTEX_LOCK (); + int errors = 0; /* Initialize only at first call. */ if (++initialized == 1) { - handles = 0; - user_search_path = 0; /* empty search path */ - -#if HAVE_LIBDL && !defined(__CYGWIN__) - errors += lt_dlloader_add (lt_dlloader_next (0), &sys_dl, "dlopen"); -#endif -#if HAVE_SHL_LOAD - errors += lt_dlloader_add (lt_dlloader_next (0), &sys_shl, "dlopen"); -#endif -#ifdef __WINDOWS__ - errors += lt_dlloader_add (lt_dlloader_next (0), &sys_wll, "dlopen"); -#endif -#ifdef __BEOS__ - errors += lt_dlloader_add (lt_dlloader_next (0), &sys_bedl, "dlopen"); -#endif -#if HAVE_DLD - errors += lt_dlloader_add (lt_dlloader_next (0), &sys_dld, "dld"); -#endif - errors += lt_dlloader_add (lt_dlloader_next (0), &presym, "dlpreload"); - - if (presym_init (presym.dlloader_data)) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INIT_LOADER)); - ++errors; - } - else if (errors != 0) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (DLOPEN_NOT_SUPPORTED)); - ++errors; - } - } - - LT_DLMUTEX_UNLOCK (); - - return errors; -} - -int -lt_dlpreload (preloaded) - const lt_dlsymlist *preloaded; -{ - int errors = 0; - - if (preloaded) - { - errors = presym_add_symlist (preloaded); + lt__alloc_die = lt__alloc_die_callback; + handles = 0; + user_search_path = 0; /* empty search path */ + + /* First set up the statically loaded preload module loader, so + we can use it to preopen the other loaders we linked in at + compile time. */ + errors += loader_init (get_vtable, 0); + + /* Now open all the preloaded module loaders, so the application + can use _them_ to lt_dlopen its own modules. */ +#ifdef HAVE_LIBDLLOADER + if (!errors) + { + errors += lt_dlpreload (&preloaded_symbols); + } + + if (!errors) + { + errors += lt_dlpreload_open (LT_STR(LTDLOPEN), loader_init_callback); + } +#endif /* HAVE_LIBDLLOADER */ } - else - { - presym_free_symlists(); - LT_DLMUTEX_LOCK (); - if (default_preloaded_symbols) - { - errors = lt_dlpreload (default_preloaded_symbols); - } - LT_DLMUTEX_UNLOCK (); - } +#ifdef LT_DEBUG_LOADERS + lt_dlloader_dump(); +#endif return errors; } int -lt_dlpreload_default (preloaded) - const lt_dlsymlist *preloaded; -{ - LT_DLMUTEX_LOCK (); - default_preloaded_symbols = preloaded; - LT_DLMUTEX_UNLOCK (); - return 0; -} - -int -lt_dlexit () +lt_dlexit (void) { /* shut down libltdl */ - lt_dlloader *loader; - int errors = 0; - - LT_DLMUTEX_LOCK (); - loader = loaders; + lt_dlloader *loader = 0; + lt_dlhandle handle = handles; + int errors = 0; if (!initialized) { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SHUTDOWN)); + LT__SETERROR (SHUTDOWN); ++errors; goto done; } @@ -1823,171 +269,236 @@ /* shut down only at last call. */ if (--initialized == 0) { - int level; + int level; while (handles && LT_DLIS_RESIDENT (handles)) - { - handles = handles->next; - } + { + handles = handles->next; + } /* close all modules */ - for (level = 1; handles; ++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 (!LT_DLIS_RESIDENT (tmp) && tmp->info.ref_count <= level) - { - if (lt_dlclose (tmp)) - { - ++errors; - } - } - } - /* done if only resident modules are left */ - if (!saw_nonresident) - break; - } + 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 */ - while (loader) - { - lt_dlloader *next = loader->next; - lt_user_data data = loader->dlloader_data; - if (loader->dlloader_exit && loader->dlloader_exit (data)) - { - ++errors; - } - - LT_DLMEM_REASSIGN (loader, next); - } - loaders = 0; + 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: - LT_DLMUTEX_UNLOCK (); 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 (handle, filename) - lt_dlhandle *handle; - const char *filename; -{ - lt_dlhandle cur; - lt_dlloader *loader; - const char *saved_error; - int errors = 0; +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; - LT_DLMUTEX_GETERROR (saved_error); - LT_DLMUTEX_LOCK (); +#ifdef LT_DEBUG_LOADERS + fprintf (stderr, "tryall_dlopen (%s, %s)\n", + filename ? filename : "(null)", + vtable ? vtable->name : "(ALL)"); +#endif - cur = handles; - loader = loaders; + LT__GETERROR (saved_error); /* check whether the module was already opened */ - while (cur) + for (;handle; handle = handle->next) { - /* try to dlopen the program itself? */ - if (!cur->info.filename && !filename) - { - break; - } - - if (cur->info.filename && filename - && strcmp (cur->info.filename, filename) == 0) - { - break; - } - - cur = cur->next; + if ((handle->info.filename == filename) /* dlopen self: 0 == 0 */ + || (handle->info.filename && filename + && streq (handle->info.filename, filename))) + { + break; + } } - if (cur) + if (handle) { - ++cur->info.ref_count; - *handle = cur; + ++handle->info.ref_count; + *phandle = handle; goto done; } - cur = *handle; + handle = *phandle; if (filename) { - cur->info.filename = lt_estrdup (filename); - if (!cur->info.filename) - { - ++errors; - goto done; - } + /* 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 { - cur->info.filename = 0; + handle->info.filename = 0; } - while (loader) - { - lt_user_data data = loader->dlloader_data; + { + lt_dlloader loader = lt_dlloader_next (0); + const lt_dlvtable *loader_vtable; - cur->module = loader->module_open (data, filename); + do + { + if (vtable) + loader_vtable = vtable; + else + loader_vtable = lt_dlloader_get (loader); + +#ifdef LT_DEBUG_LOADERS + fprintf (stderr, "Calling %s->module_open (%s)\n", + (loader_vtable && loader_vtable->name) ? loader_vtable->name : "(null)", + filename ? filename : "(null)"); +#endif + handle->module = (*loader_vtable->module_open) (loader_vtable->dlloader_data, + filename, advise); +#ifdef LT_DEBUG_LOADERS + fprintf (stderr, " Result: %s\n", + handle->module ? "Success" : "Failed"); +#endif + + if (handle->module != 0) + { + if (advise) + { + handle->info.is_resident = advise->is_resident; + handle->info.is_symglobal = advise->is_symglobal; + handle->info.is_symlocal = advise->is_symlocal; + } + break; + } + } + while (!vtable && (loader = lt_dlloader_next (loader))); - if (cur->module != 0) - { - break; - } - loader = loader->next; - } + /* 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; + } - if (!loader) - { - LT_DLFREE (cur->info.filename); - ++errors; - goto done; - } + handle->vtable = loader_vtable; + } - cur->loader = loader; - LT_DLMUTEX_SETERROR (saved_error); + LT__SETERRORSTR (saved_error); done: - LT_DLMUTEX_UNLOCK (); - return errors; } + static int -tryall_dlopen_module (handle, prefix, dirname, dlname) - lt_dlhandle *handle; - const char *prefix; - const char *dirname; - const char *dlname; -{ - int error = 0; - char *filename = 0; - size_t filename_len = 0; - size_t dirname_len = LT_STRLEN (dirname); +tryall_dlopen_module (lt_dlhandle *handle, const char *prefix, + const char *dirname, const char *dlname, + lt_dladvise advise) +{ + int error = 0; + char *filename = 0; + size_t filename_len = 0; + size_t dirname_len = LT_STRLEN (dirname); assert (handle); assert (dirname); assert (dlname); -#ifdef LT_DIRSEP_CHAR +#if defined(LT_DIRSEP_CHAR) /* Only canonicalized names (i.e. with DIRSEP chars already converted) should make it into this function: */ assert (strchr (dirname, LT_DIRSEP_CHAR) == 0); #endif - if (dirname[dirname_len -1] == '/') - --dirname_len; + if (dirname_len > 0) + if (dirname[dirname_len -1] == '/') + --dirname_len; filename_len = dirname_len + 1 + LT_STRLEN (dlname); /* Allocate memory, and combine DIRNAME and MODULENAME into it. The PREFIX (if any) is handled below. */ - filename = LT_EMALLOC (char, dirname_len + 1 + filename_len + 1); + filename = MALLOC (char, filename_len + 1); if (!filename) return 1; @@ -1998,31 +509,28 @@ shuffled. Otherwise, attempt to open FILENAME as a module. */ if (prefix) { - error += tryall_dlopen_module (handle, - (const char *) 0, prefix, filename); + error += tryall_dlopen_module (handle, (const char *) 0, + prefix, filename, advise); } - else if (tryall_dlopen (handle, filename) != 0) + else if (tryall_dlopen (handle, filename, advise, 0) != 0) { ++error; } - LT_DLFREE (filename); + FREE (filename); return error; } 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; +find_module (lt_dlhandle *handle, const char *dir, const char *libdir, + const char *dlname, const char *old_name, int installed, + lt_dladvise advise) { /* Try to open the old library first; if it was dlpreopened, we want the preopened version of it, even if a dlopenable module is available. */ - if (old_name && tryall_dlopen (handle, old_name) == 0) + if (old_name && tryall_dlopen (handle, old_name, + advise, lt_dlloader_find ("lt_preopen") ) == 0) { return 0; } @@ -2032,24 +540,25 @@ { /* try to open the installed module */ if (installed && libdir) - { - if (tryall_dlopen_module (handle, - (const char *) 0, libdir, dlname) == 0) - return 0; - } + { + 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) == 0) - return 0; - } + { + if (tryall_dlopen_module (handle, dir, objdir, + dlname, advise) == 0) + return 0; + } /* maybe it was moved to another directory */ { - if (tryall_dlopen_module (handle, - (const char *) 0, dir, dlname) == 0) - return 0; + if (dir && (tryall_dlopen_module (handle, (const char *) 0, + dir, dlname, advise) == 0)) + return 0; } } @@ -2058,16 +567,14 @@ static int -canonicalize_path (path, pcanonical) - const char *path; - char **pcanonical; +canonicalize_path (const char *path, char **pcanonical) { char *canonical = 0; assert (path && *path); assert (pcanonical); - canonical = LT_EMALLOC (char, 1+ LT_STRLEN (path)); + canonical = MALLOC (char, 1+ LT_STRLEN (path)); if (!canonical) return 1; @@ -2076,38 +583,38 @@ size_t src; for (src = 0; path[src] != LT_EOS_CHAR; ++src) { - /* Path separators are not copied to the beginning or end of - the destination, or if another separator would follow - immediately. */ - if (path[src] == LT_PATHSEP_CHAR) - { - if ((dest == 0) - || (path[1+ src] == LT_PATHSEP_CHAR) - || (path[1+ src] == LT_EOS_CHAR)) - continue; - } - - /* Anything other than a directory separator is copied verbatim. */ - if ((path[src] != '/') -#ifdef 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) -#ifdef LT_DIRSEP_CHAR - && (path[1+ src] != LT_DIRSEP_CHAR) -#endif - && (path[1+ src] != '/')) - { - canonical[dest++] = '/'; - } + /* Path separators are not copied to the beginning or end of + the destination, or if another separator would follow + immediately. */ + if (path[src] == LT_PATHSEP_CHAR) + { + if ((dest == 0) + || (path[1+ src] == LT_PATHSEP_CHAR) + || (path[1+ src] == LT_EOS_CHAR)) + continue; + } + + /* Anything other than a directory separator is copied verbatim. */ + if ((path[src] != '/') +#if defined(LT_DIRSEP_CHAR) + && (path[src] != LT_DIRSEP_CHAR) +#endif + ) + { + canonical[dest++] = path[src]; + } + /* Directory separators are converted and copied only if they are + not at the end of a path -- i.e. before a path separator or + NULL terminator. */ + else if ((path[1+ src] != LT_PATHSEP_CHAR) + && (path[1+ src] != LT_EOS_CHAR) +#if defined(LT_DIRSEP_CHAR) + && (path[1+ src] != LT_DIRSEP_CHAR) +#endif + && (path[1+ src] != '/')) + { + canonical[dest++] = '/'; + } } /* Add an end-of-string marker at the end. */ @@ -2121,10 +628,7 @@ } static int -argzize_path (path, pargz, pargz_len) - const char *path; - char **pargz; - size_t *pargz_len; +argzize_path (const char *path, char **pargz, size_t *pargz_len) { error_t error; @@ -2135,14 +639,14 @@ if ((error = argz_create_sep (path, LT_PATHSEP_CHAR, pargz, pargz_len))) { switch (error) - { - case ENOMEM: - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - break; - default: - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN)); - break; - } + { + case ENOMEM: + LT__SETERROR (NO_MEMORY); + break; + default: + LT__SETERROR (UNKNOWN); + break; + } return 1; } @@ -2155,26 +659,20 @@ 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 (search_path, base_name, func, data1, data2) - const char *search_path; - const char *base_name; - foreach_callback_func *func; - lt_ptr data1; - lt_ptr data2; -{ - int result = 0; - int filenamesize = 0; - size_t lenbase = LT_STRLEN (base_name); - size_t argz_len = 0; - char *argz = 0; - char *filename = 0; - char *canonical = 0; - - LT_DLMUTEX_LOCK (); +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; if (!search_path || !*search_path) { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); + LT__SETERROR (FILE_NOT_FOUND); goto cleanup; } @@ -2188,38 +686,38 @@ char *dir_name = 0; while ((dir_name = argz_next (argz, argz_len, dir_name))) { - size_t lendir = LT_STRLEN (dir_name); + size_t lendir = LT_STRLEN (dir_name); - if (lendir +1 +lenbase >= filenamesize) - { - LT_DLFREE (filename); - filenamesize = lendir +1 +lenbase +1; /* "/d" + '/' + "f" + '\0' */ - filename = LT_EMALLOC (char, filenamesize); - if (!filename) - goto cleanup; - } - - strncpy (filename, dir_name, lendir); - if (base_name && *base_name) - { - if (filename[lendir -1] != '/') - filename[lendir++] = '/'; - strcpy (filename +lendir, base_name); - } - - if ((result = (*func) (filename, data1, data2))) - { - break; - } + if (1+ lendir + lenbase >= filenamesize) + { + FREE (filename); + filenamesize = 1+ lendir + 1+ lenbase; /* "/d" + '/' + "f" + '\0' */ + filename = MALLOC (char, filenamesize); + if (!filename) + goto cleanup; + } + + assert (filenamesize > lendir); + strcpy (filename, dir_name); + + if (base_name && *base_name) + { + if (filename[lendir -1] != '/') + filename[lendir++] = '/'; + strcpy (filename +lendir, base_name); + } + + if ((result = (*func) (filename, data1, data2))) + { + break; + } } } cleanup: - LT_DLFREE (argz); - LT_DLFREE (canonical); - LT_DLFREE (filename); - - LT_DLMUTEX_UNLOCK (); + FREE (argz); + FREE (canonical); + FREE (filename); return result; } @@ -2228,14 +726,11 @@ 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 -find_file_callback (filename, data1, data2) - char *filename; - lt_ptr data1; - lt_ptr data2; -{ - char **pdir = (char **) data1; - FILE **pfile = (FILE **) data2; - int is_done = 0; +find_file_callback (char *filename, void *data1, void *data2) +{ + char **pdir = (char **) data1; + FILE **pfile = (FILE **) data2; + int is_done = 0; assert (filename && *filename); assert (pdir); @@ -2246,10 +741,10 @@ char *dirend = strrchr (filename, '/'); if (dirend > filename) - *dirend = LT_EOS_CHAR; + *dirend = LT_EOS_CHAR; - LT_DLFREE (*pdir); - *pdir = lt_estrdup (filename); + FREE (*pdir); + *pdir = lt__strdup (filename); is_done = (*pdir == 0) ? -1 : 1; } @@ -2257,10 +752,7 @@ } static FILE * -find_file (search_path, base_name, pdir) - const char *search_path; - const char *base_name; - char **pdir; +find_file (const char *search_path, const char *base_name, char **pdir) { FILE *file = 0; @@ -2270,22 +762,20 @@ } static int -find_handle_callback (filename, data, ignored) - char *filename; - lt_ptr data; - lt_ptr ignored; +find_handle_callback (char *filename, void *data, void *data2) { - lt_dlhandle *handle = (lt_dlhandle *) data; - int found = access (filename, R_OK); + 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 (!found) + if (notfound) return 0; /* Try to dlopen the file, but do not continue searching in any case. */ - if (tryall_dlopen (handle, filename) != 0) - *handle = 0; + if (tryall_dlopen (phandle, filename, advise, 0) != 0) + *phandle = 0; return 1; } @@ -2293,91 +783,87 @@ /* 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 (search_path, base_name, handle) - const char *search_path; - const char *base_name; - lt_dlhandle *handle; +find_handle (const char *search_path, const char *base_name, + lt_dlhandle *phandle, lt_dladvise advise) { if (!search_path) return 0; if (!foreach_dirinpath (search_path, base_name, find_handle_callback, - handle, 0)) + phandle, advise)) return 0; - return handle; + return phandle; +} + +#if !defined(LTDL_DLOPEN_DEPLIBS) +static int +load_deplibs (lt_dlhandle handle, char * LT__UNUSED deplibs) +{ + handle->depcount = 0; + return 0; } +#else /* defined(LTDL_DLOPEN_DEPLIBS) */ static int -load_deplibs (handle, deplibs) - lt_dlhandle handle; - char *deplibs; +load_deplibs (lt_dlhandle handle, char *deplibs) { -#if LTDL_DLOPEN_DEPLIBS - char *p, *save_search_path = 0; + char *p, *save_search_path = 0; int depcount = 0; - int i; - char **names = 0; -#endif - int errors = 0; + int i; + char **names = 0; + int errors = 0; handle->depcount = 0; -#if LTDL_DLOPEN_DEPLIBS if (!deplibs) { return errors; } ++errors; - LT_DLMUTEX_LOCK (); if (user_search_path) { - save_search_path = lt_estrdup (user_search_path); + save_search_path = lt__strdup (user_search_path); if (!save_search_path) - goto cleanup; + goto cleanup; } /* extract search paths and count deplibs */ p = deplibs; while (*p) { - if (!isspace ((int) *p)) - { - char *end = p+1; - while (*end && !isspace((int) *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; - } + 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; - } + p = end; + } else - { - ++p; - } + { + ++p; + } } - /* restore the old search path */ - LT_DLFREE (user_search_path); - user_search_path = save_search_path; - - LT_DLMUTEX_UNLOCK (); if (!depcount) { @@ -2385,7 +871,7 @@ goto cleanup; } - names = LT_EMALLOC (char *, depcount * sizeof (char*)); + names = MALLOC (char *, depcount); if (!names) goto cleanup; @@ -2395,40 +881,40 @@ while (*p) { if (isspace ((unsigned char) *p)) - { - ++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 = LT_EMALLOC (char, 1+ name_len); - if (name) - sprintf (name, "lib%s", p+2); - } - else - name = lt_estrdup(p); - - if (!name) - goto cleanup_names; - - names[depcount++] = name; - *end = save; - } - p = end; - } + { + 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; + } } /* load the deplibs (in reverse order) @@ -2438,80 +924,87 @@ later on if the loaded module cannot resolve all of its symbols. */ if (depcount) { - int j = 0; + lt_dlhandle cur = handle; + int j = 0; - handle->deplibs = (lt_dlhandle*) LT_EMALLOC (lt_dlhandle *, depcount); - if (!handle->deplibs) - goto cleanup; + cur->deplibs = MALLOC (lt_dlhandle, depcount); + if (!cur->deplibs) + goto cleanup_names; for (i = 0; i < depcount; ++i) - { - handle->deplibs[j] = lt_dlopenext(names[depcount-1-i]); - if (handle->deplibs[j]) - { - ++j; - } - } + { + cur->deplibs[j] = lt_dlopenext(names[depcount-1-i]); + if (cur->deplibs[j]) + { + ++j; + } + } - handle->depcount = j; /* Number of successfully loaded deplibs */ - errors = 0; + cur->depcount = j; /* Number of successfully loaded deplibs */ + errors = 0; } cleanup_names: for (i = 0; i < depcount; ++i) { - LT_DLFREE (names[i]); + FREE (names[i]); } cleanup: - LT_DLFREE (names); -#endif + FREE (names); + /* restore the old search path */ + if (save_search_path) { + MEMREASSIGN (user_search_path, save_search_path); + } return errors; } +#endif /* defined(LTDL_DLOPEN_DEPLIBS) */ static int -unload_deplibs (handle) - lt_dlhandle handle; +unload_deplibs (lt_dlhandle handle) { int i; int errors = 0; + lt_dlhandle cur = handle; - if (handle->depcount) + if (cur->depcount) { - for (i = 0; i < handle->depcount; ++i) - { - if (!LT_DLIS_RESIDENT (handle->deplibs[i])) - { - errors += lt_dlclose (handle->deplibs[i]); - } - } + 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 -trim (dest, str) - char **dest; - const char *str; +trim (char **dest, const char *str) { /* remove the leading and trailing "'" from str and store the result in dest */ const char *end = strrchr (str, '\''); - size_t len = LT_STRLEN (str); + size_t len = LT_STRLEN (str); char *tmp; - LT_DLFREE (*dest); + FREE (*dest); + + if (!end) + return 1; if (len > 3 && str[0] == '\'') { - tmp = LT_EMALLOC (char, end - str); + tmp = MALLOC (char, end - str); if (!tmp) - return 1; + return 1; - strncpy(tmp, &str[1], (end - str) - 1); - tmp[len-3] = LT_EOS_CHAR; + memcpy(tmp, &str[1], (end - str) - 1); + tmp[(end - str) - 1] = LT_EOS_CHAR; *dest = tmp; } else @@ -2522,67 +1015,187 @@ return 0; } +/* Read the .la file FILE. */ static int -free_vars (dlname, oldname, libdir, deplibs) - char *dlname; - char *oldname; - char *libdir; - char *deplibs; -{ - LT_DLFREE (dlname); - LT_DLFREE (oldname); - LT_DLFREE (libdir); - LT_DLFREE (deplibs); +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); - return 0; + 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]); + } +#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]); + } + +#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); + } + } + + if (errors) + break; + } +cleanup: + FREE (line); + return errors; } + +/* Try to open FILENAME as a module. */ static int -try_dlopen (phandle, filename) - lt_dlhandle *phandle; - const char *filename; -{ - const char * ext = 0; - const char * saved_error = 0; - char * canonical = 0; - char * base_name = 0; - char * dir = 0; - char * name = 0; - int errors = 0; - lt_dlhandle newhandle; +try_dlopen (lt_dlhandle *phandle, const char *filename, const char *ext, + lt_dladvise advise) +{ + 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); - LT_DLMUTEX_GETERROR (saved_error); +#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_EMALLOC (struct lt_dlhandle_struct, 1); + *phandle = (lt_dlhandle) lt__zalloc (sizeof (struct lt__handle)); if (*phandle == 0) - return 1; + return 1; - memset (*phandle, 0, sizeof(struct lt_dlhandle_struct)); - newhandle = *phandle; + newhandle = *phandle; /* lt_dlclose()ing yourself is very bad! Disallow it. */ - LT_DLSET_FLAG (*phandle, LT_DLRESIDENT_FLAG); + newhandle->info.is_resident = 1; - if (tryall_dlopen (&newhandle, 0) != 0) - { - LT_DLFREE (*phandle); - return 1; - } + if (tryall_dlopen (&newhandle, 0, advise, 0) != 0) + { + FREE (*phandle); + return 1; + } goto register_handle; } assert (filename && *filename); + if (ext) + { + attempt = MALLOC (char, LT_STRLEN (filename) + LT_STRLEN (ext) + 1); + if (!attempt) + return 1; + + 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 (filename, &canonical) != 0) + if (canonicalize_path (attempt, &canonical) != 0) { ++errors; goto cleanup; @@ -2595,12 +1208,12 @@ { size_t dirlen = (1+ base_name) - canonical; - dir = LT_EMALLOC (char, 1+ dirlen); + dir = MALLOC (char, 1+ dirlen); if (!dir) - { - ++errors; - goto cleanup; - } + { + ++errors; + goto cleanup; + } strncpy (dir, canonical, dirlen); dir[dirlen] = LT_EOS_CHAR; @@ -2608,447 +1221,476 @@ ++base_name; } else - LT_DLMEM_REASSIGN (base_name, canonical); + MEMREASSIGN (base_name, canonical); assert (base_name && *base_name); - /* Check whether we are opening a libtool module (.la extension). */ ext = strrchr (base_name, '.'); - if (ext && strcmp (ext, archive_ext) == 0) + if (!ext) { - /* this seems to be a libtool module */ - FILE * file = 0; - char * dlname = 0; - char * old_name = 0; - char * libdir = 0; - char * deplibs = 0; - char * line = 0; - size_t line_len; + ext = base_name + LT_STRLEN (base_name); + } - /* 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 = LT_EMALLOC (char, ext - base_name + 1); - if (!name) - { - ++errors; - goto cleanup; - } + /* extract the module name from the file name */ + name = MALLOC (char, ext - base_name + 1); + if (!name) + { + ++errors; + goto cleanup; + } - /* canonicalize the module name */ + /* canonicalize the module name */ + { + int i; + for (i = 0; i < ext - base_name; ++i) { - size_t 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; + 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) + { + /* name + "." + libext + NULL */ + archive_name = MALLOC (char, LT_STRLEN (name) + LT_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. */ + 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. */ + 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; + { + const char *search_path = user_search_path; + + if (search_path) + file = find_file (user_search_path, base_name, &dir); - LT_DLMUTEX_LOCK (); - search_path = user_search_path; - if (search_path) - file = find_file (user_search_path, base_name, &dir); - LT_DLMUTEX_UNLOCK (); - - if (!file) - { - search_path = getenv (LTDL_SEARCHPATH_VAR); - if (search_path) - file = find_file (search_path, base_name, &dir); - } - -#ifdef LTDL_SHLIBPATH_VAR - if (!file) - { - search_path = getenv (LTDL_SHLIBPATH_VAR); - if (search_path) - file = find_file (search_path, base_name, &dir); - } -#endif -#ifdef LTDL_SYSSEARCHPATH - if (!file && sys_search_path) - { - file = find_file (sys_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 - } - if (!file) - { - file = fopen (filename, LT_READTEXT_MODE); - } + } + 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. */ + the status flag, and bail out. */ if (!file) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); - ++errors; - goto cleanup; - } - - line_len = LT_FILENAME_MAX; - line = LT_EMALLOC (char, line_len); - if (!line) - { - fclose (file); - ++errors; - goto cleanup; - } + { + LT__SETERROR (FILE_NOT_FOUND); + ++errors; + goto cleanup; + } /* read the .la file */ - while (!feof (file)) - { - 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. */ - while (line[LT_STRLEN(line) -1] != '\n') - { - line = LT_DLREALLOC (char, line, line_len *2); - 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]); - } -#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]); - } - -#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 (strcmp (line, "installed=yes\n") == 0) - { - installed = 1; - } - else if (strcmp (line, "installed=no\n") == 0) - { - 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_estrdup (last_libname + 1); - if (!last_libname) - { - ++errors; - goto cleanup; - } - LT_DLMEM_REASSIGN (dlname, last_libname); - } - } - - if (errors) - break; - } + if (parse_dotla_file(file, &dlname, &libdir, &deplibs, + &old_name, &installed) != 0) + ++errors; fclose (file); - LT_DLFREE (line); /* allocate the handle */ - *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1); + *phandle = (lt_dlhandle) lt__zalloc (sizeof (struct lt__handle)); if (*phandle == 0) - ++errors; + ++errors; if (errors) - { - free_vars (dlname, old_name, libdir, deplibs); - LT_DLFREE (*phandle); - goto cleanup; - } + { + FREE (dlname); + FREE (old_name); + FREE (libdir); + FREE (deplibs); + FREE (*phandle); + goto cleanup; + } assert (*phandle); - memset (*phandle, 0, sizeof(struct lt_dlhandle_struct)); if (load_deplibs (*phandle, deplibs) == 0) - { - newhandle = *phandle; - /* find_module may replace newhandle */ - if (find_module (&newhandle, dir, libdir, dlname, old_name, installed)) - { - unload_deplibs (*phandle); - ++errors; - } - } + { + newhandle = *phandle; + /* find_module may replace newhandle */ + if (find_module (&newhandle, dir, libdir, dlname, old_name, + installed, advise)) + { + unload_deplibs (*phandle); + ++errors; + } + } else - { - ++errors; - } + { + ++errors; + } + + FREE (dlname); + FREE (old_name); + FREE (libdir); + FREE (deplibs); - free_vars (dlname, old_name, libdir, deplibs); if (errors) - { - LT_DLFREE (*phandle); - goto cleanup; - } + { + FREE (*phandle); + goto cleanup; + } if (*phandle != newhandle) - { - unload_deplibs (*phandle); - } + { + unload_deplibs (*phandle); + } } else { /* not a libtool module */ - *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1); + *phandle = (lt_dlhandle) lt__zalloc (sizeof (struct lt__handle)); if (*phandle == 0) - { - ++errors; - goto cleanup; - } + { + ++errors; + goto cleanup; + } - memset (*phandle, 0, sizeof (struct lt_dlhandle_struct)); 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) - && !find_handle (getenv (LTDL_SEARCHPATH_VAR), base_name, - &newhandle) -#ifdef LTDL_SHLIBPATH_VAR - && !find_handle (getenv (LTDL_SHLIBPATH_VAR), base_name, - &newhandle) -#endif -#ifdef LTDL_SYSSEARCHPATH - && !find_handle (sys_search_path, base_name, &newhandle) -#endif - ))) - { - tryall_dlopen (&newhandle, filename); - } + 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) - { - LT_DLFREE (*phandle); - ++errors; - goto cleanup; - } + { + FREE (*phandle); + ++errors; + goto cleanup; + } } register_handle: - LT_DLMEM_REASSIGN (*phandle, newhandle); + MEMREASSIGN (*phandle, newhandle); if ((*phandle)->info.ref_count == 0) { - (*phandle)->info.ref_count = 1; - LT_DLMEM_REASSIGN ((*phandle)->info.name, name); + (*phandle)->info.ref_count = 1; + MEMREASSIGN ((*phandle)->info.name, name); - LT_DLMUTEX_LOCK (); - (*phandle)->next = handles; - handles = *phandle; - LT_DLMUTEX_UNLOCK (); + (*phandle)->next = handles; + handles = *phandle; } - LT_DLMUTEX_SETERROR (saved_error); + LT__SETERRORSTR (saved_error); cleanup: - LT_DLFREE (dir); - LT_DLFREE (name); - LT_DLFREE (canonical); + FREE (dir); + FREE (attempt); + FREE (name); + if (!canonical) /* was MEMREASSIGNed */ + FREE (base_name); + FREE (canonical); + FREE (archive_name); return errors; } -lt_dlhandle -lt_dlopen (filename) - const char *filename; -{ - lt_dlhandle handle = 0; - - /* Just incase we missed a code path in try_dlopen() that reports - an error, but forgets to reset handle... */ - if (try_dlopen (&handle, filename) != 0) - return 0; - - return handle; -} /* If the last error messge store was `FILE_NOT_FOUND', then return non-zero. */ static int -file_not_found () +file_not_found (void) { const char *error = 0; - LT_DLMUTEX_GETERROR (error); - if (error == LT_DLSTRERROR (FILE_NOT_FOUND)) + LT__GETERROR (error); + if (error == LT__STRERROR (FILE_NOT_FOUND)) return 1; return 0; } -/* If FILENAME has an ARCHIVE_EXT or SHLIB_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 SHLIB_EXT appended - instead. */ -lt_dlhandle -lt_dlopenext (filename) - const char *filename; -{ - lt_dlhandle handle = 0; - char * tmp = 0; - char * ext = 0; - size_t len; - int errors = 0; - if (!filename) - { - return lt_dlopen (filename); - } +/* Unless FILENAME already bears a suitable library extension, then + return 0. */ +static int +has_library_ext (const char *filename) +{ + char * ext = 0; assert (filename); - len = LT_STRLEN (filename); ext = strrchr (filename, '.'); - /* If FILENAME already bears a suitable extension, there is no need - to try appending additional extensions. */ - if (ext && ((strcmp (ext, archive_ext) == 0) -#ifdef LTDL_SHLIB_EXT - || (strcmp (ext, shlib_ext) == 0) + if (ext && ((streq (ext, archive_ext)) +#if defined(LT_MODULE_EXT) + || (streq (ext, shlib_ext)) #endif - )) + )) { - return lt_dlopen (filename); + return 1; } - /* First try appending ARCHIVE_EXT. */ - tmp = LT_EMALLOC (char, len + LT_STRLEN (archive_ext) + 1); - if (!tmp) - return 0; + return 0; +} - strcpy (tmp, filename); - strcat (tmp, archive_ext); - errors = try_dlopen (&handle, tmp); - - /* 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 ())) - { - LT_DLFREE (tmp); - return handle; - } -#ifdef LTDL_SHLIB_EXT - /* Try appending SHLIB_EXT. */ - if (LT_STRLEN (shlib_ext) > LT_STRLEN (archive_ext)) - { - LT_DLFREE (tmp); - tmp = LT_EMALLOC (char, len + LT_STRLEN (shlib_ext) + 1); - if (!tmp) - return 0; +/* Initialise and configure a user lt_dladvise opaque object. */ - strcpy (tmp, filename); - } - else +int +lt_dladvise_init (lt_dladvise *padvise) +{ + lt_dladvise advise = (lt_dladvise) lt__zalloc (sizeof (struct lt__advise)); + *padvise = advise; + return (advise ? 0 : 1); +} + +int +lt_dladvise_destroy (lt_dladvise *padvise) +{ + if (padvise) + FREE(*padvise); + return 0; +} + +int +lt_dladvise_ext (lt_dladvise *padvise) +{ + assert (padvise && *padvise); + (*padvise)->try_ext = 1; + return 0; +} + +int +lt_dladvise_resident (lt_dladvise *padvise) +{ + assert (padvise && *padvise); + (*padvise)->is_resident = 1; + return 0; +} + +int +lt_dladvise_local (lt_dladvise *padvise) +{ + assert (padvise && *padvise); + (*padvise)->is_symlocal = 1; + return 0; +} + +int +lt_dladvise_global (lt_dladvise *padvise) +{ + assert (padvise && *padvise); + (*padvise)->is_symglobal = 1; + return 0; +} + +int +lt_dladvise_preload (lt_dladvise *padvise) +{ + assert (padvise && *padvise); + (*padvise)->try_preload_only = 1; + return 0; +} + +/* Libtool-1.5.x interface for loading a new module named FILENAME. */ +lt_dlhandle +lt_dlopen (const char *filename) +{ + return lt_dlopenadvise (filename, NULL); +} + + +/* 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; + + if (!lt_dladvise_init (&advise) && !lt_dladvise_ext (&advise)) + handle = lt_dlopenadvise (filename, advise); + + lt_dladvise_destroy (&advise); + return handle; +} + + +lt_dlhandle +lt_dlopenadvise (const char *filename, lt_dladvise advise) +{ + lt_dlhandle handle = 0; + int errors = 0; + + /* Can't have symbols hidden and visible at the same time! */ + if (advise && advise->is_symlocal && advise->is_symglobal) { - tmp[len] = LT_EOS_CHAR; + LT__SETERROR (CONFLICTING_FLAGS); + return 0; } - strcat(tmp, shlib_ext); - errors = try_dlopen (&handle, tmp); + 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; - /* As before, if the file was found but loading failed, return now - with the current error message. */ - if (handle || ((errors > 0) && file_not_found ())) - { - LT_DLFREE (tmp); 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. */ + 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 + } /* Still here? Then we really did fail to locate any of the file names we tried. */ - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); - LT_DLFREE (tmp); + LT__SETERROR (FILE_NOT_FOUND); return 0; } static int -lt_argz_insert (pargz, pargz_len, before, entry) - char **pargz; - size_t *pargz_len; - char *before; - const char *entry; +lt_argz_insert (char **pargz, size_t *pargz_len, char *before, + const char *entry) { error_t error; - if ((error = argz_insert (pargz, pargz_len, before, entry))) + /* 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_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - break; - default: - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN)); - break; - } + { + case ENOMEM: + LT__SETERROR (NO_MEMORY); + break; + default: + LT__SETERROR (UNKNOWN); + break; + } return 1; } @@ -3056,10 +1698,7 @@ } static int -lt_argz_insertinorder (pargz, pargz_len, entry) - char **pargz; - size_t *pargz_len; - const char *entry; +lt_argz_insertinorder (char **pargz, size_t *pargz_len, const char *entry) { char *before = 0; @@ -3070,42 +1709,39 @@ if (*pargz) while ((before = argz_next (*pargz, *pargz_len, before))) { - int cmp = strcmp (entry, before); + int cmp = strcmp (entry, before); - if (cmp < 0) break; - if (cmp == 0) return 0; /* No duplicates! */ + if (cmp < 0) break; + if (cmp == 0) return 0; /* No duplicates! */ } return lt_argz_insert (pargz, pargz_len, before, entry); } static int -lt_argz_insertdir (pargz, pargz_len, dirnam, dp) - char **pargz; - size_t *pargz_len; - const char *dirnam; - struct dirent *dp; +lt_argz_insertdir (char **pargz, size_t *pargz_len, const char *dirnam, + struct dirent *dp) { - char *buf = 0; + char *buf = 0; size_t buf_len = 0; - char *end = 0; + char *end = 0; size_t end_offset = 0; size_t dir_len = 0; - int errors = 0; + int errors = 0; assert (pargz); assert (pargz_len); assert (dp); dir_len = LT_STRLEN (dirnam); - end = dp->d_name + LT_D_NAMLEN(dp); + 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; + break; if (*p == '.') end = p; @@ -3116,16 +1752,16 @@ char *p; for (p = end -1; p > dp->d_name; --p) if (*p == '.') - { - end = p; - break; - } + { + end = p; + break; + } } /* Prepend the directory name. */ - end_offset = end - dp->d_name; - buf_len = dir_len + 1+ end_offset; - buf = LT_EMALLOC (char, 1+ buf_len); + end_offset = end - dp->d_name; + buf_len = dir_len + 1+ end_offset; + buf = MALLOC (char, 1+ buf_len); if (!buf) return ++errors; @@ -3140,19 +1776,16 @@ if (lt_argz_insertinorder (pargz, pargz_len, buf) != 0) ++errors; - LT_DLFREE (buf); + FREE (buf); return errors; } static int -list_files_by_dir (dirnam, pargz, pargz_len) - const char *dirnam; - char **pargz; - size_t *pargz_len; +list_files_by_dir (const char *dirnam, char **pargz, size_t *pargz_len) { - DIR *dirp = 0; - int errors = 0; + DIR *dirp = 0; + int errors = 0; assert (dirnam && *dirnam); assert (pargz); @@ -3162,15 +1795,15 @@ dirp = opendir (dirnam); if (dirp) { - struct dirent *dp = 0; + struct dirent *dp = 0; while ((dp = readdir (dirp))) - if (dp->d_name[0] != '.') - if (lt_argz_insertdir (pargz, pargz_len, dirnam, dp)) - { - ++errors; - break; - } + if (dp->d_name[0] != '.') + if (lt_argz_insertdir (pargz, pargz_len, dirnam, dp)) + { + ++errors; + break; + } closedir (dirp); } @@ -3184,15 +1817,11 @@ /* 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 -foreachfile_callback (dirname, data1, data2) - char *dirname; - lt_ptr data1; - lt_ptr data2; +foreachfile_callback (char *dirname, void *data1, void *data2) { - int (*func) LT_PARAMS((const char *filename, lt_ptr data)) - = (int (*) LT_PARAMS((const char *filename, lt_ptr data))) data1; + file_worker_func *func = *(file_worker_func **) data1; - int is_done = 0; + int is_done = 0; char *argz = 0; size_t argz_len = 0; @@ -3205,11 +1834,11 @@ char *filename = 0; while ((filename = argz_next (argz, argz_len, filename))) if ((is_done = (*func) (filename, data2))) - break; + break; } cleanup: - LT_DLFREE (argz); + FREE (argz); return is_done; } @@ -3222,44 +1851,44 @@ 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 (search_path, func, data) - const char *search_path; - int (*func) LT_PARAMS ((const char *filename, lt_ptr data)); - lt_ptr data; +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. */ + listed in it. */ is_done = foreach_dirinpath (search_path, 0, - foreachfile_callback, func, data); + foreachfile_callback, fpptr, data); } else { /* Otherwise search the default paths. */ is_done = foreach_dirinpath (user_search_path, 0, - foreachfile_callback, func, data); + foreachfile_callback, fpptr, data); if (!is_done) - { - is_done = foreach_dirinpath (getenv("LTDL_LIBRARY_PATH"), 0, - foreachfile_callback, func, data); - } + { + is_done = foreach_dirinpath (getenv(LTDL_SEARCHPATH_VAR), 0, + foreachfile_callback, fpptr, data); + } -#ifdef LTDL_SHLIBPATH_VAR - if (!is_done) - { - is_done = foreach_dirinpath (getenv(LTDL_SHLIBPATH_VAR), 0, - foreachfile_callback, func, data); - } -#endif -#ifdef LTDL_SYSSEARCHPATH +#if defined(LT_MODULE_PATH_VAR) if (!is_done) - { - is_done = foreach_dirinpath (getenv(LTDL_SYSSEARCHPATH), 0, - foreachfile_callback, func, data); - } + { + 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); + } #endif } @@ -3267,14 +1896,11 @@ } int -lt_dlclose (handle) - lt_dlhandle handle; +lt_dlclose (lt_dlhandle handle) { lt_dlhandle cur, last; int errors = 0; - LT_DLMUTEX_LOCK (); - /* check whether the handle is valid */ last = cur = handles; while (cur && handle != cur) @@ -3285,80 +1911,80 @@ if (!cur) { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); + LT__SETERROR (INVALID_HANDLE); ++errors; goto done; } - handle->info.ref_count--; + 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 (handle->info.ref_count <= 0 && !LT_DLIS_RESIDENT (handle)) + if (cur->info.ref_count <= 0 && !LT_DLIS_RESIDENT (cur)) { - lt_user_data data = handle->loader->dlloader_data; + lt_user_data data = cur->vtable->dlloader_data; - if (handle != handles) - { - last->next = handle->next; - } + if (cur != handles) + { + last->next = cur->next; + } else - { - handles = handle->next; - } + { + handles = cur->next; + } - errors += handle->loader->module_close (data, handle->module); - errors += unload_deplibs(handle); + errors += cur->vtable->module_close (data, cur->module); + errors += unload_deplibs (handle); /* It is up to the callers to free the data itself. */ - LT_DLFREE (handle->caller_data); + FREE (cur->interface_data); - LT_DLFREE (handle->info.filename); - LT_DLFREE (handle->info.name); - LT_DLFREE (handle); + FREE (cur->info.filename); + FREE (cur->info.name); + FREE (cur); goto done; } if (LT_DLIS_RESIDENT (handle)) { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CLOSE_RESIDENT_MODULE)); + LT__SETERROR (CLOSE_RESIDENT_MODULE); ++errors; } done: - LT_DLMUTEX_UNLOCK (); - return errors; } -lt_ptr -lt_dlsym (handle, symbol) - lt_dlhandle handle; - const char *symbol; +void * +lt_dlsym (lt_dlhandle place, const char *symbol) { size_t lensym; - char lsym[LT_SYMBOL_LENGTH]; - char *sym; - lt_ptr address; + char lsym[LT_SYMBOL_LENGTH]; + char *sym; + void *address; lt_user_data data; + lt_dlhandle handle; - if (!handle) + if (!place) { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); + LT__SETERROR (INVALID_HANDLE); return 0; } + handle = place; + if (!symbol) { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); + LT__SETERROR (SYMBOL_NOT_FOUND); return 0; } - lensym = LT_STRLEN (symbol) + LT_STRLEN (handle->loader->sym_prefix) - + LT_STRLEN (handle->info.name); + lensym = LT_STRLEN (symbol) + LT_STRLEN (handle->vtable->sym_prefix) + + LT_STRLEN (handle->info.name); if (lensym + LT_SYMBOL_OVERHEAD < LT_SYMBOL_LENGTH) { @@ -3366,52 +1992,52 @@ } else { - sym = LT_EMALLOC (char, lensym + LT_SYMBOL_OVERHEAD + 1); + sym = MALLOC (char, lensym + LT_SYMBOL_OVERHEAD + 1); if (!sym) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (BUFFER_OVERFLOW)); - return 0; - } + { + LT__SETERROR (BUFFER_OVERFLOW); + return 0; + } } - data = handle->loader->dlloader_data; + data = handle->vtable->dlloader_data; if (handle->info.name) { const char *saved_error; - LT_DLMUTEX_GETERROR (saved_error); + LT__GETERROR (saved_error); /* this is a libtool module */ - if (handle->loader->sym_prefix) - { - strcpy(sym, handle->loader->sym_prefix); - strcat(sym, handle->info.name); - } + if (handle->vtable->sym_prefix) + { + strcpy(sym, handle->vtable->sym_prefix); + strcat(sym, handle->info.name); + } else - { - strcpy(sym, handle->info.name); - } + { + strcpy(sym, handle->info.name); + } strcat(sym, "_LTX_"); strcat(sym, symbol); /* try "modulename_LTX_symbol" */ - address = handle->loader->find_sym (data, handle->module, sym); + address = handle->vtable->find_sym (data, handle->module, sym); if (address) - { - if (sym != lsym) - { - LT_DLFREE (sym); - } - return address; - } - LT_DLMUTEX_SETERROR (saved_error); + { + if (sym != lsym) + { + FREE (sym); + } + return address; + } + LT__SETERRORSTR (saved_error); } /* otherwise try "symbol" */ - if (handle->loader->sym_prefix) + if (handle->vtable->sym_prefix) { - strcpy(sym, handle->loader->sym_prefix); + strcpy(sym, handle->vtable->sym_prefix); strcat(sym, symbol); } else @@ -3419,36 +2045,33 @@ strcpy(sym, symbol); } - address = handle->loader->find_sym (data, handle->module, sym); + address = handle->vtable->find_sym (data, handle->module, sym); if (sym != lsym) { - LT_DLFREE (sym); + FREE (sym); } return address; } const char * -lt_dlerror () +lt_dlerror (void) { const char *error; - LT_DLMUTEX_GETERROR (error); - LT_DLMUTEX_SETERROR (0); + LT__GETERROR (error); + LT__SETERRORSTR (0); - return error ? error : LT_DLSTRERROR (UNKNOWN); + return error ? error : NULL; } static int -lt_dlpath_insertdir (ppath, before, dir) - char **ppath; - char *before; - const char *dir; +lt_dlpath_insertdir (char **ppath, char *before, const char *dir) { - int errors = 0; - char *canonical = 0; - char *argz = 0; - size_t argz_len = 0; + int errors = 0; + char *canonical = 0; + char *argz = 0; + size_t argz_len = 0; assert (ppath); assert (dir && *dir); @@ -3464,14 +2087,14 @@ /* 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! */ + assert (!before); /* BEFORE cannot be set without PPATH. */ + assert (dir); /* Without DIR, don't call this function! */ - *ppath = lt_estrdup (dir); + *ppath = lt__strdup (dir); if (*ppath == 0) - ++errors; + ++errors; - return errors; + goto cleanup; } assert (ppath && *ppath); @@ -3490,7 +2113,7 @@ if (before) { assert (*ppath <= before); - assert (before - *ppath <= strlen (*ppath)); + assert ((int) (before - *ppath) <= (int) strlen (*ppath)); before = before - *ppath + argz; } @@ -3502,127 +2125,108 @@ } argz_stringify (argz, argz_len, LT_PATHSEP_CHAR); - LT_DLMEM_REASSIGN (*ppath, argz); + MEMREASSIGN(*ppath, argz); cleanup: - LT_DLFREE (canonical); - LT_DLFREE (argz); + FREE (argz); + FREE (canonical); return errors; } int -lt_dladdsearchdir (search_dir) - const char *search_dir; +lt_dladdsearchdir (const char *search_dir) { int errors = 0; if (search_dir && *search_dir) { - LT_DLMUTEX_LOCK (); if (lt_dlpath_insertdir (&user_search_path, 0, search_dir) != 0) - ++errors; - LT_DLMUTEX_UNLOCK (); + ++errors; } return errors; } int -lt_dlinsertsearchdir (before, search_dir) - const char *before; - const char *search_dir; +lt_dlinsertsearchdir (const char *before, const char *search_dir) { int errors = 0; if (before) { - LT_DLMUTEX_LOCK (); if ((before < user_search_path) - || (before >= user_search_path + LT_STRLEN (user_search_path))) - { - LT_DLMUTEX_UNLOCK (); - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_POSITION)); - return 1; - } - LT_DLMUTEX_UNLOCK (); + || (before >= user_search_path + LT_STRLEN (user_search_path))) + { + LT__SETERROR (INVALID_POSITION); + return 1; + } } if (search_dir && *search_dir) { - LT_DLMUTEX_LOCK (); if (lt_dlpath_insertdir (&user_search_path, - (char *) before, search_dir) != 0) - { - ++errors; - } - LT_DLMUTEX_UNLOCK (); + (char *) before, search_dir) != 0) + { + ++errors; + } } return errors; } int -lt_dlsetsearchpath (search_path) - const char *search_path; +lt_dlsetsearchpath (const char *search_path) { - int errors = 0; + int errors = 0; - LT_DLMUTEX_LOCK (); - LT_DLFREE (user_search_path); - LT_DLMUTEX_UNLOCK (); + FREE (user_search_path); if (!search_path || !LT_STRLEN (search_path)) { return errors; } - LT_DLMUTEX_LOCK (); if (canonicalize_path (search_path, &user_search_path) != 0) ++errors; - LT_DLMUTEX_UNLOCK (); return errors; } const char * -lt_dlgetsearchpath () +lt_dlgetsearchpath (void) { const char *saved_path; - LT_DLMUTEX_LOCK (); saved_path = user_search_path; - LT_DLMUTEX_UNLOCK (); return saved_path; } int -lt_dlmakeresident (handle) - lt_dlhandle handle; +lt_dlmakeresident (lt_dlhandle handle) { int errors = 0; if (!handle) { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); + LT__SETERROR (INVALID_HANDLE); ++errors; } else { - LT_DLSET_FLAG (handle, LT_DLRESIDENT_FLAG); + handle->info.is_resident = 1; } return errors; } int -lt_dlisresident (handle) - lt_dlhandle handle; +lt_dlisresident (lt_dlhandle handle) { if (!handle) { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); + LT__SETERROR (INVALID_HANDLE); return -1; } @@ -3631,369 +2235,187 @@ - /* --- MODULE INFORMATION --- */ -const lt_dlinfo * -lt_dlgetinfo (handle) - lt_dlhandle handle; -{ - if (!handle) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); - return 0; - } - - return &(handle->info); -} - -lt_dlhandle -lt_dlhandle_next (place) - lt_dlhandle place; -{ - return place ? place->next : handles; -} - -int -lt_dlforeach (func, data) - int (*func) LT_PARAMS((lt_dlhandle handle, lt_ptr data)); - lt_ptr data; -{ - int errors = 0; - lt_dlhandle cur; - - LT_DLMUTEX_LOCK (); - - cur = handles; - while (cur) - { - lt_dlhandle tmp = cur; - - cur = cur->next; - if ((*func) (tmp, data)) - { - ++errors; - break; - } +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) +{ + lt__interface_id *interface_id = (lt__interface_id *) lt__malloc (sizeof *interface_id); + + /* 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; } - LT_DLMUTEX_UNLOCK (); - - return errors; + return (lt_dlinterface_id) interface_id; } -lt_dlcaller_id -lt_dlcaller_register () +void lt_dlinterface_free (lt_dlinterface_id key) { - static lt_dlcaller_id last_caller_id = 0; - int result; - - LT_DLMUTEX_LOCK (); - result = ++last_caller_id; - LT_DLMUTEX_UNLOCK (); - - return result; + lt__interface_id *interface_id = (lt__interface_id *)key; + FREE (interface_id->id_string); + FREE (interface_id); } -lt_ptr -lt_dlcaller_set_data (key, handle, data) - lt_dlcaller_id key; - lt_dlhandle handle; - lt_ptr data; +void * +lt_dlcaller_set_data (lt_dlinterface_id key, lt_dlhandle handle, void *data) { int n_elements = 0; - lt_ptr stale = (lt_ptr) 0; + void *stale = (void *) 0; + lt_dlhandle cur = handle; int i; - /* This needs to be locked so that the caller data can be updated - simultaneously by different threads. */ - LT_DLMUTEX_LOCK (); - - if (handle->caller_data) - while (handle->caller_data[n_elements].key) + if (cur->interface_data) + while (cur->interface_data[n_elements].key) ++n_elements; for (i = 0; i < n_elements; ++i) { - if (handle->caller_data[i].key == key) - { - stale = handle->caller_data[i].data; - break; - } + if (cur->interface_data[i].key == key) + { + stale = cur->interface_data[i].data; + break; + } } - /* Ensure that there is enough room in this handle's caller_data + /* 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_caller_data *temp - = LT_DLREALLOC (lt_caller_data, handle->caller_data, 2+ n_elements); + lt_interface_data *temp + = REALLOC (lt_interface_data, cur->interface_data, 2+ n_elements); if (!temp) - { - stale = 0; - goto done; - } + { + stale = 0; + goto done; + } - handle->caller_data = temp; + cur->interface_data = temp; - /* We only need this if we needed to allocate a new caller_data. */ - handle->caller_data[i].key = key; - handle->caller_data[1+ i].key = 0; + /* 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; } - handle->caller_data[i].data = data; + cur->interface_data[i].data = data; done: - LT_DLMUTEX_UNLOCK (); - return stale; } -lt_ptr -lt_dlcaller_get_data (key, handle) - lt_dlcaller_id key; - lt_dlhandle handle; -{ - lt_ptr result = (lt_ptr) 0; - - /* This needs to be locked so that the caller data isn't updated by - another thread part way through this function. */ - LT_DLMUTEX_LOCK (); +void * +lt_dlcaller_get_data (lt_dlinterface_id key, lt_dlhandle handle) +{ + void *result = (void *) 0; + lt_dlhandle cur = handle; /* Locate the index of the element with a matching KEY. */ - { - int i; - for (i = 0; handle->caller_data[i].key; ++i) - { - if (handle->caller_data[i].key == key) - { - result = handle->caller_data[i].data; - break; - } - } - } - - LT_DLMUTEX_UNLOCK (); + 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; + } + } + } return result; } - - -/* --- USER MODULE LOADER API --- */ - - -int -lt_dlloader_add (place, dlloader, loader_name) - lt_dlloader *place; - const struct lt_user_dlloader *dlloader; - const char *loader_name; +const lt_dlinfo * +lt_dlgetinfo (lt_dlhandle handle) { - int errors = 0; - lt_dlloader *node = 0, *ptr = 0; - - if ((dlloader == 0) /* diagnose null parameters */ - || (dlloader->module_open == 0) - || (dlloader->module_close == 0) - || (dlloader->find_sym == 0)) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); - return 1; - } - - /* Create a new dlloader node with copies of the user callbacks. */ - node = LT_EMALLOC (lt_dlloader, 1); - if (!node) - return 1; - - node->next = 0; - node->loader_name = loader_name; - node->sym_prefix = dlloader->sym_prefix; - node->dlloader_exit = dlloader->dlloader_exit; - node->module_open = dlloader->module_open; - node->module_close = dlloader->module_close; - node->find_sym = dlloader->find_sym; - node->dlloader_data = dlloader->dlloader_data; - - LT_DLMUTEX_LOCK (); - if (!loaders) - { - /* If there are no loaders, NODE becomes the list! */ - loaders = node; - } - else if (!place) - { - /* If PLACE is not set, add NODE to the end of the - LOADERS list. */ - for (ptr = loaders; ptr->next; ptr = ptr->next) - { - /*NOWORK*/; - } - - ptr->next = node; - } - else if (loaders == place) - { - /* If PLACE is the first loader, NODE goes first. */ - node->next = place; - loaders = node; - } - else + if (!handle) { - /* Find the node immediately preceding PLACE. */ - for (ptr = loaders; ptr->next != place; ptr = ptr->next) - { - /*NOWORK*/; - } - - if (ptr->next != place) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); - ++errors; - } - else - { - /* Insert NODE between PTR and PLACE. */ - node->next = place; - ptr->next = node; - } + LT__SETERROR (INVALID_HANDLE); + return 0; } - LT_DLMUTEX_UNLOCK (); - - return errors; + return &(handle->info); } -int -lt_dlloader_remove (loader_name) - const char *loader_name; -{ - lt_dlloader *place = lt_dlloader_find (loader_name); - lt_dlhandle handle; - int errors = 0; - - if (!place) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); - return 1; - } - LT_DLMUTEX_LOCK (); +lt_dlhandle +lt_dlhandle_iterate (lt_dlinterface_id iface, lt_dlhandle place) +{ + lt_dlhandle handle = place; + lt__interface_id *iterator = (lt__interface_id *) iface; - /* Fail if there are any open modules which use this loader. */ - for (handle = handles; handle; handle = handle->next) - { - if (handle->loader == place) - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (REMOVE_LOADER)); - ++errors; - goto done; - } - } + assert (iface); /* iface is a required argument */ - if (place == loaders) - { - /* PLACE is the first loader in the list. */ - loaders = loaders->next; - } + if (!handle) + handle = handles; else - { - /* Find the loader before the one being removed. */ - lt_dlloader *prev; - for (prev = loaders; prev->next; prev = prev->next) - { - if (!strcmp (prev->next->loader_name, loader_name)) - { - break; - } - } + handle = handle->next; - place = prev->next; - prev->next = prev->next->next; - } - - if (place->dlloader_exit) + /* advance while the interface check fails */ + while (handle && iterator->iface + && ((*iterator->iface) (handle, iterator->id_string) != 0)) { - errors = place->dlloader_exit (place->dlloader_data); + handle = handle->next; } - LT_DLFREE (place); - - done: - LT_DLMUTEX_UNLOCK (); - - return errors; + return handle; } -lt_dlloader * -lt_dlloader_next (place) - lt_dlloader *place; -{ - lt_dlloader *next; - - LT_DLMUTEX_LOCK (); - next = place ? place->next : loaders; - LT_DLMUTEX_UNLOCK (); - - return next; -} -const char * -lt_dlloader_name (place) - lt_dlloader *place; +lt_dlhandle +lt_dlhandle_fetch (lt_dlinterface_id iface, const char *module_name) { - const char *name = 0; + lt_dlhandle handle = 0; - if (place) - { - LT_DLMUTEX_LOCK (); - name = place ? place->loader_name : 0; - LT_DLMUTEX_UNLOCK (); - } - else + assert (iface); /* iface is a required argument */ + + while ((handle = lt_dlhandle_iterate (iface, handle))) { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); + lt_dlhandle cur = handle; + if (cur && cur->info.name && streq (cur->info.name, module_name)) + break; } - return name; + return handle; } -lt_user_data * -lt_dlloader_data (place) - lt_dlloader *place; + +int +lt_dlhandle_map (lt_dlinterface_id iface, + int (*func) (lt_dlhandle handle, void *data), void *data) { - lt_user_data *data = 0; + lt__interface_id *iterator = (lt__interface_id *) iface; + lt_dlhandle cur = handles; - if (place) - { - LT_DLMUTEX_LOCK (); - data = place ? &(place->dlloader_data) : 0; - LT_DLMUTEX_UNLOCK (); - } - else - { - LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); - } + assert (iface); /* iface is a required argument */ - return data; -} + while (cur) + { + int errorcode = 0; -lt_dlloader * -lt_dlloader_find (loader_name) - const char *loader_name; -{ - lt_dlloader *place = 0; + /* advance while the interface check fails */ + while (cur && iterator->iface + && ((*iterator->iface) (cur, iterator->id_string) != 0)) + { + cur = cur->next; + } - LT_DLMUTEX_LOCK (); - for (place = loaders; place; place = place->next) - { - if (strcmp (place->loader_name, loader_name) == 0) - { - break; - } + if ((errorcode = (*func) (cur, data)) != 0) + return errorcode; } - LT_DLMUTEX_UNLOCK (); - return place; + return 0; }