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 it
6
under the terms of the GNU Library General Public License as published
7
by the Free Software Foundation; either version 2, or (at your option)
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 GNU
13
Library General Public License for more details.
15
You should have received a copy of the GNU Library General Public
16
License along with this program; if not, write to the Free Software
17
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
21
/* Tell glibc's <stdio.h> to provide a prototype for getline().
22
This must come before <config.h> because <config.h> may include
23
<features.h>, and once <features.h> has been included, it's too late. */
25
# define _GNU_SOURCE 1
28
#define _GL_USE_STDLIB_ALLOC 1
32
#include "relocatable.h"
34
#if ENABLE_RELOCATABLE
42
# define xmalloc malloc
47
#if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__
48
# define WIN32_LEAN_AND_MEAN
52
#if DEPENDS_ON_LIBCHARSET
53
# include <libcharset.h>
55
#if DEPENDS_ON_LIBICONV && HAVE_ICONV
58
#if DEPENDS_ON_LIBINTL && ENABLE_NLS
62
/* Faked cheap 'bool'. */
71
ISSLASH(C) tests whether C is a directory separator character.
72
IS_PATH_WITH_DIR(P) tests whether P contains a directory specification.
74
#if ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__
75
/* Win32, OS/2, DOS */
76
# define ISSLASH(C) ((C) == '/' || (C) == '\\')
77
# define HAS_DEVICE(P) \
78
((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
80
# define IS_PATH_WITH_DIR(P) \
81
(strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
82
# define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
85
# define ISSLASH(C) ((C) == '/')
86
# define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
87
# define FILE_SYSTEM_PREFIX_LEN(P) 0
90
/* Original installation prefix. */
91
static char *orig_prefix;
92
static size_t orig_prefix_len;
93
/* Current installation prefix. */
94
static char *curr_prefix;
95
static size_t curr_prefix_len;
96
/* These prefixes do not end in a slash. Anything that will be concatenated
97
to them must start with a slash. */
99
/* Sets the original and the current installation prefix of this module.
100
Relocation simply replaces a pathname starting with the original prefix
101
by the corresponding pathname with the current prefix instead. Both
102
prefixes should be directory names without trailing slash (i.e. use ""
105
set_this_relocation_prefix (const char *orig_prefix_arg,
106
const char *curr_prefix_arg)
108
if (orig_prefix_arg != NULL && curr_prefix_arg != NULL
109
/* Optimization: if orig_prefix and curr_prefix are equal, the
110
relocation is a nop. */
111
&& strcmp (orig_prefix_arg, curr_prefix_arg) != 0)
113
/* Duplicate the argument strings. */
116
orig_prefix_len = strlen (orig_prefix_arg);
117
curr_prefix_len = strlen (curr_prefix_arg);
118
memory = (char *) xmalloc (orig_prefix_len + 1 + curr_prefix_len + 1);
123
memcpy (memory, orig_prefix_arg, orig_prefix_len + 1);
124
orig_prefix = memory;
125
memory += orig_prefix_len + 1;
126
memcpy (memory, curr_prefix_arg, curr_prefix_len + 1);
127
curr_prefix = memory;
133
/* Don't worry about wasted memory here - this function is usually only
137
/* Sets the original and the current installation prefix of the package.
138
Relocation simply replaces a pathname starting with the original prefix
139
by the corresponding pathname with the current prefix instead. Both
140
prefixes should be directory names without trailing slash (i.e. use ""
143
set_relocation_prefix (const char *orig_prefix_arg, const char *curr_prefix_arg)
145
set_this_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
147
/* Now notify all dependent libraries. */
148
#if DEPENDS_ON_LIBCHARSET
149
libcharset_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
151
#if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109
152
libiconv_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
154
#if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_prefix
155
libintl_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
159
#if !defined IN_LIBRARY || (defined PIC && defined INSTALLDIR)
161
/* Convenience function:
162
Computes the current installation prefix, based on the original
163
installation prefix, the original installation directory of a particular
164
file, and the current pathname of this file.
165
Returns it, freshly allocated. Returns NULL upon failure. */
167
#define compute_curr_prefix local_compute_curr_prefix
171
compute_curr_prefix (const char *orig_installprefix,
172
const char *orig_installdir,
173
const char *curr_pathname)
175
char *curr_installdir;
176
const char *rel_installdir;
178
if (curr_pathname == NULL)
181
/* Determine the relative installation directory, relative to the prefix.
182
This is simply the difference between orig_installprefix and
184
if (strncmp (orig_installprefix, orig_installdir, strlen (orig_installprefix))
186
/* Shouldn't happen - nothing should be installed outside $(prefix). */
188
rel_installdir = orig_installdir + strlen (orig_installprefix);
190
/* Determine the current installation directory. */
192
const char *p_base = curr_pathname + FILE_SYSTEM_PREFIX_LEN (curr_pathname);
193
const char *p = curr_pathname + strlen (curr_pathname);
203
q = (char *) xmalloc (p - curr_pathname + 1);
208
memcpy (q, curr_pathname, p - curr_pathname);
209
q[p - curr_pathname] = '\0';
213
/* Compute the current installation prefix by removing the trailing
214
rel_installdir from it. */
216
const char *rp = rel_installdir + strlen (rel_installdir);
217
const char *cp = curr_installdir + strlen (curr_installdir);
218
const char *cp_base =
219
curr_installdir + FILE_SYSTEM_PREFIX_LEN (curr_installdir);
221
while (rp > rel_installdir && cp > cp_base)
224
const char *rpi = rp;
225
const char *cpi = cp;
227
while (rpi > rel_installdir && cpi > cp_base)
231
if (ISSLASH (*rpi) || ISSLASH (*cpi))
233
if (ISSLASH (*rpi) && ISSLASH (*cpi))
237
/* Do case-insensitive comparison if the file system is always or
238
often case-insensitive. It's better to accept the comparison
239
if the difference is only in case, rather than to fail. */
240
#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
241
/* Win32, Cygwin, OS/2, DOS - case insignificant file system */
242
if ((*rpi >= 'a' && *rpi <= 'z' ? *rpi - 'a' + 'A' : *rpi)
243
!= (*cpi >= 'a' && *cpi <= 'z' ? *cpi - 'a' + 'A' : *cpi))
252
/* The last pathname component was the same. opi and cpi now point
253
to the slash before it. */
258
if (rp > rel_installdir)
260
/* Unexpected: The curr_installdir does not end with rel_installdir. */
261
free (curr_installdir);
266
size_t curr_prefix_len = cp - curr_installdir;
269
curr_prefix = (char *) xmalloc (curr_prefix_len + 1);
271
if (curr_prefix == NULL)
273
free (curr_installdir);
277
memcpy (curr_prefix, curr_installdir, curr_prefix_len);
278
curr_prefix[curr_prefix_len] = '\0';
280
free (curr_installdir);
287
#endif /* !IN_LIBRARY || PIC */
289
#if defined PIC && defined INSTALLDIR
291
/* Full pathname of shared library, or NULL. */
292
static char *shared_library_fullname;
294
#if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__
295
/* Native Win32 only.
296
On Cygwin, it is better to use the Cygwin provided /proc interface, than
297
to use native Win32 API and cygwin_conv_to_posix_path, because it supports
299
(see <http://cygwin.com/ml/cygwin/2011-01/msg00410.html>). */
301
/* Determine the full pathname of the shared library when it is loaded. */
304
DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved)
308
if (event == DLL_PROCESS_ATTACH)
310
/* The DLL is being loaded into an application's address range. */
311
static char location[MAX_PATH];
313
if (!GetModuleFileName (module_handle, location, sizeof (location)))
314
/* Shouldn't happen. */
317
if (!IS_PATH_WITH_DIR (location))
318
/* Shouldn't happen. */
321
shared_library_fullname = strdup (location);
330
find_shared_library_fullname ()
332
#if (defined __linux__ && (__GLIBC__ >= 2 || defined __UCLIBC__)) || defined __CYGWIN__
333
/* Linux has /proc/self/maps. glibc 2 and uClibc have the getline()
335
Cygwin >= 1.5 has /proc/self/maps and the getline() function too. */
338
/* Open the current process' maps file. It describes one VMA per line. */
339
fp = fopen ("/proc/self/maps", "r");
342
unsigned long address = (unsigned long) &find_shared_library_fullname;
345
unsigned long start, end;
348
if (fscanf (fp, "%lx-%lx", &start, &end) != 2)
350
if (address >= start && address <= end - 1)
352
/* Found it. Now see if this line contains a filename. */
353
while (c = getc (fp), c != EOF && c != '\n' && c != '/')
361
shared_library_fullname = NULL; size = 0;
362
len = getline (&shared_library_fullname, &size, fp);
365
/* Success: filled shared_library_fullname. */
366
if (len > 0 && shared_library_fullname[len - 1] == '\n')
367
shared_library_fullname[len - 1] = '\0';
372
while (c = getc (fp), c != EOF && c != '\n')
380
#endif /* WIN32 / Unix */
382
/* Return the full pathname of the current shared library.
383
Return NULL if unknown.
384
Guaranteed to work only on Linux, Cygwin and Woe32. */
386
get_shared_library_fullname ()
388
#if !((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__)
389
static bool tried_find_shared_library_fullname;
390
if (!tried_find_shared_library_fullname)
392
find_shared_library_fullname ();
393
tried_find_shared_library_fullname = true;
396
return shared_library_fullname;
401
/* Returns the pathname, relocated according to the current installation
403
The returned string is either PATHNAME unmodified or a freshly allocated
404
string that you can free with free() after casting it to 'char *'. */
406
relocate (const char *pathname)
408
#if defined PIC && defined INSTALLDIR
409
static int initialized;
411
/* Initialization code for a shared library. */
414
/* At this point, orig_prefix and curr_prefix likely have already been
415
set through the main program's set_program_name_and_installdir
416
function. This is sufficient in the case that the library has
417
initially been installed in the same orig_prefix. But we can do
418
better, to also cover the cases that 1. it has been installed
419
in a different prefix before being moved to orig_prefix and (later)
420
to curr_prefix, 2. unlike the program, it has not moved away from
422
const char *orig_installprefix = INSTALLPREFIX;
423
const char *orig_installdir = INSTALLDIR;
424
char *curr_prefix_better;
427
compute_curr_prefix (orig_installprefix, orig_installdir,
428
get_shared_library_fullname ());
430
set_relocation_prefix (orig_installprefix,
431
curr_prefix_better != NULL
435
if (curr_prefix_better != NULL)
436
free (curr_prefix_better);
442
/* Note: It is not necessary to perform case insensitive comparison here,
443
even for DOS-like file systems, because the pathname argument was
444
typically created from the same Makefile variable as orig_prefix came
446
if (orig_prefix != NULL && curr_prefix != NULL
447
&& strncmp (pathname, orig_prefix, orig_prefix_len) == 0)
449
if (pathname[orig_prefix_len] == '\0')
451
/* pathname equals orig_prefix. */
452
char *result = (char *) xmalloc (strlen (curr_prefix) + 1);
458
strcpy (result, curr_prefix);
462
else if (ISSLASH (pathname[orig_prefix_len]))
464
/* pathname starts with orig_prefix. */
465
const char *pathname_tail = &pathname[orig_prefix_len];
467
(char *) xmalloc (curr_prefix_len + strlen (pathname_tail) + 1);
473
memcpy (result, curr_prefix, curr_prefix_len);
474
strcpy (result + curr_prefix_len, pathname_tail);
479
/* Nothing to relocate. */