home *** CD-ROM | disk | FTP | other *** search
/ Clickx 115 / Clickx 115.iso / software / tools / windows / tails-i386-0.16.iso / live / filesystem.squashfs / usr / share / gettext / intl / relocatable.c < prev    next >
Encoding:
C/C++ Source or Header  |  2010-09-19  |  15.5 KB  |  494 lines

  1. /* Provide relocatable packages.
  2.    Copyright (C) 2003-2006, 2008-2009 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 file system 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 file system */
  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 file systems, 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
  494.