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