1 /* Provide relocatable packages.
2 Copyright (C) 2003-2006, 2008-2013 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2003.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
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 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
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. */
23 # define _GNU_SOURCE 1
26 #define _GL_USE_STDLIB_ALLOC 1
30 #include "relocatable.h"
32 #if ENABLE_RELOCATABLE
40 # define xmalloc malloc
45 #if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__
46 # define WIN32_LEAN_AND_MEAN
50 #if DEPENDS_ON_LIBCHARSET
51 # include <libcharset.h>
53 #if DEPENDS_ON_LIBICONV && HAVE_ICONV
56 #if DEPENDS_ON_LIBINTL && ENABLE_NLS
60 /* Faked cheap 'bool'. */
69 ISSLASH(C) tests whether C is a directory separator character.
70 IS_PATH_WITH_DIR(P) tests whether P contains a directory specification.
72 #if ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__
73 /* Native Windows, 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')) \
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)
83 # define ISSLASH(C) ((C) == '/')
84 # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
85 # define FILE_SYSTEM_PREFIX_LEN(P) 0
88 /* Whether to enable the more costly support for relocatable libraries.
89 It allows libraries to be have been installed with a different original
90 prefix than the program. But it is quite costly, especially on Cygwin
91 platforms, see below. Therefore we enable it by default only on native
93 #ifndef ENABLE_COSTLY_RELOCATABLE
94 # if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__
95 # define ENABLE_COSTLY_RELOCATABLE 1
97 # define ENABLE_COSTLY_RELOCATABLE 0
101 /* Original installation prefix. */
102 static char *orig_prefix;
103 static size_t orig_prefix_len;
104 /* Current installation prefix. */
105 static char *curr_prefix;
106 static size_t curr_prefix_len;
107 /* These prefixes do not end in a slash. Anything that will be concatenated
108 to them must start with a slash. */
110 /* Sets the original and the current installation prefix of this module.
111 Relocation simply replaces a pathname starting with the original prefix
112 by the corresponding pathname with the current prefix instead. Both
113 prefixes should be directory names without trailing slash (i.e. use ""
116 set_this_relocation_prefix (const char *orig_prefix_arg,
117 const char *curr_prefix_arg)
119 if (orig_prefix_arg != NULL && curr_prefix_arg != NULL
120 /* Optimization: if orig_prefix and curr_prefix are equal, the
121 relocation is a nop. */
122 && strcmp (orig_prefix_arg, curr_prefix_arg) != 0)
124 /* Duplicate the argument strings. */
127 orig_prefix_len = strlen (orig_prefix_arg);
128 curr_prefix_len = strlen (curr_prefix_arg);
129 memory = (char *) xmalloc (orig_prefix_len + 1 + curr_prefix_len + 1);
134 memcpy (memory, orig_prefix_arg, orig_prefix_len + 1);
135 orig_prefix = memory;
136 memory += orig_prefix_len + 1;
137 memcpy (memory, curr_prefix_arg, curr_prefix_len + 1);
138 curr_prefix = memory;
144 /* Don't worry about wasted memory here - this function is usually only
148 /* Sets the original and the current installation prefix of the package.
149 Relocation simply replaces a pathname starting with the original prefix
150 by the corresponding pathname with the current prefix instead. Both
151 prefixes should be directory names without trailing slash (i.e. use ""
154 set_relocation_prefix (const char *orig_prefix_arg, const char *curr_prefix_arg)
156 set_this_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
158 /* Now notify all dependent libraries. */
159 #if DEPENDS_ON_LIBCHARSET
160 libcharset_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
162 #if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109
163 libiconv_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
165 #if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_prefix
166 libintl_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
170 #if !defined IN_LIBRARY || (defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE)
172 /* Convenience function:
173 Computes the current installation prefix, based on the original
174 installation prefix, the original installation directory of a particular
175 file, and the current pathname of this file.
176 Returns it, freshly allocated. Returns NULL upon failure. */
178 #define compute_curr_prefix local_compute_curr_prefix
182 compute_curr_prefix (const char *orig_installprefix,
183 const char *orig_installdir,
184 const char *curr_pathname)
186 char *curr_installdir;
187 const char *rel_installdir;
189 if (curr_pathname == NULL)
192 /* Determine the relative installation directory, relative to the prefix.
193 This is simply the difference between orig_installprefix and
195 if (strncmp (orig_installprefix, orig_installdir, strlen (orig_installprefix))
197 /* Shouldn't happen - nothing should be installed outside $(prefix). */
199 rel_installdir = orig_installdir + strlen (orig_installprefix);
201 /* Determine the current installation directory. */
203 const char *p_base = curr_pathname + FILE_SYSTEM_PREFIX_LEN (curr_pathname);
204 const char *p = curr_pathname + strlen (curr_pathname);
214 q = (char *) xmalloc (p - curr_pathname + 1);
219 memcpy (q, curr_pathname, p - curr_pathname);
220 q[p - curr_pathname] = '\0';
224 /* Compute the current installation prefix by removing the trailing
225 rel_installdir from it. */
227 const char *rp = rel_installdir + strlen (rel_installdir);
228 const char *cp = curr_installdir + strlen (curr_installdir);
229 const char *cp_base =
230 curr_installdir + FILE_SYSTEM_PREFIX_LEN (curr_installdir);
232 while (rp > rel_installdir && cp > cp_base)
235 const char *rpi = rp;
236 const char *cpi = cp;
238 while (rpi > rel_installdir && cpi > cp_base)
242 if (ISSLASH (*rpi) || ISSLASH (*cpi))
244 if (ISSLASH (*rpi) && ISSLASH (*cpi))
248 /* Do case-insensitive comparison if the file system is always or
249 often case-insensitive. It's better to accept the comparison
250 if the difference is only in case, rather than to fail. */
251 #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
252 /* Native Windows, Cygwin, OS/2, DOS - case insignificant file system */
253 if ((*rpi >= 'a' && *rpi <= 'z' ? *rpi - 'a' + 'A' : *rpi)
254 != (*cpi >= 'a' && *cpi <= 'z' ? *cpi - 'a' + 'A' : *cpi))
263 /* The last pathname component was the same. opi and cpi now point
264 to the slash before it. */
269 if (rp > rel_installdir)
271 /* Unexpected: The curr_installdir does not end with rel_installdir. */
272 free (curr_installdir);
277 size_t curr_prefix_len = cp - curr_installdir;
280 curr_prefix = (char *) xmalloc (curr_prefix_len + 1);
282 if (curr_prefix == NULL)
284 free (curr_installdir);
288 memcpy (curr_prefix, curr_installdir, curr_prefix_len);
289 curr_prefix[curr_prefix_len] = '\0';
291 free (curr_installdir);
298 #endif /* !IN_LIBRARY || PIC */
300 #if defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE
302 /* Full pathname of shared library, or NULL. */
303 static char *shared_library_fullname;
305 #if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__
306 /* Native Windows only.
307 On Cygwin, it is better to use the Cygwin provided /proc interface, than
308 to use native Windows API and cygwin_conv_to_posix_path, because it
309 supports longer file names
310 (see <http://cygwin.com/ml/cygwin/2011-01/msg00410.html>). */
312 /* Determine the full pathname of the shared library when it is loaded. */
315 DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved)
319 if (event == DLL_PROCESS_ATTACH)
321 /* The DLL is being loaded into an application's address range. */
322 static char location[MAX_PATH];
324 if (!GetModuleFileName (module_handle, location, sizeof (location)))
325 /* Shouldn't happen. */
328 if (!IS_PATH_WITH_DIR (location))
329 /* Shouldn't happen. */
332 shared_library_fullname = strdup (location);
341 find_shared_library_fullname ()
343 #if (defined __linux__ && (__GLIBC__ >= 2 || defined __UCLIBC__)) || defined __CYGWIN__
344 /* Linux has /proc/self/maps. glibc 2 and uClibc have the getline()
346 Cygwin >= 1.5 has /proc/self/maps and the getline() function too.
347 But it is costly: ca. 0.3 ms on Linux, 3 ms on Cygwin 1.5, and 5 ms on
351 /* Open the current process' maps file. It describes one VMA per line. */
352 fp = fopen ("/proc/self/maps", "r");
355 unsigned long address = (unsigned long) &find_shared_library_fullname;
358 unsigned long start, end;
361 if (fscanf (fp, "%lx-%lx", &start, &end) != 2)
363 if (address >= start && address <= end - 1)
365 /* Found it. Now see if this line contains a filename. */
366 while (c = getc (fp), c != EOF && c != '\n' && c != '/')
374 shared_library_fullname = NULL; size = 0;
375 len = getline (&shared_library_fullname, &size, fp);
378 /* Success: filled shared_library_fullname. */
379 if (len > 0 && shared_library_fullname[len - 1] == '\n')
380 shared_library_fullname[len - 1] = '\0';
385 while (c = getc (fp), c != EOF && c != '\n')
393 #endif /* Native Windows / Unix */
395 /* Return the full pathname of the current shared library.
396 Return NULL if unknown.
397 Guaranteed to work only on Linux, Cygwin, and native Windows. */
399 get_shared_library_fullname ()
401 #if !((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__)
402 static bool tried_find_shared_library_fullname;
403 if (!tried_find_shared_library_fullname)
405 find_shared_library_fullname ();
406 tried_find_shared_library_fullname = true;
409 return shared_library_fullname;
414 /* Returns the pathname, relocated according to the current installation
416 The returned string is either PATHNAME unmodified or a freshly allocated
417 string that you can free with free() after casting it to 'char *'. */
419 relocate (const char *pathname)
421 #if defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE
422 static int initialized;
424 /* Initialization code for a shared library. */
427 /* At this point, orig_prefix and curr_prefix likely have already been
428 set through the main program's set_program_name_and_installdir
429 function. This is sufficient in the case that the library has
430 initially been installed in the same orig_prefix. But we can do
431 better, to also cover the cases that 1. it has been installed
432 in a different prefix before being moved to orig_prefix and (later)
433 to curr_prefix, 2. unlike the program, it has not moved away from
435 const char *orig_installprefix = INSTALLPREFIX;
436 const char *orig_installdir = INSTALLDIR;
437 char *curr_prefix_better;
440 compute_curr_prefix (orig_installprefix, orig_installdir,
441 get_shared_library_fullname ());
443 set_relocation_prefix (orig_installprefix,
444 curr_prefix_better != NULL
448 if (curr_prefix_better != NULL)
449 free (curr_prefix_better);
455 /* Note: It is not necessary to perform case insensitive comparison here,
456 even for DOS-like file systems, because the pathname argument was
457 typically created from the same Makefile variable as orig_prefix came
459 if (orig_prefix != NULL && curr_prefix != NULL
460 && strncmp (pathname, orig_prefix, orig_prefix_len) == 0)
462 if (pathname[orig_prefix_len] == '\0')
464 /* pathname equals orig_prefix. */
465 char *result = (char *) xmalloc (strlen (curr_prefix) + 1);
471 strcpy (result, curr_prefix);
475 else if (ISSLASH (pathname[orig_prefix_len]))
477 /* pathname starts with orig_prefix. */
478 const char *pathname_tail = &pathname[orig_prefix_len];
480 (char *) xmalloc (curr_prefix_len + strlen (pathname_tail) + 1);
486 memcpy (result, curr_prefix, curr_prefix_len);
487 strcpy (result + curr_prefix_len, pathname_tail);
492 /* Nothing to relocate. */