applied patch from David Schleef <ds@schleef.org> which implements a
[platform/upstream/glib.git] / gmodule / gmodule.c
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 #ifdef HAVE_CONFIG_H
32 # include <config.h>
33 #endif
34 #include        "gmodule.h"
35 #include        "gmoduleconf.h"
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 #if defined (G_OS_WIN32)
45 # include <io.h>                /* For open() and close() prototypes. */
46 #endif
47
48 /* We maintain a list of modules, so we can reference count them.
49  * That's needed because some platforms don't support refernce counts on
50  * modules e.g. the shl_* implementation of HP-UX
51  * (http://www.stat.umn.edu/~luke/xls/projects/dlbasics/dlbasics.html).
52  * Also, the module for the program itself is kept seperatedly for
53  * faster access and because it has special semantics.
54  */
55
56
57 /* --- structures --- */
58 struct _GModule
59 {
60   gchar *file_name;
61   gpointer handle;
62   guint ref_count : 31;
63   guint is_resident : 1;
64   GModuleUnload unload;
65   GModule *next;
66 };
67
68
69 /* --- prototypes --- */
70 static gpointer         _g_module_open          (const gchar    *file_name,
71                                                  gboolean        bind_lazy,
72                                                  gboolean        bind_local);
73 static void             _g_module_close         (gpointer        handle,
74                                                  gboolean        is_unref);
75 static gpointer         _g_module_self          (void);
76 static gpointer         _g_module_symbol        (gpointer        handle,
77                                                  const gchar    *symbol_name);
78 static gchar*           _g_module_build_path    (const gchar    *directory,
79                                                  const gchar    *module_name);
80 static inline void      g_module_set_error      (const gchar    *error);
81 static inline GModule*  g_module_find_by_handle (gpointer        handle);
82 static inline GModule*  g_module_find_by_name   (const gchar    *name);
83
84
85 /* --- variables --- */
86 static GModule       *modules = NULL;
87 static GModule       *main_module = NULL;
88 static GStaticPrivate module_error_private = G_STATIC_PRIVATE_INIT;
89
90
91 /* --- inline functions --- */
92 static inline GModule*
93 g_module_find_by_handle (gpointer handle)
94 {
95   GModule *module;
96   GModule *retval = NULL;
97   
98   if (main_module && main_module->handle == handle)
99     retval = main_module;
100   else
101     for (module = modules; module; module = module->next)
102       if (handle == module->handle)
103         {
104           retval = module;
105           break;
106         }
107
108   return retval;
109 }
110
111 static inline GModule*
112 g_module_find_by_name (const gchar *name)
113 {
114   GModule *module;
115   GModule *retval = NULL;
116   
117   for (module = modules; module; module = module->next)
118     if (strcmp (name, module->file_name) == 0)
119         {
120           retval = module;
121           break;
122         }
123
124   return retval;
125 }
126
127 static inline void
128 g_module_set_error_unduped (gchar *error)
129 {
130   g_static_private_set (&module_error_private, error, g_free);
131   errno = 0;
132 }
133
134 static inline void
135 g_module_set_error (const gchar *error)
136 {
137   g_module_set_error_unduped (g_strdup (error));
138 }
139
140
141 /* --- include platform specifc code --- */
142 #define SUPPORT_OR_RETURN(rv)   { g_module_set_error (NULL); }
143 #if     (G_MODULE_IMPL == G_MODULE_IMPL_DL)
144 #include "gmodule-dl.c"
145 #elif   (G_MODULE_IMPL == G_MODULE_IMPL_DLD)
146 #include "gmodule-dld.c"
147 #elif   (G_MODULE_IMPL == G_MODULE_IMPL_WIN32)
148 #include "gmodule-win32.c"
149 #elif   (G_MODULE_IMPL == G_MODULE_IMPL_DYLD)
150 #include "gmodule-dyld.c"
151 #else
152 #undef  SUPPORT_OR_RETURN
153 #define SUPPORT_OR_RETURN(rv)   { g_module_set_error ("dynamic modules are " \
154                                               "not supported by this system"); return rv; }
155 static gpointer
156 _g_module_open (const gchar     *file_name,
157                 gboolean         bind_lazy,
158                 gboolean         bind_local)
159 {
160   return NULL;
161 }
162 static void
163 _g_module_close (gpointer        handle,
164                  gboolean        is_unref)
165 {
166 }
167 static gpointer
168 _g_module_self (void)
169 {
170   return NULL;
171 }
172 static gpointer
173 _g_module_symbol (gpointer       handle,
174                   const gchar   *symbol_name)
175 {
176   return NULL;
177 }
178 static gchar*
179 _g_module_build_path (const gchar *directory,
180                       const gchar *module_name)
181 {
182   return NULL;
183 }
184 #endif  /* no implementation */
185
186 /* --- functions --- */
187 gboolean
188 g_module_supported (void)
189 {
190   SUPPORT_OR_RETURN (FALSE);
191   
192   return TRUE;
193 }
194
195 static gchar*
196 parse_libtool_archive (const gchar* libtool_name)
197 {
198   const gint TOKEN_DLNAME = G_TOKEN_LAST + 1;
199   const gint TOKEN_INSTALLED = G_TOKEN_LAST + 2;
200   const gint TOKEN_LIBDIR = G_TOKEN_LAST + 3;
201   gchar *lt_dlname = NULL;
202   gboolean lt_installed = TRUE;
203   gchar *lt_libdir = NULL;
204   gchar *name;
205   GTokenType token;
206   GScanner *scanner;
207   
208   int fd = open (libtool_name, O_RDONLY, 0);
209   if (fd < 0)
210     {
211       g_module_set_error_unduped (g_strdup_printf ("failed to open libtool archive \"%s\"", libtool_name));   
212       return NULL;
213     }
214   /* search libtool's dlname specification  */
215   scanner = g_scanner_new (NULL);
216   g_scanner_input_file (scanner, fd);
217   scanner->config->symbol_2_token = TRUE;
218   g_scanner_scope_add_symbol (scanner, 0, "dlname", 
219                               GUINT_TO_POINTER (TOKEN_DLNAME));
220   g_scanner_scope_add_symbol (scanner, 0, "installed", 
221                               GUINT_TO_POINTER (TOKEN_INSTALLED));
222   g_scanner_scope_add_symbol (scanner, 0, "libdir", 
223                               GUINT_TO_POINTER (TOKEN_LIBDIR));
224   while (!g_scanner_eof (scanner))
225     {
226       token = g_scanner_get_next_token (scanner);
227       if (token == TOKEN_DLNAME || token == TOKEN_INSTALLED || 
228           token == TOKEN_LIBDIR)
229         {
230           if (g_scanner_get_next_token (scanner) != '=' ||
231               g_scanner_get_next_token (scanner) != 
232               (token == TOKEN_INSTALLED ? 
233                G_TOKEN_IDENTIFIER : G_TOKEN_STRING))
234             {
235               g_module_set_error_unduped (g_strdup_printf ("unable to parse libtool archive \"%s\"", libtool_name));
236
237               g_free (lt_dlname);
238               g_free (lt_libdir);
239               g_scanner_destroy (scanner);
240               close (fd);
241
242               return NULL;
243             }
244           else
245             {
246               if (token == TOKEN_DLNAME)
247                 {
248                   g_free (lt_dlname);
249                   lt_dlname = g_strdup (scanner->value.v_string);
250                 }
251               else if (token == TOKEN_INSTALLED)
252                 lt_installed = 
253                   strcmp (scanner->value.v_identifier, "yes") == 0;
254               else /* token == TOKEN_LIBDIR */
255                 {
256                   g_free (lt_libdir);
257                   lt_libdir = g_strdup (scanner->value.v_string);
258                 }
259             }
260         }      
261     }
262
263   if (!lt_installed)
264     {
265       gchar *dir = g_path_get_dirname (libtool_name);
266       g_free (lt_libdir);
267       lt_libdir = g_strconcat (dir, G_DIR_SEPARATOR_S ".libs", NULL);
268       g_free (dir);
269     }
270
271   name = g_strconcat (lt_libdir, G_DIR_SEPARATOR_S, lt_dlname, NULL);
272   
273   g_free (lt_dlname);
274   g_free (lt_libdir);
275   g_scanner_destroy (scanner);
276   close (fd);
277
278   return name;
279 }
280
281 static inline gboolean
282 str_check_suffix (const gchar* string,
283                   const gchar* suffix)
284 {
285   gsize string_len = strlen (string);    
286   gsize suffix_len = strlen (suffix);    
287
288   return string_len >= suffix_len && 
289     strcmp (string + string_len - suffix_len, suffix) == 0;
290 }
291
292 static GStaticRecMutex g_module_global_lock = G_STATIC_REC_MUTEX_INIT;
293
294 GModule*
295 g_module_open (const gchar    *file_name,
296                GModuleFlags    flags)
297 {
298   GModule *module;
299   gpointer handle = NULL;
300   gchar *name = NULL;
301   
302   SUPPORT_OR_RETURN (NULL);
303   
304   g_static_rec_mutex_lock (&g_module_global_lock);
305   if (!file_name)
306     {      
307       if (!main_module)
308         {
309           handle = _g_module_self ();
310           if (handle)
311             {
312               main_module = g_new (GModule, 1);
313               main_module->file_name = NULL;
314               main_module->handle = handle;
315               main_module->ref_count = 1;
316               main_module->is_resident = TRUE;
317               main_module->unload = NULL;
318               main_module->next = NULL;
319             }
320         }
321       else
322         main_module->ref_count++;
323
324       g_static_rec_mutex_unlock (&g_module_global_lock);
325       return main_module;
326     }
327   
328   /* we first search the module list by name */
329   module = g_module_find_by_name (file_name);
330   if (module)
331     {
332       module->ref_count++;
333       
334       g_static_rec_mutex_unlock (&g_module_global_lock);
335       return module;
336     }
337
338   /* check whether we have a readable file right away */
339   if (g_file_test (file_name, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
340     name = g_strdup (file_name);
341   /* try completing file name with standard library suffix */
342   if (!name)
343     {
344       name = g_strconcat (file_name, "." G_MODULE_SUFFIX, NULL);
345       if (!g_file_test (name, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
346         {
347           g_free (name);
348           name = NULL;
349         }
350     }
351   /* try completing by appending libtool suffix */
352   if (!name)
353     {
354       name = g_strconcat (file_name, ".la", NULL);
355       if (!g_file_test (name, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
356         {
357           g_free (name);
358           name = NULL;
359         }
360     }
361   /* we can't access() the file, lets hope the platform backends finds
362    * it via library paths
363    */
364   if (!name)
365     {
366       gchar *dot = strrchr (file_name, '.');
367       gchar *slash = strrchr (file_name, G_DIR_SEPARATOR);
368       
369       /* make sure the name has a suffix */
370       if (!dot || dot < slash)
371         name = g_strconcat (file_name, "." G_MODULE_SUFFIX, NULL);
372       else
373         name = g_strdup (file_name);
374     }
375
376   /* ok, try loading the module */
377   if (name)
378     {
379       /* if it's a libtool archive, figure library file to load */
380       if (str_check_suffix (name, ".la")) /* libtool archive? */
381         {
382           gchar *real_name = parse_libtool_archive (name);
383
384           /* real_name might be NULL, but then module error is already set */
385           g_free (name);
386           name = real_name;
387         }
388       if (name)
389         handle = _g_module_open (name, (flags & G_MODULE_BIND_LAZY) != 0,
390                         (flags & G_MODULE_BIND_LOCAL) != 0);
391     }
392   else
393     g_module_set_error_unduped (g_strdup_printf ("unable to access file \"%s\"", file_name));
394   g_free (name);
395
396   if (handle)
397     {
398       gchar *saved_error;
399       GModuleCheckInit check_init;
400       const gchar *check_failed = NULL;
401       
402       /* search the module list by handle, since file names are not unique */
403       module = g_module_find_by_handle (handle);
404       if (module)
405         {
406           _g_module_close (module->handle, TRUE);
407           module->ref_count++;
408           g_module_set_error (NULL);
409           
410           g_static_rec_mutex_unlock (&g_module_global_lock);
411           return module;
412         }
413       
414       saved_error = g_strdup (g_module_error ());
415       g_module_set_error (NULL);
416       
417       module = g_new (GModule, 1);
418       module->file_name = g_strdup (file_name);
419       module->handle = handle;
420       module->ref_count = 1;
421       module->is_resident = FALSE;
422       module->unload = NULL;
423       module->next = modules;
424       modules = module;
425       
426       /* check initialization */
427       if (g_module_symbol (module, "g_module_check_init", (gpointer) &check_init))
428         check_failed = check_init (module);
429       
430       /* we don't call unload() if the initialization check failed. */
431       if (!check_failed)
432         g_module_symbol (module, "g_module_unload", (gpointer) &module->unload);
433       
434       if (check_failed)
435         {
436           gchar *error;
437
438           error = g_strconcat ("GModule initialization check failed: ", check_failed, NULL);
439           g_module_close (module);
440           module = NULL;
441           g_module_set_error (error);
442           g_free (error);
443         }
444       else
445         g_module_set_error (saved_error);
446
447       g_free (saved_error);
448     }
449
450   g_static_rec_mutex_unlock (&g_module_global_lock);
451   return module;
452 }
453
454 gboolean
455 g_module_close (GModule        *module)
456 {
457   SUPPORT_OR_RETURN (FALSE);
458   
459   g_return_val_if_fail (module != NULL, FALSE);
460   g_return_val_if_fail (module->ref_count > 0, FALSE);
461   
462   g_static_rec_mutex_lock (&g_module_global_lock);
463
464   module->ref_count--;
465   
466   if (!module->ref_count && !module->is_resident && module->unload)
467     {
468       GModuleUnload unload;
469
470       unload = module->unload;
471       module->unload = NULL;
472       unload (module);
473     }
474
475   if (!module->ref_count && !module->is_resident)
476     {
477       GModule *last;
478       GModule *node;
479       
480       last = NULL;
481       
482       node = modules;
483       while (node)
484         {
485           if (node == module)
486             {
487               if (last)
488                 last->next = node->next;
489               else
490                 modules = node->next;
491               break;
492             }
493           last = node;
494           node = last->next;
495         }
496       module->next = NULL;
497       
498       _g_module_close (module->handle, FALSE);
499       g_free (module->file_name);
500       
501       g_free (module);
502     }
503   
504   g_static_rec_mutex_unlock (&g_module_global_lock);
505   return g_module_error() == NULL;
506 }
507
508 void
509 g_module_make_resident (GModule *module)
510 {
511   g_return_if_fail (module != NULL);
512
513   module->is_resident = TRUE;
514 }
515
516 G_CONST_RETURN gchar*
517 g_module_error (void)
518 {
519   return g_static_private_get (&module_error_private);
520 }
521
522 gboolean
523 g_module_symbol (GModule        *module,
524                  const gchar    *symbol_name,
525                  gpointer       *symbol)
526 {
527   const gchar *module_error;
528
529   if (symbol)
530     *symbol = NULL;
531   SUPPORT_OR_RETURN (FALSE);
532   
533   g_return_val_if_fail (module != NULL, FALSE);
534   g_return_val_if_fail (symbol_name != NULL, FALSE);
535   g_return_val_if_fail (symbol != NULL, FALSE);
536   
537   g_static_rec_mutex_lock (&g_module_global_lock);
538
539 #ifdef  G_MODULE_NEED_USCORE
540   {
541     gchar *name;
542
543     name = g_strconcat ("_", symbol_name, NULL);
544     *symbol = _g_module_symbol (module->handle, name);
545     g_free (name);
546   }
547 #else   /* !G_MODULE_NEED_USCORE */
548   *symbol = _g_module_symbol (module->handle, symbol_name);
549 #endif  /* !G_MODULE_NEED_USCORE */
550   
551   module_error = g_module_error ();
552   if (module_error)
553     {
554       gchar *error;
555
556       error = g_strconcat ("`", symbol_name, "': ", module_error, NULL);
557       g_module_set_error (error);
558       g_free (error);
559       *symbol = NULL;
560     }
561   
562   g_static_rec_mutex_unlock (&g_module_global_lock);
563   return !module_error;
564 }
565
566 G_CONST_RETURN gchar*
567 g_module_name (GModule *module)
568 {
569   g_return_val_if_fail (module != NULL, NULL);
570   
571   if (module == main_module)
572     return "main";
573   
574   return module->file_name;
575 }
576
577 gchar*
578 g_module_build_path (const gchar *directory,
579                      const gchar *module_name)
580 {
581   g_return_val_if_fail (module_name != NULL, NULL);
582   
583   return _g_module_build_path (directory, module_name);
584 }