1 /* ltdl.c -- system independent dlopen wrapper
2 
3    Copyright (C) 1998, 1999, 2000, 2004, 2005, 2006,
4 		 2007, 2008, 2011 Free Software Foundation, Inc.
5    Written by Thomas Tanner, 1998
6 
7    NOTE: The canonical source of this file is maintained with the
8    GNU Libtool package.  Report bugs to bug-libtool@gnu.org.
9 
10 GNU Libltdl is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2 of the License, or (at your option) any later version.
14 
15 As a special exception to the GNU Lesser General Public License,
16 if you distribute this file as part of a program or library that
17 is built using GNU Libtool, you may include this file under the
18 same distribution terms that you use for the rest of that program.
19 
20 GNU Libltdl is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23 GNU Lesser General Public License for more details.
24 
25 You should have received a copy of the GNU Lesser General Public
26 License along with GNU Libltdl; see the file COPYING.LIB.  If not, a
27 copy can be downloaded from  http://www.gnu.org/licenses/lgpl.html,
28 or obtained by writing to the Free Software Foundation, Inc.,
29 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
30 */
31 
32 #include "lt__private.h"
33 #include "lt_system.h"
34 #include "lt_dlloader.h"
35 
36 
37 /* --- MANIFEST CONSTANTS --- */
38 
39 
40 /* Standard libltdl search path environment variable name  */
41 #undef  LTDL_SEARCHPATH_VAR
42 #define LTDL_SEARCHPATH_VAR	"LTDL_LIBRARY_PATH"
43 
44 /* Standard libtool archive file extension.  */
45 #undef  LT_ARCHIVE_EXT
46 #define LT_ARCHIVE_EXT	".la"
47 
48 /* max. filename length */
49 #if !defined(LT_FILENAME_MAX)
50 #  define LT_FILENAME_MAX	1024
51 #endif
52 
53 #if !defined(LT_LIBEXT)
54 #  define LT_LIBEXT "a"
55 #endif
56 
57 #if !defined(LT_LIBPREFIX)
58 #  define LT_LIBPREFIX "lib"
59 #endif
60 
61 /* This is the maximum symbol size that won't require malloc/free */
62 #undef	LT_SYMBOL_LENGTH
63 #define LT_SYMBOL_LENGTH	128
64 
65 /* This accounts for the _LTX_ separator */
66 #undef	LT_SYMBOL_OVERHEAD
67 #define LT_SYMBOL_OVERHEAD	5
68 
69 /* Various boolean flags can be stored in the flags field of an
70    lt_dlhandle... */
71 #define LT_DLIS_RESIDENT(handle)  ((handle)->info.is_resident)
72 #define LT_DLIS_SYMGLOBAL(handle) ((handle)->info.is_symglobal)
73 #define LT_DLIS_SYMLOCAL(handle)  ((handle)->info.is_symlocal)
74 
75 
76 static	const char	objdir[]		= LT_OBJDIR;
77 static	const char	archive_ext[]		= LT_ARCHIVE_EXT;
78 static  const char	libext[]		= LT_LIBEXT;
79 static  const char	libprefix[]		= LT_LIBPREFIX;
80 #if defined(LT_MODULE_EXT)
81 static	const char	shlib_ext[]		= LT_MODULE_EXT;
82 #endif
83 /* If the loadable module suffix is not the same as the linkable
84  * shared library suffix, this will be defined. */
85 #if defined(LT_SHARED_EXT)
86 static	const char	shared_ext[]		= LT_SHARED_EXT;
87 #endif
88 #if defined(LT_DLSEARCH_PATH)
89 static	const char	sys_dlsearch_path[]	= LT_DLSEARCH_PATH;
90 #endif
91 
92 
93 
94 
95 /* --- DYNAMIC MODULE LOADING --- */
96 
97 
98 /* The type of a function used at each iteration of  foreach_dirinpath().  */
99 typedef int	foreach_callback_func (char *filename, void *data1,
100 				       void *data2);
101 /* foreachfile_callback itself calls a function of this type: */
102 typedef int	file_worker_func      (const char *filename, void *data);
103 
104 
105 static	int	foreach_dirinpath     (const char *search_path,
106 				       const char *base_name,
107 				       foreach_callback_func *func,
108 				       void *data1, void *data2);
109 static	int	find_file_callback    (char *filename, void *data1,
110 				       void *data2);
111 static	int	find_handle_callback  (char *filename, void *data,
112 				       void *ignored);
113 static	int	foreachfile_callback  (char *filename, void *data1,
114 				       void *data2);
115 
116 
117 static	int     canonicalize_path     (const char *path, char **pcanonical);
118 static	int	argzize_path	      (const char *path,
119 				       char **pargz, size_t *pargz_len);
120 static	FILE   *find_file	      (const char *search_path,
121 				       const char *base_name, char **pdir);
122 static	lt_dlhandle *find_handle      (const char *search_path,
123 				       const char *base_name,
124 				       lt_dlhandle *handle,
125 				       lt_dladvise advise);
126 static	int	find_module	      (lt_dlhandle *handle, const char *dir,
127 				       const char *libdir, const char *dlname,
128 				       const char *old_name, int installed,
129 				       lt_dladvise advise);
130 static  int     has_library_ext       (const char *filename);
131 static	int	load_deplibs	      (lt_dlhandle handle,  char *deplibs);
132 static	int	trim		      (char **dest, const char *str);
133 static	int	try_dlopen	      (lt_dlhandle *handle,
134 				       const char *filename, const char *ext,
135 				       lt_dladvise advise);
136 static	int	tryall_dlopen	      (lt_dlhandle *handle,
137 				       const char *filename,
138 				       lt_dladvise padvise,
139 				       const lt_dlvtable *vtable);
140 static	int	unload_deplibs	      (lt_dlhandle handle);
141 static	int	lt_argz_insert	      (char **pargz, size_t *pargz_len,
142 				       char *before, const char *entry);
143 static	int	lt_argz_insertinorder (char **pargz, size_t *pargz_len,
144 				       const char *entry);
145 static	int	lt_argz_insertdir     (char **pargz, size_t *pargz_len,
146 				       const char *dirnam, struct dirent *dp);
147 static	int	lt_dlpath_insertdir   (char **ppath, char *before,
148 				       const char *dir);
149 static	int	list_files_by_dir     (const char *dirnam,
150 				       char **pargz, size_t *pargz_len);
151 static	int	file_not_found	      (void);
152 
153 #ifdef HAVE_LIBDLLOADER
154 static	int	loader_init_callback  (lt_dlhandle handle);
155 #endif /* HAVE_LIBDLLOADER */
156 
157 static	int	loader_init	      (lt_get_vtable *vtable_func,
158 				       lt_user_data data);
159 
160 static	char	       *user_search_path= 0;
161 static	lt_dlhandle	handles	= 0;
162 static	int		initialized	= 0;
163 
164 /* Our memory failure callback sets the error message to be passed back
165    up to the client, so we must be careful to return from mallocation
166    callers if allocation fails (as this callback returns!!).  */
167 void
lt__alloc_die_callback(void)168 lt__alloc_die_callback (void)
169 {
170   LT__SETERROR (NO_MEMORY);
171 }
172 
173 #ifdef HAVE_LIBDLLOADER
174 /* This function is called to initialise each preloaded module loader,
175    and hook it into the list of loaders to be used when attempting to
176    dlopen an application module.  */
177 static int
loader_init_callback(lt_dlhandle handle)178 loader_init_callback (lt_dlhandle handle)
179 {
180   lt_get_vtable *vtable_func = (lt_get_vtable *) lt_dlsym (handle, "get_vtable");
181   return loader_init (vtable_func, 0);
182 }
183 #endif /* HAVE_LIBDLLOADER */
184 
185 static int
loader_init(lt_get_vtable * vtable_func,lt_user_data data)186 loader_init (lt_get_vtable *vtable_func, lt_user_data data)
187 {
188   const lt_dlvtable *vtable = 0;
189   int errors = 0;
190 
191   if (vtable_func)
192     {
193       vtable = (*vtable_func) (data);
194     }
195 
196   /* lt_dlloader_add will LT__SETERROR if it fails.  */
197   errors += lt_dlloader_add (vtable);
198 
199   assert (errors || vtable);
200 
201   if ((!errors) && vtable->dlloader_init)
202     {
203       if ((*vtable->dlloader_init) (vtable->dlloader_data))
204 	{
205 	  LT__SETERROR (INIT_LOADER);
206 	  ++errors;
207 	}
208     }
209 
210   return errors;
211 }
212 
213 /* Bootstrap the loader loading with the preopening loader.  */
214 #define get_vtable		preopen_LTX_get_vtable
215 #define preloaded_symbols	LT_CONC3(lt_, LTDLOPEN, _LTX_preloaded_symbols)
216 
217 LT_BEGIN_C_DECLS
218 LT_SCOPE const lt_dlvtable *	get_vtable (lt_user_data data);
219 LT_END_C_DECLS
220 #ifdef HAVE_LIBDLLOADER
221 extern LT_DLSYM_CONST lt_dlsymlist preloaded_symbols[];
222 #endif
223 
224 /* Initialize libltdl. */
225 int
lt_dlinit(void)226 lt_dlinit (void)
227 {
228   int	errors	= 0;
229 
230   /* Initialize only at first call. */
231   if (++initialized == 1)
232     {
233       lt__alloc_die	= lt__alloc_die_callback;
234       handles		= 0;
235       user_search_path	= 0; /* empty search path */
236 
237       /* First set up the statically loaded preload module loader, so
238 	 we can use it to preopen the other loaders we linked in at
239 	 compile time.  */
240       errors += loader_init (get_vtable, 0);
241 
242       /* Now open all the preloaded module loaders, so the application
243 	 can use _them_ to lt_dlopen its own modules.  */
244 #ifdef HAVE_LIBDLLOADER
245       if (!errors)
246 	{
247 	  errors += lt_dlpreload (preloaded_symbols);
248 	}
249 
250       if (!errors)
251 	{
252 	  errors += lt_dlpreload_open (LT_STR(LTDLOPEN), loader_init_callback);
253 	}
254 #endif /* HAVE_LIBDLLOADER */
255     }
256 
257 #ifdef LT_DEBUG_LOADERS
258   lt_dlloader_dump();
259 #endif
260 
261   return errors;
262 }
263 
264 int
lt_dlexit(void)265 lt_dlexit (void)
266 {
267   /* shut down libltdl */
268   lt_dlloader *loader   = 0;
269   lt_dlhandle  handle   = handles;
270   int	       errors   = 0;
271 
272   if (!initialized)
273     {
274       LT__SETERROR (SHUTDOWN);
275       ++errors;
276       goto done;
277     }
278 
279   /* shut down only at last call. */
280   if (--initialized == 0)
281     {
282       int	level;
283 
284       while (handles && LT_DLIS_RESIDENT (handles))
285 	{
286 	  handles = handles->next;
287 	}
288 
289       /* close all modules */
290       for (level = 1; handle; ++level)
291 	{
292 	  lt_dlhandle cur = handles;
293 	  int saw_nonresident = 0;
294 
295 	  while (cur)
296 	    {
297 	      lt_dlhandle tmp = cur;
298 	      cur = cur->next;
299 	      if (!LT_DLIS_RESIDENT (tmp))
300 		{
301 		  saw_nonresident = 1;
302 		  if (tmp->info.ref_count <= level)
303 		    {
304 		      if (lt_dlclose (tmp))
305 			{
306 			  ++errors;
307 			}
308 		      /* Make sure that the handle pointed to by 'cur' still exists.
309 			 lt_dlclose recursively closes dependent libraries which removes
310 			 them from the linked list.  One of these might be the one
311 			 pointed to by 'cur'.  */
312 		      if (cur)
313 			{
314 			  for (tmp = handles; tmp; tmp = tmp->next)
315 			    if (tmp == cur)
316 			      break;
317 			  if (! tmp)
318 			    cur = handles;
319 			}
320 		    }
321 		}
322 	    }
323 	  /* done if only resident modules are left */
324 	  if (!saw_nonresident)
325 	    break;
326 	}
327 
328       /* When removing loaders, we can only find out failure by testing
329 	 the error string, so avoid a spurious one from an earlier
330 	 failed command. */
331       if (!errors)
332 	LT__SETERRORSTR (0);
333 
334       /* close all loaders */
335       for (loader = (lt_dlloader *) lt_dlloader_next (NULL); loader;)
336 	{
337 	  lt_dlloader *next   = (lt_dlloader *) lt_dlloader_next (loader);
338 	  lt_dlvtable *vtable = (lt_dlvtable *) lt_dlloader_get (loader);
339 
340 	  if ((vtable = lt_dlloader_remove ((char *) vtable->name)))
341 	    {
342 	      FREE (vtable);
343 	    }
344 	  else
345 	    {
346 	      /* ignore errors due to resident modules */
347 	      const char *err;
348 	      LT__GETERROR (err);
349 	      if (err)
350 		++errors;
351 	    }
352 
353 	  loader = next;
354 	}
355 
356       FREE(user_search_path);
357     }
358 
359  done:
360   return errors;
361 }
362 
363 
364 /* Try VTABLE or, if VTABLE is NULL, all available loaders for FILENAME.
365    If the library is not successfully loaded, return non-zero.  Otherwise,
366    the dlhandle is stored at the address given in PHANDLE.  */
367 static int
tryall_dlopen(lt_dlhandle * phandle,const char * filename,lt_dladvise advise,const lt_dlvtable * vtable)368 tryall_dlopen (lt_dlhandle *phandle, const char *filename,
369 	       lt_dladvise advise, const lt_dlvtable *vtable)
370 {
371   lt_dlhandle	handle		= handles;
372   const char *	saved_error	= 0;
373   int		errors		= 0;
374 
375 #ifdef LT_DEBUG_LOADERS
376   fprintf (stderr, "tryall_dlopen (%s, %s)\n",
377 	   filename ? filename : "(null)",
378 	   vtable ? vtable->name : "(ALL)");
379 #endif
380 
381   LT__GETERROR (saved_error);
382 
383   /* check whether the module was already opened */
384   for (;handle; handle = handle->next)
385     {
386       if ((handle->info.filename == filename) /* dlopen self: 0 == 0 */
387 	  || (handle->info.filename && filename
388 	      && streq (handle->info.filename, filename)))
389 	{
390 	  break;
391 	}
392     }
393 
394   if (handle)
395     {
396       ++handle->info.ref_count;
397       *phandle = handle;
398       goto done;
399     }
400 
401   handle = *phandle;
402   if (filename)
403     {
404       /* Comment out the check of file permissions using access.
405 	 This call seems to always return -1 with error EACCES.
406       */
407       /* We need to catch missing file errors early so that
408 	 file_not_found() can detect what happened.
409       if (access (filename, R_OK) != 0)
410 	{
411 	  LT__SETERROR (FILE_NOT_FOUND);
412 	  ++errors;
413 	  goto done;
414 	} */
415 
416       handle->info.filename = lt__strdup (filename);
417       if (!handle->info.filename)
418 	{
419 	  ++errors;
420 	  goto done;
421 	}
422     }
423   else
424     {
425       handle->info.filename = 0;
426     }
427 
428   {
429     lt_dlloader loader = lt_dlloader_next (0);
430     const lt_dlvtable *loader_vtable;
431 
432     do
433       {
434 	if (vtable)
435 	  loader_vtable = vtable;
436 	else
437 	  loader_vtable = lt_dlloader_get (loader);
438 
439 #ifdef LT_DEBUG_LOADERS
440 	fprintf (stderr, "Calling %s->module_open (%s)\n",
441 		 (loader_vtable && loader_vtable->name) ? loader_vtable->name : "(null)",
442 		 filename ? filename : "(null)");
443 #endif
444 	handle->module = (*loader_vtable->module_open) (loader_vtable->dlloader_data,
445 							filename, advise);
446 #ifdef LT_DEBUG_LOADERS
447 	fprintf (stderr, "  Result: %s\n",
448 		 handle->module ? "Success" : "Failed");
449 #endif
450 
451 	if (handle->module != 0)
452 	  {
453 	    if (advise)
454 	      {
455 		handle->info.is_resident  = advise->is_resident;
456 		handle->info.is_symglobal = advise->is_symglobal;
457 		handle->info.is_symlocal  = advise->is_symlocal;
458 	      }
459 	    break;
460 	  }
461       }
462     while (!vtable && (loader = lt_dlloader_next (loader)));
463 
464     /* If VTABLE was given but couldn't open the module, or VTABLE wasn't
465        given but we exhausted all loaders without opening the module, bail
466        out!  */
467     if ((vtable && !handle->module)
468 	|| (!vtable && !loader))
469       {
470 	FREE (handle->info.filename);
471 	++errors;
472 	goto done;
473       }
474 
475     handle->vtable = loader_vtable;
476   }
477 
478   LT__SETERRORSTR (saved_error);
479 
480  done:
481   return errors;
482 }
483 
484 
485 static int
tryall_dlopen_module(lt_dlhandle * handle,const char * prefix,const char * dirname,const char * dlname,lt_dladvise advise)486 tryall_dlopen_module (lt_dlhandle *handle, const char *prefix,
487 		      const char *dirname, const char *dlname,
488 		      lt_dladvise advise)
489 {
490   int      error	= 0;
491   char     *filename	= 0;
492   size_t   filename_len	= 0;
493   size_t   dirname_len	= LT_STRLEN (dirname);
494 
495   assert (handle);
496   assert (dirname);
497   assert (dlname);
498 #if defined(LT_DIRSEP_CHAR)
499   /* Only canonicalized names (i.e. with DIRSEP chars already converted)
500      should make it into this function:  */
501   assert (strchr (dirname, LT_DIRSEP_CHAR) == 0);
502 #endif
503 
504   if (dirname_len > 0)
505     if (dirname[dirname_len -1] == '/')
506       --dirname_len;
507   filename_len = dirname_len + 1 + LT_STRLEN (dlname);
508 
509   /* Allocate memory, and combine DIRNAME and MODULENAME into it.
510      The PREFIX (if any) is handled below.  */
511   filename  = MALLOC (char, filename_len + 1);
512   if (!filename)
513     return 1;
514 
515   sprintf (filename, "%.*s/%s", (int) dirname_len, dirname, dlname);
516 
517   /* Now that we have combined DIRNAME and MODULENAME, if there is
518      also a PREFIX to contend with, simply recurse with the arguments
519      shuffled.  Otherwise, attempt to open FILENAME as a module.  */
520   if (prefix)
521     {
522       error += tryall_dlopen_module (handle, (const char *) 0,
523 				     prefix, filename, advise);
524     }
525   else if (tryall_dlopen (handle, filename, advise, 0) != 0)
526     {
527       ++error;
528     }
529 
530   FREE (filename);
531   return error;
532 }
533 
534 static int
find_module(lt_dlhandle * handle,const char * dir,const char * libdir,const char * dlname,const char * old_name,int installed,lt_dladvise advise)535 find_module (lt_dlhandle *handle, const char *dir, const char *libdir,
536 	     const char *dlname,  const char *old_name, int installed,
537 	     lt_dladvise advise)
538 {
539   /* Try to open the old library first; if it was dlpreopened,
540      we want the preopened version of it, even if a dlopenable
541      module is available.  */
542   if (old_name && tryall_dlopen (handle, old_name,
543 			  advise, lt_dlloader_find ("lt_preopen") ) == 0)
544     {
545       return 0;
546     }
547 
548   /* Try to open the dynamic library.  */
549   if (dlname)
550     {
551       /* try to open the installed module */
552       if (installed && libdir)
553 	{
554 	  if (tryall_dlopen_module (handle, (const char *) 0,
555 				    libdir, dlname, advise) == 0)
556 	    return 0;
557 	}
558 
559       /* try to open the not-installed module */
560       if (!installed)
561 	{
562 	  if (tryall_dlopen_module (handle, dir, objdir,
563 				    dlname, advise) == 0)
564 	    return 0;
565 	}
566 
567       /* maybe it was moved to another directory */
568       {
569 	  if (dir && (tryall_dlopen_module (handle, (const char *) 0,
570 					    dir, dlname, advise) == 0))
571 	    return 0;
572       }
573     }
574 
575   return 1;
576 }
577 
578 
579 static int
canonicalize_path(const char * path,char ** pcanonical)580 canonicalize_path (const char *path, char **pcanonical)
581 {
582   char *canonical = 0;
583 
584   assert (path && *path);
585   assert (pcanonical);
586 
587   canonical = MALLOC (char, 1+ LT_STRLEN (path));
588   if (!canonical)
589     return 1;
590 
591   {
592     size_t dest = 0;
593     size_t src;
594     for (src = 0; path[src] != LT_EOS_CHAR; ++src)
595       {
596 	/* Path separators are not copied to the beginning or end of
597 	   the destination, or if another separator would follow
598 	   immediately.  */
599 	if (path[src] == LT_PATHSEP_CHAR)
600 	  {
601 	    if ((dest == 0)
602 		|| (path[1+ src] == LT_PATHSEP_CHAR)
603 		|| (path[1+ src] == LT_EOS_CHAR))
604 	      continue;
605 	  }
606 
607 	/* Anything other than a directory separator is copied verbatim.  */
608 	if ((path[src] != '/')
609 #if defined(LT_DIRSEP_CHAR)
610 	    && (path[src] != LT_DIRSEP_CHAR)
611 #endif
612 	    )
613 	  {
614 	    canonical[dest++] = path[src];
615 	  }
616 	/* Directory separators are converted and copied only if they are
617 	   not at the end of a path -- i.e. before a path separator or
618 	   NULL terminator.  */
619 	else if ((path[1+ src] != LT_PATHSEP_CHAR)
620 		 && (path[1+ src] != LT_EOS_CHAR)
621 #if defined(LT_DIRSEP_CHAR)
622 		 && (path[1+ src] != LT_DIRSEP_CHAR)
623 #endif
624 		 && (path[1+ src] != '/'))
625 	  {
626 	    canonical[dest++] = '/';
627 	  }
628       }
629 
630     /* Add an end-of-string marker at the end.  */
631     canonical[dest] = LT_EOS_CHAR;
632   }
633 
634   /* Assign new value.  */
635   *pcanonical = canonical;
636 
637   return 0;
638 }
639 
640 static int
argzize_path(const char * path,char ** pargz,size_t * pargz_len)641 argzize_path (const char *path, char **pargz, size_t *pargz_len)
642 {
643   error_t error;
644 
645   assert (path);
646   assert (pargz);
647   assert (pargz_len);
648 
649   if ((error = argz_create_sep (path, LT_PATHSEP_CHAR, pargz, pargz_len)))
650     {
651       switch (error)
652 	{
653 	case ENOMEM:
654 	  LT__SETERROR (NO_MEMORY);
655 	  break;
656 	default:
657 	  LT__SETERROR (UNKNOWN);
658 	  break;
659 	}
660 
661       return 1;
662     }
663 
664   return 0;
665 }
666 
667 /* Repeatedly call FUNC with each LT_PATHSEP_CHAR delimited element
668    of SEARCH_PATH and references to DATA1 and DATA2, until FUNC returns
669    non-zero or all elements are exhausted.  If BASE_NAME is non-NULL,
670    it is appended to each SEARCH_PATH element before FUNC is called.  */
671 static int
foreach_dirinpath(const char * search_path,const char * base_name,foreach_callback_func * func,void * data1,void * data2)672 foreach_dirinpath (const char *search_path, const char *base_name,
673 		   foreach_callback_func *func, void *data1, void *data2)
674 {
675   int	 result		= 0;
676   size_t filenamesize	= 0;
677   size_t lenbase	= LT_STRLEN (base_name);
678   size_t argz_len	= 0;
679   char *argz		= 0;
680   char *filename	= 0;
681   char *canonical	= 0;
682 
683   if (!search_path || !*search_path)
684     {
685       LT__SETERROR (FILE_NOT_FOUND);
686       goto cleanup;
687     }
688 
689   if (canonicalize_path (search_path, &canonical) != 0)
690     goto cleanup;
691 
692   if (argzize_path (canonical, &argz, &argz_len) != 0)
693     goto cleanup;
694 
695   {
696     char *dir_name = 0;
697     while ((dir_name = argz_next (argz, argz_len, dir_name)))
698       {
699 	size_t lendir = LT_STRLEN (dir_name);
700 
701 	if (1+ lendir + lenbase >= filenamesize)
702 	{
703 	  FREE (filename);
704 	  filenamesize	= 1+ lendir + 1+ lenbase; /* "/d" + '/' + "f" + '\0' */
705 	  filename	= MALLOC (char, filenamesize);
706 	  if (!filename)
707 	    goto cleanup;
708 	}
709 
710 	assert (filenamesize > lendir);
711 	strcpy (filename, dir_name);
712 
713 	if (base_name && *base_name)
714 	  {
715 	    if (filename[lendir -1] != '/')
716 	      filename[lendir++] = '/';
717 	    strcpy (filename +lendir, base_name);
718 	  }
719 
720 	if ((result = (*func) (filename, data1, data2)))
721 	  {
722 	    break;
723 	  }
724       }
725   }
726 
727  cleanup:
728   FREE (argz);
729   FREE (canonical);
730   FREE (filename);
731 
732   return result;
733 }
734 
735 /* If FILEPATH can be opened, store the name of the directory component
736    in DATA1, and the opened FILE* structure address in DATA2.  Otherwise
737    DATA1 is unchanged, but DATA2 is set to a pointer to NULL.  */
738 static int
find_file_callback(char * filename,void * data1,void * data2)739 find_file_callback (char *filename, void *data1, void *data2)
740 {
741   char	     **pdir	= (char **) data1;
742   FILE	     **pfile	= (FILE **) data2;
743   int	     is_done	= 0;
744 
745   assert (filename && *filename);
746   assert (pdir);
747   assert (pfile);
748 
749   if ((*pfile = fopen (filename, LT_READTEXT_MODE)))
750     {
751       char *dirend = strrchr (filename, '/');
752 
753       if (dirend > filename)
754 	*dirend   = LT_EOS_CHAR;
755 
756       FREE (*pdir);
757       *pdir   = lt__strdup (filename);
758       is_done = (*pdir == 0) ? -1 : 1;
759     }
760 
761   return is_done;
762 }
763 
764 static FILE *
find_file(const char * search_path,const char * base_name,char ** pdir)765 find_file (const char *search_path, const char *base_name, char **pdir)
766 {
767   FILE *file = 0;
768 
769   foreach_dirinpath (search_path, base_name, find_file_callback, pdir, &file);
770 
771   return file;
772 }
773 
774 static int
find_handle_callback(char * filename,void * data,void * data2)775 find_handle_callback (char *filename, void *data, void *data2)
776 {
777   lt_dlhandle  *phandle		= (lt_dlhandle *) data;
778   int		notfound	= access (filename, R_OK);
779   lt_dladvise   advise		= (lt_dladvise) data2;
780 
781   /* Bail out if file cannot be read...  */
782   if (notfound)
783     return 0;
784 
785   /* Try to dlopen the file, but do not continue searching in any
786      case.  */
787   if (tryall_dlopen (phandle, filename, advise, 0) != 0)
788     *phandle = 0;
789 
790   return 1;
791 }
792 
793 /* If HANDLE was found return it, otherwise return 0.  If HANDLE was
794    found but could not be opened, *HANDLE will be set to 0.  */
795 static lt_dlhandle *
find_handle(const char * search_path,const char * base_name,lt_dlhandle * phandle,lt_dladvise advise)796 find_handle (const char *search_path, const char *base_name,
797 	     lt_dlhandle *phandle, lt_dladvise advise)
798 {
799   if (!search_path)
800     return 0;
801 
802   if (!foreach_dirinpath (search_path, base_name, find_handle_callback,
803 			  phandle, advise))
804     return 0;
805 
806   return phandle;
807 }
808 
809 #if !defined(LTDL_DLOPEN_DEPLIBS)
810 static int
load_deplibs(lt_dlhandle handle,char * LT__UNUSED deplibs)811 load_deplibs (lt_dlhandle handle, char * LT__UNUSED deplibs)
812 {
813   handle->depcount = 0;
814   return 0;
815 }
816 
817 #else /* defined(LTDL_DLOPEN_DEPLIBS) */
818 static int
load_deplibs(lt_dlhandle handle,char * deplibs)819 load_deplibs (lt_dlhandle handle, char *deplibs)
820 {
821   char	*p, *save_search_path = 0;
822   int   depcount = 0;
823   int	i;
824   char	**names = 0;
825   int	errors = 0;
826 
827   handle->depcount = 0;
828 
829   if (!deplibs)
830     {
831       return errors;
832     }
833   ++errors;
834 
835   if (user_search_path)
836     {
837       save_search_path = lt__strdup (user_search_path);
838       if (!save_search_path)
839 	goto cleanup;
840     }
841 
842   /* extract search paths and count deplibs */
843   p = deplibs;
844   while (*p)
845     {
846       if (!isspace ((unsigned char) *p))
847 	{
848 	  char *end = p+1;
849 	  while (*end && !isspace((unsigned char) *end))
850 	    {
851 	      ++end;
852 	    }
853 
854 	  if (strncmp(p, "-L", 2) == 0 || strncmp(p, "-R", 2) == 0)
855 	    {
856 	      char save = *end;
857 	      *end = 0; /* set a temporary string terminator */
858 	      if (lt_dladdsearchdir(p+2))
859 		{
860 		  goto cleanup;
861 		}
862 	      *end = save;
863 	    }
864 	  else
865 	    {
866 	      ++depcount;
867 	    }
868 
869 	  p = end;
870 	}
871       else
872 	{
873 	  ++p;
874 	}
875     }
876 
877 
878   if (!depcount)
879     {
880       errors = 0;
881       goto cleanup;
882     }
883 
884   names = MALLOC (char *, depcount);
885   if (!names)
886     goto cleanup;
887 
888   /* now only extract the actual deplibs */
889   depcount = 0;
890   p = deplibs;
891   while (*p)
892     {
893       if (isspace ((unsigned char) *p))
894 	{
895 	  ++p;
896 	}
897       else
898 	{
899 	  char *end = p+1;
900 	  while (*end && !isspace ((unsigned char) *end))
901 	    {
902 	      ++end;
903 	    }
904 
905 	  if (strncmp(p, "-L", 2) != 0 && strncmp(p, "-R", 2) != 0)
906 	    {
907 	      char *name;
908 	      char save = *end;
909 	      *end = 0; /* set a temporary string terminator */
910 	      if (strncmp(p, "-l", 2) == 0)
911 		{
912 		  size_t name_len = 3+ /* "lib" */ LT_STRLEN (p + 2);
913 		  name = MALLOC (char, 1+ name_len);
914 		  if (name)
915 		    sprintf (name, "lib%s", p+2);
916 		}
917 	      else
918 		name = lt__strdup(p);
919 
920 	      if (!name)
921 		goto cleanup_names;
922 
923 	      names[depcount++] = name;
924 	      *end = save;
925 	    }
926 	  p = end;
927 	}
928     }
929 
930   /* load the deplibs (in reverse order)
931      At this stage, don't worry if the deplibs do not load correctly,
932      they may already be statically linked into the loading application
933      for instance.  There will be a more enlightening error message
934      later on if the loaded module cannot resolve all of its symbols.  */
935   if (depcount)
936     {
937       lt_dlhandle cur = handle;
938       int	j = 0;
939 
940       cur->deplibs = MALLOC (lt_dlhandle, depcount);
941       if (!cur->deplibs)
942 	goto cleanup_names;
943 
944       for (i = 0; i < depcount; ++i)
945 	{
946 	  cur->deplibs[j] = lt_dlopenext(names[depcount-1-i]);
947 	  if (cur->deplibs[j])
948 	    {
949 	      ++j;
950 	    }
951 	}
952 
953       cur->depcount	= j;	/* Number of successfully loaded deplibs */
954       errors		= 0;
955     }
956 
957  cleanup_names:
958   for (i = 0; i < depcount; ++i)
959     {
960       FREE (names[i]);
961     }
962 
963  cleanup:
964   FREE (names);
965   /* restore the old search path */
966   if (save_search_path) {
967     MEMREASSIGN (user_search_path, save_search_path);
968   }
969 
970   return errors;
971 }
972 #endif /* defined(LTDL_DLOPEN_DEPLIBS) */
973 
974 static int
unload_deplibs(lt_dlhandle handle)975 unload_deplibs (lt_dlhandle handle)
976 {
977   int i;
978   int errors = 0;
979   lt_dlhandle cur = handle;
980 
981   if (cur->depcount)
982     {
983       for (i = 0; i < cur->depcount; ++i)
984 	{
985 	  if (!LT_DLIS_RESIDENT (cur->deplibs[i]))
986 	    {
987 	      errors += lt_dlclose (cur->deplibs[i]);
988 	    }
989 	}
990       FREE (cur->deplibs);
991     }
992 
993   return errors;
994 }
995 
996 static int
trim(char ** dest,const char * str)997 trim (char **dest, const char *str)
998 {
999   /* remove the leading and trailing "'" from str
1000      and store the result in dest */
1001   const char *end   = strrchr (str, '\'');
1002   size_t len	    = LT_STRLEN (str);
1003   char *tmp;
1004 
1005   FREE (*dest);
1006 
1007   if (!end || end == str)
1008     return 1;
1009 
1010   if (len > 3 && str[0] == '\'')
1011     {
1012       tmp = MALLOC (char, end - str);
1013       if (!tmp)
1014 	return 1;
1015 
1016       memcpy(tmp, &str[1], (end - str) - 1);
1017       tmp[(end - str) - 1] = LT_EOS_CHAR;
1018       *dest = tmp;
1019     }
1020   else
1021     {
1022       *dest = 0;
1023     }
1024 
1025   return 0;
1026 }
1027 
1028 /* Read the .la file FILE. */
1029 static int
parse_dotla_file(FILE * file,char ** dlname,char ** libdir,char ** deplibs,char ** old_name,int * installed)1030 parse_dotla_file(FILE *file, char **dlname, char **libdir, char **deplibs,
1031     char **old_name, int *installed)
1032 {
1033   int		errors = 0;
1034   size_t	line_len = LT_FILENAME_MAX;
1035   char *	line = MALLOC (char, line_len);
1036 
1037   if (!line)
1038     {
1039       LT__SETERROR (FILE_NOT_FOUND);
1040       return 1;
1041     }
1042 
1043   while (!feof (file))
1044     {
1045       line[line_len-2] = '\0';
1046       if (!fgets (line, (int) line_len, file))
1047 	{
1048 	  break;
1049 	}
1050 
1051       /* Handle the case where we occasionally need to read a line
1052 	 that is longer than the initial buffer size.
1053 	 Behave even if the file contains NUL bytes due to corruption. */
1054       while (line[line_len-2] != '\0' && line[line_len-2] != '\n' && !feof (file))
1055 	{
1056 	  line = REALLOC (char, line, line_len *2);
1057 	  if (!line)
1058 	    {
1059 	      ++errors;
1060 	      goto cleanup;
1061 	    }
1062 	  line[line_len * 2 - 2] = '\0';
1063 	  if (!fgets (&line[line_len -1], (int) line_len +1, file))
1064 	    {
1065 	      break;
1066 	    }
1067 	  line_len *= 2;
1068 	}
1069 
1070       if (line[0] == '\n' || line[0] == '#')
1071 	{
1072 	  continue;
1073 	}
1074 
1075 #undef  STR_DLNAME
1076 #define STR_DLNAME	"dlname="
1077       if (strncmp (line, STR_DLNAME, sizeof (STR_DLNAME) - 1) == 0)
1078 	{
1079 	  errors += trim (dlname, &line[sizeof (STR_DLNAME) - 1]);
1080 	}
1081 
1082 #undef  STR_OLD_LIBRARY
1083 #define STR_OLD_LIBRARY	"old_library="
1084       else if (strncmp (line, STR_OLD_LIBRARY,
1085 	    sizeof (STR_OLD_LIBRARY) - 1) == 0)
1086 	{
1087 	  errors += trim (old_name, &line[sizeof (STR_OLD_LIBRARY) - 1]);
1088 	}
1089 
1090       /* Windows native tools do not understand the POSIX paths we store
1091 	 in libdir. */
1092 #undef  STR_LIBDIR
1093 #define STR_LIBDIR	"libdir="
1094       else if (strncmp (line, STR_LIBDIR, sizeof (STR_LIBDIR) - 1) == 0)
1095 	{
1096 	  errors += trim (libdir, &line[sizeof(STR_LIBDIR) - 1]);
1097 #ifdef __WINDOWS__
1098 	  /* Disallow following unix-style paths on MinGW.  */
1099 	  if (*libdir && (**libdir == '/' || **libdir == '\\'))
1100 	    **libdir = '\0';
1101 #endif
1102 	}
1103 
1104 #undef  STR_DL_DEPLIBS
1105 #define STR_DL_DEPLIBS	"dependency_libs="
1106       else if (strncmp (line, STR_DL_DEPLIBS,
1107 	    sizeof (STR_DL_DEPLIBS) - 1) == 0)
1108 	{
1109 	  errors += trim (deplibs, &line[sizeof (STR_DL_DEPLIBS) - 1]);
1110 	}
1111       else if (streq (line, "installed=yes\n"))
1112 	{
1113 	  *installed = 1;
1114 	}
1115       else if (streq (line, "installed=no\n"))
1116 	{
1117 	  *installed = 0;
1118 	}
1119 
1120 #undef  STR_LIBRARY_NAMES
1121 #define STR_LIBRARY_NAMES "library_names="
1122       else if (!*dlname && strncmp (line, STR_LIBRARY_NAMES,
1123 	    sizeof (STR_LIBRARY_NAMES) - 1) == 0)
1124 	{
1125 	  char *last_libname;
1126 	  errors += trim (dlname, &line[sizeof (STR_LIBRARY_NAMES) - 1]);
1127 	  if (!errors
1128 	      && *dlname
1129 	      && (last_libname = strrchr (*dlname, ' ')) != 0)
1130 	    {
1131 	      last_libname = lt__strdup (last_libname + 1);
1132 	      if (!last_libname)
1133 		{
1134 		  ++errors;
1135 		  goto cleanup;
1136 		}
1137 	      MEMREASSIGN (*dlname, last_libname);
1138 	    }
1139 	}
1140 
1141       if (errors)
1142 	break;
1143     }
1144 cleanup:
1145   FREE (line);
1146   return errors;
1147 }
1148 
1149 
1150 /* Try to open FILENAME as a module. */
1151 static int
try_dlopen(lt_dlhandle * phandle,const char * filename,const char * ext,lt_dladvise advise)1152 try_dlopen (lt_dlhandle *phandle, const char *filename, const char *ext,
1153 	    lt_dladvise advise)
1154 {
1155   const char *	saved_error	= 0;
1156   char *	archive_name	= 0;
1157   char *	canonical	= 0;
1158   char *	base_name	= 0;
1159   char *	dir		= 0;
1160   char *	name		= 0;
1161   char *        attempt		= 0;
1162   int		errors		= 0;
1163   lt_dlhandle	newhandle;
1164 
1165   assert (phandle);
1166   assert (*phandle == 0);
1167 
1168 #ifdef LT_DEBUG_LOADERS
1169   fprintf (stderr, "try_dlopen (%s, %s)\n",
1170 	   filename ? filename : "(null)",
1171 	   ext ? ext : "(null)");
1172 #endif
1173 
1174   LT__GETERROR (saved_error);
1175 
1176   /* dlopen self? */
1177   if (!filename)
1178     {
1179       *phandle = (lt_dlhandle) lt__zalloc (sizeof (struct lt__handle));
1180       if (*phandle == 0)
1181 	return 1;
1182 
1183       newhandle	= *phandle;
1184 
1185       /* lt_dlclose()ing yourself is very bad!  Disallow it.  */
1186       newhandle->info.is_resident = 1;
1187 
1188       if (tryall_dlopen (&newhandle, 0, advise, 0) != 0)
1189 	{
1190 	  FREE (*phandle);
1191 	  return 1;
1192 	}
1193 
1194       goto register_handle;
1195     }
1196 
1197   assert (filename && *filename);
1198 
1199   if (ext)
1200     {
1201       attempt = MALLOC (char, LT_STRLEN (filename) + LT_STRLEN (ext) + 1);
1202       if (!attempt)
1203 	return 1;
1204 
1205       sprintf(attempt, "%s%s", filename, ext);
1206     }
1207   else
1208     {
1209       attempt = lt__strdup (filename);
1210       if (!attempt)
1211 	return 1;
1212     }
1213 
1214   /* Doing this immediately allows internal functions to safely
1215      assume only canonicalized paths are passed.  */
1216   if (canonicalize_path (attempt, &canonical) != 0)
1217     {
1218       ++errors;
1219       goto cleanup;
1220     }
1221 
1222   /* If the canonical module name is a path (relative or absolute)
1223      then split it into a directory part and a name part.  */
1224   base_name = strrchr (canonical, '/');
1225   if (base_name)
1226     {
1227       size_t dirlen = (1+ base_name) - canonical;
1228 
1229       dir = MALLOC (char, 1+ dirlen);
1230       if (!dir)
1231 	{
1232 	  ++errors;
1233 	  goto cleanup;
1234 	}
1235 
1236       strncpy (dir, canonical, dirlen);
1237       dir[dirlen] = LT_EOS_CHAR;
1238 
1239       ++base_name;
1240     }
1241   else
1242     MEMREASSIGN (base_name, canonical);
1243 
1244   assert (base_name && *base_name);
1245 
1246   ext = strrchr (base_name, '.');
1247   if (!ext)
1248     {
1249       ext = base_name + LT_STRLEN (base_name);
1250     }
1251 
1252   /* extract the module name from the file name */
1253   name = MALLOC (char, ext - base_name + 1);
1254   if (!name)
1255     {
1256       ++errors;
1257       goto cleanup;
1258     }
1259 
1260   /* canonicalize the module name */
1261   {
1262     int i;
1263     for (i = 0; i < ext - base_name; ++i)
1264       {
1265 	if (isalnum ((unsigned char)(base_name[i])))
1266 	  {
1267 	    name[i] = base_name[i];
1268 	  }
1269 	else
1270 	  {
1271 	    name[i] = '_';
1272 	  }
1273       }
1274     name[ext - base_name] = LT_EOS_CHAR;
1275   }
1276 
1277   /* Before trawling through the filesystem in search of a module,
1278      check whether we are opening a preloaded module.  */
1279   if (!dir)
1280     {
1281       const lt_dlvtable *vtable	= lt_dlloader_find ("lt_preopen");
1282 
1283       if (vtable)
1284 	{
1285 	  /* libprefix + name + "." + libext + NULL */
1286 	  archive_name = MALLOC (char, strlen (libprefix) + LT_STRLEN (name) + strlen (libext) + 2);
1287 	  *phandle = (lt_dlhandle) lt__zalloc (sizeof (struct lt__handle));
1288 
1289 	  if ((*phandle == NULL) || (archive_name == NULL))
1290 	    {
1291 	      ++errors;
1292 	      goto cleanup;
1293 	    }
1294 	  newhandle = *phandle;
1295 
1296 	  /* Preloaded modules are always named according to their old
1297 	     archive name.  */
1298 	  if (strncmp(name, "lib", 3) == 0)
1299 	    {
1300 	      sprintf (archive_name, "%s%s.%s", libprefix, name + 3, libext);
1301 	    }
1302 	  else
1303 	    {
1304 	      sprintf (archive_name, "%s.%s", name, libext);
1305 	    }
1306 
1307 	  if (tryall_dlopen (&newhandle, archive_name, advise, vtable) == 0)
1308 	    {
1309 	      goto register_handle;
1310 	    }
1311 
1312 	  /* If we're still here, there was no matching preloaded module,
1313 	     so put things back as we found them, and continue searching.  */
1314 	  FREE (*phandle);
1315 	  newhandle = NULL;
1316 	}
1317     }
1318 
1319   /* If we are allowing only preloaded modules, and we didn't find
1320      anything yet, give up on the search here.  */
1321   if (advise && advise->try_preload_only)
1322     {
1323       goto cleanup;
1324     }
1325 
1326   /* Check whether we are opening a libtool module (.la extension).  */
1327   if (ext && streq (ext, archive_ext))
1328     {
1329       /* this seems to be a libtool module */
1330       FILE *	file	 = 0;
1331       char *	dlname	 = 0;
1332       char *	old_name = 0;
1333       char *	libdir	 = 0;
1334       char *	deplibs	 = 0;
1335 
1336       /* if we can't find the installed flag, it is probably an
1337 	 installed libtool archive, produced with an old version
1338 	 of libtool */
1339       int	installed = 1;
1340 
1341       /* Now try to open the .la file.  If there is no directory name
1342 	 component, try to find it first in user_search_path and then other
1343 	 prescribed paths.  Otherwise (or in any case if the module was not
1344 	 yet found) try opening just the module name as passed.  */
1345       if (!dir)
1346 	{
1347 	  const char *search_path = user_search_path;
1348 
1349 	  if (search_path)
1350 	    file = find_file (user_search_path, base_name, &dir);
1351 
1352 	  if (!file)
1353 	    {
1354 	      search_path = getenv (LTDL_SEARCHPATH_VAR);
1355 	      if (search_path)
1356 		file = find_file (search_path, base_name, &dir);
1357 	    }
1358 
1359 #if defined(LT_MODULE_PATH_VAR)
1360 	  if (!file)
1361 	    {
1362 	      search_path = getenv (LT_MODULE_PATH_VAR);
1363 	      if (search_path)
1364 		file = find_file (search_path, base_name, &dir);
1365 	    }
1366 #endif
1367 #if defined(LT_DLSEARCH_PATH)
1368 	  if (!file && *sys_dlsearch_path)
1369 	    {
1370 	      file = find_file (sys_dlsearch_path, base_name, &dir);
1371 	    }
1372 #endif
1373 	}
1374       else
1375 	{
1376 	  file = fopen (attempt, LT_READTEXT_MODE);
1377 	}
1378 
1379       /* If we didn't find the file by now, it really isn't there.  Set
1380 	 the status flag, and bail out.  */
1381       if (!file)
1382 	{
1383 	  LT__SETERROR (FILE_NOT_FOUND);
1384 	  ++errors;
1385 	  goto cleanup;
1386 	}
1387 
1388       /* read the .la file */
1389       if (parse_dotla_file(file, &dlname, &libdir, &deplibs,
1390 	    &old_name, &installed) != 0)
1391 	++errors;
1392 
1393       fclose (file);
1394 
1395       /* allocate the handle */
1396       *phandle = (lt_dlhandle) lt__zalloc (sizeof (struct lt__handle));
1397       if (*phandle == 0)
1398 	++errors;
1399 
1400       if (errors)
1401 	{
1402 	  FREE (dlname);
1403 	  FREE (old_name);
1404 	  FREE (libdir);
1405 	  FREE (deplibs);
1406 	  FREE (*phandle);
1407 	  goto cleanup;
1408 	}
1409 
1410       assert (*phandle);
1411 
1412       if (load_deplibs (*phandle, deplibs) == 0)
1413 	{
1414 	  newhandle = *phandle;
1415 	  /* find_module may replace newhandle */
1416 	  if (find_module (&newhandle, dir, libdir, dlname, old_name,
1417 			   installed, advise))
1418 	    {
1419 	      unload_deplibs (*phandle);
1420 	      ++errors;
1421 	    }
1422 	}
1423       else
1424 	{
1425 	  ++errors;
1426 	}
1427 
1428       FREE (dlname);
1429       FREE (old_name);
1430       FREE (libdir);
1431       FREE (deplibs);
1432 
1433       if (errors)
1434 	{
1435 	  FREE (*phandle);
1436 	  goto cleanup;
1437 	}
1438 
1439       if (*phandle != newhandle)
1440 	{
1441 	  unload_deplibs (*phandle);
1442 	}
1443     }
1444   else
1445     {
1446       /* not a libtool module */
1447       *phandle = (lt_dlhandle) lt__zalloc (sizeof (struct lt__handle));
1448       if (*phandle == 0)
1449 	{
1450 	  ++errors;
1451 	  goto cleanup;
1452 	}
1453 
1454       newhandle = *phandle;
1455 
1456       /* If the module has no directory name component, try to find it
1457 	 first in user_search_path and then other prescribed paths.
1458 	 Otherwise (or in any case if the module was not yet found) try
1459 	 opening just the module name as passed.  */
1460       if ((dir || (!find_handle (user_search_path, base_name,
1461 				 &newhandle, advise)
1462 		   && !find_handle (getenv (LTDL_SEARCHPATH_VAR), base_name,
1463 				    &newhandle, advise)
1464 #if defined(LT_MODULE_PATH_VAR)
1465 		   && !find_handle (getenv (LT_MODULE_PATH_VAR), base_name,
1466 				    &newhandle, advise)
1467 #endif
1468 #if defined(LT_DLSEARCH_PATH)
1469 		   && !find_handle (sys_dlsearch_path, base_name,
1470 				    &newhandle, advise)
1471 #endif
1472 		   )))
1473 	{
1474 	  if (tryall_dlopen (&newhandle, attempt, advise, 0) != 0)
1475 	    {
1476 	      newhandle = NULL;
1477 	    }
1478 	}
1479 
1480       if (!newhandle)
1481 	{
1482 	  FREE (*phandle);
1483 	  ++errors;
1484 	  goto cleanup;
1485 	}
1486     }
1487 
1488  register_handle:
1489   MEMREASSIGN (*phandle, newhandle);
1490 
1491   if ((*phandle)->info.ref_count == 0)
1492     {
1493       (*phandle)->info.ref_count	= 1;
1494       MEMREASSIGN ((*phandle)->info.name, name);
1495 
1496       (*phandle)->next	= handles;
1497       handles		= *phandle;
1498     }
1499 
1500   LT__SETERRORSTR (saved_error);
1501 
1502  cleanup:
1503   FREE (dir);
1504   FREE (attempt);
1505   FREE (name);
1506   if (!canonical)		/* was MEMREASSIGNed */
1507     FREE (base_name);
1508   FREE (canonical);
1509   FREE (archive_name);
1510 
1511   return errors;
1512 }
1513 
1514 
1515 /* If the last error message stored was `FILE_NOT_FOUND', then return
1516    non-zero.  */
1517 static int
file_not_found(void)1518 file_not_found (void)
1519 {
1520   const char *error = 0;
1521 
1522   LT__GETERROR (error);
1523   if (error == LT__STRERROR (FILE_NOT_FOUND))
1524     return 1;
1525 
1526   return 0;
1527 }
1528 
1529 
1530 /* Unless FILENAME already bears a suitable library extension, then
1531    return 0.  */
1532 static int
has_library_ext(const char * filename)1533 has_library_ext (const char *filename)
1534 {
1535   const char *	ext     = 0;
1536 
1537   assert (filename);
1538 
1539   ext = strrchr (filename, '.');
1540 
1541   if (ext && ((streq (ext, archive_ext))
1542 #if defined(LT_MODULE_EXT)
1543 	     || (streq (ext, shlib_ext))
1544 #endif
1545 #if defined(LT_SHARED_EXT)
1546 	     || (streq (ext, shared_ext))
1547 #endif
1548     ))
1549     {
1550       return 1;
1551     }
1552 
1553   return 0;
1554 }
1555 
1556 
1557 /* Initialise and configure a user lt_dladvise opaque object.  */
1558 
1559 int
lt_dladvise_init(lt_dladvise * padvise)1560 lt_dladvise_init (lt_dladvise *padvise)
1561 {
1562   lt_dladvise advise = (lt_dladvise) lt__zalloc (sizeof (struct lt__advise));
1563   *padvise = advise;
1564   return (advise ? 0 : 1);
1565 }
1566 
1567 int
lt_dladvise_destroy(lt_dladvise * padvise)1568 lt_dladvise_destroy (lt_dladvise *padvise)
1569 {
1570   if (padvise)
1571     FREE(*padvise);
1572   return 0;
1573 }
1574 
1575 int
lt_dladvise_ext(lt_dladvise * padvise)1576 lt_dladvise_ext (lt_dladvise *padvise)
1577 {
1578   assert (padvise && *padvise);
1579   (*padvise)->try_ext = 1;
1580   return 0;
1581 }
1582 
1583 int
lt_dladvise_resident(lt_dladvise * padvise)1584 lt_dladvise_resident (lt_dladvise *padvise)
1585 {
1586   assert (padvise && *padvise);
1587   (*padvise)->is_resident = 1;
1588   return 0;
1589 }
1590 
1591 int
lt_dladvise_local(lt_dladvise * padvise)1592 lt_dladvise_local (lt_dladvise *padvise)
1593 {
1594   assert (padvise && *padvise);
1595   (*padvise)->is_symlocal = 1;
1596   return 0;
1597 }
1598 
1599 int
lt_dladvise_global(lt_dladvise * padvise)1600 lt_dladvise_global (lt_dladvise *padvise)
1601 {
1602   assert (padvise && *padvise);
1603   (*padvise)->is_symglobal = 1;
1604   return 0;
1605 }
1606 
1607 int
lt_dladvise_preload(lt_dladvise * padvise)1608 lt_dladvise_preload (lt_dladvise *padvise)
1609 {
1610   assert (padvise && *padvise);
1611   (*padvise)->try_preload_only = 1;
1612   return 0;
1613 }
1614 
1615 /* Libtool-1.5.x interface for loading a new module named FILENAME.  */
1616 lt_dlhandle
lt_dlopen(const char * filename)1617 lt_dlopen (const char *filename)
1618 {
1619   return lt_dlopenadvise (filename, NULL);
1620 }
1621 
1622 
1623 /* If FILENAME has an ARCHIVE_EXT or MODULE_EXT extension, try to
1624    open the FILENAME as passed.  Otherwise try appending ARCHIVE_EXT,
1625    and if a file is still not found try again with MODULE_EXT appended
1626    instead.  */
1627 lt_dlhandle
lt_dlopenext(const char * filename)1628 lt_dlopenext (const char *filename)
1629 {
1630   lt_dlhandle	handle	= 0;
1631   lt_dladvise	advise;
1632 
1633   if (!lt_dladvise_init (&advise) && !lt_dladvise_ext (&advise))
1634     handle = lt_dlopenadvise (filename, advise);
1635 
1636   lt_dladvise_destroy (&advise);
1637   return handle;
1638 }
1639 
1640 
1641 lt_dlhandle
lt_dlopenadvise(const char * filename,lt_dladvise advise)1642 lt_dlopenadvise (const char *filename, lt_dladvise advise)
1643 {
1644   lt_dlhandle	handle	= 0;
1645   int		errors	= 0;
1646   const char *	saved_error	= 0;
1647 
1648   LT__GETERROR (saved_error);
1649 
1650   /* Can't have symbols hidden and visible at the same time!  */
1651   if (advise && advise->is_symlocal && advise->is_symglobal)
1652     {
1653       LT__SETERROR (CONFLICTING_FLAGS);
1654       return 0;
1655     }
1656 
1657   if (!filename
1658       || !advise
1659       || !advise->try_ext
1660       || has_library_ext (filename))
1661     {
1662       /* Just incase we missed a code path in try_dlopen() that reports
1663 	 an error, but forgot to reset handle... */
1664       if (try_dlopen (&handle, filename, NULL, advise) != 0)
1665 	return 0;
1666 
1667       return handle;
1668     }
1669   else if (filename && *filename)
1670     {
1671 
1672       /* First try appending ARCHIVE_EXT.  */
1673       errors += try_dlopen (&handle, filename, archive_ext, advise);
1674 
1675       /* If we found FILENAME, stop searching -- whether we were able to
1676 	 load the file as a module or not.  If the file exists but loading
1677 	 failed, it is better to return an error message here than to
1678 	 report FILE_NOT_FOUND when the alternatives (foo.so etc) are not
1679 	 in the module search path.  */
1680       if (handle || ((errors > 0) && !file_not_found ()))
1681 	return handle;
1682 
1683 #if defined(LT_MODULE_EXT)
1684       /* Try appending SHLIB_EXT.   */
1685       LT__SETERRORSTR (saved_error);
1686       errors = try_dlopen (&handle, filename, shlib_ext, advise);
1687 
1688       /* As before, if the file was found but loading failed, return now
1689 	 with the current error message.  */
1690       if (handle || ((errors > 0) && !file_not_found ()))
1691 	return handle;
1692 #endif
1693 
1694 #if defined(LT_SHARED_EXT)
1695       /* Try appending SHARED_EXT.   */
1696       LT__SETERRORSTR (saved_error);
1697       errors = try_dlopen (&handle, filename, shared_ext, advise);
1698 
1699       /* As before, if the file was found but loading failed, return now
1700 	 with the current error message.  */
1701       if (handle || ((errors > 0) && !file_not_found ()))
1702 	return handle;
1703 #endif
1704     }
1705 
1706   /* Still here?  Then we really did fail to locate any of the file
1707      names we tried.  */
1708   LT__SETERROR (FILE_NOT_FOUND);
1709   return 0;
1710 }
1711 
1712 
1713 static int
lt_argz_insert(char ** pargz,size_t * pargz_len,char * before,const char * entry)1714 lt_argz_insert (char **pargz, size_t *pargz_len, char *before,
1715 		const char *entry)
1716 {
1717   error_t error;
1718 
1719   /* Prior to Sep 8, 2005, newlib had a bug where argz_insert(pargz,
1720      pargz_len, NULL, entry) failed with EINVAL.  */
1721   if (before)
1722     error = argz_insert (pargz, pargz_len, before, entry);
1723   else
1724     error = argz_append (pargz, pargz_len, entry, 1 + strlen (entry));
1725 
1726   if (error)
1727     {
1728       switch (error)
1729 	{
1730 	case ENOMEM:
1731 	  LT__SETERROR (NO_MEMORY);
1732 	  break;
1733 	default:
1734 	  LT__SETERROR (UNKNOWN);
1735 	  break;
1736 	}
1737       return 1;
1738     }
1739 
1740   return 0;
1741 }
1742 
1743 static int
lt_argz_insertinorder(char ** pargz,size_t * pargz_len,const char * entry)1744 lt_argz_insertinorder (char **pargz, size_t *pargz_len, const char *entry)
1745 {
1746   char *before = 0;
1747 
1748   assert (pargz);
1749   assert (pargz_len);
1750   assert (entry && *entry);
1751 
1752   if (*pargz)
1753     while ((before = argz_next (*pargz, *pargz_len, before)))
1754       {
1755 	int cmp = strcmp (entry, before);
1756 
1757 	if (cmp < 0)  break;
1758 	if (cmp == 0) return 0;	/* No duplicates! */
1759       }
1760 
1761   return lt_argz_insert (pargz, pargz_len, before, entry);
1762 }
1763 
1764 static int
lt_argz_insertdir(char ** pargz,size_t * pargz_len,const char * dirnam,struct dirent * dp)1765 lt_argz_insertdir (char **pargz, size_t *pargz_len, const char *dirnam,
1766 		   struct dirent *dp)
1767 {
1768   char   *buf	    = 0;
1769   size_t buf_len    = 0;
1770   char   *end	    = 0;
1771   size_t end_offset = 0;
1772   size_t dir_len    = 0;
1773   int    errors	    = 0;
1774 
1775   assert (pargz);
1776   assert (pargz_len);
1777   assert (dp);
1778 
1779   dir_len = LT_STRLEN (dirnam);
1780   end     = dp->d_name + D_NAMLEN(dp);
1781 
1782   /* Ignore version numbers.  */
1783   {
1784     char *p;
1785     for (p = end; p -1 > dp->d_name; --p)
1786       if (strchr (".0123456789", p[-1]) == 0)
1787 	break;
1788 
1789     if (*p == '.')
1790       end = p;
1791   }
1792 
1793   /* Ignore filename extension.  */
1794   {
1795     char *p;
1796     for (p = end -1; p > dp->d_name; --p)
1797       if (*p == '.')
1798 	{
1799 	  end = p;
1800 	  break;
1801 	}
1802   }
1803 
1804   /* Prepend the directory name.  */
1805   end_offset	= end - dp->d_name;
1806   buf_len	= dir_len + 1+ end_offset;
1807   buf		= MALLOC (char, 1+ buf_len);
1808   if (!buf)
1809     return ++errors;
1810 
1811   assert (buf);
1812 
1813   strcpy  (buf, dirnam);
1814   strcat  (buf, "/");
1815   strncat (buf, dp->d_name, end_offset);
1816   buf[buf_len] = LT_EOS_CHAR;
1817 
1818   /* Try to insert (in order) into ARGZ/ARGZ_LEN.  */
1819   if (lt_argz_insertinorder (pargz, pargz_len, buf) != 0)
1820     ++errors;
1821 
1822   FREE (buf);
1823 
1824   return errors;
1825 }
1826 
1827 static int
list_files_by_dir(const char * dirnam,char ** pargz,size_t * pargz_len)1828 list_files_by_dir (const char *dirnam, char **pargz, size_t *pargz_len)
1829 {
1830   DIR	*dirp	  = 0;
1831   int    errors	  = 0;
1832 
1833   assert (dirnam && *dirnam);
1834   assert (pargz);
1835   assert (pargz_len);
1836   assert (dirnam[LT_STRLEN(dirnam) -1] != '/');
1837 
1838   dirp = opendir (dirnam);
1839   if (dirp)
1840     {
1841       struct dirent *dp	= 0;
1842 
1843       while ((dp = readdir (dirp)))
1844 	if (dp->d_name[0] != '.')
1845 	  if (lt_argz_insertdir (pargz, pargz_len, dirnam, dp))
1846 	    {
1847 	      ++errors;
1848 	      break;
1849 	    }
1850 
1851       closedir (dirp);
1852     }
1853   else
1854     ++errors;
1855 
1856   return errors;
1857 }
1858 
1859 
1860 /* If there are any files in DIRNAME, call the function passed in
1861    DATA1 (with the name of each file and DATA2 as arguments).  */
1862 static int
foreachfile_callback(char * dirname,void * data1,void * data2)1863 foreachfile_callback (char *dirname, void *data1, void *data2)
1864 {
1865   file_worker_func *func = *(file_worker_func **) data1;
1866 
1867   int	  is_done  = 0;
1868   char   *argz     = 0;
1869   size_t  argz_len = 0;
1870 
1871   if (list_files_by_dir (dirname, &argz, &argz_len) != 0)
1872     goto cleanup;
1873   if (!argz)
1874     goto cleanup;
1875 
1876   {
1877     char *filename = 0;
1878     while ((filename = argz_next (argz, argz_len, filename)))
1879       if ((is_done = (*func) (filename, data2)))
1880 	break;
1881   }
1882 
1883  cleanup:
1884   FREE (argz);
1885 
1886   return is_done;
1887 }
1888 
1889 
1890 /* Call FUNC for each unique extensionless file in SEARCH_PATH, along
1891    with DATA.  The filenames passed to FUNC would be suitable for
1892    passing to lt_dlopenext.  The extensions are stripped so that
1893    individual modules do not generate several entries (e.g. libfoo.la,
1894    libfoo.so, libfoo.so.1, libfoo.so.1.0.0).  If SEARCH_PATH is NULL,
1895    then the same directories that lt_dlopen would search are examined.  */
1896 int
lt_dlforeachfile(const char * search_path,int (* func)(const char * filename,void * data),void * data)1897 lt_dlforeachfile (const char *search_path,
1898 		  int (*func) (const char *filename, void *data),
1899 		  void *data)
1900 {
1901   int is_done = 0;
1902   file_worker_func **fpptr = &func;
1903 
1904   if (search_path)
1905     {
1906       /* If a specific path was passed, search only the directories
1907 	 listed in it.  */
1908       is_done = foreach_dirinpath (search_path, 0,
1909 				   foreachfile_callback, fpptr, data);
1910     }
1911   else
1912     {
1913       /* Otherwise search the default paths.  */
1914       is_done = foreach_dirinpath (user_search_path, 0,
1915 				   foreachfile_callback, fpptr, data);
1916       if (!is_done)
1917 	{
1918 	  is_done = foreach_dirinpath (getenv(LTDL_SEARCHPATH_VAR), 0,
1919 				       foreachfile_callback, fpptr, data);
1920 	}
1921 
1922 #if defined(LT_MODULE_PATH_VAR)
1923       if (!is_done)
1924 	{
1925 	  is_done = foreach_dirinpath (getenv(LT_MODULE_PATH_VAR), 0,
1926 				       foreachfile_callback, fpptr, data);
1927 	}
1928 #endif
1929 #if defined(LT_DLSEARCH_PATH)
1930       if (!is_done && *sys_dlsearch_path)
1931 	{
1932 	  is_done = foreach_dirinpath (sys_dlsearch_path, 0,
1933 				       foreachfile_callback, fpptr, data);
1934 	}
1935 #endif
1936     }
1937 
1938   return is_done;
1939 }
1940 
1941 int
lt_dlclose(lt_dlhandle handle)1942 lt_dlclose (lt_dlhandle handle)
1943 {
1944   lt_dlhandle cur, last;
1945   int errors = 0;
1946 
1947   /* check whether the handle is valid */
1948   last = cur = handles;
1949   while (cur && handle != cur)
1950     {
1951       last = cur;
1952       cur = cur->next;
1953     }
1954 
1955   if (!cur)
1956     {
1957       LT__SETERROR (INVALID_HANDLE);
1958       ++errors;
1959       goto done;
1960     }
1961 
1962   cur = handle;
1963   cur->info.ref_count--;
1964 
1965   /* Note that even with resident modules, we must track the ref_count
1966      correctly incase the user decides to reset the residency flag
1967      later (even though the API makes no provision for that at the
1968      moment).  */
1969   if (cur->info.ref_count <= 0 && !LT_DLIS_RESIDENT (cur))
1970     {
1971       lt_user_data data = cur->vtable->dlloader_data;
1972 
1973       if (cur != handles)
1974 	{
1975 	  last->next = cur->next;
1976 	}
1977       else
1978 	{
1979 	  handles = cur->next;
1980 	}
1981 
1982       errors += cur->vtable->module_close (data, cur->module);
1983       errors += unload_deplibs (handle);
1984 
1985       /* It is up to the callers to free the data itself.  */
1986       FREE (cur->interface_data);
1987 
1988       FREE (cur->info.filename);
1989       FREE (cur->info.name);
1990       FREE (cur);
1991 
1992       goto done;
1993     }
1994 
1995   if (LT_DLIS_RESIDENT (handle))
1996     {
1997       LT__SETERROR (CLOSE_RESIDENT_MODULE);
1998       ++errors;
1999     }
2000 
2001  done:
2002   return errors;
2003 }
2004 
2005 void *
lt_dlsym(lt_dlhandle place,const char * symbol)2006 lt_dlsym (lt_dlhandle place, const char *symbol)
2007 {
2008   size_t lensym;
2009   char	lsym[LT_SYMBOL_LENGTH];
2010   char	*sym;
2011   void *address;
2012   lt_user_data data;
2013   lt_dlhandle handle;
2014 
2015   if (!place)
2016     {
2017       LT__SETERROR (INVALID_HANDLE);
2018       return 0;
2019     }
2020 
2021   handle = place;
2022 
2023   if (!symbol)
2024     {
2025       LT__SETERROR (SYMBOL_NOT_FOUND);
2026       return 0;
2027     }
2028 
2029   lensym = LT_STRLEN (symbol) + LT_STRLEN (handle->vtable->sym_prefix)
2030 					+ LT_STRLEN (handle->info.name);
2031 
2032   if (lensym + LT_SYMBOL_OVERHEAD < LT_SYMBOL_LENGTH)
2033     {
2034       sym = lsym;
2035     }
2036   else
2037     {
2038       sym = MALLOC (char, lensym + LT_SYMBOL_OVERHEAD + 1);
2039       if (!sym)
2040 	{
2041 	  LT__SETERROR (BUFFER_OVERFLOW);
2042 	  return 0;
2043 	}
2044     }
2045 
2046   data = handle->vtable->dlloader_data;
2047   if (handle->info.name)
2048     {
2049       const char *saved_error;
2050 
2051       LT__GETERROR (saved_error);
2052 
2053       /* this is a libtool module */
2054       if (handle->vtable->sym_prefix)
2055 	{
2056 	  strcpy(sym, handle->vtable->sym_prefix);
2057 	  strcat(sym, handle->info.name);
2058 	}
2059       else
2060 	{
2061 	  strcpy(sym, handle->info.name);
2062 	}
2063 
2064       strcat(sym, "_LTX_");
2065       strcat(sym, symbol);
2066 
2067       /* try "modulename_LTX_symbol" */
2068       address = handle->vtable->find_sym (data, handle->module, sym);
2069       if (address)
2070 	{
2071 	  if (sym != lsym)
2072 	    {
2073 	      FREE (sym);
2074 	    }
2075 	  return address;
2076 	}
2077       LT__SETERRORSTR (saved_error);
2078     }
2079 
2080   /* otherwise try "symbol" */
2081   if (handle->vtable->sym_prefix)
2082     {
2083       strcpy(sym, handle->vtable->sym_prefix);
2084       strcat(sym, symbol);
2085     }
2086   else
2087     {
2088       strcpy(sym, symbol);
2089     }
2090 
2091   address = handle->vtable->find_sym (data, handle->module, sym);
2092   if (sym != lsym)
2093     {
2094       FREE (sym);
2095     }
2096 
2097   return address;
2098 }
2099 
2100 const char *
lt_dlerror(void)2101 lt_dlerror (void)
2102 {
2103   const char *error;
2104 
2105   LT__GETERROR (error);
2106   LT__SETERRORSTR (0);
2107 
2108   return error;
2109 }
2110 
2111 static int
lt_dlpath_insertdir(char ** ppath,char * before,const char * dir)2112 lt_dlpath_insertdir (char **ppath, char *before, const char *dir)
2113 {
2114   int    errors		= 0;
2115   char  *canonical	= 0;
2116   char  *argz		= 0;
2117   size_t argz_len	= 0;
2118 
2119   assert (ppath);
2120   assert (dir && *dir);
2121 
2122   if (canonicalize_path (dir, &canonical) != 0)
2123     {
2124       ++errors;
2125       goto cleanup;
2126     }
2127 
2128   assert (canonical && *canonical);
2129 
2130   /* If *PPATH is empty, set it to DIR.  */
2131   if (*ppath == 0)
2132     {
2133       assert (!before);		/* BEFORE cannot be set without PPATH.  */
2134       assert (dir);		/* Without DIR, don't call this function!  */
2135 
2136       *ppath = lt__strdup (dir);
2137       if (*ppath == 0)
2138 	++errors;
2139 
2140       goto cleanup;
2141     }
2142 
2143   assert (ppath && *ppath);
2144 
2145   if (argzize_path (*ppath, &argz, &argz_len) != 0)
2146     {
2147       ++errors;
2148       goto cleanup;
2149     }
2150 
2151   /* Convert BEFORE into an equivalent offset into ARGZ.  This only works
2152      if *PPATH is already canonicalized, and hence does not change length
2153      with respect to ARGZ.  We canonicalize each entry as it is added to
2154      the search path, and don't call this function with (uncanonicalized)
2155      user paths, so this is a fair assumption.  */
2156   if (before)
2157     {
2158       assert (*ppath <= before);
2159       assert ((int) (before - *ppath) <= (int) strlen (*ppath));
2160 
2161       before = before - *ppath + argz;
2162     }
2163 
2164   if (lt_argz_insert (&argz, &argz_len, before, dir) != 0)
2165     {
2166       ++errors;
2167       goto cleanup;
2168     }
2169 
2170   argz_stringify (argz, argz_len, LT_PATHSEP_CHAR);
2171   MEMREASSIGN(*ppath, argz);
2172 
2173  cleanup:
2174   FREE (argz);
2175   FREE (canonical);
2176 
2177   return errors;
2178 }
2179 
2180 int
lt_dladdsearchdir(const char * search_dir)2181 lt_dladdsearchdir (const char *search_dir)
2182 {
2183   int errors = 0;
2184 
2185   if (search_dir && *search_dir)
2186     {
2187       if (lt_dlpath_insertdir (&user_search_path, 0, search_dir) != 0)
2188 	++errors;
2189     }
2190 
2191   return errors;
2192 }
2193 
2194 int
lt_dlinsertsearchdir(const char * before,const char * search_dir)2195 lt_dlinsertsearchdir (const char *before, const char *search_dir)
2196 {
2197   int errors = 0;
2198 
2199   if (before)
2200     {
2201       if ((before < user_search_path)
2202 	  || (before >= user_search_path + LT_STRLEN (user_search_path)))
2203 	{
2204 	  LT__SETERROR (INVALID_POSITION);
2205 	  return 1;
2206 	}
2207     }
2208 
2209   if (search_dir && *search_dir)
2210     {
2211       if (lt_dlpath_insertdir (&user_search_path,
2212 			       (char *) before, search_dir) != 0)
2213 	{
2214 	  ++errors;
2215 	}
2216     }
2217 
2218   return errors;
2219 }
2220 
2221 int
lt_dlsetsearchpath(const char * search_path)2222 lt_dlsetsearchpath (const char *search_path)
2223 {
2224   int   errors	    = 0;
2225 
2226   FREE (user_search_path);
2227 
2228   if (!search_path || !LT_STRLEN (search_path))
2229     {
2230       return errors;
2231     }
2232 
2233   if (canonicalize_path (search_path, &user_search_path) != 0)
2234     ++errors;
2235 
2236   return errors;
2237 }
2238 
2239 const char *
lt_dlgetsearchpath(void)2240 lt_dlgetsearchpath (void)
2241 {
2242   const char *saved_path;
2243 
2244   saved_path = user_search_path;
2245 
2246   return saved_path;
2247 }
2248 
2249 int
lt_dlmakeresident(lt_dlhandle handle)2250 lt_dlmakeresident (lt_dlhandle handle)
2251 {
2252   int errors = 0;
2253 
2254   if (!handle)
2255     {
2256       LT__SETERROR (INVALID_HANDLE);
2257       ++errors;
2258     }
2259   else
2260     {
2261       handle->info.is_resident = 1;
2262     }
2263 
2264   return errors;
2265 }
2266 
2267 int
lt_dlisresident(lt_dlhandle handle)2268 lt_dlisresident	(lt_dlhandle handle)
2269 {
2270   if (!handle)
2271     {
2272       LT__SETERROR (INVALID_HANDLE);
2273       return -1;
2274     }
2275 
2276   return LT_DLIS_RESIDENT (handle);
2277 }
2278 
2279 
2280 
2281 /* --- MODULE INFORMATION --- */
2282 
2283 typedef struct {
2284   const char *id_string;
2285   lt_dlhandle_interface *iface;
2286 } lt__interface_id;
2287 
2288 lt_dlinterface_id
lt_dlinterface_register(const char * id_string,lt_dlhandle_interface * iface)2289 lt_dlinterface_register (const char *id_string, lt_dlhandle_interface *iface)
2290 {
2291   lt__interface_id *interface_id = (lt__interface_id *) lt__malloc (sizeof *interface_id);
2292 
2293   /* If lt__malloc fails, it will LT__SETERROR (NO_MEMORY), which
2294      can then be detected with lt_dlerror() if we return 0.  */
2295   if (interface_id)
2296     {
2297       interface_id->id_string = lt__strdup (id_string);
2298       if (!interface_id->id_string)
2299 	FREE (interface_id);
2300       else
2301 	interface_id->iface = iface;
2302     }
2303 
2304   return (lt_dlinterface_id) interface_id;
2305 }
2306 
lt_dlinterface_free(lt_dlinterface_id key)2307 void lt_dlinterface_free (lt_dlinterface_id key)
2308 {
2309   lt__interface_id *interface_id = (lt__interface_id *)key;
2310   FREE (interface_id->id_string);
2311   FREE (interface_id);
2312 }
2313 
2314 void *
lt_dlcaller_set_data(lt_dlinterface_id key,lt_dlhandle handle,void * data)2315 lt_dlcaller_set_data (lt_dlinterface_id key, lt_dlhandle handle, void *data)
2316 {
2317   int n_elements = 0;
2318   void *stale = (void *) 0;
2319   lt_dlhandle cur = handle;
2320   int i;
2321 
2322   if (cur->interface_data)
2323     while (cur->interface_data[n_elements].key)
2324       ++n_elements;
2325 
2326   for (i = 0; i < n_elements; ++i)
2327     {
2328       if (cur->interface_data[i].key == key)
2329 	{
2330 	  stale = cur->interface_data[i].data;
2331 	  break;
2332 	}
2333     }
2334 
2335   /* Ensure that there is enough room in this handle's interface_data
2336      array to accept a new element (and an empty end marker).  */
2337   if (i == n_elements)
2338     {
2339       lt_interface_data *temp
2340 	= REALLOC (lt_interface_data, cur->interface_data, 2+ n_elements);
2341 
2342       if (!temp)
2343 	{
2344 	  stale = 0;
2345 	  goto done;
2346 	}
2347 
2348       cur->interface_data = temp;
2349 
2350       /* We only need this if we needed to allocate a new interface_data.  */
2351       cur->interface_data[i].key	= key;
2352       cur->interface_data[1+ i].key	= 0;
2353     }
2354 
2355   cur->interface_data[i].data = data;
2356 
2357  done:
2358   return stale;
2359 }
2360 
2361 void *
lt_dlcaller_get_data(lt_dlinterface_id key,lt_dlhandle handle)2362 lt_dlcaller_get_data (lt_dlinterface_id key, lt_dlhandle handle)
2363 {
2364   void *result = (void *) 0;
2365   lt_dlhandle cur = handle;
2366 
2367   /* Locate the index of the element with a matching KEY.  */
2368   if (cur->interface_data)
2369     {
2370       int i;
2371       for (i = 0; cur->interface_data[i].key; ++i)
2372 	{
2373 	  if (cur->interface_data[i].key == key)
2374 	    {
2375 	      result = cur->interface_data[i].data;
2376 	      break;
2377 	    }
2378 	}
2379     }
2380 
2381   return result;
2382 }
2383 
2384 const lt_dlinfo *
lt_dlgetinfo(lt_dlhandle handle)2385 lt_dlgetinfo (lt_dlhandle handle)
2386 {
2387   if (!handle)
2388     {
2389       LT__SETERROR (INVALID_HANDLE);
2390       return 0;
2391     }
2392 
2393   return &(handle->info);
2394 }
2395 
2396 
2397 lt_dlhandle
lt_dlhandle_iterate(lt_dlinterface_id iface,lt_dlhandle place)2398 lt_dlhandle_iterate (lt_dlinterface_id iface, lt_dlhandle place)
2399 {
2400   lt_dlhandle handle = place;
2401   lt__interface_id *iterator = (lt__interface_id *) iface;
2402 
2403   assert (iface); /* iface is a required argument */
2404 
2405   if (!handle)
2406     handle = handles;
2407   else
2408     handle = handle->next;
2409 
2410   /* advance while the interface check fails */
2411   while (handle && iterator->iface
2412 	 && ((*iterator->iface) (handle, iterator->id_string) != 0))
2413     {
2414       handle = handle->next;
2415     }
2416 
2417   return handle;
2418 }
2419 
2420 
2421 lt_dlhandle
lt_dlhandle_fetch(lt_dlinterface_id iface,const char * module_name)2422 lt_dlhandle_fetch (lt_dlinterface_id iface, const char *module_name)
2423 {
2424   lt_dlhandle handle = 0;
2425 
2426   assert (iface); /* iface is a required argument */
2427 
2428   while ((handle = lt_dlhandle_iterate (iface, handle)))
2429     {
2430       lt_dlhandle cur = handle;
2431       if (cur && cur->info.name && streq (cur->info.name, module_name))
2432 	break;
2433     }
2434 
2435   return handle;
2436 }
2437 
2438 
2439 int
lt_dlhandle_map(lt_dlinterface_id iface,int (* func)(lt_dlhandle handle,void * data),void * data)2440 lt_dlhandle_map (lt_dlinterface_id iface,
2441 		 int (*func) (lt_dlhandle handle, void *data), void *data)
2442 {
2443   lt__interface_id *iterator = (lt__interface_id *) iface;
2444   lt_dlhandle cur = handles;
2445 
2446   assert (iface); /* iface is a required argument */
2447 
2448   while (cur)
2449     {
2450       int errorcode = 0;
2451 
2452       /* advance while the interface check fails */
2453       while (cur && iterator->iface
2454 	     && ((*iterator->iface) (cur, iterator->id_string) != 0))
2455 	{
2456 	  cur = cur->next;
2457 	}
2458 
2459       if ((errorcode = (*func) (cur, data)) != 0)
2460 	return errorcode;
2461     }
2462 
2463   return 0;
2464 }
2465