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