(root)/
gettext-0.22.4/
gettext-runtime/
gnulib-lib/
relocwrapper.c
       1  /* Relocating wrapper program.
       2     Copyright (C) 2003, 2005-2007, 2009-2023 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            -> c-bool
      33            -> libc-config
      34            -> errno
      35            -> fcntl-h
      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  
      85  /* Use the system functions, not the gnulib overrides in this file.  */
      86  #undef fprintf
      87  #undef strerror
      88  
      89  /* Return a copy of the filename, with an extra ".bin" at the end.
      90     More generally, it replaces "${EXEEXT}" at the end with ".bin${EXEEXT}".  */
      91  static char *
      92  add_dotbin (const char *filename)
      93  {
      94    size_t filename_len = strlen (filename);
      95    char *result = (char *) malloc (filename_len + 4 + 1);
      96  
      97    if (result != NULL)
      98      {
      99        if (sizeof (EXEEXT) > sizeof (""))
     100          {
     101            /* EXEEXT handling.  */
     102            const size_t exeext_len = sizeof (EXEEXT) - sizeof ("");
     103            static const char exeext[] = EXEEXT;
     104            if (filename_len > exeext_len)
     105              {
     106                /* Compare using an inlined copy of c_strncasecmp(), because
     107                   the filenames may have undergone a case conversion since
     108                   they were packaged.  In other words, EXEEXT may be ".exe"
     109                   on one system and ".EXE" on another.  */
     110                const char *s1 = filename + filename_len - exeext_len;
     111                const char *s2 = exeext;
     112                for (; *s1 != '\0'; s1++, s2++)
     113                  {
     114                    unsigned char c1 = *s1;
     115                    unsigned char c2 = *s2;
     116                    if (c_tolower (c1) != c_tolower (c2))
     117                      goto simple_append;
     118                  }
     119                /* Insert ".bin" before EXEEXT or its equivalent.  */
     120                memcpy (result, filename, filename_len - exeext_len);
     121                memcpy (result + filename_len - exeext_len, ".bin", 4);
     122                memcpy (result + filename_len - exeext_len + 4,
     123                        filename + filename_len - exeext_len,
     124                        exeext_len + 1);
     125                return result;
     126              }
     127          }
     128       simple_append:
     129        /* Simply append ".bin".  */
     130        memcpy (result, filename, filename_len);
     131        memcpy (result + filename_len, ".bin", 4 + 1);
     132        return result;
     133      }
     134    else
     135      {
     136        fprintf (stderr, "%s: %s\n", program_name, "memory exhausted");
     137        exit (1);
     138      }
     139  }
     140  
     141  /* List of directories that contain the libraries.  */
     142  static const char *libdirs[] = { LIBDIRS NULL };
     143  /* Verify that at least one directory is given.  */
     144  static_assert (sizeof (libdirs) / sizeof (libdirs[0]) > 1);
     145  
     146  /* Relocate the list of directories that contain the libraries.  */
     147  static void
     148  relocate_libdirs ()
     149  {
     150    size_t i;
     151  
     152    for (i = 0; i < sizeof (libdirs) / sizeof (libdirs[0]) - 1; i++)
     153      libdirs[i] = relocate (libdirs[i]);
     154  }
     155  
     156  /* Activate the list of directories in the LIBPATHVAR.  */
     157  static void
     158  activate_libdirs ()
     159  {
     160    const char *old_value;
     161    size_t total;
     162    size_t i;
     163    char *value;
     164    char *p;
     165  
     166    old_value = getenv (LIBPATHVAR);
     167    if (old_value == NULL)
     168      old_value = "";
     169  
     170    total = 0;
     171    for (i = 0; i < sizeof (libdirs) / sizeof (libdirs[0]) - 1; i++)
     172      total += strlen (libdirs[i]) + 1;
     173    total += strlen (old_value) + 1;
     174  
     175    value = (char *) malloc (total);
     176    if (value == NULL)
     177      {
     178        fprintf (stderr, "%s: %s\n", program_name, "memory exhausted");
     179        exit (1);
     180      }
     181    p = value;
     182    for (i = 0; i < sizeof (libdirs) / sizeof (libdirs[0]) - 1; i++)
     183      {
     184        size_t len = strlen (libdirs[i]);
     185        memcpy (p, libdirs[i], len);
     186        p += len;
     187        *p++ = ':';
     188      }
     189    if (old_value[0] != '\0')
     190      strcpy (p, old_value);
     191    else
     192      p[-1] = '\0';
     193  
     194    if (setenv (LIBPATHVAR, value, 1) < 0)
     195      {
     196        fprintf (stderr, "%s: %s\n", program_name, "memory exhausted");
     197        exit (1);
     198      }
     199  }
     200  
     201  int
     202  main (int argc, char *argv[])
     203  {
     204    char *full_program_name;
     205  
     206    /* Set the program name and perform preparations for
     207       get_full_program_name() and relocate().  */
     208    set_program_name_and_installdir (argv[0], INSTALLPREFIX, INSTALLDIR);
     209  
     210    /* Get the full program path.  (Important if accessed through a symlink.)  */
     211    full_program_name = get_full_program_name ();
     212    if (full_program_name == NULL)
     213      full_program_name = argv[0];
     214  
     215    /* Invoke the real program, with suffix ".bin".  */
     216    argv[0] = add_dotbin (full_program_name);
     217    relocate_libdirs ();
     218    activate_libdirs ();
     219    execv (argv[0], argv);
     220    fprintf (stderr, "%s: could not execute %s: %s\n",
     221             program_name, argv[0], strerror (errno));
     222    exit (127);
     223  }