Diff for /embedaddon/libiconv/srclib/progreloc.c between versions 1.1 and 1.1.1.3

version 1.1, 2012/02/21 22:57:48 version 1.1.1.3, 2021/03/17 13:38:46
Line 1 Line 1
 /* Provide relocatable programs.  /* Provide relocatable programs.
   Copyright (C) 2003-2009 Free Software Foundation, Inc.   Copyright (C) 2003-2019 Free Software Foundation, Inc.
    Written by Bruno Haible <bruno@clisp.org>, 2003.     Written by Bruno Haible <bruno@clisp.org>, 2003.
   
    This program is free software: you can redistribute it and/or modify     This program is free software: you can redistribute it and/or modify
Line 13 Line 13
    GNU General Public License for more details.     GNU General Public License for more details.
   
    You should have received a copy of the GNU General Public License     You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
   
   
   #define _GL_USE_STDLIB_ALLOC 1
 #include <config.h>  #include <config.h>
   
 /* Specification.  */  /* Specification.  */
 #include "progname.h"  #include "progname.h"
   
   #include <errno.h>
 #include <stdbool.h>  #include <stdbool.h>
 #include <stdio.h>  #include <stdio.h>
 #include <stdlib.h>  #include <stdlib.h>
Line 29 Line 31
 #include <unistd.h>  #include <unistd.h>
 #include <sys/stat.h>  #include <sys/stat.h>
   
/* Get declaration of _NSGetExecutablePath on MacOS X 10.2 or newer.  *//* Get declaration of _NSGetExecutablePath on Mac OS X 10.2 or newer.  */
 #if HAVE_MACH_O_DYLD_H  #if HAVE_MACH_O_DYLD_H
 # include <mach-o/dyld.h>  # include <mach-o/dyld.h>
 #endif  #endif
   
#if defined _WIN32 || defined __WIN32__#if defined _WIN32 && !defined __CYGWIN__
# define WIN32_NATIVE# define WINDOWS_NATIVE
 #endif  #endif
   
#if defined WIN32_NATIVE || defined __CYGWIN__#ifdef WINDOWS_NATIVE
 # define WIN32_LEAN_AND_MEAN  # define WIN32_LEAN_AND_MEAN
 # include <windows.h>  # include <windows.h>
 #endif  #endif
   
#include "canonicalize.h"#ifdef __EMX__
 # define INCL_DOS
 # include <os2.h>
 #endif
 
 #include "relocatable.h"  #include "relocatable.h"
   
 #ifdef NO_XMALLOC  #ifdef NO_XMALLOC
Line 60 Line 66
 # include "xalloc.h"  # include "xalloc.h"
 #endif  #endif
   
   #ifndef O_EXEC
   # define O_EXEC O_RDONLY /* This is often close enough in older systems.  */
   #endif
   
   /* Declare canonicalize_file_name.
      The <stdlib.h> included above may be the system's one, not the gnulib
      one.  */
   extern char * canonicalize_file_name (const char *name);
   
 /* Pathname support.  /* Pathname support.
    ISSLASH(C)           tests whether C is a directory separator character.     ISSLASH(C)           tests whether C is a directory separator character.
    IS_PATH_WITH_DIR(P)  tests whether P contains a directory specification.     IS_PATH_WITH_DIR(P)  tests whether P contains a directory specification.
  */   */
#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__#if (defined _WIN32 && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__
  /* Win32, Cygwin, OS/2, DOS */  /* Native Windows, OS/2, DOS */
 # define ISSLASH(C) ((C) == '/' || (C) == '\\')  # define ISSLASH(C) ((C) == '/' || (C) == '\\')
 # define HAS_DEVICE(P) \  # define HAS_DEVICE(P) \
     ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \      ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
Line 80 Line 95
 # define FILE_SYSTEM_PREFIX_LEN(P) 0  # define FILE_SYSTEM_PREFIX_LEN(P) 0
 #endif  #endif
   
