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

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