Blame gettext-runtime/gnulib-lib/relocwrapper.c

Packit Bot 06c835
/* Relocating wrapper program.
Packit Bot 06c835
   Copyright (C) 2003, 2005-2007, 2009-2015 Free Software Foundation, Inc.
Packit Bot 06c835
   Written by Bruno Haible <bruno@clisp.org>, 2003.
Packit Bot 06c835
Packit Bot 06c835
   This program is free software: you can redistribute it and/or modify
Packit Bot 06c835
   it under the terms of the GNU General Public License as published by
Packit Bot 06c835
   the Free Software Foundation; either version 3 of the License, or
Packit Bot 06c835
   (at your option) any later version.
Packit Bot 06c835
Packit Bot 06c835
   This program is distributed in the hope that it will be useful,
Packit Bot 06c835
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Bot 06c835
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Bot 06c835
   GNU General Public License for more details.
Packit Bot 06c835
Packit Bot 06c835
   You should have received a copy of the GNU General Public License
Packit Bot 06c835
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit Bot 06c835
Packit Bot 06c835
/* Dependencies:
Packit Bot 06c835
   relocwrapper
Packit Bot 06c835
    -> progname
Packit Bot 06c835
    -> progreloc
Packit Bot 06c835
        -> areadlink
Packit Bot 06c835
           -> careadlinkat
Packit Bot 06c835
             -> allocator
Packit Bot 06c835
           -> readlink
Packit Bot 06c835
        -> canonicalize-lgpl
Packit Bot 06c835
           -> malloca
Packit Bot 06c835
           -> readlink
Packit Bot 06c835
    -> relocatable
Packit Bot 06c835
    -> setenv
Packit Bot 06c835
       -> malloca
Packit Bot 06c835
    -> c-ctype
Packit Bot 06c835
Packit Bot 06c835
   Macros that need to be set while compiling this file:
Packit Bot 06c835
     - ENABLE_RELOCATABLE 1
Packit Bot 06c835
     - INSTALLPREFIX the base installation directory
Packit Bot 06c835
     - INSTALLDIR the directory into which this program is installed
Packit Bot 06c835
     - LIBPATHVAR the platform dependent runtime library path variable
Packit Bot 06c835
     - LIBDIRS a comma-terminated list of strings representing the list of
Packit Bot 06c835
       directories that contain the libraries at installation time
Packit Bot 06c835
Packit Bot 06c835
   We don't want to internationalize this wrapper because then it would
Packit Bot 06c835
   depend on libintl and therefore need relocation itself.  So use only
Packit Bot 06c835
   libc functions, no gettext(), no error(), no xmalloc(), no xsetenv().
Packit Bot 06c835
 */
Packit Bot 06c835
Packit Bot 06c835
#define _GL_USE_STDLIB_ALLOC 1
Packit Bot 06c835
#include <config.h>
Packit Bot 06c835
Packit Bot 06c835
#include <stdio.h>
Packit Bot 06c835
#include <stdlib.h>
Packit Bot 06c835
#include <string.h>
Packit Bot 06c835
#include <unistd.h>
Packit Bot 06c835
#include <errno.h>
Packit Bot 06c835
Packit Bot 06c835
#include "progname.h"
Packit Bot 06c835
#include "relocatable.h"
Packit Bot 06c835
#include "c-ctype.h"
Packit Bot 06c835
#include "verify.h"
Packit Bot 06c835
Packit Bot 06c835
/* Use the system functions, not the gnulib overrides in this file.  */
Packit Bot 06c835
#undef fprintf
Packit Bot 06c835
Packit Bot 06c835
/* Return a copy of the filename, with an extra ".bin" at the end.
Packit Bot 06c835
   More generally, it replaces "${EXEEXT}" at the end with ".bin${EXEEXT}".  */