/* The results of open() in this file are not used with fchdir,/* Use the system functions, not the gnulib overrides in this file.  */
   therefore save some unnecessary work in fchdir.c.  */#undef sprintf
#undef open 
#undef close 
   
 #undef set_program_name  #undef set_program_name
   
   
 #if ENABLE_RELOCATABLE  #if ENABLE_RELOCATABLE
   
#ifdef __linux__#ifdef __sun
 
 /* Helper function, from gnulib module 'safe-read'.  */
 static size_t
 safe_read (int fd, void *buf, size_t count)
 {
   for (;;)
     {
       ssize_t result = read (fd, buf, count);
 
       if (0 <= result || errno != EINTR)
         return result;
     }
 }
 
 /* Helper function, from gnulib module 'full-read'.  */
 static size_t
 full_read (int fd, void *buf, size_t count)
 {
   size_t total = 0;
   const char *ptr = (const char *) buf;
 
   while (count > 0)
     {
       size_t n = safe_read (fd, ptr, count);
       if (n == (size_t) -1)
         break;
       if (n == 0)
         {
           errno = 0;
           break;
         }
       total += n;
       ptr += n;
       count -= n;
     }
 
   return total;
 }
 
 #endif
 
 #if defined __linux__ || defined __CYGWIN__
 /* File descriptor of the executable.  /* File descriptor of the executable.
    (Only used to verify that we find the correct executable.)  */     (Only used to verify that we find the correct executable.)  */
 static int executable_fd = -1;  static int executable_fd = -1;
