Home | History | Annotate | Line # | Download | only in gnulib-lib
      1  1.1  christos /* Relocating wrapper program.
      2  1.1  christos    Copyright (C) 2003, 2005-2006 Free Software Foundation, Inc.
      3  1.1  christos    Written by Bruno Haible <bruno (at) clisp.org>, 2003.
      4  1.1  christos 
      5  1.1  christos    This program is free software; you can redistribute it and/or modify
      6  1.1  christos    it under the terms of the GNU General Public License as published by
      7  1.1  christos    the Free Software Foundation; either version 2, or (at your option)
      8  1.1  christos    any later version.
      9  1.1  christos 
     10  1.1  christos    This program is distributed in the hope that it will be useful,
     11  1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  1.1  christos    GNU General Public License for more details.
     14  1.1  christos 
     15  1.1  christos    You should have received a copy of the GNU General Public License
     16  1.1  christos    along with this program; if not, write to the Free Software Foundation,
     17  1.1  christos    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
     18  1.1  christos 
     19  1.1  christos /* Dependencies:
     20  1.1  christos    relocwrapper
     21  1.1  christos     -> progname
     22  1.1  christos     -> progreloc
     23  1.1  christos         -> xreadlink
     24  1.1  christos            -> readlink
     25  1.1  christos         -> canonicalize
     26  1.1  christos            -> allocsa
     27  1.1  christos     -> relocatable
     28  1.1  christos     -> setenv
     29  1.1  christos        -> allocsa
     30  1.1  christos     -> strerror
     31  1.1  christos 
     32  1.1  christos    Macros that need to be set while compiling this file:
     33  1.1  christos      - ENABLE_RELOCATABLE 1
     34  1.1  christos      - INSTALLPREFIX the base installation directory
     35  1.1  christos      - INSTALLDIR the directory into which this program is installed
     36  1.1  christos      - LIBPATHVAR the platform dependent runtime library path variable
     37  1.1  christos      - LIBDIRS a comma-terminated list of strings representing the list of
     38  1.1  christos        directories that contain the libraries at installation time
     39  1.1  christos 
     40  1.1  christos    We don't want to internationalize this wrapper because then it would
     41  1.1  christos    depend on libintl and therefore need relocation itself.  So use only
     42  1.1  christos    libc functions, no gettext(), no error(), no xmalloc(), no xsetenv().
     43  1.1  christos  */
     44  1.1  christos 
     45  1.1  christos #include <config.h>
     46  1.1  christos 
     47  1.1  christos #include <stdio.h>
     48  1.1  christos #include <stdlib.h>
     49  1.1  christos #include <string.h>
     50  1.1  christos #if HAVE_UNISTD_H
     51  1.1  christos # include <unistd.h>
     52  1.1  christos #endif
     53  1.1  christos #include <errno.h>
     54  1.1  christos 
     55  1.1  christos #include "progname.h"
     56  1.1  christos #include "relocatable.h"
     57  1.1  christos #include "setenv.h"
     58  1.1  christos 
     59  1.1  christos /* Return a copy of the filename, with an extra ".bin" at the end.
     60  1.1  christos    More generally, it replaces "${EXEEXT}" at the end with ".bin${EXEEXT}".  */
     61  1.1  christos static char *
     62  1.1  christos add_dotbin (const char *filename)
     63  1.1  christos {
     64  1.1  christos   size_t filename_len = strlen (filename);
     65  1.1  christos   char *result = (char *) malloc (filename_len + 4 + 1);
     66  1.1  christos 
     67  1.1  christos   if (result != NULL)
     68  1.1  christos     {
     69  1.1  christos       if (sizeof (EXEEXT) > sizeof (""))
     70  1.1  christos 	{
     71  1.1  christos 	  /* EXEEXT handling.  */
     72  1.1  christos 	  const size_t exeext_len = sizeof (EXEEXT) - sizeof ("");
     73  1.1  christos 	  static const char exeext[] = EXEEXT;
     74  1.1  christos 	  if (filename_len > exeext_len)
     75  1.1  christos 	    {
     76  1.1  christos 	      /* Compare using an inlined copy of c_strncasecmp(), because
     77  1.1  christos 		 the filenames may have undergone a case conversion since
     78  1.1  christos 		 they were packaged.  In other words, EXEEXT may be ".exe"
     79  1.1  christos 		 on one system and ".EXE" on another.  */
     80  1.1  christos 	      const char *s1 = filename + filename_len - exeext_len;
     81  1.1  christos 	      const char *s2 = exeext;
     82  1.1  christos 	      for (; *s1 != '\0'; s1++, s2++)
     83  1.1  christos 		{
     84  1.1  christos 		  unsigned char c1 = *s1;
     85  1.1  christos 		  unsigned char c2 = *s2;
     86  1.1  christos 		  if ((c1 >= 'A' && c1 <= 'Z' ? c1 - 'A' + 'a' : c1)
     87  1.1  christos 		      != (c2 >= 'A' && c2 <= 'Z' ? c2 - 'A' + 'a' : c2))
     88  1.1  christos 		    goto simple_append;
     89  1.1  christos 		}
     90  1.1  christos 	      /* Insert ".bin" before EXEEXT or its equivalent.  */
     91  1.1  christos 	      memcpy (result, filename, filename_len - exeext_len);
     92  1.1  christos 	      memcpy (result + filename_len - exeext_len, ".bin", 4);
     93  1.1  christos 	      memcpy (result + filename_len - exeext_len + 4,
     94  1.1  christos 		      filename + filename_len - exeext_len,
     95  1.1  christos 		      exeext_len + 1);
     96  1.1  christos 	      return result;
     97  1.1  christos 	    }
     98  1.1  christos 	}
     99  1.1  christos      simple_append:
    100  1.1  christos       /* Simply append ".bin".  */
    101  1.1  christos       memcpy (result, filename, filename_len);
    102  1.1  christos       memcpy (result + filename_len, ".bin", 4 + 1);
    103  1.1  christos       return result;
    104  1.1  christos     }
    105  1.1  christos   else
    106  1.1  christos     {
    107  1.1  christos       fprintf (stderr, "%s: %s\n", program_name, "memory exhausted");
    108  1.1  christos       exit (1);
    109  1.1  christos     }
    110  1.1  christos }
    111  1.1  christos 
    112  1.1  christos /* List of directories that contain the libraries.  */
    113  1.1  christos static const char *libdirs[] = { LIBDIRS NULL };
    114  1.1  christos /* Verify that at least one directory is given.  */
    115  1.1  christos typedef int verify1[2 * (sizeof (libdirs) / sizeof (libdirs[0]) > 1) - 1];
    116  1.1  christos 
    117  1.1  christos /* Relocate the list of directories that contain the libraries.  */
    118  1.1  christos static void
    119  1.1  christos relocate_libdirs ()
    120  1.1  christos {
    121  1.1  christos   size_t i;
    122  1.1  christos 
    123  1.1  christos   for (i = 0; i < sizeof (libdirs) / sizeof (libdirs[0]) - 1; i++)
    124  1.1  christos     libdirs[i] = relocate (libdirs[i]);
    125  1.1  christos }
    126  1.1  christos 
    127  1.1  christos /* Activate the list of directories in the LIBPATHVAR.  */
    128  1.1  christos static void
    129  1.1  christos activate_libdirs ()
    130  1.1  christos {
    131  1.1  christos   const char *old_value;
    132  1.1  christos   size_t total;
    133  1.1  christos   size_t i;
    134  1.1  christos   char *value;
    135  1.1  christos   char *p;
    136  1.1  christos 
    137  1.1  christos   old_value = getenv (LIBPATHVAR);
    138  1.1  christos   if (old_value == NULL)
    139  1.1  christos     old_value = "";
    140  1.1  christos 
    141  1.1  christos   total = 0;
    142  1.1  christos   for (i = 0; i < sizeof (libdirs) / sizeof (libdirs[0]) - 1; i++)
    143  1.1  christos     total += strlen (libdirs[i]) + 1;
    144  1.1  christos   total += strlen (old_value) + 1;
    145  1.1  christos 
    146  1.1  christos   value = (char *) malloc (total);
    147  1.1  christos   if (value == NULL)
    148  1.1  christos     {
    149  1.1  christos       fprintf (stderr, "%s: %s\n", program_name, "memory exhausted");
    150  1.1  christos       exit (1);
    151  1.1  christos     }
    152  1.1  christos   p = value;
    153  1.1  christos   for (i = 0; i < sizeof (libdirs) / sizeof (libdirs[0]) - 1; i++)
    154  1.1  christos     {
    155  1.1  christos       size_t len = strlen (libdirs[i]);
    156  1.1  christos       memcpy (p, libdirs[i], len);
    157  1.1  christos       p += len;
    158  1.1  christos       *p++ = ':';
    159  1.1  christos     }
    160  1.1  christos   if (old_value[0] != '\0')
    161  1.1  christos     strcpy (p, old_value);
    162  1.1  christos   else
    163  1.1  christos     p[-1] = '\0';
    164  1.1  christos 
    165  1.1  christos   if (setenv (LIBPATHVAR, value, 1) < 0)
    166  1.1  christos     {
    167  1.1  christos       fprintf (stderr, "%s: %s\n", program_name, "memory exhausted");
    168  1.1  christos       exit (1);
    169  1.1  christos     }
    170  1.1  christos }
    171  1.1  christos 
    172  1.1  christos int
    173  1.1  christos main (int argc, char *argv[])
    174  1.1  christos {
    175  1.1  christos   char *full_program_name;
    176  1.1  christos 
    177  1.1  christos   /* Set the program name and perform preparations for
    178  1.1  christos      get_full_program_name() and relocate().  */
    179  1.1  christos   set_program_name_and_installdir (argv[0], INSTALLPREFIX, INSTALLDIR);
    180  1.1  christos 
    181  1.1  christos   /* Get the full program path.  (Important if accessed through a symlink.)  */
    182  1.1  christos   full_program_name = get_full_program_name ();
    183  1.1  christos   if (full_program_name == NULL)
    184  1.1  christos     full_program_name = argv[0];
    185  1.1  christos 
    186  1.1  christos   /* Invoke the real program, with suffix ".bin".  */
    187  1.1  christos   argv[0] = add_dotbin (full_program_name);
    188  1.1  christos   relocate_libdirs ();
    189  1.1  christos   activate_libdirs ();
    190  1.1  christos   execv (argv[0], argv);
    191  1.1  christos   fprintf (stderr, "%s: could not execute %s: %s\n",
    192  1.1  christos 	   program_name, argv[0], strerror (errno));
    193  1.1  christos   exit (127);
    194  1.1  christos }
    195