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