(root)/
binutils-2.41/
intl/
relocatable.c
       1  /* Provide relocatable packages.
       2     Copyright (C) 2003 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  #ifdef HAVE_CONFIG_H
      29  # include "config.h"
      30  #endif
      31  
      32  /* Specification.  */
      33  #include "relocatable.h"
      34  
      35  #if ENABLE_RELOCATABLE
      36  
      37  #include <stddef.h>
      38  #include <stdio.h>
      39  #include <stdlib.h>
      40  #include <string.h>
      41  
      42  #ifdef NO_XMALLOC
      43  # define xmalloc malloc
      44  #else
      45  # include "xmalloc.h"
      46  #endif
      47  
      48  #if DEPENDS_ON_LIBCHARSET
      49  # include <libcharset.h>
      50  #endif
      51  #if DEPENDS_ON_LIBICONV && HAVE_ICONV
      52  # include <iconv.h>
      53  #endif
      54  #if DEPENDS_ON_LIBINTL && ENABLE_NLS
      55  # include <libintl.h>
      56  #endif
      57  
      58  /* Faked cheap 'bool'.  */
      59  #undef bool
      60  #undef false
      61  #undef true
      62  #define bool int
      63  #define false 0
      64  #define true 1
      65  
      66  /* Pathname support.
      67     ISSLASH(C)           tests whether C is a directory separator character.
      68     IS_PATH_WITH_DIR(P)  tests whether P contains a directory specification.
      69   */
      70  #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
      71    /* Win32, OS/2, DOS */
      72  # define ISSLASH(C) ((C) == '/' || (C) == '\\')
      73  # define HAS_DEVICE(P) \
      74      ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
      75       && (P)[1] == ':')
      76  # define IS_PATH_WITH_DIR(P) \
      77      (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
      78  # define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
      79  #else
      80    /* Unix */
      81  # define ISSLASH(C) ((C) == '/')
      82  # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
      83  # define FILESYSTEM_PREFIX_LEN(P) 0
      84  #endif
      85  
      86  /* Original installation prefix.  */
      87  static char *orig_prefix;
      88  static size_t orig_prefix_len;
      89  /* Current installation prefix.  */
      90  static char *curr_prefix;
      91  static size_t curr_prefix_len;
      92  /* These prefixes do not end in a slash.  Anything that will be concatenated
      93     to them must start with a slash.  */
      94  
      95  /* Sets the original and the current installation prefix of this module.
      96     Relocation simply replaces a pathname starting with the original prefix
      97     by the corresponding pathname with the current prefix instead.  Both
      98     prefixes should be directory names without trailing slash (i.e. use ""
      99     instead of "/").  */
     100  static void
     101  set_this_relocation_prefix (const char *orig_prefix_arg,
     102  			    const char *curr_prefix_arg)
     103  {
     104    if (orig_prefix_arg != NULL && curr_prefix_arg != NULL
     105        /* Optimization: if orig_prefix and curr_prefix are equal, the
     106  	 relocation is a nop.  */
     107        && strcmp (orig_prefix_arg, curr_prefix_arg) != 0)
     108      {
     109        /* Duplicate the argument strings.  */
     110        char *memory;
     111  
     112        orig_prefix_len = strlen (orig_prefix_arg);
     113        curr_prefix_len = strlen (curr_prefix_arg);
     114        memory = (char *) xmalloc (orig_prefix_len + 1 + curr_prefix_len + 1);
     115  #ifdef NO_XMALLOC
     116        if (memory != NULL)
     117  #endif
     118  	{
     119  	  memcpy (memory, orig_prefix_arg, orig_prefix_len + 1);
     120  	  orig_prefix = memory;
     121  	  memory += orig_prefix_len + 1;
     122  	  memcpy (memory, curr_prefix_arg, curr_prefix_len + 1);
     123  	  curr_prefix = memory;
     124  	  return;
     125  	}
     126      }
     127    orig_prefix = NULL;
     128    curr_prefix = NULL;
     129    /* Don't worry about wasted memory here - this function is usually only
     130       called once.  */
     131  }
     132  
     133  /* Sets the original and the current installation prefix of the package.
     134     Relocation simply replaces a pathname starting with the original prefix
     135     by the corresponding pathname with the current prefix instead.  Both
     136     prefixes should be directory names without trailing slash (i.e. use ""
     137     instead of "/").  */
     138  void
     139  set_relocation_prefix (const char *orig_prefix_arg, const char *curr_prefix_arg)
     140  {
     141    set_this_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
     142  
     143    /* Now notify all dependent libraries.  */
     144  #if DEPENDS_ON_LIBCHARSET
     145    libcharset_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
     146  #endif
     147  #if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109
     148    libiconv_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
     149  #endif
     150  #if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_prefix
     151    libintl_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
     152  #endif
     153  }
     154  
     155  /* Convenience function:
     156     Computes the current installation prefix, based on the original
     157     installation prefix, the original installation directory of a particular
     158     file, and the current pathname of this file.  Returns NULL upon failure.  */
     159  #ifdef IN_LIBRARY
     160  #define compute_curr_prefix local_compute_curr_prefix
     161  static
     162  #endif
     163  const char *
     164  compute_curr_prefix (const char *orig_installprefix,
     165  		     const char *orig_installdir,
     166  		     const char *curr_pathname)
     167  {
     168    const char *curr_installdir;
     169    const char *rel_installdir;
     170  
     171    if (curr_pathname == NULL)
     172      return NULL;
     173  
     174    /* Determine the relative installation directory, relative to the prefix.
     175       This is simply the difference between orig_installprefix and
     176       orig_installdir.  */
     177    if (strncmp (orig_installprefix, orig_installdir, strlen (orig_installprefix))
     178        != 0)
     179      /* Shouldn't happen - nothing should be installed outside $(prefix).  */
     180      return NULL;
     181    rel_installdir = orig_installdir + strlen (orig_installprefix);
     182  
     183    /* Determine the current installation directory.  */
     184    {
     185      const char *p_base = curr_pathname + FILESYSTEM_PREFIX_LEN (curr_pathname);
     186      const char *p = curr_pathname + strlen (curr_pathname);
     187      char *q;
     188  
     189      while (p > p_base)
     190        {
     191  	p--;
     192  	if (ISSLASH (*p))
     193  	  break;
     194        }
     195  
     196      q = (char *) xmalloc (p - curr_pathname + 1);
     197  #ifdef NO_XMALLOC
     198      if (q == NULL)
     199        return NULL;
     200  #endif
     201      memcpy (q, curr_pathname, p - curr_pathname);
     202      q[p - curr_pathname] = '\0';
     203      curr_installdir = q;
     204    }
     205  
     206    /* Compute the current installation prefix by removing the trailing
     207       rel_installdir from it.  */
     208    {
     209      const char *rp = rel_installdir + strlen (rel_installdir);
     210      const char *cp = curr_installdir + strlen (curr_installdir);
     211      const char *cp_base =
     212        curr_installdir + FILESYSTEM_PREFIX_LEN (curr_installdir);
     213  
     214      while (rp > rel_installdir && cp > cp_base)
     215        {
     216  	bool same = false;
     217  	const char *rpi = rp;
     218  	const char *cpi = cp;
     219  
     220  	while (rpi > rel_installdir && cpi > cp_base)
     221  	  {
     222  	    rpi--;
     223  	    cpi--;
     224  	    if (ISSLASH (*rpi) || ISSLASH (*cpi))
     225  	      {
     226  		if (ISSLASH (*rpi) && ISSLASH (*cpi))
     227  		  same = true;
     228  		break;
     229  	      }
     230  #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
     231  	    /* Win32, OS/2, DOS - case insignificant filesystem */
     232  	    if ((*rpi >= 'a' && *rpi <= 'z' ? *rpi - 'a' + 'A' : *rpi)
     233  		!= (*cpi >= 'a' && *cpi <= 'z' ? *cpi - 'a' + 'A' : *cpi))
     234  	      break;
     235  #else
     236  	    if (*rpi != *cpi)
     237  	      break;
     238  #endif
     239  	  }
     240  	if (!same)
     241  	  break;
     242  	/* The last pathname component was the same.  opi and cpi now point
     243  	   to the slash before it.  */
     244  	rp = rpi;
     245  	cp = cpi;
     246        }
     247  
     248      if (rp > rel_installdir)
     249        /* Unexpected: The curr_installdir does not end with rel_installdir.  */
     250        return NULL;
     251  
     252      {
     253        size_t curr_prefix_len = cp - curr_installdir;
     254        char *curr_prefix;
     255  
     256        curr_prefix = (char *) xmalloc (curr_prefix_len + 1);
     257  #ifdef NO_XMALLOC
     258        if (curr_prefix == NULL)
     259  	return NULL;
     260  #endif
     261        memcpy (curr_prefix, curr_installdir, curr_prefix_len);
     262        curr_prefix[curr_prefix_len] = '\0';
     263  
     264        return curr_prefix;
     265      }
     266    }
     267  }
     268  
     269  #if defined PIC && defined INSTALLDIR
     270  
     271  /* Full pathname of shared library, or NULL.  */
     272  static char *shared_library_fullname;
     273  
     274  #if defined _WIN32 || defined __WIN32__
     275  
     276  /* Determine the full pathname of the shared library when it is loaded.  */
     277  
     278  BOOL WINAPI
     279  DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved)
     280  {
     281    (void) reserved;
     282  
     283    if (event == DLL_PROCESS_ATTACH)
     284      {
     285        /* The DLL is being loaded into an application's address range.  */
     286        static char location[MAX_PATH];
     287  
     288        if (!GetModuleFileName (module_handle, location, sizeof (location)))
     289  	/* Shouldn't happen.  */
     290  	return FALSE;
     291  
     292        if (!IS_PATH_WITH_DIR (location))
     293  	/* Shouldn't happen.  */
     294  	return FALSE;
     295  
     296        shared_library_fullname = strdup (location);
     297      }
     298  
     299    return TRUE;
     300  }
     301  
     302  #else /* Unix */
     303  
     304  static void
     305  find_shared_library_fullname ()
     306  {
     307  #ifdef __linux__
     308    FILE *fp;
     309  
     310    /* Open the current process' maps file.  It describes one VMA per line.  */
     311    fp = fopen ("/proc/self/maps", "r");
     312    if (fp)
     313      {
     314        unsigned long address = (unsigned long) &find_shared_library_fullname;
     315        for (;;)
     316  	{
     317  	  unsigned long start, end;
     318  	  int c;
     319  
     320  	  if (fscanf (fp, "%lx-%lx", &start, &end) != 2)
     321  	    break;
     322  	  if (address >= start && address <= end - 1)
     323  	    {
     324  	      /* Found it.  Now see if this line contains a filename.  */
     325  	      while (c = getc (fp), c != EOF && c != '\n' && c != '/')
     326  		continue;
     327  	      if (c == '/')
     328  		{
     329  		  size_t size;
     330  		  int len;
     331  
     332  		  ungetc (c, fp);
     333  		  shared_library_fullname = NULL; size = 0;
     334  		  len = getline (&shared_library_fullname, &size, fp);
     335  		  if (len >= 0)
     336  		    {
     337  		      /* Success: filled shared_library_fullname.  */
     338  		      if (len > 0 && shared_library_fullname[len - 1] == '\n')
     339  			shared_library_fullname[len - 1] = '\0';
     340  		    }
     341  		}
     342  	      break;
     343  	    }
     344  	  while (c = getc (fp), c != EOF && c != '\n')
     345  	    continue;
     346  	}
     347        fclose (fp);
     348      }
     349  #endif
     350  }
     351  
     352  #endif /* WIN32 / Unix */
     353  
     354  /* Return the full pathname of the current shared library.
     355     Return NULL if unknown.
     356     Guaranteed to work only on Linux and Woe32.  */
     357  static char *
     358  get_shared_library_fullname ()
     359  {
     360  #if !(defined _WIN32 || defined __WIN32__)
     361    static bool tried_find_shared_library_fullname;
     362    if (!tried_find_shared_library_fullname)
     363      {
     364        find_shared_library_fullname ();
     365        tried_find_shared_library_fullname = true;
     366      }
     367  #endif
     368    return shared_library_fullname;
     369  }
     370  
     371  #endif /* PIC */
     372  
     373  /* Returns the pathname, relocated according to the current installation
     374     directory.  */
     375  const char *
     376  relocate (const char *pathname)
     377  {
     378  #if defined PIC && defined INSTALLDIR
     379    static int initialized;
     380  
     381    /* Initialization code for a shared library.  */
     382    if (!initialized)
     383      {
     384        /* At this point, orig_prefix and curr_prefix likely have already been
     385  	 set through the main program's set_program_name_and_installdir
     386  	 function.  This is sufficient in the case that the library has
     387  	 initially been installed in the same orig_prefix.  But we can do
     388  	 better, to also cover the cases that 1. it has been installed
     389  	 in a different prefix before being moved to orig_prefix and (later)
     390  	 to curr_prefix, 2. unlike the program, it has not moved away from
     391  	 orig_prefix.  */
     392        const char *orig_installprefix = INSTALLPREFIX;
     393        const char *orig_installdir = INSTALLDIR;
     394        const char *curr_prefix_better;
     395  
     396        curr_prefix_better =
     397  	compute_curr_prefix (orig_installprefix, orig_installdir,
     398  			     get_shared_library_fullname ());
     399        if (curr_prefix_better == NULL)
     400  	curr_prefix_better = curr_prefix;
     401  
     402        set_relocation_prefix (orig_installprefix, curr_prefix_better);
     403  
     404        initialized = 1;
     405      }
     406  #endif
     407  
     408    /* Note: It is not necessary to perform case insensitive comparison here,
     409       even for DOS-like filesystems, because the pathname argument was
     410       typically created from the same Makefile variable as orig_prefix came
     411       from.  */
     412    if (orig_prefix != NULL && curr_prefix != NULL
     413        && strncmp (pathname, orig_prefix, orig_prefix_len) == 0)
     414      {
     415        if (pathname[orig_prefix_len] == '\0')
     416  	/* pathname equals orig_prefix.  */
     417  	return curr_prefix;
     418        if (ISSLASH (pathname[orig_prefix_len]))
     419  	{
     420  	  /* pathname starts with orig_prefix.  */
     421  	  const char *pathname_tail = &pathname[orig_prefix_len];
     422  	  char *result =
     423  	    (char *) xmalloc (curr_prefix_len + strlen (pathname_tail) + 1);
     424  
     425  #ifdef NO_XMALLOC
     426  	  if (result != NULL)
     427  #endif
     428  	    {
     429  	      memcpy (result, curr_prefix, curr_prefix_len);
     430  	      strcpy (result + curr_prefix_len, pathname_tail);
     431  	      return result;
     432  	    }
     433  	}
     434      }
     435    /* Nothing to relocate.  */
     436    return pathname;
     437  }
     438  
     439  #endif