3 /* Provide relocatable packages.
4 Copyright (C) 2003 Free Software Foundation, Inc.
5 Written by Bruno Haible <bruno@clisp.org>, 2003.
7 This program is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Library General Public License as published
9 by the Free Software Foundation; either version 2, or (at your option)
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
17 You should have received a copy of the GNU Library General Public
18 License along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
23 /* Tell glibc's <stdio.h> to provide a prototype for getline().
24 This must come before <config.h> because <config.h> may include
25 <features.h>, and once <features.h> has been included, it's too late. */
27 # define _GNU_SOURCE 1
35 #include "relocatable.h"
37 #if ENABLE_RELOCATABLE
45 # define xmalloc malloc
50 #if defined _WIN32 || defined __WIN32__
51 # define WIN32_LEAN_AND_MEAN
55 #if DEPENDS_ON_LIBCHARSET
56 # include <libcharset.h>
58 #if DEPENDS_ON_LIBICONV && HAVE_ICONV
61 #if DEPENDS_ON_LIBINTL && ENABLE_NLS
65 /* Faked cheap 'bool'. */
74 ISSLASH(C) tests whether C is a directory separator character.
75 IS_PATH_WITH_DIR(P) tests whether P contains a directory specification.
77 #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
78 /* Win32, OS/2, DOS */
79 # define ISSLASH(C) ((C) == '/' || (C) == '\\')
80 # define HAS_DEVICE(P) \
81 ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
83 # define IS_PATH_WITH_DIR(P) \
84 (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
85 # define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
88 # define ISSLASH(C) ((C) == '/')
89 # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
90 # define FILESYSTEM_PREFIX_LEN(P) 0
93 /* Original installation prefix. */
94 static char *orig_prefix
;
95 static size_t orig_prefix_len
;
96 /* Current installation prefix. */
97 static char *curr_prefix
;
98 static size_t curr_prefix_len
;
99 /* These prefixes do not end in a slash. Anything that will be concatenated
100 to them must start with a slash. */
102 /* Sets the original and the current installation prefix of this module.
103 Relocation simply replaces a pathname starting with the original prefix
104 by the corresponding pathname with the current prefix instead. Both
105 prefixes should be directory names without trailing slash (i.e. use ""
108 set_this_relocation_prefix (const char *orig_prefix_arg
,
109 const char *curr_prefix_arg
)
111 if (orig_prefix_arg
!= NULL
&& curr_prefix_arg
!= NULL
112 /* Optimization: if orig_prefix and curr_prefix are equal, the
113 relocation is a nop. */
114 && strcmp (orig_prefix_arg
, curr_prefix_arg
) != 0)
116 /* Duplicate the argument strings. */
119 orig_prefix_len
= strlen (orig_prefix_arg
);
120 curr_prefix_len
= strlen (curr_prefix_arg
);
121 memory
= (char *) xmalloc (orig_prefix_len
+ 1 + curr_prefix_len
+ 1);
126 memcpy (memory
, orig_prefix_arg
, orig_prefix_len
+ 1);
127 orig_prefix
= memory
;
128 memory
+= orig_prefix_len
+ 1;
129 memcpy (memory
, curr_prefix_arg
, curr_prefix_len
+ 1);
130 curr_prefix
= memory
;
136 /* Don't worry about wasted memory here - this function is usually only
140 /* Sets the original and the current installation prefix of the package.
141 Relocation simply replaces a pathname starting with the original prefix
142 by the corresponding pathname with the current prefix instead. Both
143 prefixes should be directory names without trailing slash (i.e. use ""
146 set_relocation_prefix (const char *orig_prefix_arg
, const char *curr_prefix_arg
)
148 set_this_relocation_prefix (orig_prefix_arg
, curr_prefix_arg
);
150 /* Now notify all dependent libraries. */
151 #if DEPENDS_ON_LIBCHARSET
152 libcharset_set_relocation_prefix (orig_prefix_arg
, curr_prefix_arg
);
154 #if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109
155 libiconv_set_relocation_prefix (orig_prefix_arg
, curr_prefix_arg
);
157 #if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_prefix
158 libintl_set_relocation_prefix (orig_prefix_arg
, curr_prefix_arg
);
162 #if !defined IN_LIBRARY || (defined PIC && defined INSTALLDIR)
164 /* Convenience function:
165 Computes the current installation prefix, based on the original
166 installation prefix, the original installation directory of a particular
167 file, and the current pathname of this file. Returns NULL upon failure. */
169 #define compute_curr_prefix local_compute_curr_prefix
173 compute_curr_prefix (const char *orig_installprefix
,
174 const char *orig_installdir
,
175 const char *curr_pathname
)
177 const char *curr_installdir
;
178 const char *rel_installdir
;
180 if (curr_pathname
== NULL
)
183 /* Determine the relative installation directory, relative to the prefix.
184 This is simply the difference between orig_installprefix and
186 if (strncmp (orig_installprefix
, orig_installdir
, strlen (orig_installprefix
))
188 /* Shouldn't happen - nothing should be installed outside $(prefix). */
190 rel_installdir
= orig_installdir
+ strlen (orig_installprefix
);
192 /* Determine the current installation directory. */
194 const char *p_base
= curr_pathname
+ FILESYSTEM_PREFIX_LEN (curr_pathname
);
195 const char *p
= curr_pathname
+ strlen (curr_pathname
);
205 q
= (char *) xmalloc (p
- curr_pathname
+ 1);
210 memcpy (q
, curr_pathname
, p
- curr_pathname
);
211 q
[p
- curr_pathname
] = '\0';
215 /* Compute the current installation prefix by removing the trailing
216 rel_installdir from it. */
218 const char *rp
= rel_installdir
+ strlen (rel_installdir
);
219 const char *cp
= curr_installdir
+ strlen (curr_installdir
);
220 const char *cp_base
=
221 curr_installdir
+ FILESYSTEM_PREFIX_LEN (curr_installdir
);
223 while (rp
> rel_installdir
&& cp
> cp_base
)
226 const char *rpi
= rp
;
227 const char *cpi
= cp
;
229 while (rpi
> rel_installdir
&& cpi
> cp_base
)
233 if (ISSLASH (*rpi
) || ISSLASH (*cpi
))
235 if (ISSLASH (*rpi
) && ISSLASH (*cpi
))
239 #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
240 /* Win32, OS/2, DOS - case insignificant filesystem */
241 if ((*rpi
>= 'a' && *rpi
<= 'z' ? *rpi
- 'a' + 'A' : *rpi
)
242 != (*cpi
>= 'a' && *cpi
<= 'z' ? *cpi
- 'a' + 'A' : *cpi
))
251 /* The last pathname component was the same. opi and cpi now point
252 to the slash before it. */
257 if (rp
> rel_installdir
)
258 /* Unexpected: The curr_installdir does not end with rel_installdir. */
262 size_t curr_prefix_len
= cp
- curr_installdir
;
265 curr_prefix
= (char *) xmalloc (curr_prefix_len
+ 1);
267 if (curr_prefix
== NULL
)
270 memcpy (curr_prefix
, curr_installdir
, curr_prefix_len
);
271 curr_prefix
[curr_prefix_len
] = '\0';
278 #endif /* !IN_LIBRARY || PIC */
280 #if defined PIC && defined INSTALLDIR
282 /* Full pathname of shared library, or NULL. */
283 static char *shared_library_fullname
;
285 #if defined _WIN32 || defined __WIN32__
287 /* Determine the full pathname of the shared library when it is loaded. */
290 DllMain (HINSTANCE module_handle
, DWORD event
, LPVOID reserved
)
294 if (event
== DLL_PROCESS_ATTACH
)
296 /* The DLL is being loaded into an application's address range. */
297 static char location
[MAX_PATH
];
299 if (!GetModuleFileName (module_handle
, location
, sizeof (location
)))
300 /* Shouldn't happen. */
303 if (!IS_PATH_WITH_DIR (location
))
304 /* Shouldn't happen. */
307 shared_library_fullname
= strdup (location
);
316 find_shared_library_fullname ()
318 #if defined __linux__ && __GLIBC__ >= 2
319 /* Linux has /proc/self/maps. glibc 2 has the getline() function. */
322 /* Open the current process' maps file. It describes one VMA per line. */
323 fp
= fopen ("/proc/self/maps", "r");
326 unsigned long address
= (unsigned long) &find_shared_library_fullname
;
329 unsigned long start
, end
;
332 if (fscanf (fp
, "%lx-%lx", &start
, &end
) != 2)
334 if (address
>= start
&& address
<= end
- 1)
336 /* Found it. Now see if this line contains a filename. */
337 while (c
= getc (fp
), c
!= EOF
&& c
!= '\n' && c
!= '/')
345 shared_library_fullname
= NULL
; size
= 0;
346 len
= getline (&shared_library_fullname
, &size
, fp
);
349 /* Success: filled shared_library_fullname. */
350 if (len
> 0 && shared_library_fullname
[len
- 1] == '\n')
351 shared_library_fullname
[len
- 1] = '\0';
356 while (c
= getc (fp
), c
!= EOF
&& c
!= '\n')
364 #endif /* WIN32 / Unix */
366 /* Return the full pathname of the current shared library.
367 Return NULL if unknown.
368 Guaranteed to work only on Linux and Woe32. */
370 get_shared_library_fullname ()
372 #if !(defined _WIN32 || defined __WIN32__)
373 static bool tried_find_shared_library_fullname
;
374 if (!tried_find_shared_library_fullname
)
376 find_shared_library_fullname ();
377 tried_find_shared_library_fullname
= true;
380 return shared_library_fullname
;
385 /* Returns the pathname, relocated according to the current installation
388 relocate (const char *pathname
)
390 #if defined PIC && defined INSTALLDIR
391 static int initialized
;
393 /* Initialization code for a shared library. */
396 /* At this point, orig_prefix and curr_prefix likely have already been
397 set through the main program's set_program_name_and_installdir
398 function. This is sufficient in the case that the library has
399 initially been installed in the same orig_prefix. But we can do
400 better, to also cover the cases that 1. it has been installed
401 in a different prefix before being moved to orig_prefix and (later)
402 to curr_prefix, 2. unlike the program, it has not moved away from
404 const char *orig_installprefix
= INSTALLPREFIX
;
405 const char *orig_installdir
= INSTALLDIR
;
406 const char *curr_prefix_better
;
409 compute_curr_prefix (orig_installprefix
, orig_installdir
,
410 get_shared_library_fullname ());
411 if (curr_prefix_better
== NULL
)
412 curr_prefix_better
= curr_prefix
;
414 set_relocation_prefix (orig_installprefix
, curr_prefix_better
);
420 /* Note: It is not necessary to perform case insensitive comparison here,
421 even for DOS-like filesystems, because the pathname argument was
422 typically created from the same Makefile variable as orig_prefix came
424 if (orig_prefix
!= NULL
&& curr_prefix
!= NULL
425 && strncmp (pathname
, orig_prefix
, orig_prefix_len
) == 0)
427 if (pathname
[orig_prefix_len
] == '\0')
428 /* pathname equals orig_prefix. */
430 if (ISSLASH (pathname
[orig_prefix_len
]))
432 /* pathname starts with orig_prefix. */
433 const char *pathname_tail
= &pathname
[orig_prefix_len
];
435 (char *) xmalloc (curr_prefix_len
+ strlen (pathname_tail
) + 1);
441 memcpy (result
, curr_prefix
, curr_prefix_len
);
442 strcpy (result
+ curr_prefix_len
, pathname_tail
);
447 /* Nothing to relocate. */