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