Return to relocatable.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / libiconv / libcharset / lib |
1.1 ! misho 1: /* Provide relocatable packages. ! 2: Copyright (C) 2003-2006, 2008 Free Software Foundation, Inc. ! 3: Written by Bruno Haible <bruno@clisp.org>, 2003. ! 4: ! 5: This program is free software; you can redistribute it and/or modify it ! 6: under the terms of the GNU Library General Public License as published ! 7: by the Free Software Foundation; either version 2, or (at your option) ! 8: any later version. ! 9: ! 10: This program is distributed in the hope that it will be useful, ! 11: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 12: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 13: Library General Public License for more details. ! 14: ! 15: You should have received a copy of the GNU Library General Public ! 16: License along with this program; if not, write to the Free Software ! 17: Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, ! 18: USA. */ ! 19: ! 20: ! 21: /* Tell glibc's <stdio.h> to provide a prototype for getline(). ! 22: This must come before <config.h> because <config.h> may include ! 23: <features.h>, and once <features.h> has been included, it's too late. */ ! 24: #ifndef _GNU_SOURCE ! 25: # define _GNU_SOURCE 1 ! 26: #endif ! 27: ! 28: #include <config.h> ! 29: ! 30: /* Specification. */ ! 31: #include "relocatable.h" ! 32: ! 33: #if ENABLE_RELOCATABLE ! 34: ! 35: #include <stddef.h> ! 36: #include <stdio.h> ! 37: #include <stdlib.h> ! 38: #include <string.h> ! 39: ! 40: #ifdef NO_XMALLOC ! 41: # define xmalloc malloc ! 42: #else ! 43: # include "xalloc.h" ! 44: #endif ! 45: ! 46: #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ ! 47: # define WIN32_LEAN_AND_MEAN ! 48: # include <windows.h> ! 49: #endif ! 50: ! 51: #if DEPENDS_ON_LIBCHARSET ! 52: # include <libcharset.h> ! 53: #endif ! 54: #if DEPENDS_ON_LIBICONV && HAVE_ICONV ! 55: # include <iconv.h> ! 56: #endif ! 57: #if DEPENDS_ON_LIBINTL && ENABLE_NLS ! 58: # include <libintl.h> ! 59: #endif ! 60: ! 61: /* Faked cheap 'bool'. */ ! 62: #undef bool ! 63: #undef false ! 64: #undef true ! 65: #define bool int ! 66: #define false 0 ! 67: #define true 1 ! 68: ! 69: /* Pathname support. ! 70: ISSLASH(C) tests whether C is a directory separator character. ! 71: IS_PATH_WITH_DIR(P) tests whether P contains a directory specification. ! 72: */ ! 73: #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__ ! 74: /* Win32, Cygwin, OS/2, DOS */ ! 75: # define ISSLASH(C) ((C) == '/' || (C) == '\\') ! 76: # define HAS_DEVICE(P) \ ! 77: ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \ ! 78: && (P)[1] == ':') ! 79: # define IS_PATH_WITH_DIR(P) \ ! 80: (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P)) ! 81: # define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0) ! 82: #else ! 83: /* Unix */ ! 84: # define ISSLASH(C) ((C) == '/') ! 85: # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL) ! 86: # define FILE_SYSTEM_PREFIX_LEN(P) 0 ! 87: #endif ! 88: ! 89: /* Original installation prefix. */ ! 90: static char *orig_prefix; ! 91: static size_t orig_prefix_len; ! 92: /* Current installation prefix. */ ! 93: static char *curr_prefix; ! 94: static size_t curr_prefix_len; ! 95: /* These prefixes do not end in a slash. Anything that will be concatenated ! 96: to them must start with a slash. */ ! 97: ! 98: /* Sets the original and the current installation prefix of this module. ! 99: Relocation simply replaces a pathname starting with the original prefix ! 100: by the corresponding pathname with the current prefix instead. Both ! 101: prefixes should be directory names without trailing slash (i.e. use "" ! 102: instead of "/"). */ ! 103: static void ! 104: set_this_relocation_prefix (const char *orig_prefix_arg, ! 105: const char *curr_prefix_arg) ! 106: { ! 107: if (orig_prefix_arg != NULL && curr_prefix_arg != NULL ! 108: /* Optimization: if orig_prefix and curr_prefix are equal, the ! 109: relocation is a nop. */ ! 110: && strcmp (orig_prefix_arg, curr_prefix_arg) != 0) ! 111: { ! 112: /* Duplicate the argument strings. */ ! 113: char *memory; ! 114: ! 115: orig_prefix_len = strlen (orig_prefix_arg); ! 116: curr_prefix_len = strlen (curr_prefix_arg); ! 117: memory = (char *) xmalloc (orig_prefix_len + 1 + curr_prefix_len + 1); ! 118: #ifdef NO_XMALLOC ! 119: if (memory != NULL) ! 120: #endif ! 121: { ! 122: memcpy (memory, orig_prefix_arg, orig_prefix_len + 1); ! 123: orig_prefix = memory; ! 124: memory += orig_prefix_len + 1; ! 125: memcpy (memory, curr_prefix_arg, curr_prefix_len + 1); ! 126: curr_prefix = memory; ! 127: return; ! 128: } ! 129: } ! 130: orig_prefix = NULL; ! 131: curr_prefix = NULL; ! 132: /* Don't worry about wasted memory here - this function is usually only ! 133: called once. */ ! 134: } ! 135: ! 136: /* Sets the original and the current installation prefix of the package. ! 137: Relocation simply replaces a pathname starting with the original prefix ! 138: by the corresponding pathname with the current prefix instead. Both ! 139: prefixes should be directory names without trailing slash (i.e. use "" ! 140: instead of "/"). */ ! 141: void ! 142: set_relocation_prefix (const char *orig_prefix_arg, const char *curr_prefix_arg) ! 143: { ! 144: set_this_relocation_prefix (orig_prefix_arg, curr_prefix_arg); ! 145: ! 146: /* Now notify all dependent libraries. */ ! 147: #if DEPENDS_ON_LIBCHARSET ! 148: libcharset_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg); ! 149: #endif ! 150: #if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109 ! 151: libiconv_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg); ! 152: #endif ! 153: #if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_prefix ! 154: libintl_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg); ! 155: #endif ! 156: } ! 157: ! 158: #if !defined IN_LIBRARY || (defined PIC && defined INSTALLDIR) ! 159: ! 160: /* Convenience function: ! 161: Computes the current installation prefix, based on the original ! 162: installation prefix, the original installation directory of a particular ! 163: file, and the current pathname of this file. ! 164: Returns it, freshly allocated. Returns NULL upon failure. */ ! 165: #ifdef IN_LIBRARY ! 166: #define compute_curr_prefix local_compute_curr_prefix ! 167: static ! 168: #endif ! 169: char * ! 170: compute_curr_prefix (const char *orig_installprefix, ! 171: const char *orig_installdir, ! 172: const char *curr_pathname) ! 173: { ! 174: char *curr_installdir; ! 175: const char *rel_installdir; ! 176: ! 177: if (curr_pathname == NULL) ! 178: return NULL; ! 179: ! 180: /* Determine the relative installation directory, relative to the prefix. ! 181: This is simply the difference between orig_installprefix and ! 182: orig_installdir. */ ! 183: if (strncmp (orig_installprefix, orig_installdir, strlen (orig_installprefix)) ! 184: != 0) ! 185: /* Shouldn't happen - nothing should be installed outside $(prefix). */ ! 186: return NULL; ! 187: rel_installdir = orig_installdir + strlen (orig_installprefix); ! 188: ! 189: /* Determine the current installation directory. */ ! 190: { ! 191: const char *p_base = curr_pathname + FILE_SYSTEM_PREFIX_LEN (curr_pathname); ! 192: const char *p = curr_pathname + strlen (curr_pathname); ! 193: char *q; ! 194: ! 195: while (p > p_base) ! 196: { ! 197: p--; ! 198: if (ISSLASH (*p)) ! 199: break; ! 200: } ! 201: ! 202: q = (char *) xmalloc (p - curr_pathname + 1); ! 203: #ifdef NO_XMALLOC ! 204: if (q == NULL) ! 205: return NULL; ! 206: #endif ! 207: memcpy (q, curr_pathname, p - curr_pathname); ! 208: q[p - curr_pathname] = '\0'; ! 209: curr_installdir = q; ! 210: } ! 211: ! 212: /* Compute the current installation prefix by removing the trailing ! 213: rel_installdir from it. */ ! 214: { ! 215: const char *rp = rel_installdir + strlen (rel_installdir); ! 216: const char *cp = curr_installdir + strlen (curr_installdir); ! 217: const char *cp_base = ! 218: curr_installdir + FILE_SYSTEM_PREFIX_LEN (curr_installdir); ! 219: ! 220: while (rp > rel_installdir && cp > cp_base) ! 221: { ! 222: bool same = false; ! 223: const char *rpi = rp; ! 224: const char *cpi = cp; ! 225: ! 226: while (rpi > rel_installdir && cpi > cp_base) ! 227: { ! 228: rpi--; ! 229: cpi--; ! 230: if (ISSLASH (*rpi) || ISSLASH (*cpi)) ! 231: { ! 232: if (ISSLASH (*rpi) && ISSLASH (*cpi)) ! 233: same = true; ! 234: break; ! 235: } ! 236: /* Do case-insensitive comparison if the filesystem is always or ! 237: often case-insensitive. It's better to accept the comparison ! 238: if the difference is only in case, rather than to fail. */ ! 239: #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__ ! 240: /* Win32, Cygwin, OS/2, DOS - case insignificant filesystem */ ! 241: if ((*rpi >= 'a' && *rpi <= 'z' ? *rpi - 'a' + 'A' : *rpi) ! 242: != (*cpi >= 'a' && *cpi <= 'z' ? *cpi - 'a' + 'A' : *cpi)) ! 243: break; ! 244: #else ! 245: if (*rpi != *cpi) ! 246: break; ! 247: #endif ! 248: } ! 249: if (!same) ! 250: break; ! 251: /* The last pathname component was the same. opi and cpi now point ! 252: to the slash before it. */ ! 253: rp = rpi; ! 254: cp = cpi; ! 255: } ! 256: ! 257: if (rp > rel_installdir) ! 258: { ! 259: /* Unexpected: The curr_installdir does not end with rel_installdir. */ ! 260: free (curr_installdir); ! 261: return NULL; ! 262: } ! 263: ! 264: { ! 265: size_t curr_prefix_len = cp - curr_installdir; ! 266: char *curr_prefix; ! 267: ! 268: curr_prefix = (char *) xmalloc (curr_prefix_len + 1); ! 269: #ifdef NO_XMALLOC ! 270: if (curr_prefix == NULL) ! 271: { ! 272: free (curr_installdir); ! 273: return NULL; ! 274: } ! 275: #endif ! 276: memcpy (curr_prefix, curr_installdir, curr_prefix_len); ! 277: curr_prefix[curr_prefix_len] = '\0'; ! 278: ! 279: free (curr_installdir); ! 280: ! 281: return curr_prefix; ! 282: } ! 283: } ! 284: } ! 285: ! 286: #endif /* !IN_LIBRARY || PIC */ ! 287: ! 288: #if defined PIC && defined INSTALLDIR ! 289: ! 290: /* Full pathname of shared library, or NULL. */ ! 291: static char *shared_library_fullname; ! 292: ! 293: #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ ! 294: ! 295: /* Determine the full pathname of the shared library when it is loaded. */ ! 296: ! 297: BOOL WINAPI ! 298: DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved) ! 299: { ! 300: (void) reserved; ! 301: ! 302: if (event == DLL_PROCESS_ATTACH) ! 303: { ! 304: /* The DLL is being loaded into an application's address range. */ ! 305: static char location[MAX_PATH]; ! 306: ! 307: if (!GetModuleFileName (module_handle, location, sizeof (location))) ! 308: /* Shouldn't happen. */ ! 309: return FALSE; ! 310: ! 311: if (!IS_PATH_WITH_DIR (location)) ! 312: /* Shouldn't happen. */ ! 313: return FALSE; ! 314: ! 315: { ! 316: #if defined __CYGWIN__ ! 317: /* On Cygwin, we need to convert paths coming from Win32 system calls ! 318: to the Unix-like slashified notation. */ ! 319: static char location_as_posix_path[2 * MAX_PATH]; ! 320: /* There's no error return defined for cygwin_conv_to_posix_path. ! 321: See cygwin-api/func-cygwin-conv-to-posix-path.html. ! 322: Does it overflow the buffer of expected size MAX_PATH or does it ! 323: truncate the path? I don't know. Let's catch both. */ ! 324: cygwin_conv_to_posix_path (location, location_as_posix_path); ! 325: location_as_posix_path[MAX_PATH - 1] = '\0'; ! 326: if (strlen (location_as_posix_path) >= MAX_PATH - 1) ! 327: /* A sign of buffer overflow or path truncation. */ ! 328: return FALSE; ! 329: shared_library_fullname = strdup (location_as_posix_path); ! 330: #else ! 331: shared_library_fullname = strdup (location); ! 332: #endif ! 333: } ! 334: } ! 335: ! 336: return TRUE; ! 337: } ! 338: ! 339: #else /* Unix except Cygwin */ ! 340: ! 341: static void ! 342: find_shared_library_fullname () ! 343: { ! 344: #if defined __linux__ && __GLIBC__ >= 2 ! 345: /* Linux has /proc/self/maps. glibc 2 has the getline() function. */ ! 346: FILE *fp; ! 347: ! 348: /* Open the current process' maps file. It describes one VMA per line. */ ! 349: fp = fopen ("/proc/self/maps", "r"); ! 350: if (fp) ! 351: { ! 352: unsigned long address = (unsigned long) &find_shared_library_fullname; ! 353: for (;;) ! 354: { ! 355: unsigned long start, end; ! 356: int c; ! 357: ! 358: if (fscanf (fp, "%lx-%lx", &start, &end) != 2) ! 359: break; ! 360: if (address >= start && address <= end - 1) ! 361: { ! 362: /* Found it. Now see if this line contains a filename. */ ! 363: while (c = getc (fp), c != EOF && c != '\n' && c != '/') ! 364: continue; ! 365: if (c == '/') ! 366: { ! 367: size_t size; ! 368: int len; ! 369: ! 370: ungetc (c, fp); ! 371: shared_library_fullname = NULL; size = 0; ! 372: len = getline (&shared_library_fullname, &size, fp); ! 373: if (len >= 0) ! 374: { ! 375: /* Success: filled shared_library_fullname. */ ! 376: if (len > 0 && shared_library_fullname[len - 1] == '\n') ! 377: shared_library_fullname[len - 1] = '\0'; ! 378: } ! 379: } ! 380: break; ! 381: } ! 382: while (c = getc (fp), c != EOF && c != '\n') ! 383: continue; ! 384: } ! 385: fclose (fp); ! 386: } ! 387: #endif ! 388: } ! 389: ! 390: #endif /* (WIN32 or Cygwin) / (Unix except Cygwin) */ ! 391: ! 392: /* Return the full pathname of the current shared library. ! 393: Return NULL if unknown. ! 394: Guaranteed to work only on Linux, Cygwin and Woe32. */ ! 395: static char * ! 396: get_shared_library_fullname () ! 397: { ! 398: #if !(defined _WIN32 || defined __WIN32__ || defined __CYGWIN__) ! 399: static bool tried_find_shared_library_fullname; ! 400: if (!tried_find_shared_library_fullname) ! 401: { ! 402: find_shared_library_fullname (); ! 403: tried_find_shared_library_fullname = true; ! 404: } ! 405: #endif ! 406: return shared_library_fullname; ! 407: } ! 408: ! 409: #endif /* PIC */ ! 410: ! 411: /* Returns the pathname, relocated according to the current installation ! 412: directory. ! 413: The returned string is either PATHNAME unmodified or a freshly allocated ! 414: string that you can free with free() after casting it to 'char *'. */ ! 415: const char * ! 416: relocate (const char *pathname) ! 417: { ! 418: #if defined PIC && defined INSTALLDIR ! 419: static int initialized; ! 420: ! 421: /* Initialization code for a shared library. */ ! 422: if (!initialized) ! 423: { ! 424: /* At this point, orig_prefix and curr_prefix likely have already been ! 425: set through the main program's set_program_name_and_installdir ! 426: function. This is sufficient in the case that the library has ! 427: initially been installed in the same orig_prefix. But we can do ! 428: better, to also cover the cases that 1. it has been installed ! 429: in a different prefix before being moved to orig_prefix and (later) ! 430: to curr_prefix, 2. unlike the program, it has not moved away from ! 431: orig_prefix. */ ! 432: const char *orig_installprefix = INSTALLPREFIX; ! 433: const char *orig_installdir = INSTALLDIR; ! 434: char *curr_prefix_better; ! 435: ! 436: curr_prefix_better = ! 437: compute_curr_prefix (orig_installprefix, orig_installdir, ! 438: get_shared_library_fullname ()); ! 439: ! 440: set_relocation_prefix (orig_installprefix, ! 441: curr_prefix_better != NULL ! 442: ? curr_prefix_better ! 443: : curr_prefix); ! 444: ! 445: if (curr_prefix_better != NULL) ! 446: free (curr_prefix_better); ! 447: ! 448: initialized = 1; ! 449: } ! 450: #endif ! 451: ! 452: /* Note: It is not necessary to perform case insensitive comparison here, ! 453: even for DOS-like filesystems, because the pathname argument was ! 454: typically created from the same Makefile variable as orig_prefix came ! 455: from. */ ! 456: if (orig_prefix != NULL && curr_prefix != NULL ! 457: && strncmp (pathname, orig_prefix, orig_prefix_len) == 0) ! 458: { ! 459: if (pathname[orig_prefix_len] == '\0') ! 460: { ! 461: /* pathname equals orig_prefix. */ ! 462: char *result = (char *) xmalloc (strlen (curr_prefix) + 1); ! 463: ! 464: #ifdef NO_XMALLOC ! 465: if (result != NULL) ! 466: #endif ! 467: { ! 468: strcpy (result, curr_prefix); ! 469: return result; ! 470: } ! 471: } ! 472: else if (ISSLASH (pathname[orig_prefix_len])) ! 473: { ! 474: /* pathname starts with orig_prefix. */ ! 475: const char *pathname_tail = &pathname[orig_prefix_len]; ! 476: char *result = ! 477: (char *) xmalloc (curr_prefix_len + strlen (pathname_tail) + 1); ! 478: ! 479: #ifdef NO_XMALLOC ! 480: if (result != NULL) ! 481: #endif ! 482: { ! 483: memcpy (result, curr_prefix, curr_prefix_len); ! 484: strcpy (result + curr_prefix_len, pathname_tail); ! 485: return result; ! 486: } ! 487: } ! 488: } ! 489: /* Nothing to relocate. */ ! 490: return pathname; ! 491: } ! 492: ! 493: #endif