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