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