1 /* Provide relocatable packages.
2 Copyright (C) 2003-2006, 2008-2020 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 General Public License as published by
7 the Free Software Foundation; either version 3 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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://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 __CYGWIN__
46 # define WIN32_LEAN_AND_MEAN
54 # define strcmp stricmp
55 # define strncmp strnicmp
58 #if DEPENDS_ON_LIBCHARSET
59 # include <libcharset.h>
61 #if DEPENDS_ON_LIBICONV && HAVE_ICONV
64 #if DEPENDS_ON_LIBINTL && ENABLE_NLS
68 #if defined _WIN32 && !defined __CYGWIN__
69 /* Don't assume that UNICODE is not defined. */
70 # undef GetModuleFileName
71 # define GetModuleFileName GetModuleFileNameA
74 /* Faked cheap 'bool'. */
83 ISSLASH(C) tests whether C is a directory separator character.
84 IS_FILE_NAME_WITH_DIR(P) tests whether P contains a directory specification.
86 #if (defined _WIN32 && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__
87 /* Native Windows, OS/2, DOS */
88 # define ISSLASH(C) ((C) == '/' || (C) == '\\')
89 # define HAS_DEVICE(P) \
90 ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
92 # define IS_FILE_NAME_WITH_DIR(P) \
93 (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
94 # define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
97 # define ISSLASH(C) ((C) == '/')
98 # define IS_FILE_NAME_WITH_DIR(P) (strchr (P, '/') != NULL)
99 # define FILE_SYSTEM_PREFIX_LEN(P) 0
102 /* Whether to enable the more costly support for relocatable libraries.
103 It allows libraries to be have been installed with a different original
104 prefix than the program. But it is quite costly, especially on Cygwin
105 platforms, see below. Therefore we enable it by default only on native
106 Windows platforms. */
107 #ifndef ENABLE_COSTLY_RELOCATABLE
108 # if defined _WIN32 && !defined __CYGWIN__
109 # define ENABLE_COSTLY_RELOCATABLE 1
111 # define ENABLE_COSTLY_RELOCATABLE 0
115 /* Original installation prefix. */
116 static char *orig_prefix
;
117 static size_t orig_prefix_len
;
118 /* Current installation prefix. */
119 static char *curr_prefix
;
120 static size_t curr_prefix_len
;
121 /* These prefixes do not end in a slash. Anything that will be concatenated
122 to them must start with a slash. */
124 /* Sets the original and the current installation prefix of this module.
125 Relocation simply replaces a pathname starting with the original prefix
126 by the corresponding pathname with the current prefix instead. Both
127 prefixes should be directory names without trailing slash (i.e. use ""
130 set_this_relocation_prefix (const char *orig_prefix_arg
,
131 const char *curr_prefix_arg
)
133 if (orig_prefix_arg
!= NULL
&& curr_prefix_arg
!= NULL
134 /* Optimization: if orig_prefix and curr_prefix are equal, the
135 relocation is a nop. */
136 && strcmp (orig_prefix_arg
, curr_prefix_arg
) != 0)
138 /* Duplicate the argument strings. */
141 orig_prefix_len
= strlen (orig_prefix_arg
);
142 curr_prefix_len
= strlen (curr_prefix_arg
);
143 memory
= (char *) xmalloc (orig_prefix_len
+ 1 + curr_prefix_len
+ 1);
148 memcpy (memory
, orig_prefix_arg
, orig_prefix_len
+ 1);
149 orig_prefix
= memory
;
150 memory
+= orig_prefix_len
+ 1;
151 memcpy (memory
, curr_prefix_arg
, curr_prefix_len
+ 1);
152 curr_prefix
= memory
;
158 /* Don't worry about wasted memory here - this function is usually only
162 /* Sets the original and the current installation prefix of the package.
163 Relocation simply replaces a pathname starting with the original prefix
164 by the corresponding pathname with the current prefix instead. Both
165 prefixes should be directory names without trailing slash (i.e. use ""
168 set_relocation_prefix (const char *orig_prefix_arg
, const char *curr_prefix_arg
)
170 set_this_relocation_prefix (orig_prefix_arg
, curr_prefix_arg
);
172 /* Now notify all dependent libraries. */
173 #if DEPENDS_ON_LIBCHARSET
174 libcharset_set_relocation_prefix (orig_prefix_arg
, curr_prefix_arg
);
176 #if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109
177 libiconv_set_relocation_prefix (orig_prefix_arg
, curr_prefix_arg
);
179 #if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_prefix
180 libintl_set_relocation_prefix (orig_prefix_arg
, curr_prefix_arg
);
184 #if !defined IN_LIBRARY || (defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE)
186 /* Convenience function:
187 Computes the current installation prefix, based on the original
188 installation prefix, the original installation directory of a particular
189 file, and the current pathname of this file.
190 Returns it, freshly allocated. Returns NULL upon failure. */
192 #define compute_curr_prefix local_compute_curr_prefix
196 compute_curr_prefix (const char *orig_installprefix
,
197 const char *orig_installdir
,
198 const char *curr_pathname
)
200 char *curr_installdir
;
201 const char *rel_installdir
;
203 if (curr_pathname
== NULL
)
206 /* Determine the relative installation directory, relative to the prefix.
207 This is simply the difference between orig_installprefix and
209 if (strncmp (orig_installprefix
, orig_installdir
, strlen (orig_installprefix
))
211 /* Shouldn't happen - nothing should be installed outside $(prefix). */
213 rel_installdir
= orig_installdir
+ strlen (orig_installprefix
);
215 /* Determine the current installation directory. */
217 const char *p_base
= curr_pathname
+ FILE_SYSTEM_PREFIX_LEN (curr_pathname
);
218 const char *p
= curr_pathname
+ strlen (curr_pathname
);
228 q
= (char *) xmalloc (p
- curr_pathname
+ 1);
233 memcpy (q
, curr_pathname
, p
- curr_pathname
);
234 q
[p
- curr_pathname
] = '\0';
238 /* Compute the current installation prefix by removing the trailing
239 rel_installdir from it. */
241 const char *rp
= rel_installdir
+ strlen (rel_installdir
);
242 const char *cp
= curr_installdir
+ strlen (curr_installdir
);
243 const char *cp_base
=
244 curr_installdir
+ FILE_SYSTEM_PREFIX_LEN (curr_installdir
);
246 while (rp
> rel_installdir
&& cp
> cp_base
)
249 const char *rpi
= rp
;
250 const char *cpi
= cp
;
252 while (rpi
> rel_installdir
&& cpi
> cp_base
)
256 if (ISSLASH (*rpi
) || ISSLASH (*cpi
))
258 if (ISSLASH (*rpi
) && ISSLASH (*cpi
))
262 /* Do case-insensitive comparison if the file system is always or
263 often case-insensitive. It's better to accept the comparison
264 if the difference is only in case, rather than to fail. */
265 #if defined _WIN32 || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
266 /* Native Windows, Cygwin, OS/2, DOS - case insignificant file system */
267 if ((*rpi
>= 'a' && *rpi
<= 'z' ? *rpi
- 'a' + 'A' : *rpi
)
268 != (*cpi
>= 'a' && *cpi
<= 'z' ? *cpi
- 'a' + 'A' : *cpi
))
277 /* The last pathname component was the same. rpi and cpi now point
278 to the slash before it. */
283 if (rp
> rel_installdir
)
285 /* Unexpected: The curr_installdir does not end with rel_installdir. */
286 free (curr_installdir
);
291 size_t computed_curr_prefix_len
= cp
- curr_installdir
;
292 char *computed_curr_prefix
;
294 computed_curr_prefix
= (char *) xmalloc (computed_curr_prefix_len
+ 1);
296 if (computed_curr_prefix
== NULL
)
298 free (curr_installdir
);
302 memcpy (computed_curr_prefix
, curr_installdir
, computed_curr_prefix_len
);
303 computed_curr_prefix
[computed_curr_prefix_len
] = '\0';
305 free (curr_installdir
);
307 return computed_curr_prefix
;
312 #endif /* !IN_LIBRARY || PIC */
314 #if defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE
316 /* Full pathname of shared library, or NULL. */
317 static char *shared_library_fullname
;
319 #if defined _WIN32 && !defined __CYGWIN__
320 /* Native Windows only.
321 On Cygwin, it is better to use the Cygwin provided /proc interface, than
322 to use native Windows API and cygwin_conv_to_posix_path, because it
323 supports longer file names
324 (see <https://cygwin.com/ml/cygwin/2011-01/msg00410.html>). */
326 /* Determine the full pathname of the shared library when it is loaded. */
329 DllMain (HINSTANCE module_handle
, DWORD event
, LPVOID reserved
)
333 if (event
== DLL_PROCESS_ATTACH
)
335 /* The DLL is being loaded into an application's address range. */
336 static char location
[MAX_PATH
];
338 if (!GetModuleFileName (module_handle
, location
, sizeof (location
)))
339 /* Shouldn't happen. */
342 if (!IS_FILE_NAME_WITH_DIR (location
))
343 /* Shouldn't happen. */
346 shared_library_fullname
= strdup (location
);
352 #elif defined __EMX__
354 extern int _CRT_init (void);
355 extern void _CRT_term (void);
356 extern void __ctordtorInit (void);
357 extern void __ctordtorTerm (void);
359 unsigned long _System
360 _DLL_InitTerm (unsigned long hModule
, unsigned long ulFlag
)
362 static char location
[CCHMAXPATH
];
367 if (_CRT_init () == -1)
372 /* See http://cyberkinetica.homeunix.net/os2tk45/cp1/1247_L2H_DosQueryModuleNameSy.html
373 for specification of DosQueryModuleName(). */
374 if (DosQueryModuleName (hModule
, sizeof (location
), location
))
377 _fnslashify (location
);
378 shared_library_fullname
= strdup (location
);
394 find_shared_library_fullname ()
396 #if (defined __linux__ && (__GLIBC__ >= 2 || defined __UCLIBC__)) || defined __CYGWIN__
397 /* Linux has /proc/self/maps. glibc 2 and uClibc have the getline()
399 Cygwin >= 1.5 has /proc/self/maps and the getline() function too.
400 But it is costly: ca. 0.3 ms on Linux, 3 ms on Cygwin 1.5, and 5 ms on
404 /* Open the current process' maps file. It describes one VMA per line. */
405 fp
= fopen ("/proc/self/maps", "r");
408 unsigned long address
= (unsigned long) &find_shared_library_fullname
;
411 unsigned long start
, end
;
414 if (fscanf (fp
, "%lx-%lx", &start
, &end
) != 2)
416 if (address
>= start
&& address
<= end
- 1)
418 /* Found it. Now see if this line contains a filename. */
419 while (c
= getc (fp
), c
!= EOF
&& c
!= '\n' && c
!= '/')
427 shared_library_fullname
= NULL
; size
= 0;
428 len
= getline (&shared_library_fullname
, &size
, fp
);
431 /* Success: filled shared_library_fullname. */
432 if (len
> 0 && shared_library_fullname
[len
- 1] == '\n')
433 shared_library_fullname
[len
- 1] = '\0';
438 while (c
= getc (fp
), c
!= EOF
&& c
!= '\n')
446 #endif /* Native Windows / EMX / Unix */
448 /* Return the full pathname of the current shared library.
449 Return NULL if unknown.
450 Guaranteed to work only on Linux, EMX, Cygwin, and native Windows. */
452 get_shared_library_fullname ()
454 #if !(defined _WIN32 && !defined __CYGWIN__) && !defined __EMX__
455 static bool tried_find_shared_library_fullname
;
456 if (!tried_find_shared_library_fullname
)
458 find_shared_library_fullname ();
459 tried_find_shared_library_fullname
= true;
462 return shared_library_fullname
;
467 /* Returns the pathname, relocated according to the current installation
469 The returned string is either PATHNAME unmodified or a freshly allocated
470 string that you can free with free() after casting it to 'char *'. */
472 relocate (const char *pathname
)
474 #if defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE
475 static int initialized
;
477 /* Initialization code for a shared library. */
480 /* At this point, orig_prefix and curr_prefix likely have already been
481 set through the main program's set_program_name_and_installdir
482 function. This is sufficient in the case that the library has
483 initially been installed in the same orig_prefix. But we can do
484 better, to also cover the cases that 1. it has been installed
485 in a different prefix before being moved to orig_prefix and (later)
486 to curr_prefix, 2. unlike the program, it has not moved away from
488 const char *orig_installprefix
= INSTALLPREFIX
;
489 const char *orig_installdir
= INSTALLDIR
;
490 char *curr_prefix_better
;
493 compute_curr_prefix (orig_installprefix
, orig_installdir
,
494 get_shared_library_fullname ());
496 set_relocation_prefix (orig_installprefix
,
497 curr_prefix_better
!= NULL
501 if (curr_prefix_better
!= NULL
)
502 free (curr_prefix_better
);
508 /* Note: It is not necessary to perform case insensitive comparison here,
509 even for DOS-like file systems, because the pathname argument was
510 typically created from the same Makefile variable as orig_prefix came
512 if (orig_prefix
!= NULL
&& curr_prefix
!= NULL
513 && strncmp (pathname
, orig_prefix
, orig_prefix_len
) == 0)
515 if (pathname
[orig_prefix_len
] == '\0')
517 /* pathname equals orig_prefix. */
518 char *result
= (char *) xmalloc (strlen (curr_prefix
) + 1);
524 strcpy (result
, curr_prefix
);
528 else if (ISSLASH (pathname
[orig_prefix_len
]))
530 /* pathname starts with orig_prefix. */
531 const char *pathname_tail
= &pathname
[orig_prefix_len
];
533 (char *) xmalloc (curr_prefix_len
+ strlen (pathname_tail
) + 1);
539 memcpy (result
, curr_prefix
, curr_prefix_len
);
540 strcpy (result
+ curr_prefix_len
, pathname_tail
);
550 if (strncmp (pathname
, "/@unixroot", 10) == 0
551 && (pathname
[10] == '\0' || ISSLASH (pathname
[10])))
553 /* kLIBC itself processes /@unixroot prefix */
558 if (ISSLASH (pathname
[0]))
560 const char *unixroot
= getenv ("UNIXROOT");
562 if (unixroot
&& HAS_DEVICE (unixroot
) && unixroot
[2] == '\0')
564 char *result
= (char *) xmalloc (2 + strlen (pathname
) + 1);
569 memcpy (result
, unixroot
, 2);
570 strcpy (result
+ 2, pathname
);
577 /* Nothing to relocate. */
581 /* Returns the pathname, relocated according to the current installation
583 This function sets *ALLOCATEDP to the allocated memory, or to NULL if
584 no memory allocation occurs. So that, after you're done with the return
585 value, to reclaim allocated memory, you can do: free (*ALLOCATEDP). */
587 relocate2 (const char *pathname
, char **allocatedp
)
589 const char *result
= relocate (pathname
);
590 *allocatedp
= (result
!= pathname
? (char *) result
: NULL
);