Packit Bot 06c835
static char *
Packit Bot 06c835
add_dotbin (const char *filename)
Packit Bot 06c835
{
Packit Bot 06c835
  size_t filename_len = strlen (filename);
Packit Bot 06c835
  char *result = (char *) malloc (filename_len + 4 + 1);
Packit Bot 06c835
Packit Bot 06c835
  if (result != NULL)
Packit Bot 06c835
    {
Packit Bot 06c835
      if (sizeof (EXEEXT) > sizeof (""))
Packit Bot 06c835
        {
Packit Bot 06c835
          /* EXEEXT handling.  */
Packit Bot 06c835
          const size_t exeext_len = sizeof (EXEEXT) - sizeof ("");
Packit Bot 06c835
          static const char exeext[] = EXEEXT;
Packit Bot 06c835
          if (filename_len > exeext_len)
Packit Bot 06c835
            {
Packit Bot 06c835
              /* Compare using an inlined copy of c_strncasecmp(), because
Packit Bot 06c835
                 the filenames may have undergone a case conversion since
Packit Bot 06c835
                 they were packaged.  In other words, EXEEXT may be ".exe"
Packit Bot 06c835
                 on one system and ".EXE" on another.  */
Packit Bot 06c835
              const char *s1 = filename + filename_len - exeext_len;
Packit Bot 06c835
              const char *s2 = exeext;
Packit Bot 06c835
              for (; *s1 != '\0'; s1++, s2++)
Packit Bot 06c835
                {
Packit Bot 06c835
                  unsigned char c1 = *s1;
Packit Bot 06c835
                  unsigned char c2 = *s2;
Packit Bot 06c835
                  if (c_tolower (c1) != c_tolower (c2))
Packit Bot 06c835
                    goto simple_append;
Packit Bot 06c835
                }
Packit Bot 06c835
              /* Insert ".bin" before EXEEXT or its equivalent.  */
Packit Bot 06c835
              memcpy (result, filename, filename_len - exeext_len);
Packit Bot 06c835
              memcpy (result + filename_len - exeext_len, ".bin", 4);
Packit Bot 06c835
              memcpy (result + filename_len - exeext_len + 4,
Packit Bot 06c835
                      filename + filename_len - exeext_len,
Packit Bot 06c835
                      exeext_len + 1);
Packit Bot 06c835
              return result;
Packit Bot 06c835
            }
Packit Bot 06c835
        }
Packit Bot 06c835
     simple_append:
Packit Bot 06c835
      /* Simply append ".bin".  */
Packit Bot 06c835
      memcpy (result, filename, filename_len);
Packit Bot 06c835
      memcpy (result + filename_len, ".bin", 4 + 1);
Packit Bot 06c835
      return result;
Packit Bot 06c835
    }
Packit Bot 06c835
  else
Packit Bot 06c835
    {
Packit Bot 06c835
      fprintf (stderr, "%s: %s\n", program_name, "memory exhausted");
Packit Bot 06c835
      exit (1);
Packit Bot 06c835
    }
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
/* List of directories that contain the libraries.  */
Packit Bot 06c835
static const char *libdirs[] = { LIBDIRS NULL };
Packit Bot 06c835
/* Verify that at least one directory is given.  */
Packit Bot 06c835
verify (sizeof (libdirs) / sizeof (libdirs[0]) > 1);
Packit Bot 06c835
Packit Bot 06c835
/* Relocate the list of directories that contain the libraries.  */
Packit Bot 06c835
static void
Packit Bot 06c835
relocate_libdirs ()
Packit Bot 06c835
{
Packit Bot 06c835
  size_t i;
Packit Bot 06c835
Packit Bot 06c835
  for (i = 0; i < sizeof (libdirs) / sizeof (libdirs[0]) - 1; i++)
Packit Bot 06c835
    libdirs[i] = relocate (libdirs[i]);
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
/* Activate the list of directories in the LIBPATHVAR.  */
Packit Bot 06c835
static void
Packit Bot 06c835
activate_libdirs ()
Packit Bot 06c835
{
Packit Bot 06c835
  const char *old_value;
Packit Bot 06c835
  size_t total;
Packit Bot 06c835
  size_t i;
Packit Bot 06c835
  char *value;
Packit Bot 06c835
  char *p;
Packit Bot 06c835
Packit Bot 06c835
  old_value = getenv (LIBPATHVAR);
Packit Bot 06c835
  if (old_value == NULL)
Packit Bot 06c835
    old_value = "";
Packit Bot 06c835
Packit Bot 06c835
  total = 0;
Packit Bot 06c835
  for (i = 0; i < sizeof (libdirs) / sizeof (libdirs[0]) - 1; i++)
Packit Bot 06c835
    total += strlen (libdirs[i]) + 1;
Packit Bot 06c835
  total += strlen (old_value) + 1;
Packit Bot 06c835
Packit Bot 06c835
  value = (char *) malloc (total);
Packit Bot 06c835
  if (value == NULL)
Packit Bot 06c835
    {
Packit Bot 06c835
      fprintf (stderr, "%s: %s\n", program_name, "memory exhausted");
Packit Bot 06c835
      exit (1);
Packit Bot 06c835
    }
Packit Bot 06c835
  p = value;
Packit Bot 06c835
  for (i = 0; i < sizeof (libdirs) / sizeof (libdirs[0]) - 1; i++)
Packit Bot 06c835
    {
Packit Bot 06c835
      size_t len = strlen (libdirs[i]);
Packit Bot 06c835
      memcpy (p, libdirs[i], len);
Packit Bot 06c835
      p += len;
Packit Bot 06c835
      *p++ = ':';
Packit Bot 06c835
    }
Packit Bot 06c835
  if (old_value[0] != '\0')
Packit Bot 06c835
    strcpy (p, old_value);
Packit Bot 06c835
  else
Packit Bot 06c835
    p[-1] = '\0';
Packit Bot 06c835
Packit Bot 06c835
  if (setenv (LIBPATHVAR, value, 1) < 0)
Packit Bot 06c835
    {
Packit Bot 06c835
      fprintf (stderr, "%s: %s\n", program_name, "memory exhausted");
Packit Bot 06c835
      exit (1);
Packit Bot 06c835
    }
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
int
Packit Bot 06c835
main (int argc, char *argv[])
Packit Bot 06c835
{
Packit Bot 06c835
  char *full_program_name;
Packit Bot 06c835
Packit Bot 06c835
  /* Set the program name and perform preparations for
Packit Bot 06c835
     get_full_program_name() and relocate().  */
Packit Bot 06c835
  set_program_name_and_installdir (argv[0], INSTALLPREFIX, INSTALLDIR);
Packit Bot 06c835
Packit Bot 06c835
  /* Get the full program path.  (Important if accessed through a symlink.)  */
Packit Bot 06c835
  full_program_name = get_full_program_name ();
Packit Bot 06c835
  if (full_program_name == NULL)
Packit Bot 06c835
    full_program_name = argv[0];
Packit Bot 06c835
Packit Bot 06c835
  /* Invoke the real program, with suffix ".bin".  */
Packit Bot 06c835
  argv[0] = add_dotbin (full_program_name);
Packit Bot 06c835
  relocate_libdirs ();
Packit Bot 06c835
  activate_libdirs ();
Packit Bot 06c835
  execv (argv[0], argv);
Packit Bot 06c835
  fprintf (stderr, "%s: could not execute %s: %s\n",
Packit Bot 06c835
           program_name, argv[0], strerror (errno));
Packit Bot 06c835
  exit (127);
Packit Bot 06c835
}