Annotation of embedaddon/libiconv/srclib/relocatable.c, revision 1.1.1.2

1.1       misho       1: /* Provide relocatable packages.
1.1.1.2 ! misho       2:    Copyright (C) 2003-2006, 2008-2011 Free Software Foundation, Inc.
1.1       misho       3:    Written by Bruno Haible <bruno@clisp.org>, 2003.
                      4: 
1.1.1.2 ! misho       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.
1.1       misho       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
1.1.1.2 ! misho      12:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            13:    GNU General Public License for more details.
1.1       misho      14: 
1.1.1.2 ! misho      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/>.  */
1.1       misho      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
1.1.1.2 ! misho      23: # define _GNU_SOURCE 1
1.1       misho      24: #endif
                     25: 
1.1.1.2 ! misho      26: #define _GL_USE_STDLIB_ALLOC 1
1.1       misho      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: 
1.1.1.2 ! misho      45: #if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__
1.1       misho      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:  */
1.1.1.2 ! misho      72: #if ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__
        !            73:   /* Win32, OS/2, DOS */
1.1       misho      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,
1.1.1.2 ! misho     104:                             const char *curr_prefix_arg)
1.1       misho     105: {
                    106:   if (orig_prefix_arg != NULL && curr_prefix_arg != NULL
                    107:       /* Optimization: if orig_prefix and curr_prefix are equal, the
1.1.1.2 ! misho     108:          relocation is a nop.  */
1.1       misho     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
1.1.1.2 ! misho     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:         }
1.1       misho     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,
1.1.1.2 ! misho     170:                      const char *orig_installdir,
        !           171:                      const char *curr_pathname)
1.1       misho     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:       {
1.1.1.2 ! misho     196:         p--;
        !           197:         if (ISSLASH (*p))
        !           198:           break;
1.1       misho     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:       {
1.1.1.2 ! misho     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.  */
1.1       misho     238: #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
1.1.1.2 ! misho     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;
1.1       misho     243: #else
1.1.1.2 ! misho     244:             if (*rpi != *cpi)
        !           245:               break;
1.1       misho     246: #endif
1.1.1.2 ! misho     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;
1.1       misho     254:       }
                    255: 
                    256:     if (rp > rel_installdir)
                    257:       {
1.1.1.2 ! misho     258:         /* Unexpected: The curr_installdir does not end with rel_installdir.  */
        !           259:         free (curr_installdir);
        !           260:         return NULL;
1.1       misho     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)
1.1.1.2 ! misho     270:         {
        !           271:           free (curr_installdir);
        !           272:           return NULL;
        !           273:         }
1.1       misho     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: 
1.1.1.2 ! misho     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>).  */
1.1       misho     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)))
1.1.1.2 ! misho     312:         /* Shouldn't happen.  */
        !           313:         return FALSE;
1.1       misho     314: 
                    315:       if (!IS_PATH_WITH_DIR (location))
1.1.1.2 ! misho     316:         /* Shouldn't happen.  */
        !           317:         return FALSE;
1.1       misho     318: 
1.1.1.2 ! misho     319:       shared_library_fullname = strdup (location);
1.1       misho     320:     }
                    321: 
                    322:   return TRUE;
                    323: }
                    324: 
1.1.1.2 ! misho     325: #else /* Unix */
1.1       misho     326: 
                    327: static void
                    328: find_shared_library_fullname ()
                    329: {
1.1.1.2 ! misho     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.  */
1.1       misho     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 (;;)
1.1.1.2 ! misho     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:         }
1.1       misho     373:       fclose (fp);
                    374:     }
                    375: #endif
                    376: }
                    377: 
1.1.1.2 ! misho     378: #endif /* WIN32 / Unix */
1.1       misho     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: {
1.1.1.2 ! misho     386: #if !((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__)
1.1       misho     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
1.1.1.2 ! misho     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.  */
1.1       misho     420:       const char *orig_installprefix = INSTALLPREFIX;
                    421:       const char *orig_installdir = INSTALLDIR;
                    422:       char *curr_prefix_better;
                    423: 
                    424:       curr_prefix_better =
1.1.1.2 ! misho     425:         compute_curr_prefix (orig_installprefix, orig_installdir,
        !           426:                              get_shared_library_fullname ());
1.1       misho     427: 
                    428:       set_relocation_prefix (orig_installprefix,
1.1.1.2 ! misho     429:                              curr_prefix_better != NULL
        !           430:                              ? curr_prefix_better
        !           431:                              : curr_prefix);
1.1       misho     432: 
                    433:       if (curr_prefix_better != NULL)
1.1.1.2 ! misho     434:         free (curr_prefix_better);
1.1       misho     435: 
                    436:       initialized = 1;
                    437:     }
                    438: #endif
                    439: 
                    440:   /* Note: It is not necessary to perform case insensitive comparison here,
1.1.1.2 ! misho     441:      even for DOS-like file systems, because the pathname argument was
1.1       misho     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')
1.1.1.2 ! misho     448:         {
        !           449:           /* pathname equals orig_prefix.  */
        !           450:           char *result = (char *) xmalloc (strlen (curr_prefix) + 1);
1.1       misho     451: 
                    452: #ifdef NO_XMALLOC
1.1.1.2 ! misho     453:           if (result != NULL)
1.1       misho     454: #endif
1.1.1.2 ! misho     455:             {
        !           456:               strcpy (result, curr_prefix);
        !           457:               return result;
        !           458:             }
        !           459:         }
1.1       misho     460:       else if (ISSLASH (pathname[orig_prefix_len]))
1.1.1.2 ! misho     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);
1.1       misho     466: 
                    467: #ifdef NO_XMALLOC
1.1.1.2 ! misho     468:           if (result != NULL)
1.1       misho     469: #endif
1.1.1.2 ! misho     470:             {
        !           471:               memcpy (result, curr_prefix, curr_prefix_len);
        !           472:               strcpy (result + curr_prefix_len, pathname_tail);
        !           473:               return result;
        !           474:             }
        !           475:         }
1.1       misho     476:     }
                    477:   /* Nothing to relocate.  */
                    478:   return pathname;
                    479: }
                    480: 
                    481: #endif

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