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