File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libiconv / srclib / relocatable.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 13:38:46 2021 UTC (3 years, 3 months ago) by misho
Branches: libiconv, MAIN
CVS tags: v1_16p0, HEAD
libiconv 1.16

    1: /* Provide relocatable packages.
    2:    Copyright (C) 2003-2006, 2008-2019 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 <https://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 __CYGWIN__
   46: # define WIN32_LEAN_AND_MEAN
   47: # include <windows.h>
   48: #endif
   49: 
   50: #ifdef __EMX__
   51: # define INCL_DOS
   52: # include <os2.h>
   53: 
   54: # define strcmp  stricmp
   55: # define strncmp strnicmp
   56: #endif
   57: 
   58: #if DEPENDS_ON_LIBCHARSET
   59: # include <libcharset.h>
   60: #endif
   61: #if DEPENDS_ON_LIBICONV && HAVE_ICONV
   62: # include <iconv.h>
   63: #endif
   64: #if DEPENDS_ON_LIBINTL && ENABLE_NLS
   65: # include <libintl.h>
   66: #endif
   67: 
   68: /* Faked cheap 'bool'.  */
   69: #undef bool
   70: #undef false
   71: #undef true
   72: #define bool int
   73: #define false 0
   74: #define true 1
   75: 
   76: /* Pathname support.
   77:    ISSLASH(C)           tests whether C is a directory separator character.
   78:    IS_PATH_WITH_DIR(P)  tests whether P contains a directory specification.
   79:  */
   80: #if (defined _WIN32 && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__
   81:   /* Native Windows, OS/2, DOS */
   82: # define ISSLASH(C) ((C) == '/' || (C) == '\\')
   83: # define HAS_DEVICE(P) \
   84:     ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
   85:      && (P)[1] == ':')
   86: # define IS_PATH_WITH_DIR(P) \
   87:     (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
   88: # define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
   89: #else
   90:   /* Unix */
   91: # define ISSLASH(C) ((C) == '/')
   92: # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
   93: # define FILE_SYSTEM_PREFIX_LEN(P) 0
   94: #endif
   95: 
   96: /* Whether to enable the more costly support for relocatable libraries.
   97:    It allows libraries to be have been installed with a different original
   98:    prefix than the program.  But it is quite costly, especially on Cygwin
   99:    platforms, see below.  Therefore we enable it by default only on native
  100:    Windows platforms.  */
  101: #ifndef ENABLE_COSTLY_RELOCATABLE
  102: # if defined _WIN32 && !defined __CYGWIN__
  103: #  define ENABLE_COSTLY_RELOCATABLE 1
  104: # else
  105: #  define ENABLE_COSTLY_RELOCATABLE 0
  106: # endif
  107: #endif
  108: 
  109: /* Original installation prefix.  */
  110: static char *orig_prefix;
  111: static size_t orig_prefix_len;
  112: /* Current installation prefix.  */
  113: static char *curr_prefix;
  114: static size_t curr_prefix_len;
  115: /* These prefixes do not end in a slash.  Anything that will be concatenated
  116:    to them must start with a slash.  */
  117: 
  118: /* Sets the original and the current installation prefix of this module.
  119:    Relocation simply replaces a pathname starting with the original prefix
  120:    by the corresponding pathname with the current prefix instead.  Both
  121:    prefixes should be directory names without trailing slash (i.e. use ""
  122:    instead of "/").  */
  123: static void
  124: set_this_relocation_prefix (const char *orig_prefix_arg,
  125:                             const char *curr_prefix_arg)
  126: {
  127:   if (orig_prefix_arg != NULL && curr_prefix_arg != NULL
  128:       /* Optimization: if orig_prefix and curr_prefix are equal, the
  129:          relocation is a nop.  */
  130:       && strcmp (orig_prefix_arg, curr_prefix_arg) != 0)
  131:     {
  132:       /* Duplicate the argument strings.  */
  133:       char *memory;
  134: 
  135:       orig_prefix_len = strlen (orig_prefix_arg);
  136:       curr_prefix_len = strlen (curr_prefix_arg);
  137:       memory = (char *) xmalloc (orig_prefix_len + 1 + curr_prefix_len + 1);
  138: #ifdef NO_XMALLOC
  139:       if (memory != NULL)
  140: #endif
  141:         {
  142:           memcpy (memory, orig_prefix_arg, orig_prefix_len + 1);
  143:           orig_prefix = memory;
  144:           memory += orig_prefix_len + 1;
  145:           memcpy (memory, curr_prefix_arg, curr_prefix_len + 1);
  146:           curr_prefix = memory;
  147:           return;
  148:         }
  149:     }
  150:   orig_prefix = NULL;
  151:   curr_prefix = NULL;
  152:   /* Don't worry about wasted memory here - this function is usually only
  153:      called once.  */
  154: }
  155: 
  156: /* Sets the original and the current installation prefix of the package.
  157:    Relocation simply replaces a pathname starting with the original prefix
  158:    by the corresponding pathname with the current prefix instead.  Both
  159:    prefixes should be directory names without trailing slash (i.e. use ""
  160:    instead of "/").  */
  161: void
  162: set_relocation_prefix (const char *orig_prefix_arg, const char *curr_prefix_arg)
  163: {
  164:   set_this_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
  165: 
  166:   /* Now notify all dependent libraries.  */
  167: #if DEPENDS_ON_LIBCHARSET
  168:   libcharset_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
  169: #endif
  170: #if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109
  171:   libiconv_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
  172: #endif
  173: #if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_prefix
  174:   libintl_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
  175: #endif
  176: }
  177: 
  178: #if !defined IN_LIBRARY || (defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE)
  179: 
  180: /* Convenience function:
  181:    Computes the current installation prefix, based on the original
  182:    installation prefix, the original installation directory of a particular
  183:    file, and the current pathname of this file.
  184:    Returns it, freshly allocated.  Returns NULL upon failure.  */
  185: #ifdef IN_LIBRARY
  186: #define compute_curr_prefix local_compute_curr_prefix
  187: static
  188: #endif
  189: char *
  190: compute_curr_prefix (const char *orig_installprefix,
  191:                      const char *orig_installdir,
  192:                      const char *curr_pathname)
  193: {
  194:   char *curr_installdir;
  195:   const char *rel_installdir;
  196: 
  197:   if (curr_pathname == NULL)
  198:     return NULL;
  199: 
  200:   /* Determine the relative installation directory, relative to the prefix.
  201:      This is simply the difference between orig_installprefix and
  202:      orig_installdir.  */
  203:   if (strncmp (orig_installprefix, orig_installdir, strlen (orig_installprefix))
  204:       != 0)
  205:     /* Shouldn't happen - nothing should be installed outside $(prefix).  */
  206:     return NULL;
  207:   rel_installdir = orig_installdir + strlen (orig_installprefix);
  208: 
  209:   /* Determine the current installation directory.  */
  210:   {
  211:     const char *p_base = curr_pathname + FILE_SYSTEM_PREFIX_LEN (curr_pathname);
  212:     const char *p = curr_pathname + strlen (curr_pathname);
  213:     char *q;
  214: 
  215:     while (p > p_base)
  216:       {
  217:         p--;
  218:         if (ISSLASH (*p))
  219:           break;
  220:       }
  221: 
  222:     q = (char *) xmalloc (p - curr_pathname + 1);
  223: #ifdef NO_XMALLOC
  224:     if (q == NULL)
  225:       return NULL;
  226: #endif
  227:     memcpy (q, curr_pathname, p - curr_pathname);
  228:     q[p - curr_pathname] = '\0';
  229:     curr_installdir = q;
  230:   }
  231: 
  232:   /* Compute the current installation prefix by removing the trailing
  233:      rel_installdir from it.  */
  234:   {
  235:     const char *rp = rel_installdir + strlen (rel_installdir);
  236:     const char *cp = curr_installdir + strlen (curr_installdir);
  237:     const char *cp_base =
  238:       curr_installdir + FILE_SYSTEM_PREFIX_LEN (curr_installdir);
  239: 
  240:     while (rp > rel_installdir && cp > cp_base)
  241:       {
  242:         bool same = false;
  243:         const char *rpi = rp;
  244:         const char *cpi = cp;
  245: 
  246:         while (rpi > rel_installdir && cpi > cp_base)
  247:           {
  248:             rpi--;
  249:             cpi--;
  250:             if (ISSLASH (*rpi) || ISSLASH (*cpi))
  251:               {
  252:                 if (ISSLASH (*rpi) && ISSLASH (*cpi))
  253:                   same = true;
  254:                 break;
  255:               }
  256:             /* Do case-insensitive comparison if the file system is always or
  257:                often case-insensitive.  It's better to accept the comparison
  258:                if the difference is only in case, rather than to fail.  */
  259: #if defined _WIN32 || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
  260:             /* Native Windows, Cygwin, OS/2, DOS - case insignificant file system */
  261:             if ((*rpi >= 'a' && *rpi <= 'z' ? *rpi - 'a' + 'A' : *rpi)
  262:                 != (*cpi >= 'a' && *cpi <= 'z' ? *cpi - 'a' + 'A' : *cpi))
  263:               break;
  264: #else
  265:             if (*rpi != *cpi)
  266:               break;
  267: #endif
  268:           }
  269:         if (!same)
  270:           break;
  271:         /* The last pathname component was the same.  rpi and cpi now point
  272:            to the slash before it.  */
  273:         rp = rpi;
  274:         cp = cpi;
  275:       }
  276: 
  277:     if (rp > rel_installdir)
  278:       {
  279:         /* Unexpected: The curr_installdir does not end with rel_installdir.  */
  280:         free (curr_installdir);
  281:         return NULL;
  282:       }
  283: 
  284:     {
  285:       size_t computed_curr_prefix_len = cp - curr_installdir;
  286:       char *computed_curr_prefix;
  287: 
  288:       computed_curr_prefix = (char *) xmalloc (computed_curr_prefix_len + 1);
  289: #ifdef NO_XMALLOC
  290:       if (computed_curr_prefix == NULL)
  291:         {
  292:           free (curr_installdir);
  293:           return NULL;
  294:         }
  295: #endif
  296:       memcpy (computed_curr_prefix, curr_installdir, computed_curr_prefix_len);
  297:       computed_curr_prefix[computed_curr_prefix_len] = '\0';
  298: 
  299:       free (curr_installdir);
  300: 
  301:       return computed_curr_prefix;
  302:     }
  303:   }
  304: }
  305: 
  306: #endif /* !IN_LIBRARY || PIC */
  307: 
  308: #if defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE
  309: 
  310: /* Full pathname of shared library, or NULL.  */
  311: static char *shared_library_fullname;
  312: 
  313: #if defined _WIN32 && !defined __CYGWIN__
  314: /* Native Windows only.
  315:    On Cygwin, it is better to use the Cygwin provided /proc interface, than
  316:    to use native Windows API and cygwin_conv_to_posix_path, because it
  317:    supports longer file names
  318:    (see <https://cygwin.com/ml/cygwin/2011-01/msg00410.html>).  */
  319: 
  320: /* Determine the full pathname of the shared library when it is loaded.  */
  321: 
  322: BOOL WINAPI
  323: DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved)
  324: {
  325:   (void) reserved;
  326: 
  327:   if (event == DLL_PROCESS_ATTACH)
  328:     {
  329:       /* The DLL is being loaded into an application's address range.  */
  330:       static char location[MAX_PATH];
  331: 
  332:       if (!GetModuleFileName (module_handle, location, sizeof (location)))
  333:         /* Shouldn't happen.  */
  334:         return FALSE;
  335: 
  336:       if (!IS_PATH_WITH_DIR (location))
  337:         /* Shouldn't happen.  */
  338:         return FALSE;
  339: 
  340:       shared_library_fullname = strdup (location);
  341:     }
  342: 
  343:   return TRUE;
  344: }
  345: 
  346: #elif defined __EMX__
  347: 
  348: extern int  _CRT_init (void);
  349: extern void _CRT_term (void);
  350: extern void __ctordtorInit (void);
  351: extern void __ctordtorTerm (void);
  352: 
  353: unsigned long _System
  354: _DLL_InitTerm (unsigned long hModule, unsigned long ulFlag)
  355: {
  356:   static char location[CCHMAXPATH];
  357: 
  358:   switch (ulFlag)
  359:     {
  360:       case 0:
  361:         if (_CRT_init () == -1)
  362:           return 0;
  363: 
  364:         __ctordtorInit();
  365: 
  366:         /* See http://cyberkinetica.homeunix.net/os2tk45/cp1/1247_L2H_DosQueryModuleNameSy.html
  367:            for specification of DosQueryModuleName(). */
  368:         if (DosQueryModuleName (hModule, sizeof (location), location))
  369:           return 0;
  370: 
  371:         _fnslashify (location);
  372:         shared_library_fullname = strdup (location);
  373:         break;
  374: 
  375:       case 1:
  376:         __ctordtorTerm();
  377: 
  378:         _CRT_term ();
  379:         break;
  380:     }
  381: 
  382:   return 1;
  383: }
  384: 
  385: #else /* Unix */
  386: 
  387: static void
  388: find_shared_library_fullname ()
  389: {
  390: #if (defined __linux__ && (__GLIBC__ >= 2 || defined __UCLIBC__)) || defined __CYGWIN__
  391:   /* Linux has /proc/self/maps. glibc 2 and uClibc have the getline()
  392:      function.
  393:      Cygwin >= 1.5 has /proc/self/maps and the getline() function too.
  394:      But it is costly: ca. 0.3 ms on Linux, 3 ms on Cygwin 1.5, and 5 ms on
  395:      Cygwin 1.7.  */
  396:   FILE *fp;
  397: 
  398:   /* Open the current process' maps file.  It describes one VMA per line.  */
  399:   fp = fopen ("/proc/self/maps", "r");
  400:   if (fp)
  401:     {
  402:       unsigned long address = (unsigned long) &find_shared_library_fullname;
  403:       for (;;)
  404:         {
  405:           unsigned long start, end;
  406:           int c;
  407: 
  408:           if (fscanf (fp, "%lx-%lx", &start, &end) != 2)
  409:             break;
  410:           if (address >= start && address <= end - 1)
  411:             {
  412:               /* Found it.  Now see if this line contains a filename.  */
  413:               while (c = getc (fp), c != EOF && c != '\n' && c != '/')
  414:                 continue;
  415:               if (c == '/')
  416:                 {
  417:                   size_t size;
  418:                   int len;
  419: 
  420:                   ungetc (c, fp);
  421:                   shared_library_fullname = NULL; size = 0;
  422:                   len = getline (&shared_library_fullname, &size, fp);
  423:                   if (len >= 0)
  424:                     {
  425:                       /* Success: filled shared_library_fullname.  */
  426:                       if (len > 0 && shared_library_fullname[len - 1] == '\n')
  427:                         shared_library_fullname[len - 1] = '\0';
  428:                     }
  429:                 }
  430:               break;
  431:             }
  432:           while (c = getc (fp), c != EOF && c != '\n')
  433:             continue;
  434:         }
  435:       fclose (fp);
  436:     }
  437: #endif
  438: }
  439: 
  440: #endif /* Native Windows / EMX / Unix */
  441: 
  442: /* Return the full pathname of the current shared library.
  443:    Return NULL if unknown.
  444:    Guaranteed to work only on Linux, EMX, Cygwin, and native Windows.  */
  445: static char *
  446: get_shared_library_fullname ()
  447: {
  448: #if !(defined _WIN32 && !defined __CYGWIN__) && !defined __EMX__
  449:   static bool tried_find_shared_library_fullname;
  450:   if (!tried_find_shared_library_fullname)
  451:     {
  452:       find_shared_library_fullname ();
  453:       tried_find_shared_library_fullname = true;
  454:     }
  455: #endif
  456:   return shared_library_fullname;
  457: }
  458: 
  459: #endif /* PIC */
  460: 
  461: /* Returns the pathname, relocated according to the current installation
  462:    directory.
  463:    The returned string is either PATHNAME unmodified or a freshly allocated
  464:    string that you can free with free() after casting it to 'char *'.  */
  465: const char *
  466: relocate (const char *pathname)
  467: {
  468: #if defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE
  469:   static int initialized;
  470: 
  471:   /* Initialization code for a shared library.  */
  472:   if (!initialized)
  473:     {
  474:       /* At this point, orig_prefix and curr_prefix likely have already been
  475:          set through the main program's set_program_name_and_installdir
  476:          function.  This is sufficient in the case that the library has
  477:          initially been installed in the same orig_prefix.  But we can do
  478:          better, to also cover the cases that 1. it has been installed
  479:          in a different prefix before being moved to orig_prefix and (later)
  480:          to curr_prefix, 2. unlike the program, it has not moved away from
  481:          orig_prefix.  */
  482:       const char *orig_installprefix = INSTALLPREFIX;
  483:       const char *orig_installdir = INSTALLDIR;
  484:       char *curr_prefix_better;
  485: 
  486:       curr_prefix_better =
  487:         compute_curr_prefix (orig_installprefix, orig_installdir,
  488:                              get_shared_library_fullname ());
  489: 
  490:       set_relocation_prefix (orig_installprefix,
  491:                              curr_prefix_better != NULL
  492:                              ? curr_prefix_better
  493:                              : curr_prefix);
  494: 
  495:       if (curr_prefix_better != NULL)
  496:         free (curr_prefix_better);
  497: 
  498:       initialized = 1;
  499:     }
  500: #endif
  501: 
  502:   /* Note: It is not necessary to perform case insensitive comparison here,
  503:      even for DOS-like file systems, because the pathname argument was
  504:      typically created from the same Makefile variable as orig_prefix came
  505:      from.  */
  506:   if (orig_prefix != NULL && curr_prefix != NULL
  507:       && strncmp (pathname, orig_prefix, orig_prefix_len) == 0)
  508:     {
  509:       if (pathname[orig_prefix_len] == '\0')
  510:         {
  511:           /* pathname equals orig_prefix.  */
  512:           char *result = (char *) xmalloc (strlen (curr_prefix) + 1);
  513: 
  514: #ifdef NO_XMALLOC
  515:           if (result != NULL)
  516: #endif
  517:             {
  518:               strcpy (result, curr_prefix);
  519:               return result;
  520:             }
  521:         }
  522:       else if (ISSLASH (pathname[orig_prefix_len]))
  523:         {
  524:           /* pathname starts with orig_prefix.  */
  525:           const char *pathname_tail = &pathname[orig_prefix_len];
  526:           char *result =
  527:             (char *) xmalloc (curr_prefix_len + strlen (pathname_tail) + 1);
  528: 
  529: #ifdef NO_XMALLOC
  530:           if (result != NULL)
  531: #endif
  532:             {
  533:               memcpy (result, curr_prefix, curr_prefix_len);
  534:               strcpy (result + curr_prefix_len, pathname_tail);
  535:               return result;
  536:             }
  537:         }
  538:     }
  539: 
  540: #ifdef __EMX__
  541: # ifdef __KLIBC__
  542: #  undef strncmp
  543: 
  544:   if (strncmp (pathname, "/@unixroot", 10) == 0
  545:       && (pathname[10] == '\0' || ISSLASH (pathname[10])))
  546:     {
  547:       /* kLIBC itself processes /@unixroot prefix */
  548:       return pathname;
  549:     }
  550:   else
  551: # endif
  552:   if (ISSLASH (pathname[0]))
  553:     {
  554:       const char *unixroot = getenv ("UNIXROOT");
  555: 
  556:       if (unixroot && HAS_DEVICE (unixroot) && unixroot[2] == '\0')
  557:         {
  558:           char *result = (char *) xmalloc (2 + strlen (pathname) + 1);
  559: #ifdef NO_XMALLOC
  560:           if (result != NULL)
  561: #endif
  562:             {
  563:               memcpy (result, unixroot, 2);
  564:               strcpy (result + 2, pathname);
  565:               return result;
  566:             }
  567:         }
  568:     }
  569: #endif
  570: 
  571:   /* Nothing to relocate.  */
  572:   return pathname;
  573: }
  574: 
  575: /* Returns the pathname, relocated according to the current installation
  576:    directory.
  577:    This function sets *ALLOCATEDP to the allocated memory, or to NULL if
  578:    no memory allocation occurs.  So that, after you're done with the return
  579:    value, to reclaim allocated memory, you can do: free (*ALLOCATEDP).  */
  580: const char *
  581: relocate2 (const char *pathname, char **allocatedp)
  582: {
  583:   const char *result = relocate (pathname);
  584:   *allocatedp = (result != pathname ? (char *) result : NULL);
  585:   return result;
  586: }
  587: 
  588: #endif

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