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.1 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, see <http://www.gnu.org/licenses/>. |
16 | */ |
17 | |
18 | /* |
19 | * Modified by the GLib Team and others 1997-2000. See the AUTHORS |
20 | * file for a list of people on the GLib Team. See the ChangeLog |
21 | * files for a list of changes. These files are distributed with |
22 | * GLib at ftp://ftp.gtk.org/pub/gtk/. |
23 | */ |
24 | |
25 | /* |
26 | * MT safe |
27 | */ |
28 | |
29 | #include "config.h" |
30 | |
31 | #include "glib.h" |
32 | #include "gmodule.h" |
33 | |
34 | #include <errno.h> |
35 | #include <string.h> |
36 | #include <sys/types.h> |
37 | #include <sys/stat.h> |
38 | #include <fcntl.h> |
39 | #ifdef G_OS_UNIX |
40 | #include <unistd.h> |
41 | #endif |
42 | #ifdef G_OS_WIN32 |
43 | #include <io.h> /* For open() and close() prototypes. */ |
44 | #endif |
45 | |
46 | #include "gmoduleconf.h" |
47 | #include "gstdio.h" |
48 | |
49 | /** |
50 | * SECTION:modules |
51 | * @title: Dynamic Loading of Modules |
52 | * @short_description: portable method for dynamically loading 'plug-ins' |
53 | * |
54 | * These functions provide a portable way to dynamically load object files |
55 | * (commonly known as 'plug-ins'). The current implementation supports all |
56 | * systems that provide an implementation of dlopen() (e.g. Linux/Sun), as |
57 | * well as Windows platforms via DLLs. |
58 | * |
59 | * A program which wants to use these functions must be linked to the |
60 | * libraries output by the command `pkg-config --libs gmodule-2.0`. |
61 | * |
62 | * To use them you must first determine whether dynamic loading |
63 | * is supported on the platform by calling g_module_supported(). |
64 | * If it is, you can open a module with g_module_open(), |
65 | * find the module's symbols (e.g. function names) with g_module_symbol(), |
66 | * and later close the module with g_module_close(). |
67 | * g_module_name() will return the file name of a currently opened module. |
68 | * |
69 | * If any of the above functions fail, the error status can be found with |
70 | * g_module_error(). |
71 | * |
72 | * The #GModule implementation features reference counting for opened modules, |
73 | * and supports hook functions within a module which are called when the |
74 | * module is loaded and unloaded (see #GModuleCheckInit and #GModuleUnload). |
75 | * |
76 | * If your module introduces static data to common subsystems in the running |
77 | * program, e.g. through calling |
78 | * `g_quark_from_static_string ("my-module-stuff")`, |
79 | * it must ensure that it is never unloaded, by calling g_module_make_resident(). |
80 | * |
81 | * Example: Calling a function defined in a GModule |
82 | * |[<!-- language="C" --> |
83 | * // the function signature for 'say_hello' |
84 | * typedef void (* SayHelloFunc) (const char *message); |
85 | * |
86 | * gboolean |
87 | * just_say_hello (const char *filename, GError **error) |
88 | * { |
89 | * SayHelloFunc say_hello; |
90 | * GModule *module; |
91 | * |
92 | * module = g_module_open (filename, G_MODULE_BIND_LAZY); |
93 | * if (!module) |
94 | * { |
95 | * g_set_error (error, FOO_ERROR, FOO_ERROR_BLAH, |
96 | * "%s", g_module_error ()); |
97 | * return FALSE; |
98 | * } |
99 | * |
100 | * if (!g_module_symbol (module, "say_hello", (gpointer *)&say_hello)) |
101 | * { |
102 | * g_set_error (error, SAY_ERROR, SAY_ERROR_OPEN, |
103 | * "%s: %s", filename, g_module_error ()); |
104 | * if (!g_module_close (module)) |
105 | * g_warning ("%s: %s", filename, g_module_error ()); |
106 | * return FALSE; |
107 | * } |
108 | * |
109 | * if (say_hello == NULL) |
110 | * { |
111 | * g_set_error (error, SAY_ERROR, SAY_ERROR_OPEN, |
112 | * "symbol say_hello is NULL"); |
113 | * if (!g_module_close (module)) |
114 | * g_warning ("%s: %s", filename, g_module_error ()); |
115 | * return FALSE; |
116 | * } |
117 | * |
118 | * // call our function in the module |
119 | * say_hello ("Hello world!"); |
120 | * |
121 | * if (!g_module_close (module)) |
122 | * g_warning ("%s: %s", filename, g_module_error ()); |
123 | * return TRUE; |
124 | * } |
125 | * ]| |
126 | */ |
127 | |
128 | /** |
129 | * GModule: |
130 | * |
131 | * The #GModule struct is an opaque data structure to represent a |
132 | * [dynamically-loaded module][glib-Dynamic-Loading-of-Modules]. |
133 | * It should only be accessed via the following functions. |
134 | */ |
135 | |
136 | /** |
137 | * GModuleCheckInit: |
138 | * @module: the #GModule corresponding to the module which has just been loaded |
139 | * |
140 | * Specifies the type of the module initialization function. |
141 | * If a module contains a function named g_module_check_init() it is called |
142 | * automatically when the module is loaded. It is passed the #GModule structure |
143 | * and should return %NULL on success or a string describing the initialization |
144 | * error. |
145 | * |
146 | * Returns: %NULL on success, or a string describing the initialization error |
147 | */ |
148 | |
149 | /** |
150 | * GModuleUnload: |
151 | * @module: the #GModule about to be unloaded |
152 | * |
153 | * Specifies the type of the module function called when it is unloaded. |
154 | * If a module contains a function named g_module_unload() it is called |
155 | * automatically when the module is unloaded. |
156 | * It is passed the #GModule structure. |
157 | */ |
158 | |
159 | /** |
160 | * G_MODULE_SUFFIX: |
161 | * |
162 | * Expands to the proper shared library suffix for the current platform |
163 | * without the leading dot. For most Unices and Linux this is "so", and |
164 | * for Windows this is "dll". |
165 | */ |
166 | |
167 | /** |
168 | * G_MODULE_EXPORT: |
169 | * |
170 | * Used to declare functions exported by libraries or modules. |
171 | * |
172 | * When compiling for Windows, it marks the symbol as `dllexport`. |
173 | * |
174 | * When compiling for Linux and Unices, it marks the symbol as having `default` |
175 | * visibility. This is no-op unless the code is being compiled with a |
176 | * non-default |
177 | * [visibility flag](https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#index-fvisibility-1260) |
178 | * such as `hidden`. |
179 | */ |
180 | |
181 | /** |
182 | * G_MODULE_IMPORT: |
183 | * |
184 | * Used to declare functions imported from modules. |
185 | */ |
186 | |
187 | /* We maintain a list of modules, so we can reference count them. |
188 | * That's needed because some platforms don't support references counts on |
189 | * modules. Also, the module for the program itself is kept separately for |
190 | * faster access and because it has special semantics. |
191 | */ |
192 | |
193 | |
194 | /* --- structures --- */ |
195 | struct _GModule |
196 | { |
197 | gchar *file_name; |
198 | gpointer handle; |
199 | guint ref_count : 31; |
200 | guint is_resident : 1; |
201 | GModuleUnload unload; |
202 | GModule *next; |
203 | }; |
204 | |
205 | |
206 | /* --- prototypes --- */ |
207 | static gpointer _g_module_open (const gchar *file_name, |
208 | gboolean bind_lazy, |
209 | gboolean bind_local); |
210 | static void _g_module_close (gpointer handle); |
211 | static gpointer _g_module_self (void); |
212 | static gpointer _g_module_symbol (gpointer handle, |
213 | const gchar *symbol_name); |
214 | static gchar* _g_module_build_path (const gchar *directory, |
215 | const gchar *module_name); |
216 | static inline void g_module_set_error (const gchar *error); |
217 | static inline GModule* g_module_find_by_handle (gpointer handle); |
218 | static inline GModule* g_module_find_by_name (const gchar *name); |
219 | |
220 | |
221 | /* --- variables --- */ |
222 | static GModule *modules = NULL; |
223 | static GModule *main_module = NULL; |
224 | static GPrivate module_error_private = G_PRIVATE_INIT (g_free); |
225 | static gboolean module_debug_initialized = FALSE; |
226 | static guint module_debug_flags = 0; |
227 | |
228 | |
229 | /* --- inline functions --- */ |
230 | static inline GModule* |
231 | g_module_find_by_handle (gpointer handle) |
232 | { |
233 | GModule *module; |
234 | GModule *retval = NULL; |
235 | |
236 | if (main_module && main_module->handle == handle) |
237 | retval = main_module; |
238 | else |
239 | for (module = modules; module; module = module->next) |
240 | if (handle == module->handle) |
241 | { |
242 | retval = module; |
243 | break; |
244 | } |
245 | |
246 | return retval; |
247 | } |
248 | |
249 | static inline GModule* |
250 | g_module_find_by_name (const gchar *name) |
251 | { |
252 | GModule *module; |
253 | GModule *retval = NULL; |
254 | |
255 | for (module = modules; module; module = module->next) |
256 | if (strcmp (s1: name, s2: module->file_name) == 0) |
257 | { |
258 | retval = module; |
259 | break; |
260 | } |
261 | |
262 | return retval; |
263 | } |
264 | |
265 | static inline void |
266 | g_module_set_error_unduped (gchar *error) |
267 | { |
268 | g_private_replace (key: &module_error_private, value: error); |
269 | errno = 0; |
270 | } |
271 | |
272 | static inline void |
273 | g_module_set_error (const gchar *error) |
274 | { |
275 | g_module_set_error_unduped (error: g_strdup (str: error)); |
276 | } |
277 | |
278 | |
279 | /* --- include platform specific code --- */ |
280 | #define SUPPORT_OR_RETURN(rv) { g_module_set_error (NULL); } |
281 | #if (G_MODULE_IMPL == G_MODULE_IMPL_DL) |
282 | #include "gmodule-dl.c" |
283 | #elif (G_MODULE_IMPL == G_MODULE_IMPL_WIN32) |
284 | #include "gmodule-win32.c" |
285 | #elif (G_MODULE_IMPL == G_MODULE_IMPL_AR) |
286 | #include "gmodule-ar.c" |
287 | #else |
288 | #undef SUPPORT_OR_RETURN |
289 | #define SUPPORT_OR_RETURN(rv) { g_module_set_error ("dynamic modules are " \ |
290 | "not supported by this system"); return rv; } |
291 | static gpointer |
292 | _g_module_open (const gchar *file_name, |
293 | gboolean bind_lazy, |
294 | gboolean bind_local) |
295 | { |
296 | return NULL; |
297 | } |
298 | static void |
299 | _g_module_close (gpointer handle) |
300 | { |
301 | } |
302 | static gpointer |
303 | _g_module_self (void) |
304 | { |
305 | return NULL; |
306 | } |
307 | static gpointer |
308 | _g_module_symbol (gpointer handle, |
309 | const gchar *symbol_name) |
310 | { |
311 | return NULL; |
312 | } |
313 | static gchar* |
314 | _g_module_build_path (const gchar *directory, |
315 | const gchar *module_name) |
316 | { |
317 | return NULL; |
318 | } |
319 | #endif /* no implementation */ |
320 | |
321 | /* --- functions --- */ |
322 | |
323 | /** |
324 | * g_module_supported: |
325 | * |
326 | * Checks if modules are supported on the current platform. |
327 | * |
328 | * Returns: %TRUE if modules are supported |
329 | */ |
330 | gboolean |
331 | g_module_supported (void) |
332 | { |
333 | SUPPORT_OR_RETURN (FALSE); |
334 | |
335 | return TRUE; |
336 | } |
337 | |
338 | static gchar* |
339 | parse_libtool_archive (const gchar* libtool_name) |
340 | { |
341 | const guint TOKEN_DLNAME = G_TOKEN_LAST + 1; |
342 | const guint TOKEN_INSTALLED = G_TOKEN_LAST + 2; |
343 | const guint TOKEN_LIBDIR = G_TOKEN_LAST + 3; |
344 | gchar *lt_dlname = NULL; |
345 | gboolean lt_installed = TRUE; |
346 | gchar *lt_libdir = NULL; |
347 | gchar *name; |
348 | GTokenType token; |
349 | GScanner *scanner; |
350 | |
351 | int fd = g_open (file: libtool_name, O_RDONLY, 0); |
352 | if (fd < 0) |
353 | { |
354 | gchar *display_libtool_name = g_filename_display_name (filename: libtool_name); |
355 | g_module_set_error_unduped (error: g_strdup_printf (format: "failed to open libtool archive \"%s\"" , display_libtool_name)); |
356 | g_free (mem: display_libtool_name); |
357 | return NULL; |
358 | } |
359 | /* search libtool's dlname specification */ |
360 | scanner = g_scanner_new (NULL); |
361 | g_scanner_input_file (scanner, input_fd: fd); |
362 | scanner->config->symbol_2_token = TRUE; |
363 | g_scanner_scope_add_symbol (scanner, scope_id: 0, symbol: "dlname" , |
364 | GUINT_TO_POINTER (TOKEN_DLNAME)); |
365 | g_scanner_scope_add_symbol (scanner, scope_id: 0, symbol: "installed" , |
366 | GUINT_TO_POINTER (TOKEN_INSTALLED)); |
367 | g_scanner_scope_add_symbol (scanner, scope_id: 0, symbol: "libdir" , |
368 | GUINT_TO_POINTER (TOKEN_LIBDIR)); |
369 | while (!g_scanner_eof (scanner)) |
370 | { |
371 | token = g_scanner_get_next_token (scanner); |
372 | if (token == TOKEN_DLNAME || token == TOKEN_INSTALLED || |
373 | token == TOKEN_LIBDIR) |
374 | { |
375 | if (g_scanner_get_next_token (scanner) != '=' || |
376 | g_scanner_get_next_token (scanner) != |
377 | (token == TOKEN_INSTALLED ? |
378 | G_TOKEN_IDENTIFIER : G_TOKEN_STRING)) |
379 | { |
380 | gchar *display_libtool_name = g_filename_display_name (filename: libtool_name); |
381 | g_module_set_error_unduped (error: g_strdup_printf (format: "unable to parse libtool archive \"%s\"" , display_libtool_name)); |
382 | g_free (mem: display_libtool_name); |
383 | |
384 | g_free (mem: lt_dlname); |
385 | g_free (mem: lt_libdir); |
386 | g_scanner_destroy (scanner); |
387 | close (fd: fd); |
388 | |
389 | return NULL; |
390 | } |
391 | else |
392 | { |
393 | if (token == TOKEN_DLNAME) |
394 | { |
395 | g_free (mem: lt_dlname); |
396 | lt_dlname = g_strdup (str: scanner->value.v_string); |
397 | } |
398 | else if (token == TOKEN_INSTALLED) |
399 | lt_installed = |
400 | strcmp (s1: scanner->value.v_identifier, s2: "yes" ) == 0; |
401 | else /* token == TOKEN_LIBDIR */ |
402 | { |
403 | g_free (mem: lt_libdir); |
404 | lt_libdir = g_strdup (str: scanner->value.v_string); |
405 | } |
406 | } |
407 | } |
408 | } |
409 | |
410 | if (!lt_installed) |
411 | { |
412 | gchar *dir = g_path_get_dirname (file_name: libtool_name); |
413 | g_free (mem: lt_libdir); |
414 | lt_libdir = g_strconcat (string1: dir, G_DIR_SEPARATOR_S ".libs" , NULL); |
415 | g_free (mem: dir); |
416 | } |
417 | |
418 | name = g_strconcat (string1: lt_libdir, G_DIR_SEPARATOR_S, lt_dlname, NULL); |
419 | |
420 | g_free (mem: lt_dlname); |
421 | g_free (mem: lt_libdir); |
422 | g_scanner_destroy (scanner); |
423 | close (fd: fd); |
424 | |
425 | return name; |
426 | } |
427 | |
428 | static inline gboolean |
429 | str_check_suffix (const gchar* string, |
430 | const gchar* suffix) |
431 | { |
432 | gsize string_len = strlen (s: string); |
433 | gsize suffix_len = strlen (s: suffix); |
434 | |
435 | return string_len >= suffix_len && |
436 | strcmp (s1: string + string_len - suffix_len, s2: suffix) == 0; |
437 | } |
438 | |
439 | enum |
440 | { |
441 | G_MODULE_DEBUG_RESIDENT_MODULES = 1 << 0, |
442 | G_MODULE_DEBUG_BIND_NOW_MODULES = 1 << 1 |
443 | }; |
444 | |
445 | static void |
446 | _g_module_debug_init (void) |
447 | { |
448 | const GDebugKey keys[] = { |
449 | { "resident-modules" , G_MODULE_DEBUG_RESIDENT_MODULES }, |
450 | { "bind-now-modules" , G_MODULE_DEBUG_BIND_NOW_MODULES } |
451 | }; |
452 | const gchar *env; |
453 | |
454 | env = g_getenv (variable: "G_DEBUG" ); |
455 | |
456 | module_debug_flags = |
457 | !env ? 0 : g_parse_debug_string (string: env, keys, G_N_ELEMENTS (keys)); |
458 | |
459 | module_debug_initialized = TRUE; |
460 | } |
461 | |
462 | static GRecMutex g_module_global_lock; |
463 | |
464 | /** |
465 | * g_module_open: |
466 | * @file_name: (nullable): the name of the file containing the module, or %NULL |
467 | * to obtain a #GModule representing the main program itself |
468 | * @flags: the flags used for opening the module. This can be the |
469 | * logical OR of any of the #GModuleFlags |
470 | * |
471 | * Opens a module. If the module has already been opened, |
472 | * its reference count is incremented. |
473 | * |
474 | * First of all g_module_open() tries to open @file_name as a module. |
475 | * If that fails and @file_name has the ".la"-suffix (and is a libtool |
476 | * archive) it tries to open the corresponding module. If that fails |
477 | * and it doesn't have the proper module suffix for the platform |
478 | * (#G_MODULE_SUFFIX), this suffix will be appended and the corresponding |
479 | * module will be opened. If that fails and @file_name doesn't have the |
480 | * ".la"-suffix, this suffix is appended and g_module_open() tries to open |
481 | * the corresponding module. If eventually that fails as well, %NULL is |
482 | * returned. |
483 | * |
484 | * Returns: a #GModule on success, or %NULL on failure |
485 | */ |
486 | GModule* |
487 | g_module_open (const gchar *file_name, |
488 | GModuleFlags flags) |
489 | { |
490 | GModule *module; |
491 | gpointer handle = NULL; |
492 | gchar *name = NULL; |
493 | |
494 | SUPPORT_OR_RETURN (NULL); |
495 | |
496 | g_rec_mutex_lock (rec_mutex: &g_module_global_lock); |
497 | |
498 | if (G_UNLIKELY (!module_debug_initialized)) |
499 | _g_module_debug_init (); |
500 | |
501 | if (module_debug_flags & G_MODULE_DEBUG_BIND_NOW_MODULES) |
502 | flags &= ~G_MODULE_BIND_LAZY; |
503 | |
504 | if (!file_name) |
505 | { |
506 | if (!main_module) |
507 | { |
508 | handle = _g_module_self (); |
509 | /* On Android 64 bit, RTLD_DEFAULT is (void *)0x0 |
510 | * so it always fails to create main_module if file_name is NULL */ |
511 | #if !defined(__BIONIC__) || !defined(__LP64__) |
512 | if (handle) |
513 | #endif |
514 | { |
515 | main_module = g_new (GModule, 1); |
516 | main_module->file_name = NULL; |
517 | main_module->handle = handle; |
518 | main_module->ref_count = 1; |
519 | main_module->is_resident = TRUE; |
520 | main_module->unload = NULL; |
521 | main_module->next = NULL; |
522 | } |
523 | } |
524 | else |
525 | main_module->ref_count++; |
526 | |
527 | g_rec_mutex_unlock (rec_mutex: &g_module_global_lock); |
528 | return main_module; |
529 | } |
530 | |
531 | /* we first search the module list by name */ |
532 | module = g_module_find_by_name (name: file_name); |
533 | if (module) |
534 | { |
535 | module->ref_count++; |
536 | |
537 | g_rec_mutex_unlock (rec_mutex: &g_module_global_lock); |
538 | return module; |
539 | } |
540 | |
541 | /* check whether we have a readable file right away */ |
542 | if (g_file_test (filename: file_name, test: G_FILE_TEST_IS_REGULAR)) |
543 | name = g_strdup (str: file_name); |
544 | /* try completing file name with standard library suffix */ |
545 | if (!name) |
546 | { |
547 | name = g_strconcat (string1: file_name, "." G_MODULE_SUFFIX, NULL); |
548 | if (!g_file_test (filename: name, test: G_FILE_TEST_IS_REGULAR)) |
549 | { |
550 | g_free (mem: name); |
551 | name = NULL; |
552 | } |
553 | } |
554 | /* try completing by appending libtool suffix */ |
555 | if (!name) |
556 | { |
557 | name = g_strconcat (string1: file_name, ".la" , NULL); |
558 | if (!g_file_test (filename: name, test: G_FILE_TEST_IS_REGULAR)) |
559 | { |
560 | g_free (mem: name); |
561 | name = NULL; |
562 | } |
563 | } |
564 | /* we can't access() the file, lets hope the platform backends finds |
565 | * it via library paths |
566 | */ |
567 | if (!name) |
568 | { |
569 | gchar *dot = strrchr (s: file_name, c: '.'); |
570 | gchar *slash = strrchr (s: file_name, G_DIR_SEPARATOR); |
571 | |
572 | /* make sure the name has a suffix */ |
573 | if (!dot || dot < slash) |
574 | name = g_strconcat (string1: file_name, "." G_MODULE_SUFFIX, NULL); |
575 | else |
576 | name = g_strdup (str: file_name); |
577 | } |
578 | |
579 | /* ok, try loading the module */ |
580 | if (name) |
581 | { |
582 | /* if it's a libtool archive, figure library file to load */ |
583 | if (str_check_suffix (string: name, suffix: ".la" )) /* libtool archive? */ |
584 | { |
585 | gchar *real_name = parse_libtool_archive (libtool_name: name); |
586 | |
587 | /* real_name might be NULL, but then module error is already set */ |
588 | if (real_name) |
589 | { |
590 | g_free (mem: name); |
591 | name = real_name; |
592 | } |
593 | } |
594 | if (name) |
595 | handle = _g_module_open (file_name: name, bind_lazy: (flags & G_MODULE_BIND_LAZY) != 0, |
596 | bind_local: (flags & G_MODULE_BIND_LOCAL) != 0); |
597 | } |
598 | else |
599 | { |
600 | gchar *display_file_name = g_filename_display_name (filename: file_name); |
601 | g_module_set_error_unduped (error: g_strdup_printf (format: "unable to access file \"%s\"" , display_file_name)); |
602 | g_free (mem: display_file_name); |
603 | } |
604 | g_free (mem: name); |
605 | |
606 | if (handle) |
607 | { |
608 | gchar *saved_error; |
609 | GModuleCheckInit check_init; |
610 | const gchar *check_failed = NULL; |
611 | |
612 | /* search the module list by handle, since file names are not unique */ |
613 | module = g_module_find_by_handle (handle); |
614 | if (module) |
615 | { |
616 | _g_module_close (handle: module->handle); |
617 | module->ref_count++; |
618 | g_module_set_error (NULL); |
619 | |
620 | g_rec_mutex_unlock (rec_mutex: &g_module_global_lock); |
621 | return module; |
622 | } |
623 | |
624 | saved_error = g_strdup (str: g_module_error ()); |
625 | g_module_set_error (NULL); |
626 | |
627 | module = g_new (GModule, 1); |
628 | module->file_name = g_strdup (str: file_name); |
629 | module->handle = handle; |
630 | module->ref_count = 1; |
631 | module->is_resident = FALSE; |
632 | module->unload = NULL; |
633 | module->next = modules; |
634 | modules = module; |
635 | |
636 | /* check initialization */ |
637 | if (g_module_symbol (module, symbol_name: "g_module_check_init" , symbol: (gpointer) &check_init) && check_init != NULL) |
638 | check_failed = check_init (module); |
639 | |
640 | /* we don't call unload() if the initialization check failed. */ |
641 | if (!check_failed) |
642 | g_module_symbol (module, symbol_name: "g_module_unload" , symbol: (gpointer) &module->unload); |
643 | |
644 | if (check_failed) |
645 | { |
646 | gchar *error; |
647 | |
648 | error = g_strconcat (string1: "GModule (" , file_name, ") " , |
649 | "initialization check failed: " , |
650 | check_failed, NULL); |
651 | g_module_close (module); |
652 | module = NULL; |
653 | g_module_set_error (error); |
654 | g_free (mem: error); |
655 | } |
656 | else |
657 | g_module_set_error (error: saved_error); |
658 | |
659 | g_free (mem: saved_error); |
660 | } |
661 | |
662 | if (module != NULL && |
663 | (module_debug_flags & G_MODULE_DEBUG_RESIDENT_MODULES)) |
664 | g_module_make_resident (module); |
665 | |
666 | g_rec_mutex_unlock (rec_mutex: &g_module_global_lock); |
667 | return module; |
668 | } |
669 | |
670 | /** |
671 | * g_module_close: |
672 | * @module: a #GModule to close |
673 | * |
674 | * Closes a module. |
675 | * |
676 | * Returns: %TRUE on success |
677 | */ |
678 | gboolean |
679 | g_module_close (GModule *module) |
680 | { |
681 | SUPPORT_OR_RETURN (FALSE); |
682 | |
683 | g_return_val_if_fail (module != NULL, FALSE); |
684 | g_return_val_if_fail (module->ref_count > 0, FALSE); |
685 | |
686 | g_rec_mutex_lock (rec_mutex: &g_module_global_lock); |
687 | |
688 | module->ref_count--; |
689 | |
690 | if (!module->ref_count && !module->is_resident && module->unload) |
691 | { |
692 | GModuleUnload unload; |
693 | |
694 | unload = module->unload; |
695 | module->unload = NULL; |
696 | unload (module); |
697 | } |
698 | |
699 | if (!module->ref_count && !module->is_resident) |
700 | { |
701 | GModule *last; |
702 | GModule *node; |
703 | |
704 | last = NULL; |
705 | |
706 | node = modules; |
707 | while (node) |
708 | { |
709 | if (node == module) |
710 | { |
711 | if (last) |
712 | last->next = node->next; |
713 | else |
714 | modules = node->next; |
715 | break; |
716 | } |
717 | last = node; |
718 | node = last->next; |
719 | } |
720 | module->next = NULL; |
721 | |
722 | _g_module_close (handle: module->handle); |
723 | g_free (mem: module->file_name); |
724 | g_free (mem: module); |
725 | } |
726 | |
727 | g_rec_mutex_unlock (rec_mutex: &g_module_global_lock); |
728 | return g_module_error() == NULL; |
729 | } |
730 | |
731 | /** |
732 | * g_module_make_resident: |
733 | * @module: a #GModule to make permanently resident |
734 | * |
735 | * Ensures that a module will never be unloaded. |
736 | * Any future g_module_close() calls on the module will be ignored. |
737 | */ |
738 | void |
739 | g_module_make_resident (GModule *module) |
740 | { |
741 | g_return_if_fail (module != NULL); |
742 | |
743 | module->is_resident = TRUE; |
744 | } |
745 | |
746 | /** |
747 | * g_module_error: |
748 | * |
749 | * Gets a string describing the last module error. |
750 | * |
751 | * Returns: a string describing the last module error |
752 | */ |
753 | const gchar * |
754 | g_module_error (void) |
755 | { |
756 | return g_private_get (key: &module_error_private); |
757 | } |
758 | |
759 | /** |
760 | * g_module_symbol: |
761 | * @module: a #GModule |
762 | * @symbol_name: the name of the symbol to find |
763 | * @symbol: (out): returns the pointer to the symbol value |
764 | * |
765 | * Gets a symbol pointer from a module, such as one exported |
766 | * by #G_MODULE_EXPORT. Note that a valid symbol can be %NULL. |
767 | * |
768 | * Returns: %TRUE on success |
769 | */ |
770 | gboolean |
771 | g_module_symbol (GModule *module, |
772 | const gchar *symbol_name, |
773 | gpointer *symbol) |
774 | { |
775 | const gchar *module_error; |
776 | |
777 | if (symbol) |
778 | *symbol = NULL; |
779 | SUPPORT_OR_RETURN (FALSE); |
780 | |
781 | g_return_val_if_fail (module != NULL, FALSE); |
782 | g_return_val_if_fail (symbol_name != NULL, FALSE); |
783 | g_return_val_if_fail (symbol != NULL, FALSE); |
784 | |
785 | g_rec_mutex_lock (rec_mutex: &g_module_global_lock); |
786 | |
787 | #ifdef G_MODULE_NEED_USCORE |
788 | { |
789 | gchar *name; |
790 | |
791 | name = g_strconcat ("_" , symbol_name, NULL); |
792 | *symbol = _g_module_symbol (module->handle, name); |
793 | g_free (name); |
794 | } |
795 | #else /* !G_MODULE_NEED_USCORE */ |
796 | *symbol = _g_module_symbol (handle: module->handle, symbol_name); |
797 | #endif /* !G_MODULE_NEED_USCORE */ |
798 | |
799 | module_error = g_module_error (); |
800 | if (module_error) |
801 | { |
802 | gchar *error; |
803 | |
804 | error = g_strconcat (string1: "'" , symbol_name, "': " , module_error, NULL); |
805 | g_module_set_error (error); |
806 | g_free (mem: error); |
807 | *symbol = NULL; |
808 | } |
809 | |
810 | g_rec_mutex_unlock (rec_mutex: &g_module_global_lock); |
811 | return !module_error; |
812 | } |
813 | |
814 | /** |
815 | * g_module_name: |
816 | * @module: a #GModule |
817 | * |
818 | * Returns the filename that the module was opened with. |
819 | * |
820 | * If @module refers to the application itself, "main" is returned. |
821 | * |
822 | * Returns: (transfer none): the filename of the module |
823 | */ |
824 | const gchar * |
825 | g_module_name (GModule *module) |
826 | { |
827 | g_return_val_if_fail (module != NULL, NULL); |
828 | |
829 | if (module == main_module) |
830 | return "main" ; |
831 | |
832 | return module->file_name; |
833 | } |
834 | |
835 | /** |
836 | * g_module_build_path: |
837 | * @directory: (nullable): the directory where the module is. This can be |
838 | * %NULL or the empty string to indicate that the standard platform-specific |
839 | * directories will be used, though that is not recommended |
840 | * @module_name: the name of the module |
841 | * |
842 | * A portable way to build the filename of a module. The platform-specific |
843 | * prefix and suffix are added to the filename, if needed, and the result |
844 | * is added to the directory, using the correct separator character. |
845 | * |
846 | * The directory should specify the directory where the module can be found. |
847 | * It can be %NULL or an empty string to indicate that the module is in a |
848 | * standard platform-specific directory, though this is not recommended |
849 | * since the wrong module may be found. |
850 | * |
851 | * For example, calling g_module_build_path() on a Linux system with a |
852 | * @directory of `/lib` and a @module_name of "mylibrary" will return |
853 | * `/lib/libmylibrary.so`. On a Windows system, using `\Windows` as the |
854 | * directory it will return `\Windows\mylibrary.dll`. |
855 | * |
856 | * Returns: the complete path of the module, including the standard library |
857 | * prefix and suffix. This should be freed when no longer needed |
858 | */ |
859 | gchar * |
860 | g_module_build_path (const gchar *directory, |
861 | const gchar *module_name) |
862 | { |
863 | g_return_val_if_fail (module_name != NULL, NULL); |
864 | |
865 | return _g_module_build_path (directory, module_name); |
866 | } |
867 | |
868 | |
869 | #ifdef G_OS_WIN32 |
870 | |
871 | /* Binary compatibility versions. Not for newly compiled code. */ |
872 | |
873 | _GLIB_EXTERN GModule * g_module_open_utf8 (const gchar *file_name, |
874 | GModuleFlags flags); |
875 | |
876 | _GLIB_EXTERN const gchar *g_module_name_utf8 (GModule *module); |
877 | |
878 | GModule* |
879 | g_module_open_utf8 (const gchar *file_name, |
880 | GModuleFlags flags) |
881 | { |
882 | return g_module_open (file_name, flags); |
883 | } |
884 | |
885 | const gchar * |
886 | g_module_name_utf8 (GModule *module) |
887 | { |
888 | return g_module_name (module); |
889 | } |
890 | |
891 | #endif |
892 | |