1 /* Provide relocatable packages.
2 Copyright (C) 2003-2006, 2008-2011 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 /* 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')) \
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 /* Original installation prefix. */
89 static char *orig_prefix;
90 static size_t orig_prefix_len;
91 /* Current installation prefix. */
92 static char *curr_prefix;
93 static 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. */
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 ""
103 set_this_relocation_prefix (const char *orig_prefix_arg,
104 const char *curr_prefix_arg)
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)
111 /* Duplicate the argument strings. */
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);
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;
131 /* Don't worry about wasted memory here - this function is usually only
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 ""
141 set_relocation_prefix (const char *orig_prefix_arg, const char *curr_prefix_arg)
143 set_this_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
145 /* Now notify all dependent libraries. */
146 #if DEPENDS_ON_LIBCHARSET
147 libcharset_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
149 #if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109
150 libiconv_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
152 #if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_prefix
153 libintl_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
157 #if !defined IN_LIBRARY || (defined PIC && defined INSTALLDIR)
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. */
165 #define compute_curr_prefix local_compute_curr_prefix
169 compute_curr_prefix (const char *orig_installprefix,
170 const char *orig_installdir,
171 const char *curr_pathname)
173 char *curr_installdir;
174 const char *rel_installdir;
176 if (curr_pathname == NULL)
179 /* Determine the relative installation directory, relative to the prefix.
180 This is simply the difference between orig_installprefix and
182 if (strncmp (orig_installprefix, orig_installdir, strlen (orig_installprefix))
184 /* Shouldn't happen - nothing should be installed outside $(prefix). */
186 rel_installdir = orig_installdir + strlen (orig_installprefix);
188 /* Determine the current installation directory. */
190 const char *p_base = curr_pathname + FILE_SYSTEM_PREFIX_LEN (curr_pathname);
191 const char *p = curr_pathname + strlen (curr_pathname);
201 q = (char *) xmalloc (p - curr_pathname + 1);
206 memcpy (q, curr_pathname, p - curr_pathname);
207 q[p - curr_pathname] = '\0';
211 /* Compute the current installation prefix by removing the trailing
212 rel_installdir from it. */
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);
219 while (rp > rel_installdir && cp > cp_base)
222 const char *rpi = rp;
223 const char *cpi = cp;
225 while (rpi > rel_installdir && cpi > cp_base)
229 if (ISSLASH (*rpi) || ISSLASH (*cpi))
231 if (ISSLASH (*rpi) && ISSLASH (*cpi))
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))
250 /* The last pathname component was the same. opi and cpi now point
251 to the slash before it. */
256 if (rp > rel_installdir)
258 /* Unexpected: The curr_installdir does not end with rel_installdir. */
259 free (curr_installdir);
264 size_t curr_prefix_len = cp - curr_installdir;
267 curr_prefix = (char *) xmalloc (curr_prefix_len + 1);
269 if (curr_prefix == NULL)
271 free (curr_installdir);
275 memcpy (curr_prefix, curr_installdir, curr_prefix_len);
276 curr_prefix[curr_prefix_len] = '\0';
278 free (curr_installdir);
285 #endif /* !IN_LIBRARY || PIC */
287 #if defined PIC && defined INSTALLDIR
289 /* Full pathname of shared library, or NULL. */
290 static char *shared_library_fullname;
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
297 (see <http://cygwin.com/ml/cygwin/2011-01/msg00410.html>). */
299 /* Determine the full pathname of the shared library when it is loaded. */
302 DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved)
306 if (event == DLL_PROCESS_ATTACH)
308 /* The DLL is being loaded into an application's address range. */
309 static char location[MAX_PATH];
311 if (!GetModuleFileName (module_handle, location, sizeof (location)))
312 /* Shouldn't happen. */
315 if (!IS_PATH_WITH_DIR (location))
316 /* Shouldn't happen. */
319 shared_library_fullname = strdup (location);
328 find_shared_library_fullname ()
330 #if (defined __linux__ && (__GLIBC__ >= 2 || defined __UCLIBC__)) || defined __CYGWIN__
331 /* Linux has /proc/self/maps. glibc 2 and uClibc have the getline()
333 Cygwin >= 1.5 has /proc/self/maps and the getline() function too. */
336 /* Open the current process' maps file. It describes one VMA per line. */
337 fp = fopen ("/proc/self/maps", "r");
340 unsigned long address = (unsigned long) &find_shared_library_fullname;
343 unsigned long start, end;
346 if (fscanf (fp, "%lx-%lx", &start, &end) != 2)
348 if (address >= start && address <= end - 1)
350 /* Found it. Now see if this line contains a filename. */
351 while (c = getc (fp), c != EOF && c != '\n' && c != '/')
359 shared_library_fullname = NULL; size = 0;
360 len = getline (&shared_library_fullname, &size, fp);
363 /* Success: filled shared_library_fullname. */
364 if (len > 0 && shared_library_fullname[len - 1] == '\n')
365 shared_library_fullname[len - 1] = '\0';
370 while (c = getc (fp), c != EOF && c != '\n')
378 #endif /* WIN32 / Unix */
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. */
384 get_shared_library_fullname ()
386 #if !((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__)
387 static bool tried_find_shared_library_fullname;
388 if (!tried_find_shared_library_fullname)
390 find_shared_library_fullname ();
391 tried_find_shared_library_fullname = true;
394 return shared_library_fullname;
399 /* Returns the pathname, relocated according to the current installation
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 *'. */
404 relocate (const char *pathname)
406 #if defined PIC && defined INSTALLDIR
407 static int initialized;
409 /* Initialization code for a shared library. */
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
420 const char *orig_installprefix = INSTALLPREFIX;
421 const char *orig_installdir = INSTALLDIR;
422 char *curr_prefix_better;
425 compute_curr_prefix (orig_installprefix, orig_installdir,
426 get_shared_library_fullname ());
428 set_relocation_prefix (orig_installprefix,
429 curr_prefix_better != NULL
433 if (curr_prefix_better != NULL)
434 free (curr_prefix_better);
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
444 if (orig_prefix != NULL && curr_prefix != NULL
445 && strncmp (pathname, orig_prefix, orig_prefix_len) == 0)
447 if (pathname[orig_prefix_len] == '\0')
449 /* pathname equals orig_prefix. */
450 char *result = (char *) xmalloc (strlen (curr_prefix) + 1);
456 strcpy (result, curr_prefix);
460 else if (ISSLASH (pathname[orig_prefix_len]))
462 /* pathname starts with orig_prefix. */
463 const char *pathname_tail = &pathname[orig_prefix_len];
465 (char *) xmalloc (curr_prefix_len + strlen (pathname_tail) + 1);
471 memcpy (result, curr_prefix, curr_prefix_len);
472 strcpy (result + curr_prefix_len, pathname_tail);
477 /* Nothing to relocate. */