1/* Provide relocatable packages. 2 Copyright (C) 2003-2006, 2008-2011 Free Software Foundation, Inc. 3 Written by Bruno Haible <bruno@clisp.org>, 2003. 4 5 This program is free software: you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 17 18 19/* Tell glibc's <stdio.h> to provide a prototype for getline(). 20 This must come before <config.h> because <config.h> may include 21 <features.h>, and once <features.h> has been included, it's too late. */ 22#ifndef _GNU_SOURCE 23# define _GNU_SOURCE 1 24#endif 25 26#define _GL_USE_STDLIB_ALLOC 1 27#include <config.h> 28 29/* Specification. */ 30#include "relocatable.h" 31 32#if ENABLE_RELOCATABLE 33 34#include <stddef.h> 35#include <stdio.h> 36#include <stdlib.h> 37#include <string.h> 38 39#ifdef NO_XMALLOC 40# define xmalloc malloc 41#else 42# include "xalloc.h" 43#endif 44 45#if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__ 46# define WIN32_LEAN_AND_MEAN 47# include <windows.h> 48#endif 49 50#if DEPENDS_ON_LIBCHARSET 51# include <libcharset.h> 52#endif 53#if DEPENDS_ON_LIBICONV && HAVE_ICONV 54# include <iconv.h> 55#endif 56#if DEPENDS_ON_LIBINTL && ENABLE_NLS 57# include <libintl.h> 58#endif 59 60/* Faked cheap 'bool'. */ 61#undef bool 62#undef false 63#undef true 64#define bool int 65#define false 0 66#define true 1 67 68/* Pathname support. 69 ISSLASH(C) tests whether C is a directory separator character. 70 IS_PATH_WITH_DIR(P) tests whether P contains a directory specification. 71 */ 72#if ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__ 73 /* Win32, OS/2, DOS */ 74# define ISSLASH(C) ((C) == '/' || (C) == '\\') 75# define HAS_DEVICE(P) \ 76 ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \ 77 && (P)[1] == ':') 78# define IS_PATH_WITH_DIR(P) \ 79 (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P)) 80# define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0) 81#else 82 /* Unix */ 83# define ISSLASH(C) ((C) == '/') 84# define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL) 85# define FILE_SYSTEM_PREFIX_LEN(P) 0 86#endif 87 88/* Original installation prefix. */ 89static char *orig_prefix; 90static size_t orig_prefix_len; 91/* Current installation prefix. */ 92static char *curr_prefix; 93static size_t curr_prefix_len; 94/* These prefixes do not end in a slash. Anything that will be concatenated 95 to them must start with a slash. */ 96 97/* Sets the original and the current installation prefix of this module. 98 Relocation simply replaces a pathname starting with the original prefix 99 by the corresponding pathname with the current prefix instead. Both 100 prefixes should be directory names without trailing slash (i.e. use "" 101 instead of "/"). */ 102static void 103set_this_relocation_prefix (const char *orig_prefix_arg, 104 const char *curr_prefix_arg) 105{ 106 if (orig_prefix_arg != NULL && curr_prefix_arg != NULL 107 /* Optimization: if orig_prefix and curr_prefix are equal, the 108 relocation is a nop. */ 109 && strcmp (orig_prefix_arg, curr_prefix_arg) != 0) 110 { 111 /* Duplicate the argument strings. */ 112 char *memory; 113 114 orig_prefix_len = strlen (orig_prefix_arg); 115 curr_prefix_len = strlen (curr_prefix_arg); 116 memory = (char *) xmalloc (orig_prefix_len + 1 + curr_prefix_len + 1); 117#ifdef NO_XMALLOC 118 if (memory != NULL) 119#endif 120 { 121 memcpy (memory, orig_prefix_arg, orig_prefix_len + 1); 122 orig_prefix = memory; 123 memory += orig_prefix_len + 1; 124 memcpy (memory, curr_prefix_arg, curr_prefix_len + 1); 125 curr_prefix = memory; 126 return; 127 } 128 } 129 orig_prefix = NULL; 130 curr_prefix = NULL; 131 /* Don't worry about wasted memory here - this function is usually only 132 called once. */ 133} 134 135/* Sets the original and the current installation prefix of the package. 136 Relocation simply replaces a pathname starting with the original prefix 137 by the corresponding pathname with the current prefix instead. Both 138 prefixes should be directory names without trailing slash (i.e. use "" 139 instead of "/"). */ 140void 141set_relocation_prefix (const char *orig_prefix_arg, const char *curr_prefix_arg) 142{ 143 set_this_relocation_prefix (orig_prefix_arg, curr_prefix_arg); 144 145 /* Now notify all dependent libraries. */ 146#if DEPENDS_ON_LIBCHARSET 147 libcharset_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg); 148#endif 149#if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109 150 libiconv_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg); 151#endif 152#if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_prefix 153 libintl_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg); 154#endif 155} 156 157#if !defined IN_LIBRARY || (defined PIC && defined INSTALLDIR) 158 159/* Convenience function: 160 Computes the current installation prefix, based on the original 161 installation prefix, the original installation directory of a particular 162 file, and the current pathname of this file. 163 Returns it, freshly allocated. Returns NULL upon failure. */ 164#ifdef IN_LIBRARY 165#define compute_curr_prefix local_compute_curr_prefix 166static 167#endif 168char * 169compute_curr_prefix (const char *orig_installprefix, 170 const char *orig_installdir, 171 const char *curr_pathname) 172{ 173 char *curr_installdir; 174 const char *rel_installdir; 175 176 if (curr_pathname == NULL) 177 return NULL; 178 179 /* Determine the relative installation directory, relative to the prefix. 180 This is simply the difference between orig_installprefix and 181 orig_installdir. */ 182 if (strncmp (orig_installprefix, orig_installdir, strlen (orig_installprefix)) 183 != 0) 184 /* Shouldn't happen - nothing should be installed outside $(prefix). */ 185 return NULL; 186 rel_installdir = orig_installdir + strlen (orig_installprefix); 187 188 /* Determine the current installation directory. */ 189 { 190 const char *p_base = curr_pathname + FILE_SYSTEM_PREFIX_LEN (curr_pathname); 191 const char *p = curr_pathname + strlen (curr_pathname); 192 char *q; 193 194 while (p > p_base) 195 { 196 p--; 197 if (ISSLASH (*p)) 198 break; 199 } 200 201 q = (char *) xmalloc (p - curr_pathname + 1); 202#ifdef NO_XMALLOC 203 if (q == NULL) 204 return NULL; 205#endif 206 memcpy (q, curr_pathname, p - curr_pathname); 207 q[p - curr_pathname] = '\0'; 208 curr_installdir = q; 209 } 210 211 /* Compute the current installation prefix by removing the trailing 212 rel_installdir from it. */ 213 { 214 const char *rp = rel_installdir + strlen (rel_installdir); 215 const char *cp = curr_installdir + strlen (curr_installdir); 216 const char *cp_base = 217 curr_installdir + FILE_SYSTEM_PREFIX_LEN (curr_installdir); 218 219 while (rp > rel_installdir && cp > cp_base) 220 { 221 bool same = false; 222 const char *rpi = rp; 223 const char *cpi = cp; 224 225 while (rpi > rel_installdir && cpi > cp_base) 226 { 227 rpi--; 228 cpi--; 229 if (ISSLASH (*rpi) || ISSLASH (*cpi)) 230 { 231 if (ISSLASH (*rpi) && ISSLASH (*cpi)) 232 same = true; 233 break; 234 } 235 /* Do case-insensitive comparison if the file system is always or 236 often case-insensitive. It's better to accept the comparison 237 if the difference is only in case, rather than to fail. */ 238#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__ 239 /* Win32, Cygwin, OS/2, DOS - case insignificant file system */ 240 if ((*rpi >= 'a' && *rpi <= 'z' ? *rpi - 'a' + 'A' : *rpi) 241 != (*cpi >= 'a' && *cpi <= 'z' ? *cpi - 'a' + 'A' : *cpi)) 242 break; 243#else 244 if (*rpi != *cpi) 245 break; 246#endif 247 } 248 if (!same) 249 break; 250 /* The last pathname component was the same. opi and cpi now point 251 to the slash before it. */ 252 rp = rpi; 253 cp = cpi; 254 } 255 256 if (rp > rel_installdir) 257 { 258 /* Unexpected: The curr_installdir does not end with rel_installdir. */ 259 free (curr_installdir); 260 return NULL; 261 } 262 263 { 264 size_t curr_prefix_len = cp - curr_installdir; 265 char *curr_prefix; 266 267 curr_prefix = (char *) xmalloc (curr_prefix_len + 1); 268#ifdef NO_XMALLOC 269 if (curr_prefix == NULL) 270 { 271 free (curr_installdir); 272 return NULL; 273 } 274#endif 275 memcpy (curr_prefix, curr_installdir, curr_prefix_len); 276 curr_prefix[curr_prefix_len] = '\0'; 277 278 free (curr_installdir); 279 280 return curr_prefix; 281 } 282 } 283} 284 285#endif /* !IN_LIBRARY || PIC */ 286 287#if defined PIC && defined INSTALLDIR 288 289/* Full pathname of shared library, or NULL. */ 290static char *shared_library_fullname; 291 292#if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__ 293/* Native Win32 only. 294 On Cygwin, it is better to use the Cygwin provided /proc interface, than 295 to use native Win32 API and cygwin_conv_to_posix_path, because it supports 296 longer file names 297 (see <http://cygwin.com/ml/cygwin/2011-01/msg00410.html>). */ 298 299/* Determine the full pathname of the shared library when it is loaded. */ 300 301BOOL WINAPI 302DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved) 303{ 304 (void) reserved; 305 306 if (event == DLL_PROCESS_ATTACH) 307 { 308 /* The DLL is being loaded into an application's address range. */ 309 static char location[MAX_PATH]; 310 311 if (!GetModuleFileName (module_handle, location, sizeof (location))) 312 /* Shouldn't happen. */ 313 return FALSE; 314 315 if (!IS_PATH_WITH_DIR (location)) 316 /* Shouldn't happen. */ 317 return FALSE; 318 319 shared_library_fullname = strdup (location); 320 } 321 322 return TRUE; 323} 324 325#else /* Unix */ 326 327static void 328find_shared_library_fullname () 329{ 330#if (defined __linux__ && (__GLIBC__ >= 2 || defined __UCLIBC__)) || defined __CYGWIN__ 331 /* Linux has /proc/self/maps. glibc 2 and uClibc have the getline() 332 function. 333 Cygwin >= 1.5 has /proc/self/maps and the getline() function too. */ 334 FILE *fp; 335 336 /* Open the current process' maps file. It describes one VMA per line. */ 337 fp = fopen ("/proc/self/maps", "r"); 338 if (fp) 339 { 340 unsigned long address = (unsigned long) &find_shared_library_fullname; 341 for (;;) 342 { 343 unsigned long start, end; 344 int c; 345 346 if (fscanf (fp, "%lx-%lx", &start, &end) != 2) 347 break; 348 if (address >= start && address <= end - 1) 349 { 350 /* Found it. Now see if this line contains a filename. */ 351 while (c = getc (fp), c != EOF && c != '\n' && c != '/') 352 continue; 353 if (c == '/') 354 { 355 size_t size; 356 int len; 357 358 ungetc (c, fp); 359 shared_library_fullname = NULL; size = 0; 360 len = getline (&shared_library_fullname, &size, fp); 361 if (len >= 0) 362 { 363 /* Success: filled shared_library_fullname. */ 364 if (len > 0 && shared_library_fullname[len - 1] == '\n') 365 shared_library_fullname[len - 1] = '\0'; 366 } 367 } 368 break; 369 } 370 while (c = getc (fp), c != EOF && c != '\n') 371 continue; 372 } 373 fclose (fp); 374 } 375#endif 376} 377 378#endif /* WIN32 / Unix */ 379 380/* Return the full pathname of the current shared library. 381 Return NULL if unknown. 382 Guaranteed to work only on Linux, Cygwin and Woe32. */ 383static char * 384get_shared_library_fullname () 385{ 386#if !((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) 387 static bool tried_find_shared_library_fullname; 388 if (!tried_find_shared_library_fullname) 389 { 390 find_shared_library_fullname (); 391 tried_find_shared_library_fullname = true; 392 } 393#endif 394 return shared_library_fullname; 395} 396 397#endif /* PIC */ 398 399/* Returns the pathname, relocated according to the current installation 400 directory. 401 The returned string is either PATHNAME unmodified or a freshly allocated 402 string that you can free with free() after casting it to 'char *'. */ 403const char * 404relocate (const char *pathname) 405{ 406#if defined PIC && defined INSTALLDIR 407 static int initialized; 408 409 /* Initialization code for a shared library. */ 410 if (!initialized) 411 { 412 /* At this point, orig_prefix and curr_prefix likely have already been 413 set through the main program's set_program_name_and_installdir 414 function. This is sufficient in the case that the library has 415 initially been installed in the same orig_prefix. But we can do 416 better, to also cover the cases that 1. it has been installed 417 in a different prefix before being moved to orig_prefix and (later) 418 to curr_prefix, 2. unlike the program, it has not moved away from 419 orig_prefix. */ 420 const char *orig_installprefix = INSTALLPREFIX; 421 const char *orig_installdir = INSTALLDIR; 422 char *curr_prefix_better; 423 424 curr_prefix_better = 425 compute_curr_prefix (orig_installprefix, orig_installdir, 426 get_shared_library_fullname ()); 427 428 set_relocation_prefix (orig_installprefix, 429 curr_prefix_better != NULL 430 ? curr_prefix_better 431 : curr_prefix); 432 433 if (curr_prefix_better != NULL) 434 free (curr_prefix_better); 435 436 initialized = 1; 437 } 438#endif 439 440 /* Note: It is not necessary to perform case insensitive comparison here, 441 even for DOS-like file systems, because the pathname argument was 442 typically created from the same Makefile variable as orig_prefix came 443 from. */ 444 if (orig_prefix != NULL && curr_prefix != NULL 445 && strncmp (pathname, orig_prefix, orig_prefix_len) == 0) 446 { 447 if (pathname[orig_prefix_len] == '\0') 448 { 449 /* pathname equals orig_prefix. */ 450 char *result = (char *) xmalloc (strlen (curr_prefix) + 1); 451 452#ifdef NO_XMALLOC 453 if (result != NULL) 454#endif 455 { 456 strcpy (result, curr_prefix); 457 return result; 458 } 459 } 460 else if (ISSLASH (pathname[orig_prefix_len])) 461 { 462 /* pathname starts with orig_prefix. */ 463 const char *pathname_tail = &pathname[orig_prefix_len]; 464 char *result = 465 (char *) xmalloc (curr_prefix_len + strlen (pathname_tail) + 1); 466 467#ifdef NO_XMALLOC 468 if (result != NULL) 469#endif 470 { 471 memcpy (result, curr_prefix, curr_prefix_len); 472 strcpy (result + curr_prefix_len, pathname_tail); 473 return result; 474 } 475 } 476 } 477 /* Nothing to relocate. */ 478 return pathname; 479} 480 481#endif 482