1
/* Provide relocatable packages.
2
Copyright (C) 2003 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
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
33
#include "relocatable.h"
35
#if ENABLE_RELOCATABLE
43
# define xmalloc malloc
48
#if defined _WIN32 || defined __WIN32__
49
# define WIN32_LEAN_AND_MEAN
53
#if DEPENDS_ON_LIBCHARSET
54
# include <libcharset.h>
56
#if DEPENDS_ON_LIBICONV && HAVE_ICONV
59
#if DEPENDS_ON_LIBINTL && ENABLE_NLS
63
/* Faked cheap 'bool'. */
72
ISSLASH(C) tests whether C is a directory separator character.
73
IS_PATH_WITH_DIR(P) tests whether P contains a directory specification.
75
#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
76
/* Win32, OS/2, DOS */
77
# define ISSLASH(C) ((C) == '/' || (C) == '\\')
78
# define HAS_DEVICE(P) \
79
((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
81
# define IS_PATH_WITH_DIR(P) \
82
(strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
83
# define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
86
# define ISSLASH(C) ((C) == '/')
87
# define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
88
# define FILESYSTEM_PREFIX_LEN(P) 0
91
/* Original installation prefix. */
92
static char *orig_prefix;
93
static size_t orig_prefix_len;
94
/* Current installation prefix. */
95
static char *curr_prefix;
96
static size_t curr_prefix_len;
97
/* These prefixes do not end in a slash. Anything that will be concatenated
98
to them must start with a slash. */
100
/* Sets the original and the current installation prefix of this module.
101
Relocation simply replaces a pathname starting with the original prefix
102
by the corresponding pathname with the current prefix instead. Both
103
prefixes should be directory names without trailing slash (i.e. use ""
106
set_this_relocation_prefix (const char *orig_prefix_arg,
107
const char *curr_prefix_arg)
109
if (orig_prefix_arg != NULL && curr_prefix_arg != NULL
110
/* Optimization: if orig_prefix and curr_prefix are equal, the
111
relocation is a nop. */
112
&& strcmp (orig_prefix_arg, curr_prefix_arg) != 0)
114
/* Duplicate the argument strings. */
117
orig_prefix_len = strlen (orig_prefix_arg);
118
curr_prefix_len = strlen (curr_prefix_arg);
119
memory = (char *) xmalloc (orig_prefix_len + 1 + curr_prefix_len + 1);
124
memcpy (memory, orig_prefix_arg, orig_prefix_len + 1);
125
orig_prefix = memory;
126
memory += orig_prefix_len + 1;
127
memcpy (memory, curr_prefix_arg, curr_prefix_len + 1);
128
curr_prefix = memory;
134
/* Don't worry about wasted memory here - this function is usually only
138
/* Sets the original and the current installation prefix of the package.
139
Relocation simply replaces a pathname starting with the original prefix
140
by the corresponding pathname with the current prefix instead. Both
141
prefixes should be directory names without trailing slash (i.e. use ""
144
set_relocation_prefix (const char *orig_prefix_arg, const char *curr_prefix_arg)
146
set_this_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
148
/* Now notify all dependent libraries. */
149
#if DEPENDS_ON_LIBCHARSET
150
libcharset_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
152
#if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109
153
libiconv_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
155
#if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_prefix
156
libintl_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
160
#if !defined IN_LIBRARY || (defined PIC && defined INSTALLDIR)
162
/* Convenience function:
163
Computes the current installation prefix, based on the original
164
installation prefix, the original installation directory of a particular
165
file, and the current pathname of this file. 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
const 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 + FILESYSTEM_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 + FILESYSTEM_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
#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
238
/* Win32, OS/2, DOS - case insignificant filesystem */
239
if ((*rpi >= 'a' && *rpi <= 'z' ? *rpi - 'a' + 'A' : *rpi)
240
!= (*cpi >= 'a' && *cpi <= 'z' ? *cpi - 'a' + 'A' : *cpi))
249
/* The last pathname component was the same. opi and cpi now point
250
to the slash before it. */
255
if (rp > rel_installdir)
256
/* Unexpected: The curr_installdir does not end with rel_installdir. */
260
size_t curr_prefix_len = cp - curr_installdir;
263
curr_prefix = (char *) xmalloc (curr_prefix_len + 1);
265
if (curr_prefix == NULL)
268
memcpy (curr_prefix, curr_installdir, curr_prefix_len);
269
curr_prefix[curr_prefix_len] = '\0';
276
#endif /* !IN_LIBRARY || PIC */
278
#if defined PIC && defined INSTALLDIR
280
/* Full pathname of shared library, or NULL. */
281
static char *shared_library_fullname;
283
#if defined _WIN32 || defined __WIN32__
285
/* Determine the full pathname of the shared library when it is loaded. */
288
DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved)
292
if (event == DLL_PROCESS_ATTACH)
294
/* The DLL is being loaded into an application's address range. */
295
static char location[MAX_PATH];
297
if (!GetModuleFileName (module_handle, location, sizeof (location)))
298
/* Shouldn't happen. */
301
if (!IS_PATH_WITH_DIR (location))
302
/* Shouldn't happen. */
305
shared_library_fullname = strdup (location);
314
find_shared_library_fullname ()
316
#if defined __linux__ && __GLIBC__ >= 2
317
/* Linux has /proc/self/maps. glibc 2 has the getline() function. */
320
/* Open the current process' maps file. It describes one VMA per line. */
321
fp = fopen ("/proc/self/maps", "r");
324
unsigned long address = (unsigned long) &find_shared_library_fullname;
327
unsigned long start, end;
330
if (fscanf (fp, "%lx-%lx", &start, &end) != 2)
332
if (address >= start && address <= end - 1)
334
/* Found it. Now see if this line contains a filename. */
335
while (c = getc (fp), c != EOF && c != '\n' && c != '/')
343
shared_library_fullname = NULL; size = 0;
344
len = getline (&shared_library_fullname, &size, fp);
347
/* Success: filled shared_library_fullname. */
348
if (len > 0 && shared_library_fullname[len - 1] == '\n')
349
shared_library_fullname[len - 1] = '\0';
354
while (c = getc (fp), c != EOF && c != '\n')
362
#endif /* WIN32 / Unix */
364
/* Return the full pathname of the current shared library.
365
Return NULL if unknown.
366
Guaranteed to work only on Linux and Woe32. */
368
get_shared_library_fullname ()
370
#if !(defined _WIN32 || defined __WIN32__)
371
static bool tried_find_shared_library_fullname;
372
if (!tried_find_shared_library_fullname)
374
find_shared_library_fullname ();
375
tried_find_shared_library_fullname = true;
378
return shared_library_fullname;
383
/* Returns the pathname, relocated according to the current installation
386
relocate (const char *pathname)
388
#if defined PIC && defined INSTALLDIR
389
static int initialized;
391
/* Initialization code for a shared library. */
394
/* At this point, orig_prefix and curr_prefix likely have already been
395
set through the main program's set_program_name_and_installdir
396
function. This is sufficient in the case that the library has
397
initially been installed in the same orig_prefix. But we can do
398
better, to also cover the cases that 1. it has been installed
399
in a different prefix before being moved to orig_prefix and (later)
400
to curr_prefix, 2. unlike the program, it has not moved away from
402
const char *orig_installprefix = INSTALLPREFIX;
403
const char *orig_installdir = INSTALLDIR;
404
const char *curr_prefix_better;
407
compute_curr_prefix (orig_installprefix, orig_installdir,
408
get_shared_library_fullname ());
409
if (curr_prefix_better == NULL)
410
curr_prefix_better = curr_prefix;
412
set_relocation_prefix (orig_installprefix, curr_prefix_better);
418
/* Note: It is not necessary to perform case insensitive comparison here,
419
even for DOS-like filesystems, because the pathname argument was
420
typically created from the same Makefile variable as orig_prefix came
422
if (orig_prefix != NULL && curr_prefix != NULL
423
&& strncmp (pathname, orig_prefix, orig_prefix_len) == 0)
425
if (pathname[orig_prefix_len] == '\0')
426
/* pathname equals orig_prefix. */
428
if (ISSLASH (pathname[orig_prefix_len]))
430
/* pathname starts with orig_prefix. */
431
const char *pathname_tail = &pathname[orig_prefix_len];
433
(char *) xmalloc (curr_prefix_len + strlen (pathname_tail) + 1);
439
memcpy (result, curr_prefix, curr_prefix_len);
440
strcpy (result + curr_prefix_len, pathname_tail);
445
/* Nothing to relocate. */