1/* GMODULE - GLIB wrapper code for dynamic module loading
2 * Copyright (C) 1998 Tim Janik
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19
20/*
21 * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
22 * file for a list of people on the GLib Team.  See the ChangeLog
23 * files for a list of changes.  These files are distributed with
24 * GLib at ftp://ftp.gtk.org/pub/gtk/.
25 */
26
27/*
28 * MT safe
29 */
30
31#include "config.h"
32
33#include "glib.h"
34#include "gmodule.h"
35
36#include <errno.h>
37#include <string.h>
38#include <sys/types.h>
39#include <sys/stat.h>
40#include <fcntl.h>
41#ifdef HAVE_UNISTD_H
42#include <unistd.h>
43#endif
44#ifdef G_OS_WIN32
45#include <io.h>		/* For open() and close() prototypes. */
46#endif
47
48#include "gmoduleconf.h"
49#include "gstdio.h"
50
51/* We maintain a list of modules, so we can reference count them.
52 * That's needed because some platforms don't support refernce counts on
53 * modules e.g. the shl_* implementation of HP-UX
54 * (http://www.stat.umn.edu/~luke/xls/projects/dlbasics/dlbasics.html).
55 * Also, the module for the program itself is kept seperatedly for
56 * faster access and because it has special semantics.
57 */
58
59
60/* --- structures --- */
61struct _GModule
62{
63  gchar	*file_name;
64#if defined (G_OS_WIN32) && !defined(_WIN64)
65  gchar *cp_file_name;
66#endif
67  gpointer handle;
68  guint ref_count : 31;
69  guint is_resident : 1;
70  GModuleUnload unload;
71  GModule *next;
72};
73
74
75/* --- prototypes --- */
76static gpointer		_g_module_open		(const gchar	*file_name,
77						 gboolean	 bind_lazy,
78						 gboolean	 bind_local);
79static void		_g_module_close		(gpointer	 handle,
80						 gboolean	 is_unref);
81static gpointer		_g_module_self		(void);
82static gpointer		_g_module_symbol	(gpointer	 handle,
83						 const gchar	*symbol_name);
84static gchar*		_g_module_build_path	(const gchar	*directory,
85						 const gchar	*module_name);
86static inline void	g_module_set_error	(const gchar	*error);
87static inline GModule*	g_module_find_by_handle (gpointer	 handle);
88static inline GModule*	g_module_find_by_name	(const gchar	*name);
89
90
91/* --- variables --- */
92static GModule	     *modules = NULL;
93static GModule	     *main_module = NULL;
94static GStaticPrivate module_error_private = G_STATIC_PRIVATE_INIT;
95static gboolean	      module_debug_initialized = FALSE;
96static guint	      module_debug_flags = 0;
97
98
99/* --- inline functions --- */
100static inline GModule*
101g_module_find_by_handle (gpointer handle)
102{
103  GModule *module;
104  GModule *retval = NULL;
105
106  if (main_module && main_module->handle == handle)
107    retval = main_module;
108  else
109    for (module = modules; module; module = module->next)
110      if (handle == module->handle)
111	{
112	  retval = module;
113	  break;
114	}
115
116  return retval;
117}
118
119static inline GModule*
120g_module_find_by_name (const gchar *name)
121{
122  GModule *module;
123  GModule *retval = NULL;
124
125  for (module = modules; module; module = module->next)
126    if (strcmp (name, module->file_name) == 0)
127	{
128	  retval = module;
129	  break;
130	}
131
132  return retval;
133}
134
135static inline void
136g_module_set_error_unduped (gchar *error)
137{
138  g_static_private_set (&module_error_private, error, g_free);
139  errno = 0;
140}
141
142static inline void
143g_module_set_error (const gchar *error)
144{
145  g_module_set_error_unduped (g_strdup (error));
146}
147
148
149/* --- include platform specifc code --- */
150#define	SUPPORT_OR_RETURN(rv)	{ g_module_set_error (NULL); }
151#if	(G_MODULE_IMPL == G_MODULE_IMPL_DL)
152#include "gmodule-dl.c"
153#elif	(G_MODULE_IMPL == G_MODULE_IMPL_DLD)
154#include "gmodule-dld.c"
155#elif	(G_MODULE_IMPL == G_MODULE_IMPL_WIN32)
156#include "gmodule-win32.c"
157#elif	(G_MODULE_IMPL == G_MODULE_IMPL_DYLD)
158#include "gmodule-dyld.c"
159#elif	(G_MODULE_IMPL == G_MODULE_IMPL_AR)
160#include "gmodule-ar.c"
161#else
162#undef	SUPPORT_OR_RETURN
163#define	SUPPORT_OR_RETURN(rv)	{ g_module_set_error ("dynamic modules are " \
164                                              "not supported by this system"); return rv; }
165static gpointer
166_g_module_open (const gchar	*file_name,
167		gboolean	 bind_lazy,
168		gboolean	 bind_local)
169{
170  return NULL;
171}
172static void
173_g_module_close	(gpointer	 handle,
174		 gboolean	 is_unref)
175{
176}
177static gpointer
178_g_module_self (void)
179{
180  return NULL;
181}
182static gpointer
183_g_module_symbol (gpointer	 handle,
184		  const gchar	*symbol_name)
185{
186  return NULL;
187}
188static gchar*
189_g_module_build_path (const gchar *directory,
190		      const gchar *module_name)
191{
192  return NULL;
193}
194#endif	/* no implementation */
195
196/* --- functions --- */
197gboolean
198g_module_supported (void)
199{
200  SUPPORT_OR_RETURN (FALSE);
201
202  return TRUE;
203}
204
205static gchar*
206parse_libtool_archive (const gchar* libtool_name)
207{
208  const guint TOKEN_DLNAME = G_TOKEN_LAST + 1;
209  const guint TOKEN_INSTALLED = G_TOKEN_LAST + 2;
210  const guint TOKEN_LIBDIR = G_TOKEN_LAST + 3;
211  gchar *lt_dlname = NULL;
212  gboolean lt_installed = TRUE;
213  gchar *lt_libdir = NULL;
214  gchar *name;
215  GTokenType token;
216  GScanner *scanner;
217
218  int fd = g_open (libtool_name, O_RDONLY, 0);
219  if (fd < 0)
220    {
221      gchar *display_libtool_name = g_filename_display_name (libtool_name);
222      g_module_set_error_unduped (g_strdup_printf ("failed to open libtool archive \"%s\"", display_libtool_name));
223      g_free (display_libtool_name);
224      return NULL;
225    }
226  /* search libtool's dlname specification  */
227  scanner = g_scanner_new (NULL);
228  g_scanner_input_file (scanner, fd);
229  scanner->config->symbol_2_token = TRUE;
230  g_scanner_scope_add_symbol (scanner, 0, "dlname",
231			      GUINT_TO_POINTER (TOKEN_DLNAME));
232  g_scanner_scope_add_symbol (scanner, 0, "installed",
233			      GUINT_TO_POINTER (TOKEN_INSTALLED));
234  g_scanner_scope_add_symbol (scanner, 0, "libdir",
235			      GUINT_TO_POINTER (TOKEN_LIBDIR));
236  while (!g_scanner_eof (scanner))
237    {
238      token = g_scanner_get_next_token (scanner);
239      if (token == TOKEN_DLNAME || token == TOKEN_INSTALLED ||
240	  token == TOKEN_LIBDIR)
241	{
242	  if (g_scanner_get_next_token (scanner) != '=' ||
243	      g_scanner_get_next_token (scanner) !=
244	      (token == TOKEN_INSTALLED ?
245	       G_TOKEN_IDENTIFIER : G_TOKEN_STRING))
246	    {
247	      gchar *display_libtool_name = g_filename_display_name (libtool_name);
248	      g_module_set_error_unduped (g_strdup_printf ("unable to parse libtool archive \"%s\"", display_libtool_name));
249	      g_free (display_libtool_name);
250
251	      g_free (lt_dlname);
252	      g_free (lt_libdir);
253	      g_scanner_destroy (scanner);
254	      close (fd);
255
256	      return NULL;
257	    }
258	  else
259	    {
260	      if (token == TOKEN_DLNAME)
261		{
262		  g_free (lt_dlname);
263		  lt_dlname = g_strdup (scanner->value.v_string);
264		}
265	      else if (token == TOKEN_INSTALLED)
266		lt_installed =
267		  strcmp (scanner->value.v_identifier, "yes") == 0;
268	      else /* token == TOKEN_LIBDIR */
269		{
270		  g_free (lt_libdir);
271		  lt_libdir = g_strdup (scanner->value.v_string);
272		}
273	    }
274	}
275    }
276
277  if (!lt_installed)
278    {
279      gchar *dir = g_path_get_dirname (libtool_name);
280      g_free (lt_libdir);
281      lt_libdir = g_strconcat (dir, G_DIR_SEPARATOR_S ".libs", NULL);
282      g_free (dir);
283    }
284
285  name = g_strconcat (lt_libdir, G_DIR_SEPARATOR_S, lt_dlname, NULL);
286
287  g_free (lt_dlname);
288  g_free (lt_libdir);
289  g_scanner_destroy (scanner);
290  close (fd);
291
292  return name;
293}
294
295static inline gboolean
296str_check_suffix (const gchar* string,
297		  const gchar* suffix)
298{
299  gsize string_len = strlen (string);
300  gsize suffix_len = strlen (suffix);
301
302  return string_len >= suffix_len &&
303    strcmp (string + string_len - suffix_len, suffix) == 0;
304}
305
306enum
307{
308  G_MODULE_DEBUG_RESIDENT_MODULES = 1 << 0,
309  G_MODULE_DEBUG_BIND_NOW_MODULES = 1 << 1
310};
311
312static void
313_g_module_debug_init (void)
314{
315  const GDebugKey keys[] = {
316    { "resident-modules", G_MODULE_DEBUG_RESIDENT_MODULES },
317    { "bind-now-modules", G_MODULE_DEBUG_BIND_NOW_MODULES }
318  };
319  const gchar *env;
320
321  env = g_getenv ("G_DEBUG");
322
323  module_debug_flags =
324    !env ? 0 : g_parse_debug_string (env, keys, G_N_ELEMENTS (keys));
325
326  module_debug_initialized = TRUE;
327}
328
329static GStaticRecMutex g_module_global_lock = G_STATIC_REC_MUTEX_INIT;
330
331GModule*
332g_module_open (const gchar    *file_name,
333	       GModuleFlags    flags)
334{
335  GModule *module;
336  gpointer handle = NULL;
337  gchar *name = NULL;
338
339  SUPPORT_OR_RETURN (NULL);
340
341  g_static_rec_mutex_lock (&g_module_global_lock);
342
343  if (G_UNLIKELY (!module_debug_initialized))
344    _g_module_debug_init ();
345
346  if (module_debug_flags & G_MODULE_DEBUG_BIND_NOW_MODULES)
347    flags &= ~G_MODULE_BIND_LAZY;
348
349  if (!file_name)
350    {
351      if (!main_module)
352	{
353	  handle = _g_module_self ();
354	  if (handle)
355	    {
356	      main_module = g_new (GModule, 1);
357	      main_module->file_name = NULL;
358#if defined (G_OS_WIN32) && !defined(_WIN64)
359	      main_module->cp_file_name = NULL;
360#endif
361	      main_module->handle = handle;
362	      main_module->ref_count = 1;
363	      main_module->is_resident = TRUE;
364	      main_module->unload = NULL;
365	      main_module->next = NULL;
366	    }
367	}
368      else
369	main_module->ref_count++;
370
371      g_static_rec_mutex_unlock (&g_module_global_lock);
372      return main_module;
373    }
374
375  /* we first search the module list by name */
376  module = g_module_find_by_name (file_name);
377  if (module)
378    {
379      module->ref_count++;
380
381      g_static_rec_mutex_unlock (&g_module_global_lock);
382      return module;
383    }
384
385  /* check whether we have a readable file right away */
386  if (g_file_test (file_name, G_FILE_TEST_IS_REGULAR))
387    name = g_strdup (file_name);
388  /* try completing file name with standard library suffix */
389  if (!name)
390    {
391      name = g_strconcat (file_name, "." G_MODULE_SUFFIX, NULL);
392      if (!g_file_test (name, G_FILE_TEST_IS_REGULAR))
393	{
394	  g_free (name);
395	  name = NULL;
396	}
397    }
398  /* try completing by appending libtool suffix */
399  if (!name)
400    {
401      name = g_strconcat (file_name, ".la", NULL);
402      if (!g_file_test (name, G_FILE_TEST_IS_REGULAR))
403	{
404	  g_free (name);
405	  name = NULL;
406	}
407    }
408  /* we can't access() the file, lets hope the platform backends finds
409   * it via library paths
410   */
411  if (!name)
412    {
413      gchar *dot = strrchr (file_name, '.');
414      gchar *slash = strrchr (file_name, G_DIR_SEPARATOR);
415
416      /* make sure the name has a suffix */
417      if (!dot || dot < slash)
418	name = g_strconcat (file_name, "." G_MODULE_SUFFIX, NULL);
419      else
420	name = g_strdup (file_name);
421    }
422
423  /* ok, try loading the module */
424  if (name)
425    {
426      /* if it's a libtool archive, figure library file to load */
427      if (str_check_suffix (name, ".la")) /* libtool archive? */
428	{
429	  gchar *real_name = parse_libtool_archive (name);
430
431	  /* real_name might be NULL, but then module error is already set */
432	  if (real_name)
433	    {
434	      g_free (name);
435	      name = real_name;
436            }
437	}
438      if (name)
439	handle = _g_module_open (name, (flags & G_MODULE_BIND_LAZY) != 0,
440			(flags & G_MODULE_BIND_LOCAL) != 0);
441    }
442  else
443    {
444      gchar *display_file_name = g_filename_display_name (file_name);
445      g_module_set_error_unduped (g_strdup_printf ("unable to access file \"%s\"", display_file_name));
446      g_free (display_file_name);
447    }
448  g_free (name);
449
450  if (handle)
451    {
452      gchar *saved_error;
453      GModuleCheckInit check_init;
454      const gchar *check_failed = NULL;
455
456      /* search the module list by handle, since file names are not unique */
457      module = g_module_find_by_handle (handle);
458      if (module)
459	{
460	  _g_module_close (module->handle, TRUE);
461	  module->ref_count++;
462	  g_module_set_error (NULL);
463
464	  g_static_rec_mutex_unlock (&g_module_global_lock);
465	  return module;
466	}
467
468      saved_error = g_strdup (g_module_error ());
469      g_module_set_error (NULL);
470
471      module = g_new (GModule, 1);
472      module->file_name = g_strdup (file_name);
473#if defined (G_OS_WIN32) && !defined(_WIN64)
474      module->cp_file_name = g_locale_from_utf8 (file_name, -1,
475						 NULL, NULL, NULL);
476#endif
477      module->handle = handle;
478      module->ref_count = 1;
479      module->is_resident = FALSE;
480      module->unload = NULL;
481      module->next = modules;
482      modules = module;
483
484      /* check initialization */
485      if (g_module_symbol (module, "g_module_check_init", (gpointer) &check_init) && check_init != NULL)
486	check_failed = check_init (module);
487
488      /* we don't call unload() if the initialization check failed. */
489      if (!check_failed)
490	g_module_symbol (module, "g_module_unload", (gpointer) &module->unload);
491
492      if (check_failed)
493	{
494	  gchar *error;
495
496	  error = g_strconcat ("GModule (",
497                               file_name ? file_name : "NULL",
498                               ") initialization check failed: ",
499                               check_failed, NULL);
500	  g_module_close (module);
501	  module = NULL;
502	  g_module_set_error (error);
503	  g_free (error);
504	}
505      else
506	g_module_set_error (saved_error);
507
508      g_free (saved_error);
509    }
510
511  if (module != NULL &&
512      (module_debug_flags & G_MODULE_DEBUG_RESIDENT_MODULES))
513    g_module_make_resident (module);
514
515  g_static_rec_mutex_unlock (&g_module_global_lock);
516  return module;
517}
518
519#if defined (G_OS_WIN32) && !defined(_WIN64)
520
521#undef g_module_open
522
523GModule*
524g_module_open (const gchar    *file_name,
525	       GModuleFlags    flags)
526{
527  gchar *utf8_file_name = g_locale_to_utf8 (file_name, -1, NULL, NULL, NULL);
528  GModule *retval = g_module_open_utf8 (utf8_file_name, flags);
529
530  g_free (utf8_file_name);
531
532  return retval;
533}
534
535#endif
536
537gboolean
538g_module_close (GModule	       *module)
539{
540  SUPPORT_OR_RETURN (FALSE);
541
542  g_return_val_if_fail (module != NULL, FALSE);
543  g_return_val_if_fail (module->ref_count > 0, FALSE);
544
545  g_static_rec_mutex_lock (&g_module_global_lock);
546
547  module->ref_count--;
548
549  if (!module->ref_count && !module->is_resident && module->unload)
550    {
551      GModuleUnload unload;
552
553      unload = module->unload;
554      module->unload = NULL;
555      unload (module);
556    }
557
558  if (!module->ref_count && !module->is_resident)
559    {
560      GModule *last;
561      GModule *node;
562
563      last = NULL;
564
565      node = modules;
566      while (node)
567	{
568	  if (node == module)
569	    {
570	      if (last)
571		last->next = node->next;
572	      else
573		modules = node->next;
574	      break;
575	    }
576	  last = node;
577	  node = last->next;
578	}
579      module->next = NULL;
580
581      _g_module_close (module->handle, FALSE);
582      g_free (module->file_name);
583#if defined (G_OS_WIN32) && !defined(_WIN64)
584      g_free (module->cp_file_name);
585#endif
586      g_free (module);
587    }
588
589  g_static_rec_mutex_unlock (&g_module_global_lock);
590  return g_module_error() == NULL;
591}
592
593void
594g_module_make_resident (GModule *module)
595{
596  g_return_if_fail (module != NULL);
597
598  module->is_resident = TRUE;
599}
600
601G_CONST_RETURN gchar*
602g_module_error (void)
603{
604  return g_static_private_get (&module_error_private);
605}
606
607gboolean
608g_module_symbol (GModule	*module,
609		 const gchar	*symbol_name,
610		 gpointer	*symbol)
611{
612  const gchar *module_error;
613
614  if (symbol)
615    *symbol = NULL;
616  SUPPORT_OR_RETURN (FALSE);
617
618  g_return_val_if_fail (module != NULL, FALSE);
619  g_return_val_if_fail (symbol_name != NULL, FALSE);
620  g_return_val_if_fail (symbol != NULL, FALSE);
621
622  g_static_rec_mutex_lock (&g_module_global_lock);
623
624#ifdef	G_MODULE_NEED_USCORE
625  {
626    gchar *name;
627
628    name = g_strconcat ("_", symbol_name, NULL);
629    *symbol = _g_module_symbol (module->handle, name);
630    g_free (name);
631  }
632#else	/* !G_MODULE_NEED_USCORE */
633  *symbol = _g_module_symbol (module->handle, symbol_name);
634#endif	/* !G_MODULE_NEED_USCORE */
635
636  module_error = g_module_error ();
637  if (module_error)
638    {
639      gchar *error;
640
641      error = g_strconcat ("`", symbol_name, "': ", module_error, NULL);
642      g_module_set_error (error);
643      g_free (error);
644      *symbol = NULL;
645    }
646
647  g_static_rec_mutex_unlock (&g_module_global_lock);
648  return !module_error;
649}
650
651G_CONST_RETURN gchar*
652g_module_name (GModule *module)
653{
654  g_return_val_if_fail (module != NULL, NULL);
655
656  if (module == main_module)
657    return "main";
658
659  return module->file_name;
660}
661
662#if defined (G_OS_WIN32) && !defined(_WIN64)
663
664#undef g_module_name
665
666G_CONST_RETURN gchar*
667g_module_name (GModule *module)
668{
669  g_return_val_if_fail (module != NULL, NULL);
670
671  if (module == main_module)
672    return "main";
673
674  return module->cp_file_name;
675}
676
677#endif
678
679gchar*
680g_module_build_path (const gchar *directory,
681		     const gchar *module_name)
682{
683  g_return_val_if_fail (module_name != NULL, NULL);
684
685  return _g_module_build_path (directory, module_name);
686}
687