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 --- */ 61 struct _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 --- */ 76 static gpointer _g_module_open (const gchar *file_name, 77 gboolean bind_lazy, 78 gboolean bind_local); 79 static void _g_module_close (gpointer handle, 80 gboolean is_unref); 81 static gpointer _g_module_self (void); 82 static gpointer _g_module_symbol (gpointer handle, 83 const gchar *symbol_name); 84 static gchar* _g_module_build_path (const gchar *directory, 85 const gchar *module_name); 86 static inline void g_module_set_error (const gchar *error); 87 static inline GModule* g_module_find_by_handle (gpointer handle); 88 static inline GModule* g_module_find_by_name (const gchar *name); 89 90 91 /* --- variables --- */ 92 static GModule *modules = NULL; 93 static GModule *main_module = NULL; 94 static GStaticPrivate module_error_private = G_STATIC_PRIVATE_INIT; 95 static gboolean module_debug_initialized = FALSE; 96 static guint module_debug_flags = 0; 97 98 99 /* --- inline functions --- */ 100 static inline GModule* 101 g_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 119 static inline GModule* 120 g_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 135 static inline void 136 g_module_set_error_unduped (gchar *error) 137 { 138 g_static_private_set (&module_error_private, error, g_free); 139 errno = 0; 140 } 141 142 static inline void 143 g_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; } 165 static gpointer 166 _g_module_open (const gchar *file_name, 167 gboolean bind_lazy, 168 gboolean bind_local) 169 { 170 return NULL; 171 } 172 static void 173 _g_module_close (gpointer handle, 174 gboolean is_unref) 175 { 176 } 177 static gpointer 178 _g_module_self (void) 179 { 180 return NULL; 181 } 182 static gpointer 183 _g_module_symbol (gpointer handle, 184 const gchar *symbol_name) 185 { 186 return NULL; 187 } 188 static 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 --- */ 197 gboolean 198 g_module_supported (void) 199 { 200 SUPPORT_OR_RETURN (FALSE); 201 202 return TRUE; 203 } 204 205 static gchar* 206 parse_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 295 static inline gboolean 296 str_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 306 enum 307 { 308 G_MODULE_DEBUG_RESIDENT_MODULES = 1 << 0, 309 G_MODULE_DEBUG_BIND_NOW_MODULES = 1 << 1 310 }; 311 312 static 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 329 static GStaticRecMutex g_module_global_lock = G_STATIC_REC_MUTEX_INIT; 330 331 GModule* 332 g_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 523 GModule* 524 g_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 537 gboolean 538 g_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 593 void 594 g_module_make_resident (GModule *module) 595 { 596 g_return_if_fail (module != NULL); 597 598 module->is_resident = TRUE; 599 } 600 601 G_CONST_RETURN gchar* 602 g_module_error (void) 603 { 604 return g_static_private_get (&module_error_private); 605 } 606 607 gboolean 608 g_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 651 G_CONST_RETURN gchar* 652 g_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 666 G_CONST_RETURN gchar* 667 g_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 679 gchar* 680 g_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