(root)/
bison-3.8.2/
lib/
progreloc.c
       1  /* Provide relocatable programs.
       2     Copyright (C) 2003-2021 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  #define _GL_USE_STDLIB_ALLOC 1
      20  #include <config.h>
      21  
      22  /* Specification.  */
      23  #include "progname.h"
      24  
      25  #include <errno.h>
      26  #include <stdbool.h>
      27  #include <stdio.h>
      28  #include <stdlib.h>
      29  #include <string.h>
      30  #include <fcntl.h>
      31  #include <unistd.h>
      32  #include <sys/stat.h>
      33  
      34  /* Get declaration of _NSGetExecutablePath on Mac OS X 10.2 or newer.  */
      35  #if HAVE_MACH_O_DYLD_H
      36  # include <mach-o/dyld.h>
      37  #endif
      38  
      39  #if defined _WIN32 && !defined __CYGWIN__
      40  # define WINDOWS_NATIVE
      41  #endif
      42  
      43  #ifdef WINDOWS_NATIVE
      44  # define WIN32_LEAN_AND_MEAN
      45  # include <windows.h>
      46  #endif
      47  
      48  #ifdef __EMX__
      49  # define INCL_DOS
      50  # include <os2.h>
      51  #endif
      52  
      53  #include "relocatable.h"
      54  
      55  #ifdef NO_XMALLOC
      56  # include "areadlink.h"
      57  # define xreadlink areadlink
      58  #else
      59  # include "xreadlink.h"
      60  #endif
      61  
      62  #ifdef NO_XMALLOC
      63  # define xmalloc malloc
      64  # define xstrdup strdup
      65  #else
      66  # include "xalloc.h"
      67  #endif
      68  
      69  #ifndef O_EXEC
      70  # define O_EXEC O_RDONLY /* This is often close enough in older systems.  */
      71  #endif
      72  
      73  #if defined IN_RELOCWRAPPER && (!defined O_CLOEXEC || GNULIB_defined_O_CLOEXEC)
      74  # undef O_CLOEXEC
      75  # define O_CLOEXEC 0
      76  #endif
      77  
      78  /* Declare canonicalize_file_name.
      79     The <stdlib.h> included above may be the system's one, not the gnulib
      80     one.  */
      81  extern char * canonicalize_file_name (const char *name);
      82  
      83  #if defined WINDOWS_NATIVE
      84  /* Don't assume that UNICODE is not defined.  */
      85  # undef GetModuleFileName
      86  # define GetModuleFileName GetModuleFileNameA
      87  #endif
      88  
      89  /* Pathname support.
      90     ISSLASH(C)                tests whether C is a directory separator character.
      91     IS_FILE_NAME_WITH_DIR(P)  tests whether P contains a directory specification.
      92   */
      93  #if (defined _WIN32 && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__
      94    /* Native Windows, OS/2, DOS */
      95  # define ISSLASH(C) ((C) == '/' || (C) == '\\')
      96  # define HAS_DEVICE(P) \
      97      ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
      98       && (P)[1] == ':')
      99  # define IS_FILE_NAME_WITH_DIR(P) \
     100      (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
     101  # define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
     102  #else
     103    /* Unix */
     104  # define ISSLASH(C) ((C) == '/')
     105  # define IS_FILE_NAME_WITH_DIR(P) (strchr (P, '/') != NULL)
     106  # define FILE_SYSTEM_PREFIX_LEN(P) 0
     107  #endif
     108  
     109  /* Use the system functions, not the gnulib overrides in this file.  */
     110  #undef sprintf
     111  
     112  #undef set_program_name
     113  
     114  
     115  #if ENABLE_RELOCATABLE
     116  
     117  #ifdef __sun
     118  
     119  /* Helper function, from gnulib module 'safe-read'.  */
     120  static size_t
     121  safe_read (int fd, void *buf, size_t count)
     122  {
     123    for (;;)
     124      {
     125        ssize_t result = read (fd, buf, count);
     126  
     127        if (0 <= result || errno != EINTR)
     128          return result;
     129      }
     130  }
     131  
     132  /* Helper function, from gnulib module 'full-read'.  */
     133  static size_t
     134  full_read (int fd, void *buf, size_t count)
     135  {
     136    size_t total = 0;
     137    const char *ptr = (const char *) buf;
     138  
     139    while (count > 0)
     140      {
     141        size_t n = safe_read (fd, ptr, count);
     142        if (n == (size_t) -1)
     143          break;
     144        if (n == 0)
     145          {
     146            errno = 0;
     147            break;
     148          }
     149        total += n;
     150        ptr += n;
     151        count -= n;
     152      }
     153  
     154    return total;
     155  }
     156  
     157  #endif
     158  
     159  #if defined __linux__ || defined __CYGWIN__
     160  /* File descriptor of the executable.
     161     (Only used to verify that we find the correct executable.)  */
     162  static int executable_fd = -1;
     163  #endif
     164  
     165  /* Define this function only when it's needed.  */
     166  #if !(defined WINDOWS_NATIVE || defined __EMX__)
     167  
     168  /* Tests whether a given filename may belong to the executable.  */
     169  static bool
     170  maybe_executable (const char *filename)
     171  {
     172    /* The native Windows API lacks the access() function.  */
     173  # if !defined WINDOWS_NATIVE
     174    if (access (filename, X_OK) < 0)
     175      return false;
     176  # endif
     177  
     178  # if defined __linux__ || defined __CYGWIN__
     179    if (executable_fd >= 0)
     180      {
     181        /* If we already have an executable_fd, check that filename points to
     182           the same inode.  */
     183        struct stat statexe;
     184        struct stat statfile;
     185  
     186        if (fstat (executable_fd, &statexe) >= 0)
     187          return (stat (filename, &statfile) >= 0
     188                  && statfile.st_dev
     189                  && statfile.st_dev == statexe.st_dev
     190                  && statfile.st_ino == statexe.st_ino);
     191      }
     192  # endif
     193  
     194    /* Check that the filename does not point to a directory.  */
     195    {
     196      struct stat statfile;
     197  
     198      return (stat (filename, &statfile) >= 0
     199              && ! S_ISDIR (statfile.st_mode));
     200    }
     201  }
     202  
     203  #endif
     204  
     205  /* Determine the full pathname of the current executable, freshly allocated.
     206     Return NULL if unknown.
     207     Guaranteed to work on Linux and native Windows.  Likely to work on the
     208     other Unixes (maybe except BeOS), under most conditions.  */
     209  static char *
     210  find_executable (const char *argv0)
     211  {
     212  #if defined WINDOWS_NATIVE
     213    /* Native Windows only.
     214       On Cygwin, it is better to use the Cygwin provided /proc interface, than
     215       to use native Windows API and cygwin_conv_to_posix_path, because it
     216       supports longer file names
     217       (see <https://cygwin.com/ml/cygwin/2011-01/msg00410.html>).  */
     218    char location[MAX_PATH];
     219    int length = GetModuleFileName (NULL, location, sizeof (location));
     220    if (length < 0)
     221      return NULL;
     222    if (!IS_FILE_NAME_WITH_DIR (location))
     223      /* Shouldn't happen.  */
     224      return NULL;
     225    return xstrdup (location);
     226  #elif defined __EMX__
     227    PPIB ppib;
     228    char location[CCHMAXPATH];
     229  
     230    /* See http://cyberkinetica.homeunix.net/os2tk45/cp1/619_L2H_DosGetInfoBlocksSynt.html
     231       for specification of DosGetInfoBlocks().  */
     232    if (DosGetInfoBlocks (NULL, &ppib))
     233      return NULL;
     234  
     235    /* See http://cyberkinetica.homeunix.net/os2tk45/cp1/1247_L2H_DosQueryModuleNameSy.html
     236       for specification of DosQueryModuleName().  */
     237    if (DosQueryModuleName (ppib->pib_hmte, sizeof (location), location))
     238      return NULL;
     239  
     240    _fnslashify (location);
     241  
     242    return xstrdup (location);
     243  #else /* Unix */
     244  # if defined __linux__
     245    /* The executable is accessible as /proc/<pid>/exe.  In newer Linux
     246       versions, also as /proc/self/exe.  Linux >= 2.1 provides a symlink
     247       to the true pathname; older Linux versions give only device and ino,
     248       enclosed in brackets, which we cannot use here.  */
     249    {
     250      char *link;
     251  
     252      link = xreadlink ("/proc/self/exe");
     253      if (link != NULL && link[0] != '[')
     254        return link;
     255      if (executable_fd < 0)
     256        executable_fd = open ("/proc/self/exe", O_EXEC | O_CLOEXEC, 0);
     257  
     258      {
     259        char buf[6+10+5];
     260        sprintf (buf, "/proc/%d/exe", getpid ());
     261        link = xreadlink (buf);
     262        if (link != NULL && link[0] != '[')
     263          return link;
     264        if (executable_fd < 0)
     265          executable_fd = open (buf, O_EXEC | O_CLOEXEC, 0);
     266      }
     267    }
     268  # endif
     269  # if defined __ANDROID__ || defined __FreeBSD_kernel__
     270    /* On Android and GNU/kFreeBSD, the executable is accessible as
     271       /proc/<pid>/exe and /proc/self/exe.  */
     272    {
     273      char *link;
     274  
     275      link = xreadlink ("/proc/self/exe");
     276      if (link != NULL)
     277        return link;
     278    }
     279  # endif
     280  # if defined __FreeBSD__ || defined __DragonFly__
     281    /* In FreeBSD >= 5.0, the executable is accessible as /proc/<pid>/file and
     282       /proc/curproc/file.  */
     283    {
     284      char *link;
     285  
     286      link = xreadlink ("/proc/curproc/file");
     287      if (link != NULL)
     288        {
     289          if (strcmp (link, "unknown") != 0)
     290            return link;
     291          free (link);
     292        }
     293    }
     294  # endif
     295  # if defined __NetBSD__
     296    /* In NetBSD >= 4.0, the executable is accessible as /proc/<pid>/exe and
     297       /proc/curproc/exe.  */
     298    {
     299      char *link;
     300  
     301      link = xreadlink ("/proc/curproc/exe");
     302      if (link != NULL)
     303        return link;
     304    }
     305  # endif
     306  # if defined __sun
     307    /* On Solaris >= 11.4, /proc/<pid>/execname and /proc/self/execname contains
     308       the name of the executable, either as an absolute file name or relative to
     309       the current directory.  */
     310    {
     311      char namebuf[4096];
     312      int fd = open ("/proc/self/execname", O_RDONLY | O_CLOEXEC, 0);
     313      if (fd >= 0)
     314        {
     315          size_t len = full_read (fd, namebuf, sizeof (namebuf));
     316          close (fd);
     317          if (len > 0 && len < sizeof (namebuf))
     318            {
     319              namebuf[len] = '\0';
     320              return canonicalize_file_name (namebuf);
     321            }
     322        }
     323    }
     324  # endif
     325  # if defined __CYGWIN__
     326    /* The executable is accessible as /proc/<pid>/exe, at least in
     327       Cygwin >= 1.5.  */
     328    {
     329      char *link;
     330  
     331      link = xreadlink ("/proc/self/exe");
     332      if (link != NULL)
     333        return link;
     334      if (executable_fd < 0)
     335        executable_fd = open ("/proc/self/exe", O_EXEC | O_CLOEXEC, 0);
     336    }
     337  # endif
     338  # if HAVE_MACH_O_DYLD_H && HAVE__NSGETEXECUTABLEPATH
     339    /* On Mac OS X 10.2 or newer, the function
     340         int _NSGetExecutablePath (char *buf, uint32_t *bufsize);
     341       can be used to retrieve the executable's full path.  */
     342    char location[4096];
     343    unsigned int length = sizeof (location);
     344    if (_NSGetExecutablePath (location, &length) == 0
     345        && location[0] == '/')
     346      return canonicalize_file_name (location);
     347  # endif
     348    /* Guess the executable's full path.  We assume the executable has been
     349       called via execlp() or execvp() with properly set up argv[0].  The
     350       login(1) convention to add a '-' prefix to argv[0] is not supported.  */
     351    {
     352      bool has_slash = false;
     353      {
     354        const char *p;
     355        for (p = argv0; *p; p++)
     356          if (*p == '/')
     357            {
     358              has_slash = true;
     359              break;
     360            }
     361      }
     362      if (!has_slash)
     363        {
     364          /* exec searches paths without slashes in the directory list given
     365             by $PATH.  */
     366          const char *path = getenv ("PATH");
     367  
     368          if (path != NULL)
     369            {
     370              const char *p;
     371              const char *p_next;
     372  
     373              for (p = path; *p; p = p_next)
     374                {
     375                  const char *q;
     376                  size_t p_len;
     377                  char *concat_name;
     378  
     379                  for (q = p; *q; q++)
     380                    if (*q == ':')
     381                      break;
     382                  p_len = q - p;
     383                  p_next = (*q == '\0' ? q : q + 1);
     384  
     385                  /* We have a path item at p, of length p_len.
     386                     Now concatenate the path item and argv0.  */
     387                  concat_name = (char *) xmalloc (p_len + strlen (argv0) + 2);
     388  # ifdef NO_XMALLOC
     389                  if (concat_name == NULL)
     390                    return NULL;
     391  # endif
     392                  if (p_len == 0)
     393                    /* An empty PATH element designates the current directory.  */
     394                    strcpy (concat_name, argv0);
     395                  else
     396                    {
     397                      memcpy (concat_name, p, p_len);
     398                      concat_name[p_len] = '/';
     399                      strcpy (concat_name + p_len + 1, argv0);
     400                    }
     401                  if (maybe_executable (concat_name))
     402                    return canonicalize_file_name (concat_name);
     403                  free (concat_name);
     404                }
     405            }
     406          /* Not found in the PATH, assume the current directory.  */
     407        }
     408      /* exec treats paths containing slashes as relative to the current
     409         directory.  */
     410      if (maybe_executable (argv0))
     411        return canonicalize_file_name (argv0);
     412    }
     413    /* No way to find the executable.  */
     414    return NULL;
     415  #endif
     416  }
     417  
     418  /* Full pathname of executable, or NULL.  */
     419  static char *executable_fullname;
     420  
     421  static void
     422  prepare_relocate (const char *orig_installprefix, const char *orig_installdir,
     423                    const char *argv0)
     424  {
     425    char *curr_prefix;
     426  
     427    /* Determine the full pathname of the current executable.  */
     428    executable_fullname = find_executable (argv0);
     429  
     430    /* Determine the current installation prefix from it.  */
     431    curr_prefix = compute_curr_prefix (orig_installprefix, orig_installdir,
     432                                       executable_fullname);
     433    if (curr_prefix != NULL)
     434      {
     435        /* Now pass this prefix to all copies of the relocate.c source file.  */
     436        set_relocation_prefix (orig_installprefix, curr_prefix);
     437  
     438        free (curr_prefix);
     439      }
     440  }
     441  
     442  /* Set program_name, based on argv[0], and original installation prefix and
     443     directory, for relocatability.  */
     444  void
     445  set_program_name_and_installdir (const char *argv0,
     446                                   const char *orig_installprefix,
     447                                   const char *orig_installdir)
     448  {
     449    const char *argv0_stripped = argv0;
     450  
     451    /* Relocatable programs are renamed to .bin by install-reloc.  Or, more
     452       generally, their suffix is changed from $exeext to .bin$exeext.
     453       Remove the ".bin" here.  */
     454    {
     455      size_t argv0_len = strlen (argv0);
     456      const size_t exeext_len = sizeof (EXEEXT) - sizeof ("");
     457      if (argv0_len > 4 + exeext_len)
     458        if (memcmp (argv0 + argv0_len - exeext_len - 4, ".bin", 4) == 0)
     459          {
     460            if (sizeof (EXEEXT) > sizeof (""))
     461              {
     462                /* Compare using an inlined copy of c_strncasecmp(), because
     463                   the filenames may have undergone a case conversion since
     464                   they were packaged.  In other words, EXEEXT may be ".exe"
     465                   on one system and ".EXE" on another.  */
     466                static const char exeext[] = EXEEXT;
     467                const char *s1 = argv0 + argv0_len - exeext_len;
     468                const char *s2 = exeext;
     469                for (; *s1 != '\0'; s1++, s2++)
     470                  {
     471                    unsigned char c1 = *s1;
     472                    unsigned char c2 = *s2;
     473                    if ((c1 >= 'A' && c1 <= 'Z' ? c1 - 'A' + 'a' : c1)
     474                        != (c2 >= 'A' && c2 <= 'Z' ? c2 - 'A' + 'a' : c2))
     475                      goto done_stripping;
     476                  }
     477              }
     478            /* Remove ".bin" before EXEEXT or its equivalent.  */
     479            {
     480              char *shorter = (char *) xmalloc (argv0_len - 4 + 1);
     481  #ifdef NO_XMALLOC
     482              if (shorter != NULL)
     483  #endif
     484                {
     485                  memcpy (shorter, argv0, argv0_len - exeext_len - 4);
     486                  if (sizeof (EXEEXT) > sizeof (""))
     487                    memcpy (shorter + argv0_len - exeext_len - 4,
     488                            argv0 + argv0_len - exeext_len - 4,
     489                            exeext_len);
     490                  shorter[argv0_len - 4] = '\0';
     491                  argv0_stripped = shorter;
     492                }
     493            }
     494           done_stripping: ;
     495        }
     496    }
     497  
     498    set_program_name (argv0_stripped);
     499  
     500    prepare_relocate (orig_installprefix, orig_installdir, argv0);
     501  }
     502  
     503  /* Return the full pathname of the current executable, based on the earlier
     504     call to set_program_name_and_installdir.  Return NULL if unknown.  */
     505  char *
     506  get_full_program_name (void)
     507  {
     508    return executable_fullname;
     509  }
     510  
     511  #endif