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