|
|
1.1 root 1: /* ltdl.c -- system independent dlopen wrapper 1.1.1.2 ! root 2: Copyright (C) 1998, 1999, 2000, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. 1.1 root 3: Originally by Thomas Tanner <[email protected]> 4: This file is part of GNU Libtool. 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 of the License, or (at your option) any later version. 10: 11: As a special exception to the GNU Lesser General Public License, 12: if you distribute this file as part of a program or library that 13: is built using GNU libtool, you may include it under the same 14: distribution terms that you use for the rest of that program. 15: 16: This library is distributed in the hope that it will be useful, 17: but WITHOUT ANY WARRANTY; without even the implied warranty of 18: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19: Lesser General Public License for more details. 20: 21: You should have received a copy of the GNU Lesser General Public 22: License along with this library; if not, write to the Free Software 1.1.1.2 ! root 23: Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ! 24: 02110-1301 USA 1.1 root 25: 26: */ 27: 28: #if HAVE_CONFIG_H 29: # include <config.h> 30: #endif 31: 32: #if HAVE_UNISTD_H 33: # include <unistd.h> 34: #endif 35: 36: #if HAVE_STDIO_H 37: # include <stdio.h> 38: #endif 39: 1.1.1.2 ! root 40: /* Include the header defining malloc. On K&R C compilers, ! 41: that's <malloc.h>, on ANSI C and ISO C compilers, that's <stdlib.h>. */ 1.1 root 42: #if HAVE_STDLIB_H 43: # include <stdlib.h> 1.1.1.2 ! root 44: #else ! 45: # if HAVE_MALLOC_H ! 46: # include <malloc.h> ! 47: # endif 1.1 root 48: #endif 49: 50: #if HAVE_STRING_H 51: # include <string.h> 52: #else 53: # if HAVE_STRINGS_H 54: # include <strings.h> 55: # endif 56: #endif 57: 58: #if HAVE_CTYPE_H 59: # include <ctype.h> 60: #endif 61: 62: #if HAVE_MEMORY_H 63: # include <memory.h> 64: #endif 65: 66: #if HAVE_ERRNO_H 67: # include <errno.h> 68: #endif 69: 70: 71: #ifndef __WINDOWS__ 72: # ifdef __WIN32__ 73: # define __WINDOWS__ 74: # endif 75: #endif 76: 77: 78: #undef LT_USE_POSIX_DIRENT 79: #ifdef HAVE_CLOSEDIR 80: # ifdef HAVE_OPENDIR 81: # ifdef HAVE_READDIR 82: # ifdef HAVE_DIRENT_H 83: # define LT_USE_POSIX_DIRENT 84: # endif /* HAVE_DIRENT_H */ 85: # endif /* HAVE_READDIR */ 86: # endif /* HAVE_OPENDIR */ 87: #endif /* HAVE_CLOSEDIR */ 88: 89: 90: #undef LT_USE_WINDOWS_DIRENT_EMULATION 91: #ifndef LT_USE_POSIX_DIRENT 92: # ifdef __WINDOWS__ 93: # define LT_USE_WINDOWS_DIRENT_EMULATION 94: # endif /* __WINDOWS__ */ 95: #endif /* LT_USE_POSIX_DIRENT */ 96: 97: 98: #ifdef LT_USE_POSIX_DIRENT 99: # include <dirent.h> 100: # define LT_D_NAMLEN(dirent) (strlen((dirent)->d_name)) 101: #else 102: # ifdef LT_USE_WINDOWS_DIRENT_EMULATION 103: # define LT_D_NAMLEN(dirent) (strlen((dirent)->d_name)) 104: # else 105: # define dirent direct 106: # define LT_D_NAMLEN(dirent) ((dirent)->d_namlen) 107: # if HAVE_SYS_NDIR_H 108: # include <sys/ndir.h> 109: # endif 110: # if HAVE_SYS_DIR_H 111: # include <sys/dir.h> 112: # endif 113: # if HAVE_NDIR_H 114: # include <ndir.h> 115: # endif 116: # endif 117: #endif 118: 119: #if HAVE_ARGZ_H 120: # include <argz.h> 121: #endif 122: 123: #if HAVE_ASSERT_H 124: # include <assert.h> 125: #else 126: # define assert(arg) ((void) 0) 127: #endif 128: 129: #include "ltdl.h" 130: 131: #if WITH_DMALLOC 132: # include <dmalloc.h> 133: #endif 134: 135: 136: 137: 138: /* --- WINDOWS SUPPORT --- */ 139: 1.1.1.2 ! root 140: /* DLL building support on win32 hosts; mostly to workaround their ! 141: ridiculous implementation of data symbol exporting. */ ! 142: #ifndef LT_GLOBAL_DATA ! 143: # if defined(__WINDOWS__) || defined(__CYGWIN__) ! 144: # ifdef DLL_EXPORT /* defined by libtool (if required) */ ! 145: # define LT_GLOBAL_DATA __declspec(dllexport) ! 146: # endif ! 147: # endif ! 148: # ifndef LT_GLOBAL_DATA /* static linking or !__WINDOWS__ */ ! 149: # define LT_GLOBAL_DATA ! 150: # endif 1.1 root 151: #endif 152: 153: /* fopen() mode flags for reading a text file */ 154: #undef LT_READTEXT_MODE 1.1.1.2 ! root 155: #if defined(__WINDOWS__) || defined(__CYGWIN__) 1.1 root 156: # define LT_READTEXT_MODE "rt" 157: #else 158: # define LT_READTEXT_MODE "r" 159: #endif 160: 161: #ifdef LT_USE_WINDOWS_DIRENT_EMULATION 162: 163: #include <windows.h> 164: 165: #define dirent lt_dirent 166: #define DIR lt_DIR 167: 168: struct dirent 169: { 170: char d_name[2048]; 171: int d_namlen; 172: }; 173: 174: typedef struct _DIR 175: { 176: HANDLE hSearch; 177: WIN32_FIND_DATA Win32FindData; 178: BOOL firsttime; 179: struct dirent file_info; 180: } DIR; 181: 182: #endif /* LT_USE_WINDOWS_DIRENT_EMULATION */ 183: 184: 185: /* --- MANIFEST CONSTANTS --- */ 186: 187: 188: /* Standard libltdl search path environment variable name */ 189: #undef LTDL_SEARCHPATH_VAR 190: #define LTDL_SEARCHPATH_VAR "LTDL_LIBRARY_PATH" 191: 192: /* Standard libtool archive file extension. */ 193: #undef LTDL_ARCHIVE_EXT 194: #define LTDL_ARCHIVE_EXT ".la" 195: 196: /* max. filename length */ 197: #ifndef LT_FILENAME_MAX 198: # define LT_FILENAME_MAX 1024 199: #endif 200: 201: /* This is the maximum symbol size that won't require malloc/free */ 202: #undef LT_SYMBOL_LENGTH 203: #define LT_SYMBOL_LENGTH 128 204: 205: /* This accounts for the _LTX_ separator */ 206: #undef LT_SYMBOL_OVERHEAD 207: #define LT_SYMBOL_OVERHEAD 5 208: 209: 210: 211: 212: /* --- MEMORY HANDLING --- */ 213: 214: 215: /* These are the functions used internally. In addition to making 216: use of the associated function pointers above, they also perform 217: error handling. */ 218: static char *lt_estrdup LT_PARAMS((const char *str)); 219: static lt_ptr lt_emalloc LT_PARAMS((size_t size)); 220: static lt_ptr lt_erealloc LT_PARAMS((lt_ptr addr, size_t size)); 221: 222: /* static lt_ptr rpl_realloc LT_PARAMS((lt_ptr ptr, size_t size)); */ 223: #define rpl_realloc realloc 224: 225: /* These are the pointers that can be changed by the caller: */ 226: LT_GLOBAL_DATA lt_ptr (*lt_dlmalloc) LT_PARAMS((size_t size)) 227: = (lt_ptr (*) LT_PARAMS((size_t))) malloc; 228: LT_GLOBAL_DATA lt_ptr (*lt_dlrealloc) LT_PARAMS((lt_ptr ptr, size_t size)) 229: = (lt_ptr (*) LT_PARAMS((lt_ptr, size_t))) rpl_realloc; 230: LT_GLOBAL_DATA void (*lt_dlfree) LT_PARAMS((lt_ptr ptr)) 231: = (void (*) LT_PARAMS((lt_ptr))) free; 232: 233: /* The following macros reduce the amount of typing needed to cast 234: assigned memory. */ 235: #if WITH_DMALLOC 236: 237: #define LT_DLMALLOC(tp, n) ((tp *) xmalloc ((n) * sizeof(tp))) 238: #define LT_DLREALLOC(tp, p, n) ((tp *) xrealloc ((p), (n) * sizeof(tp))) 239: #define LT_DLFREE(p) \ 240: LT_STMT_START { if (p) (p) = (xfree (p), (lt_ptr) 0); } LT_STMT_END 241: 242: #define LT_EMALLOC(tp, n) ((tp *) xmalloc ((n) * sizeof(tp))) 243: #define LT_EREALLOC(tp, p, n) ((tp *) xrealloc ((p), (n) * sizeof(tp))) 244: 245: #else 246: 247: #define LT_DLMALLOC(tp, n) ((tp *) lt_dlmalloc ((n) * sizeof(tp))) 1.1.1.2 ! root 248: #define LT_DLREALLOC(tp, p, n) ((tp *) lt_dlrealloc ((p), (n) * sizeof(tp))) 1.1 root 249: #define LT_DLFREE(p) \ 250: LT_STMT_START { if (p) (p) = (lt_dlfree (p), (lt_ptr) 0); } LT_STMT_END 251: 252: #define LT_EMALLOC(tp, n) ((tp *) lt_emalloc ((n) * sizeof(tp))) 253: #define LT_EREALLOC(tp, p, n) ((tp *) lt_erealloc ((p), (n) * sizeof(tp))) 254: 255: #endif 256: 257: #define LT_DLMEM_REASSIGN(p, q) LT_STMT_START { \ 258: if ((p) != (q)) { if (p) lt_dlfree (p); (p) = (q); (q) = 0; } \ 259: } LT_STMT_END 260: 261: 262: /* --- REPLACEMENT FUNCTIONS --- */ 263: 264: 265: #undef strdup 266: #define strdup rpl_strdup 267: 268: static char *strdup LT_PARAMS((const char *str)); 269: 270: static char * 271: strdup(str) 272: const char *str; 273: { 274: char *tmp = 0; 275: 276: if (str) 277: { 278: tmp = LT_DLMALLOC (char, 1+ strlen (str)); 279: if (tmp) 280: { 281: strcpy(tmp, str); 282: } 283: } 284: 285: return tmp; 286: } 287: 288: 289: #if ! HAVE_STRCMP 290: 291: #undef strcmp 292: #define strcmp rpl_strcmp 293: 294: static int strcmp LT_PARAMS((const char *str1, const char *str2)); 295: 296: static int 297: strcmp (str1, str2) 298: const char *str1; 299: const char *str2; 300: { 301: if (str1 == str2) 302: return 0; 303: if (str1 == 0) 304: return -1; 305: if (str2 == 0) 306: return 1; 307: 308: for (;*str1 && *str2; ++str1, ++str2) 309: { 310: if (*str1 != *str2) 311: break; 312: } 313: 314: return (int)(*str1 - *str2); 315: } 316: #endif 317: 318: 319: #if ! HAVE_STRCHR 320: 321: # if HAVE_INDEX 322: # define strchr index 323: # else 324: # define strchr rpl_strchr 325: 326: static const char *strchr LT_PARAMS((const char *str, int ch)); 327: 328: static const char* 329: strchr(str, ch) 330: const char *str; 331: int ch; 332: { 333: const char *p; 334: 335: for (p = str; *p != (char)ch && *p != LT_EOS_CHAR; ++p) 336: /*NOWORK*/; 337: 338: return (*p == (char)ch) ? p : 0; 339: } 340: 341: # endif 342: #endif /* !HAVE_STRCHR */ 343: 344: 345: #if ! HAVE_STRRCHR 346: 347: # if HAVE_RINDEX 348: # define strrchr rindex 349: # else 350: # define strrchr rpl_strrchr 351: 352: static const char *strrchr LT_PARAMS((const char *str, int ch)); 353: 354: static const char* 355: strrchr(str, ch) 356: const char *str; 357: int ch; 358: { 359: const char *p, *q = 0; 360: 361: for (p = str; *p != LT_EOS_CHAR; ++p) 362: { 363: if (*p == (char) ch) 364: { 365: q = p; 366: } 367: } 368: 369: return q; 370: } 371: 372: # endif 373: #endif 374: 375: /* NOTE: Neither bcopy nor the memcpy implementation below can 376: reliably handle copying in overlapping areas of memory. Use 377: memmove (for which there is a fallback implmentation below) 378: if you need that behaviour. */ 379: #if ! HAVE_MEMCPY 380: 381: # if HAVE_BCOPY 382: # define memcpy(dest, src, size) bcopy (src, dest, size) 383: # else 384: # define memcpy rpl_memcpy 385: 386: static lt_ptr memcpy LT_PARAMS((lt_ptr dest, const lt_ptr src, size_t size)); 387: 388: static lt_ptr 389: memcpy (dest, src, size) 390: lt_ptr dest; 391: const lt_ptr src; 392: size_t size; 393: { 1.1.1.2 ! root 394: const char * s = src; ! 395: char * d = dest; ! 396: size_t i = 0; 1.1 root 397: 398: for (i = 0; i < size; ++i) 399: { 1.1.1.2 ! root 400: d[i] = s[i]; 1.1 root 401: } 402: 403: return dest; 404: } 405: 406: # endif /* !HAVE_BCOPY */ 407: #endif /* !HAVE_MEMCPY */ 408: 409: #if ! HAVE_MEMMOVE 410: # define memmove rpl_memmove 411: 412: static lt_ptr memmove LT_PARAMS((lt_ptr dest, const lt_ptr src, size_t size)); 413: 414: static lt_ptr 415: memmove (dest, src, size) 416: lt_ptr dest; 417: const lt_ptr src; 418: size_t size; 419: { 1.1.1.2 ! root 420: const char * s = src; ! 421: char * d = dest; ! 422: size_t i; 1.1 root 423: 1.1.1.2 ! root 424: if (d < s) 1.1 root 425: for (i = 0; i < size; ++i) 426: { 1.1.1.2 ! root 427: d[i] = s[i]; 1.1 root 428: } 1.1.1.2 ! root 429: else if (d > s && size > 0) ! 430: for (i = size -1; ; --i) 1.1 root 431: { 1.1.1.2 ! root 432: d[i] = s[i]; ! 433: if (i == 0) ! 434: break; 1.1 root 435: } 436: 437: return dest; 438: } 439: 440: #endif /* !HAVE_MEMMOVE */ 441: 442: #ifdef LT_USE_WINDOWS_DIRENT_EMULATION 443: 444: static void closedir LT_PARAMS((DIR *entry)); 445: 446: static void 447: closedir(entry) 448: DIR *entry; 449: { 450: assert(entry != (DIR *) NULL); 451: FindClose(entry->hSearch); 452: lt_dlfree((lt_ptr)entry); 453: } 454: 455: 456: static DIR * opendir LT_PARAMS((const char *path)); 457: 458: static DIR* 459: opendir (path) 460: const char *path; 461: { 462: char file_specification[LT_FILENAME_MAX]; 463: DIR *entry; 464: 465: assert(path != (char *) NULL); 1.1.1.2 ! root 466: /* allow space for: path + '\\' '\\' '*' '.' '*' + '\0' */ ! 467: (void) strncpy (file_specification, path, LT_FILENAME_MAX-6); ! 468: file_specification[LT_FILENAME_MAX-6] = LT_EOS_CHAR; 1.1 root 469: (void) strcat(file_specification,"\\"); 470: entry = LT_DLMALLOC (DIR,sizeof(DIR)); 471: if (entry != (DIR *) 0) 472: { 473: entry->firsttime = TRUE; 474: entry->hSearch = FindFirstFile(file_specification,&entry->Win32FindData); 475: } 476: if (entry->hSearch == INVALID_HANDLE_VALUE) 477: { 478: (void) strcat(file_specification,"\\*.*"); 479: entry->hSearch = FindFirstFile(file_specification,&entry->Win32FindData); 480: if (entry->hSearch == INVALID_HANDLE_VALUE) 481: { 482: LT_DLFREE (entry); 483: return (DIR *) 0; 484: } 485: } 486: return(entry); 487: } 488: 489: 490: static struct dirent *readdir LT_PARAMS((DIR *entry)); 491: 492: static struct dirent *readdir(entry) 493: DIR *entry; 494: { 495: int 496: status; 497: 498: if (entry == (DIR *) 0) 499: return((struct dirent *) 0); 500: if (!entry->firsttime) 501: { 502: status = FindNextFile(entry->hSearch,&entry->Win32FindData); 503: if (status == 0) 504: return((struct dirent *) 0); 505: } 506: entry->firsttime = FALSE; 507: (void) strncpy(entry->file_info.d_name,entry->Win32FindData.cFileName, 508: LT_FILENAME_MAX-1); 1.1.1.2 ! root 509: entry->file_info.d_name[LT_FILENAME_MAX - 1] = LT_EOS_CHAR; 1.1 root 510: entry->file_info.d_namlen = strlen(entry->file_info.d_name); 511: return(&entry->file_info); 512: } 513: 514: #endif /* LT_USE_WINDOWS_DIRENT_EMULATION */ 515: 516: /* According to Alexandre Oliva <[email protected]>, 517: ``realloc is not entirely portable'' 518: In any case we want to use the allocator supplied by the user without 519: burdening them with an lt_dlrealloc function pointer to maintain. 520: Instead implement our own version (with known boundary conditions) 521: using lt_dlmalloc and lt_dlfree. */ 522: 523: /* #undef realloc 524: #define realloc rpl_realloc 525: */ 526: #if 0 527: /* You can't (re)define realloc unless you also (re)define malloc. 528: Right now, this code uses the size of the *destination* to decide 529: how much to copy. That's not right, but you can't know the size 530: of the source unless you know enough about, or wrote malloc. So 531: this code is disabled... */ 532: 533: static lt_ptr 534: realloc (ptr, size) 535: lt_ptr ptr; 536: size_t size; 537: { 538: if (size == 0) 539: { 540: /* For zero or less bytes, free the original memory */ 541: if (ptr != 0) 542: { 543: lt_dlfree (ptr); 544: } 545: 546: return (lt_ptr) 0; 547: } 548: else if (ptr == 0) 549: { 550: /* Allow reallocation of a NULL pointer. */ 551: return lt_dlmalloc (size); 552: } 553: else 554: { 555: /* Allocate a new block, copy and free the old block. */ 556: lt_ptr mem = lt_dlmalloc (size); 557: 558: if (mem) 559: { 560: memcpy (mem, ptr, size); 561: lt_dlfree (ptr); 562: } 563: 564: /* Note that the contents of PTR are not damaged if there is 565: insufficient memory to realloc. */ 566: return mem; 567: } 568: } 569: #endif 570: 571: 572: #if ! HAVE_ARGZ_APPEND 573: # define argz_append rpl_argz_append 574: 575: static error_t argz_append LT_PARAMS((char **pargz, size_t *pargz_len, 576: const char *buf, size_t buf_len)); 577: 578: static error_t 579: argz_append (pargz, pargz_len, buf, buf_len) 580: char **pargz; 581: size_t *pargz_len; 582: const char *buf; 583: size_t buf_len; 584: { 585: size_t argz_len; 586: char *argz; 587: 588: assert (pargz); 589: assert (pargz_len); 590: assert ((*pargz && *pargz_len) || (!*pargz && !*pargz_len)); 591: 592: /* If nothing needs to be appended, no more work is required. */ 593: if (buf_len == 0) 594: return 0; 595: 596: /* Ensure there is enough room to append BUF_LEN. */ 597: argz_len = *pargz_len + buf_len; 598: argz = LT_DLREALLOC (char, *pargz, argz_len); 599: if (!argz) 600: return ENOMEM; 601: 602: /* Copy characters from BUF after terminating '\0' in ARGZ. */ 603: memcpy (argz + *pargz_len, buf, buf_len); 604: 605: /* Assign new values. */ 606: *pargz = argz; 607: *pargz_len = argz_len; 608: 609: return 0; 610: } 611: #endif /* !HAVE_ARGZ_APPEND */ 612: 613: 614: #if ! HAVE_ARGZ_CREATE_SEP 615: # define argz_create_sep rpl_argz_create_sep 616: 617: static error_t argz_create_sep LT_PARAMS((const char *str, int delim, 618: char **pargz, size_t *pargz_len)); 619: 620: static error_t 621: argz_create_sep (str, delim, pargz, pargz_len) 622: const char *str; 623: int delim; 624: char **pargz; 625: size_t *pargz_len; 626: { 627: size_t argz_len; 628: char *argz = 0; 629: 630: assert (str); 631: assert (pargz); 632: assert (pargz_len); 633: 1.1.1.2 ! root 634: /* Make a copy of STR, but replacing each occurrence of 1.1 root 635: DELIM with '\0'. */ 636: argz_len = 1+ LT_STRLEN (str); 637: if (argz_len) 638: { 639: const char *p; 640: char *q; 641: 642: argz = LT_DLMALLOC (char, argz_len); 643: if (!argz) 644: return ENOMEM; 645: 646: for (p = str, q = argz; *p != LT_EOS_CHAR; ++p) 647: { 648: if (*p == delim) 649: { 650: /* Ignore leading delimiters, and fold consecutive 651: delimiters in STR into a single '\0' in ARGZ. */ 652: if ((q > argz) && (q[-1] != LT_EOS_CHAR)) 653: *q++ = LT_EOS_CHAR; 654: else 655: --argz_len; 656: } 657: else 658: *q++ = *p; 659: } 660: /* Copy terminating LT_EOS_CHAR. */ 661: *q = *p; 662: } 663: 664: /* If ARGZ_LEN has shrunk to nothing, release ARGZ's memory. */ 665: if (!argz_len) 666: LT_DLFREE (argz); 667: 668: /* Assign new values. */ 669: *pargz = argz; 670: *pargz_len = argz_len; 671: 672: return 0; 673: } 674: #endif /* !HAVE_ARGZ_CREATE_SEP */ 675: 676: 677: #if ! HAVE_ARGZ_INSERT 678: # define argz_insert rpl_argz_insert 679: 680: static error_t argz_insert LT_PARAMS((char **pargz, size_t *pargz_len, 681: char *before, const char *entry)); 682: 683: static error_t 684: argz_insert (pargz, pargz_len, before, entry) 685: char **pargz; 686: size_t *pargz_len; 687: char *before; 688: const char *entry; 689: { 690: assert (pargz); 691: assert (pargz_len); 692: assert (entry && *entry); 693: 694: /* No BEFORE address indicates ENTRY should be inserted after the 695: current last element. */ 696: if (!before) 697: return argz_append (pargz, pargz_len, entry, 1+ LT_STRLEN (entry)); 698: 699: /* This probably indicates a programmer error, but to preserve 700: semantics, scan back to the start of an entry if BEFORE points 701: into the middle of it. */ 1.1.1.2 ! root 702: while ((before > *pargz) && (before[-1] != LT_EOS_CHAR)) 1.1 root 703: --before; 704: 705: { 706: size_t entry_len = 1+ LT_STRLEN (entry); 707: size_t argz_len = *pargz_len + entry_len; 708: size_t offset = before - *pargz; 709: char *argz = LT_DLREALLOC (char, *pargz, argz_len); 710: 711: if (!argz) 712: return ENOMEM; 713: 714: /* Make BEFORE point to the equivalent offset in ARGZ that it 715: used to have in *PARGZ incase realloc() moved the block. */ 716: before = argz + offset; 717: 718: /* Move the ARGZ entries starting at BEFORE up into the new 719: space at the end -- making room to copy ENTRY into the 720: resulting gap. */ 721: memmove (before + entry_len, before, *pargz_len - offset); 722: memcpy (before, entry, entry_len); 723: 724: /* Assign new values. */ 725: *pargz = argz; 726: *pargz_len = argz_len; 727: } 728: 729: return 0; 730: } 731: #endif /* !HAVE_ARGZ_INSERT */ 732: 733: 734: #if ! HAVE_ARGZ_NEXT 735: # define argz_next rpl_argz_next 736: 737: static char *argz_next LT_PARAMS((char *argz, size_t argz_len, 738: const char *entry)); 739: 740: static char * 741: argz_next (argz, argz_len, entry) 742: char *argz; 743: size_t argz_len; 744: const char *entry; 745: { 746: assert ((argz && argz_len) || (!argz && !argz_len)); 747: 748: if (entry) 749: { 750: /* Either ARGZ/ARGZ_LEN is empty, or ENTRY points into an address 751: within the ARGZ vector. */ 752: assert ((!argz && !argz_len) 753: || ((argz <= entry) && (entry < (argz + argz_len)))); 754: 755: /* Move to the char immediately after the terminating 756: '\0' of ENTRY. */ 757: entry = 1+ strchr (entry, LT_EOS_CHAR); 758: 759: /* Return either the new ENTRY, or else NULL if ARGZ is 760: exhausted. */ 761: return (entry >= argz + argz_len) ? 0 : (char *) entry; 762: } 763: else 764: { 765: /* This should probably be flagged as a programmer error, 766: since starting an argz_next loop with the iterator set 767: to ARGZ is safer. To preserve semantics, handle the NULL 768: case by returning the start of ARGZ (if any). */ 769: if (argz_len > 0) 770: return argz; 771: else 772: return 0; 773: } 774: } 775: #endif /* !HAVE_ARGZ_NEXT */ 776: 777: 778: 779: #if ! HAVE_ARGZ_STRINGIFY 780: # define argz_stringify rpl_argz_stringify 781: 782: static void argz_stringify LT_PARAMS((char *argz, size_t argz_len, 783: int sep)); 784: 785: static void 786: argz_stringify (argz, argz_len, sep) 787: char *argz; 788: size_t argz_len; 789: int sep; 790: { 791: assert ((argz && argz_len) || (!argz && !argz_len)); 792: 793: if (sep) 794: { 795: --argz_len; /* don't stringify the terminating EOS */ 796: while (--argz_len > 0) 797: { 798: if (argz[argz_len] == LT_EOS_CHAR) 799: argz[argz_len] = sep; 800: } 801: } 802: } 803: #endif /* !HAVE_ARGZ_STRINGIFY */ 804: 805: 806: 807: 808: /* --- TYPE DEFINITIONS -- */ 809: 810: 811: /* This type is used for the array of caller data sets in each handler. */ 812: typedef struct { 813: lt_dlcaller_id key; 814: lt_ptr data; 815: } lt_caller_data; 816: 817: 818: 819: 820: /* --- OPAQUE STRUCTURES DECLARED IN LTDL.H --- */ 821: 822: 823: /* Extract the diagnostic strings from the error table macro in the same 824: order as the enumerated indices in ltdl.h. */ 825: 826: static const char *lt_dlerror_strings[] = 827: { 828: #define LT_ERROR(name, diagnostic) (diagnostic), 829: lt_dlerror_table 830: #undef LT_ERROR 831: 832: 0 833: }; 834: 835: /* This structure is used for the list of registered loaders. */ 836: struct lt_dlloader { 837: struct lt_dlloader *next; 838: const char *loader_name; /* identifying name for each loader */ 839: const char *sym_prefix; /* prefix for symbols */ 840: lt_module_open *module_open; 841: lt_module_close *module_close; 842: lt_find_sym *find_sym; 843: lt_dlloader_exit *dlloader_exit; 844: lt_user_data dlloader_data; 845: }; 846: 847: struct lt_dlhandle_struct { 848: struct lt_dlhandle_struct *next; 849: lt_dlloader *loader; /* dlopening interface */ 850: lt_dlinfo info; 851: int depcount; /* number of dependencies */ 852: lt_dlhandle *deplibs; /* dependencies */ 853: lt_module module; /* system module handle */ 854: lt_ptr system; /* system specific data */ 855: lt_caller_data *caller_data; /* per caller associated data */ 856: int flags; /* various boolean stats */ 857: }; 858: 859: /* Various boolean flags can be stored in the flags field of an 860: lt_dlhandle_struct... */ 861: #define LT_DLGET_FLAG(handle, flag) (((handle)->flags & (flag)) == (flag)) 862: #define LT_DLSET_FLAG(handle, flag) ((handle)->flags |= (flag)) 863: 864: #define LT_DLRESIDENT_FLAG (0x01 << 0) 865: /* ...add more flags here... */ 866: 867: #define LT_DLIS_RESIDENT(handle) LT_DLGET_FLAG(handle, LT_DLRESIDENT_FLAG) 868: 869: 870: #define LT_DLSTRERROR(name) lt_dlerror_strings[LT_CONC(LT_ERROR_,name)] 871: 872: static const char objdir[] = LTDL_OBJDIR; 873: static const char archive_ext[] = LTDL_ARCHIVE_EXT; 874: #ifdef LTDL_SHLIB_EXT 875: static const char shlib_ext[] = LTDL_SHLIB_EXT; 876: #endif 877: #ifdef LTDL_SYSSEARCHPATH 878: static const char sys_search_path[] = LTDL_SYSSEARCHPATH; 879: #endif 880: 881: 882: 883: 884: /* --- MUTEX LOCKING --- */ 885: 886: 887: /* Macros to make it easier to run the lock functions only if they have 888: been registered. The reason for the complicated lock macro is to 889: ensure that the stored error message from the last error is not 890: accidentally erased if the current function doesn't generate an 891: error of its own. */ 892: #define LT_DLMUTEX_LOCK() LT_STMT_START { \ 893: if (lt_dlmutex_lock_func) (*lt_dlmutex_lock_func)(); \ 894: } LT_STMT_END 895: #define LT_DLMUTEX_UNLOCK() LT_STMT_START { \ 896: if (lt_dlmutex_unlock_func) (*lt_dlmutex_unlock_func)();\ 897: } LT_STMT_END 898: #define LT_DLMUTEX_SETERROR(errormsg) LT_STMT_START { \ 899: if (lt_dlmutex_seterror_func) \ 900: (*lt_dlmutex_seterror_func) (errormsg); \ 901: else lt_dllast_error = (errormsg); } LT_STMT_END 902: #define LT_DLMUTEX_GETERROR(errormsg) LT_STMT_START { \ 1.1.1.2 ! root 903: if (lt_dlmutex_geterror_func) \ 1.1 root 904: (errormsg) = (*lt_dlmutex_geterror_func) (); \ 905: else (errormsg) = lt_dllast_error; } LT_STMT_END 906: 907: /* The mutex functions stored here are global, and are necessarily the 908: same for all threads that wish to share access to libltdl. */ 909: static lt_dlmutex_lock *lt_dlmutex_lock_func = 0; 910: static lt_dlmutex_unlock *lt_dlmutex_unlock_func = 0; 911: static lt_dlmutex_seterror *lt_dlmutex_seterror_func = 0; 912: static lt_dlmutex_geterror *lt_dlmutex_geterror_func = 0; 913: static const char *lt_dllast_error = 0; 914: 915: 916: /* Either set or reset the mutex functions. Either all the arguments must 917: be valid functions, or else all can be NULL to turn off locking entirely. 918: The registered functions should be manipulating a static global lock 919: from the lock() and unlock() callbacks, which needs to be reentrant. */ 920: int 921: lt_dlmutex_register (lock, unlock, seterror, geterror) 922: lt_dlmutex_lock *lock; 923: lt_dlmutex_unlock *unlock; 924: lt_dlmutex_seterror *seterror; 925: lt_dlmutex_geterror *geterror; 926: { 1.1.1.2 ! root 927: lt_dlmutex_unlock *old_unlock = lt_dlmutex_unlock_func; 1.1 root 928: int errors = 0; 929: 930: /* Lock using the old lock() callback, if any. */ 931: LT_DLMUTEX_LOCK (); 932: 933: if ((lock && unlock && seterror && geterror) 934: || !(lock || unlock || seterror || geterror)) 935: { 936: lt_dlmutex_lock_func = lock; 937: lt_dlmutex_unlock_func = unlock; 1.1.1.2 ! root 938: lt_dlmutex_seterror_func = seterror; 1.1 root 939: lt_dlmutex_geterror_func = geterror; 940: } 941: else 942: { 943: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_MUTEX_ARGS)); 944: ++errors; 945: } 946: 947: /* Use the old unlock() callback we saved earlier, if any. Otherwise 948: record any errors using internal storage. */ 949: if (old_unlock) 950: (*old_unlock) (); 951: 952: /* Return the number of errors encountered during the execution of 953: this function. */ 954: return errors; 955: } 956: 957: 958: 959: 960: /* --- ERROR HANDLING --- */ 961: 962: 963: static const char **user_error_strings = 0; 964: static int errorcount = LT_ERROR_MAX; 965: 966: int 967: lt_dladderror (diagnostic) 968: const char *diagnostic; 969: { 970: int errindex = 0; 971: int result = -1; 972: const char **temp = (const char **) 0; 973: 974: assert (diagnostic); 975: 976: LT_DLMUTEX_LOCK (); 977: 978: errindex = errorcount - LT_ERROR_MAX; 979: temp = LT_EREALLOC (const char *, user_error_strings, 1 + errindex); 980: if (temp) 981: { 982: user_error_strings = temp; 983: user_error_strings[errindex] = diagnostic; 984: result = errorcount++; 985: } 986: 987: LT_DLMUTEX_UNLOCK (); 988: 989: return result; 990: } 991: 992: int 993: lt_dlseterror (errindex) 994: int errindex; 995: { 996: int errors = 0; 997: 998: LT_DLMUTEX_LOCK (); 999: 1000: if (errindex >= errorcount || errindex < 0) 1001: { 1002: /* Ack! Error setting the error message! */ 1003: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_ERRORCODE)); 1004: ++errors; 1005: } 1006: else if (errindex < LT_ERROR_MAX) 1007: { 1008: /* No error setting the error message! */ 1009: LT_DLMUTEX_SETERROR (lt_dlerror_strings[errindex]); 1010: } 1011: else 1012: { 1013: /* No error setting the error message! */ 1014: LT_DLMUTEX_SETERROR (user_error_strings[errindex - LT_ERROR_MAX]); 1015: } 1016: 1017: LT_DLMUTEX_UNLOCK (); 1018: 1019: return errors; 1020: } 1021: 1022: static lt_ptr 1023: lt_emalloc (size) 1024: size_t size; 1025: { 1026: lt_ptr mem = lt_dlmalloc (size); 1027: if (size && !mem) 1028: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); 1029: return mem; 1030: } 1031: 1032: static lt_ptr 1033: lt_erealloc (addr, size) 1034: lt_ptr addr; 1035: size_t size; 1036: { 1.1.1.2 ! root 1037: lt_ptr mem = lt_dlrealloc (addr, size); 1.1 root 1038: if (size && !mem) 1039: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); 1040: return mem; 1041: } 1042: 1043: static char * 1044: lt_estrdup (str) 1045: const char *str; 1046: { 1047: char *copy = strdup (str); 1048: if (LT_STRLEN (str) && !copy) 1049: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); 1050: return copy; 1051: } 1052: 1053: 1054: 1055: 1056: /* --- DLOPEN() INTERFACE LOADER --- */ 1057: 1058: 1059: #if HAVE_LIBDL 1060: 1061: /* dynamic linking with dlopen/dlsym */ 1062: 1063: #if HAVE_DLFCN_H 1064: # include <dlfcn.h> 1065: #endif 1066: 1067: #if HAVE_SYS_DL_H 1068: # include <sys/dl.h> 1069: #endif 1070: 1071: #ifdef RTLD_GLOBAL 1072: # define LT_GLOBAL RTLD_GLOBAL 1073: #else 1074: # ifdef DL_GLOBAL 1075: # define LT_GLOBAL DL_GLOBAL 1076: # endif 1077: #endif /* !RTLD_GLOBAL */ 1078: #ifndef LT_GLOBAL 1079: # define LT_GLOBAL 0 1080: #endif /* !LT_GLOBAL */ 1081: 1082: /* We may have to define LT_LAZY_OR_NOW in the command line if we 1083: find out it does not work in some platform. */ 1084: #ifndef LT_LAZY_OR_NOW 1085: # ifdef RTLD_LAZY 1086: # define LT_LAZY_OR_NOW RTLD_LAZY 1087: # else 1088: # ifdef DL_LAZY 1089: # define LT_LAZY_OR_NOW DL_LAZY 1090: # endif 1091: # endif /* !RTLD_LAZY */ 1092: #endif 1093: #ifndef LT_LAZY_OR_NOW 1094: # ifdef RTLD_NOW 1095: # define LT_LAZY_OR_NOW RTLD_NOW 1096: # else 1097: # ifdef DL_NOW 1098: # define LT_LAZY_OR_NOW DL_NOW 1099: # endif 1100: # endif /* !RTLD_NOW */ 1101: #endif 1102: #ifndef LT_LAZY_OR_NOW 1103: # define LT_LAZY_OR_NOW 0 1104: #endif /* !LT_LAZY_OR_NOW */ 1105: 1106: #if HAVE_DLERROR 1107: # define DLERROR(arg) dlerror () 1108: #else 1109: # define DLERROR(arg) LT_DLSTRERROR (arg) 1110: #endif 1111: 1112: static lt_module 1113: sys_dl_open (loader_data, filename) 1114: lt_user_data loader_data; 1115: const char *filename; 1116: { 1117: lt_module module = dlopen (filename, LT_GLOBAL | LT_LAZY_OR_NOW); 1118: 1119: if (!module) 1120: { 1121: LT_DLMUTEX_SETERROR (DLERROR (CANNOT_OPEN)); 1122: } 1123: 1124: return module; 1125: } 1126: 1127: static int 1128: sys_dl_close (loader_data, module) 1129: lt_user_data loader_data; 1130: lt_module module; 1131: { 1132: int errors = 0; 1133: 1134: if (dlclose (module) != 0) 1135: { 1136: LT_DLMUTEX_SETERROR (DLERROR (CANNOT_CLOSE)); 1137: ++errors; 1138: } 1139: 1140: return errors; 1141: } 1142: 1143: static lt_ptr 1144: sys_dl_sym (loader_data, module, symbol) 1145: lt_user_data loader_data; 1146: lt_module module; 1147: const char *symbol; 1148: { 1149: lt_ptr address = dlsym (module, symbol); 1150: 1151: if (!address) 1152: { 1153: LT_DLMUTEX_SETERROR (DLERROR (SYMBOL_NOT_FOUND)); 1154: } 1155: 1156: return address; 1157: } 1158: 1159: static struct lt_user_dlloader sys_dl = 1160: { 1161: # ifdef NEED_USCORE 1162: "_", 1163: # else 1164: 0, 1165: # endif 1166: sys_dl_open, sys_dl_close, sys_dl_sym, 0, 0 }; 1167: 1168: 1169: #endif /* HAVE_LIBDL */ 1170: 1171: 1172: 1173: /* --- SHL_LOAD() INTERFACE LOADER --- */ 1174: 1175: #if HAVE_SHL_LOAD 1176: 1177: /* dynamic linking with shl_load (HP-UX) (comments from gmodule) */ 1178: 1179: #ifdef HAVE_DL_H 1180: # include <dl.h> 1181: #endif 1182: 1183: /* some flags are missing on some systems, so we provide 1184: * harmless defaults. 1185: * 1186: * Mandatory: 1187: * BIND_IMMEDIATE - Resolve symbol references when the library is loaded. 1188: * BIND_DEFERRED - Delay code symbol resolution until actual reference. 1189: * 1190: * Optionally: 1191: * BIND_FIRST - Place the library at the head of the symbol search 1192: * order. 1193: * BIND_NONFATAL - The default BIND_IMMEDIATE behavior is to treat all 1194: * unsatisfied symbols as fatal. This flag allows 1195: * binding of unsatisfied code symbols to be deferred 1196: * until use. 1197: * [Perl: For certain libraries, like DCE, deferred 1198: * binding often causes run time problems. Adding 1199: * BIND_NONFATAL to BIND_IMMEDIATE still allows 1200: * unresolved references in situations like this.] 1201: * BIND_NOSTART - Do not call the initializer for the shared library 1202: * when the library is loaded, nor on a future call to 1203: * shl_unload(). 1204: * BIND_VERBOSE - Print verbose messages concerning possible 1205: * unsatisfied symbols. 1206: * 1207: * hp9000s700/hp9000s800: 1208: * BIND_RESTRICTED - Restrict symbols visible by the library to those 1209: * present at library load time. 1210: * DYNAMIC_PATH - Allow the loader to dynamically search for the 1211: * library specified by the path argument. 1212: */ 1213: 1214: #ifndef DYNAMIC_PATH 1215: # define DYNAMIC_PATH 0 1216: #endif 1217: #ifndef BIND_RESTRICTED 1218: # define BIND_RESTRICTED 0 1219: #endif 1220: 1221: #define LT_BIND_FLAGS (BIND_IMMEDIATE | BIND_NONFATAL | DYNAMIC_PATH) 1222: 1223: static lt_module 1224: sys_shl_open (loader_data, filename) 1225: lt_user_data loader_data; 1226: const char *filename; 1227: { 1228: static shl_t self = (shl_t) 0; 1229: lt_module module = shl_load (filename, LT_BIND_FLAGS, 0L); 1230: 1231: /* Since searching for a symbol against a NULL module handle will also 1232: look in everything else that was already loaded and exported with 1233: the -E compiler flag, we always cache a handle saved before any 1234: modules are loaded. */ 1235: if (!self) 1236: { 1237: lt_ptr address; 1238: shl_findsym (&self, "main", TYPE_UNDEFINED, &address); 1239: } 1240: 1241: if (!filename) 1242: { 1243: module = self; 1244: } 1245: else 1246: { 1247: module = shl_load (filename, LT_BIND_FLAGS, 0L); 1248: 1249: if (!module) 1250: { 1251: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); 1252: } 1253: } 1254: 1255: return module; 1256: } 1257: 1258: static int 1259: sys_shl_close (loader_data, module) 1260: lt_user_data loader_data; 1261: lt_module module; 1262: { 1263: int errors = 0; 1264: 1265: if (module && (shl_unload ((shl_t) (module)) != 0)) 1266: { 1267: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); 1268: ++errors; 1269: } 1270: 1271: return errors; 1272: } 1273: 1274: static lt_ptr 1275: sys_shl_sym (loader_data, module, symbol) 1276: lt_user_data loader_data; 1277: lt_module module; 1278: const char *symbol; 1279: { 1280: lt_ptr address = 0; 1281: 1282: /* sys_shl_open should never return a NULL module handle */ 1283: if (module == (lt_module) 0) 1284: { 1285: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); 1286: } 1287: else if (!shl_findsym((shl_t*) &module, symbol, TYPE_UNDEFINED, &address)) 1288: { 1289: if (!address) 1290: { 1291: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); 1292: } 1293: } 1294: 1295: return address; 1296: } 1297: 1298: static struct lt_user_dlloader sys_shl = { 1299: 0, sys_shl_open, sys_shl_close, sys_shl_sym, 0, 0 1300: }; 1301: 1302: #endif /* HAVE_SHL_LOAD */ 1303: 1304: 1305: 1306: 1307: /* --- LOADLIBRARY() INTERFACE LOADER --- */ 1308: 1309: #ifdef __WINDOWS__ 1310: 1311: /* dynamic linking for Win32 */ 1312: 1313: #include <windows.h> 1314: 1315: /* Forward declaration; required to implement handle search below. */ 1316: static lt_dlhandle handles; 1317: 1318: static lt_module 1319: sys_wll_open (loader_data, filename) 1320: lt_user_data loader_data; 1321: const char *filename; 1322: { 1323: lt_dlhandle cur; 1324: lt_module module = 0; 1325: const char *errormsg = 0; 1326: char *searchname = 0; 1327: char *ext; 1328: char self_name_buf[MAX_PATH]; 1329: 1330: if (!filename) 1331: { 1332: /* Get the name of main module */ 1333: *self_name_buf = 0; 1334: GetModuleFileName (NULL, self_name_buf, sizeof (self_name_buf)); 1335: filename = ext = self_name_buf; 1336: } 1337: else 1338: { 1339: ext = strrchr (filename, '.'); 1340: } 1341: 1342: if (ext) 1343: { 1344: /* FILENAME already has an extension. */ 1345: searchname = lt_estrdup (filename); 1346: } 1347: else 1348: { 1349: /* Append a `.' to stop Windows from adding an 1350: implicit `.dll' extension. */ 1351: searchname = LT_EMALLOC (char, 2+ LT_STRLEN (filename)); 1352: if (searchname) 1353: sprintf (searchname, "%s.", filename); 1354: } 1355: if (!searchname) 1356: return 0; 1357: 1358: { 1.1.1.2 ! root 1359: /* Silence dialog from LoadLibrary on some failures. ! 1360: No way to get the error mode, but to set it, ! 1361: so set it twice to preserve any previous flags. */ ! 1362: UINT errormode = SetErrorMode(SEM_FAILCRITICALERRORS); ! 1363: SetErrorMode(errormode | SEM_FAILCRITICALERRORS); ! 1364: ! 1365: #if defined(__CYGWIN__) ! 1366: { ! 1367: char wpath[MAX_PATH]; ! 1368: cygwin_conv_to_full_win32_path (searchname, wpath); ! 1369: module = LoadLibrary (wpath); ! 1370: } 1.1 root 1371: #else 1.1.1.2 ! root 1372: module = LoadLibrary (searchname); 1.1 root 1373: #endif 1.1.1.2 ! root 1374: ! 1375: /* Restore the error mode. */ ! 1376: SetErrorMode(errormode); ! 1377: } ! 1378: 1.1 root 1379: LT_DLFREE (searchname); 1380: 1381: /* libltdl expects this function to fail if it is unable 1382: to physically load the library. Sadly, LoadLibrary 1383: will search the loaded libraries for a match and return 1384: one of them if the path search load fails. 1385: 1386: We check whether LoadLibrary is returning a handle to 1387: an already loaded module, and simulate failure if we 1388: find one. */ 1389: LT_DLMUTEX_LOCK (); 1390: cur = handles; 1391: while (cur) 1392: { 1393: if (!cur->module) 1394: { 1395: cur = 0; 1396: break; 1397: } 1398: 1399: if (cur->module == module) 1400: { 1401: break; 1402: } 1403: 1404: cur = cur->next; 1405: } 1406: LT_DLMUTEX_UNLOCK (); 1407: 1408: if (cur || !module) 1409: { 1410: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); 1411: module = 0; 1412: } 1413: 1414: return module; 1415: } 1416: 1417: static int 1418: sys_wll_close (loader_data, module) 1419: lt_user_data loader_data; 1420: lt_module module; 1421: { 1422: int errors = 0; 1423: 1424: if (FreeLibrary(module) == 0) 1425: { 1426: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); 1427: ++errors; 1428: } 1429: 1430: return errors; 1431: } 1432: 1433: static lt_ptr 1434: sys_wll_sym (loader_data, module, symbol) 1435: lt_user_data loader_data; 1436: lt_module module; 1437: const char *symbol; 1438: { 1439: lt_ptr address = GetProcAddress (module, symbol); 1440: 1441: if (!address) 1442: { 1443: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); 1444: } 1445: 1446: return address; 1447: } 1448: 1449: static struct lt_user_dlloader sys_wll = { 1450: 0, sys_wll_open, sys_wll_close, sys_wll_sym, 0, 0 1451: }; 1452: 1453: #endif /* __WINDOWS__ */ 1454: 1455: 1456: 1457: 1458: /* --- LOAD_ADD_ON() INTERFACE LOADER --- */ 1459: 1460: 1461: #ifdef __BEOS__ 1462: 1463: /* dynamic linking for BeOS */ 1464: 1465: #include <kernel/image.h> 1466: 1467: static lt_module 1468: sys_bedl_open (loader_data, filename) 1469: lt_user_data loader_data; 1470: const char *filename; 1471: { 1472: image_id image = 0; 1473: 1474: if (filename) 1475: { 1476: image = load_add_on (filename); 1477: } 1478: else 1479: { 1480: image_info info; 1481: int32 cookie = 0; 1482: if (get_next_image_info (0, &cookie, &info) == B_OK) 1483: image = load_add_on (info.name); 1484: } 1485: 1486: if (image <= 0) 1487: { 1488: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); 1489: image = 0; 1490: } 1491: 1492: return (lt_module) image; 1493: } 1494: 1495: static int 1496: sys_bedl_close (loader_data, module) 1497: lt_user_data loader_data; 1498: lt_module module; 1499: { 1500: int errors = 0; 1501: 1502: if (unload_add_on ((image_id) module) != B_OK) 1503: { 1504: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); 1505: ++errors; 1506: } 1507: 1508: return errors; 1509: } 1510: 1511: static lt_ptr 1512: sys_bedl_sym (loader_data, module, symbol) 1513: lt_user_data loader_data; 1514: lt_module module; 1515: const char *symbol; 1516: { 1517: lt_ptr address = 0; 1518: image_id image = (image_id) module; 1519: 1520: if (get_image_symbol (image, symbol, B_SYMBOL_TYPE_ANY, address) != B_OK) 1521: { 1522: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); 1523: address = 0; 1524: } 1525: 1526: return address; 1527: } 1528: 1529: static struct lt_user_dlloader sys_bedl = { 1530: 0, sys_bedl_open, sys_bedl_close, sys_bedl_sym, 0, 0 1531: }; 1532: 1533: #endif /* __BEOS__ */ 1534: 1535: 1536: 1537: 1538: /* --- DLD_LINK() INTERFACE LOADER --- */ 1539: 1540: 1541: #if HAVE_DLD 1542: 1543: /* dynamic linking with dld */ 1544: 1545: #if HAVE_DLD_H 1546: #include <dld.h> 1547: #endif 1548: 1549: static lt_module 1550: sys_dld_open (loader_data, filename) 1551: lt_user_data loader_data; 1552: const char *filename; 1553: { 1554: lt_module module = strdup (filename); 1555: 1556: if (dld_link (filename) != 0) 1557: { 1558: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); 1559: LT_DLFREE (module); 1560: module = 0; 1561: } 1562: 1563: return module; 1564: } 1565: 1566: static int 1567: sys_dld_close (loader_data, module) 1568: lt_user_data loader_data; 1569: lt_module module; 1570: { 1571: int errors = 0; 1572: 1573: if (dld_unlink_by_file ((char*)(module), 1) != 0) 1574: { 1575: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); 1576: ++errors; 1577: } 1578: else 1579: { 1580: LT_DLFREE (module); 1581: } 1582: 1583: return errors; 1584: } 1585: 1586: static lt_ptr 1587: sys_dld_sym (loader_data, module, symbol) 1588: lt_user_data loader_data; 1589: lt_module module; 1590: const char *symbol; 1591: { 1592: lt_ptr address = dld_get_func (symbol); 1593: 1594: if (!address) 1595: { 1596: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); 1597: } 1598: 1599: return address; 1600: } 1601: 1602: static struct lt_user_dlloader sys_dld = { 1603: 0, sys_dld_open, sys_dld_close, sys_dld_sym, 0, 0 1604: }; 1605: 1606: #endif /* HAVE_DLD */ 1607: 1608: /* --- DYLD() MACOSX/DARWIN INTERFACE LOADER --- */ 1609: #if HAVE_DYLD 1610: 1611: 1612: #if HAVE_MACH_O_DYLD_H 1.1.1.2 ! root 1613: #if !defined(__APPLE_CC__) && !defined(__MWERKS__) && !defined(__private_extern__) ! 1614: /* Is this correct? Does it still function properly? */ ! 1615: #define __private_extern__ extern ! 1616: #endif 1.1 root 1617: # include <mach-o/dyld.h> 1618: #endif 1619: #include <mach-o/getsect.h> 1620: 1621: /* We have to put some stuff here that isn't in older dyld.h files */ 1622: #ifndef ENUM_DYLD_BOOL 1623: # define ENUM_DYLD_BOOL 1624: # undef FALSE 1625: # undef TRUE 1626: enum DYLD_BOOL { 1627: FALSE, 1628: TRUE 1629: }; 1630: #endif 1631: #ifndef LC_REQ_DYLD 1632: # define LC_REQ_DYLD 0x80000000 1633: #endif 1634: #ifndef LC_LOAD_WEAK_DYLIB 1635: # define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD) 1636: #endif 1637: static const struct mach_header * (*ltdl_NSAddImage)(const char *image_name, unsigned long options) = 0; 1638: static NSSymbol (*ltdl_NSLookupSymbolInImage)(const struct mach_header *image,const char *symbolName, unsigned long options) = 0; 1639: static enum DYLD_BOOL (*ltdl_NSIsSymbolNameDefinedInImage)(const struct mach_header *image, const char *symbolName) = 0; 1640: static enum DYLD_BOOL (*ltdl_NSMakePrivateModulePublic)(NSModule module) = 0; 1641: 1642: #ifndef NSADDIMAGE_OPTION_NONE 1.1.1.2 ! root 1643: #define NSADDIMAGE_OPTION_NONE 0x0 1.1 root 1644: #endif 1645: #ifndef NSADDIMAGE_OPTION_RETURN_ON_ERROR 1646: #define NSADDIMAGE_OPTION_RETURN_ON_ERROR 0x1 1.1.1.2 ! root 1647: #endif 1.1 root 1648: #ifndef NSADDIMAGE_OPTION_WITH_SEARCHING 1649: #define NSADDIMAGE_OPTION_WITH_SEARCHING 0x2 1.1.1.2 ! root 1650: #endif 1.1 root 1651: #ifndef NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 1652: #define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 0x4 1653: #endif 1654: #ifndef NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME 1655: #define NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME 0x8 1656: #endif 1657: #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND 1658: #define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND 0x0 1.1.1.2 ! root 1659: #endif 1.1 root 1660: #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW 1661: #define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW 0x1 1662: #endif 1663: #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY 1664: #define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY 0x2 1665: #endif 1666: #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 1667: #define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 0x4 1668: #endif 1669: 1670: 1671: static const char * 1672: lt_int_dyld_error(othererror) 1673: char* othererror; 1674: { 1675: /* return the dyld error string, or the passed in error string if none */ 1676: NSLinkEditErrors ler; 1677: int lerno; 1678: const char *errstr; 1679: const char *file; 1.1.1.2 ! root 1680: NSLinkEditError(&ler,&lerno,&file,&errstr); 1.1 root 1681: if (!errstr || !strlen(errstr)) errstr = othererror; 1682: return errstr; 1683: } 1.1.1.2 ! root 1684: 1.1 root 1685: static const struct mach_header * 1686: lt_int_dyld_get_mach_header_from_nsmodule(module) 1687: NSModule module; 1688: { 1689: /* There should probably be an apple dyld api for this */ 1690: int i=_dyld_image_count(); 1691: int j; 1692: const char *modname=NSNameOfModule(module); 1693: const struct mach_header *mh=NULL; 1694: if (!modname) return NULL; 1695: for (j = 0; j < i; j++) 1696: { 1697: if (!strcmp(_dyld_get_image_name(j),modname)) 1698: { 1699: mh=_dyld_get_image_header(j); 1700: break; 1701: } 1702: } 1703: return mh; 1704: } 1705: 1706: static const char* lt_int_dyld_lib_install_name(mh) 1707: const struct mach_header *mh; 1.1.1.2 ! root 1708: { 1.1 root 1709: /* NSAddImage is also used to get the loaded image, but it only works if the lib 1710: is installed, for uninstalled libs we need to check the install_names against 1711: each other. Note that this is still broken if DYLD_IMAGE_SUFFIX is set and a 1712: different lib was loaded as a result 1713: */ 1714: int j; 1715: struct load_command *lc; 1716: unsigned long offset = sizeof(struct mach_header); 1717: const char* retStr=NULL; 1718: for (j = 0; j < mh->ncmds; j++) 1719: { 1720: lc = (struct load_command*)(((unsigned long)mh) + offset); 1721: if (LC_ID_DYLIB == lc->cmd) 1722: { 1.1.1.2 ! root 1723: retStr=(char*)(((struct dylib_command*)lc)->dylib.name.offset + 1.1 root 1724: (unsigned long)lc); 1725: } 1726: offset += lc->cmdsize; 1727: } 1728: return retStr; 1729: } 1730: 1731: static const struct mach_header * 1732: lt_int_dyld_match_loaded_lib_by_install_name(const char *name) 1733: { 1734: int i=_dyld_image_count(); 1735: int j; 1736: const struct mach_header *mh=NULL; 1.1.1.2 ! root 1737: const char *id=NULL; 1.1 root 1738: for (j = 0; j < i; j++) 1739: { 1740: id=lt_int_dyld_lib_install_name(_dyld_get_image_header(j)); 1741: if ((id) && (!strcmp(id,name))) 1742: { 1743: mh=_dyld_get_image_header(j); 1744: break; 1745: } 1746: } 1747: return mh; 1748: } 1.1.1.2 ! root 1749: 1.1 root 1750: static NSSymbol 1751: lt_int_dyld_NSlookupSymbolInLinkedLibs(symbol,mh) 1752: const char *symbol; 1753: const struct mach_header *mh; 1754: { 1755: /* Safe to assume our mh is good */ 1756: int j; 1757: struct load_command *lc; 1758: unsigned long offset = sizeof(struct mach_header); 1759: NSSymbol retSym = 0; 1760: const struct mach_header *mh1; 1761: if ((ltdl_NSLookupSymbolInImage) && NSIsSymbolNameDefined(symbol) ) 1762: { 1763: for (j = 0; j < mh->ncmds; j++) 1764: { 1765: lc = (struct load_command*)(((unsigned long)mh) + offset); 1766: if ((LC_LOAD_DYLIB == lc->cmd) || (LC_LOAD_WEAK_DYLIB == lc->cmd)) 1767: { 1.1.1.2 ! root 1768: mh1=lt_int_dyld_match_loaded_lib_by_install_name((char*)(((struct dylib_command*)lc)->dylib.name.offset + 1.1 root 1769: (unsigned long)lc)); 1770: if (!mh1) 1.1.1.2 ! root 1771: { ! 1772: /* Maybe NSAddImage can find it */ ! 1773: mh1=ltdl_NSAddImage((char*)(((struct dylib_command*)lc)->dylib.name.offset + 1.1 root 1774: (unsigned long)lc), 1.1.1.2 ! root 1775: NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED + 1.1 root 1776: NSADDIMAGE_OPTION_WITH_SEARCHING + 1777: NSADDIMAGE_OPTION_RETURN_ON_ERROR ); 1.1.1.2 ! root 1778: } 1.1 root 1779: if (mh1) 1780: { 1781: retSym = ltdl_NSLookupSymbolInImage(mh1, 1782: symbol, 1.1.1.2 ! root 1783: NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW 1.1 root 1784: | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 1785: ); 1.1.1.2 ! root 1786: if (retSym) break; ! 1787: } 1.1 root 1788: } 1789: offset += lc->cmdsize; 1790: } 1791: } 1792: return retSym; 1793: } 1794: 1795: static int 1796: sys_dyld_init() 1797: { 1798: int retCode = 0; 1799: int err = 0; 1.1.1.2 ! root 1800: if (!_dyld_present()) { 1.1 root 1801: retCode=1; 1802: } 1803: else { 1804: err = _dyld_func_lookup("__dyld_NSAddImage",(unsigned long*)<dl_NSAddImage); 1805: err = _dyld_func_lookup("__dyld_NSLookupSymbolInImage",(unsigned long*)<dl_NSLookupSymbolInImage); 1806: err = _dyld_func_lookup("__dyld_NSIsSymbolNameDefinedInImage",(unsigned long*)<dl_NSIsSymbolNameDefinedInImage); 1807: err = _dyld_func_lookup("__dyld_NSMakePrivateModulePublic",(unsigned long*)<dl_NSMakePrivateModulePublic); 1808: } 1809: return retCode; 1810: } 1811: 1812: static lt_module 1813: sys_dyld_open (loader_data, filename) 1814: lt_user_data loader_data; 1815: const char *filename; 1816: { 1817: lt_module module = 0; 1818: NSObjectFileImage ofi = 0; 1819: NSObjectFileImageReturnCode ofirc; 1.1.1.2 ! root 1820: ! 1821: if (!filename) 1.1 root 1822: return (lt_module)-1; 1823: ofirc = NSCreateObjectFileImageFromFile(filename, &ofi); 1824: switch (ofirc) 1825: { 1826: case NSObjectFileImageSuccess: 1827: module = NSLinkModule(ofi, filename, 1828: NSLINKMODULE_OPTION_RETURN_ON_ERROR 1829: | NSLINKMODULE_OPTION_PRIVATE 1830: | NSLINKMODULE_OPTION_BINDNOW); 1831: NSDestroyObjectFileImage(ofi); 1832: if (module) 1833: ltdl_NSMakePrivateModulePublic(module); 1834: break; 1835: case NSObjectFileImageInappropriateFile: 1836: if (ltdl_NSIsSymbolNameDefinedInImage && ltdl_NSLookupSymbolInImage) 1837: { 1.1.1.2 ! root 1838: module = (lt_module)ltdl_NSAddImage(filename, NSADDIMAGE_OPTION_RETURN_ON_ERROR); 1.1 root 1839: break; 1.1.1.2 ! root 1840: } 1.1 root 1841: default: 1842: LT_DLMUTEX_SETERROR (lt_int_dyld_error(LT_DLSTRERROR(CANNOT_OPEN))); 1843: return 0; 1844: } 1845: if (!module) LT_DLMUTEX_SETERROR (lt_int_dyld_error(LT_DLSTRERROR(CANNOT_OPEN))); 1846: return module; 1847: } 1848: 1849: static int 1850: sys_dyld_close (loader_data, module) 1851: lt_user_data loader_data; 1852: lt_module module; 1853: { 1854: int retCode = 0; 1855: int flags = 0; 1856: if (module == (lt_module)-1) return 0; 1.1.1.2 ! root 1857: #ifdef __BIG_ENDIAN__ 1.1 root 1858: if (((struct mach_header *)module)->magic == MH_MAGIC) 1.1.1.2 ! root 1859: #else 1.1 root 1860: if (((struct mach_header *)module)->magic == MH_CIGAM) 1.1.1.2 ! root 1861: #endif 1.1 root 1862: { 1863: LT_DLMUTEX_SETERROR("Can not close a dylib"); 1864: retCode = 1; 1865: } 1866: else 1867: { 1868: #if 1 1869: /* Currently, if a module contains c++ static destructors and it is unloaded, we 1870: get a segfault in atexit(), due to compiler and dynamic loader differences of 1871: opinion, this works around that. 1.1.1.2 ! root 1872: */ ! 1873: if ((const struct section *)NULL != 1.1 root 1874: getsectbynamefromheader(lt_int_dyld_get_mach_header_from_nsmodule(module), 1875: "__DATA","__mod_term_func")) 1876: { 1877: flags += NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED; 1.1.1.2 ! root 1878: } ! 1879: #endif 1.1 root 1880: #ifdef __ppc__ 1881: flags += NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES; 1882: #endif 1883: if (!NSUnLinkModule(module,flags)) 1884: { 1885: retCode=1; 1886: LT_DLMUTEX_SETERROR (lt_int_dyld_error(LT_DLSTRERROR(CANNOT_CLOSE))); 1.1.1.2 ! root 1887: } 1.1 root 1888: } 1.1.1.2 ! root 1889: 1.1 root 1890: return retCode; 1891: } 1892: 1893: static lt_ptr 1894: sys_dyld_sym (loader_data, module, symbol) 1895: lt_user_data loader_data; 1896: lt_module module; 1897: const char *symbol; 1898: { 1899: lt_ptr address = 0; 1900: NSSymbol *nssym = 0; 1901: void *unused; 1902: const struct mach_header *mh=NULL; 1.1.1.2 ! root 1903: char saveError[256] = "Symbol not found"; 1.1 root 1904: if (module == (lt_module)-1) 1905: { 1906: _dyld_lookup_and_bind(symbol,(unsigned long*)&address,&unused); 1907: return address; 1908: } 1.1.1.2 ! root 1909: #ifdef __BIG_ENDIAN__ 1.1 root 1910: if (((struct mach_header *)module)->magic == MH_MAGIC) 1.1.1.2 ! root 1911: #else 1.1 root 1912: if (((struct mach_header *)module)->magic == MH_CIGAM) 1.1.1.2 ! root 1913: #endif 1.1 root 1914: { 1915: if (ltdl_NSIsSymbolNameDefinedInImage && ltdl_NSLookupSymbolInImage) 1916: { 1917: mh=module; 1.1.1.2 ! root 1918: if (ltdl_NSIsSymbolNameDefinedInImage((struct mach_header*)module,symbol)) 1.1 root 1919: { 1920: nssym = ltdl_NSLookupSymbolInImage((struct mach_header*)module, 1921: symbol, 1.1.1.2 ! root 1922: NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW 1.1 root 1923: | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 1924: ); 1925: } 1.1.1.2 ! root 1926: } ! 1927: ! 1928: } 1.1 root 1929: else { 1930: nssym = NSLookupSymbolInModule(module, symbol); 1931: } 1.1.1.2 ! root 1932: if (!nssym) 1.1 root 1933: { 1.1.1.2 ! root 1934: strncpy(saveError, lt_int_dyld_error(LT_DLSTRERROR(SYMBOL_NOT_FOUND)), 255); ! 1935: saveError[255] = 0; 1.1 root 1936: if (!mh) mh=lt_int_dyld_get_mach_header_from_nsmodule(module); 1937: nssym = lt_int_dyld_NSlookupSymbolInLinkedLibs(symbol,mh); 1.1.1.2 ! root 1938: } ! 1939: if (!nssym) 1.1 root 1940: { 1.1.1.2 ! root 1941: LT_DLMUTEX_SETERROR (saveError); 1.1 root 1942: return NULL; 1.1.1.2 ! root 1943: } 1.1 root 1944: return NSAddressOfSymbol(nssym); 1945: } 1946: 1947: static struct lt_user_dlloader sys_dyld = 1948: { "_", sys_dyld_open, sys_dyld_close, sys_dyld_sym, 0, 0 }; 1949: 1950: 1951: #endif /* HAVE_DYLD */ 1952: 1953: 1954: /* --- DLPREOPEN() INTERFACE LOADER --- */ 1955: 1956: 1957: /* emulate dynamic linking using preloaded_symbols */ 1958: 1959: typedef struct lt_dlsymlists_t 1960: { 1961: struct lt_dlsymlists_t *next; 1962: const lt_dlsymlist *syms; 1963: } lt_dlsymlists_t; 1964: 1965: static const lt_dlsymlist *default_preloaded_symbols = 0; 1966: static lt_dlsymlists_t *preloaded_symbols = 0; 1967: 1968: static int 1969: presym_init (loader_data) 1970: lt_user_data loader_data; 1971: { 1972: int errors = 0; 1973: 1974: LT_DLMUTEX_LOCK (); 1975: 1976: preloaded_symbols = 0; 1977: if (default_preloaded_symbols) 1978: { 1979: errors = lt_dlpreload (default_preloaded_symbols); 1980: } 1981: 1982: LT_DLMUTEX_UNLOCK (); 1983: 1984: return errors; 1985: } 1986: 1987: static int 1988: presym_free_symlists () 1989: { 1990: lt_dlsymlists_t *lists; 1991: 1992: LT_DLMUTEX_LOCK (); 1993: 1994: lists = preloaded_symbols; 1995: while (lists) 1996: { 1997: lt_dlsymlists_t *tmp = lists; 1998: 1999: lists = lists->next; 2000: LT_DLFREE (tmp); 2001: } 2002: preloaded_symbols = 0; 2003: 2004: LT_DLMUTEX_UNLOCK (); 2005: 2006: return 0; 2007: } 2008: 2009: static int 2010: presym_exit (loader_data) 2011: lt_user_data loader_data; 2012: { 2013: presym_free_symlists (); 2014: return 0; 2015: } 2016: 2017: static int 2018: presym_add_symlist (preloaded) 2019: const lt_dlsymlist *preloaded; 2020: { 2021: lt_dlsymlists_t *tmp; 2022: lt_dlsymlists_t *lists; 2023: int errors = 0; 2024: 2025: LT_DLMUTEX_LOCK (); 2026: 2027: lists = preloaded_symbols; 2028: while (lists) 2029: { 2030: if (lists->syms == preloaded) 2031: { 2032: goto done; 2033: } 2034: lists = lists->next; 2035: } 2036: 2037: tmp = LT_EMALLOC (lt_dlsymlists_t, 1); 2038: if (tmp) 2039: { 2040: memset (tmp, 0, sizeof(lt_dlsymlists_t)); 2041: tmp->syms = preloaded; 2042: tmp->next = preloaded_symbols; 2043: preloaded_symbols = tmp; 2044: } 2045: else 2046: { 2047: ++errors; 2048: } 2049: 2050: done: 2051: LT_DLMUTEX_UNLOCK (); 2052: return errors; 2053: } 2054: 2055: static lt_module 2056: presym_open (loader_data, filename) 2057: lt_user_data loader_data; 2058: const char *filename; 2059: { 2060: lt_dlsymlists_t *lists; 2061: lt_module module = (lt_module) 0; 2062: 2063: LT_DLMUTEX_LOCK (); 2064: lists = preloaded_symbols; 2065: 2066: if (!lists) 2067: { 2068: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_SYMBOLS)); 2069: goto done; 2070: } 2071: 2072: /* Can't use NULL as the reflective symbol header, as NULL is 2073: used to mark the end of the entire symbol list. Self-dlpreopened 2074: symbols follow this magic number, chosen to be an unlikely 2075: clash with a real module name. */ 2076: if (!filename) 2077: { 2078: filename = "@PROGRAM@"; 2079: } 2080: 2081: while (lists) 2082: { 2083: const lt_dlsymlist *syms = lists->syms; 2084: 2085: while (syms->name) 2086: { 2087: if (!syms->address && strcmp(syms->name, filename) == 0) 2088: { 2089: module = (lt_module) syms; 2090: goto done; 2091: } 2092: ++syms; 2093: } 2094: 2095: lists = lists->next; 2096: } 2097: 2098: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); 2099: 2100: done: 2101: LT_DLMUTEX_UNLOCK (); 2102: return module; 2103: } 2104: 2105: static int 2106: presym_close (loader_data, module) 2107: lt_user_data loader_data; 2108: lt_module module; 2109: { 2110: /* Just to silence gcc -Wall */ 2111: module = 0; 2112: return 0; 2113: } 2114: 2115: static lt_ptr 2116: presym_sym (loader_data, module, symbol) 2117: lt_user_data loader_data; 2118: lt_module module; 2119: const char *symbol; 2120: { 2121: lt_dlsymlist *syms = (lt_dlsymlist*) module; 2122: 2123: ++syms; 2124: while (syms->address) 2125: { 2126: if (strcmp(syms->name, symbol) == 0) 2127: { 2128: return syms->address; 2129: } 2130: 2131: ++syms; 2132: } 2133: 2134: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); 2135: 2136: return 0; 2137: } 2138: 2139: static struct lt_user_dlloader presym = { 2140: 0, presym_open, presym_close, presym_sym, presym_exit, 0 2141: }; 2142: 2143: 2144: 2145: 2146: 2147: /* --- DYNAMIC MODULE LOADING --- */ 2148: 2149: 2150: /* The type of a function used at each iteration of foreach_dirinpath(). */ 2151: typedef int foreach_callback_func LT_PARAMS((char *filename, lt_ptr data1, 2152: lt_ptr data2)); 2153: 2154: static int foreach_dirinpath LT_PARAMS((const char *search_path, 2155: const char *base_name, 2156: foreach_callback_func *func, 2157: lt_ptr data1, lt_ptr data2)); 2158: 2159: static int find_file_callback LT_PARAMS((char *filename, lt_ptr data, 2160: lt_ptr ignored)); 2161: static int find_handle_callback LT_PARAMS((char *filename, lt_ptr data, 2162: lt_ptr ignored)); 2163: static int foreachfile_callback LT_PARAMS((char *filename, lt_ptr data1, 2164: lt_ptr data2)); 2165: 2166: 2167: static int canonicalize_path LT_PARAMS((const char *path, 2168: char **pcanonical)); 2169: static int argzize_path LT_PARAMS((const char *path, 2170: char **pargz, 2171: size_t *pargz_len)); 2172: static FILE *find_file LT_PARAMS((const char *search_path, 2173: const char *base_name, 2174: char **pdir)); 2175: static lt_dlhandle *find_handle LT_PARAMS((const char *search_path, 2176: const char *base_name, 2177: lt_dlhandle *handle)); 2178: static int find_module LT_PARAMS((lt_dlhandle *handle, 2179: const char *dir, 2180: const char *libdir, 2181: const char *dlname, 2182: const char *old_name, 2183: int installed)); 2184: static int free_vars LT_PARAMS((char *dlname, char *oldname, 2185: char *libdir, char *deplibs)); 2186: static int load_deplibs LT_PARAMS((lt_dlhandle handle, 2187: char *deplibs)); 2188: static int trim LT_PARAMS((char **dest, 2189: const char *str)); 2190: static int try_dlopen LT_PARAMS((lt_dlhandle *handle, 2191: const char *filename)); 2192: static int tryall_dlopen LT_PARAMS((lt_dlhandle *handle, 2193: const char *filename)); 2194: static int unload_deplibs LT_PARAMS((lt_dlhandle handle)); 2195: static int lt_argz_insert LT_PARAMS((char **pargz, 2196: size_t *pargz_len, 2197: char *before, 2198: const char *entry)); 2199: static int lt_argz_insertinorder LT_PARAMS((char **pargz, 2200: size_t *pargz_len, 2201: const char *entry)); 2202: static int lt_argz_insertdir LT_PARAMS((char **pargz, 2203: size_t *pargz_len, 2204: const char *dirnam, 2205: struct dirent *dp)); 2206: static int lt_dlpath_insertdir LT_PARAMS((char **ppath, 2207: char *before, 2208: const char *dir)); 2209: static int list_files_by_dir LT_PARAMS((const char *dirnam, 2210: char **pargz, 2211: size_t *pargz_len)); 2212: static int file_not_found LT_PARAMS((void)); 2213: 2214: static char *user_search_path= 0; 2215: static lt_dlloader *loaders = 0; 2216: static lt_dlhandle handles = 0; 2217: static int initialized = 0; 2218: 2219: /* Initialize libltdl. */ 2220: int 2221: lt_dlinit () 2222: { 2223: int errors = 0; 2224: 2225: LT_DLMUTEX_LOCK (); 2226: 2227: /* Initialize only at first call. */ 2228: if (++initialized == 1) 2229: { 2230: handles = 0; 2231: user_search_path = 0; /* empty search path */ 2232: 2233: #if HAVE_LIBDL 2234: errors += lt_dlloader_add (lt_dlloader_next (0), &sys_dl, "dlopen"); 2235: #endif 2236: #if HAVE_SHL_LOAD 2237: errors += lt_dlloader_add (lt_dlloader_next (0), &sys_shl, "dlopen"); 2238: #endif 2239: #ifdef __WINDOWS__ 2240: errors += lt_dlloader_add (lt_dlloader_next (0), &sys_wll, "dlopen"); 2241: #endif 2242: #ifdef __BEOS__ 2243: errors += lt_dlloader_add (lt_dlloader_next (0), &sys_bedl, "dlopen"); 2244: #endif 2245: #if HAVE_DLD 2246: errors += lt_dlloader_add (lt_dlloader_next (0), &sys_dld, "dld"); 2247: #endif 2248: #if HAVE_DYLD 2249: errors += lt_dlloader_add (lt_dlloader_next (0), &sys_dyld, "dyld"); 2250: errors += sys_dyld_init(); 2251: #endif 2252: errors += lt_dlloader_add (lt_dlloader_next (0), &presym, "dlpreload"); 2253: 2254: if (presym_init (presym.dlloader_data)) 2255: { 2256: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INIT_LOADER)); 2257: ++errors; 2258: } 2259: else if (errors != 0) 2260: { 2261: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (DLOPEN_NOT_SUPPORTED)); 2262: ++errors; 2263: } 2264: } 2265: 2266: LT_DLMUTEX_UNLOCK (); 2267: 2268: return errors; 2269: } 2270: 2271: int 2272: lt_dlpreload (preloaded) 2273: const lt_dlsymlist *preloaded; 2274: { 2275: int errors = 0; 2276: 2277: if (preloaded) 2278: { 2279: errors = presym_add_symlist (preloaded); 2280: } 2281: else 2282: { 2283: presym_free_symlists(); 2284: 2285: LT_DLMUTEX_LOCK (); 2286: if (default_preloaded_symbols) 2287: { 2288: errors = lt_dlpreload (default_preloaded_symbols); 2289: } 2290: LT_DLMUTEX_UNLOCK (); 2291: } 2292: 2293: return errors; 2294: } 2295: 2296: int 2297: lt_dlpreload_default (preloaded) 2298: const lt_dlsymlist *preloaded; 2299: { 2300: LT_DLMUTEX_LOCK (); 2301: default_preloaded_symbols = preloaded; 2302: LT_DLMUTEX_UNLOCK (); 2303: return 0; 2304: } 2305: 2306: int 2307: lt_dlexit () 2308: { 2309: /* shut down libltdl */ 2310: lt_dlloader *loader; 2311: int errors = 0; 2312: 2313: LT_DLMUTEX_LOCK (); 2314: loader = loaders; 2315: 2316: if (!initialized) 2317: { 2318: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SHUTDOWN)); 2319: ++errors; 2320: goto done; 2321: } 2322: 2323: /* shut down only at last call. */ 2324: if (--initialized == 0) 2325: { 2326: int level; 2327: 2328: while (handles && LT_DLIS_RESIDENT (handles)) 2329: { 2330: handles = handles->next; 2331: } 2332: 2333: /* close all modules */ 2334: for (level = 1; handles; ++level) 2335: { 2336: lt_dlhandle cur = handles; 2337: int saw_nonresident = 0; 2338: 2339: while (cur) 2340: { 2341: lt_dlhandle tmp = cur; 2342: cur = cur->next; 2343: if (!LT_DLIS_RESIDENT (tmp)) 2344: saw_nonresident = 1; 2345: if (!LT_DLIS_RESIDENT (tmp) && tmp->info.ref_count <= level) 2346: { 2347: if (lt_dlclose (tmp)) 2348: { 2349: ++errors; 2350: } 1.1.1.2 ! root 2351: /* Make sure that the handle pointed to by 'cur' still exists. ! 2352: lt_dlclose recursively closes dependent libraries which removes ! 2353: them from the linked list. One of these might be the one ! 2354: pointed to by 'cur'. */ ! 2355: if (cur) ! 2356: { ! 2357: for (tmp = handles; tmp; tmp = tmp->next) ! 2358: if (tmp == cur) ! 2359: break; ! 2360: if (! tmp) ! 2361: cur = handles; ! 2362: } 1.1 root 2363: } 2364: } 2365: /* done if only resident modules are left */ 2366: if (!saw_nonresident) 2367: break; 2368: } 2369: 2370: /* close all loaders */ 2371: while (loader) 2372: { 2373: lt_dlloader *next = loader->next; 2374: lt_user_data data = loader->dlloader_data; 2375: if (loader->dlloader_exit && loader->dlloader_exit (data)) 2376: { 2377: ++errors; 2378: } 2379: 2380: LT_DLMEM_REASSIGN (loader, next); 2381: } 2382: loaders = 0; 2383: } 2384: 2385: done: 2386: LT_DLMUTEX_UNLOCK (); 2387: return errors; 2388: } 2389: 2390: static int 2391: tryall_dlopen (handle, filename) 2392: lt_dlhandle *handle; 2393: const char *filename; 2394: { 2395: lt_dlhandle cur; 2396: lt_dlloader *loader; 2397: const char *saved_error; 2398: int errors = 0; 2399: 2400: LT_DLMUTEX_GETERROR (saved_error); 2401: LT_DLMUTEX_LOCK (); 2402: 2403: cur = handles; 2404: loader = loaders; 2405: 2406: /* check whether the module was already opened */ 2407: while (cur) 2408: { 2409: /* try to dlopen the program itself? */ 2410: if (!cur->info.filename && !filename) 2411: { 2412: break; 2413: } 2414: 2415: if (cur->info.filename && filename 2416: && strcmp (cur->info.filename, filename) == 0) 2417: { 2418: break; 2419: } 2420: 2421: cur = cur->next; 2422: } 2423: 2424: if (cur) 2425: { 2426: ++cur->info.ref_count; 2427: *handle = cur; 2428: goto done; 2429: } 2430: 2431: cur = *handle; 2432: if (filename) 2433: { 2434: /* Comment out the check of file permissions using access. 2435: This call seems to always return -1 with error EACCES. 2436: */ 2437: /* We need to catch missing file errors early so that 2438: file_not_found() can detect what happened. 2439: if (access (filename, R_OK) != 0) 2440: { 2441: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); 2442: ++errors; 2443: goto done; 2444: } */ 2445: 2446: cur->info.filename = lt_estrdup (filename); 2447: if (!cur->info.filename) 2448: { 2449: ++errors; 2450: goto done; 2451: } 2452: } 2453: else 2454: { 2455: cur->info.filename = 0; 2456: } 2457: 2458: while (loader) 2459: { 2460: lt_user_data data = loader->dlloader_data; 2461: 2462: cur->module = loader->module_open (data, filename); 2463: 2464: if (cur->module != 0) 2465: { 2466: break; 2467: } 2468: loader = loader->next; 2469: } 2470: 2471: if (!loader) 2472: { 2473: LT_DLFREE (cur->info.filename); 2474: ++errors; 2475: goto done; 2476: } 2477: 2478: cur->loader = loader; 2479: LT_DLMUTEX_SETERROR (saved_error); 2480: 2481: done: 2482: LT_DLMUTEX_UNLOCK (); 2483: 2484: return errors; 2485: } 2486: 2487: static int 2488: tryall_dlopen_module (handle, prefix, dirname, dlname) 2489: lt_dlhandle *handle; 2490: const char *prefix; 2491: const char *dirname; 2492: const char *dlname; 2493: { 2494: int error = 0; 2495: char *filename = 0; 2496: size_t filename_len = 0; 2497: size_t dirname_len = LT_STRLEN (dirname); 2498: 2499: assert (handle); 2500: assert (dirname); 2501: assert (dlname); 2502: #ifdef LT_DIRSEP_CHAR 2503: /* Only canonicalized names (i.e. with DIRSEP chars already converted) 2504: should make it into this function: */ 2505: assert (strchr (dirname, LT_DIRSEP_CHAR) == 0); 2506: #endif 2507: 2508: if (dirname_len > 0) 2509: if (dirname[dirname_len -1] == '/') 2510: --dirname_len; 2511: filename_len = dirname_len + 1 + LT_STRLEN (dlname); 2512: 2513: /* Allocate memory, and combine DIRNAME and MODULENAME into it. 2514: The PREFIX (if any) is handled below. */ 2515: filename = LT_EMALLOC (char, dirname_len + 1 + filename_len + 1); 2516: if (!filename) 2517: return 1; 2518: 2519: sprintf (filename, "%.*s/%s", (int) dirname_len, dirname, dlname); 2520: 2521: /* Now that we have combined DIRNAME and MODULENAME, if there is 2522: also a PREFIX to contend with, simply recurse with the arguments 2523: shuffled. Otherwise, attempt to open FILENAME as a module. */ 2524: if (prefix) 2525: { 2526: error += tryall_dlopen_module (handle, 2527: (const char *) 0, prefix, filename); 2528: } 2529: else if (tryall_dlopen (handle, filename) != 0) 2530: { 2531: ++error; 2532: } 2533: 2534: LT_DLFREE (filename); 2535: return error; 2536: } 2537: 2538: static int 2539: find_module (handle, dir, libdir, dlname, old_name, installed) 2540: lt_dlhandle *handle; 2541: const char *dir; 2542: const char *libdir; 2543: const char *dlname; 2544: const char *old_name; 2545: int installed; 2546: { 2547: /* Try to open the old library first; if it was dlpreopened, 2548: we want the preopened version of it, even if a dlopenable 2549: module is available. */ 2550: if (old_name && tryall_dlopen (handle, old_name) == 0) 2551: { 2552: return 0; 2553: } 2554: 2555: /* Try to open the dynamic library. */ 2556: if (dlname) 2557: { 2558: /* try to open the installed module */ 2559: if (installed && libdir) 2560: { 2561: if (tryall_dlopen_module (handle, 2562: (const char *) 0, libdir, dlname) == 0) 2563: return 0; 2564: } 2565: 2566: /* try to open the not-installed module */ 2567: if (!installed) 2568: { 2569: if (tryall_dlopen_module (handle, dir, objdir, dlname) == 0) 2570: return 0; 2571: } 2572: 2573: /* maybe it was moved to another directory */ 2574: { 1.1.1.2 ! root 2575: if (dir && (tryall_dlopen_module (handle, ! 2576: (const char *) 0, dir, dlname) == 0)) 1.1 root 2577: return 0; 2578: } 2579: } 2580: 2581: return 1; 2582: } 2583: 2584: 2585: static int 2586: canonicalize_path (path, pcanonical) 2587: const char *path; 2588: char **pcanonical; 2589: { 2590: char *canonical = 0; 2591: 2592: assert (path && *path); 2593: assert (pcanonical); 2594: 2595: canonical = LT_EMALLOC (char, 1+ LT_STRLEN (path)); 2596: if (!canonical) 2597: return 1; 2598: 2599: { 2600: size_t dest = 0; 2601: size_t src; 2602: for (src = 0; path[src] != LT_EOS_CHAR; ++src) 2603: { 2604: /* Path separators are not copied to the beginning or end of 2605: the destination, or if another separator would follow 2606: immediately. */ 2607: if (path[src] == LT_PATHSEP_CHAR) 2608: { 2609: if ((dest == 0) 2610: || (path[1+ src] == LT_PATHSEP_CHAR) 2611: || (path[1+ src] == LT_EOS_CHAR)) 2612: continue; 2613: } 2614: 2615: /* Anything other than a directory separator is copied verbatim. */ 2616: if ((path[src] != '/') 2617: #ifdef LT_DIRSEP_CHAR 2618: && (path[src] != LT_DIRSEP_CHAR) 2619: #endif 2620: ) 2621: { 2622: canonical[dest++] = path[src]; 2623: } 2624: /* Directory separators are converted and copied only if they are 2625: not at the end of a path -- i.e. before a path separator or 2626: NULL terminator. */ 2627: else if ((path[1+ src] != LT_PATHSEP_CHAR) 2628: && (path[1+ src] != LT_EOS_CHAR) 2629: #ifdef LT_DIRSEP_CHAR 2630: && (path[1+ src] != LT_DIRSEP_CHAR) 2631: #endif 2632: && (path[1+ src] != '/')) 2633: { 2634: canonical[dest++] = '/'; 2635: } 2636: } 2637: 2638: /* Add an end-of-string marker at the end. */ 2639: canonical[dest] = LT_EOS_CHAR; 2640: } 2641: 2642: /* Assign new value. */ 2643: *pcanonical = canonical; 2644: 2645: return 0; 2646: } 2647: 2648: static int 2649: argzize_path (path, pargz, pargz_len) 2650: const char *path; 2651: char **pargz; 2652: size_t *pargz_len; 2653: { 2654: error_t error; 2655: 2656: assert (path); 2657: assert (pargz); 2658: assert (pargz_len); 2659: 2660: if ((error = argz_create_sep (path, LT_PATHSEP_CHAR, pargz, pargz_len))) 2661: { 2662: switch (error) 2663: { 2664: case ENOMEM: 2665: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); 2666: break; 2667: default: 2668: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN)); 2669: break; 2670: } 2671: 2672: return 1; 2673: } 2674: 2675: return 0; 2676: } 2677: 2678: /* Repeatedly call FUNC with each LT_PATHSEP_CHAR delimited element 2679: of SEARCH_PATH and references to DATA1 and DATA2, until FUNC returns 2680: non-zero or all elements are exhausted. If BASE_NAME is non-NULL, 2681: it is appended to each SEARCH_PATH element before FUNC is called. */ 2682: static int 2683: foreach_dirinpath (search_path, base_name, func, data1, data2) 2684: const char *search_path; 2685: const char *base_name; 2686: foreach_callback_func *func; 2687: lt_ptr data1; 2688: lt_ptr data2; 2689: { 2690: int result = 0; 2691: int filenamesize = 0; 2692: size_t lenbase = LT_STRLEN (base_name); 2693: size_t argz_len = 0; 2694: char *argz = 0; 2695: char *filename = 0; 2696: char *canonical = 0; 2697: 2698: LT_DLMUTEX_LOCK (); 2699: 2700: if (!search_path || !*search_path) 2701: { 2702: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); 2703: goto cleanup; 2704: } 2705: 2706: if (canonicalize_path (search_path, &canonical) != 0) 2707: goto cleanup; 2708: 2709: if (argzize_path (canonical, &argz, &argz_len) != 0) 2710: goto cleanup; 2711: 2712: { 2713: char *dir_name = 0; 2714: while ((dir_name = argz_next (argz, argz_len, dir_name))) 2715: { 2716: size_t lendir = LT_STRLEN (dir_name); 2717: 2718: if (lendir +1 +lenbase >= filenamesize) 2719: { 2720: LT_DLFREE (filename); 2721: filenamesize = lendir +1 +lenbase +1; /* "/d" + '/' + "f" + '\0' */ 2722: filename = LT_EMALLOC (char, filenamesize); 2723: if (!filename) 2724: goto cleanup; 2725: } 2726: 2727: assert (filenamesize > lendir); 2728: strcpy (filename, dir_name); 2729: 2730: if (base_name && *base_name) 2731: { 2732: if (filename[lendir -1] != '/') 2733: filename[lendir++] = '/'; 2734: strcpy (filename +lendir, base_name); 2735: } 2736: 2737: if ((result = (*func) (filename, data1, data2))) 2738: { 2739: break; 2740: } 2741: } 2742: } 2743: 2744: cleanup: 2745: LT_DLFREE (argz); 2746: LT_DLFREE (canonical); 2747: LT_DLFREE (filename); 2748: 2749: LT_DLMUTEX_UNLOCK (); 2750: 2751: return result; 2752: } 2753: 2754: /* If FILEPATH can be opened, store the name of the directory component 2755: in DATA1, and the opened FILE* structure address in DATA2. Otherwise 2756: DATA1 is unchanged, but DATA2 is set to a pointer to NULL. */ 2757: static int 2758: find_file_callback (filename, data1, data2) 2759: char *filename; 2760: lt_ptr data1; 2761: lt_ptr data2; 2762: { 2763: char **pdir = (char **) data1; 2764: FILE **pfile = (FILE **) data2; 2765: int is_done = 0; 2766: 2767: assert (filename && *filename); 2768: assert (pdir); 2769: assert (pfile); 2770: 2771: if ((*pfile = fopen (filename, LT_READTEXT_MODE))) 2772: { 2773: char *dirend = strrchr (filename, '/'); 2774: 2775: if (dirend > filename) 2776: *dirend = LT_EOS_CHAR; 2777: 2778: LT_DLFREE (*pdir); 2779: *pdir = lt_estrdup (filename); 2780: is_done = (*pdir == 0) ? -1 : 1; 2781: } 2782: 2783: return is_done; 2784: } 2785: 2786: static FILE * 2787: find_file (search_path, base_name, pdir) 2788: const char *search_path; 2789: const char *base_name; 2790: char **pdir; 2791: { 2792: FILE *file = 0; 2793: 2794: foreach_dirinpath (search_path, base_name, find_file_callback, pdir, &file); 2795: 2796: return file; 2797: } 2798: 2799: static int 2800: find_handle_callback (filename, data, ignored) 2801: char *filename; 2802: lt_ptr data; 2803: lt_ptr ignored; 2804: { 2805: lt_dlhandle *handle = (lt_dlhandle *) data; 2806: int notfound = access (filename, R_OK); 2807: 2808: /* Bail out if file cannot be read... */ 2809: if (notfound) 2810: return 0; 2811: 2812: /* Try to dlopen the file, but do not continue searching in any 2813: case. */ 2814: if (tryall_dlopen (handle, filename) != 0) 2815: *handle = 0; 2816: 2817: return 1; 2818: } 2819: 2820: /* If HANDLE was found return it, otherwise return 0. If HANDLE was 2821: found but could not be opened, *HANDLE will be set to 0. */ 2822: static lt_dlhandle * 2823: find_handle (search_path, base_name, handle) 2824: const char *search_path; 2825: const char *base_name; 2826: lt_dlhandle *handle; 2827: { 2828: if (!search_path) 2829: return 0; 2830: 2831: if (!foreach_dirinpath (search_path, base_name, find_handle_callback, 2832: handle, 0)) 2833: return 0; 2834: 2835: return handle; 2836: } 2837: 2838: static int 2839: load_deplibs (handle, deplibs) 2840: lt_dlhandle handle; 2841: char *deplibs; 2842: { 2843: #if LTDL_DLOPEN_DEPLIBS 2844: char *p, *save_search_path = 0; 2845: int depcount = 0; 2846: int i; 2847: char **names = 0; 2848: #endif 2849: int errors = 0; 2850: 2851: handle->depcount = 0; 2852: 2853: #if LTDL_DLOPEN_DEPLIBS 2854: if (!deplibs) 2855: { 2856: return errors; 2857: } 2858: ++errors; 2859: 2860: LT_DLMUTEX_LOCK (); 2861: if (user_search_path) 2862: { 2863: save_search_path = lt_estrdup (user_search_path); 2864: if (!save_search_path) 2865: goto cleanup; 2866: } 2867: 2868: /* extract search paths and count deplibs */ 2869: p = deplibs; 2870: while (*p) 2871: { 2872: if (!isspace ((int) *p)) 2873: { 2874: char *end = p+1; 2875: while (*end && !isspace((int) *end)) 2876: { 2877: ++end; 2878: } 2879: 2880: if (strncmp(p, "-L", 2) == 0 || strncmp(p, "-R", 2) == 0) 2881: { 2882: char save = *end; 2883: *end = 0; /* set a temporary string terminator */ 2884: if (lt_dladdsearchdir(p+2)) 2885: { 2886: goto cleanup; 2887: } 2888: *end = save; 2889: } 2890: else 2891: { 2892: ++depcount; 2893: } 2894: 2895: p = end; 2896: } 2897: else 2898: { 2899: ++p; 2900: } 2901: } 2902: 2903: if (!depcount) 2904: { 2905: errors = 0; 2906: goto cleanup; 2907: } 2908: 2909: names = LT_EMALLOC (char *, depcount * sizeof (char*)); 2910: if (!names) 2911: goto cleanup; 2912: 2913: /* now only extract the actual deplibs */ 2914: depcount = 0; 2915: p = deplibs; 2916: while (*p) 2917: { 2918: if (isspace ((int) *p)) 2919: { 2920: ++p; 2921: } 2922: else 2923: { 2924: char *end = p+1; 2925: while (*end && !isspace ((int) *end)) 2926: { 2927: ++end; 2928: } 2929: 2930: if (strncmp(p, "-L", 2) != 0 && strncmp(p, "-R", 2) != 0) 2931: { 2932: char *name; 2933: char save = *end; 2934: *end = 0; /* set a temporary string terminator */ 2935: if (strncmp(p, "-l", 2) == 0) 2936: { 2937: size_t name_len = 3+ /* "lib" */ LT_STRLEN (p + 2); 2938: name = LT_EMALLOC (char, 1+ name_len); 2939: if (name) 2940: sprintf (name, "lib%s", p+2); 2941: } 2942: else 2943: name = lt_estrdup(p); 2944: 2945: if (!name) 2946: goto cleanup_names; 2947: 2948: names[depcount++] = name; 2949: *end = save; 2950: } 2951: p = end; 2952: } 2953: } 2954: 2955: /* load the deplibs (in reverse order) 2956: At this stage, don't worry if the deplibs do not load correctly, 2957: they may already be statically linked into the loading application 2958: for instance. There will be a more enlightening error message 2959: later on if the loaded module cannot resolve all of its symbols. */ 2960: if (depcount) 2961: { 2962: int j = 0; 2963: 2964: handle->deplibs = (lt_dlhandle*) LT_EMALLOC (lt_dlhandle *, depcount); 2965: if (!handle->deplibs) 1.1.1.2 ! root 2966: goto cleanup_names; 1.1 root 2967: 2968: for (i = 0; i < depcount; ++i) 2969: { 2970: handle->deplibs[j] = lt_dlopenext(names[depcount-1-i]); 2971: if (handle->deplibs[j]) 2972: { 2973: ++j; 2974: } 2975: } 2976: 2977: handle->depcount = j; /* Number of successfully loaded deplibs */ 2978: errors = 0; 2979: } 2980: 2981: cleanup_names: 2982: for (i = 0; i < depcount; ++i) 2983: { 2984: LT_DLFREE (names[i]); 2985: } 2986: 2987: cleanup: 2988: LT_DLFREE (names); 1.1.1.2 ! root 2989: /* restore the old search path */ ! 2990: if (user_search_path) { ! 2991: LT_DLFREE (user_search_path); ! 2992: user_search_path = save_search_path; ! 2993: } ! 2994: LT_DLMUTEX_UNLOCK (); ! 2995: 1.1 root 2996: #endif 2997: 2998: return errors; 2999: } 3000: 3001: static int 3002: unload_deplibs (handle) 3003: lt_dlhandle handle; 3004: { 3005: int i; 3006: int errors = 0; 3007: 3008: if (handle->depcount) 3009: { 3010: for (i = 0; i < handle->depcount; ++i) 3011: { 3012: if (!LT_DLIS_RESIDENT (handle->deplibs[i])) 3013: { 3014: errors += lt_dlclose (handle->deplibs[i]); 3015: } 3016: } 1.1.1.2 ! root 3017: LT_DLFREE (handle->deplibs); 1.1 root 3018: } 3019: 3020: return errors; 3021: } 3022: 3023: static int 3024: trim (dest, str) 3025: char **dest; 3026: const char *str; 3027: { 3028: /* remove the leading and trailing "'" from str 3029: and store the result in dest */ 3030: const char *end = strrchr (str, '\''); 3031: size_t len = LT_STRLEN (str); 3032: char *tmp; 3033: 3034: LT_DLFREE (*dest); 3035: 1.1.1.2 ! root 3036: if (!end) ! 3037: return 1; ! 3038: 1.1 root 3039: if (len > 3 && str[0] == '\'') 3040: { 3041: tmp = LT_EMALLOC (char, end - str); 3042: if (!tmp) 3043: return 1; 3044: 3045: strncpy(tmp, &str[1], (end - str) - 1); 3046: tmp[len-3] = LT_EOS_CHAR; 3047: *dest = tmp; 3048: } 3049: else 3050: { 3051: *dest = 0; 3052: } 3053: 3054: return 0; 3055: } 3056: 3057: static int 3058: free_vars (dlname, oldname, libdir, deplibs) 3059: char *dlname; 3060: char *oldname; 3061: char *libdir; 3062: char *deplibs; 3063: { 3064: LT_DLFREE (dlname); 3065: LT_DLFREE (oldname); 3066: LT_DLFREE (libdir); 3067: LT_DLFREE (deplibs); 3068: 3069: return 0; 3070: } 3071: 3072: static int 3073: try_dlopen (phandle, filename) 3074: lt_dlhandle *phandle; 3075: const char *filename; 3076: { 3077: const char * ext = 0; 3078: const char * saved_error = 0; 3079: char * canonical = 0; 3080: char * base_name = 0; 3081: char * dir = 0; 3082: char * name = 0; 3083: int errors = 0; 3084: lt_dlhandle newhandle; 3085: 3086: assert (phandle); 3087: assert (*phandle == 0); 3088: 3089: LT_DLMUTEX_GETERROR (saved_error); 3090: 3091: /* dlopen self? */ 3092: if (!filename) 3093: { 3094: *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1); 3095: if (*phandle == 0) 3096: return 1; 3097: 3098: memset (*phandle, 0, sizeof(struct lt_dlhandle_struct)); 3099: newhandle = *phandle; 3100: 3101: /* lt_dlclose()ing yourself is very bad! Disallow it. */ 3102: LT_DLSET_FLAG (*phandle, LT_DLRESIDENT_FLAG); 3103: 3104: if (tryall_dlopen (&newhandle, 0) != 0) 3105: { 3106: LT_DLFREE (*phandle); 3107: return 1; 3108: } 3109: 3110: goto register_handle; 3111: } 3112: 3113: assert (filename && *filename); 3114: 3115: /* Doing this immediately allows internal functions to safely 3116: assume only canonicalized paths are passed. */ 3117: if (canonicalize_path (filename, &canonical) != 0) 3118: { 3119: ++errors; 3120: goto cleanup; 3121: } 3122: 3123: /* If the canonical module name is a path (relative or absolute) 3124: then split it into a directory part and a name part. */ 3125: base_name = strrchr (canonical, '/'); 3126: if (base_name) 3127: { 3128: size_t dirlen = (1+ base_name) - canonical; 3129: 3130: dir = LT_EMALLOC (char, 1+ dirlen); 3131: if (!dir) 3132: { 3133: ++errors; 3134: goto cleanup; 3135: } 3136: 3137: strncpy (dir, canonical, dirlen); 3138: dir[dirlen] = LT_EOS_CHAR; 3139: 3140: ++base_name; 3141: } 3142: else 1.1.1.2 ! root 3143: base_name = canonical; 1.1 root 3144: 3145: assert (base_name && *base_name); 3146: 3147: /* Check whether we are opening a libtool module (.la extension). */ 3148: ext = strrchr (base_name, '.'); 3149: if (ext && strcmp (ext, archive_ext) == 0) 3150: { 3151: /* this seems to be a libtool module */ 3152: FILE * file = 0; 3153: char * dlname = 0; 3154: char * old_name = 0; 3155: char * libdir = 0; 3156: char * deplibs = 0; 3157: char * line = 0; 3158: size_t line_len; 3159: 3160: /* if we can't find the installed flag, it is probably an 3161: installed libtool archive, produced with an old version 3162: of libtool */ 3163: int installed = 1; 3164: 3165: /* extract the module name from the file name */ 3166: name = LT_EMALLOC (char, ext - base_name + 1); 3167: if (!name) 3168: { 3169: ++errors; 3170: goto cleanup; 3171: } 3172: 3173: /* canonicalize the module name */ 3174: { 3175: size_t i; 3176: for (i = 0; i < ext - base_name; ++i) 3177: { 3178: if (isalnum ((int)(base_name[i]))) 3179: { 3180: name[i] = base_name[i]; 3181: } 3182: else 3183: { 3184: name[i] = '_'; 3185: } 3186: } 3187: name[ext - base_name] = LT_EOS_CHAR; 3188: } 3189: 3190: /* Now try to open the .la file. If there is no directory name 3191: component, try to find it first in user_search_path and then other 3192: prescribed paths. Otherwise (or in any case if the module was not 3193: yet found) try opening just the module name as passed. */ 3194: if (!dir) 3195: { 3196: const char *search_path; 3197: 3198: LT_DLMUTEX_LOCK (); 3199: search_path = user_search_path; 3200: if (search_path) 3201: file = find_file (user_search_path, base_name, &dir); 3202: LT_DLMUTEX_UNLOCK (); 3203: 3204: if (!file) 3205: { 3206: search_path = getenv (LTDL_SEARCHPATH_VAR); 3207: if (search_path) 3208: file = find_file (search_path, base_name, &dir); 3209: } 3210: 3211: #ifdef LTDL_SHLIBPATH_VAR 3212: if (!file) 3213: { 3214: search_path = getenv (LTDL_SHLIBPATH_VAR); 3215: if (search_path) 3216: file = find_file (search_path, base_name, &dir); 3217: } 3218: #endif 3219: #ifdef LTDL_SYSSEARCHPATH 3220: if (!file && sys_search_path) 3221: { 3222: file = find_file (sys_search_path, base_name, &dir); 3223: } 3224: #endif 3225: } 3226: if (!file) 3227: { 3228: file = fopen (filename, LT_READTEXT_MODE); 3229: } 3230: 3231: /* If we didn't find the file by now, it really isn't there. Set 3232: the status flag, and bail out. */ 3233: if (!file) 3234: { 3235: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); 3236: ++errors; 3237: goto cleanup; 3238: } 3239: 3240: line_len = LT_FILENAME_MAX; 3241: line = LT_EMALLOC (char, line_len); 3242: if (!line) 3243: { 3244: fclose (file); 3245: ++errors; 3246: goto cleanup; 3247: } 3248: 3249: /* read the .la file */ 3250: while (!feof (file)) 3251: { 3252: if (!fgets (line, (int) line_len, file)) 3253: { 3254: break; 3255: } 3256: 3257: /* Handle the case where we occasionally need to read a line 3258: that is longer than the initial buffer size. */ 3259: while ((line[LT_STRLEN(line) -1] != '\n') && (!feof (file))) 3260: { 3261: line = LT_DLREALLOC (char, line, line_len *2); 3262: if (!fgets (&line[line_len -1], (int) line_len +1, file)) 3263: { 3264: break; 3265: } 3266: line_len *= 2; 3267: } 3268: 3269: if (line[0] == '\n' || line[0] == '#') 3270: { 3271: continue; 3272: } 3273: 3274: #undef STR_DLNAME 3275: #define STR_DLNAME "dlname=" 3276: if (strncmp (line, STR_DLNAME, sizeof (STR_DLNAME) - 1) == 0) 3277: { 3278: errors += trim (&dlname, &line[sizeof (STR_DLNAME) - 1]); 3279: } 3280: 3281: #undef STR_OLD_LIBRARY 3282: #define STR_OLD_LIBRARY "old_library=" 3283: else if (strncmp (line, STR_OLD_LIBRARY, 3284: sizeof (STR_OLD_LIBRARY) - 1) == 0) 3285: { 3286: errors += trim (&old_name, &line[sizeof (STR_OLD_LIBRARY) - 1]); 3287: } 3288: #undef STR_LIBDIR 3289: #define STR_LIBDIR "libdir=" 3290: else if (strncmp (line, STR_LIBDIR, sizeof (STR_LIBDIR) - 1) == 0) 3291: { 3292: errors += trim (&libdir, &line[sizeof(STR_LIBDIR) - 1]); 3293: } 3294: 3295: #undef STR_DL_DEPLIBS 3296: #define STR_DL_DEPLIBS "dependency_libs=" 3297: else if (strncmp (line, STR_DL_DEPLIBS, 3298: sizeof (STR_DL_DEPLIBS) - 1) == 0) 3299: { 3300: errors += trim (&deplibs, &line[sizeof (STR_DL_DEPLIBS) - 1]); 3301: } 3302: else if (strcmp (line, "installed=yes\n") == 0) 3303: { 3304: installed = 1; 3305: } 3306: else if (strcmp (line, "installed=no\n") == 0) 3307: { 3308: installed = 0; 3309: } 3310: 3311: #undef STR_LIBRARY_NAMES 3312: #define STR_LIBRARY_NAMES "library_names=" 3313: else if (! dlname && strncmp (line, STR_LIBRARY_NAMES, 3314: sizeof (STR_LIBRARY_NAMES) - 1) == 0) 3315: { 3316: char *last_libname; 3317: errors += trim (&dlname, &line[sizeof (STR_LIBRARY_NAMES) - 1]); 3318: if (!errors 3319: && dlname 3320: && (last_libname = strrchr (dlname, ' ')) != 0) 3321: { 3322: last_libname = lt_estrdup (last_libname + 1); 3323: if (!last_libname) 3324: { 3325: ++errors; 3326: goto cleanup; 3327: } 3328: LT_DLMEM_REASSIGN (dlname, last_libname); 3329: } 3330: } 3331: 3332: if (errors) 3333: break; 3334: } 3335: 3336: fclose (file); 3337: LT_DLFREE (line); 3338: 3339: /* allocate the handle */ 3340: *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1); 3341: if (*phandle == 0) 3342: ++errors; 3343: 3344: if (errors) 3345: { 3346: free_vars (dlname, old_name, libdir, deplibs); 3347: LT_DLFREE (*phandle); 3348: goto cleanup; 3349: } 3350: 3351: assert (*phandle); 3352: 3353: memset (*phandle, 0, sizeof(struct lt_dlhandle_struct)); 3354: if (load_deplibs (*phandle, deplibs) == 0) 3355: { 3356: newhandle = *phandle; 3357: /* find_module may replace newhandle */ 3358: if (find_module (&newhandle, dir, libdir, dlname, old_name, installed)) 3359: { 3360: unload_deplibs (*phandle); 3361: ++errors; 3362: } 3363: } 3364: else 3365: { 3366: ++errors; 3367: } 3368: 3369: free_vars (dlname, old_name, libdir, deplibs); 3370: if (errors) 3371: { 3372: LT_DLFREE (*phandle); 3373: goto cleanup; 3374: } 3375: 3376: if (*phandle != newhandle) 3377: { 3378: unload_deplibs (*phandle); 3379: } 3380: } 3381: else 3382: { 3383: /* not a libtool module */ 3384: *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1); 3385: if (*phandle == 0) 3386: { 3387: ++errors; 3388: goto cleanup; 3389: } 3390: 3391: memset (*phandle, 0, sizeof (struct lt_dlhandle_struct)); 3392: newhandle = *phandle; 3393: 3394: /* If the module has no directory name component, try to find it 3395: first in user_search_path and then other prescribed paths. 3396: Otherwise (or in any case if the module was not yet found) try 3397: opening just the module name as passed. */ 3398: if ((dir || (!find_handle (user_search_path, base_name, &newhandle) 3399: && !find_handle (getenv (LTDL_SEARCHPATH_VAR), base_name, 3400: &newhandle) 3401: #ifdef LTDL_SHLIBPATH_VAR 3402: && !find_handle (getenv (LTDL_SHLIBPATH_VAR), base_name, 3403: &newhandle) 3404: #endif 3405: #ifdef LTDL_SYSSEARCHPATH 3406: && !find_handle (sys_search_path, base_name, &newhandle) 3407: #endif 3408: ))) 3409: { 3410: if (tryall_dlopen (&newhandle, filename) != 0) 3411: { 3412: newhandle = NULL; 3413: } 3414: } 3415: 3416: if (!newhandle) 3417: { 3418: LT_DLFREE (*phandle); 3419: ++errors; 3420: goto cleanup; 3421: } 3422: } 3423: 3424: register_handle: 3425: LT_DLMEM_REASSIGN (*phandle, newhandle); 3426: 3427: if ((*phandle)->info.ref_count == 0) 3428: { 3429: (*phandle)->info.ref_count = 1; 3430: LT_DLMEM_REASSIGN ((*phandle)->info.name, name); 3431: 3432: LT_DLMUTEX_LOCK (); 3433: (*phandle)->next = handles; 3434: handles = *phandle; 3435: LT_DLMUTEX_UNLOCK (); 3436: } 3437: 3438: LT_DLMUTEX_SETERROR (saved_error); 3439: 3440: cleanup: 3441: LT_DLFREE (dir); 3442: LT_DLFREE (name); 3443: LT_DLFREE (canonical); 3444: 3445: return errors; 3446: } 3447: 3448: lt_dlhandle 3449: lt_dlopen (filename) 3450: const char *filename; 3451: { 3452: lt_dlhandle handle = 0; 3453: 3454: /* Just incase we missed a code path in try_dlopen() that reports 3455: an error, but forgets to reset handle... */ 3456: if (try_dlopen (&handle, filename) != 0) 3457: return 0; 3458: 3459: return handle; 3460: } 3461: 3462: /* If the last error messge store was `FILE_NOT_FOUND', then return 3463: non-zero. */ 3464: static int 3465: file_not_found () 3466: { 3467: const char *error = 0; 3468: 3469: LT_DLMUTEX_GETERROR (error); 3470: if (error == LT_DLSTRERROR (FILE_NOT_FOUND)) 3471: return 1; 3472: 3473: return 0; 3474: } 3475: 3476: /* If FILENAME has an ARCHIVE_EXT or SHLIB_EXT extension, try to 3477: open the FILENAME as passed. Otherwise try appending ARCHIVE_EXT, 3478: and if a file is still not found try again with SHLIB_EXT appended 3479: instead. */ 3480: lt_dlhandle 3481: lt_dlopenext (filename) 3482: const char *filename; 3483: { 3484: lt_dlhandle handle = 0; 3485: char * tmp = 0; 3486: char * ext = 0; 3487: size_t len; 3488: int errors = 0; 3489: 3490: if (!filename) 3491: { 3492: return lt_dlopen (filename); 3493: } 3494: 3495: assert (filename); 3496: 3497: len = LT_STRLEN (filename); 3498: ext = strrchr (filename, '.'); 3499: 3500: /* If FILENAME already bears a suitable extension, there is no need 3501: to try appending additional extensions. */ 3502: if (ext && ((strcmp (ext, archive_ext) == 0) 3503: #ifdef LTDL_SHLIB_EXT 3504: || (strcmp (ext, shlib_ext) == 0) 3505: #endif 3506: )) 3507: { 3508: return lt_dlopen (filename); 3509: } 3510: 3511: /* First try appending ARCHIVE_EXT. */ 3512: tmp = LT_EMALLOC (char, len + LT_STRLEN (archive_ext) + 1); 3513: if (!tmp) 3514: return 0; 3515: 3516: strcpy (tmp, filename); 3517: strcat (tmp, archive_ext); 3518: errors = try_dlopen (&handle, tmp); 3519: 3520: /* If we found FILENAME, stop searching -- whether we were able to 3521: load the file as a module or not. If the file exists but loading 3522: failed, it is better to return an error message here than to 3523: report FILE_NOT_FOUND when the alternatives (foo.so etc) are not 3524: in the module search path. */ 3525: if (handle || ((errors > 0) && !file_not_found ())) 3526: { 3527: LT_DLFREE (tmp); 3528: return handle; 3529: } 3530: 3531: #ifdef LTDL_SHLIB_EXT 3532: /* Try appending SHLIB_EXT. */ 3533: if (LT_STRLEN (shlib_ext) > LT_STRLEN (archive_ext)) 3534: { 3535: LT_DLFREE (tmp); 3536: tmp = LT_EMALLOC (char, len + LT_STRLEN (shlib_ext) + 1); 3537: if (!tmp) 3538: return 0; 3539: 3540: strcpy (tmp, filename); 3541: } 3542: else 3543: { 3544: tmp[len] = LT_EOS_CHAR; 3545: } 3546: 3547: strcat(tmp, shlib_ext); 3548: errors = try_dlopen (&handle, tmp); 3549: 3550: /* As before, if the file was found but loading failed, return now 3551: with the current error message. */ 3552: if (handle || ((errors > 0) && !file_not_found ())) 3553: { 3554: LT_DLFREE (tmp); 3555: return handle; 3556: } 3557: #endif 3558: 3559: /* Still here? Then we really did fail to locate any of the file 3560: names we tried. */ 3561: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); 3562: LT_DLFREE (tmp); 3563: return 0; 3564: } 3565: 3566: 3567: static int 3568: lt_argz_insert (pargz, pargz_len, before, entry) 3569: char **pargz; 3570: size_t *pargz_len; 3571: char *before; 3572: const char *entry; 3573: { 3574: error_t error; 3575: 1.1.1.2 ! root 3576: /* Prior to Sep 8, 2005, newlib had a bug where argz_insert(pargz, ! 3577: pargz_len, NULL, entry) failed with EINVAL. */ ! 3578: if (before) ! 3579: error = argz_insert (pargz, pargz_len, before, entry); ! 3580: else ! 3581: error = argz_append (pargz, pargz_len, entry, 1 + LT_STRLEN (entry)); ! 3582: ! 3583: if (error) 1.1 root 3584: { 3585: switch (error) 3586: { 3587: case ENOMEM: 3588: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); 3589: break; 3590: default: 3591: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN)); 3592: break; 3593: } 3594: return 1; 3595: } 3596: 3597: return 0; 3598: } 3599: 3600: static int 3601: lt_argz_insertinorder (pargz, pargz_len, entry) 3602: char **pargz; 3603: size_t *pargz_len; 3604: const char *entry; 3605: { 3606: char *before = 0; 3607: 3608: assert (pargz); 3609: assert (pargz_len); 3610: assert (entry && *entry); 3611: 3612: if (*pargz) 3613: while ((before = argz_next (*pargz, *pargz_len, before))) 3614: { 3615: int cmp = strcmp (entry, before); 3616: 3617: if (cmp < 0) break; 3618: if (cmp == 0) return 0; /* No duplicates! */ 3619: } 3620: 3621: return lt_argz_insert (pargz, pargz_len, before, entry); 3622: } 3623: 3624: static int 3625: lt_argz_insertdir (pargz, pargz_len, dirnam, dp) 3626: char **pargz; 3627: size_t *pargz_len; 3628: const char *dirnam; 3629: struct dirent *dp; 3630: { 3631: char *buf = 0; 3632: size_t buf_len = 0; 3633: char *end = 0; 3634: size_t end_offset = 0; 3635: size_t dir_len = 0; 3636: int errors = 0; 3637: 3638: assert (pargz); 3639: assert (pargz_len); 3640: assert (dp); 3641: 3642: dir_len = LT_STRLEN (dirnam); 3643: end = dp->d_name + LT_D_NAMLEN(dp); 3644: 3645: /* Ignore version numbers. */ 3646: { 3647: char *p; 3648: for (p = end; p -1 > dp->d_name; --p) 3649: if (strchr (".0123456789", p[-1]) == 0) 3650: break; 3651: 3652: if (*p == '.') 3653: end = p; 3654: } 3655: 3656: /* Ignore filename extension. */ 3657: { 3658: char *p; 3659: for (p = end -1; p > dp->d_name; --p) 3660: if (*p == '.') 3661: { 3662: end = p; 3663: break; 3664: } 3665: } 3666: 3667: /* Prepend the directory name. */ 3668: end_offset = end - dp->d_name; 3669: buf_len = dir_len + 1+ end_offset; 3670: buf = LT_EMALLOC (char, 1+ buf_len); 3671: if (!buf) 3672: return ++errors; 3673: 3674: assert (buf); 3675: 3676: strcpy (buf, dirnam); 3677: strcat (buf, "/"); 3678: strncat (buf, dp->d_name, end_offset); 3679: buf[buf_len] = LT_EOS_CHAR; 3680: 3681: /* Try to insert (in order) into ARGZ/ARGZ_LEN. */ 3682: if (lt_argz_insertinorder (pargz, pargz_len, buf) != 0) 3683: ++errors; 3684: 3685: LT_DLFREE (buf); 3686: 3687: return errors; 3688: } 3689: 3690: static int 3691: list_files_by_dir (dirnam, pargz, pargz_len) 3692: const char *dirnam; 3693: char **pargz; 3694: size_t *pargz_len; 3695: { 3696: DIR *dirp = 0; 3697: int errors = 0; 3698: 3699: assert (dirnam && *dirnam); 3700: assert (pargz); 3701: assert (pargz_len); 3702: assert (dirnam[LT_STRLEN(dirnam) -1] != '/'); 3703: 3704: dirp = opendir (dirnam); 3705: if (dirp) 3706: { 3707: struct dirent *dp = 0; 3708: 3709: while ((dp = readdir (dirp))) 3710: if (dp->d_name[0] != '.') 3711: if (lt_argz_insertdir (pargz, pargz_len, dirnam, dp)) 3712: { 3713: ++errors; 3714: break; 3715: } 3716: 3717: closedir (dirp); 3718: } 3719: else 3720: ++errors; 3721: 3722: return errors; 3723: } 3724: 3725: 3726: /* If there are any files in DIRNAME, call the function passed in 3727: DATA1 (with the name of each file and DATA2 as arguments). */ 3728: static int 3729: foreachfile_callback (dirname, data1, data2) 3730: char *dirname; 3731: lt_ptr data1; 3732: lt_ptr data2; 3733: { 3734: int (*func) LT_PARAMS((const char *filename, lt_ptr data)) 3735: = (int (*) LT_PARAMS((const char *filename, lt_ptr data))) data1; 3736: 3737: int is_done = 0; 3738: char *argz = 0; 3739: size_t argz_len = 0; 3740: 3741: if (list_files_by_dir (dirname, &argz, &argz_len) != 0) 3742: goto cleanup; 3743: if (!argz) 3744: goto cleanup; 3745: 3746: { 3747: char *filename = 0; 3748: while ((filename = argz_next (argz, argz_len, filename))) 3749: if ((is_done = (*func) (filename, data2))) 3750: break; 3751: } 3752: 3753: cleanup: 3754: LT_DLFREE (argz); 3755: 3756: return is_done; 3757: } 3758: 3759: 3760: /* Call FUNC for each unique extensionless file in SEARCH_PATH, along 3761: with DATA. The filenames passed to FUNC would be suitable for 3762: passing to lt_dlopenext. The extensions are stripped so that 3763: individual modules do not generate several entries (e.g. libfoo.la, 3764: libfoo.so, libfoo.so.1, libfoo.so.1.0.0). If SEARCH_PATH is NULL, 3765: then the same directories that lt_dlopen would search are examined. */ 3766: int 3767: lt_dlforeachfile (search_path, func, data) 3768: const char *search_path; 3769: int (*func) LT_PARAMS ((const char *filename, lt_ptr data)); 3770: lt_ptr data; 3771: { 3772: int is_done = 0; 3773: 3774: if (search_path) 3775: { 3776: /* If a specific path was passed, search only the directories 3777: listed in it. */ 3778: is_done = foreach_dirinpath (search_path, 0, 3779: foreachfile_callback, func, data); 3780: } 3781: else 3782: { 3783: /* Otherwise search the default paths. */ 3784: is_done = foreach_dirinpath (user_search_path, 0, 3785: foreachfile_callback, func, data); 3786: if (!is_done) 3787: { 3788: is_done = foreach_dirinpath (getenv("LTDL_LIBRARY_PATH"), 0, 3789: foreachfile_callback, func, data); 3790: } 3791: 3792: #ifdef LTDL_SHLIBPATH_VAR 3793: if (!is_done) 3794: { 3795: is_done = foreach_dirinpath (getenv(LTDL_SHLIBPATH_VAR), 0, 3796: foreachfile_callback, func, data); 3797: } 3798: #endif 3799: #ifdef LTDL_SYSSEARCHPATH 3800: if (!is_done) 3801: { 3802: is_done = foreach_dirinpath (getenv(LTDL_SYSSEARCHPATH), 0, 3803: foreachfile_callback, func, data); 3804: } 3805: #endif 3806: } 3807: 3808: return is_done; 3809: } 3810: 3811: int 3812: lt_dlclose (handle) 3813: lt_dlhandle handle; 3814: { 3815: lt_dlhandle cur, last; 3816: int errors = 0; 3817: 3818: LT_DLMUTEX_LOCK (); 3819: 3820: /* check whether the handle is valid */ 3821: last = cur = handles; 3822: while (cur && handle != cur) 3823: { 3824: last = cur; 3825: cur = cur->next; 3826: } 3827: 3828: if (!cur) 3829: { 3830: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); 3831: ++errors; 3832: goto done; 3833: } 3834: 3835: handle->info.ref_count--; 3836: 3837: /* Note that even with resident modules, we must track the ref_count 3838: correctly incase the user decides to reset the residency flag 3839: later (even though the API makes no provision for that at the 3840: moment). */ 3841: if (handle->info.ref_count <= 0 && !LT_DLIS_RESIDENT (handle)) 3842: { 3843: lt_user_data data = handle->loader->dlloader_data; 3844: 3845: if (handle != handles) 3846: { 3847: last->next = handle->next; 3848: } 3849: else 3850: { 3851: handles = handle->next; 3852: } 3853: 3854: errors += handle->loader->module_close (data, handle->module); 3855: errors += unload_deplibs(handle); 3856: 3857: /* It is up to the callers to free the data itself. */ 3858: LT_DLFREE (handle->caller_data); 3859: 3860: LT_DLFREE (handle->info.filename); 3861: LT_DLFREE (handle->info.name); 3862: LT_DLFREE (handle); 3863: 3864: goto done; 3865: } 3866: 3867: if (LT_DLIS_RESIDENT (handle)) 3868: { 3869: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CLOSE_RESIDENT_MODULE)); 3870: ++errors; 3871: } 3872: 3873: done: 3874: LT_DLMUTEX_UNLOCK (); 3875: 3876: return errors; 3877: } 3878: 3879: lt_ptr 3880: lt_dlsym (handle, symbol) 3881: lt_dlhandle handle; 3882: const char *symbol; 3883: { 3884: size_t lensym; 3885: char lsym[LT_SYMBOL_LENGTH]; 3886: char *sym; 3887: lt_ptr address; 3888: lt_user_data data; 3889: 3890: if (!handle) 3891: { 3892: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); 3893: return 0; 3894: } 3895: 3896: if (!symbol) 3897: { 3898: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); 3899: return 0; 3900: } 3901: 3902: lensym = LT_STRLEN (symbol) + LT_STRLEN (handle->loader->sym_prefix) 3903: + LT_STRLEN (handle->info.name); 3904: 3905: if (lensym + LT_SYMBOL_OVERHEAD < LT_SYMBOL_LENGTH) 3906: { 3907: sym = lsym; 3908: } 3909: else 3910: { 3911: sym = LT_EMALLOC (char, lensym + LT_SYMBOL_OVERHEAD + 1); 3912: if (!sym) 3913: { 3914: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (BUFFER_OVERFLOW)); 3915: return 0; 3916: } 3917: } 3918: 3919: data = handle->loader->dlloader_data; 3920: if (handle->info.name) 3921: { 3922: const char *saved_error; 3923: 3924: LT_DLMUTEX_GETERROR (saved_error); 3925: 3926: /* this is a libtool module */ 3927: if (handle->loader->sym_prefix) 3928: { 3929: strcpy(sym, handle->loader->sym_prefix); 3930: strcat(sym, handle->info.name); 3931: } 3932: else 3933: { 3934: strcpy(sym, handle->info.name); 3935: } 3936: 3937: strcat(sym, "_LTX_"); 3938: strcat(sym, symbol); 3939: 3940: /* try "modulename_LTX_symbol" */ 3941: address = handle->loader->find_sym (data, handle->module, sym); 3942: if (address) 3943: { 3944: if (sym != lsym) 3945: { 3946: LT_DLFREE (sym); 3947: } 3948: return address; 3949: } 3950: LT_DLMUTEX_SETERROR (saved_error); 3951: } 3952: 3953: /* otherwise try "symbol" */ 3954: if (handle->loader->sym_prefix) 3955: { 3956: strcpy(sym, handle->loader->sym_prefix); 3957: strcat(sym, symbol); 3958: } 3959: else 3960: { 3961: strcpy(sym, symbol); 3962: } 3963: 3964: address = handle->loader->find_sym (data, handle->module, sym); 3965: if (sym != lsym) 3966: { 3967: LT_DLFREE (sym); 3968: } 3969: 3970: return address; 3971: } 3972: 3973: const char * 3974: lt_dlerror () 3975: { 3976: const char *error; 3977: 3978: LT_DLMUTEX_GETERROR (error); 3979: LT_DLMUTEX_SETERROR (0); 3980: 1.1.1.2 ! root 3981: return error ? error : NULL; 1.1 root 3982: } 3983: 3984: static int 3985: lt_dlpath_insertdir (ppath, before, dir) 3986: char **ppath; 3987: char *before; 3988: const char *dir; 3989: { 3990: int errors = 0; 3991: char *canonical = 0; 3992: char *argz = 0; 3993: size_t argz_len = 0; 3994: 3995: assert (ppath); 3996: assert (dir && *dir); 3997: 3998: if (canonicalize_path (dir, &canonical) != 0) 3999: { 4000: ++errors; 4001: goto cleanup; 4002: } 4003: 4004: assert (canonical && *canonical); 4005: 4006: /* If *PPATH is empty, set it to DIR. */ 4007: if (*ppath == 0) 4008: { 4009: assert (!before); /* BEFORE cannot be set without PPATH. */ 4010: assert (dir); /* Without DIR, don't call this function! */ 4011: 4012: *ppath = lt_estrdup (dir); 4013: if (*ppath == 0) 4014: ++errors; 4015: 4016: return errors; 4017: } 4018: 4019: assert (ppath && *ppath); 4020: 4021: if (argzize_path (*ppath, &argz, &argz_len) != 0) 4022: { 4023: ++errors; 4024: goto cleanup; 4025: } 4026: 4027: /* Convert BEFORE into an equivalent offset into ARGZ. This only works 4028: if *PPATH is already canonicalized, and hence does not change length 4029: with respect to ARGZ. We canonicalize each entry as it is added to 4030: the search path, and don't call this function with (uncanonicalized) 4031: user paths, so this is a fair assumption. */ 4032: if (before) 4033: { 4034: assert (*ppath <= before); 4035: assert (before - *ppath <= strlen (*ppath)); 4036: 4037: before = before - *ppath + argz; 4038: } 4039: 4040: if (lt_argz_insert (&argz, &argz_len, before, dir) != 0) 4041: { 4042: ++errors; 4043: goto cleanup; 4044: } 4045: 4046: argz_stringify (argz, argz_len, LT_PATHSEP_CHAR); 4047: LT_DLMEM_REASSIGN (*ppath, argz); 4048: 4049: cleanup: 4050: LT_DLFREE (canonical); 4051: LT_DLFREE (argz); 4052: 4053: return errors; 4054: } 4055: 4056: int 4057: lt_dladdsearchdir (search_dir) 4058: const char *search_dir; 4059: { 4060: int errors = 0; 4061: 4062: if (search_dir && *search_dir) 4063: { 4064: LT_DLMUTEX_LOCK (); 4065: if (lt_dlpath_insertdir (&user_search_path, 0, search_dir) != 0) 4066: ++errors; 4067: LT_DLMUTEX_UNLOCK (); 4068: } 4069: 4070: return errors; 4071: } 4072: 4073: int 4074: lt_dlinsertsearchdir (before, search_dir) 4075: const char *before; 4076: const char *search_dir; 4077: { 4078: int errors = 0; 4079: 4080: if (before) 4081: { 4082: LT_DLMUTEX_LOCK (); 4083: if ((before < user_search_path) 4084: || (before >= user_search_path + LT_STRLEN (user_search_path))) 4085: { 4086: LT_DLMUTEX_UNLOCK (); 4087: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_POSITION)); 4088: return 1; 4089: } 4090: LT_DLMUTEX_UNLOCK (); 4091: } 4092: 4093: if (search_dir && *search_dir) 4094: { 4095: LT_DLMUTEX_LOCK (); 4096: if (lt_dlpath_insertdir (&user_search_path, 4097: (char *) before, search_dir) != 0) 4098: { 4099: ++errors; 4100: } 4101: LT_DLMUTEX_UNLOCK (); 4102: } 4103: 4104: return errors; 4105: } 4106: 4107: int 4108: lt_dlsetsearchpath (search_path) 4109: const char *search_path; 4110: { 4111: int errors = 0; 4112: 4113: LT_DLMUTEX_LOCK (); 4114: LT_DLFREE (user_search_path); 4115: LT_DLMUTEX_UNLOCK (); 4116: 4117: if (!search_path || !LT_STRLEN (search_path)) 4118: { 4119: return errors; 4120: } 4121: 4122: LT_DLMUTEX_LOCK (); 4123: if (canonicalize_path (search_path, &user_search_path) != 0) 4124: ++errors; 4125: LT_DLMUTEX_UNLOCK (); 4126: 4127: return errors; 4128: } 4129: 4130: const char * 4131: lt_dlgetsearchpath () 4132: { 4133: const char *saved_path; 4134: 4135: LT_DLMUTEX_LOCK (); 4136: saved_path = user_search_path; 4137: LT_DLMUTEX_UNLOCK (); 4138: 4139: return saved_path; 4140: } 4141: 4142: int 4143: lt_dlmakeresident (handle) 4144: lt_dlhandle handle; 4145: { 4146: int errors = 0; 4147: 4148: if (!handle) 4149: { 4150: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); 4151: ++errors; 4152: } 4153: else 4154: { 4155: LT_DLSET_FLAG (handle, LT_DLRESIDENT_FLAG); 4156: } 4157: 4158: return errors; 4159: } 4160: 4161: int 4162: lt_dlisresident (handle) 4163: lt_dlhandle handle; 4164: { 4165: if (!handle) 4166: { 4167: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); 4168: return -1; 4169: } 4170: 4171: return LT_DLIS_RESIDENT (handle); 4172: } 4173: 4174: 4175: 4176: 4177: /* --- MODULE INFORMATION --- */ 4178: 4179: const lt_dlinfo * 4180: lt_dlgetinfo (handle) 4181: lt_dlhandle handle; 4182: { 4183: if (!handle) 4184: { 4185: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); 4186: return 0; 4187: } 4188: 4189: return &(handle->info); 4190: } 4191: 4192: lt_dlhandle 4193: lt_dlhandle_next (place) 4194: lt_dlhandle place; 4195: { 4196: return place ? place->next : handles; 4197: } 4198: 4199: int 4200: lt_dlforeach (func, data) 4201: int (*func) LT_PARAMS((lt_dlhandle handle, lt_ptr data)); 4202: lt_ptr data; 4203: { 4204: int errors = 0; 4205: lt_dlhandle cur; 4206: 4207: LT_DLMUTEX_LOCK (); 4208: 4209: cur = handles; 4210: while (cur) 4211: { 4212: lt_dlhandle tmp = cur; 4213: 4214: cur = cur->next; 4215: if ((*func) (tmp, data)) 4216: { 4217: ++errors; 4218: break; 4219: } 4220: } 4221: 4222: LT_DLMUTEX_UNLOCK (); 4223: 4224: return errors; 4225: } 4226: 4227: lt_dlcaller_id 4228: lt_dlcaller_register () 4229: { 4230: static lt_dlcaller_id last_caller_id = 0; 4231: int result; 4232: 4233: LT_DLMUTEX_LOCK (); 4234: result = ++last_caller_id; 4235: LT_DLMUTEX_UNLOCK (); 4236: 4237: return result; 4238: } 4239: 4240: lt_ptr 4241: lt_dlcaller_set_data (key, handle, data) 4242: lt_dlcaller_id key; 4243: lt_dlhandle handle; 4244: lt_ptr data; 4245: { 4246: int n_elements = 0; 4247: lt_ptr stale = (lt_ptr) 0; 4248: int i; 4249: 4250: /* This needs to be locked so that the caller data can be updated 4251: simultaneously by different threads. */ 4252: LT_DLMUTEX_LOCK (); 4253: 4254: if (handle->caller_data) 4255: while (handle->caller_data[n_elements].key) 4256: ++n_elements; 4257: 4258: for (i = 0; i < n_elements; ++i) 4259: { 4260: if (handle->caller_data[i].key == key) 4261: { 4262: stale = handle->caller_data[i].data; 4263: break; 4264: } 4265: } 4266: 4267: /* Ensure that there is enough room in this handle's caller_data 4268: array to accept a new element (and an empty end marker). */ 4269: if (i == n_elements) 4270: { 4271: lt_caller_data *temp 4272: = LT_DLREALLOC (lt_caller_data, handle->caller_data, 2+ n_elements); 4273: 4274: if (!temp) 4275: { 4276: stale = 0; 4277: goto done; 4278: } 4279: 4280: handle->caller_data = temp; 4281: 4282: /* We only need this if we needed to allocate a new caller_data. */ 4283: handle->caller_data[i].key = key; 4284: handle->caller_data[1+ i].key = 0; 4285: } 4286: 4287: handle->caller_data[i].data = data; 4288: 4289: done: 4290: LT_DLMUTEX_UNLOCK (); 4291: 4292: return stale; 4293: } 4294: 4295: lt_ptr 4296: lt_dlcaller_get_data (key, handle) 4297: lt_dlcaller_id key; 4298: lt_dlhandle handle; 4299: { 4300: lt_ptr result = (lt_ptr) 0; 4301: 4302: /* This needs to be locked so that the caller data isn't updated by 4303: another thread part way through this function. */ 4304: LT_DLMUTEX_LOCK (); 4305: 4306: /* Locate the index of the element with a matching KEY. */ 4307: { 4308: int i; 4309: for (i = 0; handle->caller_data[i].key; ++i) 4310: { 4311: if (handle->caller_data[i].key == key) 4312: { 4313: result = handle->caller_data[i].data; 4314: break; 4315: } 4316: } 4317: } 4318: 4319: LT_DLMUTEX_UNLOCK (); 4320: 4321: return result; 4322: } 4323: 4324: 4325: 4326: /* --- USER MODULE LOADER API --- */ 4327: 4328: 4329: int 4330: lt_dlloader_add (place, dlloader, loader_name) 4331: lt_dlloader *place; 4332: const struct lt_user_dlloader *dlloader; 4333: const char *loader_name; 4334: { 4335: int errors = 0; 4336: lt_dlloader *node = 0, *ptr = 0; 4337: 4338: if ((dlloader == 0) /* diagnose null parameters */ 4339: || (dlloader->module_open == 0) 4340: || (dlloader->module_close == 0) 4341: || (dlloader->find_sym == 0)) 4342: { 4343: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); 4344: return 1; 4345: } 4346: 4347: /* Create a new dlloader node with copies of the user callbacks. */ 4348: node = LT_EMALLOC (lt_dlloader, 1); 4349: if (!node) 4350: return 1; 4351: 4352: node->next = 0; 4353: node->loader_name = loader_name; 4354: node->sym_prefix = dlloader->sym_prefix; 4355: node->dlloader_exit = dlloader->dlloader_exit; 4356: node->module_open = dlloader->module_open; 4357: node->module_close = dlloader->module_close; 4358: node->find_sym = dlloader->find_sym; 4359: node->dlloader_data = dlloader->dlloader_data; 4360: 4361: LT_DLMUTEX_LOCK (); 4362: if (!loaders) 4363: { 4364: /* If there are no loaders, NODE becomes the list! */ 4365: loaders = node; 4366: } 4367: else if (!place) 4368: { 4369: /* If PLACE is not set, add NODE to the end of the 4370: LOADERS list. */ 4371: for (ptr = loaders; ptr->next; ptr = ptr->next) 4372: { 4373: /*NOWORK*/; 4374: } 4375: 4376: ptr->next = node; 4377: } 4378: else if (loaders == place) 4379: { 4380: /* If PLACE is the first loader, NODE goes first. */ 4381: node->next = place; 4382: loaders = node; 4383: } 4384: else 4385: { 4386: /* Find the node immediately preceding PLACE. */ 4387: for (ptr = loaders; ptr->next != place; ptr = ptr->next) 4388: { 4389: /*NOWORK*/; 4390: } 4391: 4392: if (ptr->next != place) 4393: { 4394: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); 4395: ++errors; 4396: } 4397: else 4398: { 4399: /* Insert NODE between PTR and PLACE. */ 4400: node->next = place; 4401: ptr->next = node; 4402: } 4403: } 4404: 4405: LT_DLMUTEX_UNLOCK (); 4406: 4407: return errors; 4408: } 4409: 4410: int 4411: lt_dlloader_remove (loader_name) 4412: const char *loader_name; 4413: { 4414: lt_dlloader *place = lt_dlloader_find (loader_name); 4415: lt_dlhandle handle; 4416: int errors = 0; 4417: 4418: if (!place) 4419: { 4420: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); 4421: return 1; 4422: } 4423: 4424: LT_DLMUTEX_LOCK (); 4425: 4426: /* Fail if there are any open modules which use this loader. */ 4427: for (handle = handles; handle; handle = handle->next) 4428: { 4429: if (handle->loader == place) 4430: { 4431: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (REMOVE_LOADER)); 4432: ++errors; 4433: goto done; 4434: } 4435: } 4436: 4437: if (place == loaders) 4438: { 4439: /* PLACE is the first loader in the list. */ 4440: loaders = loaders->next; 4441: } 4442: else 4443: { 4444: /* Find the loader before the one being removed. */ 4445: lt_dlloader *prev; 4446: for (prev = loaders; prev->next; prev = prev->next) 4447: { 4448: if (!strcmp (prev->next->loader_name, loader_name)) 4449: { 4450: break; 4451: } 4452: } 4453: 4454: place = prev->next; 4455: prev->next = prev->next->next; 4456: } 4457: 4458: if (place->dlloader_exit) 4459: { 4460: errors = place->dlloader_exit (place->dlloader_data); 4461: } 4462: 4463: LT_DLFREE (place); 4464: 4465: done: 4466: LT_DLMUTEX_UNLOCK (); 4467: 4468: return errors; 4469: } 4470: 4471: lt_dlloader * 4472: lt_dlloader_next (place) 4473: lt_dlloader *place; 4474: { 4475: lt_dlloader *next; 4476: 4477: LT_DLMUTEX_LOCK (); 4478: next = place ? place->next : loaders; 4479: LT_DLMUTEX_UNLOCK (); 4480: 4481: return next; 4482: } 4483: 4484: const char * 4485: lt_dlloader_name (place) 4486: lt_dlloader *place; 4487: { 4488: const char *name = 0; 4489: 4490: if (place) 4491: { 4492: LT_DLMUTEX_LOCK (); 4493: name = place ? place->loader_name : 0; 4494: LT_DLMUTEX_UNLOCK (); 4495: } 4496: else 4497: { 4498: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); 4499: } 4500: 4501: return name; 4502: } 4503: 4504: lt_user_data * 4505: lt_dlloader_data (place) 4506: lt_dlloader *place; 4507: { 4508: lt_user_data *data = 0; 4509: 4510: if (place) 4511: { 4512: LT_DLMUTEX_LOCK (); 4513: data = place ? &(place->dlloader_data) : 0; 4514: LT_DLMUTEX_UNLOCK (); 4515: } 4516: else 4517: { 4518: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); 4519: } 4520: 4521: return data; 4522: } 4523: 4524: lt_dlloader * 4525: lt_dlloader_find (loader_name) 4526: const char *loader_name; 4527: { 4528: lt_dlloader *place = 0; 4529: 4530: LT_DLMUTEX_LOCK (); 4531: for (place = loaders; place; place = place->next) 4532: { 4533: if (strcmp (place->loader_name, loader_name) == 0) 4534: { 4535: break; 4536: } 4537: } 4538: LT_DLMUTEX_UNLOCK (); 4539: 4540: return place; 4541: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.