Home | History | Annotate | Line # | Download | only in libiberty
make-relative-prefix.c revision 1.1
      1  1.1  christos /* Relative (relocatable) prefix support.
      2  1.1  christos    Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
      3  1.1  christos    1999, 2000, 2001, 2002, 2006, 2012 Free Software Foundation, Inc.
      4  1.1  christos 
      5  1.1  christos This file is part of libiberty.
      6  1.1  christos 
      7  1.1  christos GCC is free software; you can redistribute it and/or modify it under
      8  1.1  christos the terms of the GNU General Public License as published by the Free
      9  1.1  christos Software Foundation; either version 2, or (at your option) any later
     10  1.1  christos version.
     11  1.1  christos 
     12  1.1  christos GCC is distributed in the hope that it will be useful, but WITHOUT ANY
     13  1.1  christos WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  1.1  christos FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     15  1.1  christos for more details.
     16  1.1  christos 
     17  1.1  christos You should have received a copy of the GNU General Public License
     18  1.1  christos along with GCC; see the file COPYING.  If not, write to the Free
     19  1.1  christos Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
     20  1.1  christos 02110-1301, USA.  */
     21  1.1  christos 
     22  1.1  christos /*
     23  1.1  christos 
     24  1.1  christos @deftypefn Extension {const char*} make_relative_prefix (const char *@var{progname}, @
     25  1.1  christos   const char *@var{bin_prefix}, const char *@var{prefix})
     26  1.1  christos 
     27  1.1  christos Given three paths @var{progname}, @var{bin_prefix}, @var{prefix},
     28  1.1  christos return the path that is in the same position relative to
     29  1.1  christos @var{progname}'s directory as @var{prefix} is relative to
     30  1.1  christos @var{bin_prefix}.  That is, a string starting with the directory
     31  1.1  christos portion of @var{progname}, followed by a relative pathname of the
     32  1.1  christos difference between @var{bin_prefix} and @var{prefix}.
     33  1.1  christos 
     34  1.1  christos If @var{progname} does not contain any directory separators,
     35  1.1  christos @code{make_relative_prefix} will search @env{PATH} to find a program
     36  1.1  christos named @var{progname}.  Also, if @var{progname} is a symbolic link,
     37  1.1  christos the symbolic link will be resolved.
     38  1.1  christos 
     39  1.1  christos For example, if @var{bin_prefix} is @code{/alpha/beta/gamma/gcc/delta},
     40  1.1  christos @var{prefix} is @code{/alpha/beta/gamma/omega/}, and @var{progname} is
     41  1.1  christos @code{/red/green/blue/gcc}, then this function will return
     42  1.1  christos @code{/red/green/blue/../../omega/}.
     43  1.1  christos 
     44  1.1  christos The return value is normally allocated via @code{malloc}.  If no
     45  1.1  christos relative prefix can be found, return @code{NULL}.
     46  1.1  christos 
     47  1.1  christos @end deftypefn
     48  1.1  christos 
     49  1.1  christos */
     50  1.1  christos 
     51  1.1  christos #ifdef HAVE_CONFIG_H
     52  1.1  christos #include "config.h"
     53  1.1  christos #endif
     54  1.1  christos 
     55  1.1  christos #ifdef HAVE_STDLIB_H
     56  1.1  christos #include <stdlib.h>
     57  1.1  christos #endif
     58  1.1  christos #ifdef HAVE_UNISTD_H
     59  1.1  christos #include <unistd.h>
     60  1.1  christos #endif
     61  1.1  christos #ifdef HAVE_SYS_STAT_H
     62  1.1  christos #include <sys/stat.h>
     63  1.1  christos #endif
     64  1.1  christos 
     65  1.1  christos #include <string.h>
     66  1.1  christos 
     67  1.1  christos #include "ansidecl.h"
     68  1.1  christos #include "libiberty.h"
     69  1.1  christos 
     70  1.1  christos #ifndef R_OK
     71  1.1  christos #define R_OK 4
     72  1.1  christos #define W_OK 2
     73  1.1  christos #define X_OK 1
     74  1.1  christos #endif
     75  1.1  christos 
     76  1.1  christos #ifndef DIR_SEPARATOR
     77  1.1  christos #  define DIR_SEPARATOR '/'
     78  1.1  christos #endif
     79  1.1  christos 
     80  1.1  christos #if defined (_WIN32) || defined (__MSDOS__) \
     81  1.1  christos     || defined (__DJGPP__) || defined (__OS2__)
     82  1.1  christos #  define HAVE_DOS_BASED_FILE_SYSTEM
     83  1.1  christos #  define HAVE_HOST_EXECUTABLE_SUFFIX
     84  1.1  christos #  define HOST_EXECUTABLE_SUFFIX ".exe"
     85  1.1  christos #  ifndef DIR_SEPARATOR_2
     86  1.1  christos #    define DIR_SEPARATOR_2 '\\'
     87  1.1  christos #  endif
     88  1.1  christos #  define PATH_SEPARATOR ';'
     89  1.1  christos #else
     90  1.1  christos #  define PATH_SEPARATOR ':'
     91  1.1  christos #endif
     92  1.1  christos 
     93  1.1  christos #ifndef DIR_SEPARATOR_2
     94  1.1  christos #  define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
     95  1.1  christos #else
     96  1.1  christos #  define IS_DIR_SEPARATOR(ch) \
     97  1.1  christos 	(((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
     98  1.1  christos #endif
     99  1.1  christos 
    100  1.1  christos #define DIR_UP ".."
    101  1.1  christos 
    102  1.1  christos static char *save_string (const char *, int);
    103  1.1  christos static char **split_directories	(const char *, int *);
    104  1.1  christos static void free_split_directories (char **);
    105  1.1  christos 
    106  1.1  christos static char *
    107  1.1  christos save_string (const char *s, int len)
    108  1.1  christos {
    109  1.1  christos   char *result = (char *) malloc (len + 1);
    110  1.1  christos 
    111  1.1  christos   memcpy (result, s, len);
    112  1.1  christos   result[len] = 0;
    113  1.1  christos   return result;
    114  1.1  christos }
    115  1.1  christos 
    116  1.1  christos /* Split a filename into component directories.  */
    117  1.1  christos 
    118  1.1  christos static char **
    119  1.1  christos split_directories (const char *name, int *ptr_num_dirs)
    120  1.1  christos {
    121  1.1  christos   int num_dirs = 0;
    122  1.1  christos   char **dirs;
    123  1.1  christos   const char *p, *q;
    124  1.1  christos   int ch;
    125  1.1  christos 
    126  1.1  christos   /* Count the number of directories.  Special case MSDOS disk names as part
    127  1.1  christos      of the initial directory.  */
    128  1.1  christos   p = name;
    129  1.1  christos #ifdef HAVE_DOS_BASED_FILE_SYSTEM
    130  1.1  christos   if (name[1] == ':' && IS_DIR_SEPARATOR (name[2]))
    131  1.1  christos     {
    132  1.1  christos       p += 3;
    133  1.1  christos       num_dirs++;
    134  1.1  christos     }
    135  1.1  christos #endif /* HAVE_DOS_BASED_FILE_SYSTEM */
    136  1.1  christos 
    137  1.1  christos   while ((ch = *p++) != '\0')
    138  1.1  christos     {
    139  1.1  christos       if (IS_DIR_SEPARATOR (ch))
    140  1.1  christos 	{
    141  1.1  christos 	  num_dirs++;
    142  1.1  christos 	  while (IS_DIR_SEPARATOR (*p))
    143  1.1  christos 	    p++;
    144  1.1  christos 	}
    145  1.1  christos     }
    146  1.1  christos 
    147  1.1  christos   dirs = (char **) malloc (sizeof (char *) * (num_dirs + 2));
    148  1.1  christos   if (dirs == NULL)
    149  1.1  christos     return NULL;
    150  1.1  christos 
    151  1.1  christos   /* Now copy the directory parts.  */
    152  1.1  christos   num_dirs = 0;
    153  1.1  christos   p = name;
    154  1.1  christos #ifdef HAVE_DOS_BASED_FILE_SYSTEM
    155  1.1  christos   if (name[1] == ':' && IS_DIR_SEPARATOR (name[2]))
    156  1.1  christos     {
    157  1.1  christos       dirs[num_dirs++] = save_string (p, 3);
    158  1.1  christos       if (dirs[num_dirs - 1] == NULL)
    159  1.1  christos 	{
    160  1.1  christos 	  free (dirs);
    161  1.1  christos 	  return NULL;
    162  1.1  christos 	}
    163  1.1  christos       p += 3;
    164  1.1  christos     }
    165  1.1  christos #endif /* HAVE_DOS_BASED_FILE_SYSTEM */
    166  1.1  christos 
    167  1.1  christos   q = p;
    168  1.1  christos   while ((ch = *p++) != '\0')
    169  1.1  christos     {
    170  1.1  christos       if (IS_DIR_SEPARATOR (ch))
    171  1.1  christos 	{
    172  1.1  christos 	  while (IS_DIR_SEPARATOR (*p))
    173  1.1  christos 	    p++;
    174  1.1  christos 
    175  1.1  christos 	  dirs[num_dirs++] = save_string (q, p - q);
    176  1.1  christos 	  if (dirs[num_dirs - 1] == NULL)
    177  1.1  christos 	    {
    178  1.1  christos 	      dirs[num_dirs] = NULL;
    179  1.1  christos 	      free_split_directories (dirs);
    180  1.1  christos 	      return NULL;
    181  1.1  christos 	    }
    182  1.1  christos 	  q = p;
    183  1.1  christos 	}
    184  1.1  christos     }
    185  1.1  christos 
    186  1.1  christos   if (p - 1 - q > 0)
    187  1.1  christos     dirs[num_dirs++] = save_string (q, p - 1 - q);
    188  1.1  christos   dirs[num_dirs] = NULL;
    189  1.1  christos 
    190  1.1  christos   if (dirs[num_dirs - 1] == NULL)
    191  1.1  christos     {
    192  1.1  christos       free_split_directories (dirs);
    193  1.1  christos       return NULL;
    194  1.1  christos     }
    195  1.1  christos 
    196  1.1  christos   if (ptr_num_dirs)
    197  1.1  christos     *ptr_num_dirs = num_dirs;
    198  1.1  christos   return dirs;
    199  1.1  christos }
    200  1.1  christos 
    201  1.1  christos /* Release storage held by split directories.  */
    202  1.1  christos 
    203  1.1  christos static void
    204  1.1  christos free_split_directories (char **dirs)
    205  1.1  christos {
    206  1.1  christos   int i = 0;
    207  1.1  christos 
    208  1.1  christos   if (dirs != NULL)
    209  1.1  christos     {
    210  1.1  christos       while (dirs[i] != NULL)
    211  1.1  christos 	free (dirs[i++]);
    212  1.1  christos 
    213  1.1  christos       free ((char *) dirs);
    214  1.1  christos     }
    215  1.1  christos }
    216  1.1  christos 
    217  1.1  christos /* Given three strings PROGNAME, BIN_PREFIX, PREFIX, return a string that gets
    218  1.1  christos    to PREFIX starting with the directory portion of PROGNAME and a relative
    219  1.1  christos    pathname of the difference between BIN_PREFIX and PREFIX.
    220  1.1  christos 
    221  1.1  christos    For example, if BIN_PREFIX is /alpha/beta/gamma/gcc/delta, PREFIX is
    222  1.1  christos    /alpha/beta/gamma/omega/, and PROGNAME is /red/green/blue/gcc, then this
    223  1.1  christos    function will return /red/green/blue/../../omega/.
    224  1.1  christos 
    225  1.1  christos    If no relative prefix can be found, return NULL.  */
    226  1.1  christos 
    227  1.1  christos static char *
    228  1.1  christos make_relative_prefix_1 (const char *progname, const char *bin_prefix,
    229  1.1  christos 			const char *prefix, const int resolve_links)
    230  1.1  christos {
    231  1.1  christos   char **prog_dirs = NULL, **bin_dirs = NULL, **prefix_dirs = NULL;
    232  1.1  christos   int prog_num, bin_num, prefix_num;
    233  1.1  christos   int i, n, common;
    234  1.1  christos   int needed_len;
    235  1.1  christos   char *ret = NULL, *ptr, *full_progname;
    236  1.1  christos 
    237  1.1  christos   if (progname == NULL || bin_prefix == NULL || prefix == NULL)
    238  1.1  christos     return NULL;
    239  1.1  christos 
    240  1.1  christos   /* If there is no full pathname, try to find the program by checking in each
    241  1.1  christos      of the directories specified in the PATH environment variable.  */
    242  1.1  christos   if (lbasename (progname) == progname)
    243  1.1  christos     {
    244  1.1  christos       char *temp;
    245  1.1  christos 
    246  1.1  christos       temp = getenv ("PATH");
    247  1.1  christos       if (temp)
    248  1.1  christos 	{
    249  1.1  christos 	  char *startp, *endp, *nstore;
    250  1.1  christos 	  size_t prefixlen = strlen (temp) + 1;
    251  1.1  christos 	  size_t len;
    252  1.1  christos 	  if (prefixlen < 2)
    253  1.1  christos 	    prefixlen = 2;
    254  1.1  christos 
    255  1.1  christos 	  len = prefixlen + strlen (progname) + 1;
    256  1.1  christos #ifdef HAVE_HOST_EXECUTABLE_SUFFIX
    257  1.1  christos 	  len += strlen (HOST_EXECUTABLE_SUFFIX);
    258  1.1  christos #endif
    259  1.1  christos 	  nstore = (char *) alloca (len);
    260  1.1  christos 
    261  1.1  christos 	  startp = endp = temp;
    262  1.1  christos 	  while (1)
    263  1.1  christos 	    {
    264  1.1  christos 	      if (*endp == PATH_SEPARATOR || *endp == 0)
    265  1.1  christos 		{
    266  1.1  christos 		  if (endp == startp)
    267  1.1  christos 		    {
    268  1.1  christos 		      nstore[0] = '.';
    269  1.1  christos 		      nstore[1] = DIR_SEPARATOR;
    270  1.1  christos 		      nstore[2] = '\0';
    271  1.1  christos 		    }
    272  1.1  christos 		  else
    273  1.1  christos 		    {
    274  1.1  christos 		      memcpy (nstore, startp, endp - startp);
    275  1.1  christos 		      if (! IS_DIR_SEPARATOR (endp[-1]))
    276  1.1  christos 			{
    277  1.1  christos 			  nstore[endp - startp] = DIR_SEPARATOR;
    278  1.1  christos 			  nstore[endp - startp + 1] = 0;
    279  1.1  christos 			}
    280  1.1  christos 		      else
    281  1.1  christos 			nstore[endp - startp] = 0;
    282  1.1  christos 		    }
    283  1.1  christos 		  strcat (nstore, progname);
    284  1.1  christos 		  if (! access (nstore, X_OK)
    285  1.1  christos #ifdef HAVE_HOST_EXECUTABLE_SUFFIX
    286  1.1  christos                       || ! access (strcat (nstore, HOST_EXECUTABLE_SUFFIX), X_OK)
    287  1.1  christos #endif
    288  1.1  christos 		      )
    289  1.1  christos 		    {
    290  1.1  christos #if defined (HAVE_SYS_STAT_H) && defined (S_ISREG)
    291  1.1  christos 		      struct stat st;
    292  1.1  christos 		      if (stat (nstore, &st) >= 0 && S_ISREG (st.st_mode))
    293  1.1  christos #endif
    294  1.1  christos 			{
    295  1.1  christos 			  progname = nstore;
    296  1.1  christos 			  break;
    297  1.1  christos 			}
    298  1.1  christos 		    }
    299  1.1  christos 
    300  1.1  christos 		  if (*endp == 0)
    301  1.1  christos 		    break;
    302  1.1  christos 		  endp = startp = endp + 1;
    303  1.1  christos 		}
    304  1.1  christos 	      else
    305  1.1  christos 		endp++;
    306  1.1  christos 	    }
    307  1.1  christos 	}
    308  1.1  christos     }
    309  1.1  christos 
    310  1.1  christos   if (resolve_links)
    311  1.1  christos     full_progname = lrealpath (progname);
    312  1.1  christos   else
    313  1.1  christos     full_progname = strdup (progname);
    314  1.1  christos   if (full_progname == NULL)
    315  1.1  christos     return NULL;
    316  1.1  christos 
    317  1.1  christos   prog_dirs = split_directories (full_progname, &prog_num);
    318  1.1  christos   free (full_progname);
    319  1.1  christos   if (prog_dirs == NULL)
    320  1.1  christos     return NULL;
    321  1.1  christos 
    322  1.1  christos   bin_dirs = split_directories (bin_prefix, &bin_num);
    323  1.1  christos   if (bin_dirs == NULL)
    324  1.1  christos     goto bailout;
    325  1.1  christos 
    326  1.1  christos   /* Remove the program name from comparison of directory names.  */
    327  1.1  christos   prog_num--;
    328  1.1  christos 
    329  1.1  christos   /* If we are still installed in the standard location, we don't need to
    330  1.1  christos      specify relative directories.  Also, if argv[0] still doesn't contain
    331  1.1  christos      any directory specifiers after the search above, then there is not much
    332  1.1  christos      we can do.  */
    333  1.1  christos   if (prog_num == bin_num)
    334  1.1  christos     {
    335  1.1  christos       for (i = 0; i < bin_num; i++)
    336  1.1  christos 	{
    337  1.1  christos 	  if (strcmp (prog_dirs[i], bin_dirs[i]) != 0)
    338  1.1  christos 	    break;
    339  1.1  christos 	}
    340  1.1  christos 
    341  1.1  christos       if (prog_num <= 0 || i == bin_num)
    342  1.1  christos 	goto bailout;
    343  1.1  christos     }
    344  1.1  christos 
    345  1.1  christos   prefix_dirs = split_directories (prefix, &prefix_num);
    346  1.1  christos   if (prefix_dirs == NULL)
    347  1.1  christos     goto bailout;
    348  1.1  christos 
    349  1.1  christos   /* Find how many directories are in common between bin_prefix & prefix.  */
    350  1.1  christos   n = (prefix_num < bin_num) ? prefix_num : bin_num;
    351  1.1  christos   for (common = 0; common < n; common++)
    352  1.1  christos     {
    353  1.1  christos       if (strcmp (bin_dirs[common], prefix_dirs[common]) != 0)
    354  1.1  christos 	break;
    355  1.1  christos     }
    356  1.1  christos 
    357  1.1  christos   /* If there are no common directories, there can be no relative prefix.  */
    358  1.1  christos   if (common == 0)
    359  1.1  christos     goto bailout;
    360  1.1  christos 
    361  1.1  christos   /* Two passes: first figure out the size of the result string, and
    362  1.1  christos      then construct it.  */
    363  1.1  christos   needed_len = 0;
    364  1.1  christos   for (i = 0; i < prog_num; i++)
    365  1.1  christos     needed_len += strlen (prog_dirs[i]);
    366  1.1  christos   needed_len += sizeof (DIR_UP) * (bin_num - common);
    367  1.1  christos   for (i = common; i < prefix_num; i++)
    368  1.1  christos     needed_len += strlen (prefix_dirs[i]);
    369  1.1  christos   needed_len += 1; /* Trailing NUL.  */
    370  1.1  christos 
    371  1.1  christos   ret = (char *) malloc (needed_len);
    372  1.1  christos   if (ret == NULL)
    373  1.1  christos     goto bailout;
    374  1.1  christos 
    375  1.1  christos   /* Build up the pathnames in argv[0].  */
    376  1.1  christos   *ret = '\0';
    377  1.1  christos   for (i = 0; i < prog_num; i++)
    378  1.1  christos     strcat (ret, prog_dirs[i]);
    379  1.1  christos 
    380  1.1  christos   /* Now build up the ..'s.  */
    381  1.1  christos   ptr = ret + strlen(ret);
    382  1.1  christos   for (i = common; i < bin_num; i++)
    383  1.1  christos     {
    384  1.1  christos       strcpy (ptr, DIR_UP);
    385  1.1  christos       ptr += sizeof (DIR_UP) - 1;
    386  1.1  christos       *(ptr++) = DIR_SEPARATOR;
    387  1.1  christos     }
    388  1.1  christos   *ptr = '\0';
    389  1.1  christos 
    390  1.1  christos   /* Put in directories to move over to prefix.  */
    391  1.1  christos   for (i = common; i < prefix_num; i++)
    392  1.1  christos     strcat (ret, prefix_dirs[i]);
    393  1.1  christos 
    394  1.1  christos  bailout:
    395  1.1  christos   free_split_directories (prog_dirs);
    396  1.1  christos   free_split_directories (bin_dirs);
    397  1.1  christos   free_split_directories (prefix_dirs);
    398  1.1  christos 
    399  1.1  christos   return ret;
    400  1.1  christos }
    401  1.1  christos 
    402  1.1  christos 
    403  1.1  christos /* Do the full job, including symlink resolution.
    404  1.1  christos    This path will find files installed in the same place as the
    405  1.1  christos    program even when a soft link has been made to the program
    406  1.1  christos    from somwhere else. */
    407  1.1  christos 
    408  1.1  christos char *
    409  1.1  christos make_relative_prefix (const char *progname, const char *bin_prefix,
    410  1.1  christos 		      const char *prefix)
    411  1.1  christos {
    412  1.1  christos   return make_relative_prefix_1 (progname, bin_prefix, prefix, 1);
    413  1.1  christos }
    414  1.1  christos 
    415  1.1  christos /* Make the relative pathname without attempting to resolve any links.
    416  1.1  christos    '..' etc may also be left in the pathname.
    417  1.1  christos    This will find the files the user meant the program to find if the
    418  1.1  christos    installation is patched together with soft links. */
    419  1.1  christos 
    420  1.1  christos char *
    421  1.1  christos make_relative_prefix_ignore_links (const char *progname,
    422  1.1  christos 				   const char *bin_prefix,
    423  1.1  christos 				   const char *prefix)
    424  1.1  christos {
    425  1.1  christos   return make_relative_prefix_1 (progname, bin_prefix, prefix, 0);
    426  1.1  christos }
    427  1.1  christos 
    428