gmodule.c revision 1c391cc69846713b0406545146ea232efc5f34e2
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 --- */ 58struct _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 --- */ 70static gpointer _g_module_open (const gchar *file_name, 71 gboolean bind_lazy); 72static void _g_module_close (gpointer handle, 73 gboolean is_unref); 74static gpointer _g_module_self (void); 75static gpointer _g_module_symbol (gpointer handle, 76 const gchar *symbol_name); 77static gchar* _g_module_build_path (const gchar *directory, 78 const gchar *module_name); 79static inline void g_module_set_error (const gchar *error); 80static inline GModule* g_module_find_by_handle (gpointer handle); 81static inline GModule* g_module_find_by_name (const gchar *name); 82 83 84/* --- variables --- */ 85const char *g_log_domain_gmodule = "GModule"; 86static GModule *modules = NULL; 87static GModule *main_module = NULL; 88static GStaticPrivate module_error_private = G_STATIC_PRIVATE_INIT; 89 90 91/* --- inline functions --- */ 92static inline GModule* 93g_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 111static inline GModule* 112g_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 127static inline void 128g_module_set_error (const gchar *error) 129{ 130 g_static_private_set (&module_error_private, g_strdup (error), g_free); 131 errno = 0; 132} 133 134 135/* --- include platform specifc code --- */ 136#define SUPPORT_OR_RETURN(rv) { g_module_set_error (NULL); } 137#if (G_MODULE_IMPL == G_MODULE_IMPL_DL) 138#include "gmodule-dl.c" 139#elif (G_MODULE_IMPL == G_MODULE_IMPL_DLD) 140#include "gmodule-dld.c" 141#elif (G_MODULE_IMPL == G_MODULE_IMPL_WIN32) 142#include "gmodule-win32.c" 143#else 144#undef SUPPORT_OR_RETURN 145#define SUPPORT_OR_RETURN(rv) { g_module_set_error ("dynamic modules are " \ 146 "not supported by this system"); return rv; } 147static gpointer 148_g_module_open (const gchar *file_name, 149 gboolean bind_lazy) 150{ 151 return NULL; 152} 153static void 154_g_module_close (gpointer handle, 155 gboolean is_unref) 156{ 157} 158static gpointer 159_g_module_self (void) 160{ 161 return NULL; 162} 163static gpointer 164_g_module_symbol (gpointer handle, 165 const gchar *symbol_name) 166{ 167 return NULL; 168} 169static gchar* 170_g_module_build_path (const gchar *directory, 171 const gchar *module_name) 172{ 173 return NULL; 174} 175#endif /* no implementation */ 176 177/* --- functions --- */ 178gboolean 179g_module_supported (void) 180{ 181 SUPPORT_OR_RETURN (FALSE); 182 183 return TRUE; 184} 185 186static gchar* 187parse_libtool_archive (const gchar* libtool_name) 188{ 189 const gint TOKEN_DLNAME = G_TOKEN_LAST + 1; 190 const gint TOKEN_INSTALLED = G_TOKEN_LAST + 2; 191 const gint TOKEN_LIBDIR = G_TOKEN_LAST + 3; 192 gchar *lt_dlname = NULL; 193 gboolean lt_installed = TRUE; 194 gchar *lt_libdir = NULL; 195 gchar *name; 196 GTokenType token; 197 GScanner *scanner; 198 199 int fd = open (libtool_name, O_RDONLY, 0); 200 if (fd < 0) 201 { 202 g_module_set_error ("couldn't open libtool archive"); 203 return NULL; 204 } 205 /* search libtool's dlname specification */ 206 scanner = g_scanner_new (NULL); 207 g_scanner_input_file (scanner, fd); 208 scanner->config->symbol_2_token = TRUE; 209 g_scanner_scope_add_symbol (scanner, 0, "dlname", 210 GUINT_TO_POINTER (TOKEN_DLNAME)); 211 g_scanner_scope_add_symbol (scanner, 0, "installed", 212 GUINT_TO_POINTER (TOKEN_INSTALLED)); 213 g_scanner_scope_add_symbol (scanner, 0, "libdir", 214 GUINT_TO_POINTER (TOKEN_LIBDIR)); 215 while (!g_scanner_eof (scanner)) 216 { 217 token = g_scanner_get_next_token (scanner); 218 if (token == TOKEN_DLNAME || token == TOKEN_INSTALLED || 219 token == TOKEN_LIBDIR) 220 { 221 if (g_scanner_get_next_token (scanner) != '=' || 222 g_scanner_get_next_token (scanner) != 223 (token == TOKEN_INSTALLED ? 224 G_TOKEN_IDENTIFIER : G_TOKEN_STRING)) 225 { 226 g_module_set_error ("libtool archive has unknown format"); 227 228 g_free (lt_dlname); 229 g_free (lt_libdir); 230 g_scanner_destroy (scanner); 231 close (fd); 232 233 return NULL; 234 } 235 else 236 { 237 if (token == TOKEN_DLNAME) 238 { 239 g_free (lt_dlname); 240 lt_dlname = g_strdup (scanner->value.v_string); 241 } 242 else if (token == TOKEN_INSTALLED) 243 lt_installed = 244 strcmp (scanner->value.v_identifier, "yes") == 0; 245 else /* token == TOKEN_LIBDIR */ 246 { 247 g_free (lt_libdir); 248 lt_libdir = g_strdup (scanner->value.v_string); 249 } 250 } 251 } 252 } 253 254 if (!lt_installed) 255 { 256 gchar *dir = g_path_get_dirname (libtool_name); 257 g_free (lt_libdir); 258 lt_libdir = g_strconcat (dir, G_DIR_SEPARATOR_S ".libs", NULL); 259 } 260 261 name = g_module_build_path (lt_libdir, lt_dlname); 262 263 g_free (lt_dlname); 264 g_free (lt_libdir); 265 g_scanner_destroy (scanner); 266 close (fd); 267 268 return name; 269} 270 271static inline gboolean 272g_str_check_suffix (const gchar* string, const gchar* suffix) 273{ 274 guint string_len = strlen (string); 275 guint suffix_len = strlen (suffix); 276 277 return string_len >= suffix_len && 278 strcmp (string + string_len - suffix_len, suffix) == 0; 279} 280 281static GStaticRecMutex g_module_global_lock = G_STATIC_REC_MUTEX_INIT; 282 283GModule* 284g_module_open (const gchar *file_name, 285 GModuleFlags flags) 286{ 287 GModule *module; 288 gpointer handle; 289 290 SUPPORT_OR_RETURN (NULL); 291 292 g_static_rec_mutex_lock (&g_module_global_lock); 293 if (!file_name) 294 { 295 if (!main_module) 296 { 297 handle = _g_module_self (); 298 if (handle) 299 { 300 main_module = g_new (GModule, 1); 301 main_module->file_name = NULL; 302 main_module->handle = handle; 303 main_module->ref_count = 1; 304 main_module->is_resident = TRUE; 305 main_module->unload = NULL; 306 main_module->next = NULL; 307 } 308 } 309 310 g_static_rec_mutex_unlock (&g_module_global_lock); 311 return main_module; 312 } 313 314 /* we first search the module list by name */ 315 module = g_module_find_by_name (file_name); 316 if (module) 317 { 318 module->ref_count++; 319 320 g_static_rec_mutex_unlock (&g_module_global_lock); 321 return module; 322 } 323 324 /* First we try to open the module as provided */ 325 handle = _g_module_open (file_name, (flags & G_MODULE_BIND_LAZY) != 0); 326 327 /* If not found, we check, if it is a libtool archive */ 328 if (!handle && g_str_check_suffix (file_name, ".la")) 329 { 330 gchar *name = parse_libtool_archive (file_name); 331 if (name) 332 { 333 handle = _g_module_open (name, (flags & G_MODULE_BIND_LAZY) != 0); 334 g_free (name); 335 } 336 } 337 338 /* If still not found, we check, if it is a library name without suffix */ 339 if (!handle && !g_str_check_suffix (file_name, "." G_MODULE_SUFFIX)) 340 { 341 gchar *name = g_strconcat (file_name, "." G_MODULE_SUFFIX, NULL); 342 handle = _g_module_open (name, (flags & G_MODULE_BIND_LAZY) != 0); 343 g_free (name); 344 } 345 346 /* If still not found, we check, if it is a libtool archive name 347 * without suffix */ 348 if (!handle && !g_str_check_suffix (file_name, ".la")) 349 { 350 gchar *la_name = g_strconcat (file_name, ".la", NULL); 351 gchar *name = parse_libtool_archive (la_name); 352 if (name) 353 { 354 handle = _g_module_open (name, (flags & G_MODULE_BIND_LAZY) != 0); 355 g_free (name); 356 } 357 g_free (la_name); 358 } 359 360 if (handle) 361 { 362 gchar *saved_error; 363 GModuleCheckInit check_init; 364 const gchar *check_failed = NULL; 365 366 /* search the module list by handle, since file names are not unique */ 367 module = g_module_find_by_handle (handle); 368 if (module) 369 { 370 _g_module_close (module->handle, TRUE); 371 module->ref_count++; 372 g_module_set_error (NULL); 373 374 g_static_rec_mutex_unlock (&g_module_global_lock); 375 return module; 376 } 377 378 saved_error = g_strdup (g_module_error ()); 379 g_module_set_error (NULL); 380 381 module = g_new (GModule, 1); 382 module->file_name = g_strdup (file_name); 383 module->handle = handle; 384 module->ref_count = 1; 385 module->is_resident = FALSE; 386 module->unload = NULL; 387 module->next = modules; 388 modules = module; 389 390 /* check initialization */ 391 if (g_module_symbol (module, "g_module_check_init", (gpointer) &check_init)) 392 check_failed = check_init (module); 393 394 /* we don't call unload() if the initialization check failed. */ 395 if (!check_failed) 396 g_module_symbol (module, "g_module_unload", (gpointer) &module->unload); 397 398 if (check_failed) 399 { 400 gchar *error; 401 402 error = g_strconcat ("GModule initialization check failed: ", check_failed, NULL); 403 g_module_close (module); 404 module = NULL; 405 g_module_set_error (error); 406 g_free (error); 407 } 408 else 409 g_module_set_error (saved_error); 410 411 g_free (saved_error); 412 } 413 414 g_static_rec_mutex_unlock (&g_module_global_lock); 415 return module; 416} 417 418gboolean 419g_module_close (GModule *module) 420{ 421 SUPPORT_OR_RETURN (FALSE); 422 423 g_return_val_if_fail (module != NULL, FALSE); 424 g_return_val_if_fail (module->ref_count > 0, FALSE); 425 426 g_static_rec_mutex_lock (&g_module_global_lock); 427 428 module->ref_count--; 429 430 if (!module->ref_count && !module->is_resident && module->unload) 431 { 432 GModuleUnload unload; 433 434 unload = module->unload; 435 module->unload = NULL; 436 unload (module); 437 } 438 439 if (!module->ref_count && !module->is_resident) 440 { 441 GModule *last; 442 GModule *node; 443 444 last = NULL; 445 446 node = modules; 447 while (node) 448 { 449 if (node == module) 450 { 451 if (last) 452 last->next = node->next; 453 else 454 modules = node->next; 455 break; 456 } 457 last = node; 458 node = last->next; 459 } 460 module->next = NULL; 461 462 _g_module_close (module->handle, FALSE); 463 g_free (module->file_name); 464 465 g_free (module); 466 } 467 468 g_static_rec_mutex_unlock (&g_module_global_lock); 469 return g_module_error() == NULL; 470} 471 472void 473g_module_make_resident (GModule *module) 474{ 475 g_return_if_fail (module != NULL); 476 477 module->is_resident = TRUE; 478} 479 480G_CONST_RETURN gchar* 481g_module_error (void) 482{ 483 return g_static_private_get (&module_error_private); 484} 485 486gboolean 487g_module_symbol (GModule *module, 488 const gchar *symbol_name, 489 gpointer *symbol) 490{ 491 const gchar *module_error; 492 493 if (symbol) 494 *symbol = NULL; 495 SUPPORT_OR_RETURN (FALSE); 496 497 g_return_val_if_fail (module != NULL, FALSE); 498 g_return_val_if_fail (symbol_name != NULL, FALSE); 499 g_return_val_if_fail (symbol != NULL, FALSE); 500 501 g_static_rec_mutex_lock (&g_module_global_lock); 502 503#ifdef G_MODULE_NEED_USCORE 504 { 505 gchar *name; 506 507 name = g_strconcat ("_", symbol_name, NULL); 508 *symbol = _g_module_symbol (module->handle, name); 509 g_free (name); 510 } 511#else /* !G_MODULE_NEED_USCORE */ 512 *symbol = _g_module_symbol (module->handle, symbol_name); 513#endif /* !G_MODULE_NEED_USCORE */ 514 515 module_error = g_module_error (); 516 if (module_error) 517 { 518 gchar *error; 519 520 error = g_strconcat ("`", symbol_name, "': ", module_error, NULL); 521 g_module_set_error (error); 522 g_free (error); 523 *symbol = NULL; 524 } 525 526 g_static_rec_mutex_unlock (&g_module_global_lock); 527 return !module_error; 528} 529 530G_CONST_RETURN gchar* 531g_module_name (GModule *module) 532{ 533 g_return_val_if_fail (module != NULL, NULL); 534 535 if (module == main_module) 536 return "main"; 537 538 return module->file_name; 539} 540 541gchar* 542g_module_build_path (const gchar *directory, 543 const gchar *module_name) 544{ 545 g_return_val_if_fail (module_name != NULL, NULL); 546 547 return _g_module_build_path (directory, module_name); 548} 549