(root)/
bison-3.8.2/
lib/
relocwrapper.c
       1  /* Relocating wrapper program.
       2     Copyright (C) 2003, 2005-2007, 2009-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  /* Dependencies:
      19     relocwrapper
      20      -> progname
      21      -> progreloc
      22         -> stat
      23            -> filename
      24            -> pathmax
      25            -> verify
      26         -> areadlink
      27            -> careadlinkat
      28               -> allocator
      29            -> readlink
      30               -> stat
      31         -> canonicalize-lgpl
      32            -> libc-config
      33            -> errno
      34            -> fcntl-h
      35            -> stdbool
      36            -> sys_stat
      37            -> unistd
      38            -> eloop-threshold
      39            -> filename
      40            -> idx
      41            -> intprops
      42            -> scratch_buffer
      43               -> malloc-posix
      44               -> realloc-posix
      45               -> free-posix
      46            -> pathmax
      47            -> mempcpy
      48            -> rawmemchr
      49            -> readlink
      50            -> stat
      51            -> double-slash-root
      52      -> relocatable
      53      -> setenv
      54         -> malloca
      55      -> fprintf-posix [ignore, cut dependency tree here]
      56      -> strerror [ignore, cut dependency tree here]
      57      -> c-ctype
      58  
      59     Macros that need to be set while compiling this file:
      60       - ENABLE_RELOCATABLE 1
      61       - INSTALLPREFIX the base installation directory
      62       - INSTALLDIR the directory into which this program is installed
      63       - LIBPATHVAR the platform dependent runtime library path variable
      64       - LIBDIRS a comma-terminated list of strings representing the list of
      65         directories that contain the libraries at installation time
      66  
      67     We don't want to internationalize this wrapper because then it would
      68     depend on libintl and therefore need relocation itself.  So use only
      69     libc functions, no gettext(), no error(), no xmalloc(), no xsetenv().
      70   */
      71  
      72  #define _GL_USE_STDLIB_ALLOC 1
      73  #include <config.h>
      74  
      75  #include <stdio.h>
      76  #include <stdlib.h>
      77  #include <string.h>
      78  #include <unistd.h>
      79  #include <errno.h>
      80  
      81  #include "progname.h"
      82  #include "relocatable.h"
      83  #include "c-ctype.h"
      84  #include "verify.h"
      85  
      86  /* Use the system functions, not the gnulib overrides in this file.  */
      87  #undef fprintf
      88  #undef strerror
      89  
      90  /* Return a copy of the filename, with an extra ".bin" at the end.
      91     More generally, it replaces "${EXEEXT}" at the end with ".bin${EXEEXT}".  */
      92  static char *
      93  add_dotbin (const char *filename)
      94  {
      95    size_t filename_len = strlen (filename);
      96    char *result = (char *) malloc (filename_len + 4 + 1);
      97  
      98    if (result != NULL)
      99      {
     100        if (sizeof (EXEEXT) > sizeof (""))
     101          {
     102            /* EXEEXT handling.  */
     103            const size_t exeext_len = sizeof (EXEEXT) - sizeof ("");
     104            static const char exeext[] = EXEEXT;
     105            if (filename_len > exeext_len)
     106              {
     107                /* Compare using an inlined copy of c_strncasecmp(), because
     108                   the filenames may have undergone a case conversion since
     109                   they were packaged.  In other words, EXEEXT may be ".exe"
     110                   on one system and ".EXE" on another.  */
     111                const char *s1 = filename + filename_len - exeext_len;
     112                const char *s2 = exeext;
     113                for (; *s1 != '\0'; s1++, s2++)
     114                  {
     115                    unsigned char c1 = *s1;
     116                    unsigned char c2 = *s2;
     117                    if (c_tolower (c1) != c_tolower (c2))
     118                      goto simple_append;
     119                  }
     120                /* Insert ".bin" before EXEEXT or its equivalent.  */
     121                memcpy (result, filename, filename_len - exeext_len);
     122                memcpy (result + filename_len - exeext_len, ".bin", 4);
     123                memcpy (result + filename_len - exeext_len + 4,
     124                        filename + filename_len - exeext_len,
     125                        exeext_len + 1);
     126                return result;
     127              }
     128          }
     129       simple_append:
     130        /* Simply append ".bin".  */
     131        memcpy (result, filename, filename_len);
     132        memcpy (result + filename_len, ".bin", 4 + 1);
     133        return result;
     134      }
     135    else
     136      {
     137        fprintf (stderr, "%s: %s\n", program_name, "memory exhausted");
     138        exit (1);
     139      }
     140  }
     141  
     142  /* List of directories that contain the libraries.  */
     143  static const char *libdirs[] = { LIBDIRS NULL };
     144  /* Verify that at least one directory is given.  */
     145  verify (sizeof (libdirs) / sizeof (libdirs[0]) > 1);
     146  
     147  /* Relocate the list of directories that contain the libraries.  */
     148  static void
     149  relocate_libdirs ()
     150  {
     151    size_t i;
     152  
     153    for (i = 0; i < sizeof (libdirs) / sizeof (libdirs[0]) - 1; i++)
     154      libdirs[i] = relocate (libdirs[i]);
     155  }
     156  
     157  /* Activate the list of directories in the LIBPATHVAR.  */
     158  static void
     159  activate_libdirs ()
     160  {
     161    const char *old_value;
     162    size_t total;
     163    size_t i;
     164    char *value;
     165    char *p;
     166  
     167    old_value = getenv (LIBPATHVAR);
     168    if (old_value == NULL)
     169      old_value = "";
     170  
     171    total = 0;
     172    for (i = 0; i < sizeof (libdirs) / sizeof (libdirs[0]) - 1; i++)
     173      total += strlen (libdirs[i]) + 1;
     174    total += strlen (old_value) + 1;
     175  
     176    value = (char *) malloc (total);
     177    if (value == NULL)
     178      {
     179        fprintf (stderr, "%s: %s\n", program_name, "memory exhausted");
     180        exit (1);
     181      }
     182    p = value;
     183    for (i = 0; i < sizeof (libdirs) / sizeof (libdirs[0]) - 1; i++)
     184      {
     185        size_t len = strlen (libdirs[i]);
     186        memcpy (p, libdirs[i], len);
     187        p += len;
     188        *p++ = ':';
     189      }
     190    if (old_value[0] != '\0')
     191      strcpy (p, old_value);
     192    else
     193      p[-1] = '\0';
     194  
     195    if (setenv (LIBPATHVAR, value, 1) < 0)
     196      {
     197        fprintf (stderr, "%s: %s\n", program_name, "memory exhausted");
     198        exit (1);
     199      }
     200  }
     201  
     202  int
     203  main (int argc, char *argv[])
     204  {
     205    char *full_program_name;
     206  
     207    /* Set the program name and perform preparations for
     208       get_full_program_name() and relocate().  */
     209    set_program_name_and_installdir (argv[0], INSTALLPREFIX, INSTALLDIR);
     210  
     211    /* Get the full program path.  (Important if accessed through a symlink.)  */
     212    full_program_name = get_full_program_name ();
     213    if (full_program_name == NULL)
     214      full_program_name = argv[0];
     215  
     216    /* Invoke the real program, with suffix ".bin".  */
     217    argv[0] = add_dotbin (full_program_name);
     218    relocate_libdirs ();
     219    activate_libdirs ();
     220    execv (argv[0], argv);
     221    fprintf (stderr, "%s: could not execute %s: %s\n",
     222             program_name, argv[0], strerror (errno));
     223    exit (127);
     224  }