From: Gary V. Vaughan Date: Sun, 2 Sep 2001 18:54:31 +0000 (+0000) Subject: Backported the following patches from the development branch: X-Git-Tag: release-1-4-1~7 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b460173eee081e91ac376266af641c7b72c62a20;p=thirdparty%2Flibtool.git Backported the following patches from the development branch: Based on a patch from Marius Vollmer : * NEWS: updated. * ltdl.m4 (AC_LIB_LTDL): Check for unistd.h. * libltdl/ltdl.c: Include unistd.h if it exists. (LTDL_SEARCHPATH_VAR): Macro to prevent hardcoding "LTDL_LIBRARY_PATH". (LTDL_ARCHIVE_EXT): Macro to prevent hardcoding ".la". (archive_ext): Have only one copy of ".la" in the readonly segment of the compiled library. (find_handle_callback): Don't bother trying to dlopen the file if it doesn't exist. (find_handle): Don't bother searching for files if no search_path was supplied. (file_not_found): A new function to determine whether the last error was due to a file not found condition. (try_dlopen): Renamed from lt_dlopen() and changed to have the same footprint as tryall_dlopen. This involved a minor rewrite of much of the internals of this function. (lt_dlopen): A new function wrapped arounf try_dlopen(). (lt_dlopenext): If a file already has a suitable extension, don't bother adding additional extensions and trying to open those. Tidy up the rest of the code to prevent continued searching with an eventual FILE_NOT_FOUND when a genuine failure earlier in the search process could be legitimately reported. * libltdl/ltdl.c (argz_create_sep): Don't forget to include the terminating '0' when counting argz_len. (argz_create_sep): When canonicalizing argz, don't forget to copy the terminating '0', incase canonicalization has shortened argz. (argz_stringify): Don't covert the final '0' to a separator. * libltdl/ltdl.c (lt_dlhandle_next): Now we can loop through all loaded module handles as originally intended. * libltdl/ltdl.c (lt_dlseterror): Oops. This never worked either, due to a pair of typos. Now fixed. * libltdl/ltdl.c (N_ELEMENTS): Deleted. How come nobody noticed there was no way this could have ever worked? (lt_dlcaller_set_data): Now that valid caller_ids must be non-zero, allocate an addition entry in the caller_data vector and use a zero valued key as the end marker. (lt_dlcaller_get_data): Iterate up to the end marker in one pass. * libltdl/ltdl.c (lt_dlcaller_register): Caller ids are allocated starting from value `1', so that clients can use a value of zero to indicate that libltdl has not yet initialised. * libltdl/ltdl.c (find_file_callback): Fix a multiple free() bug. (tryall_dlopen_module): Remove some unused variables. * libltdl/ltdl.c (lt_dlinsertsearchdir): Calculate the address of the end of user_search_path correctly. * libltdl/ltdl.c (rpl_argz_stringify): New fallback implementation. * ltdl.m4 (AC_LTDL_FUNC_ARGZ): Test for argz_stringify in libc. * libltdl/ltdl.c (lt_argz_insertinorder): Renamed from lt_argz_insert to make room for... (lt_argz_insert): Wraps argz_insert with libltdl error handling. (lt_dlpath_insertdir): Insert new path elements into an argzized path. (lt_dlinsertsearchdir): New function to insert new search directories anywhere into user_search_path using the above. (lt_dladdsearchdir): Rewritten to use lt_dlpath_insertdir. * libltdl/ltdl.h (lt_dlinsertsearchdir): Prototype for export. * doc/libtool.texi (Libltdl interface): Document it. --- diff --git a/ChangeLog b/ChangeLog index 389d9eeb6..fb1012f5e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,75 @@ +2001-09-02 Gary V. Vaughan + + Backported the following patches from the development branch: + + Based on a patch from Marius Vollmer : + * NEWS: updated. + * ltdl.m4 (AC_LIB_LTDL): Check for unistd.h. + * libltdl/ltdl.c: Include unistd.h if it exists. + (LTDL_SEARCHPATH_VAR): Macro to prevent hardcoding + "LTDL_LIBRARY_PATH". + (LTDL_ARCHIVE_EXT): Macro to prevent hardcoding ".la". + (archive_ext): Have only one copy of ".la" in the readonly + segment of the compiled library. + (find_handle_callback): Don't bother trying to dlopen the file if + it doesn't exist. + (find_handle): Don't bother searching for files if no search_path + was supplied. + (file_not_found): A new function to determine whether the last + error was due to a file not found condition. + (try_dlopen): Renamed from lt_dlopen() and changed to have the + same footprint as tryall_dlopen. This involved a minor rewrite of + much of the internals of this function. + (lt_dlopen): A new function wrapped arounf try_dlopen(). + (lt_dlopenext): If a file already has a suitable extension, don't + bother adding additional extensions and trying to open those. + Tidy up the rest of the code to prevent continued searching with + an eventual FILE_NOT_FOUND when a genuine failure earlier in the + search process could be legitimately reported. + + * libltdl/ltdl.c (argz_create_sep): Don't forget to include the + terminating '\0' when counting argz_len. + (argz_create_sep): When canonicalizing argz, don't forget to copy + the terminating '\0', incase canonicalization has shortened argz. + (argz_stringify): Don't covert the final '\0' to a separator. + + * libltdl/ltdl.c (lt_dlhandle_next): Now we can loop through all + loaded module handles as originally intended. + + * libltdl/ltdl.c (lt_dlseterror): Oops. This never worked + either, due to a pair of typos. Now fixed. + + * libltdl/ltdl.c (N_ELEMENTS): Deleted. How come nobody noticed + there was no way this could have ever worked? + (lt_dlcaller_set_data): Now that valid caller_ids must be + non-zero, allocate an addition entry in the caller_data vector and + use a zero valued key as the end marker. + (lt_dlcaller_get_data): Iterate up to the end marker in one pass. + + * libltdl/ltdl.c (lt_dlcaller_register): Caller ids are allocated + starting from value `1', so that clients can use a value of zero + to indicate that libltdl has not yet initialised. + + * libltdl/ltdl.c (find_file_callback): Fix a multiple free() + bug. + (tryall_dlopen_module): Remove some unused variables. + + * libltdl/ltdl.c (lt_dlinsertsearchdir): Calculate the address + of the end of user_search_path correctly. + + * libltdl/ltdl.c (rpl_argz_stringify): New fallback implementation. + * ltdl.m4 (AC_LTDL_FUNC_ARGZ): Test for argz_stringify in libc. + * libltdl/ltdl.c (lt_argz_insertinorder): Renamed from + lt_argz_insert to make room for... + (lt_argz_insert): Wraps argz_insert with libltdl error handling. + (lt_dlpath_insertdir): Insert new path elements into an + argzized path. + (lt_dlinsertsearchdir): New function to insert new search + directories anywhere into user_search_path using the above. + (lt_dladdsearchdir): Rewritten to use lt_dlpath_insertdir. + * libltdl/ltdl.h (lt_dlinsertsearchdir): Prototype for export. + * doc/libtool.texi (Libltdl interface): Document it. + 2001-08-18 Brad * ltmain.in: Do not remove -lm from deplibs for OpenBSD. diff --git a/NEWS b/NEWS index 7b496e814..8854c6dce 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,7 @@ NEWS - list of user-visible changes between releases of GNU Libtool New in 1.4.1: 2001-??-??; CVS version 1.4.0a, Libtool team: +* Better error messages from libltdl when loading fails. * Don't leave here-doc files behind. * Improved support for OpenBSD. * Libtool will build with autoconf-2.50 and higher. diff --git a/libltdl/ltdl.c b/libltdl/ltdl.c index 03c0650e4..3de6b3ca8 100644 --- a/libltdl/ltdl.c +++ b/libltdl/ltdl.c @@ -29,6 +29,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # include #endif +#if HAVE_UNISTD_H +# include +#endif + #if HAVE_STDIO_H # include #endif @@ -57,6 +61,34 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 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 + +/* I have never seen a system without this: */ +#include + #include "ltdl.h" @@ -85,6 +117,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA /* --- 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 @@ -100,241 +140,41 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - -/* --- 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 enumberated 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; -#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 MUTEX_LOCK() LT_STMT_START { \ - if (mutex_lock) (*mutex_lock)(); } LT_STMT_END -#define MUTEX_UNLOCK() LT_STMT_START { \ - if (mutex_unlock) (*mutex_unlock)(); } LT_STMT_END -#define MUTEX_SETERROR(errormsg) LT_STMT_START { \ - if (mutex_seterror) (*mutex_seterror) (errormsg); \ - else last_error = (errormsg); } LT_STMT_END -#define MUTEX_GETERROR(errormsg) LT_STMT_START { \ - if (mutex_seterror) errormsg = (*mutex_geterror)(); \ - else (errormsg) = last_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 *mutex_lock = 0; -static lt_dlmutex_unlock *mutex_unlock = 0; -static lt_dlmutex_seterror *mutex_seterror = 0; -static lt_dlmutex_geterror *mutex_geterror = 0; -static const char *last_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. */ - MUTEX_LOCK (); - - if ((lock && unlock && seterror && geterror) - || !(lock || unlock || seterror || geterror)) - { - mutex_lock = lock; - mutex_unlock = unlock; - mutex_geterror = geterror; - } - else - { - MUTEX_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; -} - - - /* --- MEMORY HANDLING --- */ -LT_GLOBAL_DATA lt_ptr (*lt_dlmalloc) LT_PARAMS((size_t size)) - = (lt_ptr (*) LT_PARAMS((size_t))) malloc; -LT_GLOBAL_DATA void (*lt_dlfree) LT_PARAMS((lt_ptr ptr)) - = (void (*) LT_PARAMS((lt_ptr))) free; +/* 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)); -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. */ #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))) + #define LT_DLMEM_REASSIGN(p, q) LT_STMT_START { \ - if ((p) != (q)) { lt_dlfree (p); (p) = (q); } \ + if ((p) != (q)) { lt_dlfree (p); (p) = (q); (q) = 0; } \ } LT_STMT_END - - -/* --- ERROR MESSAGES --- */ - - -static const char **user_error_strings = 0; -static int errorcount = LT_ERROR_MAX; - -int -lt_dladderror (diagnostic) - const char *diagnostic; -{ - int index = 0; - int result = -1; - const char **temp = (const char **) 0; - - MUTEX_LOCK (); - - index = errorcount - LT_ERROR_MAX; - temp = LT_DLREALLOC (const char *, user_error_strings, 1 + index); - if (temp == 0) - { - MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - } - else - { - user_error_strings = temp; - user_error_strings[index] = diagnostic; - result = errorcount++; - } - - MUTEX_UNLOCK (); - - return result; -} - -int -lt_dlseterror (index) - int index; -{ - int errors = 0; - - MUTEX_LOCK (); - - if (index >= errorcount || index < 0) - { - /* Ack! Error setting the error message! */ - MUTEX_SETERROR (LT_DLSTRERROR (INVALID_ERRORCODE)); - ++errors; - } - else if (index < LT_ERROR_MAX) - { - /* No error setting the error message! */ - MUTEX_SETERROR (lt_dlerror_strings[errorcount]); - } - else - { - /* No error setting the error message! */ - MUTEX_SETERROR (user_error_strings[errorcount - LT_ERROR_MAX]); - } - - MUTEX_UNLOCK (); - - return errors; -} - - - /* --- REPLACEMENT FUNCTIONS --- */ @@ -342,7 +182,9 @@ lt_dlseterror (index) #undef strdup #define strdup rpl_strdup -static char * +static char *strdup LT_PARAMS((const char *str)); + +char * strdup(str) const char *str; { @@ -366,7 +208,9 @@ strdup(str) #undef strcmp #define strcmp rpl_strcmp -static int +static int strcmp LT_PARAMS((const char *str1, const char *str2)); + +int strcmp (str1, str2) const char *str1; const char *str2; @@ -396,14 +240,16 @@ strcmp (str1, str2) # else # define strchr rpl_strchr -static const char* +static const char *strchr LT_PARAMS((const char *str, int ch)); + +const char* strchr(str, ch) const char *str; int ch; { const char *p; - for (p = str; *p != (char)ch && *p != '\0'; ++p) + for (p = str; *p != (char)ch && *p != LT_EOS_CHAR; ++p) /*NOWORK*/; return (*p == (char)ch) ? p : 0; @@ -412,6 +258,7 @@ strchr(str, ch) # endif #endif /* !HAVE_STRCHR */ + #if ! HAVE_STRRCHR # if HAVE_RINDEX @@ -419,14 +266,16 @@ strchr(str, ch) # else # define strrchr rpl_strrchr -static const char* +static const char *strrchr LT_PARAMS((const char *str, int ch)); + +const char* strrchr(str, ch) const char *str; int ch; { const char *p, *q = 0; - for (p = str; *p != '\0'; ++p) + for (p = str; *p != LT_EOS_CHAR; ++p) { if (*p == (char) ch) { @@ -441,8 +290,9 @@ strrchr(str, ch) #endif /* NOTE: Neither bcopy nor the memcpy implementation below can - reliably handle copying in overlapping areas of memory, so - do not rely on this behaviour when invoking memcpy later. */ + 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 @@ -450,10 +300,12 @@ strrchr(str, ch) # else # define memcpy rpl_memcpy -static char * +static lt_ptr memcpy LT_PARAMS((lt_ptr dest, const lt_ptr src, size_t size)); + +lt_ptr memcpy (dest, src, size) - char *dest; - const char *src; + lt_ptr dest; + const lt_ptr src; size_t size; { size_t i = 0; @@ -466,8 +318,38 @@ memcpy (dest, src, size) return dest; } -# endif -#endif +# 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)); + +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'' @@ -475,12 +357,16 @@ memcpy (dest, src, size) 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. */ -static lt_ptr -rpl_realloc (ptr, size) + +#undef realloc +#define realloc rpl_realloc + +lt_ptr +realloc (ptr, size) lt_ptr ptr; size_t size; { - if (size < 1) + if (size <= 0) { /* For zero or less bytes, free the original memory */ if (ptr != 0) @@ -506,10 +392,496 @@ rpl_realloc (ptr, size) lt_dlfree (ptr); } - /* Note that the contents of PTR are not damaged if there is - insufficient memory to realloc. */ - return mem; - } + /* 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)); + +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)); + +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)); + +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)); + +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)); + +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; +} + +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; +} + +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; +} + +char * +lt_estrdup (str) + const char *str; +{ + char *dup = strdup (str); + if (LT_STRLEN (str) && !dup) + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); + return dup; } @@ -584,7 +956,7 @@ sys_dl_open (loader_data, filename) if (!module) { - MUTEX_SETERROR (DLERROR (CANNOT_OPEN)); + LT_DLMUTEX_SETERROR (DLERROR (CANNOT_OPEN)); } return module; @@ -599,7 +971,7 @@ sys_dl_close (loader_data, module) if (dlclose (module) != 0) { - MUTEX_SETERROR (DLERROR (CANNOT_CLOSE)); + LT_DLMUTEX_SETERROR (DLERROR (CANNOT_CLOSE)); ++errors; } @@ -616,7 +988,7 @@ sys_dl_sym (loader_data, module, symbol) if (!address) { - MUTEX_SETERROR (DLERROR (SYMBOL_NOT_FOUND)); + LT_DLMUTEX_SETERROR (DLERROR (SYMBOL_NOT_FOUND)); } return address; @@ -693,9 +1065,9 @@ sys_shl_open (loader_data, 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 + 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) @@ -703,7 +1075,7 @@ sys_shl_open (loader_data, filename) lt_ptr address; shl_findsym (&self, "main", TYPE_UNDEFINED, &address); } - + if (!filename) { module = self; @@ -714,10 +1086,10 @@ sys_shl_open (loader_data, filename) if (!module) { - MUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); } } - + return module; } @@ -730,7 +1102,7 @@ sys_shl_close (loader_data, module) if (module && (shl_unload ((shl_t) (module)) != 0)) { - MUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); ++errors; } @@ -748,16 +1120,16 @@ sys_shl_sym (loader_data, module, symbol) /* sys_shl_open should never return a NULL module handle */ if (module == (lt_module) 0) { - MUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); } else if (!shl_findsym((shl_t*) &module, symbol, TYPE_UNDEFINED, &address)) { if (!address) { - MUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); } } - + return address; } @@ -808,21 +1180,18 @@ sys_wll_open (loader_data, filename) if (ext) { /* FILENAME already has an extension. */ - searchname = strdup (filename); + searchname = lt_estrdup (filename); } else { /* Append a `.' to stop Windows from adding an implicit `.dll' extension. */ - searchname = LT_DLMALLOC (char, 2+ strlen (filename)); - if (!searchname) - { - MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - return 0; - } - strcpy (searchname, filename); - strcat (searchname, "."); + searchname = LT_EMALLOC (char, 2+ LT_STRLEN (filename)); + if (searchname) + sprintf (searchname, "%s.", filename); } + if (!searchname) + return 0; #if __CYGWIN__ { @@ -843,7 +1212,7 @@ sys_wll_open (loader_data, filename) We check whether LoadLibrary is returning a handle to an already loaded module, and simulate failure if we find one. */ - MUTEX_LOCK (); + LT_DLMUTEX_LOCK (); cur = handles; while (cur) { @@ -860,11 +1229,11 @@ sys_wll_open (loader_data, filename) cur = cur->next; } - MUTEX_UNLOCK (); + LT_DLMUTEX_UNLOCK (); if (cur || !module) { - MUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); module = 0; } @@ -880,7 +1249,7 @@ sys_wll_close (loader_data, module) if (FreeLibrary(module) == 0) { - MUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); ++errors; } @@ -897,7 +1266,7 @@ sys_wll_sym (loader_data, module, symbol) if (!address) { - MUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); } return address; @@ -942,7 +1311,7 @@ sys_bedl_open (loader_data, filename) if (image <= 0) { - MUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); image = 0; } @@ -958,7 +1327,7 @@ sys_bedl_close (loader_data, module) if (unload_add_on ((image_id) module) != B_OK) { - MUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); ++errors; } @@ -976,7 +1345,7 @@ sys_bedl_sym (loader_data, module, symbol) if (get_image_symbol (image, symbol, B_SYMBOL_TYPE_ANY, address) != B_OK) { - MUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); address = 0; } @@ -1010,14 +1379,9 @@ sys_dld_open (loader_data, filename) { lt_module module = strdup (filename); - if (!module) - { - MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - module = 0; - } - else if (dld_link (filename) != 0) + if (dld_link (filename) != 0) { - MUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); LT_DLFREE (module); module = 0; } @@ -1034,7 +1398,7 @@ sys_dld_close (loader_data, module) if (dld_unlink_by_file ((char*)(module), 1) != 0) { - MUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); ++errors; } else @@ -1055,7 +1419,7 @@ sys_dld_sym (loader_data, module, symbol) if (!address) { - MUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); } return address; @@ -1090,7 +1454,7 @@ presym_init (loader_data) { int errors = 0; - MUTEX_LOCK (); + LT_DLMUTEX_LOCK (); preloaded_symbols = 0; if (default_preloaded_symbols) @@ -1098,7 +1462,7 @@ presym_init (loader_data) errors = lt_dlpreload (default_preloaded_symbols); } - MUTEX_UNLOCK (); + LT_DLMUTEX_UNLOCK (); return errors; } @@ -1108,7 +1472,7 @@ presym_free_symlists () { lt_dlsymlists_t *lists; - MUTEX_LOCK (); + LT_DLMUTEX_LOCK (); lists = preloaded_symbols; while (lists) @@ -1120,7 +1484,7 @@ presym_free_symlists () } preloaded_symbols = 0; - MUTEX_UNLOCK (); + LT_DLMUTEX_UNLOCK (); return 0; } @@ -1141,7 +1505,7 @@ presym_add_symlist (preloaded) lt_dlsymlists_t *lists; int errors = 0; - MUTEX_LOCK (); + LT_DLMUTEX_LOCK (); lists = preloaded_symbols; while (lists) @@ -1153,22 +1517,21 @@ presym_add_symlist (preloaded) lists = lists->next; } - tmp = LT_DLMALLOC (lt_dlsymlists_t, 1); + tmp = LT_EMALLOC (lt_dlsymlists_t, 1); if (tmp) { - memset (tmp, 0, 1*sizeof(lt_dlsymlists_t)); + memset (tmp, 0, sizeof(lt_dlsymlists_t)); tmp->syms = preloaded; tmp->next = preloaded_symbols; preloaded_symbols = tmp; } else { - MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); ++errors; } done: - MUTEX_UNLOCK (); + LT_DLMUTEX_UNLOCK (); return errors; } @@ -1180,15 +1543,19 @@ presym_open (loader_data, filename) lt_dlsymlists_t *lists; lt_module module = (lt_module) 0; - MUTEX_LOCK (); + LT_DLMUTEX_LOCK (); lists = preloaded_symbols; if (!lists) { - MUTEX_SETERROR (LT_DLSTRERROR (NO_SYMBOLS)); + 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@"; @@ -1211,10 +1578,10 @@ presym_open (loader_data, filename) lists = lists->next; } - MUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); done: - MUTEX_UNLOCK (); + LT_DLMUTEX_UNLOCK (); return module; } @@ -1247,7 +1614,7 @@ presym_sym (loader_data, module, symbol) ++syms; } - MUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); return 0; } @@ -1263,6 +1630,62 @@ static struct lt_user_dlloader presym = { /* --- 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)); + +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_dlpath_insertdir LT_PARAMS((char **ppath, + char *before, + const char *dir)); + static char *user_search_path= 0; static lt_dlloader *loaders = 0; static lt_dlhandle handles = 0; @@ -1274,7 +1697,7 @@ lt_dlinit () { int errors = 0; - MUTEX_LOCK (); + LT_DLMUTEX_LOCK (); /* Initialize only at first call. */ if (++initialized == 1) @@ -1301,17 +1724,17 @@ lt_dlinit () if (presym_init (presym.dlloader_data)) { - MUTEX_SETERROR (LT_DLSTRERROR (INIT_LOADER)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INIT_LOADER)); ++errors; } else if (errors != 0) { - MUTEX_SETERROR (LT_DLSTRERROR (DLOPEN_NOT_SUPPORTED)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (DLOPEN_NOT_SUPPORTED)); ++errors; } } - MUTEX_UNLOCK (); + LT_DLMUTEX_UNLOCK (); return errors; } @@ -1328,16 +1751,14 @@ lt_dlpreload (preloaded) } else { - const char *errormsg = 0; - presym_free_symlists(); - - MUTEX_LOCK (); + + LT_DLMUTEX_LOCK (); if (default_preloaded_symbols) { errors = lt_dlpreload (default_preloaded_symbols); } - MUTEX_UNLOCK (); + LT_DLMUTEX_UNLOCK (); } return errors; @@ -1347,9 +1768,9 @@ int lt_dlpreload_default (preloaded) const lt_dlsymlist *preloaded; { - MUTEX_LOCK (); + LT_DLMUTEX_LOCK (); default_preloaded_symbols = preloaded; - MUTEX_UNLOCK (); + LT_DLMUTEX_UNLOCK (); return 0; } @@ -1358,15 +1779,14 @@ lt_dlexit () { /* shut down libltdl */ lt_dlloader *loader; - const char *errormsg; int errors = 0; - MUTEX_LOCK (); + LT_DLMUTEX_LOCK (); loader = loaders; if (!initialized) { - MUTEX_SETERROR (LT_DLSTRERROR (SHUTDOWN)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SHUTDOWN)); ++errors; goto done; } @@ -1422,7 +1842,7 @@ lt_dlexit () } done: - MUTEX_UNLOCK (); + LT_DLMUTEX_UNLOCK (); return errors; } @@ -1436,8 +1856,8 @@ tryall_dlopen (handle, filename) const char *saved_error; int errors = 0; - MUTEX_GETERROR (saved_error); - MUTEX_LOCK (); + LT_DLMUTEX_GETERROR (saved_error); + LT_DLMUTEX_LOCK (); cur = handles; loader = loaders; @@ -1470,10 +1890,9 @@ tryall_dlopen (handle, filename) cur = *handle; if (filename) { - cur->info.filename = strdup (filename); + cur->info.filename = lt_estrdup (filename); if (!cur->info.filename) { - MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); ++errors; goto done; } @@ -1504,14 +1923,63 @@ tryall_dlopen (handle, filename) } cur->loader = loader; - last_error = saved_error; - + LT_DLMUTEX_SETERROR (saved_error); + done: - MUTEX_UNLOCK (); + 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); + + assert (handle); + assert (dirname); + assert (dlname); +#ifdef 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; + 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); + if (!filename) + return 1; + + sprintf (filename, "%.*s/%s", (int) dirname_len, dirname, dlname); + + /* Now that we have combined DIRNAME and MODULENAME, if there is + also a PREFIX to contend with, simply recurse with the arguments + shuffled. Otherwise, attempt to open FILENAME as a module. */ + if (prefix) + { + tryall_dlopen_module (handle, 0, prefix, filename); + } + else if (tryall_dlopen (handle, filename) != 0) + { + ++error; + } + + LT_DLFREE (filename); + return error; +} + static int find_module (handle, dir, libdir, dlname, old_name, installed) lt_dlhandle *handle; @@ -1521,252 +1989,300 @@ find_module (handle, dir, libdir, dlname, old_name, installed) const char *old_name; int installed; { - int error; - char *filename; - - /* try to open the old library first; if it was dlpreopened, + /* 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) + module is available. */ + if (old_name && tryall_dlopen (handle, old_name) == 0) { return 0; } - /* try to open the dynamic library */ + /* Try to open the dynamic library. */ if (dlname) { - size_t len; - /* try to open the installed module */ if (installed && libdir) { - len = strlen (libdir) + 1 + strlen (dlname); - filename = LT_DLMALLOC (char, 1+ len); - - if (!filename) - { - MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - return 1; - } - - sprintf (filename, "%s/%s", libdir, dlname); - error = (tryall_dlopen (handle, filename) != 0); - LT_DLFREE (filename); - - if (!error) - { - return 0; - } + if (tryall_dlopen_module (handle, 0, libdir, dlname) == 0) + return 0; } /* try to open the not-installed module */ if (!installed) { - len = (dir ? strlen (dir) : 0) + strlen (objdir) + strlen (dlname); - filename = LT_DLMALLOC (char, 1+ len); - - if (!filename) - { - MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - return 1; - } - - if (dir) - { - strcpy (filename, dir); - } - else - { - *filename = 0; - } - strcat(filename, objdir); - strcat(filename, dlname); - - error = tryall_dlopen (handle, filename) != 0; - LT_DLFREE (filename); - if (!error) - { - return 0; - } + if (tryall_dlopen_module (handle, dir, objdir, dlname) == 0) + return 0; } /* maybe it was moved to another directory */ { - len = (dir ? strlen (dir) : 0) + strlen (dlname); - filename = LT_DLMALLOC (char, 1+ len); + if (tryall_dlopen_module (handle, 0, dir, dlname) == 0) + return 0; + } + } + + return 1; +} + + +static int +canonicalize_path (path, pcanonical) + const char *path; + char **pcanonical; +{ + char *canonical = 0; + + assert (path && *path); + assert (pcanonical); - if (dir) + canonical = LT_EMALLOC (char, 1+ LT_STRLEN (path)); + if (!canonical) + return 1; + + { + size_t dest = 0; + size_t src; + for (src = 0; path[src] != LT_EOS_CHAR; ++src) + { + /* Path separators are not copied to the beginning or end of + the destination, or if another separator would follow + immediately. */ + if (path[src] == LT_PATHSEP_CHAR) { - strcpy (filename, dir); + if ((dest == 0) + || (path[1+ src] == LT_PATHSEP_CHAR) + || (path[1+ src] == LT_EOS_CHAR)) + continue; } - else + + /* Anything other than a directory separator is copied verbatim. */ + if ((path[src] != '/') +#ifdef LT_DIRSEP_CHAR + && (path[src] != LT_DIRSEP_CHAR) +#endif + ) { - *filename = 0; + canonical[dest++] = path[src]; } - strcat(filename, dlname); - - error = (tryall_dlopen (handle, filename) != 0); - LT_DLFREE (filename); - if (!error) + /* 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] != '/')) { - return 0; + canonical[dest++] = '/'; } } - } - return 1; + /* Add an end-of-string marker at the end. */ + canonical[dest] = LT_EOS_CHAR; + } + + /* Assign new value. */ + *pcanonical = canonical; + + return 0; } -static char* -canonicalize_path (path) +static int +argzize_path (path, pargz, pargz_len) const char *path; + char **pargz; + size_t *pargz_len; { - char *canonical = 0; + error_t error; - if (path && *path) - { - char *ptr = strdup (path); - canonical = ptr; + assert (path); + assert (pargz); + assert (pargz_len); -#ifdef LT_DIRSEP_CHAR - /* Avoid this overhead where '/' is the only separator. */ - while (ptr = strchr (ptr, LT_DIRSEP_CHAR)) + if ((error = argz_create_sep (path, LT_PATHSEP_CHAR, pargz, pargz_len))) + { + switch (error) { - *ptr++ = '/'; + case ENOMEM: + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); + break; + default: + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN)); + break; } -#endif + + return 1; } - return canonical; + return 0; } -static lt_ptr -find_file (basename, search_path, pdir, handle) - const char *basename; +/* Repeatedly call FUNC with each LT_PATHSEP_CHAR delimited element + of SEARCH_PATH and references to DATA1 and DATA2, until FUNC returns + non-zero or all elements are exhausted. If BASE_NAME is non-NULL, + it is appended to each SEARCH_PATH element before FUNC is called. */ +static int +foreach_dirinpath (search_path, base_name, func, data1, data2) const char *search_path; - char **pdir; - lt_dlhandle *handle; + const char *base_name; + foreach_callback_func *func; + lt_ptr data1; + lt_ptr data2; { - /* When handle != NULL search a library, otherwise a file - return NULL on failure, otherwise the file/handle. */ + int result = 0; + int filenamesize = 0; + int lenbase = LT_STRLEN (base_name); + int argz_len = 0; + char *argz = 0; + char *filename = 0; + char *canonical = 0; - lt_ptr result = 0; - char *filename = 0; - int filenamesize= 0; - int lenbase = strlen (basename); - char *canonical = 0; - char *next = 0; - - MUTEX_LOCK (); + LT_DLMUTEX_LOCK (); if (!search_path || !*search_path) { - MUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); goto cleanup; } - canonical = canonicalize_path (search_path); - if (!canonical) - { - MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - goto cleanup; - } + if (canonicalize_path (search_path, &canonical) != 0) + goto cleanup; - next = canonical; - while (next) - { - int lendir; - char *cur = next; + if (argzize_path (canonical, &argz, &argz_len) != 0) + goto cleanup; - next = strchr (cur, LT_PATHSEP_CHAR); - if (!next) - { - next = cur + strlen (cur); - } + { + char *dir_name = 0; + while ((dir_name = argz_next (argz, argz_len, dir_name))) + { + int lendir = LT_STRLEN (dir_name); - lendir = next - cur; - if (*next == LT_PATHSEP_CHAR) + if (lendir +1 +lenbase >= filenamesize) { - ++next; - } - else - { - next = 0; + LT_DLFREE (filename); + filenamesize = lendir +1 +lenbase +1; /* "/d" + '/' + "f" + '\0' */ + filename = LT_EMALLOC (char, filenamesize); + if (!filename) + goto cleanup; } - if (lendir == 0) - { - continue; - } + strncpy (filename, dir_name, lendir); + if (base_name && *base_name) + { + if (filename[lendir -1] != '/') + filename[lendir++] = '/'; + strcpy (filename +lendir, base_name); + } - if (lendir + 1 + lenbase >= filenamesize) - { - LT_DLFREE (filename); - filenamesize = lendir + 1 + lenbase + 1; - filename = LT_DLMALLOC (char, filenamesize); + if ((result = (*func) (filename, data1, data2))) + { + break; + } + } + } - if (!filename) - { - MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - goto cleanup; - } - } + cleanup: + LT_DLFREE (argz); + LT_DLFREE (canonical); + LT_DLFREE (filename); - strncpy(filename, cur, lendir); - if (filename[lendir-1] != '/') - { - filename[lendir++] = '/'; - } - strcpy(filename+lendir, basename); - if (handle) - { - if (tryall_dlopen (handle, filename) == 0) - { - result = (lt_ptr) handle; - goto cleanup; - } - } - else - { - FILE *file = fopen (filename, LT_READTEXT_MODE); - if (file) - { - LT_DLFREE (*pdir); + LT_DLMUTEX_UNLOCK (); - filename[lendir] = '\0'; - *pdir = strdup(filename); - if (!*pdir) - { - /* We could have even avoided the strdup, - but there would be some memory overhead. */ - *pdir = filename; - filename = 0; - } + return result; +} - result = (lt_ptr) file; - goto cleanup; - } - } +/* If FILEPATH can be opened, store the name of the directory component + in DATA1, and the opened FILE* structure address in DATA2. Otherwise + DATA1 is unchanged, but DATA2 is set to a pointer to NULL. */ +static int +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; + + assert (filename && *filename); + assert (pdir); + assert (pfile); + + if ((*pfile = fopen (filename, LT_READTEXT_MODE))) + { + char *dirend = strrchr (filename, '/'); + + if (dirend > filename) + *dirend = LT_EOS_CHAR; + + LT_DLFREE (*pdir); + *pdir = lt_estrdup (filename); + is_done = (*pdir == 0) ? -1 : 1; } - MUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); + return is_done; +} - cleanup: - LT_DLFREE (filename); - LT_DLFREE (canonical); +static FILE * +find_file (search_path, base_name, pdir) + const char *search_path; + const char *base_name; + char **pdir; +{ + FILE *file = 0; - MUTEX_UNLOCK (); + foreach_dirinpath (search_path, base_name, find_file_callback, pdir, &file); - return result; + return file; +} + +static int +find_handle_callback (filename, data, ignored) + char *filename; + lt_ptr data; + lt_ptr ignored; +{ + lt_dlhandle *handle = (lt_dlhandle *) data; + int found = access (filename, R_OK); + + /* Bail out if file cannot be read... */ + if (!found) + return 0; + + /* Try to dlopen the file, but do not continue searching in any + case. */ + if (tryall_dlopen (handle, filename) != 0) + *handle = 0; + + return 1; +} + +/* 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; +{ + if (!search_path) + return 0; + + if (!foreach_dirinpath (search_path, base_name, find_handle_callback, + handle, 0)) + return 0; + + return handle; } static int -load_deplibs(handle, deplibs) +load_deplibs (handle, deplibs) lt_dlhandle handle; char *deplibs; { #if LTDL_DLOPEN_DEPLIBS - char *p, *save_search_path; + char *p, *save_search_path = 0; int depcount = 0; int i; char **names = 0; @@ -1782,12 +2298,12 @@ load_deplibs(handle, deplibs) } ++errors; - MUTEX_LOCK (); - save_search_path = strdup (user_search_path); - if (user_search_path && !save_search_path) + LT_DLMUTEX_LOCK (); + if (user_search_path) { - MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - goto cleanup; + save_search_path = lt_estrdup (user_search_path); + if (!save_search_path) + goto cleanup; } /* extract search paths and count deplibs */ @@ -1829,7 +2345,7 @@ load_deplibs(handle, deplibs) LT_DLFREE (user_search_path); user_search_path = save_search_path; - MUTEX_UNLOCK (); + LT_DLMUTEX_UNLOCK (); if (!depcount) { @@ -1837,11 +2353,9 @@ load_deplibs(handle, deplibs) goto cleanup; } - names = LT_DLMALLOC (char *, depcount * sizeof (char*)); + names = LT_EMALLOC (char *, depcount * sizeof (char*)); if (!names) - { - goto cleanup; - } + goto cleanup; /* now only extract the actual deplibs */ depcount = 0; @@ -1867,25 +2381,18 @@ load_deplibs(handle, deplibs) *end = 0; /* set a temporary string terminator */ if (strncmp(p, "-l", 2) == 0) { - name = LT_DLMALLOC (char, 3+ /* "lib" */ strlen (p+2) + 1); + 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); - } + sprintf (name, "lib%s", p+2); } else - { - name = strdup(p); - } + name = lt_estrdup(p); - if (name) - { - names[depcount++] = name; - } - else - { - goto cleanup_names; - } + if (!name) + goto cleanup_names; + + names[depcount++] = name; *end = save; } p = end; @@ -1901,11 +2408,9 @@ load_deplibs(handle, deplibs) { int j = 0; - handle->deplibs = (lt_dlhandle*) LT_DLMALLOC (lt_dlhandle *, depcount); + handle->deplibs = (lt_dlhandle*) LT_EMALLOC (lt_dlhandle *, depcount); if (!handle->deplibs) - { - goto cleanup; - } + goto cleanup; for (i = 0; i < depcount; ++i) { @@ -1934,7 +2439,7 @@ load_deplibs(handle, deplibs) } static int -unload_deplibs(handle) +unload_deplibs (handle) lt_dlhandle handle; { int i; @@ -1962,22 +2467,19 @@ trim (dest, str) /* remove the leading and trailing "'" from str and store the result in dest */ const char *end = strrchr (str, '\''); - int len = strlen (str); + int len = LT_STRLEN (str); char *tmp; LT_DLFREE (*dest); if (len > 3 && str[0] == '\'') { - tmp = LT_DLMALLOC (char, end - str); + tmp = LT_EMALLOC (char, end - str); if (!tmp) - { - last_error = LT_DLSTRERROR (NO_MEMORY); - return 1; - } + return 1; strncpy(tmp, &str[1], (end - str) - 1); - tmp[len-3] = '\0'; + tmp[len-3] = LT_EOS_CHAR; *dest = tmp; } else @@ -1989,7 +2491,7 @@ trim (dest, str) } static int -free_vars( dlname, oldname, libdir, deplibs) +free_vars (dlname, oldname, libdir, deplibs) char *dlname; char *oldname; char *libdir; @@ -2003,83 +2505,94 @@ free_vars( dlname, oldname, libdir, deplibs) return 0; } -lt_dlhandle -lt_dlopen (filename) +int +try_dlopen (phandle, filename) + lt_dlhandle *phandle; const char *filename; { - lt_dlhandle handle = 0, newhandle; - const char *ext; - const char *saved_error; - char *canonical = 0, *basename = 0, *dir = 0, *name = 0; + 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; - MUTEX_GETERROR (saved_error); + assert (phandle); + assert (*phandle == 0); + + LT_DLMUTEX_GETERROR (saved_error); /* dlopen self? */ if (!filename) { - handle = (lt_dlhandle) LT_DLMALLOC (struct lt_dlhandle_struct, 1); - if (!handle) - { - MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - return 0; - } + *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1); + if (*phandle == 0) + return 1; - memset (handle, 0, 1*sizeof(struct lt_dlhandle_struct)); - newhandle = handle; + memset (*phandle, 0, sizeof(struct lt_dlhandle_struct)); + newhandle = *phandle; /* lt_dlclose()ing yourself is very bad! Disallow it. */ - LT_DLSET_FLAG (handle, LT_DLRESIDENT_FLAG); + LT_DLSET_FLAG (*phandle, LT_DLRESIDENT_FLAG); if (tryall_dlopen (&newhandle, 0) != 0) { - LT_DLFREE (handle); - return 0; + LT_DLFREE (*phandle); + return 1; } + goto register_handle; } - canonical = canonicalize_path (filename); - if (!canonical) + assert (filename && *filename); + + /* Doing this immediately allows internal functions to safely + assume only canonicalized paths are passed. */ + if (canonicalize_path (filename, &canonical) != 0) { - MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - LT_DLFREE (handle); - return 0; + ++errors; + goto cleanup; } /* If the canonical module name is a path (relative or absolute) then split it into a directory part and a name part. */ - basename = strrchr (canonical, '/'); - if (basename) + base_name = strrchr (canonical, '/'); + if (base_name) { - ++basename; - dir = LT_DLMALLOC (char, basename - canonical + 1); + size_t dirlen = (1+ base_name) - canonical; + + dir = LT_EMALLOC (char, 1+ dirlen); if (!dir) { - MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - handle = 0; + ++errors; goto cleanup; } - strncpy (dir, canonical, basename - canonical); - dir[basename - canonical] = '\0'; + strncpy (dir, canonical, dirlen); + dir[dirlen] = LT_EOS_CHAR; + + ++base_name; } else - { - basename = canonical; - } + LT_DLMEM_REASSIGN (base_name, canonical); + + assert (base_name && *base_name); /* Check whether we are opening a libtool module (.la extension). */ - ext = strrchr(basename, '.'); - if (ext && strcmp(ext, ".la") == 0) + ext = strrchr (base_name, '.'); + if (ext && strcmp (ext, archive_ext) == 0) { /* this seems to be a libtool module */ - FILE *file = 0; - int i; - char *dlname = 0, *old_name = 0; - char *libdir = 0, *deplibs = 0; - char *line; + FILE * file = 0; + char * dlname = 0; + char * old_name = 0; + char * libdir = 0; + char * deplibs = 0; + char * line = 0; size_t line_len; - int error = 0; + int i; /* if we can't find the installed flag, it is probably an installed libtool archive, produced with an old version @@ -2087,28 +2600,26 @@ lt_dlopen (filename) int installed = 1; /* extract the module name from the file name */ - name = LT_DLMALLOC (char, ext - basename + 1); + name = LT_EMALLOC (char, ext - base_name + 1); if (!name) { - MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - handle = 0; + ++errors; goto cleanup; } /* canonicalize the module name */ - for (i = 0; i < ext - basename; ++i) + for (i = 0; i < ext - base_name; ++i) { - if (isalnum ((int)(basename[i]))) + if (isalnum ((int)(base_name[i]))) { - name[i] = basename[i]; + name[i] = base_name[i]; } else { name[i] = '_'; } } - - name[ext - basename] = '\0'; + name[ext - base_name] = LT_EOS_CHAR; /* 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 @@ -2116,24 +2627,33 @@ lt_dlopen (filename) yet found) try opening just the module name as passed. */ if (!dir) { - file = (FILE*) find_file(basename, user_search_path, &dir, 0); + const char *search_path; + + 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) { - file = (FILE*) find_file(basename, getenv("LTDL_LIBRARY_PATH"), - &dir, 0); + search_path = getenv (LTDL_SEARCHPATH_VAR); + if (search_path) + file = find_file (search_path, base_name, &dir); } #ifdef LTDL_SHLIBPATH_VAR if (!file) { - file = (FILE*) find_file(basename, getenv(LTDL_SHLIBPATH_VAR), - &dir, 0); + search_path = getenv (LTDL_SHLIBPATH_VAR); + if (search_path) + file = find_file (search_path, base_name, &dir); } #endif #ifdef LTDL_SYSSEARCHPATH - if (!file) + if (!file && sys_search_path) { - file = (FILE*) find_file(basename, sys_search_path, &dir, 0); + file = find_file (sys_search_path, base_name, &dir); } #endif } @@ -2141,39 +2661,36 @@ lt_dlopen (filename) { file = fopen (filename, LT_READTEXT_MODE); } - if (!file) - { - MUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); - } + /* If we didn't find the file by now, it really isn't there. Set + the status flag, and bail out. */ if (!file) { - handle = 0; + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); + ++errors; goto cleanup; } line_len = LT_FILENAME_MAX; - line = LT_DLMALLOC (char, line_len); + line = LT_EMALLOC (char, line_len); if (!line) { fclose (file); - MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - handle = 0; + ++errors; goto cleanup; } /* read the .la file */ - while (!feof(file)) + while (!feof (file)) { if (!fgets (line, line_len, file)) { break; } - - /* Handle the case where we occasionally need to read a line + /* Handle the case where we occasionally need to read a line that is longer than the initial buffer size. */ - while (line[strlen(line) -1] != '\n') + while (line[LT_STRLEN(line) -1] != '\n') { line = LT_DLREALLOC (char, line, line_len *2); if (!fgets (&line[line_len -1], line_len +1, file)) @@ -2192,7 +2709,7 @@ lt_dlopen (filename) #define STR_DLNAME "dlname=" if (strncmp (line, STR_DLNAME, sizeof (STR_DLNAME) - 1) == 0) { - error = trim (&dlname, &line[sizeof (STR_DLNAME) - 1]); + errors += trim (&dlname, &line[sizeof (STR_DLNAME) - 1]); } #undef STR_OLD_LIBRARY @@ -2200,13 +2717,13 @@ lt_dlopen (filename) else if (strncmp (line, STR_OLD_LIBRARY, sizeof (STR_OLD_LIBRARY) - 1) == 0) { - error = trim (&old_name, &line[sizeof (STR_OLD_LIBRARY) - 1]); + 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) { - error = trim (&libdir, &line[sizeof(STR_LIBDIR) - 1]); + errors += trim (&libdir, &line[sizeof(STR_LIBDIR) - 1]); } #undef STR_DL_DEPLIBS @@ -2214,7 +2731,7 @@ lt_dlopen (filename) else if (strncmp (line, STR_DL_DEPLIBS, sizeof (STR_DL_DEPLIBS) - 1) == 0) { - error = trim (&deplibs, &line[sizeof (STR_DL_DEPLIBS) - 1]); + errors += trim (&deplibs, &line[sizeof (STR_DL_DEPLIBS) - 1]); } else if (strcmp (line, "installed=yes\n") == 0) { @@ -2231,210 +2748,491 @@ lt_dlopen (filename) sizeof (STR_LIBRARY_NAMES) - 1) == 0) { char *last_libname; - error = trim (&dlname, &line[sizeof (STR_LIBRARY_NAMES) - 1]); - if (! error && dlname && - (last_libname = strrchr (dlname, ' ')) != NULL) + errors += trim (&dlname, &line[sizeof (STR_LIBRARY_NAMES) - 1]); + if (!errors + && dlname + && (last_libname = strrchr (dlname, ' ')) != 0) { - last_libname = strdup (last_libname + 1); + last_libname = lt_estrdup (last_libname + 1); + if (!last_libname) + { + ++errors; + goto cleanup; + } LT_DLMEM_REASSIGN (dlname, last_libname); } } - if (error) - { - break; - } + if (errors) + break; } fclose (file); LT_DLFREE (line); /* allocate the handle */ - handle = (lt_dlhandle) LT_DLMALLOC (struct lt_dlhandle_struct, 1); - if (!handle || error) - { - LT_DLFREE (handle); - if (!error) - { - MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - } + *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1); + if (*phandle == 0) + ++errors; + if (errors) + { free_vars (dlname, old_name, libdir, deplibs); - /* handle is already set to 0 */ + LT_DLFREE (*phandle); goto cleanup; } - memset (handle, 0, 1*sizeof(struct lt_dlhandle_struct)); - if (load_deplibs (handle, deplibs) == 0) + assert (*phandle); + + memset (*phandle, 0, sizeof(struct lt_dlhandle_struct)); + if (load_deplibs (*phandle, deplibs) == 0) { - newhandle = handle; + newhandle = *phandle; /* find_module may replace newhandle */ if (find_module (&newhandle, dir, libdir, dlname, old_name, installed)) { - unload_deplibs (handle); - error = 1; + unload_deplibs (*phandle); + ++errors; } } else { - error = 1; + ++errors; } free_vars (dlname, old_name, libdir, deplibs); - if (error) + if (errors) { - LT_DLFREE (handle); + LT_DLFREE (*phandle); goto cleanup; } - if (handle != newhandle) + if (*phandle != newhandle) { - unload_deplibs (handle); + unload_deplibs (*phandle); } } else { /* not a libtool module */ - handle = (lt_dlhandle) LT_DLMALLOC (struct lt_dlhandle_struct, 1); - if (!handle) + *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1); + if (*phandle == 0) { - MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - /* handle is already set to 0 */ + ++errors; goto cleanup; } - handle->info.ref_count = 0; - /* non-libtool modules don't have dependencies */ - handle->depcount = 0; - handle->deplibs = 0; - newhandle = handle; + + 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_file (basename, user_search_path, 0, &newhandle) - && !find_file (basename, getenv ("LTDL_LIBRARY_PATH"), - 0, &newhandle) + if ((dir || (!find_handle (user_search_path, base_name, &newhandle) + && !find_handle (getenv (LTDL_SEARCHPATH_VAR), base_name, + &newhandle) #ifdef LTDL_SHLIBPATH_VAR - && !find_file (basename, getenv (LTDL_SHLIBPATH_VAR), - 0, &newhandle) + && !find_handle (getenv (LTDL_SHLIBPATH_VAR), base_name, + &newhandle) #endif #ifdef LTDL_SYSSEARCHPATH - && !find_file (basename, sys_search_path, 0, &newhandle) + && !find_handle (sys_search_path, base_name, &newhandle) #endif - )) && tryall_dlopen (&newhandle, filename)) + ))) + { + tryall_dlopen (&newhandle, filename); + } + + if (!newhandle) { - LT_DLFREE (handle); + LT_DLFREE (*phandle); + ++errors; goto cleanup; } } register_handle: - LT_DLMEM_REASSIGN (handle, newhandle); + LT_DLMEM_REASSIGN (*phandle, newhandle); - if (handle->info.ref_count == 0) + if ((*phandle)->info.ref_count == 0) { - handle->info.ref_count = 1; - handle->info.name = name; - handle->next = handles; - - MUTEX_LOCK (); - handles = handle; - MUTEX_UNLOCK (); + (*phandle)->info.ref_count = 1; + LT_DLMEM_REASSIGN ((*phandle)->info.name, name); - name = 0; /* don't free this during `cleanup' */ + LT_DLMUTEX_LOCK (); + (*phandle)->next = handles; + handles = *phandle; + LT_DLMUTEX_UNLOCK (); } - MUTEX_SETERROR (saved_error); + LT_DLMUTEX_SETERROR (saved_error); cleanup: LT_DLFREE (dir); LT_DLFREE (name); LT_DLFREE (canonical); + 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. */ +int +file_not_found () +{ + const char *error = 0; + + LT_DLMUTEX_GETERROR (error); + if (error == LT_DLSTRERROR (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; - char *tmp; - int len; - const char *saved_error; - - MUTEX_GETERROR (saved_error); + lt_dlhandle handle = 0; + char * tmp = 0; + char * ext = 0; + int len; + int errors = 0; + int file_found = 1; /* until proven otherwise */ if (!filename) { return lt_dlopen (filename); } - len = strlen (filename); - if (!len) + 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) +#endif + )) { - MUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); - return 0; + return lt_dlopen (filename); } - /* try "filename.la" */ - tmp = LT_DLMALLOC (char, len+4); + /* First try appending ARCHIVE_EXT. */ + tmp = LT_EMALLOC (char, len + LT_STRLEN (archive_ext) + 1); if (!tmp) - { - MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - return 0; - } + return 0; + strcpy (tmp, filename); - strcat (tmp, ".la"); - handle = lt_dlopen (tmp); - if (handle) + 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 ())) { - MUTEX_SETERROR (saved_error); LT_DLFREE (tmp); return handle; } #ifdef LTDL_SHLIB_EXT - /* try "filename.EXT" */ - if (strlen(shlib_ext) > 3) + /* Try appending SHLIB_EXT. */ + if (LT_STRLEN (shlib_ext) > LT_STRLEN (archive_ext)) { LT_DLFREE (tmp); - tmp = LT_DLMALLOC (char, len + strlen (shlib_ext) + 1); + tmp = LT_EMALLOC (char, len + LT_STRLEN (shlib_ext) + 1); if (!tmp) - { - MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - return 0; - } + return 0; + strcpy (tmp, filename); } else { - tmp[len] = '\0'; + tmp[len] = LT_EOS_CHAR; } strcat(tmp, shlib_ext); - handle = lt_dlopen (tmp); - if (handle) + errors = try_dlopen (&handle, tmp); + + /* As before, if the file was found but loading failed, return now + with the current error message. */ + if (handle || ((errors > 0) && file_not_found ())) { - MUTEX_SETERROR (saved_error); LT_DLFREE (tmp); return handle; } #endif - /* try the normal file name */ - handle = lt_dlopen (filename); - if (handle) + /* 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); + return 0; +} + + +int +lt_argz_insert (pargz, pargz_len, before, entry) + char **pargz; + size_t *pargz_len; + char *before; + const char *entry; +{ + error_t error; + + if ((error = argz_insert (pargz, pargz_len, before, entry))) { - return handle; + switch (error) + { + case ENOMEM: + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); + break; + default: + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN)); + break; + } + return 1; } - MUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); - LT_DLFREE (tmp); return 0; } +int +lt_argz_insertinorder (pargz, pargz_len, entry) + char **pargz; + size_t *pargz_len; + const char *entry; +{ + char *before = 0; + + assert (pargz); + assert (pargz_len); + assert (entry && *entry); + + if (*pargz) + while ((before = argz_next (*pargz, *pargz_len, before))) + { + int cmp = strcmp (entry, before); + + if (cmp < 0) break; + if (cmp == 0) return 0; /* No duplicates! */ + } + + return lt_argz_insert (pargz, pargz_len, before, entry); +} + +int +lt_argz_insertdir (pargz, pargz_len, dirnam, dp) + char **pargz; + size_t *pargz_len; + const char *dirnam; + struct dirent *dp; +{ + char *buf = 0; + size_t buf_len = 0; + char *end = 0; + size_t end_offset = 0; + size_t dir_len = 0; + int errors = 0; + + assert (pargz); + assert (pargz_len); + assert (dp); + + dir_len = LT_STRLEN (dirnam); + end = dp->d_name + LT_D_NAMLEN(dp); + + /* Ignore version numbers. */ + { + char *p; + for (p = end; p -1 > dp->d_name; --p) + if (strchr (".0123456789", p[-1]) == 0) + break; + + if (*p == '.') + end = p; + } + + /* Ignore filename extension. */ + { + char *p; + for (p = end -1; p > dp->d_name; --p) + if (*p == '.') + { + end = p; + break; + } + } + + /* Prepend the directory name. */ + end_offset = end - dp->d_name; + buf_len = dir_len + 1+ end_offset; + buf = LT_EMALLOC (char, 1+ buf_len); + if (!buf) + return ++errors; + + assert (buf); + + strcpy (buf, dirnam); + strcat (buf, "/"); + strncat (buf, dp->d_name, end_offset); + buf[buf_len] = LT_EOS_CHAR; + + /* Try to insert (in order) into ARGZ/ARGZ_LEN. */ + if (lt_argz_insertinorder (pargz, pargz_len, buf) != 0) + ++errors; + + LT_DLFREE (buf); + + return errors; +} + +int +list_files_by_dir (dirnam, pargz, pargz_len) + const char *dirnam; + char **pargz; + size_t *pargz_len; +{ + DIR *dirp = 0; + int errors = 0; + + assert (dirnam && *dirnam); + assert (pargz); + assert (pargz_len); + assert (dirnam[LT_STRLEN(dirnam) -1] != '/'); + + dirp = opendir (dirnam); + if (dirp) + { + struct dirent *dp = 0; + + while ((dp = readdir (dirp))) + if (dp->d_name[0] != '.') + if (lt_argz_insertdir (pargz, pargz_len, dirnam, dp)) + { + ++errors; + break; + } + + closedir (dirp); + } + else + ++errors; + + return errors; +} + + +/* If there are any files in DIRNAME, call the function passed in + DATA1 (with the name of each file and DATA2 as arguments). */ +static int +foreachfile_callback (dirname, data1, data2) + char *dirname; + lt_ptr data1; + lt_ptr data2; +{ + int (*func) LT_PARAMS((const char *filename, lt_ptr data)) + = (int (*) LT_PARAMS((const char *filename, lt_ptr data))) data1; + + int is_done = 0; + char *argz = 0; + size_t argz_len = 0; + + if (list_files_by_dir (dirname, &argz, &argz_len) != 0) + goto cleanup; + if (!argz) + goto cleanup; + + { + char *filename = 0; + while ((filename = argz_next (argz, argz_len, filename))) + if ((is_done = (*func) (filename, data2))) + break; + } + + cleanup: + LT_DLFREE (argz); + + return is_done; +} + + +/* Call FUNC for each unique extensionless file in SEARCH_PATH, along + with DATA. The filenames passed to FUNC would be suitable for + passing to lt_dlopenext. The extensions are stripped so that + individual modules do not generate several entries (e.g. libfoo.la, + libfoo.so, libfoo.so.1, libfoo.so.1.0.0). If SEARCH_PATH is NULL, + then the same directories that lt_dlopen would search are examined. */ +int +lt_dlforeachfile (search_path, func, data) + const char *search_path; + int (*func) LT_PARAMS ((const char *filename, lt_ptr data)); + lt_ptr data; +{ + int is_done = 0; + + if (search_path) + { + /* If a specific path was passed, search only the directories + listed in it. */ + is_done = foreach_dirinpath (search_path, 0, + foreachfile_callback, func, data); + } + else + { + /* Otherwise search the default paths. */ + is_done = foreach_dirinpath (user_search_path, 0, + foreachfile_callback, func, data); + if (!is_done) + { + is_done = foreach_dirinpath (getenv("LTDL_LIBRARY_PATH"), 0, + foreachfile_callback, func, 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 (!is_done) + { + is_done = foreach_dirinpath (getenv(LTDL_SYSSEARCHPATH), 0, + foreachfile_callback, func, data); + } +#endif + } + + return is_done; +} + int lt_dlclose (handle) lt_dlhandle handle; @@ -2442,7 +3240,7 @@ lt_dlclose (handle) lt_dlhandle cur, last; int errors = 0; - MUTEX_LOCK (); + LT_DLMUTEX_LOCK (); /* check whether the handle is valid */ last = cur = handles; @@ -2454,7 +3252,7 @@ lt_dlclose (handle) if (!cur) { - MUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); ++errors; goto done; } @@ -2490,12 +3288,12 @@ lt_dlclose (handle) if (LT_DLIS_RESIDENT (handle)) { - MUTEX_SETERROR (LT_DLSTRERROR (CLOSE_RESIDENT_MODULE)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CLOSE_RESIDENT_MODULE)); ++errors; } done: - MUTEX_UNLOCK (); + LT_DLMUTEX_UNLOCK (); return errors; } @@ -2513,26 +3311,18 @@ lt_dlsym (handle, symbol) if (!handle) { - MUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); return 0; } if (!symbol) { - MUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); return 0; } - lensym = strlen(symbol); - if (handle->loader->sym_prefix) - { - lensym += strlen(handle->loader->sym_prefix); - } - - if (handle->info.name) - { - lensym += strlen(handle->info.name); - } + lensym = LT_STRLEN (symbol) + LT_STRLEN (handle->loader->sym_prefix) + + LT_STRLEN (handle->info.name); if (lensym + LT_SYMBOL_OVERHEAD < LT_SYMBOL_LENGTH) { @@ -2540,13 +3330,12 @@ lt_dlsym (handle, symbol) } else { - sym = LT_DLMALLOC (char, lensym + LT_SYMBOL_OVERHEAD + 1); - } - - if (!sym) - { - MUTEX_SETERROR (LT_DLSTRERROR (BUFFER_OVERFLOW)); - return 0; + sym = LT_EMALLOC (char, lensym + LT_SYMBOL_OVERHEAD + 1); + if (!sym) + { + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (BUFFER_OVERFLOW)); + return 0; + } } data = handle->loader->dlloader_data; @@ -2554,7 +3343,7 @@ lt_dlsym (handle, symbol) { const char *saved_error; - MUTEX_GETERROR (saved_error); + LT_DLMUTEX_GETERROR (saved_error); /* this is a libtool module */ if (handle->loader->sym_prefix) @@ -2580,7 +3369,7 @@ lt_dlsym (handle, symbol) } return address; } - MUTEX_SETERROR (saved_error); + LT_DLMUTEX_SETERROR (saved_error); } /* otherwise try "symbol" */ @@ -2608,10 +3397,82 @@ lt_dlerror () { const char *error; - MUTEX_GETERROR (error); - MUTEX_SETERROR (0); + LT_DLMUTEX_GETERROR (error); + LT_DLMUTEX_SETERROR (0); - return error; + return error ? error : LT_DLSTRERROR (UNKNOWN); +} + +int +lt_dlpath_insertdir (ppath, before, dir) + char **ppath; + char *before; + const char *dir; +{ + int errors = 0; + char *canonical = 0; + char *argz = 0; + size_t argz_len = 0; + + assert (ppath); + assert (dir && *dir); + + if (canonicalize_path (dir, &canonical) != 0) + { + ++errors; + goto cleanup; + } + + assert (canonical && *canonical); + + /* If *PPATH is empty, set it to DIR. */ + if (*ppath == 0) + { + assert (!before); /* BEFORE cannot be set without PPATH. */ + assert (dir); /* Without DIR, don't call this function! */ + + *ppath = lt_estrdup (dir); + if (*ppath == 0) + ++errors; + + return errors; + } + + assert (ppath && *ppath); + + if (argzize_path (*ppath, &argz, &argz_len) != 0) + { + ++errors; + goto cleanup; + } + + /* Convert BEFORE into an equivalent offset into ARGZ. This only works + if *PPATH is already canonicalized, and hence does not change length + with respect to ARGZ. We canonicalize each entry as it is added to + the search path, and don't call this function with (uncanonicalized) + user paths, so this is a fair assumption. */ + if (before) + { + assert (*ppath <= before); + assert (before - *ppath <= strlen (*ppath)); + + before = before - *ppath + argz; + } + + if (lt_argz_insert (&argz, &argz_len, before, dir) != 0) + { + ++errors; + goto cleanup; + } + + argz_stringify (argz, argz_len, LT_PATHSEP_CHAR); + LT_DLMEM_REASSIGN (*ppath, argz); + + cleanup: + LT_DLFREE (canonical); + LT_DLFREE (argz); + + return errors; } int @@ -2620,40 +3481,47 @@ lt_dladdsearchdir (search_dir) { int errors = 0; - if (!search_dir || !strlen(search_dir)) + if (search_dir && *search_dir) { - return errors; + LT_DLMUTEX_LOCK (); + if (lt_dlpath_insertdir (&user_search_path, 0, search_dir) != 0) + ++errors; + LT_DLMUTEX_UNLOCK (); } - MUTEX_LOCK (); - if (!user_search_path) + return errors; +} + +int +lt_dlinsertsearchdir (before, search_dir) + const char *before; + const char *search_dir; +{ + int errors = 0; + + if (before) { - user_search_path = strdup (search_dir); - if (!user_search_path) + LT_DLMUTEX_LOCK (); + if ((before < user_search_path) + || (before >= user_search_path + LT_STRLEN (user_search_path))) { - last_error = LT_DLSTRERROR (NO_MEMORY); - ++errors; + LT_DLMUTEX_UNLOCK (); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_POSITION)); + return 1; } + LT_DLMUTEX_UNLOCK (); } - else - { - size_t len = strlen (user_search_path) + 1 + strlen (search_dir); - char *new_search_path = LT_DLMALLOC (char, 1+ len); - if (!new_search_path) + if (search_dir && *search_dir) + { + LT_DLMUTEX_LOCK (); + if (lt_dlpath_insertdir (&user_search_path, + (char *) before, search_dir) != 0) { - MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); ++errors; } - else - { - sprintf (new_search_path, "%s%c%s", user_search_path, - LT_PATHSEP_CHAR, search_dir); - - LT_DLMEM_REASSIGN (user_search_path, new_search_path); - } + LT_DLMUTEX_UNLOCK (); } - MUTEX_UNLOCK (); return errors; } @@ -2662,24 +3530,21 @@ int lt_dlsetsearchpath (search_path) const char *search_path; { - int errors = 0; + int errors = 0; - MUTEX_LOCK (); + LT_DLMUTEX_LOCK (); LT_DLFREE (user_search_path); - MUTEX_UNLOCK (); + LT_DLMUTEX_UNLOCK (); - if (!search_path || !strlen (search_path)) + if (!search_path || !LT_STRLEN (search_path)) { return errors; } - MUTEX_LOCK (); - user_search_path = strdup (search_path); - if (!user_search_path) - { - ++errors; - } - MUTEX_UNLOCK (); + LT_DLMUTEX_LOCK (); + if (canonicalize_path (search_path, &user_search_path) != 0) + ++errors; + LT_DLMUTEX_UNLOCK (); return errors; } @@ -2689,9 +3554,9 @@ lt_dlgetsearchpath () { const char *saved_path; - MUTEX_LOCK (); + LT_DLMUTEX_LOCK (); saved_path = user_search_path; - MUTEX_UNLOCK (); + LT_DLMUTEX_UNLOCK (); return saved_path; } @@ -2704,7 +3569,7 @@ lt_dlmakeresident (handle) if (!handle) { - MUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); ++errors; } else @@ -2721,7 +3586,7 @@ lt_dlisresident (handle) { if (!handle) { - MUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); return -1; } @@ -2739,7 +3604,7 @@ lt_dlgetinfo (handle) { if (!handle) { - MUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); return 0; } @@ -2750,7 +3615,7 @@ lt_dlhandle lt_dlhandle_next (place) lt_dlhandle place; { - return place ? place->next : (lt_dlhandle) 0; + return place ? place->next : handles; } int @@ -2761,7 +3626,7 @@ lt_dlforeach (func, data) int errors = 0; lt_dlhandle cur; - MUTEX_LOCK (); + LT_DLMUTEX_LOCK (); cur = handles; while (cur) @@ -2776,7 +3641,7 @@ lt_dlforeach (func, data) } } - MUTEX_UNLOCK (); + LT_DLMUTEX_UNLOCK (); return errors; } @@ -2784,18 +3649,16 @@ lt_dlforeach (func, data) lt_dlcaller_id lt_dlcaller_register () { - static int last_caller_id = -1; + static lt_dlcaller_id last_caller_id = 0; int result; - MUTEX_LOCK (); + LT_DLMUTEX_LOCK (); result = ++last_caller_id; - MUTEX_UNLOCK (); + LT_DLMUTEX_UNLOCK (); return result; } -#define N_ELEMENTS(a) (sizeof(a) / sizeof(*(a))) - lt_ptr lt_dlcaller_set_data (key, handle, data) lt_dlcaller_id key; @@ -2808,10 +3671,11 @@ lt_dlcaller_set_data (key, handle, data) /* This needs to be locked so that the caller data can be updated simultaneously by different threads. */ - MUTEX_LOCK (); + LT_DLMUTEX_LOCK (); if (handle->caller_data) - n_elements = N_ELEMENTS (handle->caller_data); + while (handle->caller_data[n_elements].key) + ++n_elements; for (i = 0; i < n_elements; ++i) { @@ -2823,31 +3687,29 @@ lt_dlcaller_set_data (key, handle, data) } /* Ensure that there is enough room in this handle's caller_data - array to accept a new element. */ + 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, 1+ n_elements); + = LT_DLREALLOC (lt_caller_data, handle->caller_data, 2+ n_elements); - if (temp == 0) + if (!temp) { - MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - stale = (lt_ptr) 0; + stale = 0; goto done; } - else - { - handle->caller_data = temp; - } + + handle->caller_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; } handle->caller_data[i].data = data; done: - MUTEX_UNLOCK (); + LT_DLMUTEX_UNLOCK (); return stale; } @@ -2858,19 +3720,15 @@ lt_dlcaller_get_data (key, handle) lt_dlhandle handle; { lt_ptr result = (lt_ptr) 0; - int n_elements = 0; /* This needs to be locked so that the caller data isn't updated by another thread part way through this function. */ - MUTEX_LOCK (); - - if (handle->caller_data) - n_elements = N_ELEMENTS (handle->caller_data); + LT_DLMUTEX_LOCK (); /* Locate the index of the element with a matching KEY. */ { int i; - for (i = 0; i < n_elements; ++i) + for (i = 0; handle->caller_data[i].key; ++i) { if (handle->caller_data[i].key == key) { @@ -2880,7 +3738,7 @@ lt_dlcaller_get_data (key, handle) } } - MUTEX_UNLOCK (); + LT_DLMUTEX_UNLOCK (); return result; } @@ -2904,17 +3762,14 @@ lt_dlloader_add (place, dlloader, loader_name) || (dlloader->module_close == 0) || (dlloader->find_sym == 0)) { - MUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); return 1; } /* Create a new dlloader node with copies of the user callbacks. */ - node = LT_DLMALLOC (lt_dlloader, 1); - if (node == 0) - { - MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); - return 1; - } + node = LT_EMALLOC (lt_dlloader, 1); + if (!node) + return 1; node->next = 0; node->loader_name = loader_name; @@ -2925,7 +3780,7 @@ lt_dlloader_add (place, dlloader, loader_name) node->find_sym = dlloader->find_sym; node->dlloader_data = dlloader->dlloader_data; - MUTEX_LOCK (); + LT_DLMUTEX_LOCK (); if (!loaders) { /* If there are no loaders, NODE becomes the list! */ @@ -2958,7 +3813,7 @@ lt_dlloader_add (place, dlloader, loader_name) if (ptr->next != place) { - last_error = LT_DLSTRERROR (INVALID_LOADER); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); ++errors; } else @@ -2969,7 +3824,7 @@ lt_dlloader_add (place, dlloader, loader_name) } } - MUTEX_UNLOCK (); + LT_DLMUTEX_UNLOCK (); return errors; } @@ -2984,18 +3839,18 @@ lt_dlloader_remove (loader_name) if (!place) { - MUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); return 1; } - MUTEX_LOCK (); + LT_DLMUTEX_LOCK (); /* Fail if there are any open modules which use this loader. */ for (handle = handles; handle; handle = handle->next) { if (handle->loader == place) { - MUTEX_SETERROR (LT_DLSTRERROR (REMOVE_LOADER)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (REMOVE_LOADER)); ++errors; goto done; } @@ -3030,7 +3885,7 @@ lt_dlloader_remove (loader_name) LT_DLFREE (place); done: - MUTEX_UNLOCK (); + LT_DLMUTEX_UNLOCK (); return errors; } @@ -3041,9 +3896,9 @@ lt_dlloader_next (place) { lt_dlloader *next; - MUTEX_LOCK (); + LT_DLMUTEX_LOCK (); next = place ? place->next : loaders; - MUTEX_UNLOCK (); + LT_DLMUTEX_UNLOCK (); return next; } @@ -3056,13 +3911,13 @@ lt_dlloader_name (place) if (place) { - MUTEX_LOCK (); + LT_DLMUTEX_LOCK (); name = place ? place->loader_name : 0; - MUTEX_UNLOCK (); + LT_DLMUTEX_UNLOCK (); } else { - MUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); } return name; @@ -3076,13 +3931,13 @@ lt_dlloader_data (place) if (place) { - MUTEX_LOCK (); + LT_DLMUTEX_LOCK (); data = place ? &(place->dlloader_data) : 0; - MUTEX_UNLOCK (); + LT_DLMUTEX_UNLOCK (); } else { - MUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); + LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); } return data; @@ -3094,7 +3949,7 @@ lt_dlloader_find (loader_name) { lt_dlloader *place = 0; - MUTEX_LOCK (); + LT_DLMUTEX_LOCK (); for (place = loaders; place; place = place->next) { if (strcmp (place->loader_name, loader_name) == 0) @@ -3102,7 +3957,7 @@ lt_dlloader_find (loader_name) break; } } - MUTEX_UNLOCK (); + LT_DLMUTEX_UNLOCK (); return place; } diff --git a/libltdl/ltdl.h b/libltdl/ltdl.h index 28606c114..2bbfa302c 100644 --- a/libltdl/ltdl.h +++ b/libltdl/ltdl.h @@ -34,6 +34,9 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA /* --- MACROS FOR PORTABILITY --- */ +/* Saves on those hard to debug '\0' typos.... */ +#define LT_EOS_CHAR '\0' + /* LTDL_BEGIN_C_DECLS should be used at the beginning of your declarations, so that C++ compilers don't mangle their names. Use LTDL_END_C_DECLS at the end of C declarations. */ @@ -82,6 +85,8 @@ LT_BEGIN_C_DECLS # define LT_CONC(s,t) s/**/t #endif +/* LT_STRLEN can be used safely on NULL pointers. */ +#define LT_STRLEN(s) (((s) && (s)[0]) ? strlen (s) : 0) @@ -146,10 +151,16 @@ typedef struct lt_dlhandle_struct *lt_dlhandle; /* A loaded module. */ extern int lt_dlinit LT_PARAMS((void)); extern int lt_dlexit LT_PARAMS((void)); -/* Module search path manipultation. */ -extern int lt_dladdsearchdir LT_PARAMS((const char *search_dir)); -extern int lt_dlsetsearchpath LT_PARAMS((const char *search_path)); -extern const char *lt_dlgetsearchpath LT_PARAMS((void)); +/* Module search path manipulation. */ +extern int lt_dladdsearchdir LT_PARAMS((const char *search_dir)); +extern int lt_dlinsertsearchdir LT_PARAMS((const char *before, + const char *search_dir)); +extern int lt_dlsetsearchpath LT_PARAMS((const char *search_path)); +extern const char *lt_dlgetsearchpath LT_PARAMS((void)); +extern int lt_dlforeachfile LT_PARAMS(( + const char *search_path, + int (*func) (const char *filename, lt_ptr data), + lt_ptr data)); /* Portable libltdl versions of the system dlopen() API. */ extern lt_dlhandle lt_dlopen LT_PARAMS((const char *filename)); @@ -171,7 +182,7 @@ extern int lt_dlisresident LT_PARAMS((lt_dlhandle handle)); typedef void lt_dlmutex_lock LT_PARAMS((void)); typedef void lt_dlmutex_unlock LT_PARAMS((void)); -typedef void lt_dlmutex_seterror LT_PARAMS((const char *error)); +typedef void lt_dlmutex_seterror LT_PARAMS((const char *errmsg)); typedef const char *lt_dlmutex_geterror LT_PARAMS((void)); extern int lt_dlmutex_register LT_PARAMS((lt_dlmutex_lock *lock, @@ -185,8 +196,13 @@ extern int lt_dlmutex_register LT_PARAMS((lt_dlmutex_lock *lock, /* --- MEMORY HANDLING --- */ -/* Pointers to memory management functions to be used by libltdl. */ +/* By default, the realloc function pointer is set to our internal + realloc implementation which iself uses lt_dlmalloc and lt_dlfree. + libltdl relies on a featureful realloc, but if you are sure yours + has the right semantics then you can assign it directly. Generally, + it is safe to assign just a malloc() and a free() function. */ LT_SCOPE lt_ptr (*lt_dlmalloc) LT_PARAMS((size_t size)); +LT_SCOPE lt_ptr (*lt_dlrealloc) LT_PARAMS((lt_ptr ptr, size_t size)); LT_SCOPE void (*lt_dlfree) LT_PARAMS((lt_ptr ptr)); @@ -275,8 +291,8 @@ extern lt_dlloader *lt_dlloader_find LT_PARAMS(( extern const char *lt_dlloader_name LT_PARAMS((lt_dlloader *place)); extern lt_user_data *lt_dlloader_data LT_PARAMS((lt_dlloader *place)); extern int lt_dlloader_add LT_PARAMS((lt_dlloader *place, - const struct lt_user_dlloader *dlloader, - const char *loader_name)); + const struct lt_user_dlloader *dlloader, + const char *loader_name)); extern int lt_dlloader_remove LT_PARAMS(( const char *loader_name)); @@ -307,7 +323,8 @@ extern int lt_dlloader_remove LT_PARAMS(( LT_ERROR(INVALID_ERRORCODE, "invalid errorcode") \ LT_ERROR(SHUTDOWN, "library already shutdown") \ LT_ERROR(CLOSE_RESIDENT_MODULE, "can't close resident module") \ - LT_ERROR(INVALID_MUTEX_ARGS, "invalid mutex handler registration") + LT_ERROR(INVALID_MUTEX_ARGS, "invalid mutex handler registration") \ + LT_ERROR(INVALID_POSITION, "invalid search path insert position") /* Enumerate the symbolic error names. */ enum { diff --git a/ltdl.m4 b/ltdl.m4 index d3ee60269..0038be241 100644 --- a/ltdl.m4 +++ b/ltdl.m4 @@ -24,33 +24,36 @@ # AC_LIB_LTDL # ----------- +# Perform all the checks necessary for compilation of the ltdl objects +# -- including compiler checks and header checks. AC_DEFUN(AC_LIB_LTDL, -[AC_PREREQ(2.13)dnl -AC_REQUIRE([AC_PROG_CC])dnl -AC_REQUIRE([AC_C_CONST])dnl +[AC_PREREQ(2.13) +AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([AC_C_CONST]) +AC_REQUIRE([AC_HEADER_STDC]) +AC_REQUIRE([AC_HEADER_DIRENT]) +AC_REQUIRE([_LT_AC_CHECK_DLFCN]) +AC_REQUIRE([AC_LTDL_ENABLE_INSTALL]) +AC_REQUIRE([AC_LTDL_SHLIBEXT]) +AC_REQUIRE([AC_LTDL_SHLIBPATH]) +AC_REQUIRE([AC_LTDL_SYSSEARCHPATH]) +AC_REQUIRE([AC_LTDL_OBJDIR]) +AC_REQUIRE([AC_LTDL_DLPREOPEN]) +AC_REQUIRE([AC_LTDL_DLLIB]) +AC_REQUIRE([AC_LTDL_SYMBOL_USCORE]) +AC_REQUIRE([AC_LTDL_DLSYM_USCORE]) +AC_REQUIRE([AC_LTDL_SYS_DLOPEN_DEPLIBS]) +AC_REQUIRE([AC_LTDL_FUNC_ARGZ]) -# Perform all the checks necessary for compilation of the ltdl objects -# -- including compiler checks (above) and header checks (below). -AC_REQUIRE([AC_HEADER_STDC])dnl -AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +AC_CHECK_HEADERS([errno.h malloc.h memory.h stdlib.h stdio.h ctype.h unistd.h]) +AC_CHECK_HEADERS([dl.h sys/dl.h dld.h]) +AC_CHECK_HEADERS([string.h strings.h], break) -AC_CHECK_HEADERS(malloc.h memory.h stdlib.h stdio.h ctype.h dl.h sys/dl.h dld.h) -AC_CHECK_HEADERS(string.h strings.h, break) -AC_CHECK_FUNCS(strchr index, break) -AC_CHECK_FUNCS(strrchr rindex, break) -AC_CHECK_FUNCS(memcpy bcopy, break) -AC_CHECK_FUNCS(strcmp) +AC_CHECK_FUNCS([strchr index], break) +AC_CHECK_FUNCS([strrchr rindex], break) +AC_CHECK_FUNCS([memcpy bcopy], break) +AC_CHECK_FUNCS([memmove strcmp]) -AC_REQUIRE([AC_LTDL_ENABLE_INSTALL])dnl -AC_REQUIRE([AC_LTDL_SHLIBEXT])dnl -AC_REQUIRE([AC_LTDL_SHLIBPATH])dnl -AC_REQUIRE([AC_LTDL_SYSSEARCHPATH])dnl -AC_REQUIRE([AC_LTDL_OBJDIR])dnl -AC_REQUIRE([AC_LTDL_DLPREOPEN])dnl -AC_REQUIRE([AC_LTDL_DLLIB])dnl -AC_REQUIRE([AC_LTDL_SYMBOL_USCORE])dnl -AC_REQUIRE([AC_LTDL_DLSYM_USCORE])dnl -AC_REQUIRE([AC_LTDL_SYS_DLOPEN_DEPLIBS])dnl ])# AC_LIB_LTDL # AC_LTDL_ENABLE_INSTALL @@ -280,3 +283,21 @@ if test x"$libltdl_cv_need_uscore" = xyes; then [Define if dlsym() requires a leading underscode in symbol names. ]) fi ])# AC_LTDL_DLSYM_USCORE + + +# AC_LTDL_FUNC_ARGZ +# ----------------- +AC_DEFUN([AC_LTDL_FUNC_ARGZ], +[AC_CHECK_HEADERS([argz.h]) + +AC_CHECK_TYPES([error_t], + [], + [AC_DEFINE([error_t], [int], + [Define to a type to use for `error_t' if it is not otherwise available.])], + [#if HAVE_ARGZ_H +# include +#endif]) + +AC_CHECK_FUNCS([argz_append argz_create_sep argz_insert argz_next argz_stringify]) +])# AC_LTDL_FUNC_ARGZ +