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