File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libiconv / srclib / relocatable.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 09:29:43 2012 UTC (12 years, 1 month ago) by misho
Branches: libiconv, MAIN
CVS tags: v1_14p0, v1_14, HEAD
libiconv v1.14

    1: /* Provide relocatable packages.
    2:    Copyright (C) 2003-2006, 2008-2011 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
    6:    it under the terms of the GNU General Public License as published by
    7:    the Free Software Foundation; either version 3 of the License, or
    8:    (at your option) 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
   13:    GNU General Public License for more details.
   14: 
   15:    You should have received a copy of the GNU General Public License
   16:    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
   17: 
   18: 
   19: /* Tell glibc's <stdio.h> to provide a prototype for getline().
   20:    This must come before <config.h> because <config.h> may include
   21:    <features.h>, and once <features.h> has been included, it's too late.  */
   22: #ifndef _GNU_SOURCE
   23: # define _GNU_SOURCE 1
   24: #endif
   25: 
   26: #define _GL_USE_STDLIB_ALLOC 1
   27: #include <config.h>
   28: 
   29: /* Specification.  */
   30: #include "relocatable.h"
   31: 
   32: #if ENABLE_RELOCATABLE
   33: 
   34: #include <stddef.h>
   35: #include <stdio.h>
   36: #include <stdlib.h>
   37: #include <string.h>
   38: 
   39: #ifdef NO_XMALLOC
   40: # define xmalloc malloc
   41: #else
   42: # include "xalloc.h"
   43: #endif
   44: 
   45: #if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__
   46: # define WIN32_LEAN_AND_MEAN
   47: # include <windows.h>
   48: #endif
   49: 
   50: #if DEPENDS_ON_LIBCHARSET
   51: # include <libcharset.h>
   52: #endif
   53: #if DEPENDS_ON_LIBICONV && HAVE_ICONV
   54: # include <iconv.h>
   55: #endif
   56: #if DEPENDS_ON_LIBINTL && ENABLE_NLS
   57: # include <libintl.h>
   58: #endif
   59: 
   60: /* Faked cheap 'bool'.  */
   61: #undef bool
   62: #undef false
   63: #undef true
   64: #define bool int
   65: #define false 0
   66: #define true 1
   67: 
   68: /* Pathname support.
   69:    ISSLASH(C)           tests whether C is a directory separator character.
   70:    IS_PATH_WITH_DIR(P)  tests whether P contains a directory specification.
   71:  */
   72: #if ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__
   73:   /* Win32, OS/2, DOS */
   74: # define ISSLASH(C) ((C) == '/' || (C) == '\\')
   75: # define HAS_DEVICE(P) \
   76:     ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
   77:      && (P)[1] == ':')
   78: # define IS_PATH_WITH_DIR(P) \
   79:     (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
   80: # define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
   81: #else
   82:   /* Unix */
   83: # define ISSLASH(C) ((C) == '/')
   84: # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
   85: # define FILE_SYSTEM_PREFIX_LEN(P) 0
   86: #endif
   87: 
   88: /* Original installation prefix.  */
   89: static char *orig_prefix;
   90: static size_t orig_prefix_len;
   91: /* Current installation prefix.  */
   92: static char *curr_prefix;
   93: static size_t curr_prefix_len;
   94: /* These prefixes do not end in a slash.  Anything that will be concatenated
   95:    to them must start with a slash.  */
   96: 
   97: /* Sets the original and the current installation prefix of this module.
   98:    Relocation simply replaces a pathname starting with the original prefix
   99:    by the corresponding pathname with the current prefix instead.  Both
  100:    prefixes should be directory names without trailing slash (i.e. use ""
  101:    instead of "/").  */
  102: static void
  103: set_this_relocation_prefix (const char *orig_prefix_arg,
  104:                             const char *curr_prefix_arg)
  105: {
  106:   if (orig_prefix_arg != NULL && curr_prefix_arg != NULL
  107:       /* Optimization: if orig_prefix and curr_prefix are equal, the
  108:          relocation is a nop.  */
  109:       && strcmp (orig_prefix_arg, curr_prefix_arg) != 0)
  110:     {
  111:       /* Duplicate the argument strings.  */
  112:       char *memory;
  113: 
  114:       orig_prefix_len = strlen (orig_prefix_arg);
  115:       curr_prefix_len = strlen (curr_prefix_arg);
  116:       memory = (char *) xmalloc (orig_prefix_len + 1 + curr_prefix_len + 1);
  117: #ifdef NO_XMALLOC
  118:       if (memory != NULL)
  119: #endif
  120:         {
  121:           memcpy (memory, orig_prefix_arg, orig_prefix_len + 1);
  122:           orig_prefix = memory;
  123:           memory += orig_prefix_len + 1;
  124:           memcpy (memory, curr_prefix_arg, curr_prefix_len + 1);
  125:           curr_prefix = memory;
  126:           return;
  127:         }
  128:     }
  129:   orig_prefix = NULL;
  130:   curr_prefix = NULL;
  131:   /* Don't worry about wasted memory here - this function is usually only
  132:      called once.  */
  133: }
  134: 
  135: /* Sets the original and the current installation prefix of the package.
  136:    Relocation simply replaces a pathname starting with the original prefix
  137:    by the corresponding pathname with the current prefix instead.  Both
  138:    prefixes should be directory names without trailing slash (i.e. use ""
  139:    instead of "/").  */
  140: void
  141: set_relocation_prefix (const char *orig_prefix_arg, const char *curr_prefix_arg)
  142: {
  143:   set_this_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
  144: 
  145:   /* Now notify all dependent libraries.  */
  146: #if DEPENDS_ON_LIBCHARSET
  147:   libcharset_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
  148: #endif
  149: #if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109
  150:   libiconv_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
  151: #endif
  152: #if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_prefix
  153:   libintl_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
  154: #endif
  155: }
  156: 
  157: #if !defined IN_LIBRARY || (defined PIC && defined INSTALLDIR)
  158: 
  159: /* Convenience function:
  160:    Computes the current installation prefix, based on the original
  161:    installation prefix, the original installation directory of a particular
  162:    file, and the current pathname of this file.
  163:    Returns it, freshly allocated.  Returns NULL upon failure.  */
  164: #ifdef IN_LIBRARY
  165: #define compute_curr_prefix local_compute_curr_prefix
  166: static
  167: #endif
  168: char *
  169: compute_curr_prefix (const char *orig_installprefix,
  170:                      const char *orig_installdir,
  171:                      const char *curr_pathname)
  172: {
  173:   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 file system 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 file system */
  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:       {
  258:         /* Unexpected: The curr_installdir does not end with rel_installdir.  */
  259:         free (curr_installdir);
  260:         return NULL;
  261:       }
  262: 
  263:     {
  264:       size_t curr_prefix_len = cp - curr_installdir;
  265:       char *curr_prefix;
  266: 
  267:       curr_prefix = (char *) xmalloc (curr_prefix_len + 1);
  268: #ifdef NO_XMALLOC
  269:       if (curr_prefix == NULL)
  270:         {
  271:           free (curr_installdir);
  272:           return NULL;
  273:         }
  274: #endif
  275:       memcpy (curr_prefix, curr_installdir, curr_prefix_len);
  276:       curr_prefix[curr_prefix_len] = '\0';
  277: 
  278:       free (curr_installdir);
  279: 
  280:       return curr_prefix;
  281:     }
  282:   }
  283: }
  284: 
  285: #endif /* !IN_LIBRARY || PIC */
  286: 
  287: #if defined PIC && defined INSTALLDIR
  288: 
  289: /* Full pathname of shared library, or NULL.  */
  290: static char *shared_library_fullname;
  291: 
  292: #if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__
  293: /* Native Win32 only.
  294:    On Cygwin, it is better to use the Cygwin provided /proc interface, than
  295:    to use native Win32 API and cygwin_conv_to_posix_path, because it supports
  296:    longer file names
  297:    (see <http://cygwin.com/ml/cygwin/2011-01/msg00410.html>).  */
  298: 
  299: /* Determine the full pathname of the shared library when it is loaded.  */
  300: 
  301: BOOL WINAPI
  302: DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved)
  303: {
  304:   (void) reserved;
  305: 
  306:   if (event == DLL_PROCESS_ATTACH)
  307:     {
  308:       /* The DLL is being loaded into an application's address range.  */
  309:       static char location[MAX_PATH];
  310: 
  311:       if (!GetModuleFileName (module_handle, location, sizeof (location)))
  312:         /* Shouldn't happen.  */
  313:         return FALSE;
  314: 
  315:       if (!IS_PATH_WITH_DIR (location))
  316:         /* Shouldn't happen.  */
  317:         return FALSE;
  318: 
  319:       shared_library_fullname = strdup (location);
  320:     }
  321: 
  322:   return TRUE;
  323: }
  324: 
  325: #else /* Unix */
  326: 
  327: static void
  328: find_shared_library_fullname ()
  329: {
  330: #if (defined __linux__ && (__GLIBC__ >= 2 || defined __UCLIBC__)) || defined __CYGWIN__
  331:   /* Linux has /proc/self/maps. glibc 2 and uClibc have the getline()
  332:      function.
  333:      Cygwin >= 1.5 has /proc/self/maps and the getline() function too.  */
  334:   FILE *fp;
  335: 
  336:   /* Open the current process' maps file.  It describes one VMA per line.  */
  337:   fp = fopen ("/proc/self/maps", "r");
  338:   if (fp)
  339:     {
  340:       unsigned long address = (unsigned long) &find_shared_library_fullname;
  341:       for (;;)
  342:         {
  343:           unsigned long start, end;
  344:           int c;
  345: 
  346:           if (fscanf (fp, "%lx-%lx", &start, &end) != 2)
  347:             break;
  348:           if (address >= start && address <= end - 1)
  349:             {
  350:               /* Found it.  Now see if this line contains a filename.  */
  351:               while (c = getc (fp), c != EOF && c != '\n' && c != '/')
  352:                 continue;
  353:               if (c == '/')
  354:                 {
  355:                   size_t size;
  356:                   int len;
  357: 
  358:                   ungetc (c, fp);
  359:                   shared_library_fullname = NULL; size = 0;
  360:                   len = getline (&shared_library_fullname, &size, fp);
  361:                   if (len >= 0)
  362:                     {
  363:                       /* Success: filled shared_library_fullname.  */
  364:                       if (len > 0 && shared_library_fullname[len - 1] == '\n')
  365:                         shared_library_fullname[len - 1] = '\0';
  366:                     }
  367:                 }
  368:               break;
  369:             }
  370:           while (c = getc (fp), c != EOF && c != '\n')
  371:             continue;
  372:         }
  373:       fclose (fp);
  374:     }
  375: #endif
  376: }
  377: 
  378: #endif /* WIN32 / Unix */
  379: 
  380: /* Return the full pathname of the current shared library.
  381:    Return NULL if unknown.
  382:    Guaranteed to work only on Linux, Cygwin and Woe32.  */
  383: static char *
  384: get_shared_library_fullname ()
  385: {
  386: #if !((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__)
  387:   static bool tried_find_shared_library_fullname;
  388:   if (!tried_find_shared_library_fullname)
  389:     {
  390:       find_shared_library_fullname ();
  391:       tried_find_shared_library_fullname = true;
  392:     }
  393: #endif
  394:   return shared_library_fullname;
  395: }
  396: 
  397: #endif /* PIC */
  398: 
  399: /* Returns the pathname, relocated according to the current installation
  400:    directory.
  401:    The returned string is either PATHNAME unmodified or a freshly allocated
  402:    string that you can free with free() after casting it to 'char *'.  */
  403: const char *
  404: relocate (const char *pathname)
  405: {
  406: #if defined PIC && defined INSTALLDIR
  407:   static int initialized;
  408: 
  409:   /* Initialization code for a shared library.  */
  410:   if (!initialized)
  411:     {
  412:       /* At this point, orig_prefix and curr_prefix likely have already been
  413:          set through the main program's set_program_name_and_installdir
  414:          function.  This is sufficient in the case that the library has
  415:          initially been installed in the same orig_prefix.  But we can do
  416:          better, to also cover the cases that 1. it has been installed
  417:          in a different prefix before being moved to orig_prefix and (later)
  418:          to curr_prefix, 2. unlike the program, it has not moved away from
  419:          orig_prefix.  */
  420:       const char *orig_installprefix = INSTALLPREFIX;
  421:       const char *orig_installdir = INSTALLDIR;
  422:       char *curr_prefix_better;
  423: 
  424:       curr_prefix_better =
  425:         compute_curr_prefix (orig_installprefix, orig_installdir,
  426:                              get_shared_library_fullname ());
  427: 
  428:       set_relocation_prefix (orig_installprefix,
  429:                              curr_prefix_better != NULL
  430:                              ? curr_prefix_better
  431:                              : curr_prefix);
  432: 
  433:       if (curr_prefix_better != NULL)
  434:         free (curr_prefix_better);
  435: 
  436:       initialized = 1;
  437:     }
  438: #endif
  439: 
  440:   /* Note: It is not necessary to perform case insensitive comparison here,
  441:      even for DOS-like file systems, because the pathname argument was
  442:      typically created from the same Makefile variable as orig_prefix came
  443:      from.  */
  444:   if (orig_prefix != NULL && curr_prefix != NULL
  445:       && strncmp (pathname, orig_prefix, orig_prefix_len) == 0)
  446:     {
  447:       if (pathname[orig_prefix_len] == '\0')
  448:         {
  449:           /* pathname equals orig_prefix.  */
  450:           char *result = (char *) xmalloc (strlen (curr_prefix) + 1);
  451: 
  452: #ifdef NO_XMALLOC
  453:           if (result != NULL)
  454: #endif
  455:             {
  456:               strcpy (result, curr_prefix);
  457:               return result;
  458:             }
  459:         }
  460:       else if (ISSLASH (pathname[orig_prefix_len]))
  461:         {
  462:           /* pathname starts with orig_prefix.  */
  463:           const char *pathname_tail = &pathname[orig_prefix_len];
  464:           char *result =
  465:             (char *) xmalloc (curr_prefix_len + strlen (pathname_tail) + 1);
  466: 
  467: #ifdef NO_XMALLOC
  468:           if (result != NULL)
  469: #endif
  470:             {
  471:               memcpy (result, curr_prefix, curr_prefix_len);
  472:               strcpy (result + curr_prefix_len, pathname_tail);
  473:               return result;
  474:             }
  475:         }
  476:     }
  477:   /* Nothing to relocate.  */
  478:   return pathname;
  479: }
  480: 
  481: #endif

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