1130561Sobrien/* Relative (relocatable) prefix support. 2130561Sobrien Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 3218822Sdim 1999, 2000, 2001, 2002, 2006 Free Software Foundation, Inc. 4130561Sobrien 5130561SobrienThis file is part of libiberty. 6130561Sobrien 7130561SobrienGCC is free software; you can redistribute it and/or modify it under 8130561Sobrienthe terms of the GNU General Public License as published by the Free 9130561SobrienSoftware Foundation; either version 2, or (at your option) any later 10130561Sobrienversion. 11130561Sobrien 12130561SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY 13130561SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or 14130561SobrienFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15130561Sobrienfor more details. 16130561Sobrien 17130561SobrienYou should have received a copy of the GNU General Public License 18130561Sobrienalong with GCC; see the file COPYING. If not, write to the Free 19218822SdimSoftware Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 20218822Sdim02110-1301, USA. */ 21130561Sobrien 22130561Sobrien/* 23130561Sobrien 24130561Sobrien@deftypefn Extension {const char*} make_relative_prefix (const char *@var{progname}, const char *@var{bin_prefix}, const char *@var{prefix}) 25130561Sobrien 26130561SobrienGiven three paths @var{progname}, @var{bin_prefix}, @var{prefix}, 27130561Sobrienreturn the path that is in the same position relative to 28130561Sobrien@var{progname}'s directory as @var{prefix} is relative to 29130561Sobrien@var{bin_prefix}. That is, a string starting with the directory 30130561Sobrienportion of @var{progname}, followed by a relative pathname of the 31130561Sobriendifference between @var{bin_prefix} and @var{prefix}. 32130561Sobrien 33130561SobrienIf @var{progname} does not contain any directory separators, 34130561Sobrien@code{make_relative_prefix} will search @env{PATH} to find a program 35130561Sobriennamed @var{progname}. Also, if @var{progname} is a symbolic link, 36130561Sobrienthe symbolic link will be resolved. 37130561Sobrien 38130561SobrienFor example, if @var{bin_prefix} is @code{/alpha/beta/gamma/gcc/delta}, 39130561Sobrien@var{prefix} is @code{/alpha/beta/gamma/omega/}, and @var{progname} is 40130561Sobrien@code{/red/green/blue/gcc}, then this function will return 41130561Sobrien@code{/red/green/blue/../../omega/}. 42130561Sobrien 43130561SobrienThe return value is normally allocated via @code{malloc}. If no 44130561Sobrienrelative prefix can be found, return @code{NULL}. 45130561Sobrien 46130561Sobrien@end deftypefn 47130561Sobrien 48130561Sobrien*/ 49130561Sobrien 50130561Sobrien#ifdef HAVE_CONFIG_H 51130561Sobrien#include "config.h" 52130561Sobrien#endif 53130561Sobrien 54130561Sobrien#ifdef HAVE_STDLIB_H 55130561Sobrien#include <stdlib.h> 56130561Sobrien#endif 57130561Sobrien#ifdef HAVE_UNISTD_H 58130561Sobrien#include <unistd.h> 59130561Sobrien#endif 60130561Sobrien 61130561Sobrien#include <string.h> 62130561Sobrien 63130561Sobrien#include "ansidecl.h" 64130561Sobrien#include "libiberty.h" 65130561Sobrien 66130561Sobrien#ifndef R_OK 67130561Sobrien#define R_OK 4 68130561Sobrien#define W_OK 2 69130561Sobrien#define X_OK 1 70130561Sobrien#endif 71130561Sobrien 72130561Sobrien#ifndef DIR_SEPARATOR 73130561Sobrien# define DIR_SEPARATOR '/' 74130561Sobrien#endif 75130561Sobrien 76130561Sobrien#if defined (_WIN32) || defined (__MSDOS__) \ 77130561Sobrien || defined (__DJGPP__) || defined (__OS2__) 78130561Sobrien# define HAVE_DOS_BASED_FILE_SYSTEM 79130561Sobrien# define HAVE_HOST_EXECUTABLE_SUFFIX 80130561Sobrien# define HOST_EXECUTABLE_SUFFIX ".exe" 81130561Sobrien# ifndef DIR_SEPARATOR_2 82130561Sobrien# define DIR_SEPARATOR_2 '\\' 83130561Sobrien# endif 84130561Sobrien# define PATH_SEPARATOR ';' 85130561Sobrien#else 86130561Sobrien# define PATH_SEPARATOR ':' 87130561Sobrien#endif 88130561Sobrien 89130561Sobrien#ifndef DIR_SEPARATOR_2 90130561Sobrien# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) 91130561Sobrien#else 92130561Sobrien# define IS_DIR_SEPARATOR(ch) \ 93130561Sobrien (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) 94130561Sobrien#endif 95130561Sobrien 96130561Sobrien#define DIR_UP ".." 97130561Sobrien 98218822Sdimstatic char *save_string (const char *, int); 99218822Sdimstatic char **split_directories (const char *, int *); 100218822Sdimstatic void free_split_directories (char **); 101130561Sobrien 102130561Sobrienstatic char * 103218822Sdimsave_string (const char *s, int len) 104130561Sobrien{ 105218822Sdim char *result = (char *) malloc (len + 1); 106130561Sobrien 107130561Sobrien memcpy (result, s, len); 108130561Sobrien result[len] = 0; 109130561Sobrien return result; 110130561Sobrien} 111130561Sobrien 112130561Sobrien/* Split a filename into component directories. */ 113130561Sobrien 114130561Sobrienstatic char ** 115218822Sdimsplit_directories (const char *name, int *ptr_num_dirs) 116130561Sobrien{ 117130561Sobrien int num_dirs = 0; 118130561Sobrien char **dirs; 119130561Sobrien const char *p, *q; 120130561Sobrien int ch; 121130561Sobrien 122130561Sobrien /* Count the number of directories. Special case MSDOS disk names as part 123130561Sobrien of the initial directory. */ 124130561Sobrien p = name; 125130561Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM 126130561Sobrien if (name[1] == ':' && IS_DIR_SEPARATOR (name[2])) 127130561Sobrien { 128130561Sobrien p += 3; 129130561Sobrien num_dirs++; 130130561Sobrien } 131130561Sobrien#endif /* HAVE_DOS_BASED_FILE_SYSTEM */ 132130561Sobrien 133130561Sobrien while ((ch = *p++) != '\0') 134130561Sobrien { 135130561Sobrien if (IS_DIR_SEPARATOR (ch)) 136130561Sobrien { 137130561Sobrien num_dirs++; 138130561Sobrien while (IS_DIR_SEPARATOR (*p)) 139130561Sobrien p++; 140130561Sobrien } 141130561Sobrien } 142130561Sobrien 143130561Sobrien dirs = (char **) malloc (sizeof (char *) * (num_dirs + 2)); 144130561Sobrien if (dirs == NULL) 145130561Sobrien return NULL; 146130561Sobrien 147130561Sobrien /* Now copy the directory parts. */ 148130561Sobrien num_dirs = 0; 149130561Sobrien p = name; 150130561Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM 151130561Sobrien if (name[1] == ':' && IS_DIR_SEPARATOR (name[2])) 152130561Sobrien { 153130561Sobrien dirs[num_dirs++] = save_string (p, 3); 154130561Sobrien if (dirs[num_dirs - 1] == NULL) 155130561Sobrien { 156130561Sobrien free (dirs); 157130561Sobrien return NULL; 158130561Sobrien } 159130561Sobrien p += 3; 160130561Sobrien } 161130561Sobrien#endif /* HAVE_DOS_BASED_FILE_SYSTEM */ 162130561Sobrien 163130561Sobrien q = p; 164130561Sobrien while ((ch = *p++) != '\0') 165130561Sobrien { 166130561Sobrien if (IS_DIR_SEPARATOR (ch)) 167130561Sobrien { 168130561Sobrien while (IS_DIR_SEPARATOR (*p)) 169130561Sobrien p++; 170130561Sobrien 171130561Sobrien dirs[num_dirs++] = save_string (q, p - q); 172130561Sobrien if (dirs[num_dirs - 1] == NULL) 173130561Sobrien { 174130561Sobrien dirs[num_dirs] = NULL; 175130561Sobrien free_split_directories (dirs); 176130561Sobrien return NULL; 177130561Sobrien } 178130561Sobrien q = p; 179130561Sobrien } 180130561Sobrien } 181130561Sobrien 182130561Sobrien if (p - 1 - q > 0) 183130561Sobrien dirs[num_dirs++] = save_string (q, p - 1 - q); 184130561Sobrien dirs[num_dirs] = NULL; 185130561Sobrien 186130561Sobrien if (dirs[num_dirs - 1] == NULL) 187130561Sobrien { 188130561Sobrien free_split_directories (dirs); 189130561Sobrien return NULL; 190130561Sobrien } 191130561Sobrien 192130561Sobrien if (ptr_num_dirs) 193130561Sobrien *ptr_num_dirs = num_dirs; 194130561Sobrien return dirs; 195130561Sobrien} 196130561Sobrien 197130561Sobrien/* Release storage held by split directories. */ 198130561Sobrien 199130561Sobrienstatic void 200218822Sdimfree_split_directories (char **dirs) 201130561Sobrien{ 202130561Sobrien int i = 0; 203130561Sobrien 204130561Sobrien while (dirs[i] != NULL) 205130561Sobrien free (dirs[i++]); 206130561Sobrien 207130561Sobrien free ((char *) dirs); 208130561Sobrien} 209130561Sobrien 210130561Sobrien/* Given three strings PROGNAME, BIN_PREFIX, PREFIX, return a string that gets 211130561Sobrien to PREFIX starting with the directory portion of PROGNAME and a relative 212130561Sobrien pathname of the difference between BIN_PREFIX and PREFIX. 213130561Sobrien 214130561Sobrien For example, if BIN_PREFIX is /alpha/beta/gamma/gcc/delta, PREFIX is 215130561Sobrien /alpha/beta/gamma/omega/, and PROGNAME is /red/green/blue/gcc, then this 216130561Sobrien function will return /red/green/blue/../../omega/. 217130561Sobrien 218130561Sobrien If no relative prefix can be found, return NULL. */ 219130561Sobrien 220218822Sdimstatic char * 221218822Sdimmake_relative_prefix_1 (const char *progname, const char *bin_prefix, 222218822Sdim const char *prefix, const int resolve_links) 223130561Sobrien{ 224130561Sobrien char **prog_dirs, **bin_dirs, **prefix_dirs; 225130561Sobrien int prog_num, bin_num, prefix_num; 226130561Sobrien int i, n, common; 227130561Sobrien int needed_len; 228130561Sobrien char *ret, *ptr, *full_progname = NULL; 229130561Sobrien 230130561Sobrien if (progname == NULL || bin_prefix == NULL || prefix == NULL) 231130561Sobrien return NULL; 232130561Sobrien 233130561Sobrien /* If there is no full pathname, try to find the program by checking in each 234130561Sobrien of the directories specified in the PATH environment variable. */ 235130561Sobrien if (lbasename (progname) == progname) 236130561Sobrien { 237130561Sobrien char *temp; 238130561Sobrien 239130561Sobrien temp = getenv ("PATH"); 240130561Sobrien if (temp) 241130561Sobrien { 242130561Sobrien char *startp, *endp, *nstore; 243130561Sobrien size_t prefixlen = strlen (temp) + 1; 244130561Sobrien if (prefixlen < 2) 245130561Sobrien prefixlen = 2; 246130561Sobrien 247130561Sobrien nstore = (char *) alloca (prefixlen + strlen (progname) + 1); 248130561Sobrien 249130561Sobrien startp = endp = temp; 250130561Sobrien while (1) 251130561Sobrien { 252130561Sobrien if (*endp == PATH_SEPARATOR || *endp == 0) 253130561Sobrien { 254130561Sobrien if (endp == startp) 255130561Sobrien { 256130561Sobrien nstore[0] = '.'; 257130561Sobrien nstore[1] = DIR_SEPARATOR; 258130561Sobrien nstore[2] = '\0'; 259130561Sobrien } 260130561Sobrien else 261130561Sobrien { 262130561Sobrien strncpy (nstore, startp, endp - startp); 263130561Sobrien if (! IS_DIR_SEPARATOR (endp[-1])) 264130561Sobrien { 265130561Sobrien nstore[endp - startp] = DIR_SEPARATOR; 266130561Sobrien nstore[endp - startp + 1] = 0; 267130561Sobrien } 268130561Sobrien else 269130561Sobrien nstore[endp - startp] = 0; 270130561Sobrien } 271130561Sobrien strcat (nstore, progname); 272130561Sobrien if (! access (nstore, X_OK) 273130561Sobrien#ifdef HAVE_HOST_EXECUTABLE_SUFFIX 274130561Sobrien || ! access (strcat (nstore, HOST_EXECUTABLE_SUFFIX), X_OK) 275130561Sobrien#endif 276130561Sobrien ) 277130561Sobrien { 278130561Sobrien progname = nstore; 279130561Sobrien break; 280130561Sobrien } 281130561Sobrien 282130561Sobrien if (*endp == 0) 283130561Sobrien break; 284130561Sobrien endp = startp = endp + 1; 285130561Sobrien } 286130561Sobrien else 287130561Sobrien endp++; 288130561Sobrien } 289130561Sobrien } 290130561Sobrien } 291130561Sobrien 292218822Sdim if ( resolve_links ) 293218822Sdim { 294218822Sdim full_progname = lrealpath (progname); 295218822Sdim if (full_progname == NULL) 296218822Sdim return NULL; 297218822Sdim } 298218822Sdim else 299218822Sdim full_progname = strdup(progname); 300130561Sobrien 301130561Sobrien prog_dirs = split_directories (full_progname, &prog_num); 302130561Sobrien bin_dirs = split_directories (bin_prefix, &bin_num); 303130561Sobrien free (full_progname); 304130561Sobrien if (bin_dirs == NULL || prog_dirs == NULL) 305130561Sobrien return NULL; 306130561Sobrien 307130561Sobrien /* Remove the program name from comparison of directory names. */ 308130561Sobrien prog_num--; 309130561Sobrien 310130561Sobrien /* If we are still installed in the standard location, we don't need to 311130561Sobrien specify relative directories. Also, if argv[0] still doesn't contain 312130561Sobrien any directory specifiers after the search above, then there is not much 313130561Sobrien we can do. */ 314130561Sobrien if (prog_num == bin_num) 315130561Sobrien { 316130561Sobrien for (i = 0; i < bin_num; i++) 317130561Sobrien { 318130561Sobrien if (strcmp (prog_dirs[i], bin_dirs[i]) != 0) 319130561Sobrien break; 320130561Sobrien } 321130561Sobrien 322130561Sobrien if (prog_num <= 0 || i == bin_num) 323130561Sobrien { 324130561Sobrien free_split_directories (prog_dirs); 325130561Sobrien free_split_directories (bin_dirs); 326130561Sobrien prog_dirs = bin_dirs = (char **) 0; 327130561Sobrien return NULL; 328130561Sobrien } 329130561Sobrien } 330130561Sobrien 331130561Sobrien prefix_dirs = split_directories (prefix, &prefix_num); 332130561Sobrien if (prefix_dirs == NULL) 333130561Sobrien { 334130561Sobrien free_split_directories (prog_dirs); 335130561Sobrien free_split_directories (bin_dirs); 336130561Sobrien return NULL; 337130561Sobrien } 338130561Sobrien 339130561Sobrien /* Find how many directories are in common between bin_prefix & prefix. */ 340130561Sobrien n = (prefix_num < bin_num) ? prefix_num : bin_num; 341130561Sobrien for (common = 0; common < n; common++) 342130561Sobrien { 343130561Sobrien if (strcmp (bin_dirs[common], prefix_dirs[common]) != 0) 344130561Sobrien break; 345130561Sobrien } 346130561Sobrien 347130561Sobrien /* If there are no common directories, there can be no relative prefix. */ 348130561Sobrien if (common == 0) 349130561Sobrien { 350130561Sobrien free_split_directories (prog_dirs); 351130561Sobrien free_split_directories (bin_dirs); 352130561Sobrien free_split_directories (prefix_dirs); 353130561Sobrien return NULL; 354130561Sobrien } 355130561Sobrien 356130561Sobrien /* Two passes: first figure out the size of the result string, and 357130561Sobrien then construct it. */ 358130561Sobrien needed_len = 0; 359130561Sobrien for (i = 0; i < prog_num; i++) 360130561Sobrien needed_len += strlen (prog_dirs[i]); 361130561Sobrien needed_len += sizeof (DIR_UP) * (bin_num - common); 362130561Sobrien for (i = common; i < prefix_num; i++) 363130561Sobrien needed_len += strlen (prefix_dirs[i]); 364130561Sobrien needed_len += 1; /* Trailing NUL. */ 365130561Sobrien 366130561Sobrien ret = (char *) malloc (needed_len); 367130561Sobrien if (ret == NULL) 368130561Sobrien return NULL; 369130561Sobrien 370130561Sobrien /* Build up the pathnames in argv[0]. */ 371130561Sobrien *ret = '\0'; 372130561Sobrien for (i = 0; i < prog_num; i++) 373130561Sobrien strcat (ret, prog_dirs[i]); 374130561Sobrien 375130561Sobrien /* Now build up the ..'s. */ 376130561Sobrien ptr = ret + strlen(ret); 377130561Sobrien for (i = common; i < bin_num; i++) 378130561Sobrien { 379130561Sobrien strcpy (ptr, DIR_UP); 380130561Sobrien ptr += sizeof (DIR_UP) - 1; 381130561Sobrien *(ptr++) = DIR_SEPARATOR; 382130561Sobrien } 383130561Sobrien *ptr = '\0'; 384130561Sobrien 385130561Sobrien /* Put in directories to move over to prefix. */ 386130561Sobrien for (i = common; i < prefix_num; i++) 387130561Sobrien strcat (ret, prefix_dirs[i]); 388130561Sobrien 389130561Sobrien free_split_directories (prog_dirs); 390130561Sobrien free_split_directories (bin_dirs); 391130561Sobrien free_split_directories (prefix_dirs); 392130561Sobrien 393130561Sobrien return ret; 394130561Sobrien} 395218822Sdim 396218822Sdim 397218822Sdim/* Do the full job, including symlink resolution. 398218822Sdim This path will find files installed in the same place as the 399218822Sdim program even when a soft link has been made to the program 400218822Sdim from somwhere else. */ 401218822Sdim 402218822Sdimchar * 403218822Sdimmake_relative_prefix (const char *progname, const char *bin_prefix, 404218822Sdim const char *prefix) 405218822Sdim{ 406218822Sdim return make_relative_prefix_1 (progname, bin_prefix, prefix, 1); 407218822Sdim} 408218822Sdim 409218822Sdim/* Make the relative pathname without attempting to resolve any links. 410218822Sdim '..' etc may also be left in the pathname. 411218822Sdim This will find the files the user meant the program to find if the 412218822Sdim installation is patched together with soft links. */ 413218822Sdim 414218822Sdimchar * 415218822Sdimmake_relative_prefix_ignore_links (const char *progname, 416218822Sdim const char *bin_prefix, 417218822Sdim const char *prefix) 418218822Sdim{ 419218822Sdim return make_relative_prefix_1 (progname, bin_prefix, prefix, 0); 420218822Sdim} 421218822Sdim 422