1 /* ltdl.c -- system independent dlopen wrapper
2    Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
3    Originally by Thomas Tanner <tanner@ffii.org>
4    This file is part of GNU Libtool.
5 
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10 
11 As a special exception to the GNU Lesser General Public License,
12 if you distribute this file as part of a program or library that
13 is built using GNU libtool, you may include it under the same
14 distribution terms that you use for the rest of that program.
15 
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 Lesser General Public License for more details.
20 
21 You should have received a copy of the GNU Lesser General Public
22 License along with this library; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24 02111-1307  USA
25 
26 */
27 
28 #if HAVE_CONFIG_H
29 #  include <config.h>
30 #endif
31 
32 #if HAVE_UNISTD_H
33 #  include <unistd.h>
34 #endif
35 
36 #if HAVE_STDIO_H
37 #  include <stdio.h>
38 #endif
39 
40 #if HAVE_STDLIB_H
41 #  include <stdlib.h>
42 #endif
43 
44 #if HAVE_STRING_H
45 #  include <string.h>
46 #else
47 #  if HAVE_STRINGS_H
48 #    include <strings.h>
49 #  endif
50 #endif
51 
52 #if HAVE_CTYPE_H
53 #  include <ctype.h>
54 #endif
55 
56 #if HAVE_MALLOC_H
57 #  include <malloc.h>
58 #endif
59 
60 #if HAVE_MEMORY_H
61 #  include <memory.h>
62 #endif
63 
64 #if HAVE_ERRNO_H
65 #  include <errno.h>
66 #endif
67 
68 #if HAVE_DIRENT_H
69 #  include <dirent.h>
70 #  define LT_D_NAMLEN(dirent) (strlen((dirent)->d_name))
71 #else
72 #  define dirent direct
73 #  define LT_D_NAMLEN(dirent) ((dirent)->d_namlen)
74 #  if HAVE_SYS_NDIR_H
75 #    include <sys/ndir.h>
76 #  endif
77 #  if HAVE_SYS_DIR_H
78 #    include <sys/dir.h>
79 #  endif
80 #  if HAVE_NDIR_H
81 #    include <ndir.h>
82 #  endif
83 #endif
84 
85 #if HAVE_ARGZ_H
86 #  include <argz.h>
87 #endif
88 
89 #if HAVE_ASSERT_H
90 #  include <assert.h>
91 #else
92 #  define assert(arg)	((void) 0)
93 #endif
94 
95 #include "ltdl.h"
96 
97 #if WITH_DMALLOC
98 #  include <dmalloc.h>
99 #endif
100 
101 
102 
103 
104 /* --- WINDOWS SUPPORT --- */
105 
106 
107 #ifdef DLL_EXPORT
108 #  define LT_GLOBAL_DATA	__declspec(dllexport)
109 #else
110 #  define LT_GLOBAL_DATA
111 #endif
112 
113 /* fopen() mode flags for reading a text file */
114 #undef	LT_READTEXT_MODE
115 #ifdef __WINDOWS__
116 #  define LT_READTEXT_MODE "rt"
117 #else
118 #  define LT_READTEXT_MODE "r"
119 #endif
120 
121 
122 
123 
124 /* --- MANIFEST CONSTANTS --- */
125 
126 
127 /* Standard libltdl search path environment variable name  */
128 #undef  LTDL_SEARCHPATH_VAR
129 #define LTDL_SEARCHPATH_VAR	"LTDL_LIBRARY_PATH"
130 
131 /* Standard libtool archive file extension.  */
132 #undef  LTDL_ARCHIVE_EXT
133 #define LTDL_ARCHIVE_EXT	".la"
134 
135 /* max. filename length */
136 #ifndef LT_FILENAME_MAX
137 #  define LT_FILENAME_MAX	1024
138 #endif
139 
140 /* This is the maximum symbol size that won't require malloc/free */
141 #undef	LT_SYMBOL_LENGTH
142 #define LT_SYMBOL_LENGTH	128
143 
144 /* This accounts for the _LTX_ separator */
145 #undef	LT_SYMBOL_OVERHEAD
146 #define LT_SYMBOL_OVERHEAD	5
147 
148 
149 
150 
151 /* --- MEMORY HANDLING --- */
152 
153 
154 /* These are the functions used internally.  In addition to making
155    use of the associated function pointers above, they also perform
156    error handling.  */
157 static char   *lt_estrdup	LT_PARAMS((const char *str));
158 static lt_ptr lt_emalloc	LT_PARAMS((size_t size));
159 static lt_ptr lt_erealloc	LT_PARAMS((lt_ptr addr, size_t size));
160 
161 static lt_ptr rpl_realloc	LT_PARAMS((lt_ptr ptr, size_t size));
162 
163 /* These are the pointers that can be changed by the caller:  */
164 LT_GLOBAL_DATA lt_ptr (*lt_dlmalloc)	LT_PARAMS((size_t size))
165  			= (lt_ptr (*) LT_PARAMS((size_t))) malloc;
166 LT_GLOBAL_DATA lt_ptr (*lt_dlrealloc)	LT_PARAMS((lt_ptr ptr, size_t size))
167  			= (lt_ptr (*) LT_PARAMS((lt_ptr, size_t))) rpl_realloc;
168 LT_GLOBAL_DATA void   (*lt_dlfree)	LT_PARAMS((lt_ptr ptr))
169  			= (void (*) LT_PARAMS((lt_ptr))) free;
170 
171 /* The following macros reduce the amount of typing needed to cast
172    assigned memory.  */
173 #if WITH_DMALLOC
174 
175 #define LT_DLMALLOC(tp, n)	((tp *) xmalloc ((n) * sizeof(tp)))
176 #define LT_DLREALLOC(tp, p, n)	((tp *) xrealloc ((p), (n) * sizeof(tp)))
177 #define LT_DLFREE(p)						\
178 	LT_STMT_START { if (p) (p) = (xfree (p), (lt_ptr) 0); } LT_STMT_END
179 
180 #define LT_EMALLOC(tp, n)	((tp *) xmalloc ((n) * sizeof(tp)))
181 #define LT_EREALLOC(tp, p, n)	((tp *) xrealloc ((p), (n) * sizeof(tp)))
182 
183 #else
184 
185 #define LT_DLMALLOC(tp, n)	((tp *) lt_dlmalloc ((n) * sizeof(tp)))
186 #define LT_DLREALLOC(tp, p, n)	((tp *) rpl_realloc ((p), (n) * sizeof(tp)))
187 #define LT_DLFREE(p)						\
188 	LT_STMT_START { if (p) (p) = (lt_dlfree (p), (lt_ptr) 0); } LT_STMT_END
189 
190 #define LT_EMALLOC(tp, n)	((tp *) lt_emalloc ((n) * sizeof(tp)))
191 #define LT_EREALLOC(tp, p, n)	((tp *) lt_erealloc ((p), (n) * sizeof(tp)))
192 
193 #endif
194 
195 #define LT_DLMEM_REASSIGN(p, q)			LT_STMT_START {	\
196 	if ((p) != (q)) { if (p) lt_dlfree (p); (p) = (q); (q) = 0; }	\
197 						} LT_STMT_END
198 
199 
200 /* --- REPLACEMENT FUNCTIONS --- */
201 
202 
203 #undef strdup
204 #define strdup rpl_strdup
205 
206 static char *strdup LT_PARAMS((const char *str));
207 
208 static char *
strdup(str)209 strdup(str)
210      const char *str;
211 {
212   char *tmp = NULL;
213 
214   if (str)
215     {
216       tmp = LT_DLMALLOC (char, 1+ strlen (str));
217       if (tmp)
218 	{
219 	  strcpy(tmp, str);
220 	}
221     }
222 
223   return tmp;
224 }
225 
226 
227 #if ! HAVE_STRCMP
228 
229 #undef strcmp
230 #define strcmp rpl_strcmp
231 
232 static int strcmp LT_PARAMS((const char *str1, const char *str2));
233 
234 static int
strcmp(str1,str2)235 strcmp (str1, str2)
236      const char *str1;
237      const char *str2;
238 {
239   if (str1 == str2)
240     return 0;
241   if (str1 == NULL)
242     return -1;
243   if (str2 == NULL)
244     return 1;
245 
246   for (;*str1 && *str2; ++str1, ++str2)
247     {
248       if (*str1 != *str2)
249 	break;
250     }
251 
252   return (int)(*str1 - *str2);
253 }
254 #endif
255 
256 
257 #if ! HAVE_STRCHR
258 
259 #  if HAVE_INDEX
260 #    define strchr index
261 #  else
262 #    define strchr rpl_strchr
263 
264 static const char *strchr LT_PARAMS((const char *str, int ch));
265 
266 static const char*
strchr(str,ch)267 strchr(str, ch)
268      const char *str;
269      int ch;
270 {
271   const char *p;
272 
273   for (p = str; *p != (char)ch && *p != LT_EOS_CHAR; ++p)
274     /*NOWORK*/;
275 
276   return (*p == (char)ch) ? p : 0;
277 }
278 
279 #  endif
280 #endif /* !HAVE_STRCHR */
281 
282 
283 #if ! HAVE_STRRCHR
284 
285 #  if HAVE_RINDEX
286 #    define strrchr rindex
287 #  else
288 #    define strrchr rpl_strrchr
289 
290 static const char *strrchr LT_PARAMS((const char *str, int ch));
291 
292 static const char*
strrchr(str,ch)293 strrchr(str, ch)
294      const char *str;
295      int ch;
296 {
297   const char *p, *q = NULL;
298 
299   for (p = str; *p != LT_EOS_CHAR; ++p)
300     {
301       if (*p == (char) ch)
302 	{
303 	  q = p;
304 	}
305     }
306 
307   return q;
308 }
309 
310 # endif
311 #endif
312 
313 /* NOTE:  Neither bcopy nor the memcpy implementation below can
314           reliably handle copying in overlapping areas of memory.  Use
315           memmove (for which there is a fallback implmentation below)
316 	  if you need that behaviour.  */
317 #if ! HAVE_MEMCPY
318 
319 #  if HAVE_BCOPY
320 #    define memcpy(dest, src, size)	bcopy (src, dest, size)
321 #  else
322 #    define memcpy rpl_memcpy
323 
324 static lt_ptr memcpy LT_PARAMS((lt_ptr dest, const lt_ptr src, size_t size));
325 
326 static lt_ptr
memcpy(dest,src,size)327 memcpy (dest, src, size)
328      lt_ptr dest;
329      const lt_ptr src;
330      size_t size;
331 {
332   size_t i = 0;
333 
334   for (i = 0; i < size; ++i)
335     {
336       dest[i] = src[i];
337     }
338 
339   return dest;
340 }
341 
342 #  endif /* !HAVE_BCOPY */
343 #endif   /* !HAVE_MEMCPY */
344 
345 #if ! HAVE_MEMMOVE
346 #  define memmove rpl_memmove
347 
348 static lt_ptr memmove LT_PARAMS((lt_ptr dest, const lt_ptr src, size_t size));
349 
350 static lt_ptr
memmove(dest,src,size)351 memmove (dest, src, size)
352      lt_ptr dest;
353      const lt_ptr src;
354      size_t size;
355 {
356   size_t i;
357 
358   if (dest < src)
359     for (i = 0; i < size; ++i)
360       {
361 	dest[i] = src[i];
362       }
363   else if (dest > src)
364     for (i = size -1; i >= 0; --i)
365       {
366 	dest[i] = src[i];
367       }
368 
369   return dest;
370 }
371 
372 #endif /* !HAVE_MEMMOVE */
373 
374 
375 /* According to Alexandre Oliva <oliva@lsd.ic.unicamp.br>,
376     ``realloc is not entirely portable''
377    In any case we want to use the allocator supplied by the user without
378    burdening them with an lt_dlrealloc function pointer to maintain.
379    Instead implement our own version (with known boundary conditions)
380    using lt_dlmalloc and lt_dlfree. */
381 
382 #undef realloc
383 #define realloc rpl_realloc
384 
385 static lt_ptr
realloc(ptr,size)386 realloc (ptr, size)
387      lt_ptr ptr;
388      size_t size;
389 {
390   if (size == 0)
391     {
392       /* For zero or less bytes, free the original memory */
393       if (ptr != NULL)
394 	{
395 	  lt_dlfree (ptr);
396 	}
397 
398       return (lt_ptr) 0;
399     }
400   else if (ptr == NULL)
401     {
402       /* Allow reallocation of a NULL pointer.  */
403       return lt_dlmalloc (size);
404     }
405   else
406     {
407       /* Allocate a new block, copy and free the old block.  */
408       lt_ptr mem = lt_dlmalloc (size);
409 
410       if (mem)
411 	{
412 	  memcpy (mem, ptr, size);
413 	  lt_dlfree (ptr);
414 	}
415 
416       /* Note that the contents of PTR are not damaged if there is
417 	 insufficient memory to realloc.  */
418       return mem;
419     }
420 }
421 
422 
423 #if ! HAVE_ARGZ_APPEND
424 #  define argz_append rpl_argz_append
425 
426 static error_t argz_append LT_PARAMS((char **pargz, size_t *pargz_len,
427 					const char *buf, size_t buf_len));
428 
429 static error_t
argz_append(pargz,pargz_len,buf,buf_len)430 argz_append (pargz, pargz_len, buf, buf_len)
431      char **pargz;
432      size_t *pargz_len;
433      const char *buf;
434      size_t buf_len;
435 {
436   size_t argz_len;
437   char  *argz;
438 
439   assert (pargz);
440   assert (pargz_len);
441   assert ((*pargz && *pargz_len) || (!*pargz && !*pargz_len));
442 
443   /* If nothing needs to be appended, no more work is required.  */
444   if (buf_len == 0)
445     return 0;
446 
447   /* Ensure there is enough room to append BUF_LEN.  */
448   argz_len = *pargz_len + buf_len;
449   argz = LT_DLREALLOC (char, *pargz, argz_len);
450   if (!argz)
451     return ENOMEM;
452 
453   /* Copy characters from BUF after terminating '\0' in ARGZ.  */
454   memcpy (argz + *pargz_len, buf, buf_len);
455 
456   /* Assign new values.  */
457   *pargz = argz;
458   *pargz_len = argz_len;
459 
460   return 0;
461 }
462 #endif /* !HAVE_ARGZ_APPEND */
463 
464 
465 #if ! HAVE_ARGZ_CREATE_SEP
466 #  define argz_create_sep rpl_argz_create_sep
467 
468 static error_t argz_create_sep LT_PARAMS((const char *str, int delim,
469 					    char **pargz, size_t *pargz_len));
470 
471 static error_t
argz_create_sep(str,delim,pargz,pargz_len)472 argz_create_sep (str, delim, pargz, pargz_len)
473      const char *str;
474      int delim;
475      char **pargz;
476      size_t *pargz_len;
477 {
478   size_t argz_len;
479   char *argz = NULL;
480 
481   assert (str);
482   assert (pargz);
483   assert (pargz_len);
484 
485   /* Make a copy of STR, but replacing each occurence of
486      DELIM with '\0'.  */
487   argz_len = 1+ LT_STRLEN (str);
488   if (argz_len)
489     {
490       const char *p;
491       char *q;
492 
493       argz = LT_DLMALLOC (char, argz_len);
494       if (!argz)
495 	return ENOMEM;
496 
497       for (p = str, q = argz; *p != LT_EOS_CHAR; ++p)
498 	{
499 	  if (*p == delim)
500 	    {
501 	      /* Ignore leading delimiters, and fold consecutive
502 		 delimiters in STR into a single '\0' in ARGZ.  */
503 	      if ((q > argz) && (q[-1] != LT_EOS_CHAR))
504 		*q++ = LT_EOS_CHAR;
505 	      else
506 		--argz_len;
507 	    }
508 	  else
509 	    *q++ = *p;
510 	}
511       /* Copy terminating LT_EOS_CHAR.  */
512       *q = *p;
513     }
514 
515   /* If ARGZ_LEN has shrunk to nothing, release ARGZ's memory.  */
516   if (!argz_len)
517     LT_DLFREE (argz);
518 
519   /* Assign new values.  */
520   *pargz = argz;
521   *pargz_len = argz_len;
522 
523   return 0;
524 }
525 #endif /* !HAVE_ARGZ_CREATE_SEP */
526 
527 
528 #if ! HAVE_ARGZ_INSERT
529 #  define argz_insert rpl_argz_insert
530 
531 static error_t argz_insert LT_PARAMS((char **pargz, size_t *pargz_len,
532 					char *before, const char *entry));
533 
534 static error_t
argz_insert(pargz,pargz_len,before,entry)535 argz_insert (pargz, pargz_len, before, entry)
536      char **pargz;
537      size_t *pargz_len;
538      char *before;
539      const char *entry;
540 {
541   assert (pargz);
542   assert (pargz_len);
543   assert (entry && *entry);
544 
545   /* No BEFORE address indicates ENTRY should be inserted after the
546      current last element.  */
547   if (!before)
548     return argz_append (pargz, pargz_len, entry, 1+ LT_STRLEN (entry));
549 
550   /* This probably indicates a programmer error, but to preserve
551      semantics, scan back to the start of an entry if BEFORE points
552      into the middle of it.  */
553   while ((before >= *pargz) && (before[-1] != LT_EOS_CHAR))
554     --before;
555 
556   {
557     size_t entry_len	= 1+ LT_STRLEN (entry);
558     size_t argz_len	= *pargz_len + entry_len;
559     size_t offset	= before - *pargz;
560     char   *argz	= LT_DLREALLOC (char, *pargz, argz_len);
561 
562     if (!argz)
563       return ENOMEM;
564 
565     /* Make BEFORE point to the equivalent offset in ARGZ that it
566        used to have in *PARGZ incase realloc() moved the block.  */
567     before = argz + offset;
568 
569     /* Move the ARGZ entries starting at BEFORE up into the new
570        space at the end -- making room to copy ENTRY into the
571        resulting gap.  */
572     memmove (before + entry_len, before, *pargz_len - offset);
573     memcpy  (before, entry, entry_len);
574 
575     /* Assign new values.  */
576     *pargz = argz;
577     *pargz_len = argz_len;
578   }
579 
580   return 0;
581 }
582 #endif /* !HAVE_ARGZ_INSERT */
583 
584 
585 #if ! HAVE_ARGZ_NEXT
586 #  define argz_next rpl_argz_next
587 
588 static char *argz_next LT_PARAMS((char *argz, size_t argz_len,
589 				    const char *entry));
590 
591 static char *
argz_next(argz,argz_len,entry)592 argz_next (argz, argz_len, entry)
593      char *argz;
594      size_t argz_len;
595      const char *entry;
596 {
597   assert ((argz && argz_len) || (!argz && !argz_len));
598 
599   if (entry)
600     {
601       /* Either ARGZ/ARGZ_LEN is empty, or ENTRY points into an address
602 	 within the ARGZ vector.  */
603       assert ((!argz && !argz_len)
604 	      || ((argz <= entry) && (entry < (argz + argz_len))));
605 
606       /* Move to the char immediately after the terminating
607 	 '\0' of ENTRY.  */
608       entry = 1+ strchr (entry, LT_EOS_CHAR);
609 
610       /* Return either the new ENTRY, or else NULL if ARGZ is
611 	 exhausted.  */
612       return (entry >= argz + argz_len) ? 0 : (char *) entry;
613     }
614   else
615     {
616       /* This should probably be flagged as a programmer error,
617 	 since starting an argz_next loop with the iterator set
618 	 to ARGZ is safer.  To preserve semantics, handle the NULL
619 	 case by returning the start of ARGZ (if any).  */
620       if (argz_len > 0)
621 	return argz;
622       else
623 	return 0;
624     }
625 }
626 #endif /* !HAVE_ARGZ_NEXT */
627 
628 
629 
630 #if ! HAVE_ARGZ_STRINGIFY
631 #  define argz_stringify rpl_argz_stringify
632 
633 static void argz_stringify LT_PARAMS((char *argz, size_t argz_len,
634 				       int sep));
635 
636 static void
argz_stringify(argz,argz_len,sep)637 argz_stringify (argz, argz_len, sep)
638      char *argz;
639      size_t argz_len;
640      int sep;
641 {
642   assert ((argz && argz_len) || (!argz && !argz_len));
643 
644   if (sep)
645     {
646       --argz_len;		/* don't stringify the terminating EOS */
647       while (--argz_len > 0)
648 	{
649 	  if (argz[argz_len] == LT_EOS_CHAR)
650 	    argz[argz_len] = sep;
651 	}
652     }
653 }
654 #endif /* !HAVE_ARGZ_STRINGIFY */
655 
656 
657 
658 
659 /* --- TYPE DEFINITIONS -- */
660 
661 
662 /* This type is used for the array of caller data sets in each handler. */
663 typedef struct {
664   lt_dlcaller_id	key;
665   lt_ptr		data;
666 } lt_caller_data;
667 
668 
669 
670 
671 /* --- OPAQUE STRUCTURES DECLARED IN LTDL.H --- */
672 
673 
674 /* Extract the diagnostic strings from the error table macro in the same
675    order as the enumerated indices in ltdl.h. */
676 
677 static const char *lt_dlerror_strings[] =
678   {
679 #define LT_ERROR(name, diagnostic)	(diagnostic),
680     lt_dlerror_table
681 #undef LT_ERROR
682 
683     0
684   };
685 
686 /* This structure is used for the list of registered loaders. */
687 struct lt_dlloader {
688   struct lt_dlloader   *next;
689   const char	       *loader_name;	/* identifying name for each loader */
690   const char	       *sym_prefix;	/* prefix for symbols */
691   lt_module_open       *module_open;
692   lt_module_close      *module_close;
693   lt_find_sym	       *find_sym;
694   lt_dlloader_exit     *dlloader_exit;
695   lt_user_data		dlloader_data;
696 };
697 
698 struct lt_dlhandle_struct {
699   struct lt_dlhandle_struct   *next;
700   lt_dlloader	       *loader;		/* dlopening interface */
701   lt_dlinfo		info;
702   int			depcount;	/* number of dependencies */
703   lt_dlhandle	       *deplibs;	/* dependencies */
704   lt_module		module;		/* system module handle */
705   lt_ptr		system;		/* system specific data */
706   lt_caller_data       *caller_data;	/* per caller associated data */
707   int			flags;		/* various boolean stats */
708 };
709 
710 /* Various boolean flags can be stored in the flags field of an
711    lt_dlhandle_struct... */
712 #define LT_DLGET_FLAG(handle, flag) (((handle)->flags & (flag)) == (flag))
713 #define LT_DLSET_FLAG(handle, flag) ((handle)->flags |= (flag))
714 
715 #define LT_DLRESIDENT_FLAG	    (0x01 << 0)
716 /* ...add more flags here... */
717 
718 #define LT_DLIS_RESIDENT(handle)    LT_DLGET_FLAG(handle, LT_DLRESIDENT_FLAG)
719 
720 
721 #define LT_DLSTRERROR(name)	lt_dlerror_strings[LT_CONC(LT_ERROR_,name)]
722 
723 static	const char	objdir[]		= LTDL_OBJDIR;
724 static	const char	archive_ext[]		= LTDL_ARCHIVE_EXT;
725 #ifdef	LTDL_SHLIB_EXT
726 static	const char	shlib_ext[]		= LTDL_SHLIB_EXT;
727 #endif
728 #ifdef	LTDL_SYSSEARCHPATH
729 static	const char	sys_search_path[]	= LTDL_SYSSEARCHPATH;
730 #endif
731 
732 
733 
734 
735 /* --- MUTEX LOCKING --- */
736 
737 
738 /* Macros to make it easier to run the lock functions only if they have
739    been registered.  The reason for the complicated lock macro is to
740    ensure that the stored error message from the last error is not
741    accidentally erased if the current function doesn't generate an
742    error of its own.  */
743 #define LT_DLMUTEX_LOCK()			LT_STMT_START {	\
744 	if (lt_dlmutex_lock_func) (*lt_dlmutex_lock_func)();	\
745 						} LT_STMT_END
746 #define LT_DLMUTEX_UNLOCK()			LT_STMT_START { \
747 	if (lt_dlmutex_unlock_func) (*lt_dlmutex_unlock_func)();\
748 						} LT_STMT_END
749 #define LT_DLMUTEX_SETERROR(errormsg)		LT_STMT_START {	\
750 	if (lt_dlmutex_seterror_func)				\
751 		(*lt_dlmutex_seterror_func) (errormsg);		\
752 	else 	lt_dllast_error = (errormsg);	} LT_STMT_END
753 #define LT_DLMUTEX_GETERROR(errormsg)		LT_STMT_START {	\
754 	if (lt_dlmutex_seterror_func)				\
755 		(errormsg) = (*lt_dlmutex_geterror_func) ();	\
756 	else	(errormsg) = lt_dllast_error;	} LT_STMT_END
757 
758 /* The mutex functions stored here are global, and are necessarily the
759    same for all threads that wish to share access to libltdl.  */
760 static	lt_dlmutex_lock	    *lt_dlmutex_lock_func     = NULL;
761 static	lt_dlmutex_unlock   *lt_dlmutex_unlock_func   = NULL;
762 static	lt_dlmutex_seterror *lt_dlmutex_seterror_func = NULL;
763 static	lt_dlmutex_geterror *lt_dlmutex_geterror_func = NULL;
764 static	const char	    *lt_dllast_error	      = NULL;
765 
766 
767 /* Either set or reset the mutex functions.  Either all the arguments must
768    be valid functions, or else all can be NULL to turn off locking entirely.
769    The registered functions should be manipulating a static global lock
770    from the lock() and unlock() callbacks, which needs to be reentrant.  */
771 int
lt_dlmutex_register(lock,unlock,seterror,geterror)772 lt_dlmutex_register (lock, unlock, seterror, geterror)
773      lt_dlmutex_lock *lock;
774      lt_dlmutex_unlock *unlock;
775      lt_dlmutex_seterror *seterror;
776      lt_dlmutex_geterror *geterror;
777 {
778   lt_dlmutex_unlock *old_unlock = unlock;
779   int		     errors	= 0;
780 
781   /* Lock using the old lock() callback, if any.  */
782   LT_DLMUTEX_LOCK ();
783 
784   if ((lock && unlock && seterror && geterror)
785       || !(lock || unlock || seterror || geterror))
786     {
787       lt_dlmutex_lock_func     = lock;
788       lt_dlmutex_unlock_func   = unlock;
789       lt_dlmutex_geterror_func = geterror;
790     }
791   else
792     {
793       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_MUTEX_ARGS));
794       ++errors;
795     }
796 
797   /* Use the old unlock() callback we saved earlier, if any.  Otherwise
798      record any errors using internal storage.  */
799   if (old_unlock)
800     (*old_unlock) ();
801 
802   /* Return the number of errors encountered during the execution of
803      this function.  */
804   return errors;
805 }
806 
807 
808 
809 
810 /* --- ERROR HANDLING --- */
811 
812 
813 static	const char    **user_error_strings	= NULL;
814 static	int		errorcount		= LT_ERROR_MAX;
815 
816 int
lt_dladderror(diagnostic)817 lt_dladderror (diagnostic)
818      const char *diagnostic;
819 {
820   int		errindex = 0;
821   int		result	 = -1;
822   const char  **temp     = NULL;
823 
824   assert (diagnostic);
825 
826   LT_DLMUTEX_LOCK ();
827 
828   errindex = errorcount - LT_ERROR_MAX;
829   temp = LT_EREALLOC (const char *, user_error_strings, 1 + errindex);
830   if (temp)
831     {
832       user_error_strings		= temp;
833       user_error_strings[errindex]	= diagnostic;
834       result				= errorcount++;
835     }
836 
837   LT_DLMUTEX_UNLOCK ();
838 
839   return result;
840 }
841 
842 int
lt_dlseterror(errindex)843 lt_dlseterror (errindex)
844      int errindex;
845 {
846   int		errors	 = 0;
847 
848   LT_DLMUTEX_LOCK ();
849 
850   if (errindex >= errorcount || errindex < 0)
851     {
852       /* Ack!  Error setting the error message! */
853       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_ERRORCODE));
854       ++errors;
855     }
856   else if (errindex < LT_ERROR_MAX)
857     {
858       /* No error setting the error message! */
859       LT_DLMUTEX_SETERROR (lt_dlerror_strings[errindex]);
860     }
861   else
862     {
863       /* No error setting the error message! */
864       LT_DLMUTEX_SETERROR (user_error_strings[errindex - LT_ERROR_MAX]);
865     }
866 
867   LT_DLMUTEX_UNLOCK ();
868 
869   return errors;
870 }
871 
872 static lt_ptr
lt_emalloc(size)873 lt_emalloc (size)
874      size_t size;
875 {
876   lt_ptr mem = lt_dlmalloc (size);
877   if (size && !mem)
878     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
879   return mem;
880 }
881 
882 static lt_ptr
lt_erealloc(addr,size)883 lt_erealloc (addr, size)
884      lt_ptr addr;
885      size_t size;
886 {
887   lt_ptr mem = realloc (addr, size);
888   if (size && !mem)
889     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
890   return mem;
891 }
892 
893 static char *
lt_estrdup(str)894 lt_estrdup (str)
895      const char *str;
896 {
897   char *copy = strdup (str);
898   if (LT_STRLEN (str) && !copy)
899     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
900   return copy;
901 }
902 
903 
904 
905 
906 /* --- DLOPEN() INTERFACE LOADER --- */
907 
908 
909 /* The Cygwin dlopen implementation prints a spurious error message to
910    stderr if its call to LoadLibrary() fails for any reason.  We can
911    mitigate this by not using the Cygwin implementation, and falling
912    back to our own LoadLibrary() wrapper. */
913 #if HAVE_LIBDL && !defined(__CYGWIN__)
914 
915 /* dynamic linking with dlopen/dlsym */
916 
917 #if HAVE_DLFCN_H
918 #  include <dlfcn.h>
919 #endif
920 
921 #if HAVE_SYS_DL_H
922 #  include <sys/dl.h>
923 #endif
924 
925 #ifdef RTLD_GLOBAL
926 #  define LT_GLOBAL		RTLD_GLOBAL
927 #else
928 #  ifdef DL_GLOBAL
929 #    define LT_GLOBAL		DL_GLOBAL
930 #  endif
931 #endif /* !RTLD_GLOBAL */
932 #ifndef LT_GLOBAL
933 #  define LT_GLOBAL		0
934 #endif /* !LT_GLOBAL */
935 
936 /* We may have to define LT_LAZY_OR_NOW in the command line if we
937    find out it does not work in some platform. */
938 #ifndef LT_LAZY_OR_NOW
939 #  ifdef RTLD_LAZY
940 #    define LT_LAZY_OR_NOW	RTLD_LAZY
941 #  else
942 #    ifdef DL_LAZY
943 #      define LT_LAZY_OR_NOW	DL_LAZY
944 #    endif
945 #  endif /* !RTLD_LAZY */
946 #endif
947 #ifndef LT_LAZY_OR_NOW
948 #  ifdef RTLD_NOW
949 #    define LT_LAZY_OR_NOW	RTLD_NOW
950 #  else
951 #    ifdef DL_NOW
952 #      define LT_LAZY_OR_NOW	DL_NOW
953 #    endif
954 #  endif /* !RTLD_NOW */
955 #endif
956 #ifndef LT_LAZY_OR_NOW
957 #  define LT_LAZY_OR_NOW	0
958 #endif /* !LT_LAZY_OR_NOW */
959 
960 #if HAVE_DLERROR
961 #  define DLERROR(arg)	dlerror ()
962 #else
963 #  define DLERROR(arg)	LT_DLSTRERROR (arg)
964 #endif
965 
966 static lt_module
sys_dl_open(loader_data,filename)967 sys_dl_open (loader_data, filename)
968      lt_user_data loader_data;
969      const char *filename;
970 {
971   lt_module   module   = dlopen (filename, LT_GLOBAL | LT_LAZY_OR_NOW);
972 
973   if (!module)
974     {
975       LT_DLMUTEX_SETERROR (DLERROR (CANNOT_OPEN));
976     }
977 
978   return module;
979 }
980 
981 static int
sys_dl_close(loader_data,module)982 sys_dl_close (loader_data, module)
983      lt_user_data loader_data;
984      lt_module module;
985 {
986   int errors = 0;
987 
988   if (dlclose (module) != 0)
989     {
990       LT_DLMUTEX_SETERROR (DLERROR (CANNOT_CLOSE));
991       ++errors;
992     }
993 
994   return errors;
995 }
996 
997 static lt_ptr
sys_dl_sym(loader_data,module,symbol)998 sys_dl_sym (loader_data, module, symbol)
999      lt_user_data loader_data;
1000      lt_module module;
1001      const char *symbol;
1002 {
1003   lt_ptr address = dlsym (module, symbol);
1004 
1005   if (!address)
1006     {
1007       LT_DLMUTEX_SETERROR (DLERROR (SYMBOL_NOT_FOUND));
1008     }
1009 
1010   return address;
1011 }
1012 
1013 static struct lt_user_dlloader sys_dl =
1014   {
1015 #  ifdef NEED_USCORE
1016     "_",
1017 #  else
1018     0,
1019 #  endif
1020     sys_dl_open, sys_dl_close, sys_dl_sym, 0, 0 };
1021 
1022 
1023 #endif /* HAVE_LIBDL */
1024 
1025 
1026 
1027 /* --- SHL_LOAD() INTERFACE LOADER --- */
1028 
1029 #if HAVE_SHL_LOAD
1030 
1031 /* dynamic linking with shl_load (HP-UX) (comments from gmodule) */
1032 
1033 #ifdef HAVE_DL_H
1034 #  include <dl.h>
1035 #endif
1036 
1037 /* some flags are missing on some systems, so we provide
1038  * harmless defaults.
1039  *
1040  * Mandatory:
1041  * BIND_IMMEDIATE  - Resolve symbol references when the library is loaded.
1042  * BIND_DEFERRED   - Delay code symbol resolution until actual reference.
1043  *
1044  * Optionally:
1045  * BIND_FIRST	   - Place the library at the head of the symbol search
1046  * 		     order.
1047  * BIND_NONFATAL   - The default BIND_IMMEDIATE behavior is to treat all
1048  * 		     unsatisfied symbols as fatal.  This flag allows
1049  * 		     binding of unsatisfied code symbols to be deferred
1050  * 		     until use.
1051  *		     [Perl: For certain libraries, like DCE, deferred
1052  *		     binding often causes run time problems. Adding
1053  *		     BIND_NONFATAL to BIND_IMMEDIATE still allows
1054  *		     unresolved references in situations like this.]
1055  * BIND_NOSTART	   - Do not call the initializer for the shared library
1056  *		     when the library is loaded, nor on a future call to
1057  *		     shl_unload().
1058  * BIND_VERBOSE	   - Print verbose messages concerning possible
1059  *		     unsatisfied symbols.
1060  *
1061  * hp9000s700/hp9000s800:
1062  * BIND_RESTRICTED - Restrict symbols visible by the library to those
1063  *		     present at library load time.
1064  * DYNAMIC_PATH	   - Allow the loader to dynamically search for the
1065  *		     library specified by the path argument.
1066  */
1067 
1068 #ifndef	DYNAMIC_PATH
1069 #  define DYNAMIC_PATH		0
1070 #endif
1071 #ifndef	BIND_RESTRICTED
1072 #  define BIND_RESTRICTED	0
1073 #endif
1074 
1075 #define	LT_BIND_FLAGS	(BIND_IMMEDIATE | BIND_NONFATAL | DYNAMIC_PATH)
1076 
1077 static lt_module
sys_shl_open(loader_data,filename)1078 sys_shl_open (loader_data, filename)
1079      lt_user_data loader_data;
1080      const char *filename;
1081 {
1082   static shl_t self = (shl_t) 0;
1083   lt_module module = shl_load (filename, LT_BIND_FLAGS, 0L);
1084 
1085   /* Since searching for a symbol against a NULL module handle will also
1086      look in everything else that was already loaded and exported with
1087      the -E compiler flag, we always cache a handle saved before any
1088      modules are loaded.  */
1089   if (!self)
1090     {
1091       lt_ptr address;
1092       shl_findsym (&self, "main", TYPE_UNDEFINED, &address);
1093     }
1094 
1095   if (!filename)
1096     {
1097       module = self;
1098     }
1099   else
1100     {
1101       module = shl_load (filename, LT_BIND_FLAGS, 0L);
1102 
1103       if (!module)
1104 	{
1105 	  LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));
1106 	}
1107     }
1108 
1109   return module;
1110 }
1111 
1112 static int
sys_shl_close(loader_data,module)1113 sys_shl_close (loader_data, module)
1114      lt_user_data loader_data;
1115      lt_module module;
1116 {
1117   int errors = 0;
1118 
1119   if (module && (shl_unload ((shl_t) (module)) != 0))
1120     {
1121       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));
1122       ++errors;
1123     }
1124 
1125   return errors;
1126 }
1127 
1128 static lt_ptr
sys_shl_sym(loader_data,module,symbol)1129 sys_shl_sym (loader_data, module, symbol)
1130      lt_user_data loader_data;
1131      lt_module module;
1132      const char *symbol;
1133 {
1134   lt_ptr address = NULL;
1135 
1136   /* sys_shl_open should never return a NULL module handle */
1137   if (module == (lt_module) 0)
1138   {
1139     LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
1140   }
1141   else if (!shl_findsym((shl_t*) &module, symbol, TYPE_UNDEFINED, &address))
1142     {
1143       if (!address)
1144 	{
1145 	  LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
1146 	}
1147     }
1148 
1149   return address;
1150 }
1151 
1152 static struct lt_user_dlloader sys_shl = {
1153   0, sys_shl_open, sys_shl_close, sys_shl_sym, 0, 0
1154 };
1155 
1156 #endif /* HAVE_SHL_LOAD */
1157 
1158 
1159 
1160 
1161 /* --- LOADLIBRARY() INTERFACE LOADER --- */
1162 
1163 #ifdef __WINDOWS__
1164 
1165 /* dynamic linking for Win32 */
1166 
1167 #include <windows.h>
1168 
1169 /* Forward declaration; required to implement handle search below. */
1170 static lt_dlhandle handles;
1171 
1172 static lt_module
sys_wll_open(loader_data,filename)1173 sys_wll_open (loader_data, filename)
1174      lt_user_data loader_data;
1175      const char *filename;
1176 {
1177   lt_dlhandle	cur;
1178   lt_module	module	   = NULL;
1179   const char   *errormsg   = NULL;
1180   char	       *searchname = NULL;
1181   char	       *ext;
1182   char		self_name_buf[MAX_PATH];
1183 
1184   if (!filename)
1185     {
1186       /* Get the name of main module */
1187       *self_name_buf = '\0';
1188       GetModuleFileName (NULL, self_name_buf, sizeof (self_name_buf));
1189       filename = ext = self_name_buf;
1190     }
1191   else
1192     {
1193       ext = strrchr (filename, '.');
1194     }
1195 
1196   if (ext)
1197     {
1198       /* FILENAME already has an extension. */
1199       searchname = lt_estrdup (filename);
1200     }
1201   else
1202     {
1203       /* Append a `.' to stop Windows from adding an
1204 	 implicit `.dll' extension. */
1205       searchname = LT_EMALLOC (char, 2+ LT_STRLEN (filename));
1206       if (searchname)
1207 	sprintf (searchname, "%s.", filename);
1208     }
1209   if (!searchname)
1210     return 0;
1211 
1212 #if __CYGWIN__
1213   {
1214     char wpath[MAX_PATH];
1215     cygwin_conv_to_full_win32_path(searchname, wpath);
1216     module = LoadLibrary(wpath);
1217   }
1218 #else
1219   module = LoadLibrary (searchname);
1220 #endif
1221   LT_DLFREE (searchname);
1222 
1223   /* libltdl expects this function to fail if it is unable
1224      to physically load the library.  Sadly, LoadLibrary
1225      will search the loaded libraries for a match and return
1226      one of them if the path search load fails.
1227 
1228      We check whether LoadLibrary is returning a handle to
1229      an already loaded module, and simulate failure if we
1230      find one. */
1231   LT_DLMUTEX_LOCK ();
1232   cur = handles;
1233   while (cur)
1234     {
1235       if (!cur->module)
1236 	{
1237 	  cur = NULL;
1238 	  break;
1239 	}
1240 
1241       if (cur->module == module)
1242 	{
1243 	  break;
1244 	}
1245 
1246       cur = cur->next;
1247   }
1248   LT_DLMUTEX_UNLOCK ();
1249 
1250   if (cur || !module)
1251     {
1252       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));
1253       module = NULL;
1254     }
1255 
1256   return module;
1257 }
1258 
1259 static int
sys_wll_close(loader_data,module)1260 sys_wll_close (loader_data, module)
1261      lt_user_data loader_data;
1262      lt_module module;
1263 {
1264   int	      errors   = 0;
1265 
1266   if (FreeLibrary(module) == 0)
1267     {
1268       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));
1269       ++errors;
1270     }
1271 
1272   return errors;
1273 }
1274 
1275 static lt_ptr
sys_wll_sym(loader_data,module,symbol)1276 sys_wll_sym (loader_data, module, symbol)
1277      lt_user_data loader_data;
1278      lt_module module;
1279      const char *symbol;
1280 {
1281   lt_ptr      address  = GetProcAddress (module, symbol);
1282 
1283   if (!address)
1284     {
1285       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
1286     }
1287 
1288   return address;
1289 }
1290 
1291 static struct lt_user_dlloader sys_wll = {
1292   0, sys_wll_open, sys_wll_close, sys_wll_sym, 0, 0
1293 };
1294 
1295 #endif /* __WINDOWS__ */
1296 
1297 
1298 
1299 
1300 /* --- LOAD_ADD_ON() INTERFACE LOADER --- */
1301 
1302 
1303 #ifdef __BEOS__
1304 
1305 /* dynamic linking for BeOS */
1306 
1307 #include <kernel/image.h>
1308 
1309 static lt_module
sys_bedl_open(loader_data,filename)1310 sys_bedl_open (loader_data, filename)
1311      lt_user_data loader_data;
1312      const char *filename;
1313 {
1314   image_id image = 0;
1315 
1316   if (filename)
1317     {
1318       image = load_add_on (filename);
1319     }
1320   else
1321     {
1322       image_info info;
1323       int32 cookie = 0;
1324       if (get_next_image_info (0, &cookie, &info) == B_OK)
1325 	image = load_add_on (info.name);
1326     }
1327 
1328   if (image <= 0)
1329     {
1330       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));
1331       image = 0;
1332     }
1333 
1334   return (lt_module) image;
1335 }
1336 
1337 static int
sys_bedl_close(loader_data,module)1338 sys_bedl_close (loader_data, module)
1339      lt_user_data loader_data;
1340      lt_module module;
1341 {
1342   int errors = 0;
1343 
1344   if (unload_add_on ((image_id) module) != B_OK)
1345     {
1346       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));
1347       ++errors;
1348     }
1349 
1350   return errors;
1351 }
1352 
1353 static lt_ptr
sys_bedl_sym(loader_data,module,symbol)1354 sys_bedl_sym (loader_data, module, symbol)
1355      lt_user_data loader_data;
1356      lt_module module;
1357      const char *symbol;
1358 {
1359   lt_ptr address = NULL;
1360   image_id image = (image_id) module;
1361 
1362   if (get_image_symbol (image, symbol, B_SYMBOL_TYPE_ANY, address) != B_OK)
1363     {
1364       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
1365       address = NULL;
1366     }
1367 
1368   return address;
1369 }
1370 
1371 static struct lt_user_dlloader sys_bedl = {
1372   0, sys_bedl_open, sys_bedl_close, sys_bedl_sym, 0, 0
1373 };
1374 
1375 #endif /* __BEOS__ */
1376 
1377 
1378 
1379 
1380 /* --- DLD_LINK() INTERFACE LOADER --- */
1381 
1382 
1383 #if HAVE_DLD
1384 
1385 /* dynamic linking with dld */
1386 
1387 #if HAVE_DLD_H
1388 #include <dld.h>
1389 #endif
1390 
1391 static lt_module
sys_dld_open(loader_data,filename)1392 sys_dld_open (loader_data, filename)
1393      lt_user_data loader_data;
1394      const char *filename;
1395 {
1396   lt_module module = strdup (filename);
1397 
1398   if (dld_link (filename) != 0)
1399     {
1400       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN));
1401       LT_DLFREE (module);
1402       module = NULL;
1403     }
1404 
1405   return module;
1406 }
1407 
1408 static int
sys_dld_close(loader_data,module)1409 sys_dld_close (loader_data, module)
1410      lt_user_data loader_data;
1411      lt_module module;
1412 {
1413   int errors = 0;
1414 
1415   if (dld_unlink_by_file ((char*)(module), 1) != 0)
1416     {
1417       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE));
1418       ++errors;
1419     }
1420   else
1421     {
1422       LT_DLFREE (module);
1423     }
1424 
1425   return errors;
1426 }
1427 
1428 static lt_ptr
sys_dld_sym(loader_data,module,symbol)1429 sys_dld_sym (loader_data, module, symbol)
1430      lt_user_data loader_data;
1431      lt_module module;
1432      const char *symbol;
1433 {
1434   lt_ptr address = dld_get_func (symbol);
1435 
1436   if (!address)
1437     {
1438       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
1439     }
1440 
1441   return address;
1442 }
1443 
1444 static struct lt_user_dlloader sys_dld = {
1445   0, sys_dld_open, sys_dld_close, sys_dld_sym, 0, 0
1446 };
1447 
1448 #endif /* HAVE_DLD */
1449 
1450 
1451 
1452 
1453 /* --- DLPREOPEN() INTERFACE LOADER --- */
1454 
1455 
1456 /* emulate dynamic linking using preloaded_symbols */
1457 
1458 typedef struct lt_dlsymlists_t
1459 {
1460   struct lt_dlsymlists_t       *next;
1461   const lt_dlsymlist	       *syms;
1462 } lt_dlsymlists_t;
1463 
1464 static	const lt_dlsymlist     *default_preloaded_symbols	= NULL;
1465 static	lt_dlsymlists_t	       *preloaded_symbols		= NULL;
1466 
1467 static int
presym_init(loader_data)1468 presym_init (loader_data)
1469      lt_user_data loader_data;
1470 {
1471   int errors = 0;
1472 
1473   LT_DLMUTEX_LOCK ();
1474 
1475   preloaded_symbols = NULL;
1476   if (default_preloaded_symbols)
1477     {
1478       errors = lt_dlpreload (default_preloaded_symbols);
1479     }
1480 
1481   LT_DLMUTEX_UNLOCK ();
1482 
1483   return errors;
1484 }
1485 
1486 static int
presym_free_symlists()1487 presym_free_symlists ()
1488 {
1489   lt_dlsymlists_t *lists;
1490 
1491   LT_DLMUTEX_LOCK ();
1492 
1493   lists = preloaded_symbols;
1494   while (lists)
1495     {
1496       lt_dlsymlists_t	*tmp = lists;
1497 
1498       lists = lists->next;
1499       LT_DLFREE (tmp);
1500     }
1501   preloaded_symbols = NULL;
1502 
1503   LT_DLMUTEX_UNLOCK ();
1504 
1505   return 0;
1506 }
1507 
1508 static int
presym_exit(loader_data)1509 presym_exit (loader_data)
1510      lt_user_data loader_data;
1511 {
1512   presym_free_symlists ();
1513   return 0;
1514 }
1515 
1516 static int
presym_add_symlist(preloaded)1517 presym_add_symlist (preloaded)
1518      const lt_dlsymlist *preloaded;
1519 {
1520   lt_dlsymlists_t *tmp;
1521   lt_dlsymlists_t *lists;
1522   int		   errors   = 0;
1523 
1524   LT_DLMUTEX_LOCK ();
1525 
1526   lists = preloaded_symbols;
1527   while (lists)
1528     {
1529       if (lists->syms == preloaded)
1530 	{
1531 	  goto done;
1532 	}
1533       lists = lists->next;
1534     }
1535 
1536   tmp = LT_EMALLOC (lt_dlsymlists_t, 1);
1537   if (tmp)
1538     {
1539       memset (tmp, 0, sizeof(lt_dlsymlists_t));
1540       tmp->syms = preloaded;
1541       tmp->next = preloaded_symbols;
1542       preloaded_symbols = tmp;
1543     }
1544   else
1545     {
1546       ++errors;
1547     }
1548 
1549  done:
1550   LT_DLMUTEX_UNLOCK ();
1551   return errors;
1552 }
1553 
1554 static lt_module
presym_open(loader_data,filename)1555 presym_open (loader_data, filename)
1556      lt_user_data loader_data;
1557      const char *filename;
1558 {
1559   lt_dlsymlists_t *lists;
1560   lt_module	   module = (lt_module) 0;
1561 
1562   LT_DLMUTEX_LOCK ();
1563   lists = preloaded_symbols;
1564 
1565   if (!lists)
1566     {
1567       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_SYMBOLS));
1568       goto done;
1569     }
1570 
1571   /* Can't use NULL as the reflective symbol header, as NULL is
1572      used to mark the end of the entire symbol list.  Self-dlpreopened
1573      symbols follow this magic number, chosen to be an unlikely
1574      clash with a real module name.  */
1575   if (!filename)
1576     {
1577       filename = "@PROGRAM@";
1578     }
1579 
1580   while (lists)
1581     {
1582       const lt_dlsymlist *syms = lists->syms;
1583 
1584       while (syms->name)
1585 	{
1586 	  if (!syms->address && strcmp(syms->name, filename) == 0)
1587 	    {
1588 	      module = (lt_module) syms;
1589 	      goto done;
1590 	    }
1591 	  ++syms;
1592 	}
1593 
1594       lists = lists->next;
1595     }
1596 
1597   LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
1598 
1599  done:
1600   LT_DLMUTEX_UNLOCK ();
1601   return module;
1602 }
1603 
1604 static int
presym_close(loader_data,module)1605 presym_close (loader_data, module)
1606      lt_user_data loader_data;
1607      lt_module module;
1608 {
1609   /* Just to silence gcc -Wall */
1610   module = NULL;
1611   return 0;
1612 }
1613 
1614 static lt_ptr
presym_sym(loader_data,module,symbol)1615 presym_sym (loader_data, module, symbol)
1616      lt_user_data loader_data;
1617      lt_module module;
1618      const char *symbol;
1619 {
1620   lt_dlsymlist *syms = (lt_dlsymlist*) module;
1621 
1622   ++syms;
1623   while (syms->address)
1624     {
1625       if (strcmp(syms->name, symbol) == 0)
1626 	{
1627 	  return syms->address;
1628 	}
1629 
1630     ++syms;
1631   }
1632 
1633   LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
1634 
1635   return 0;
1636 }
1637 
1638 static struct lt_user_dlloader presym = {
1639   0, presym_open, presym_close, presym_sym, presym_exit, 0
1640 };
1641 
1642 
1643 
1644 
1645 
1646 /* --- DYNAMIC MODULE LOADING --- */
1647 
1648 
1649 /* The type of a function used at each iteration of  foreach_dirinpath().  */
1650 typedef int	foreach_callback_func LT_PARAMS((char *filename, lt_ptr data1,
1651 						 lt_ptr data2));
1652 
1653 static	int	foreach_dirinpath     LT_PARAMS((const char *search_path,
1654 						 const char *base_name,
1655 						 foreach_callback_func *func,
1656 						 lt_ptr data1, lt_ptr data2));
1657 
1658 static	int	find_file_callback    LT_PARAMS((char *filename, lt_ptr data,
1659 						 lt_ptr ignored));
1660 static	int	find_handle_callback  LT_PARAMS((char *filename, lt_ptr data,
1661 						 lt_ptr ignored));
1662 static	int	foreachfile_callback  LT_PARAMS((char *filename, lt_ptr data1,
1663 						 lt_ptr data2));
1664 
1665 
1666 static	int     canonicalize_path     LT_PARAMS((const char *path,
1667 						 char **pcanonical));
1668 static	int	argzize_path 	      LT_PARAMS((const char *path,
1669 						 char **pargz,
1670 						 size_t *pargz_len));
1671 static	FILE   *find_file	      LT_PARAMS((const char *search_path,
1672 						 const char *base_name,
1673 						 char **pdir));
1674 static	lt_dlhandle *find_handle      LT_PARAMS((const char *search_path,
1675 						 const char *base_name,
1676 						 lt_dlhandle *handle));
1677 static	int	find_module	      LT_PARAMS((lt_dlhandle *handle,
1678 						 const char *dir,
1679 						 const char *libdir,
1680 						 const char *dlname,
1681 						 const char *old_name,
1682 						 int installed));
1683 static	int	free_vars	      LT_PARAMS((char *dlname, char *oldname,
1684 						 char *libdir, char *deplibs));
1685 static	int	load_deplibs	      LT_PARAMS((lt_dlhandle handle,
1686 						 char *deplibs));
1687 static	int	trim		      LT_PARAMS((char **dest,
1688 						 const char *str));
1689 static	int	try_dlopen	      LT_PARAMS((lt_dlhandle *handle,
1690 						 const char *filename));
1691 static	int	tryall_dlopen	      LT_PARAMS((lt_dlhandle *handle,
1692 						 const char *filename));
1693 static	int	unload_deplibs	      LT_PARAMS((lt_dlhandle handle));
1694 static	int	lt_argz_insert	      LT_PARAMS((char **pargz,
1695 						 size_t *pargz_len,
1696 						 char *before,
1697 						 const char *entry));
1698 static	int	lt_argz_insertinorder LT_PARAMS((char **pargz,
1699 						 size_t *pargz_len,
1700 						 const char *entry));
1701 static	int	lt_argz_insertdir     LT_PARAMS((char **pargz,
1702 						 size_t *pargz_len,
1703 						 const char *dirnam,
1704 						 struct dirent *dp));
1705 static	int	lt_dlpath_insertdir   LT_PARAMS((char **ppath,
1706 						 char *before,
1707 						 const char *dir));
1708 static	int	list_files_by_dir     LT_PARAMS((const char *dirnam,
1709 						 char **pargz,
1710 						 size_t *pargz_len));
1711 static	int	file_not_found	      LT_PARAMS((void));
1712 
1713 static	char	       *user_search_path= NULL;
1714 static	lt_dlloader    *loaders		= NULL;
1715 static	lt_dlhandle	handles 	= NULL;
1716 static	int		initialized 	= 0;
1717 
1718 /* Initialize libltdl. */
1719 int
lt_dlinit()1720 lt_dlinit ()
1721 {
1722   int	      errors   = 0;
1723 
1724   LT_DLMUTEX_LOCK ();
1725 
1726   /* Initialize only at first call. */
1727   if (++initialized == 1)
1728     {
1729       handles = NULL;
1730       user_search_path = NULL; /* empty search path */
1731 
1732 #if HAVE_LIBDL && !defined(__CYGWIN__)
1733       errors += lt_dlloader_add (lt_dlloader_next (0), &sys_dl, "dlopen");
1734 #endif
1735 #if HAVE_SHL_LOAD
1736       errors += lt_dlloader_add (lt_dlloader_next (0), &sys_shl, "dlopen");
1737 #endif
1738 #ifdef __WINDOWS__
1739       errors += lt_dlloader_add (lt_dlloader_next (0), &sys_wll, "dlopen");
1740 #endif
1741 #ifdef __BEOS__
1742       errors += lt_dlloader_add (lt_dlloader_next (0), &sys_bedl, "dlopen");
1743 #endif
1744 #if HAVE_DLD
1745       errors += lt_dlloader_add (lt_dlloader_next (0), &sys_dld, "dld");
1746 #endif
1747       errors += lt_dlloader_add (lt_dlloader_next (0), &presym, "dlpreload");
1748 
1749       if (presym_init (presym.dlloader_data))
1750 	{
1751 	  LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INIT_LOADER));
1752 	  ++errors;
1753 	}
1754       else if (errors != 0)
1755 	{
1756 	  LT_DLMUTEX_SETERROR (LT_DLSTRERROR (DLOPEN_NOT_SUPPORTED));
1757 	  ++errors;
1758 	}
1759     }
1760 
1761   LT_DLMUTEX_UNLOCK ();
1762 
1763   return errors;
1764 }
1765 
1766 int
lt_dlpreload(preloaded)1767 lt_dlpreload (preloaded)
1768      const lt_dlsymlist *preloaded;
1769 {
1770   int errors = 0;
1771 
1772   if (preloaded)
1773     {
1774       errors = presym_add_symlist (preloaded);
1775     }
1776   else
1777     {
1778       presym_free_symlists();
1779 
1780       LT_DLMUTEX_LOCK ();
1781       if (default_preloaded_symbols)
1782 	{
1783 	  errors = lt_dlpreload (default_preloaded_symbols);
1784 	}
1785       LT_DLMUTEX_UNLOCK ();
1786     }
1787 
1788   return errors;
1789 }
1790 
1791 int
lt_dlpreload_default(preloaded)1792 lt_dlpreload_default (preloaded)
1793      const lt_dlsymlist *preloaded;
1794 {
1795   LT_DLMUTEX_LOCK ();
1796   default_preloaded_symbols = preloaded;
1797   LT_DLMUTEX_UNLOCK ();
1798   return 0;
1799 }
1800 
1801 int
lt_dlexit()1802 lt_dlexit ()
1803 {
1804   /* shut down libltdl */
1805   lt_dlloader *loader;
1806   int	       errors   = 0;
1807 
1808   LT_DLMUTEX_LOCK ();
1809   loader = loaders;
1810 
1811   if (!initialized)
1812     {
1813       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SHUTDOWN));
1814       ++errors;
1815       goto done;
1816     }
1817 
1818   /* shut down only at last call. */
1819   if (--initialized == 0)
1820     {
1821       int	level;
1822 
1823       while (handles && LT_DLIS_RESIDENT (handles))
1824 	{
1825 	  handles = handles->next;
1826 	}
1827 
1828       /* close all modules */
1829       for (level = 1; handles; ++level)
1830 	{
1831 	  lt_dlhandle cur = handles;
1832 	  int saw_nonresident = 0;
1833 
1834 	  while (cur)
1835 	    {
1836 	      lt_dlhandle tmp = cur;
1837 	      cur = cur->next;
1838 	      if (!LT_DLIS_RESIDENT (tmp))
1839 		saw_nonresident = 1;
1840 	      if (!LT_DLIS_RESIDENT (tmp) && tmp->info.ref_count <= level)
1841 		{
1842 		  if (lt_dlclose (tmp))
1843 		    {
1844 		      ++errors;
1845 		    }
1846 		}
1847 	    }
1848 	  /* done if only resident modules are left */
1849 	  if (!saw_nonresident)
1850 	    break;
1851 	}
1852 
1853       /* close all loaders */
1854       while (loader)
1855 	{
1856 	  lt_dlloader *next = loader->next;
1857 	  lt_user_data data = loader->dlloader_data;
1858 	  if (loader->dlloader_exit && loader->dlloader_exit (data))
1859 	    {
1860 	      ++errors;
1861 	    }
1862 
1863 	  LT_DLMEM_REASSIGN (loader, next);
1864 	}
1865       loaders = NULL;
1866     }
1867 
1868  done:
1869   LT_DLMUTEX_UNLOCK ();
1870   return errors;
1871 }
1872 
1873 static int
tryall_dlopen(handle,filename)1874 tryall_dlopen (handle, filename)
1875      lt_dlhandle *handle;
1876      const char *filename;
1877 {
1878   lt_dlhandle	 cur;
1879   lt_dlloader   *loader;
1880   const char	*saved_error;
1881   int		 errors		= 0;
1882 
1883   LT_DLMUTEX_GETERROR (saved_error);
1884   LT_DLMUTEX_LOCK ();
1885 
1886   cur	 = handles;
1887   loader = loaders;
1888 
1889   /* check whether the module was already opened */
1890   while (cur)
1891     {
1892       /* try to dlopen the program itself? */
1893       if (!cur->info.filename && !filename)
1894 	{
1895 	  break;
1896 	}
1897 
1898       if (cur->info.filename && filename
1899 	  && strcmp (cur->info.filename, filename) == 0)
1900 	{
1901 	  break;
1902 	}
1903 
1904       cur = cur->next;
1905     }
1906 
1907   if (cur)
1908     {
1909       ++cur->info.ref_count;
1910       *handle = cur;
1911       goto done;
1912     }
1913 
1914   cur = *handle;
1915   if (filename)
1916     {
1917       cur->info.filename = lt_estrdup (filename);
1918       if (!cur->info.filename)
1919 	{
1920 	  ++errors;
1921 	  goto done;
1922 	}
1923     }
1924   else
1925     {
1926       cur->info.filename = NULL;
1927     }
1928 
1929   while (loader)
1930     {
1931       lt_user_data data = loader->dlloader_data;
1932 
1933       cur->module = loader->module_open (data, filename);
1934 
1935       if (cur->module != NULL)
1936 	{
1937 	  break;
1938 	}
1939       loader = loader->next;
1940     }
1941 
1942   if (!loader)
1943     {
1944       LT_DLFREE (cur->info.filename);
1945       ++errors;
1946       goto done;
1947     }
1948 
1949   cur->loader	= loader;
1950   LT_DLMUTEX_SETERROR (saved_error);
1951 
1952  done:
1953   LT_DLMUTEX_UNLOCK ();
1954 
1955   return errors;
1956 }
1957 
1958 static int
tryall_dlopen_module(handle,prefix,dirname,dlname)1959 tryall_dlopen_module (handle, prefix, dirname, dlname)
1960      lt_dlhandle *handle;
1961      const char *prefix;
1962      const char *dirname;
1963      const char *dlname;
1964 {
1965   int      error	= 0;
1966   char     *filename	= NULL;
1967   size_t   filename_len	= 0;
1968   size_t   dirname_len	= LT_STRLEN (dirname);
1969 
1970   assert (handle);
1971   assert (dirname);
1972   assert (dlname);
1973 #ifdef LT_DIRSEP_CHAR
1974   /* Only canonicalized names (i.e. with DIRSEP chars already converted)
1975      should make it into this function:  */
1976   assert (strchr (dirname, LT_DIRSEP_CHAR) == NULL);
1977 #endif
1978 
1979   if (dirname[dirname_len -1] == '/')
1980     --dirname_len;
1981   filename_len = dirname_len + 1 + LT_STRLEN (dlname);
1982 
1983   /* Allocate memory, and combine DIRNAME and MODULENAME into it.
1984      The PREFIX (if any) is handled below.  */
1985   filename  = LT_EMALLOC (char, dirname_len + 1 + filename_len + 1);
1986   if (!filename)
1987     return 1;
1988 
1989   sprintf (filename, "%.*s/%s", (int) dirname_len, dirname, dlname);
1990 
1991   /* Now that we have combined DIRNAME and MODULENAME, if there is
1992      also a PREFIX to contend with, simply recurse with the arguments
1993      shuffled.  Otherwise, attempt to open FILENAME as a module.  */
1994   if (prefix)
1995     {
1996       error += tryall_dlopen_module (handle,
1997 				     (const char *) 0, prefix, filename);
1998     }
1999   else if (tryall_dlopen (handle, filename) != 0)
2000     {
2001       ++error;
2002     }
2003 
2004   LT_DLFREE (filename);
2005   return error;
2006 }
2007 
2008 static int
find_module(handle,dir,libdir,dlname,old_name,installed)2009 find_module (handle, dir, libdir, dlname, old_name, installed)
2010      lt_dlhandle *handle;
2011      const char *dir;
2012      const char *libdir;
2013      const char *dlname;
2014      const char *old_name;
2015      int installed;
2016 {
2017   /* Try to open the old library first; if it was dlpreopened,
2018      we want the preopened version of it, even if a dlopenable
2019      module is available.  */
2020   if (old_name && tryall_dlopen (handle, old_name) == 0)
2021     {
2022       return 0;
2023     }
2024 
2025   /* Try to open the dynamic library.  */
2026   if (dlname)
2027     {
2028       /* try to open the installed module */
2029       if (installed && libdir)
2030 	{
2031 	  if (tryall_dlopen_module (handle,
2032 				    (const char *) 0, libdir, dlname) == 0)
2033 	    return 0;
2034 	}
2035 
2036       /* try to open the not-installed module */
2037       if (!installed)
2038 	{
2039 	  if (tryall_dlopen_module (handle, dir, objdir, dlname) == 0)
2040 	    return 0;
2041 	}
2042 
2043       /* maybe it was moved to another directory */
2044       {
2045 	  if (tryall_dlopen_module (handle,
2046 				    (const char *) 0, dir, dlname) == 0)
2047 	    return 0;
2048       }
2049     }
2050 
2051   return 1;
2052 }
2053 
2054 
2055 static int
canonicalize_path(path,pcanonical)2056 canonicalize_path (path, pcanonical)
2057      const char *path;
2058      char **pcanonical;
2059 {
2060   char *canonical = NULL;
2061 
2062   assert (path && *path);
2063   assert (pcanonical);
2064 
2065   canonical = LT_EMALLOC (char, 1+ LT_STRLEN (path));
2066   if (!canonical)
2067     return 1;
2068 
2069   {
2070     size_t dest = 0;
2071     size_t src;
2072     for (src = 0; path[src] != LT_EOS_CHAR; ++src)
2073       {
2074 	/* Path separators are not copied to the beginning or end of
2075 	   the destination, or if another separator would follow
2076 	   immediately.  */
2077 	if (path[src] == LT_PATHSEP_CHAR)
2078 	  {
2079 	    if ((dest == 0)
2080 		|| (path[1+ src] == LT_PATHSEP_CHAR)
2081 		|| (path[1+ src] == LT_EOS_CHAR))
2082 	      continue;
2083 	  }
2084 
2085 	/* Anything other than a directory separator is copied verbatim.  */
2086 	if ((path[src] != '/')
2087 #ifdef LT_DIRSEP_CHAR
2088 	    && (path[src] != LT_DIRSEP_CHAR)
2089 #endif
2090 	    )
2091 	  {
2092 	    canonical[dest++] = path[src];
2093 	  }
2094 	/* Directory separators are converted and copied only if they are
2095 	   not at the end of a path -- i.e. before a path separator or
2096 	   NULL terminator.  */
2097 	else if ((path[1+ src] != LT_PATHSEP_CHAR)
2098 		 && (path[1+ src] != LT_EOS_CHAR)
2099 #ifdef LT_DIRSEP_CHAR
2100 		 && (path[1+ src] != LT_DIRSEP_CHAR)
2101 #endif
2102 		 && (path[1+ src] != '/'))
2103 	  {
2104 	    canonical[dest++] = '/';
2105 	  }
2106       }
2107 
2108     /* Add an end-of-string marker at the end.  */
2109     canonical[dest] = LT_EOS_CHAR;
2110   }
2111 
2112   /* Assign new value.  */
2113   *pcanonical = canonical;
2114 
2115   return 0;
2116 }
2117 
2118 static int
argzize_path(path,pargz,pargz_len)2119 argzize_path (path, pargz, pargz_len)
2120      const char *path;
2121      char **pargz;
2122      size_t *pargz_len;
2123 {
2124   error_t error;
2125 
2126   assert (path);
2127   assert (pargz);
2128   assert (pargz_len);
2129 
2130   if ((error = argz_create_sep (path, LT_PATHSEP_CHAR, pargz, pargz_len)))
2131     {
2132       switch (error)
2133 	{
2134 	case ENOMEM:
2135 	  LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
2136 	  break;
2137 	default:
2138 	  LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN));
2139 	  break;
2140 	}
2141 
2142       return 1;
2143     }
2144 
2145   return 0;
2146 }
2147 
2148 /* Repeatedly call FUNC with each LT_PATHSEP_CHAR delimited element
2149    of SEARCH_PATH and references to DATA1 and DATA2, until FUNC returns
2150    non-zero or all elements are exhausted.  If BASE_NAME is non-NULL,
2151    it is appended to each SEARCH_PATH element before FUNC is called.  */
2152 static int
foreach_dirinpath(search_path,base_name,func,data1,data2)2153 foreach_dirinpath (search_path, base_name, func, data1, data2)
2154      const char *search_path;
2155      const char *base_name;
2156      foreach_callback_func *func;
2157      lt_ptr data1;
2158      lt_ptr data2;
2159 {
2160   int	 result		= 0;
2161   int	 filenamesize	= 0;
2162   size_t lenbase	= LT_STRLEN (base_name);
2163   size_t argz_len	= 0;
2164   char *argz		= NULL;
2165   char *filename	= NULL;
2166   char *canonical	= NULL;
2167 
2168   LT_DLMUTEX_LOCK ();
2169 
2170   if (!search_path || !*search_path)
2171     {
2172       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
2173       goto cleanup;
2174     }
2175 
2176   if (canonicalize_path (search_path, &canonical) != 0)
2177     goto cleanup;
2178 
2179   if (argzize_path (canonical, &argz, &argz_len) != 0)
2180     goto cleanup;
2181 
2182   {
2183     char *dir_name = NULL;
2184     while ((dir_name = argz_next (argz, argz_len, dir_name)))
2185       {
2186 	size_t lendir = LT_STRLEN (dir_name);
2187 
2188 	if (lendir +1 +lenbase >= filenamesize)
2189 	{
2190 	  LT_DLFREE (filename);
2191 	  filenamesize	= lendir +1 +lenbase +1; /* "/d" + '/' + "f" + '\0' */
2192 	  filename	= LT_EMALLOC (char, filenamesize);
2193 	  if (!filename)
2194 	    goto cleanup;
2195 	}
2196 
2197 	assert (filenamesize > lendir);
2198 	strcpy (filename, dir_name);
2199 
2200 	if (base_name && *base_name)
2201 	  {
2202 	    if (filename[lendir -1] != '/')
2203 	      filename[lendir++] = '/';
2204 	    strcpy (filename +lendir, base_name);
2205 	  }
2206 
2207 	if ((result = (*func) (filename, data1, data2)))
2208 	  {
2209 	    break;
2210 	  }
2211       }
2212   }
2213 
2214  cleanup:
2215   LT_DLFREE (argz);
2216   LT_DLFREE (canonical);
2217   LT_DLFREE (filename);
2218 
2219   LT_DLMUTEX_UNLOCK ();
2220 
2221   return result;
2222 }
2223 
2224 /* If FILEPATH can be opened, store the name of the directory component
2225    in DATA1, and the opened FILE* structure address in DATA2.  Otherwise
2226    DATA1 is unchanged, but DATA2 is set to a pointer to NULL.  */
2227 static int
find_file_callback(filename,data1,data2)2228 find_file_callback (filename, data1, data2)
2229      char *filename;
2230      lt_ptr data1;
2231      lt_ptr data2;
2232 {
2233   char	     **pdir	= (char **) data1;
2234   FILE	     **pfile	= (FILE **) data2;
2235   int	     is_done	= 0;
2236 
2237   assert (filename && *filename);
2238   assert (pdir);
2239   assert (pfile);
2240 
2241   if ((*pfile = fopen (filename, LT_READTEXT_MODE)))
2242     {
2243       char *dirend = strrchr (filename, '/');
2244 
2245       if (dirend > filename)
2246 	*dirend   = LT_EOS_CHAR;
2247 
2248       LT_DLFREE (*pdir);
2249       *pdir   = lt_estrdup (filename);
2250       is_done = (*pdir == NULL) ? -1 : 1;
2251     }
2252 
2253   return is_done;
2254 }
2255 
2256 static FILE *
find_file(search_path,base_name,pdir)2257 find_file (search_path, base_name, pdir)
2258      const char *search_path;
2259      const char *base_name;
2260      char **pdir;
2261 {
2262   FILE *file = NULL;
2263 
2264   foreach_dirinpath (search_path, base_name, find_file_callback, pdir, &file);
2265 
2266   return file;
2267 }
2268 
2269 static int
find_handle_callback(filename,data,ignored)2270 find_handle_callback (filename, data, ignored)
2271      char *filename;
2272      lt_ptr data;
2273      lt_ptr ignored;
2274 {
2275   lt_dlhandle  *handle		= (lt_dlhandle *) data;
2276   int		notfound	= access (filename, R_OK);
2277 
2278   /* Bail out if file cannot be read...  */
2279   if (notfound)
2280     return 0;
2281 
2282   /* Try to dlopen the file, but do not continue searching in any
2283      case.  */
2284   if (tryall_dlopen (handle, filename) != 0)
2285     *handle = NULL;
2286 
2287   return 1;
2288 }
2289 
2290 /* If HANDLE was found return it, otherwise return 0.  If HANDLE was
2291    found but could not be opened, *HANDLE will be set to 0.  */
2292 static lt_dlhandle *
find_handle(search_path,base_name,handle)2293 find_handle (search_path, base_name, handle)
2294      const char *search_path;
2295      const char *base_name;
2296      lt_dlhandle *handle;
2297 {
2298   if (!search_path)
2299     return 0;
2300 
2301   if (!foreach_dirinpath (search_path, base_name, find_handle_callback,
2302 			  handle, 0))
2303     return 0;
2304 
2305   return handle;
2306 }
2307 
2308 static int
load_deplibs(handle,deplibs)2309 load_deplibs (handle, deplibs)
2310      lt_dlhandle handle;
2311      char *deplibs;
2312 {
2313 #if LTDL_DLOPEN_DEPLIBS
2314   char	*p, *save_search_path = NULL;
2315   int   depcount = 0;
2316   int	i;
2317   char	**names = NULL;
2318 #endif
2319   int	errors = 0;
2320 
2321   handle->depcount = 0;
2322 
2323 #if LTDL_DLOPEN_DEPLIBS
2324   if (!deplibs)
2325     {
2326       return errors;
2327     }
2328   ++errors;
2329 
2330   LT_DLMUTEX_LOCK ();
2331   if (user_search_path)
2332     {
2333       save_search_path = lt_estrdup (user_search_path);
2334       if (!save_search_path)
2335 	goto cleanup;
2336     }
2337 
2338   /* extract search paths and count deplibs */
2339   p = deplibs;
2340   while (*p)
2341     {
2342       if (!isspace ((int) *p))
2343 	{
2344 	  char *end = p+1;
2345 	  while (*end && !isspace((int) *end))
2346 	    {
2347 	      ++end;
2348 	    }
2349 
2350 	  if (strncmp(p, "-L", 2) == 0 || strncmp(p, "-R", 2) == 0)
2351 	    {
2352 	      char save = *end;
2353 	      *end = '\0'; /* set a temporary string terminator */
2354 	      if (lt_dladdsearchdir(p+2))
2355 		{
2356 		  goto cleanup;
2357 		}
2358 	      *end = save;
2359 	    }
2360 	  else
2361 	    {
2362 	      ++depcount;
2363 	    }
2364 
2365 	  p = end;
2366 	}
2367       else
2368 	{
2369 	  ++p;
2370 	}
2371     }
2372 
2373   /* restore the old search path */
2374   LT_DLFREE (user_search_path);
2375   user_search_path = save_search_path;
2376 
2377   LT_DLMUTEX_UNLOCK ();
2378 
2379   if (!depcount)
2380     {
2381       errors = 0;
2382       goto cleanup;
2383     }
2384 
2385   names = LT_EMALLOC (char *, depcount * sizeof (char*));
2386   if (!names)
2387     goto cleanup;
2388 
2389   /* now only extract the actual deplibs */
2390   depcount = 0;
2391   p = deplibs;
2392   while (*p)
2393     {
2394       if (isspace ((int) *p))
2395 	{
2396 	  ++p;
2397 	}
2398       else
2399 	{
2400 	  char *end = p+1;
2401 	  while (*end && !isspace ((int) *end))
2402 	    {
2403 	      ++end;
2404 	    }
2405 
2406 	  if (strncmp(p, "-L", 2) != 0 && strncmp(p, "-R", 2) != 0)
2407 	    {
2408 	      char *name;
2409 	      char save = *end;
2410 	      *end = '\0'; /* set a temporary string terminator */
2411 	      if (strncmp(p, "-l", 2) == 0)
2412 		{
2413 		  size_t name_len = 3+ /* "lib" */ LT_STRLEN (p + 2);
2414 		  name = LT_EMALLOC (char, 1+ name_len);
2415 		  if (name)
2416 		    sprintf (name, "lib%s", p+2);
2417 		}
2418 	      else
2419 		name = lt_estrdup(p);
2420 
2421 	      if (!name)
2422 		goto cleanup_names;
2423 
2424 	      names[depcount++] = name;
2425 	      *end = save;
2426 	    }
2427 	  p = end;
2428 	}
2429     }
2430 
2431   /* load the deplibs (in reverse order)
2432      At this stage, don't worry if the deplibs do not load correctly,
2433      they may already be statically linked into the loading application
2434      for instance.  There will be a more enlightening error message
2435      later on if the loaded module cannot resolve all of its symbols.  */
2436   if (depcount)
2437     {
2438       int	j = 0;
2439 
2440       handle->deplibs = (lt_dlhandle*) LT_EMALLOC (lt_dlhandle *, depcount);
2441       if (!handle->deplibs)
2442 	goto cleanup;
2443 
2444       for (i = 0; i < depcount; ++i)
2445 	{
2446 	  handle->deplibs[j] = lt_dlopenext(names[depcount-1-i]);
2447 	  if (handle->deplibs[j])
2448 	    {
2449 	      ++j;
2450 	    }
2451 	}
2452 
2453       handle->depcount	= j;	/* Number of successfully loaded deplibs */
2454       errors		= 0;
2455     }
2456 
2457  cleanup_names:
2458   for (i = 0; i < depcount; ++i)
2459     {
2460       LT_DLFREE (names[i]);
2461     }
2462 
2463  cleanup:
2464   LT_DLFREE (names);
2465 #endif
2466 
2467   return errors;
2468 }
2469 
2470 static int
unload_deplibs(handle)2471 unload_deplibs (handle)
2472      lt_dlhandle handle;
2473 {
2474   int i;
2475   int errors = 0;
2476 
2477   if (handle->depcount)
2478     {
2479       for (i = 0; i < handle->depcount; ++i)
2480 	{
2481 	  if (!LT_DLIS_RESIDENT (handle->deplibs[i]))
2482 	    {
2483 	      errors += lt_dlclose (handle->deplibs[i]);
2484 	    }
2485 	}
2486     }
2487 
2488   return errors;
2489 }
2490 
2491 static int
trim(dest,str)2492 trim (dest, str)
2493      char **dest;
2494      const char *str;
2495 {
2496   /* remove the leading and trailing "'" from str
2497      and store the result in dest */
2498   const char *end   = strrchr (str, '\'');
2499   size_t len	    = LT_STRLEN (str);
2500   char *tmp;
2501 
2502   LT_DLFREE (*dest);
2503 
2504   if (len > 3 && str[0] == '\'')
2505     {
2506       tmp = LT_EMALLOC (char, end - str);
2507       if (!tmp)
2508 	return 1;
2509 
2510       strncpy(tmp, &str[1], (end - str) - 1);
2511       tmp[len-3] = LT_EOS_CHAR;
2512       *dest = tmp;
2513     }
2514   else
2515     {
2516       *dest = NULL;
2517     }
2518 
2519   return 0;
2520 }
2521 
2522 static int
free_vars(dlname,oldname,libdir,deplibs)2523 free_vars (dlname, oldname, libdir, deplibs)
2524      char *dlname;
2525      char *oldname;
2526      char *libdir;
2527      char *deplibs;
2528 {
2529   LT_DLFREE (dlname);
2530   LT_DLFREE (oldname);
2531   LT_DLFREE (libdir);
2532   LT_DLFREE (deplibs);
2533 
2534   return 0;
2535 }
2536 
2537 static int
try_dlopen(phandle,filename)2538 try_dlopen (phandle, filename)
2539      lt_dlhandle *phandle;
2540      const char *filename;
2541 {
2542   const char *	ext		= NULL;
2543   const char *	saved_error	= NULL;
2544   char *	canonical	= NULL;
2545   char *	base_name	= NULL;
2546   char *	dir		= NULL;
2547   char *	name		= NULL;
2548   int		errors		= 0;
2549   lt_dlhandle	newhandle;
2550 
2551   assert (phandle);
2552   assert (*phandle == NULL);
2553 
2554   LT_DLMUTEX_GETERROR (saved_error);
2555 
2556   /* dlopen self? */
2557   if (!filename)
2558     {
2559       *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1);
2560       if (*phandle == NULL)
2561 	return 1;
2562 
2563       memset (*phandle, 0, sizeof(struct lt_dlhandle_struct));
2564       newhandle	= *phandle;
2565 
2566       /* lt_dlclose()ing yourself is very bad!  Disallow it.  */
2567       LT_DLSET_FLAG (*phandle, LT_DLRESIDENT_FLAG);
2568 
2569       if (tryall_dlopen (&newhandle, 0) != 0)
2570 	{
2571 	  LT_DLFREE (*phandle);
2572 	  return 1;
2573 	}
2574 
2575       goto register_handle;
2576     }
2577 
2578   assert (filename && *filename);
2579 
2580   /* Doing this immediately allows internal functions to safely
2581      assume only canonicalized paths are passed.  */
2582   if (canonicalize_path (filename, &canonical) != 0)
2583     {
2584       ++errors;
2585       goto cleanup;
2586     }
2587 
2588   /* If the canonical module name is a path (relative or absolute)
2589      then split it into a directory part and a name part.  */
2590   base_name = strrchr (canonical, '/');
2591   if (base_name)
2592     {
2593       size_t dirlen = (1+ base_name) - canonical;
2594 
2595       dir = LT_EMALLOC (char, 1+ dirlen);
2596       if (!dir)
2597 	{
2598 	  ++errors;
2599 	  goto cleanup;
2600 	}
2601 
2602       strncpy (dir, canonical, dirlen);
2603       dir[dirlen] = LT_EOS_CHAR;
2604 
2605       ++base_name;
2606     }
2607   else
2608     LT_DLMEM_REASSIGN (base_name, canonical);
2609 
2610   assert (base_name && *base_name);
2611 
2612   /* Check whether we are opening a libtool module (.la extension).  */
2613   ext = strrchr (base_name, '.');
2614   if (ext && strcmp (ext, archive_ext) == 0)
2615     {
2616       /* this seems to be a libtool module */
2617       FILE *	file	 = NULL;
2618       char *	dlname	 = NULL;
2619       char *	old_name = NULL;
2620       char *	libdir	 = NULL;
2621       char *	deplibs	 = NULL;
2622       char *    line	 = NULL;
2623       size_t	line_len;
2624 
2625       /* if we can't find the installed flag, it is probably an
2626 	 installed libtool archive, produced with an old version
2627 	 of libtool */
2628       int	installed = 1;
2629 
2630       /* extract the module name from the file name */
2631       name = LT_EMALLOC (char, ext - base_name + 1);
2632       if (!name)
2633 	{
2634 	  ++errors;
2635 	  goto cleanup;
2636 	}
2637 
2638       /* canonicalize the module name */
2639       {
2640         size_t i;
2641         for (i = 0; i < ext - base_name; ++i)
2642 	  {
2643 	    if (isalnum ((int)(base_name[i])))
2644 	      {
2645 	        name[i] = base_name[i];
2646 	      }
2647 	    else
2648 	      {
2649 	        name[i] = '_';
2650 	      }
2651 	  }
2652         name[ext - base_name] = LT_EOS_CHAR;
2653       }
2654 
2655       /* Now try to open the .la file.  If there is no directory name
2656          component, try to find it first in user_search_path and then other
2657          prescribed paths.  Otherwise (or in any case if the module was not
2658          yet found) try opening just the module name as passed.  */
2659       if (!dir)
2660 	{
2661 	  const char *search_path;
2662 
2663 	  LT_DLMUTEX_LOCK ();
2664 	  search_path = user_search_path;
2665 	  if (search_path)
2666 	    file = find_file (user_search_path, base_name, &dir);
2667 	  LT_DLMUTEX_UNLOCK ();
2668 
2669 	  if (!file)
2670 	    {
2671 	      search_path = getenv (LTDL_SEARCHPATH_VAR);
2672 	      if (search_path)
2673 		file = find_file (search_path, base_name, &dir);
2674 	    }
2675 
2676 #ifdef LTDL_SHLIBPATH_VAR
2677 	  if (!file)
2678 	    {
2679 	      search_path = getenv (LTDL_SHLIBPATH_VAR);
2680 	      if (search_path)
2681 		file = find_file (search_path, base_name, &dir);
2682 	    }
2683 #endif
2684 #ifdef LTDL_SYSSEARCHPATH
2685 	  if (!file && sys_search_path)
2686 	    {
2687 	      file = find_file (sys_search_path, base_name, &dir);
2688 	    }
2689 #endif
2690 	}
2691       if (!file)
2692 	{
2693 	  file = fopen (filename, LT_READTEXT_MODE);
2694 	}
2695 
2696       /* If we didn't find the file by now, it really isn't there.  Set
2697 	 the status flag, and bail out.  */
2698       if (!file)
2699 	{
2700 	  LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
2701 	  ++errors;
2702 	  goto cleanup;
2703 	}
2704 
2705       line_len = LT_FILENAME_MAX;
2706       line = LT_EMALLOC (char, line_len);
2707       if (!line)
2708 	{
2709 	  fclose (file);
2710 	  ++errors;
2711 	  goto cleanup;
2712 	}
2713 
2714       /* read the .la file */
2715       while (!feof (file))
2716 	{
2717 	  if (!fgets (line, (int) line_len, file))
2718 	    {
2719 	      break;
2720 	    }
2721 
2722 	  /* Handle the case where we occasionally need to read a line
2723 	     that is longer than the initial buffer size.  */
2724 	  while (line[LT_STRLEN(line) -1] != '\n')
2725 	    {
2726 	      line = LT_DLREALLOC (char, line, line_len *2);
2727 	      if (!fgets (&line[line_len -1], (int) line_len +1, file))
2728 		{
2729 		  break;
2730 		}
2731 	      line_len *= 2;
2732 	    }
2733 
2734 	  if (line[0] == '\n' || line[0] == '#')
2735 	    {
2736 	      continue;
2737 	    }
2738 
2739 #undef  STR_DLNAME
2740 #define STR_DLNAME	"dlname="
2741 	  if (strncmp (line, STR_DLNAME, sizeof (STR_DLNAME) - 1) == 0)
2742 	    {
2743 	      errors += trim (&dlname, &line[sizeof (STR_DLNAME) - 1]);
2744 	    }
2745 
2746 #undef  STR_OLD_LIBRARY
2747 #define STR_OLD_LIBRARY	"old_library="
2748 	  else if (strncmp (line, STR_OLD_LIBRARY,
2749 			    sizeof (STR_OLD_LIBRARY) - 1) == 0)
2750 	    {
2751 	      errors += trim (&old_name, &line[sizeof (STR_OLD_LIBRARY) - 1]);
2752 	    }
2753 #undef  STR_LIBDIR
2754 #define STR_LIBDIR	"libdir="
2755 	  else if (strncmp (line, STR_LIBDIR, sizeof (STR_LIBDIR) - 1) == 0)
2756 	    {
2757 	      errors += trim (&libdir, &line[sizeof(STR_LIBDIR) - 1]);
2758 	    }
2759 
2760 #undef  STR_DL_DEPLIBS
2761 #define STR_DL_DEPLIBS	"dependency_libs="
2762 	  else if (strncmp (line, STR_DL_DEPLIBS,
2763 			    sizeof (STR_DL_DEPLIBS) - 1) == 0)
2764 	    {
2765 	      errors += trim (&deplibs, &line[sizeof (STR_DL_DEPLIBS) - 1]);
2766 	    }
2767 	  else if (strcmp (line, "installed=yes\n") == 0)
2768 	    {
2769 	      installed = 1;
2770 	    }
2771 	  else if (strcmp (line, "installed=no\n") == 0)
2772 	    {
2773 	      installed = 0;
2774 	    }
2775 
2776 #undef  STR_LIBRARY_NAMES
2777 #define STR_LIBRARY_NAMES "library_names="
2778 	  else if (! dlname && strncmp (line, STR_LIBRARY_NAMES,
2779 					sizeof (STR_LIBRARY_NAMES) - 1) == 0)
2780 	    {
2781 	      char *last_libname;
2782 	      errors += trim (&dlname, &line[sizeof (STR_LIBRARY_NAMES) - 1]);
2783 	      if (!errors
2784 		  && dlname
2785 		  && (last_libname = strrchr (dlname, ' ')) != NULL)
2786 		{
2787 		  last_libname = lt_estrdup (last_libname + 1);
2788 		  if (!last_libname)
2789 		    {
2790 		      ++errors;
2791 		      goto cleanup;
2792 		    }
2793 		  LT_DLMEM_REASSIGN (dlname, last_libname);
2794 		}
2795 	    }
2796 
2797 	  if (errors)
2798 	    break;
2799 	}
2800 
2801       fclose (file);
2802       LT_DLFREE (line);
2803 
2804       /* allocate the handle */
2805       *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1);
2806       if (*phandle == NULL)
2807 	++errors;
2808 
2809       if (errors)
2810 	{
2811 	  free_vars (dlname, old_name, libdir, deplibs);
2812 	  LT_DLFREE (*phandle);
2813 	  goto cleanup;
2814 	}
2815 
2816       assert (*phandle);
2817 
2818       memset (*phandle, 0, sizeof(struct lt_dlhandle_struct));
2819       if (load_deplibs (*phandle, deplibs) == 0)
2820 	{
2821 	  newhandle = *phandle;
2822 	  /* find_module may replace newhandle */
2823 	  if (find_module (&newhandle, dir, libdir, dlname, old_name, installed))
2824 	    {
2825 	      unload_deplibs (*phandle);
2826 	      ++errors;
2827 	    }
2828 	}
2829       else
2830 	{
2831 	  ++errors;
2832 	}
2833 
2834       free_vars (dlname, old_name, libdir, deplibs);
2835       if (errors)
2836 	{
2837 	  LT_DLFREE (*phandle);
2838 	  goto cleanup;
2839 	}
2840 
2841       if (*phandle != newhandle)
2842 	{
2843 	  unload_deplibs (*phandle);
2844 	}
2845     }
2846   else
2847     {
2848       /* not a libtool module */
2849       *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1);
2850       if (*phandle == NULL)
2851 	{
2852 	  ++errors;
2853 	  goto cleanup;
2854 	}
2855 
2856       memset (*phandle, 0, sizeof (struct lt_dlhandle_struct));
2857       newhandle = *phandle;
2858 
2859       /* If the module has no directory name component, try to find it
2860 	 first in user_search_path and then other prescribed paths.
2861 	 Otherwise (or in any case if the module was not yet found) try
2862 	 opening just the module name as passed.  */
2863       if ((dir || (!find_handle (user_search_path, base_name, &newhandle)
2864 		   && !find_handle (getenv (LTDL_SEARCHPATH_VAR), base_name,
2865 				    &newhandle)
2866 #ifdef LTDL_SHLIBPATH_VAR
2867 		   && !find_handle (getenv (LTDL_SHLIBPATH_VAR), base_name,
2868 				    &newhandle)
2869 #endif
2870 #ifdef LTDL_SYSSEARCHPATH
2871 		   && !find_handle (sys_search_path, base_name, &newhandle)
2872 #endif
2873 		   )))
2874 	{
2875           if (tryall_dlopen (&newhandle, filename) != 0)
2876             {
2877               newhandle = NULL;
2878             }
2879 	}
2880 
2881       if (!newhandle)
2882 	{
2883 	  LT_DLFREE (*phandle);
2884 	  ++errors;
2885 	  goto cleanup;
2886 	}
2887     }
2888 
2889  register_handle:
2890   LT_DLMEM_REASSIGN (*phandle, newhandle);
2891 
2892   if ((*phandle)->info.ref_count == 0)
2893     {
2894       (*phandle)->info.ref_count	= 1;
2895       LT_DLMEM_REASSIGN ((*phandle)->info.name, name);
2896 
2897       LT_DLMUTEX_LOCK ();
2898       (*phandle)->next		= handles;
2899       handles			= *phandle;
2900       LT_DLMUTEX_UNLOCK ();
2901     }
2902 
2903   LT_DLMUTEX_SETERROR (saved_error);
2904 
2905  cleanup:
2906   LT_DLFREE (dir);
2907   LT_DLFREE (name);
2908   LT_DLFREE (canonical);
2909 
2910   return errors;
2911 }
2912 
2913 lt_dlhandle
lt_dlopen(filename)2914 lt_dlopen (filename)
2915      const char *filename;
2916 {
2917   lt_dlhandle handle = NULL;
2918 
2919   /* Just incase we missed a code path in try_dlopen() that reports
2920      an error, but forgets to reset handle... */
2921   if (try_dlopen (&handle, filename) != 0)
2922     return 0;
2923 
2924   return handle;
2925 }
2926 
2927 /* If the last error messge store was `FILE_NOT_FOUND', then return
2928    non-zero.  */
2929 static int
file_not_found()2930 file_not_found ()
2931 {
2932   const char *error = NULL;
2933 
2934   LT_DLMUTEX_GETERROR (error);
2935   if (error == LT_DLSTRERROR (FILE_NOT_FOUND))
2936     return 1;
2937 
2938   return 0;
2939 }
2940 
2941 /* If FILENAME has an ARCHIVE_EXT or SHLIB_EXT extension, try to
2942    open the FILENAME as passed.  Otherwise try appending ARCHIVE_EXT,
2943    and if a file is still not found try again with SHLIB_EXT appended
2944    instead.  */
2945 lt_dlhandle
lt_dlopenext(filename)2946 lt_dlopenext (filename)
2947      const char *filename;
2948 {
2949   lt_dlhandle	handle		= NULL;
2950   char *	tmp		= NULL;
2951   char *	ext		= NULL;
2952   size_t	len;
2953   int		errors		= 0;
2954 
2955   if (!filename)
2956     {
2957       return lt_dlopen (filename);
2958     }
2959 
2960   assert (filename);
2961 
2962   len = LT_STRLEN (filename);
2963   ext = strrchr (filename, '.');
2964 
2965   /* If FILENAME already bears a suitable extension, there is no need
2966      to try appending additional extensions.  */
2967   if (ext && ((strcmp (ext, archive_ext) == 0)
2968 #ifdef LTDL_SHLIB_EXT
2969 	      || (strcmp (ext, shlib_ext) == 0)
2970 #endif
2971       ))
2972     {
2973       return lt_dlopen (filename);
2974     }
2975 
2976   /* First try appending ARCHIVE_EXT.  */
2977   tmp = LT_EMALLOC (char, len + LT_STRLEN (archive_ext) + 1);
2978   if (!tmp)
2979     return 0;
2980 
2981   strcpy (tmp, filename);
2982   strcat (tmp, archive_ext);
2983   errors = try_dlopen (&handle, tmp);
2984 
2985   /* If we found FILENAME, stop searching -- whether we were able to
2986      load the file as a module or not.  If the file exists but loading
2987      failed, it is better to return an error message here than to
2988      report FILE_NOT_FOUND when the alternatives (foo.so etc) are not
2989      in the module search path.  */
2990   if (handle || ((errors > 0) && file_not_found ()))
2991     {
2992       LT_DLFREE (tmp);
2993       return handle;
2994     }
2995 
2996 #ifdef LTDL_SHLIB_EXT
2997   /* Try appending SHLIB_EXT.   */
2998   if (LT_STRLEN (shlib_ext) > LT_STRLEN (archive_ext))
2999     {
3000       LT_DLFREE (tmp);
3001       tmp = LT_EMALLOC (char, len + LT_STRLEN (shlib_ext) + 1);
3002       if (!tmp)
3003 	return 0;
3004 
3005       strcpy (tmp, filename);
3006     }
3007   else
3008     {
3009       tmp[len] = LT_EOS_CHAR;
3010     }
3011 
3012   strcat(tmp, shlib_ext);
3013   errors = try_dlopen (&handle, tmp);
3014 
3015   /* As before, if the file was found but loading failed, return now
3016      with the current error message.  */
3017   if (handle || ((errors > 0) && file_not_found ()))
3018     {
3019       LT_DLFREE (tmp);
3020       return handle;
3021     }
3022 #endif
3023 
3024   /* Still here?  Then we really did fail to locate any of the file
3025      names we tried.  */
3026   LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND));
3027   LT_DLFREE (tmp);
3028   return 0;
3029 }
3030 
3031 
3032 static int
lt_argz_insert(pargz,pargz_len,before,entry)3033 lt_argz_insert (pargz, pargz_len, before, entry)
3034      char **pargz;
3035      size_t *pargz_len;
3036      char *before;
3037      const char *entry;
3038 {
3039   error_t error;
3040 
3041   if ((error = argz_insert (pargz, pargz_len, before, entry)))
3042     {
3043       switch (error)
3044 	{
3045 	case ENOMEM:
3046 	  LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY));
3047 	  break;
3048 	default:
3049 	  LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN));
3050 	  break;
3051 	}
3052       return 1;
3053     }
3054 
3055   return 0;
3056 }
3057 
3058 static int
lt_argz_insertinorder(pargz,pargz_len,entry)3059 lt_argz_insertinorder (pargz, pargz_len, entry)
3060      char **pargz;
3061      size_t *pargz_len;
3062      const char *entry;
3063 {
3064   char *before = NULL;
3065 
3066   assert (pargz);
3067   assert (pargz_len);
3068   assert (entry && *entry);
3069 
3070   if (*pargz)
3071     while ((before = argz_next (*pargz, *pargz_len, before)))
3072       {
3073 	int cmp = strcmp (entry, before);
3074 
3075 	if (cmp < 0)  break;
3076 	if (cmp == 0) return 0;	/* No duplicates! */
3077       }
3078 
3079   return lt_argz_insert (pargz, pargz_len, before, entry);
3080 }
3081 
3082 static int
lt_argz_insertdir(pargz,pargz_len,dirnam,dp)3083 lt_argz_insertdir (pargz, pargz_len, dirnam, dp)
3084      char **pargz;
3085      size_t *pargz_len;
3086      const char *dirnam;
3087      struct dirent *dp;
3088 {
3089   char   *buf	    = NULL;
3090   size_t buf_len    = 0;
3091   char   *end	    = NULL;
3092   size_t end_offset = 0;
3093   size_t dir_len    = 0;
3094   int    errors	    = 0;
3095 
3096   assert (pargz);
3097   assert (pargz_len);
3098   assert (dp);
3099 
3100   dir_len = LT_STRLEN (dirnam);
3101   end     = dp->d_name + LT_D_NAMLEN(dp);
3102 
3103   /* Ignore version numbers.  */
3104   {
3105     char *p;
3106     for (p = end; p -1 > dp->d_name; --p)
3107       if (strchr (".0123456789", p[-1]) == 0)
3108 	break;
3109 
3110     if (*p == '.')
3111       end = p;
3112   }
3113 
3114   /* Ignore filename extension.  */
3115   {
3116     char *p;
3117     for (p = end -1; p > dp->d_name; --p)
3118       if (*p == '.')
3119 	{
3120 	  end = p;
3121 	  break;
3122 	}
3123   }
3124 
3125   /* Prepend the directory name.  */
3126   end_offset	= end - dp->d_name;
3127   buf_len	= dir_len + 1+ end_offset;
3128   buf		= LT_EMALLOC (char, 1+ buf_len);
3129   if (!buf)
3130     return ++errors;
3131 
3132   assert (buf);
3133 
3134   strcpy  (buf, dirnam);
3135   strcat  (buf, "/");
3136   strncat (buf, dp->d_name, end_offset);
3137   buf[buf_len] = LT_EOS_CHAR;
3138 
3139   /* Try to insert (in order) into ARGZ/ARGZ_LEN.  */
3140   if (lt_argz_insertinorder (pargz, pargz_len, buf) != 0)
3141     ++errors;
3142 
3143   LT_DLFREE (buf);
3144 
3145   return errors;
3146 }
3147 
3148 static int
list_files_by_dir(dirnam,pargz,pargz_len)3149 list_files_by_dir (dirnam, pargz, pargz_len)
3150      const char *dirnam;
3151      char **pargz;
3152      size_t *pargz_len;
3153 {
3154   DIR	*dirp	  = NULL;
3155   int    errors	  = 0;
3156 
3157   assert (dirnam && *dirnam);
3158   assert (pargz);
3159   assert (pargz_len);
3160   assert (dirnam[LT_STRLEN(dirnam) -1] != '/');
3161 
3162   dirp = opendir (dirnam);
3163   if (dirp)
3164     {
3165       struct dirent *dp	= NULL;
3166 
3167       while ((dp = readdir (dirp)))
3168 	if (dp->d_name[0] != '.')
3169 	  if (lt_argz_insertdir (pargz, pargz_len, dirnam, dp))
3170 	    {
3171 	      ++errors;
3172 	      break;
3173 	    }
3174 
3175       closedir (dirp);
3176     }
3177   else
3178     ++errors;
3179 
3180   return errors;
3181 }
3182 
3183 
3184 /* If there are any files in DIRNAME, call the function passed in
3185    DATA1 (with the name of each file and DATA2 as arguments).  */
3186 static int
foreachfile_callback(dirname,data1,data2)3187 foreachfile_callback (dirname, data1, data2)
3188      char *dirname;
3189      lt_ptr data1;
3190      lt_ptr data2;
3191 {
3192   int (*func) LT_PARAMS((const char *filename, lt_ptr data))
3193 	= (int (*) LT_PARAMS((const char *filename, lt_ptr data))) data1;
3194 
3195   int	  is_done  = 0;
3196   char   *argz     = NULL;
3197   size_t  argz_len = 0;
3198 
3199   if (list_files_by_dir (dirname, &argz, &argz_len) != 0)
3200     goto cleanup;
3201   if (!argz)
3202     goto cleanup;
3203 
3204   {
3205     char *filename = NULL;
3206     while ((filename = argz_next (argz, argz_len, filename)))
3207       if ((is_done = (*func) (filename, data2)))
3208 	break;
3209   }
3210 
3211  cleanup:
3212   LT_DLFREE (argz);
3213 
3214   return is_done;
3215 }
3216 
3217 
3218 /* Call FUNC for each unique extensionless file in SEARCH_PATH, along
3219    with DATA.  The filenames passed to FUNC would be suitable for
3220    passing to lt_dlopenext.  The extensions are stripped so that
3221    individual modules do not generate several entries (e.g. libfoo.la,
3222    libfoo.so, libfoo.so.1, libfoo.so.1.0.0).  If SEARCH_PATH is NULL,
3223    then the same directories that lt_dlopen would search are examined.  */
3224 int
lt_dlforeachfile(search_path,func,data)3225 lt_dlforeachfile (search_path, func, data)
3226      const char *search_path;
3227      int (*func) LT_PARAMS ((const char *filename, lt_ptr data));
3228      lt_ptr data;
3229 {
3230   int is_done = 0;
3231 
3232   if (search_path)
3233     {
3234       /* If a specific path was passed, search only the directories
3235 	 listed in it.  */
3236       is_done = foreach_dirinpath (search_path, 0,
3237 				   foreachfile_callback, func, data);
3238     }
3239   else
3240     {
3241       /* Otherwise search the default paths.  */
3242       is_done = foreach_dirinpath (user_search_path, 0,
3243 				   foreachfile_callback, func, data);
3244       if (!is_done)
3245 	{
3246 	  is_done = foreach_dirinpath (getenv("LTDL_LIBRARY_PATH"), 0,
3247 				       foreachfile_callback, func, data);
3248 	}
3249 
3250 #ifdef LTDL_SHLIBPATH_VAR
3251       if (!is_done)
3252 	{
3253 	  is_done = foreach_dirinpath (getenv(LTDL_SHLIBPATH_VAR), 0,
3254 				       foreachfile_callback, func, data);
3255 	}
3256 #endif
3257 #ifdef LTDL_SYSSEARCHPATH
3258       if (!is_done)
3259 	{
3260 	  is_done = foreach_dirinpath (getenv(LTDL_SYSSEARCHPATH), 0,
3261 				       foreachfile_callback, func, data);
3262 	}
3263 #endif
3264     }
3265 
3266   return is_done;
3267 }
3268 
3269 int
lt_dlclose(handle)3270 lt_dlclose (handle)
3271      lt_dlhandle handle;
3272 {
3273   lt_dlhandle cur, last;
3274   int errors = 0;
3275 
3276   LT_DLMUTEX_LOCK ();
3277 
3278   /* check whether the handle is valid */
3279   last = cur = handles;
3280   while (cur && handle != cur)
3281     {
3282       last = cur;
3283       cur = cur->next;
3284     }
3285 
3286   if (!cur)
3287     {
3288       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
3289       ++errors;
3290       goto done;
3291     }
3292 
3293   handle->info.ref_count--;
3294 
3295   /* Note that even with resident modules, we must track the ref_count
3296      correctly incase the user decides to reset the residency flag
3297      later (even though the API makes no provision for that at the
3298      moment).  */
3299   if (handle->info.ref_count <= 0 && !LT_DLIS_RESIDENT (handle))
3300     {
3301       lt_user_data data = handle->loader->dlloader_data;
3302 
3303       if (handle != handles)
3304 	{
3305 	  last->next = handle->next;
3306 	}
3307       else
3308 	{
3309 	  handles = handle->next;
3310 	}
3311 
3312       errors += handle->loader->module_close (data, handle->module);
3313       errors += unload_deplibs(handle);
3314 
3315       /* It is up to the callers to free the data itself.  */
3316       LT_DLFREE (handle->caller_data);
3317 
3318       LT_DLFREE (handle->info.filename);
3319       LT_DLFREE (handle->info.name);
3320       LT_DLFREE (handle);
3321 
3322       goto done;
3323     }
3324 
3325   if (LT_DLIS_RESIDENT (handle))
3326     {
3327       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CLOSE_RESIDENT_MODULE));
3328       ++errors;
3329     }
3330 
3331  done:
3332   LT_DLMUTEX_UNLOCK ();
3333 
3334   return errors;
3335 }
3336 
3337 lt_ptr
lt_dlsym(handle,symbol)3338 lt_dlsym (handle, symbol)
3339      lt_dlhandle handle;
3340      const char *symbol;
3341 {
3342   size_t lensym;
3343   char	lsym[LT_SYMBOL_LENGTH];
3344   char	*sym;
3345   lt_ptr address;
3346   lt_user_data data;
3347 
3348   if (!handle)
3349     {
3350       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
3351       return 0;
3352     }
3353 
3354   if (!symbol)
3355     {
3356       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND));
3357       return 0;
3358     }
3359 
3360   lensym = LT_STRLEN (symbol) + LT_STRLEN (handle->loader->sym_prefix)
3361 					+ LT_STRLEN (handle->info.name);
3362 
3363   if (lensym + LT_SYMBOL_OVERHEAD < LT_SYMBOL_LENGTH)
3364     {
3365       sym = lsym;
3366     }
3367   else
3368     {
3369       sym = LT_EMALLOC (char, lensym + LT_SYMBOL_OVERHEAD + 1);
3370       if (!sym)
3371 	{
3372 	  LT_DLMUTEX_SETERROR (LT_DLSTRERROR (BUFFER_OVERFLOW));
3373 	  return 0;
3374 	}
3375     }
3376 
3377   data = handle->loader->dlloader_data;
3378   if (handle->info.name)
3379     {
3380       const char *saved_error;
3381 
3382       LT_DLMUTEX_GETERROR (saved_error);
3383 
3384       /* this is a libtool module */
3385       if (handle->loader->sym_prefix)
3386 	{
3387 	  strcpy(sym, handle->loader->sym_prefix);
3388 	  strcat(sym, handle->info.name);
3389 	}
3390       else
3391 	{
3392 	  strcpy(sym, handle->info.name);
3393 	}
3394 
3395       strcat(sym, "_LTX_");
3396       strcat(sym, symbol);
3397 
3398       /* try "modulename_LTX_symbol" */
3399       address = handle->loader->find_sym (data, handle->module, sym);
3400       if (address)
3401 	{
3402 	  if (sym != lsym)
3403 	    {
3404 	      LT_DLFREE (sym);
3405 	    }
3406 	  return address;
3407 	}
3408       LT_DLMUTEX_SETERROR (saved_error);
3409     }
3410 
3411   /* otherwise try "symbol" */
3412   if (handle->loader->sym_prefix)
3413     {
3414       strcpy(sym, handle->loader->sym_prefix);
3415       strcat(sym, symbol);
3416     }
3417   else
3418     {
3419       strcpy(sym, symbol);
3420     }
3421 
3422   address = handle->loader->find_sym (data, handle->module, sym);
3423   if (sym != lsym)
3424     {
3425       LT_DLFREE (sym);
3426     }
3427 
3428   return address;
3429 }
3430 
3431 const char *
lt_dlerror()3432 lt_dlerror ()
3433 {
3434   const char *error;
3435 
3436   LT_DLMUTEX_GETERROR (error);
3437   LT_DLMUTEX_SETERROR (0);
3438 
3439   return error ? error : LT_DLSTRERROR (UNKNOWN);
3440 }
3441 
3442 static int
lt_dlpath_insertdir(ppath,before,dir)3443 lt_dlpath_insertdir (ppath, before, dir)
3444      char **ppath;
3445      char *before;
3446      const char *dir;
3447 {
3448   int    errors		= 0;
3449   char  *canonical	= NULL;
3450   char  *argz		= NULL;
3451   size_t argz_len	= 0;
3452 
3453   assert (ppath);
3454   assert (dir && *dir);
3455 
3456   if (canonicalize_path (dir, &canonical) != 0)
3457     {
3458       ++errors;
3459       goto cleanup;
3460     }
3461 
3462   assert (canonical && *canonical);
3463 
3464   /* If *PPATH is empty, set it to DIR.  */
3465   if (*ppath == NULL)
3466     {
3467       assert (!before);		/* BEFORE cannot be set without PPATH.  */
3468       assert (dir);		/* Without DIR, don't call this function!  */
3469 
3470       *ppath = lt_estrdup (dir);
3471       if (*ppath == NULL)
3472 	++errors;
3473 
3474       return errors;
3475     }
3476 
3477   assert (ppath && *ppath);
3478 
3479   if (argzize_path (*ppath, &argz, &argz_len) != 0)
3480     {
3481       ++errors;
3482       goto cleanup;
3483     }
3484 
3485   /* Convert BEFORE into an equivalent offset into ARGZ.  This only works
3486      if *PPATH is already canonicalized, and hence does not change length
3487      with respect to ARGZ.  We canonicalize each entry as it is added to
3488      the search path, and don't call this function with (uncanonicalized)
3489      user paths, so this is a fair assumption.  */
3490   if (before)
3491     {
3492       assert (*ppath <= before);
3493       assert (before - *ppath <= strlen (*ppath));
3494 
3495       before = before - *ppath + argz;
3496     }
3497 
3498   if (lt_argz_insert (&argz, &argz_len, before, dir) != 0)
3499     {
3500       ++errors;
3501       goto cleanup;
3502     }
3503 
3504   argz_stringify (argz, argz_len, LT_PATHSEP_CHAR);
3505   LT_DLMEM_REASSIGN (*ppath,  argz);
3506 
3507  cleanup:
3508   LT_DLFREE (canonical);
3509   LT_DLFREE (argz);
3510 
3511   return errors;
3512 }
3513 
3514 int
lt_dladdsearchdir(search_dir)3515 lt_dladdsearchdir (search_dir)
3516      const char *search_dir;
3517 {
3518   int errors = 0;
3519 
3520   if (search_dir && *search_dir)
3521     {
3522       LT_DLMUTEX_LOCK ();
3523       if (lt_dlpath_insertdir (&user_search_path, 0, search_dir) != 0)
3524 	++errors;
3525       LT_DLMUTEX_UNLOCK ();
3526     }
3527 
3528   return errors;
3529 }
3530 
3531 int
lt_dlinsertsearchdir(before,search_dir)3532 lt_dlinsertsearchdir (before, search_dir)
3533      const char *before;
3534      const char *search_dir;
3535 {
3536   int errors = 0;
3537 
3538   if (before)
3539     {
3540       LT_DLMUTEX_LOCK ();
3541       if ((before < user_search_path)
3542 	  || (before >= user_search_path + LT_STRLEN (user_search_path)))
3543 	{
3544 	  LT_DLMUTEX_UNLOCK ();
3545 	  LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_POSITION));
3546 	  return 1;
3547 	}
3548       LT_DLMUTEX_UNLOCK ();
3549     }
3550 
3551   if (search_dir && *search_dir)
3552     {
3553       LT_DLMUTEX_LOCK ();
3554       if (lt_dlpath_insertdir (&user_search_path,
3555 			       (char *) before, search_dir) != 0)
3556 	{
3557 	  ++errors;
3558 	}
3559       LT_DLMUTEX_UNLOCK ();
3560     }
3561 
3562   return errors;
3563 }
3564 
3565 int
lt_dlsetsearchpath(search_path)3566 lt_dlsetsearchpath (search_path)
3567      const char *search_path;
3568 {
3569   int   errors	    = 0;
3570 
3571   LT_DLMUTEX_LOCK ();
3572   LT_DLFREE (user_search_path);
3573   LT_DLMUTEX_UNLOCK ();
3574 
3575   if (!search_path || !LT_STRLEN (search_path))
3576     {
3577       return errors;
3578     }
3579 
3580   LT_DLMUTEX_LOCK ();
3581   if (canonicalize_path (search_path, &user_search_path) != 0)
3582     ++errors;
3583   LT_DLMUTEX_UNLOCK ();
3584 
3585   return errors;
3586 }
3587 
3588 const char *
lt_dlgetsearchpath()3589 lt_dlgetsearchpath ()
3590 {
3591   const char *saved_path;
3592 
3593   LT_DLMUTEX_LOCK ();
3594   saved_path = user_search_path;
3595   LT_DLMUTEX_UNLOCK ();
3596 
3597   return saved_path;
3598 }
3599 
3600 int
lt_dlmakeresident(handle)3601 lt_dlmakeresident (handle)
3602      lt_dlhandle handle;
3603 {
3604   int errors = 0;
3605 
3606   if (!handle)
3607     {
3608       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
3609       ++errors;
3610     }
3611   else
3612     {
3613       LT_DLSET_FLAG (handle, LT_DLRESIDENT_FLAG);
3614     }
3615 
3616   return errors;
3617 }
3618 
3619 int
lt_dlisresident(handle)3620 lt_dlisresident	(handle)
3621      lt_dlhandle handle;
3622 {
3623   if (!handle)
3624     {
3625       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
3626       return -1;
3627     }
3628 
3629   return LT_DLIS_RESIDENT (handle);
3630 }
3631 
3632 
3633 
3634 
3635 /* --- MODULE INFORMATION --- */
3636 
3637 const lt_dlinfo *
lt_dlgetinfo(handle)3638 lt_dlgetinfo (handle)
3639      lt_dlhandle handle;
3640 {
3641   if (!handle)
3642     {
3643       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE));
3644       return 0;
3645     }
3646 
3647   return &(handle->info);
3648 }
3649 
3650 lt_dlhandle
lt_dlhandle_next(place)3651 lt_dlhandle_next (place)
3652      lt_dlhandle place;
3653 {
3654   return place ? place->next : handles;
3655 }
3656 
3657 int
3658 lt_dlforeach (func, data)
3659      int (*func) LT_PARAMS((lt_dlhandle handle, lt_ptr data));
3660      lt_ptr data;
3661 {
3662   int errors = 0;
3663   lt_dlhandle cur;
3664 
3665   LT_DLMUTEX_LOCK ();
3666 
3667   cur = handles;
3668   while (cur)
3669     {
3670       lt_dlhandle tmp = cur;
3671 
3672       cur = cur->next;
3673       if ((*func) (tmp, data))
3674 	{
3675 	  ++errors;
3676 	  break;
3677 	}
3678     }
3679 
3680   LT_DLMUTEX_UNLOCK ();
3681 
3682   return errors;
3683 }
3684 
3685 lt_dlcaller_id
lt_dlcaller_register()3686 lt_dlcaller_register ()
3687 {
3688   static lt_dlcaller_id last_caller_id = 0;
3689   int result;
3690 
3691   LT_DLMUTEX_LOCK ();
3692   result = ++last_caller_id;
3693   LT_DLMUTEX_UNLOCK ();
3694 
3695   return result;
3696 }
3697 
3698 lt_ptr
lt_dlcaller_set_data(key,handle,data)3699 lt_dlcaller_set_data (key, handle, data)
3700      lt_dlcaller_id key;
3701      lt_dlhandle handle;
3702      lt_ptr data;
3703 {
3704   int n_elements = 0;
3705   lt_ptr stale = NULL;
3706   int i;
3707 
3708   /* This needs to be locked so that the caller data can be updated
3709      simultaneously by different threads.  */
3710   LT_DLMUTEX_LOCK ();
3711 
3712   if (handle->caller_data)
3713     while (handle->caller_data[n_elements].key)
3714       ++n_elements;
3715 
3716   for (i = 0; i < n_elements; ++i)
3717     {
3718       if (handle->caller_data[i].key == key)
3719 	{
3720 	  stale = handle->caller_data[i].data;
3721 	  break;
3722 	}
3723     }
3724 
3725   /* Ensure that there is enough room in this handle's caller_data
3726      array to accept a new element (and an empty end marker).  */
3727   if (i == n_elements)
3728     {
3729       lt_caller_data *temp
3730 	= LT_DLREALLOC (lt_caller_data, handle->caller_data, 2+ n_elements);
3731 
3732       if (!temp)
3733 	{
3734 	  stale = NULL;
3735 	  goto done;
3736 	}
3737 
3738       handle->caller_data = temp;
3739 
3740       /* We only need this if we needed to allocate a new caller_data.  */
3741       handle->caller_data[i].key  = key;
3742       handle->caller_data[1+ i].key = 0;
3743     }
3744 
3745   handle->caller_data[i].data = data;
3746 
3747  done:
3748   LT_DLMUTEX_UNLOCK ();
3749 
3750   return stale;
3751 }
3752 
3753 lt_ptr
lt_dlcaller_get_data(key,handle)3754 lt_dlcaller_get_data  (key, handle)
3755      lt_dlcaller_id key;
3756      lt_dlhandle handle;
3757 {
3758   lt_ptr result = (lt_ptr) 0;
3759 
3760   /* This needs to be locked so that the caller data isn't updated by
3761      another thread part way through this function.  */
3762   LT_DLMUTEX_LOCK ();
3763 
3764   /* Locate the index of the element with a matching KEY.  */
3765   {
3766     int i;
3767     for (i = 0; handle->caller_data[i].key; ++i)
3768       {
3769 	if (handle->caller_data[i].key == key)
3770 	  {
3771 	    result = handle->caller_data[i].data;
3772 	    break;
3773 	  }
3774       }
3775   }
3776 
3777   LT_DLMUTEX_UNLOCK ();
3778 
3779   return result;
3780 }
3781 
3782 
3783 
3784 /* --- USER MODULE LOADER API --- */
3785 
3786 
3787 int
lt_dlloader_add(place,dlloader,loader_name)3788 lt_dlloader_add (place, dlloader, loader_name)
3789      lt_dlloader *place;
3790      const struct lt_user_dlloader *dlloader;
3791      const char *loader_name;
3792 {
3793   int errors = 0;
3794   lt_dlloader *node = NULL, *ptr = NULL;
3795 
3796   if ((dlloader == NULL)	/* diagnose null parameters */
3797       || (dlloader->module_open == NULL)
3798       || (dlloader->module_close == NULL)
3799       || (dlloader->find_sym == NULL))
3800     {
3801       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
3802       return 1;
3803     }
3804 
3805   /* Create a new dlloader node with copies of the user callbacks.  */
3806   node = LT_EMALLOC (lt_dlloader, 1);
3807   if (!node)
3808     return 1;
3809 
3810   node->next		= NULL;
3811   node->loader_name	= loader_name;
3812   node->sym_prefix	= dlloader->sym_prefix;
3813   node->dlloader_exit	= dlloader->dlloader_exit;
3814   node->module_open	= dlloader->module_open;
3815   node->module_close	= dlloader->module_close;
3816   node->find_sym	= dlloader->find_sym;
3817   node->dlloader_data	= dlloader->dlloader_data;
3818 
3819   LT_DLMUTEX_LOCK ();
3820   if (!loaders)
3821     {
3822       /* If there are no loaders, NODE becomes the list! */
3823       loaders = node;
3824     }
3825   else if (!place)
3826     {
3827       /* If PLACE is not set, add NODE to the end of the
3828 	 LOADERS list. */
3829       for (ptr = loaders; ptr->next; ptr = ptr->next)
3830 	{
3831 	  /*NOWORK*/;
3832 	}
3833 
3834       ptr->next = node;
3835     }
3836   else if (loaders == place)
3837     {
3838       /* If PLACE is the first loader, NODE goes first. */
3839       node->next = place;
3840       loaders = node;
3841     }
3842   else
3843     {
3844       /* Find the node immediately preceding PLACE. */
3845       for (ptr = loaders; ptr->next != place; ptr = ptr->next)
3846 	{
3847 	  /*NOWORK*/;
3848 	}
3849 
3850       if (ptr->next != place)
3851 	{
3852 	  LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
3853 	  ++errors;
3854 	}
3855       else
3856 	{
3857 	  /* Insert NODE between PTR and PLACE. */
3858 	  node->next = place;
3859 	  ptr->next  = node;
3860 	}
3861     }
3862 
3863   LT_DLMUTEX_UNLOCK ();
3864 
3865   return errors;
3866 }
3867 
3868 int
lt_dlloader_remove(loader_name)3869 lt_dlloader_remove (loader_name)
3870      const char *loader_name;
3871 {
3872   lt_dlloader *place = lt_dlloader_find (loader_name);
3873   lt_dlhandle handle;
3874   int errors = 0;
3875 
3876   if (!place)
3877     {
3878       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
3879       return 1;
3880     }
3881 
3882   LT_DLMUTEX_LOCK ();
3883 
3884   /* Fail if there are any open modules which use this loader. */
3885   for  (handle = handles; handle; handle = handle->next)
3886     {
3887       if (handle->loader == place)
3888 	{
3889 	  LT_DLMUTEX_SETERROR (LT_DLSTRERROR (REMOVE_LOADER));
3890 	  ++errors;
3891 	  goto done;
3892 	}
3893     }
3894 
3895   if (place == loaders)
3896     {
3897       /* PLACE is the first loader in the list. */
3898       loaders = loaders->next;
3899     }
3900   else
3901     {
3902       /* Find the loader before the one being removed. */
3903       lt_dlloader *prev;
3904       for (prev = loaders; prev->next; prev = prev->next)
3905 	{
3906 	  if (!strcmp (prev->next->loader_name, loader_name))
3907 	    {
3908 	      break;
3909 	    }
3910 	}
3911 
3912       place = prev->next;
3913       prev->next = prev->next->next;
3914     }
3915 
3916   if (place->dlloader_exit)
3917     {
3918       errors = place->dlloader_exit (place->dlloader_data);
3919     }
3920 
3921   LT_DLFREE (place);
3922 
3923  done:
3924   LT_DLMUTEX_UNLOCK ();
3925 
3926   return errors;
3927 }
3928 
3929 lt_dlloader *
lt_dlloader_next(place)3930 lt_dlloader_next (place)
3931      lt_dlloader *place;
3932 {
3933   lt_dlloader *next;
3934 
3935   LT_DLMUTEX_LOCK ();
3936   next = place ? place->next : loaders;
3937   LT_DLMUTEX_UNLOCK ();
3938 
3939   return next;
3940 }
3941 
3942 const char *
lt_dlloader_name(place)3943 lt_dlloader_name (place)
3944      lt_dlloader *place;
3945 {
3946   const char *name = NULL;
3947 
3948   if (place)
3949     {
3950       LT_DLMUTEX_LOCK ();
3951       name = place ? place->loader_name : 0;
3952       LT_DLMUTEX_UNLOCK ();
3953     }
3954   else
3955     {
3956       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
3957     }
3958 
3959   return name;
3960 }
3961 
3962 lt_user_data *
lt_dlloader_data(place)3963 lt_dlloader_data (place)
3964      lt_dlloader *place;
3965 {
3966   lt_user_data *data = NULL;
3967 
3968   if (place)
3969     {
3970       LT_DLMUTEX_LOCK ();
3971       data = place ? &(place->dlloader_data) : 0;
3972       LT_DLMUTEX_UNLOCK ();
3973     }
3974   else
3975     {
3976       LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER));
3977     }
3978 
3979   return data;
3980 }
3981 
3982 lt_dlloader *
lt_dlloader_find(loader_name)3983 lt_dlloader_find (loader_name)
3984      const char *loader_name;
3985 {
3986   lt_dlloader *place = NULL;
3987 
3988   LT_DLMUTEX_LOCK ();
3989   for (place = loaders; place; place = place->next)
3990     {
3991       if (strcmp (place->loader_name, loader_name) == 0)
3992 	{
3993 	  break;
3994 	}
3995     }
3996   LT_DLMUTEX_UNLOCK ();
3997 
3998   return place;
3999 }
4000