Line 100  static int executable_fd = -1; Line 155  static int executable_fd = -1;
 static bool  static bool
 maybe_executable (const char *filename)  maybe_executable (const char *filename)
 {  {
  /* Woe32 lacks the access() function, but Cygwin doesn't.  */  /* The native Windows API lacks the access() function.  */
#if !(defined WIN32_NATIVE && !defined __CYGWIN__)#if !defined WINDOWS_NATIVE
   if (access (filename, X_OK) < 0)    if (access (filename, X_OK) < 0)
     return false;      return false;
   #endif
   
#ifdef __linux__#if defined __linux__ || defined __CYGWIN__
   if (executable_fd >= 0)    if (executable_fd >= 0)
     {      {
       /* If we already have an executable_fd, check that filename points to        /* If we already have an executable_fd, check that filename points to
         the same inode.  */         the same inode.  */
       struct stat statexe;        struct stat statexe;
       struct stat statfile;        struct stat statfile;
   
       if (fstat (executable_fd, &statexe) >= 0)        if (fstat (executable_fd, &statexe) >= 0)
        {        {
          if (stat (filename, &statfile) < 0)          if (stat (filename, &statfile) < 0)
            return false;            return false;
          if (!(statfile.st_dev          if (!(statfile.st_dev
                && statfile.st_dev == statexe.st_dev                && statfile.st_dev == statexe.st_dev
                && statfile.st_ino == statexe.st_ino))                && statfile.st_ino == statexe.st_ino))
            return false;            return false;
        }        }
     }      }
 #endif  #endif
 #endif  
   
   return true;    return true;
 }  }
   
 /* Determine the full pathname of the current executable, freshly allocated.  /* Determine the full pathname of the current executable, freshly allocated.
    Return NULL if unknown.     Return NULL if unknown.
   Guaranteed to work on Linux and Woe32.  Likely to work on the other   Guaranteed to work on Linux and native Windows.  Likely to work on the
   Unixes (maybe except BeOS), under most conditions.  */   other Unixes (maybe except BeOS), under most conditions.  */
 static char *  static char *
 find_executable (const char *argv0)  find_executable (const char *argv0)
 {  {
#if defined WIN32_NATIVE || defined __CYGWIN__#if defined WINDOWS_NATIVE
   /* Native Windows only.
      On Cygwin, it is better to use the Cygwin provided /proc interface, than
      to use native Windows API and cygwin_conv_to_posix_path, because it
      supports longer file names
      (see <https://cygwin.com/ml/cygwin/2011-01/msg00410.html>).  */
   char location[MAX_PATH];    char location[MAX_PATH];
   int length = GetModuleFileName (NULL, location, sizeof (location));    int length = GetModuleFileName (NULL, location, sizeof (location));
   if (length < 0)    if (length < 0)
Line 144  find_executable (const char *argv0) Line 204  find_executable (const char *argv0)
   if (!IS_PATH_WITH_DIR (location))    if (!IS_PATH_WITH_DIR (location))
     /* Shouldn't happen.  */      /* Shouldn't happen.  */
     return NULL;      return NULL;
  {  return xstrdup (location);
#if defined __CYGWIN__#elif defined __EMX__
    /* cygwin-1.5.13 (2005-03-01) or newer would also allow a Linux-like  PPIB ppib;
       implementation: readlink of "/proc/self/exe".  But using the  char location[CCHMAXPATH];
       result of the Win32 system call is simpler and is consistent with the
       code in relocatable.c.  */  /* See http://cyberkinetica.homeunix.net/os2tk45/cp1/619_L2H_DosGetInfoBlocksSynt.html
    /* On Cygwin, we need to convert paths coming from Win32 system calls     for specification of DosGetInfoBlocks().  */
       to the Unix-like slashified notation.  */  if (DosGetInfoBlocks (NULL, &ppib))
    static char location_as_posix_path[2 * MAX_PATH];    return NULL;
    /* There's no error return defined for cygwin_conv_to_posix_path.
       See cygwin-api/func-cygwin-conv-to-posix-path.html.  /* See http://cyberkinetica.homeunix.net/os2tk45/cp1/1247_L2H_DosQueryModuleNameSy.html
       Does it overflow the buffer of expected size MAX_PATH or does it     for specification of DosQueryModuleName().  */
       truncate the path?  I don't know.  Let's catch both.  */  if (DosQueryModuleName (ppib->pib_hmte, sizeof (location), location))
    cygwin_conv_to_posix_path (location, location_as_posix_path);    return NULL;
    location_as_posix_path[MAX_PATH - 1] = '\0';
    if (strlen (location_as_posix_path) >= MAX_PATH - 1)  _fnslashify (location);
      /* A sign of buffer overflow or path truncation.  */
      return NULL;  return xstrdup (location);
    /* Call canonicalize_file_name, because Cygwin supports symbolic links.  */#else /* Unix */
    return canonicalize_file_name (location_as_posix_path);# if defined __linux__
#else 
    return xstrdup (location); 
#endif 
  } 
#else /* Unix && !Cygwin */ 
#ifdef __linux__ 
   /* The executable is accessible as /proc/<pid>/exe.  In newer Linux    /* The executable is accessible as /proc/<pid>/exe.  In newer Linux
      versions, also as /proc/self/exe.  Linux >= 2.1 provides a symlink       versions, also as /proc/self/exe.  Linux >= 2.1 provides a symlink
      to the true pathname; older Linux versions give only device and ino,       to the true pathname; older Linux versions give only device and ino,
Line 181  find_executable (const char *argv0) Line 235  find_executable (const char *argv0)
     if (link != NULL && link[0] != '[')      if (link != NULL && link[0] != '[')
       return link;        return link;
     if (executable_fd < 0)      if (executable_fd < 0)
      executable_fd = open ("/proc/self/exe", O_RDONLY, 0);      executable_fd = open ("/proc/self/exe", O_EXEC, 0);
   
     {      {
       char buf[6+10+5];        char buf[6+10+5];
       sprintf (buf, "/proc/%d/exe", getpid ());        sprintf (buf, "/proc/%d/exe", getpid ());
       link = xreadlink (buf);        link = xreadlink (buf);
       if (link != NULL && link[0] != '[')        if (link != NULL && link[0] != '[')
        return link;        return link;
       if (executable_fd < 0)        if (executable_fd < 0)
        executable_fd = open (buf, O_RDONLY, 0);        executable_fd = open (buf, O_EXEC, 0);
     }      }
   }    }
#endif# endif
#if HAVE_MACH_O_DYLD_H && HAVE__NSGETEXECUTABLEPATHif defined __ANDROID__ || defined __FreeBSD_kernel__
  /* On MacOS X 10.2 or newer, the function  /* On Android and GNU/kFreeBSD, the executable is accessible as
      /proc/<pid>/exe and /proc/self/exe.  */
   {
     char *link;
 
     link = xreadlink ("/proc/self/exe");
     if (link != NULL)
       return link;
   }
 # endif
 # if defined __FreeBSD__ || defined __DragonFly__
   /* In FreeBSD >= 5.0, the executable is accessible as /proc/<pid>/file and
      /proc/curproc/file.  */
   {
     char *link;
 
     link = xreadlink ("/proc/curproc/file");
     if (link != NULL)
       {
         if (strcmp (link, "unknown") != 0)
           return link;
         free (link);
       }
   }
 # endif
 # if defined __NetBSD__
   /* In NetBSD >= 4.0, the executable is accessible as /proc/<pid>/exe and
      /proc/curproc/exe.  */
   {
     char *link;
 
     link = xreadlink ("/proc/curproc/exe");
     if (link != NULL)
       return link;
   }
 # endif
 # if defined __sun
   /* On Solaris >= 11.4, /proc/<pid>/execname and /proc/self/execname contains
      the name of the executable, either as an absolute file name or relative to
      the current directory.  */
   {
     char namebuf[4096];
     int fd = open ("/proc/self/execname", O_RDONLY, 0);
     if (fd >= 0)
       {
         size_t len = full_read (fd, namebuf, sizeof (namebuf));
         close (fd);
         if (len > 0 && len < sizeof (namebuf))
           {
             namebuf[len] = '\0';
             return canonicalize_file_name (namebuf);
           }
       }
   }
 # endif
 # if defined __CYGWIN__
   /* The executable is accessible as /proc/<pid>/exe, at least in
      Cygwin >= 1.5.  */
   {
     char *link;
 
     link = xreadlink ("/proc/self/exe");
     if (link != NULL)
       return link;
     if (executable_fd < 0)
       executable_fd = open ("/proc/self/exe", O_EXEC, 0);
   }
 # endif
 # if HAVE_MACH_O_DYLD_H && HAVE__NSGETEXECUTABLEPATH
   /* On Mac OS X 10.2 or newer, the function
        int _NSGetExecutablePath (char *buf, uint32_t *bufsize);         int _NSGetExecutablePath (char *buf, uint32_t *bufsize);
      can be used to retrieve the executable's full path.  */       can be used to retrieve the executable's full path.  */
   char location[4096];    char location[4096];
Line 203  find_executable (const char *argv0) Line 326  find_executable (const char *argv0)
   if (_NSGetExecutablePath (location, &length) == 0    if (_NSGetExecutablePath (location, &length) == 0
       && location[0] == '/')        && location[0] == '/')
     return canonicalize_file_name (location);      return canonicalize_file_name (location);
#endif# endif
   /* Guess the executable's full path.  We assume the executable has been    /* Guess the executable's full path.  We assume the executable has been
      called via execlp() or execvp() with properly set up argv[0].  The       called via execlp() or execvp() with properly set up argv[0].  The
      login(1) convention to add a '-' prefix to argv[0] is not supported.  */       login(1) convention to add a '-' prefix to argv[0] is not supported.  */
Line 212  find_executable (const char *argv0) Line 335  find_executable (const char *argv0)
     {      {
       const char *p;        const char *p;
       for (p = argv0; *p; p++)        for (p = argv0; *p; p++)
        if (*p == '/')        if (*p == '/')
          {          {
            has_slash = true;            has_slash = true;
            break;            break;
          }          }
     }      }
     if (!has_slash)      if (!has_slash)
       {        {
        /* exec searches paths without slashes in the directory list given        /* exec searches paths without slashes in the directory list given
           by $PATH.  */           by $PATH.  */
        const char *path = getenv ("PATH");        const char *path = getenv ("PATH");
   
        if (path != NULL)        if (path != NULL)
          {          {
            const char *p;            const char *p;
            const char *p_next;            const char *p_next;
   
            for (p = path; *p; p = p_next)            for (p = path; *p; p = p_next)
              {              {
                const char *q;                const char *q;
                size_t p_len;                size_t p_len;
                char *concat_name;                char *concat_name;
   
                for (q = p; *q; q++)                for (q = p; *q; q++)
                  if (*q == ':')                  if (*q == ':')
                    break;                    break;
                p_len = q - p;                p_len = q - p;
                p_next = (*q == '\0' ? q : q + 1);                p_next = (*q == '\0' ? q : q + 1);
   
                /* We have a path item at p, of length p_len.                /* We have a path item at p, of length p_len.
                   Now concatenate the path item and argv0.  */                   Now concatenate the path item and argv0.  */
                concat_name = (char *) xmalloc (p_len + strlen (argv0) + 2);                concat_name = (char *) xmalloc (p_len + strlen (argv0) + 2);
#ifdef NO_XMALLOCifdef NO_XMALLOC
                if (concat_name == NULL)                if (concat_name == NULL)
                  return NULL;                  return NULL;
#endifendif
                if (p_len == 0)                if (p_len == 0)
                  /* An empty PATH element designates the current directory.  */                  /* An empty PATH element designates the current directory.  */
                  strcpy (concat_name, argv0);                  strcpy (concat_name, argv0);
                else                else
                  {                  {
                    memcpy (concat_name, p, p_len);                    memcpy (concat_name, p, p_len);
                    concat_name[p_len] = '/';                    concat_name[p_len] = '/';
                    strcpy (concat_name + p_len + 1, argv0);                    strcpy (concat_name + p_len + 1, argv0);
                  }                  }
                if (maybe_executable (concat_name))                if (maybe_executable (concat_name))
                  return canonicalize_file_name (concat_name);                  return canonicalize_file_name (concat_name);
                free (concat_name);                free (concat_name);
              }              }
          }          }
        /* Not found in the PATH, assume the current directory.  */        /* Not found in the PATH, assume the current directory.  */
       }        }
     /* exec treats paths containing slashes as relative to the current      /* exec treats paths containing slashes as relative to the current
        directory.  */         directory.  */
Line 279  static char *executable_fullname; Line 402  static char *executable_fullname;
   
 static void  static void
 prepare_relocate (const char *orig_installprefix, const char *orig_installdir,  prepare_relocate (const char *orig_installprefix, const char *orig_installdir,
                  const char *argv0)                  const char *argv0)
 {  {
   char *curr_prefix;    char *curr_prefix;
   
Line 288  prepare_relocate (const char *orig_installprefix, cons Line 411  prepare_relocate (const char *orig_installprefix, cons
   
   /* Determine the current installation prefix from it.  */    /* Determine the current installation prefix from it.  */
   curr_prefix = compute_curr_prefix (orig_installprefix, orig_installdir,    curr_prefix = compute_curr_prefix (orig_installprefix, orig_installdir,
                                     executable_fullname);                                     executable_fullname);
   if (curr_prefix != NULL)    if (curr_prefix != NULL)
     {      {
       /* Now pass this prefix to all copies of the relocate.c source file.  */        /* Now pass this prefix to all copies of the relocate.c source file.  */
Line 302  prepare_relocate (const char *orig_installprefix, cons Line 425  prepare_relocate (const char *orig_installprefix, cons
    directory, for relocatability.  */     directory, for relocatability.  */
 void  void
 set_program_name_and_installdir (const char *argv0,  set_program_name_and_installdir (const char *argv0,
                                 const char *orig_installprefix,                                 const char *orig_installprefix,
                                 const char *orig_installdir)                                 const char *orig_installdir)
 {  {
   const char *argv0_stripped = argv0;    const char *argv0_stripped = argv0;
   
Line 315  set_program_name_and_installdir (const char *argv0, Line 438  set_program_name_and_installdir (const char *argv0,
     const size_t exeext_len = sizeof (EXEEXT) - sizeof ("");      const size_t exeext_len = sizeof (EXEEXT) - sizeof ("");
     if (argv0_len > 4 + exeext_len)      if (argv0_len > 4 + exeext_len)
       if (memcmp (argv0 + argv0_len - exeext_len - 4, ".bin", 4) == 0)        if (memcmp (argv0 + argv0_len - exeext_len - 4, ".bin", 4) == 0)
        {        {
          if (sizeof (EXEEXT) > sizeof (""))          if (sizeof (EXEEXT) > sizeof (""))
            {            {
              /* Compare using an inlined copy of c_strncasecmp(), because              /* Compare using an inlined copy of c_strncasecmp(), because
                 the filenames may have undergone a case conversion since                 the filenames may have undergone a case conversion since
                 they were packaged.  In other words, EXEEXT may be ".exe"                 they were packaged.  In other words, EXEEXT may be ".exe"
                 on one system and ".EXE" on another.  */                 on one system and ".EXE" on another.  */
              static const char exeext[] = EXEEXT;              static const char exeext[] = EXEEXT;
              const char *s1 = argv0 + argv0_len - exeext_len;              const char *s1 = argv0 + argv0_len - exeext_len;
              const char *s2 = exeext;              const char *s2 = exeext;
              for (; *s1 != '\0'; s1++, s2++)              for (; *s1 != '\0'; s1++, s2++)
                {                {
                  unsigned char c1 = *s1;                  unsigned char c1 = *s1;
                  unsigned char c2 = *s2;                  unsigned char c2 = *s2;
                  if ((c1 >= 'A' && c1 <= 'Z' ? c1 - 'A' + 'a' : c1)                  if ((c1 >= 'A' && c1 <= 'Z' ? c1 - 'A' + 'a' : c1)
                      != (c2 >= 'A' && c2 <= 'Z' ? c2 - 'A' + 'a' : c2))                      != (c2 >= 'A' && c2 <= 'Z' ? c2 - 'A' + 'a' : c2))
                    goto done_stripping;                    goto done_stripping;
                }                }
            }            }
          /* Remove ".bin" before EXEEXT or its equivalent.  */          /* Remove ".bin" before EXEEXT or its equivalent.  */
          {          {
            char *shorter = (char *) xmalloc (argv0_len - 4 + 1);            char *shorter = (char *) xmalloc (argv0_len - 4 + 1);
 #ifdef NO_XMALLOC  #ifdef NO_XMALLOC
            if (shorter != NULL)            if (shorter != NULL)
 #endif  #endif
              {              {
                memcpy (shorter, argv0, argv0_len - exeext_len - 4);                memcpy (shorter, argv0, argv0_len - exeext_len - 4);
                if (sizeof (EXEEXT) > sizeof (""))                if (sizeof (EXEEXT) > sizeof (""))
                  memcpy (shorter + argv0_len - exeext_len - 4,                  memcpy (shorter + argv0_len - exeext_len - 4,
                          argv0 + argv0_len - exeext_len - 4,                          argv0 + argv0_len - exeext_len - 4,
                          exeext_len);                          exeext_len);
                shorter[argv0_len - 4] = '\0';                shorter[argv0_len - 4] = '\0';
                argv0_stripped = shorter;                argv0_stripped = shorter;
              }              }
          }          }
         done_stripping: ;         done_stripping: ;
       }        }
   }    }
   

Removed from v.1.1  
changed lines
  Added in v.1.1.1.3


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