Home | History | Annotate | Line # | Download | only in gnulib-lib
progreloc.c revision 1.1.1.1
      1  1.1  christos /* Provide relocatable programs.
      2  1.1  christos    Copyright (C) 2003-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 
     20  1.1  christos #include <config.h>
     21  1.1  christos 
     22  1.1  christos /* Specification.  */
     23  1.1  christos #include "progname.h"
     24  1.1  christos 
     25  1.1  christos #include <stdbool.h>
     26  1.1  christos #include <stdio.h>
     27  1.1  christos #include <stdlib.h>
     28  1.1  christos #include <string.h>
     29  1.1  christos #include <fcntl.h>
     30  1.1  christos #if HAVE_UNISTD_H
     31  1.1  christos # include <unistd.h>
     32  1.1  christos #endif
     33  1.1  christos #include <sys/stat.h>
     34  1.1  christos 
     35  1.1  christos /* Get declaration of _NSGetExecutablePath on MacOS X 10.2 or newer.  */
     36  1.1  christos #if HAVE_MACH_O_DYLD_H
     37  1.1  christos # include <mach-o/dyld.h>
     38  1.1  christos #endif
     39  1.1  christos 
     40  1.1  christos #if defined _WIN32 || defined __WIN32__
     41  1.1  christos # define WIN32_NATIVE
     42  1.1  christos #endif
     43  1.1  christos 
     44  1.1  christos #if defined WIN32_NATIVE || defined __CYGWIN__
     45  1.1  christos # define WIN32_LEAN_AND_MEAN
     46  1.1  christos # include <windows.h>
     47  1.1  christos #endif
     48  1.1  christos 
     49  1.1  christos #include "xreadlink.h"
     50  1.1  christos #include "canonicalize.h"
     51  1.1  christos #include "relocatable.h"
     52  1.1  christos 
     53  1.1  christos #ifdef NO_XMALLOC
     54  1.1  christos # define xmalloc malloc
     55  1.1  christos # define xstrdup strdup
     56  1.1  christos #else
     57  1.1  christos # include "xalloc.h"
     58  1.1  christos #endif
     59  1.1  christos 
     60  1.1  christos /* Pathname support.
     61  1.1  christos    ISSLASH(C)           tests whether C is a directory separator character.
     62  1.1  christos    IS_PATH_WITH_DIR(P)  tests whether P contains a directory specification.
     63  1.1  christos  */
     64  1.1  christos #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
     65  1.1  christos   /* Win32, Cygwin, OS/2, DOS */
     66  1.1  christos # define ISSLASH(C) ((C) == '/' || (C) == '\\')
     67  1.1  christos # define HAS_DEVICE(P) \
     68  1.1  christos     ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
     69  1.1  christos      && (P)[1] == ':')
     70  1.1  christos # define IS_PATH_WITH_DIR(P) \
     71  1.1  christos     (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
     72  1.1  christos # define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
     73  1.1  christos #else
     74  1.1  christos   /* Unix */
     75  1.1  christos # define ISSLASH(C) ((C) == '/')
     76  1.1  christos # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
     77  1.1  christos # define FILE_SYSTEM_PREFIX_LEN(P) 0
     78  1.1  christos #endif
     79  1.1  christos 
     80  1.1  christos #undef set_program_name
     81  1.1  christos 
     82  1.1  christos 
     83  1.1  christos #if ENABLE_RELOCATABLE
     84  1.1  christos 
     85  1.1  christos #ifdef __linux__
     86  1.1  christos /* File descriptor of the executable.
     87  1.1  christos    (Only used to verify that we find the correct executable.)  */
     88  1.1  christos static int executable_fd = -1;
     89  1.1  christos #endif
     90  1.1  christos 
     91  1.1  christos /* Tests whether a given pathname may belong to the executable.  */
     92  1.1  christos static bool
     93  1.1  christos maybe_executable (const char *filename)
     94  1.1  christos {
     95  1.1  christos   /* Woe32 lacks the access() function, but Cygwin doesn't.  */
     96  1.1  christos #if !(defined WIN32_NATIVE && !defined __CYGWIN__)
     97  1.1  christos   if (access (filename, X_OK) < 0)
     98  1.1  christos     return false;
     99  1.1  christos 
    100  1.1  christos #ifdef __linux__
    101  1.1  christos   if (executable_fd >= 0)
    102  1.1  christos     {
    103  1.1  christos       /* If we already have an executable_fd, check that filename points to
    104  1.1  christos 	 the same inode.  */
    105  1.1  christos       struct stat statexe;
    106  1.1  christos       struct stat statfile;
    107  1.1  christos 
    108  1.1  christos       if (fstat (executable_fd, &statexe) >= 0)
    109  1.1  christos 	{
    110  1.1  christos 	  if (stat (filename, &statfile) < 0)
    111  1.1  christos 	    return false;
    112  1.1  christos 	  if (!(statfile.st_dev
    113  1.1  christos 		&& statfile.st_dev == statexe.st_dev
    114  1.1  christos 		&& statfile.st_ino == statexe.st_ino))
    115  1.1  christos 	    return false;
    116  1.1  christos 	}
    117  1.1  christos     }
    118  1.1  christos #endif
    119  1.1  christos #endif
    120  1.1  christos 
    121  1.1  christos   return true;
    122  1.1  christos }
    123  1.1  christos 
    124  1.1  christos /* Determine the full pathname of the current executable, freshly allocated.
    125  1.1  christos    Return NULL if unknown.
    126  1.1  christos    Guaranteed to work on Linux and Woe32.  Likely to work on the other
    127  1.1  christos    Unixes (maybe except BeOS), under most conditions.  */
    128  1.1  christos static char *
    129  1.1  christos find_executable (const char *argv0)
    130  1.1  christos {
    131  1.1  christos #if defined WIN32_NATIVE || defined __CYGWIN__
    132  1.1  christos   char location[MAX_PATH];
    133  1.1  christos   int length = GetModuleFileName (NULL, location, sizeof (location));
    134  1.1  christos   if (length < 0)
    135  1.1  christos     return NULL;
    136  1.1  christos   if (!IS_PATH_WITH_DIR (location))
    137  1.1  christos     /* Shouldn't happen.  */
    138  1.1  christos     return NULL;
    139  1.1  christos   {
    140  1.1  christos #if defined __CYGWIN__
    141  1.1  christos     /* cygwin-1.5.13 (2005-03-01) or newer would also allow a Linux-like
    142  1.1  christos        implementation: readlink of "/proc/self/exe".  But using the
    143  1.1  christos        result of the Win32 system call is simpler and is consistent with the
    144  1.1  christos        code in relocatable.c.  */
    145  1.1  christos     /* On Cygwin, we need to convert paths coming from Win32 system calls
    146  1.1  christos        to the Unix-like slashified notation.  */
    147  1.1  christos     static char location_as_posix_path[2 * MAX_PATH];
    148  1.1  christos     /* There's no error return defined for cygwin_conv_to_posix_path.
    149  1.1  christos        See cygwin-api/func-cygwin-conv-to-posix-path.html.
    150  1.1  christos        Does it overflow the buffer of expected size MAX_PATH or does it
    151  1.1  christos        truncate the path?  I don't know.  Let's catch both.  */
    152  1.1  christos     cygwin_conv_to_posix_path (location, location_as_posix_path);
    153  1.1  christos     location_as_posix_path[MAX_PATH - 1] = '\0';
    154  1.1  christos     if (strlen (location_as_posix_path) >= MAX_PATH - 1)
    155  1.1  christos       /* A sign of buffer overflow or path truncation.  */
    156  1.1  christos       return NULL;
    157  1.1  christos     /* Call canonicalize_file_name, because Cygwin supports symbolic links.  */
    158  1.1  christos     return canonicalize_file_name (location_as_posix_path);
    159  1.1  christos #else
    160  1.1  christos     return xstrdup (location);
    161  1.1  christos #endif
    162  1.1  christos   }
    163  1.1  christos #else /* Unix && !Cygwin */
    164  1.1  christos #ifdef __linux__
    165  1.1  christos   /* The executable is accessible as /proc/<pid>/exe.  In newer Linux
    166  1.1  christos      versions, also as /proc/self/exe.  Linux >= 2.1 provides a symlink
    167  1.1  christos      to the true pathname; older Linux versions give only device and ino,
    168  1.1  christos      enclosed in brackets, which we cannot use here.  */
    169  1.1  christos   {
    170  1.1  christos     char *link;
    171  1.1  christos 
    172  1.1  christos     link = xreadlink ("/proc/self/exe");
    173  1.1  christos     if (link != NULL && link[0] != '[')
    174  1.1  christos       return link;
    175  1.1  christos     if (executable_fd < 0)
    176  1.1  christos       executable_fd = open ("/proc/self/exe", O_RDONLY, 0);
    177  1.1  christos 
    178  1.1  christos     {
    179  1.1  christos       char buf[6+10+5];
    180  1.1  christos       sprintf (buf, "/proc/%d/exe", getpid ());
    181  1.1  christos       link = xreadlink (buf);
    182  1.1  christos       if (link != NULL && link[0] != '[')
    183  1.1  christos 	return link;
    184  1.1  christos       if (executable_fd < 0)
    185  1.1  christos 	executable_fd = open (buf, O_RDONLY, 0);
    186  1.1  christos     }
    187  1.1  christos   }
    188  1.1  christos #endif
    189  1.1  christos #if HAVE_MACH_O_DYLD_H && HAVE__NSGETEXECUTABLEPATH
    190  1.1  christos   /* On MacOS X 10.2 or newer, the function
    191  1.1  christos        int _NSGetExecutablePath (char *buf, unsigned long *bufsize);
    192  1.1  christos      can be used to retrieve the executable's full path.  */
    193  1.1  christos   char location[4096];
    194  1.1  christos   unsigned long length = sizeof (location);
    195  1.1  christos   if (_NSGetExecutablePath (location, &length) == 0
    196  1.1  christos       && location[0] == '/')
    197  1.1  christos     return canonicalize_file_name (location);
    198  1.1  christos #endif
    199  1.1  christos   /* Guess the executable's full path.  We assume the executable has been
    200  1.1  christos      called via execlp() or execvp() with properly set up argv[0].  The
    201  1.1  christos      login(1) convention to add a '-' prefix to argv[0] is not supported.  */
    202  1.1  christos   {
    203  1.1  christos     bool has_slash = false;
    204  1.1  christos     {
    205  1.1  christos       const char *p;
    206  1.1  christos       for (p = argv0; *p; p++)
    207  1.1  christos 	if (*p == '/')
    208  1.1  christos 	  {
    209  1.1  christos 	    has_slash = true;
    210  1.1  christos 	    break;
    211  1.1  christos 	  }
    212  1.1  christos     }
    213  1.1  christos     if (!has_slash)
    214  1.1  christos       {
    215  1.1  christos 	/* exec searches paths without slashes in the directory list given
    216  1.1  christos 	   by $PATH.  */
    217  1.1  christos 	const char *path = getenv ("PATH");
    218  1.1  christos 
    219  1.1  christos 	if (path != NULL)
    220  1.1  christos 	  {
    221  1.1  christos 	    const char *p;
    222  1.1  christos 	    const char *p_next;
    223  1.1  christos 
    224  1.1  christos 	    for (p = path; *p; p = p_next)
    225  1.1  christos 	      {
    226  1.1  christos 		const char *q;
    227  1.1  christos 		size_t p_len;
    228  1.1  christos 		char *concat_name;
    229  1.1  christos 
    230  1.1  christos 		for (q = p; *q; q++)
    231  1.1  christos 		  if (*q == ':')
    232  1.1  christos 		    break;
    233  1.1  christos 		p_len = q - p;
    234  1.1  christos 		p_next = (*q == '\0' ? q : q + 1);
    235  1.1  christos 
    236  1.1  christos 		/* We have a path item at p, of length p_len.
    237  1.1  christos 		   Now concatenate the path item and argv0.  */
    238  1.1  christos 		concat_name = (char *) xmalloc (p_len + strlen (argv0) + 2);
    239  1.1  christos #ifdef NO_XMALLOC
    240  1.1  christos 		if (concat_name == NULL)
    241  1.1  christos 		  return NULL;
    242  1.1  christos #endif
    243  1.1  christos 		if (p_len == 0)
    244  1.1  christos 		  /* An empty PATH element designates the current directory.  */
    245  1.1  christos 		  strcpy (concat_name, argv0);
    246  1.1  christos 		else
    247  1.1  christos 		  {
    248  1.1  christos 		    memcpy (concat_name, p, p_len);
    249  1.1  christos 		    concat_name[p_len] = '/';
    250  1.1  christos 		    strcpy (concat_name + p_len + 1, argv0);
    251  1.1  christos 		  }
    252  1.1  christos 		if (maybe_executable (concat_name))
    253  1.1  christos 		  return canonicalize_file_name (concat_name);
    254  1.1  christos 		free (concat_name);
    255  1.1  christos 	      }
    256  1.1  christos 	  }
    257  1.1  christos 	/* Not found in the PATH, assume the current directory.  */
    258  1.1  christos       }
    259  1.1  christos     /* exec treats paths containing slashes as relative to the current
    260  1.1  christos        directory.  */
    261  1.1  christos     if (maybe_executable (argv0))
    262  1.1  christos       return canonicalize_file_name (argv0);
    263  1.1  christos   }
    264  1.1  christos   /* No way to find the executable.  */
    265  1.1  christos   return NULL;
    266  1.1  christos #endif
    267  1.1  christos }
    268  1.1  christos 
    269  1.1  christos /* Full pathname of executable, or NULL.  */
    270  1.1  christos static char *executable_fullname;
    271  1.1  christos 
    272  1.1  christos static void
    273  1.1  christos prepare_relocate (const char *orig_installprefix, const char *orig_installdir,
    274  1.1  christos 		  const char *argv0)
    275  1.1  christos {
    276  1.1  christos   const char *curr_prefix;
    277  1.1  christos 
    278  1.1  christos   /* Determine the full pathname of the current executable.  */
    279  1.1  christos   executable_fullname = find_executable (argv0);
    280  1.1  christos 
    281  1.1  christos   /* Determine the current installation prefix from it.  */
    282  1.1  christos   curr_prefix = compute_curr_prefix (orig_installprefix, orig_installdir,
    283  1.1  christos 				     executable_fullname);
    284  1.1  christos   if (curr_prefix != NULL)
    285  1.1  christos     /* Now pass this prefix to all copies of the relocate.c source file.  */
    286  1.1  christos     set_relocation_prefix (orig_installprefix, curr_prefix);
    287  1.1  christos }
    288  1.1  christos 
    289  1.1  christos /* Set program_name, based on argv[0], and original installation prefix and
    290  1.1  christos    directory, for relocatability.  */
    291  1.1  christos void
    292  1.1  christos set_program_name_and_installdir (const char *argv0,
    293  1.1  christos 				 const char *orig_installprefix,
    294  1.1  christos 				 const char *orig_installdir)
    295  1.1  christos {
    296  1.1  christos   const char *argv0_stripped = argv0;
    297  1.1  christos 
    298  1.1  christos   /* Relocatable programs are renamed to .bin by install-reloc.  Or, more
    299  1.1  christos      generally, their suffix is changed from $exeext to .bin$exeext.
    300  1.1  christos      Remove the ".bin" here.  */
    301  1.1  christos   {
    302  1.1  christos     size_t argv0_len = strlen (argv0);
    303  1.1  christos     const size_t exeext_len = sizeof (EXEEXT) - sizeof ("");
    304  1.1  christos     if (argv0_len > 4 + exeext_len)
    305  1.1  christos       if (memcmp (argv0 + argv0_len - exeext_len - 4, ".bin", 4) == 0)
    306  1.1  christos 	{
    307  1.1  christos 	  if (sizeof (EXEEXT) > sizeof (""))
    308  1.1  christos 	    {
    309  1.1  christos 	      /* Compare using an inlined copy of c_strncasecmp(), because
    310  1.1  christos 		 the filenames may have undergone a case conversion since
    311  1.1  christos 		 they were packaged.  In other words, EXEEXT may be ".exe"
    312  1.1  christos 		 on one system and ".EXE" on another.  */
    313  1.1  christos 	      static const char exeext[] = EXEEXT;
    314  1.1  christos 	      const char *s1 = argv0 + argv0_len - exeext_len;
    315  1.1  christos 	      const char *s2 = exeext;
    316  1.1  christos 	      for (; *s1 != '\0'; s1++, s2++)
    317  1.1  christos 		{
    318  1.1  christos 		  unsigned char c1 = *s1;
    319  1.1  christos 		  unsigned char c2 = *s2;
    320  1.1  christos 		  if ((c1 >= 'A' && c1 <= 'Z' ? c1 - 'A' + 'a' : c1)
    321  1.1  christos 		      != (c2 >= 'A' && c2 <= 'Z' ? c2 - 'A' + 'a' : c2))
    322  1.1  christos 		    goto done_stripping;
    323  1.1  christos 		}
    324  1.1  christos 	    }
    325  1.1  christos 	  /* Remove ".bin" before EXEEXT or its equivalent.  */
    326  1.1  christos 	  {
    327  1.1  christos 	    char *shorter = (char *) xmalloc (argv0_len - 4 + 1);
    328  1.1  christos #ifdef NO_XMALLOC
    329  1.1  christos 	    if (shorter != NULL)
    330  1.1  christos #endif
    331  1.1  christos 	      {
    332  1.1  christos 		memcpy (shorter, argv0, argv0_len - exeext_len - 4);
    333  1.1  christos 		if (sizeof (EXEEXT) > sizeof (""))
    334  1.1  christos 		  memcpy (shorter + argv0_len - exeext_len - 4,
    335  1.1  christos 			  argv0 + argv0_len - exeext_len - 4,
    336  1.1  christos 			  exeext_len);
    337  1.1  christos 		shorter[argv0_len - 4] = '\0';
    338  1.1  christos 		argv0_stripped = shorter;
    339  1.1  christos 	      }
    340  1.1  christos 	  }
    341  1.1  christos 	 done_stripping: ;
    342  1.1  christos       }
    343  1.1  christos   }
    344  1.1  christos 
    345  1.1  christos   set_program_name (argv0_stripped);
    346  1.1  christos 
    347  1.1  christos   prepare_relocate (orig_installprefix, orig_installdir, argv0);
    348  1.1  christos }
    349  1.1  christos 
    350  1.1  christos /* Return the full pathname of the current executable, based on the earlier
    351  1.1  christos    call to set_program_name_and_installdir.  Return NULL if unknown.  */
    352  1.1  christos char *
    353  1.1  christos get_full_program_name (void)
    354  1.1  christos {
    355  1.1  christos   return executable_fullname;
    356  1.1  christos }
    357  1.1  christos 
    358  1.1  christos #endif
    359