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