File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libiconv / lib / relocatable.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 22:57:48 2012 UTC (12 years, 4 months ago) by misho
Branches: libiconv, MAIN
CVS tags: v1_13_1, HEAD
libiconv

    1: /* Provide relocatable packages.
    2:    Copyright (C) 2003-2006 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.  Returns NULL upon failure.  */
  164: #ifdef IN_LIBRARY
  165: #define compute_curr_prefix local_compute_curr_prefix
  166: static
  167: #endif
  168: const char *
  169: compute_curr_prefix (const char *orig_installprefix,
  170: 		     const char *orig_installdir,
  171: 		     const char *curr_pathname)
  172: {
  173:   const char *curr_installdir;
  174:   const char *rel_installdir;
  175: 
  176:   if (curr_pathname == NULL)
  177:     return NULL;
  178: 
  179:   /* Determine the relative installation directory, relative to the prefix.
  180:      This is simply the difference between orig_installprefix and
  181:      orig_installdir.  */
  182:   if (strncmp (orig_installprefix, orig_installdir, strlen (orig_installprefix))
  183:       != 0)
  184:     /* Shouldn't happen - nothing should be installed outside $(prefix).  */
  185:     return NULL;
  186:   rel_installdir = orig_installdir + strlen (orig_installprefix);
  187: 
  188:   /* Determine the current installation directory.  */
  189:   {
  190:     const char *p_base = curr_pathname + FILE_SYSTEM_PREFIX_LEN (curr_pathname);
  191:     const char *p = curr_pathname + strlen (curr_pathname);
  192:     char *q;
  193: 
  194:     while (p > p_base)
  195:       {
  196: 	p--;
  197: 	if (ISSLASH (*p))
  198: 	  break;
  199:       }
  200: 
  201:     q = (char *) xmalloc (p - curr_pathname + 1);
  202: #ifdef NO_XMALLOC
  203:     if (q == NULL)
  204:       return NULL;
  205: #endif
  206:     memcpy (q, curr_pathname, p - curr_pathname);
  207:     q[p - curr_pathname] = '\0';
  208:     curr_installdir = q;
  209:   }
  210: 
  211:   /* Compute the current installation prefix by removing the trailing
  212:      rel_installdir from it.  */
  213:   {
  214:     const char *rp = rel_installdir + strlen (rel_installdir);
  215:     const char *cp = curr_installdir + strlen (curr_installdir);
  216:     const char *cp_base =
  217:       curr_installdir + FILE_SYSTEM_PREFIX_LEN (curr_installdir);
  218: 
  219:     while (rp > rel_installdir && cp > cp_base)
  220:       {
  221: 	bool same = false;
  222: 	const char *rpi = rp;
  223: 	const char *cpi = cp;
  224: 
  225: 	while (rpi > rel_installdir && cpi > cp_base)
  226: 	  {
  227: 	    rpi--;
  228: 	    cpi--;
  229: 	    if (ISSLASH (*rpi) || ISSLASH (*cpi))
  230: 	      {
  231: 		if (ISSLASH (*rpi) && ISSLASH (*cpi))
  232: 		  same = true;
  233: 		break;
  234: 	      }
  235: 	    /* Do case-insensitive comparison if the filesystem is always or
  236: 	       often case-insensitive.  It's better to accept the comparison
  237: 	       if the difference is only in case, rather than to fail.  */
  238: #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
  239: 	    /* Win32, Cygwin, OS/2, DOS - case insignificant filesystem */
  240: 	    if ((*rpi >= 'a' && *rpi <= 'z' ? *rpi - 'a' + 'A' : *rpi)
  241: 		!= (*cpi >= 'a' && *cpi <= 'z' ? *cpi - 'a' + 'A' : *cpi))
  242: 	      break;
  243: #else
  244: 	    if (*rpi != *cpi)
  245: 	      break;
  246: #endif
  247: 	  }
  248: 	if (!same)
  249: 	  break;
  250: 	/* The last pathname component was the same.  opi and cpi now point
  251: 	   to the slash before it.  */
  252: 	rp = rpi;
  253: 	cp = cpi;
  254:       }
  255: 
  256:     if (rp > rel_installdir)
  257:       /* Unexpected: The curr_installdir does not end with rel_installdir.  */
  258:       return NULL;
  259: 
  260:     {
  261:       size_t curr_prefix_len = cp - curr_installdir;
  262:       char *curr_prefix;
  263: 
  264:       curr_prefix = (char *) xmalloc (curr_prefix_len + 1);
  265: #ifdef NO_XMALLOC
  266:       if (curr_prefix == NULL)
  267: 	return NULL;
  268: #endif
  269:       memcpy (curr_prefix, curr_installdir, curr_prefix_len);
  270:       curr_prefix[curr_prefix_len] = '\0';
  271: 
  272:       return curr_prefix;
  273:     }
  274:   }
  275: }
  276: 
  277: #endif /* !IN_LIBRARY || PIC */
  278: 
  279: #if defined PIC && defined INSTALLDIR
  280: 
  281: /* Full pathname of shared library, or NULL.  */
  282: static char *shared_library_fullname;
  283: 
  284: #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__
  285: 
  286: /* Determine the full pathname of the shared library when it is loaded.  */
  287: 
  288: BOOL WINAPI
  289: DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved)
  290: {
  291:   (void) reserved;
  292: 
  293:   if (event == DLL_PROCESS_ATTACH)
  294:     {
  295:       /* The DLL is being loaded into an application's address range.  */
  296:       static char location[MAX_PATH];
  297: 
  298:       if (!GetModuleFileName (module_handle, location, sizeof (location)))
  299: 	/* Shouldn't happen.  */
  300: 	return FALSE;
  301: 
  302:       if (!IS_PATH_WITH_DIR (location))
  303: 	/* Shouldn't happen.  */
  304: 	return FALSE;
  305: 
  306:       {
  307: #if defined __CYGWIN__
  308: 	/* On Cygwin, we need to convert paths coming from Win32 system calls
  309: 	   to the Unix-like slashified notation.  */
  310: 	static char location_as_posix_path[2 * MAX_PATH];
  311: 	/* There's no error return defined for cygwin_conv_to_posix_path.
  312: 	   See cygwin-api/func-cygwin-conv-to-posix-path.html.
  313: 	   Does it overflow the buffer of expected size MAX_PATH or does it
  314: 	   truncate the path?  I don't know.  Let's catch both.  */
  315: 	cygwin_conv_to_posix_path (location, location_as_posix_path);
  316: 	location_as_posix_path[MAX_PATH - 1] = '\0';
  317: 	if (strlen (location_as_posix_path) >= MAX_PATH - 1)
  318: 	  /* A sign of buffer overflow or path truncation.  */
  319: 	  return FALSE;
  320: 	shared_library_fullname = strdup (location_as_posix_path);
  321: #else
  322: 	shared_library_fullname = strdup (location);
  323: #endif
  324:       }
  325:     }
  326: 
  327:   return TRUE;
  328: }
  329: 
  330: #else /* Unix except Cygwin */
  331: 
  332: static void
  333: find_shared_library_fullname ()
  334: {
  335: #if defined __linux__ && __GLIBC__ >= 2
  336:   /* Linux has /proc/self/maps. glibc 2 has the getline() function.  */
  337:   FILE *fp;
  338: 
  339:   /* Open the current process' maps file.  It describes one VMA per line.  */
  340:   fp = fopen ("/proc/self/maps", "r");
  341:   if (fp)
  342:     {
  343:       unsigned long address = (unsigned long) &find_shared_library_fullname;
  344:       for (;;)
  345: 	{
  346: 	  unsigned long start, end;
  347: 	  int c;
  348: 
  349: 	  if (fscanf (fp, "%lx-%lx", &start, &end) != 2)
  350: 	    break;
  351: 	  if (address >= start && address <= end - 1)
  352: 	    {
  353: 	      /* Found it.  Now see if this line contains a filename.  */
  354: 	      while (c = getc (fp), c != EOF && c != '\n' && c != '/')
  355: 		continue;
  356: 	      if (c == '/')
  357: 		{
  358: 		  size_t size;
  359: 		  int len;
  360: 
  361: 		  ungetc (c, fp);
  362: 		  shared_library_fullname = NULL; size = 0;
  363: 		  len = getline (&shared_library_fullname, &size, fp);
  364: 		  if (len >= 0)
  365: 		    {
  366: 		      /* Success: filled shared_library_fullname.  */
  367: 		      if (len > 0 && shared_library_fullname[len - 1] == '\n')
  368: 			shared_library_fullname[len - 1] = '\0';
  369: 		    }
  370: 		}
  371: 	      break;
  372: 	    }
  373: 	  while (c = getc (fp), c != EOF && c != '\n')
  374: 	    continue;
  375: 	}
  376:       fclose (fp);
  377:     }
  378: #endif
  379: }
  380: 
  381: #endif /* (WIN32 or Cygwin) / (Unix except Cygwin) */
  382: 
  383: /* Return the full pathname of the current shared library.
  384:    Return NULL if unknown.
  385:    Guaranteed to work only on Linux, Cygwin and Woe32.  */
  386: static char *
  387: get_shared_library_fullname ()
  388: {
  389: #if !(defined _WIN32 || defined __WIN32__ || defined __CYGWIN__)
  390:   static bool tried_find_shared_library_fullname;
  391:   if (!tried_find_shared_library_fullname)
  392:     {
  393:       find_shared_library_fullname ();
  394:       tried_find_shared_library_fullname = true;
  395:     }
  396: #endif
  397:   return shared_library_fullname;
  398: }
  399: 
  400: #endif /* PIC */
  401: 
  402: /* Returns the pathname, relocated according to the current installation
  403:    directory.  */
  404: const char *
  405: relocate (const char *pathname)
  406: {
  407: #if defined PIC && defined INSTALLDIR
  408:   static int initialized;
  409: 
  410:   /* Initialization code for a shared library.  */
  411:   if (!initialized)
  412:     {
  413:       /* At this point, orig_prefix and curr_prefix likely have already been
  414: 	 set through the main program's set_program_name_and_installdir
  415: 	 function.  This is sufficient in the case that the library has
  416: 	 initially been installed in the same orig_prefix.  But we can do
  417: 	 better, to also cover the cases that 1. it has been installed
  418: 	 in a different prefix before being moved to orig_prefix and (later)
  419: 	 to curr_prefix, 2. unlike the program, it has not moved away from
  420: 	 orig_prefix.  */
  421:       const char *orig_installprefix = INSTALLPREFIX;
  422:       const char *orig_installdir = INSTALLDIR;
  423:       const char *curr_prefix_better;
  424: 
  425:       curr_prefix_better =
  426: 	compute_curr_prefix (orig_installprefix, orig_installdir,
  427: 			     get_shared_library_fullname ());
  428:       if (curr_prefix_better == NULL)
  429: 	curr_prefix_better = curr_prefix;
  430: 
  431:       set_relocation_prefix (orig_installprefix, curr_prefix_better);
  432: 
  433:       initialized = 1;
  434:     }
  435: #endif
  436: 
  437:   /* Note: It is not necessary to perform case insensitive comparison here,
  438:      even for DOS-like filesystems, because the pathname argument was
  439:      typically created from the same Makefile variable as orig_prefix came
  440:      from.  */
  441:   if (orig_prefix != NULL && curr_prefix != NULL
  442:       && strncmp (pathname, orig_prefix, orig_prefix_len) == 0)
  443:     {
  444:       if (pathname[orig_prefix_len] == '\0')
  445: 	/* pathname equals orig_prefix.  */
  446: 	return curr_prefix;
  447:       if (ISSLASH (pathname[orig_prefix_len]))
  448: 	{
  449: 	  /* pathname starts with orig_prefix.  */
  450: 	  const char *pathname_tail = &pathname[orig_prefix_len];
  451: 	  char *result =
  452: 	    (char *) xmalloc (curr_prefix_len + strlen (pathname_tail) + 1);
  453: 
  454: #ifdef NO_XMALLOC
  455: 	  if (result != NULL)
  456: #endif
  457: 	    {
  458: 	      memcpy (result, curr_prefix, curr_prefix_len);
  459: 	      strcpy (result + curr_prefix_len, pathname_tail);
  460: 	      return result;
  461: 	    }
  462: 	}
  463:     }
  464:   /* Nothing to relocate.  */
  465:   return pathname;
  466: }
  467: 
  468: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>