xfreopen need not depend on freopen-safer
[gnulib.git] / lib / relocatable.c
blob17cdb6590f294bfea98fae79ad6e6b581465ba14
1 /* Provide relocatable packages.
2 Copyright (C) 2003-2006, 2008-2019 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. */
22 #ifndef _GNU_SOURCE
23 # define _GNU_SOURCE 1
24 #endif
26 #define _GL_USE_STDLIB_ALLOC 1
27 #include <config.h>
29 /* Specification. */
30 #include "relocatable.h"
32 #if ENABLE_RELOCATABLE
34 #include <stddef.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
39 #ifdef NO_XMALLOC
40 # define xmalloc malloc
41 #else
42 # include "xalloc.h"
43 #endif
45 #if defined _WIN32 && !defined __CYGWIN__
46 # define WIN32_LEAN_AND_MEAN
47 # include <windows.h>
48 #endif
50 #ifdef __EMX__
51 # define INCL_DOS
52 # include <os2.h>
54 # define strcmp stricmp
55 # define strncmp strnicmp
56 #endif
58 #if DEPENDS_ON_LIBCHARSET
59 # include <libcharset.h>
60 #endif
61 #if DEPENDS_ON_LIBICONV && HAVE_ICONV
62 # include <iconv.h>
63 #endif
64 #if DEPENDS_ON_LIBINTL && ENABLE_NLS
65 # include <libintl.h>
66 #endif
68 /* Faked cheap 'bool'. */
69 #undef bool
70 #undef false
71 #undef true
72 #define bool int
73 #define false 0
74 #define true 1
76 /* Pathname support.
77 ISSLASH(C) tests whether C is a directory separator character.
78 IS_PATH_WITH_DIR(P) tests whether P contains a directory specification.
80 #if (defined _WIN32 && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__
81 /* Native Windows, OS/2, DOS */
82 # define ISSLASH(C) ((C) == '/' || (C) == '\\')
83 # define HAS_DEVICE(P) \
84 ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
85 && (P)[1] == ':')
86 # define IS_PATH_WITH_DIR(P) \
87 (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
88 # define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
89 #else
90 /* Unix */
91 # define ISSLASH(C) ((C) == '/')
92 # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
93 # define FILE_SYSTEM_PREFIX_LEN(P) 0
94 #endif
96 /* Whether to enable the more costly support for relocatable libraries.
97 It allows libraries to be have been installed with a different original
98 prefix than the program. But it is quite costly, especially on Cygwin
99 platforms, see below. Therefore we enable it by default only on native
100 Windows platforms. */
101 #ifndef ENABLE_COSTLY_RELOCATABLE
102 # if defined _WIN32 && !defined __CYGWIN__
103 # define ENABLE_COSTLY_RELOCATABLE 1
104 # else
105 # define ENABLE_COSTLY_RELOCATABLE 0
106 # endif
107 #endif
109 /* Original installation prefix. */
110 static char *orig_prefix;
111 static size_t orig_prefix_len;
112 /* Current installation prefix. */
113 static char *curr_prefix;
114 static size_t curr_prefix_len;
115 /* These prefixes do not end in a slash. Anything that will be concatenated
116 to them must start with a slash. */
118 /* Sets the original and the current installation prefix of this module.
119 Relocation simply replaces a pathname starting with the original prefix
120 by the corresponding pathname with the current prefix instead. Both
121 prefixes should be directory names without trailing slash (i.e. use ""
122 instead of "/"). */
123 static void
124 set_this_relocation_prefix (const char *orig_prefix_arg,
125 const char *curr_prefix_arg)
127 if (orig_prefix_arg != NULL && curr_prefix_arg != NULL
128 /* Optimization: if orig_prefix and curr_prefix are equal, the
129 relocation is a nop. */
130 && strcmp (orig_prefix_arg, curr_prefix_arg) != 0)
132 /* Duplicate the argument strings. */
133 char *memory;
135 orig_prefix_len = strlen (orig_prefix_arg);
136 curr_prefix_len = strlen (curr_prefix_arg);
137 memory = (char *) xmalloc (orig_prefix_len + 1 + curr_prefix_len + 1);
138 #ifdef NO_XMALLOC
139 if (memory != NULL)
140 #endif
142 memcpy (memory, orig_prefix_arg, orig_prefix_len + 1);
143 orig_prefix = memory;
144 memory += orig_prefix_len + 1;
145 memcpy (memory, curr_prefix_arg, curr_prefix_len + 1);
146 curr_prefix = memory;
147 return;
150 orig_prefix = NULL;
151 curr_prefix = NULL;
152 /* Don't worry about wasted memory here - this function is usually only
153 called once. */
156 /* Sets the original and the current installation prefix of the package.
157 Relocation simply replaces a pathname starting with the original prefix
158 by the corresponding pathname with the current prefix instead. Both
159 prefixes should be directory names without trailing slash (i.e. use ""
160 instead of "/"). */
161 void
162 set_relocation_prefix (const char *orig_prefix_arg, const char *curr_prefix_arg)
164 set_this_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
166 /* Now notify all dependent libraries. */
167 #if DEPENDS_ON_LIBCHARSET
168 libcharset_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
169 #endif
170 #if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109
171 libiconv_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
172 #endif
173 #if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_prefix
174 libintl_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
175 #endif
178 #if !defined IN_LIBRARY || (defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE)
180 /* Convenience function:
181 Computes the current installation prefix, based on the original
182 installation prefix, the original installation directory of a particular
183 file, and the current pathname of this file.
184 Returns it, freshly allocated. Returns NULL upon failure. */
185 #ifdef IN_LIBRARY
186 #define compute_curr_prefix local_compute_curr_prefix
187 static
188 #endif
189 char *
190 compute_curr_prefix (const char *orig_installprefix,
191 const char *orig_installdir,
192 const char *curr_pathname)
194 char *curr_installdir;
195 const char *rel_installdir;
197 if (curr_pathname == NULL)
198 return NULL;
200 /* Determine the relative installation directory, relative to the prefix.
201 This is simply the difference between orig_installprefix and
202 orig_installdir. */
203 if (strncmp (orig_installprefix, orig_installdir, strlen (orig_installprefix))
204 != 0)
205 /* Shouldn't happen - nothing should be installed outside $(prefix). */
206 return NULL;
207 rel_installdir = orig_installdir + strlen (orig_installprefix);
209 /* Determine the current installation directory. */
211 const char *p_base = curr_pathname + FILE_SYSTEM_PREFIX_LEN (curr_pathname);
212 const char *p = curr_pathname + strlen (curr_pathname);
213 char *q;
215 while (p > p_base)
217 p--;
218 if (ISSLASH (*p))
219 break;
222 q = (char *) xmalloc (p - curr_pathname + 1);
223 #ifdef NO_XMALLOC
224 if (q == NULL)
225 return NULL;
226 #endif
227 memcpy (q, curr_pathname, p - curr_pathname);
228 q[p - curr_pathname] = '\0';
229 curr_installdir = q;
232 /* Compute the current installation prefix by removing the trailing
233 rel_installdir from it. */
235 const char *rp = rel_installdir + strlen (rel_installdir);
236 const char *cp = curr_installdir + strlen (curr_installdir);
237 const char *cp_base =
238 curr_installdir + FILE_SYSTEM_PREFIX_LEN (curr_installdir);
240 while (rp > rel_installdir && cp > cp_base)
242 bool same = false;
243 const char *rpi = rp;
244 const char *cpi = cp;
246 while (rpi > rel_installdir && cpi > cp_base)
248 rpi--;
249 cpi--;
250 if (ISSLASH (*rpi) || ISSLASH (*cpi))
252 if (ISSLASH (*rpi) && ISSLASH (*cpi))
253 same = true;
254 break;
256 /* Do case-insensitive comparison if the file system is always or
257 often case-insensitive. It's better to accept the comparison
258 if the difference is only in case, rather than to fail. */
259 #if defined _WIN32 || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
260 /* Native Windows, Cygwin, OS/2, DOS - case insignificant file system */
261 if ((*rpi >= 'a' && *rpi <= 'z' ? *rpi - 'a' + 'A' : *rpi)
262 != (*cpi >= 'a' && *cpi <= 'z' ? *cpi - 'a' + 'A' : *cpi))
263 break;
264 #else
265 if (*rpi != *cpi)
266 break;
267 #endif
269 if (!same)
270 break;
271 /* The last pathname component was the same. opi and cpi now point
272 to the slash before it. */
273 rp = rpi;
274 cp = cpi;
277 if (rp > rel_installdir)
279 /* Unexpected: The curr_installdir does not end with rel_installdir. */
280 free (curr_installdir);
281 return NULL;
285 size_t curr_prefix_len = cp - curr_installdir;
286 char *curr_prefix;
288 curr_prefix = (char *) xmalloc (curr_prefix_len + 1);
289 #ifdef NO_XMALLOC
290 if (curr_prefix == NULL)
292 free (curr_installdir);
293 return NULL;
295 #endif
296 memcpy (curr_prefix, curr_installdir, curr_prefix_len);
297 curr_prefix[curr_prefix_len] = '\0';
299 free (curr_installdir);
301 return curr_prefix;
306 #endif /* !IN_LIBRARY || PIC */
308 #if defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE
310 /* Full pathname of shared library, or NULL. */
311 static char *shared_library_fullname;
313 #if defined _WIN32 && !defined __CYGWIN__
314 /* Native Windows only.
315 On Cygwin, it is better to use the Cygwin provided /proc interface, than
316 to use native Windows API and cygwin_conv_to_posix_path, because it
317 supports longer file names
318 (see <https://cygwin.com/ml/cygwin/2011-01/msg00410.html>). */
320 /* Determine the full pathname of the shared library when it is loaded. */
322 BOOL WINAPI
323 DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved)
325 (void) reserved;
327 if (event == DLL_PROCESS_ATTACH)
329 /* The DLL is being loaded into an application's address range. */
330 static char location[MAX_PATH];
332 if (!GetModuleFileName (module_handle, location, sizeof (location)))
333 /* Shouldn't happen. */
334 return FALSE;
336 if (!IS_PATH_WITH_DIR (location))
337 /* Shouldn't happen. */
338 return FALSE;
340 shared_library_fullname = strdup (location);
343 return TRUE;
346 #elif defined __EMX__
348 extern int _CRT_init (void);
349 extern void _CRT_term (void);
350 extern void __ctordtorInit (void);
351 extern void __ctordtorTerm (void);
353 unsigned long _System
354 _DLL_InitTerm (unsigned long hModule, unsigned long ulFlag)
356 static char location[CCHMAXPATH];
358 switch (ulFlag)
360 case 0:
361 if (_CRT_init () == -1)
362 return 0;
364 __ctordtorInit();
366 /* See http://cyberkinetica.homeunix.net/os2tk45/cp1/1247_L2H_DosQueryModuleNameSy.html
367 for specification of DosQueryModuleName(). */
368 if (DosQueryModuleName (hModule, sizeof (location), location))
369 return 0;
371 _fnslashify (location);
372 shared_library_fullname = strdup (location);
373 break;
375 case 1:
376 __ctordtorTerm();
378 _CRT_term ();
379 break;
382 return 1;
385 #else /* Unix */
387 static void
388 find_shared_library_fullname ()
390 #if (defined __linux__ && (__GLIBC__ >= 2 || defined __UCLIBC__)) || defined __CYGWIN__
391 /* Linux has /proc/self/maps. glibc 2 and uClibc have the getline()
392 function.
393 Cygwin >= 1.5 has /proc/self/maps and the getline() function too.
394 But it is costly: ca. 0.3 ms on Linux, 3 ms on Cygwin 1.5, and 5 ms on
395 Cygwin 1.7. */
396 FILE *fp;
398 /* Open the current process' maps file. It describes one VMA per line. */
399 fp = fopen ("/proc/self/maps", "r");
400 if (fp)
402 unsigned long address = (unsigned long) &find_shared_library_fullname;
403 for (;;)
405 unsigned long start, end;
406 int c;
408 if (fscanf (fp, "%lx-%lx", &start, &end) != 2)
409 break;
410 if (address >= start && address <= end - 1)
412 /* Found it. Now see if this line contains a filename. */
413 while (c = getc (fp), c != EOF && c != '\n' && c != '/')
414 continue;
415 if (c == '/')
417 size_t size;
418 int len;
420 ungetc (c, fp);
421 shared_library_fullname = NULL; size = 0;
422 len = getline (&shared_library_fullname, &size, fp);
423 if (len >= 0)
425 /* Success: filled shared_library_fullname. */
426 if (len > 0 && shared_library_fullname[len - 1] == '\n')
427 shared_library_fullname[len - 1] = '\0';
430 break;
432 while (c = getc (fp), c != EOF && c != '\n')
433 continue;
435 fclose (fp);
437 #endif
440 #endif /* Native Windows / EMX / Unix */
442 /* Return the full pathname of the current shared library.
443 Return NULL if unknown.
444 Guaranteed to work only on Linux, EMX, Cygwin, and native Windows. */
445 static char *
446 get_shared_library_fullname ()
448 #if !(defined _WIN32 && !defined __CYGWIN__) && !defined __EMX__
449 static bool tried_find_shared_library_fullname;
450 if (!tried_find_shared_library_fullname)
452 find_shared_library_fullname ();
453 tried_find_shared_library_fullname = true;
455 #endif
456 return shared_library_fullname;
459 #endif /* PIC */
461 /* Returns the pathname, relocated according to the current installation
462 directory.
463 The returned string is either PATHNAME unmodified or a freshly allocated
464 string that you can free with free() after casting it to 'char *'. */
465 const char *
466 relocate (const char *pathname)
468 #if defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE
469 static int initialized;
471 /* Initialization code for a shared library. */
472 if (!initialized)
474 /* At this point, orig_prefix and curr_prefix likely have already been
475 set through the main program's set_program_name_and_installdir
476 function. This is sufficient in the case that the library has
477 initially been installed in the same orig_prefix. But we can do
478 better, to also cover the cases that 1. it has been installed
479 in a different prefix before being moved to orig_prefix and (later)
480 to curr_prefix, 2. unlike the program, it has not moved away from
481 orig_prefix. */
482 const char *orig_installprefix = INSTALLPREFIX;
483 const char *orig_installdir = INSTALLDIR;
484 char *curr_prefix_better;
486 curr_prefix_better =
487 compute_curr_prefix (orig_installprefix, orig_installdir,
488 get_shared_library_fullname ());
490 set_relocation_prefix (orig_installprefix,
491 curr_prefix_better != NULL
492 ? curr_prefix_better
493 : curr_prefix);
495 if (curr_prefix_better != NULL)
496 free (curr_prefix_better);
498 initialized = 1;
500 #endif
502 /* Note: It is not necessary to perform case insensitive comparison here,
503 even for DOS-like file systems, because the pathname argument was
504 typically created from the same Makefile variable as orig_prefix came
505 from. */
506 if (orig_prefix != NULL && curr_prefix != NULL
507 && strncmp (pathname, orig_prefix, orig_prefix_len) == 0)
509 if (pathname[orig_prefix_len] == '\0')
511 /* pathname equals orig_prefix. */
512 char *result = (char *) xmalloc (strlen (curr_prefix) + 1);
514 #ifdef NO_XMALLOC
515 if (result != NULL)
516 #endif
518 strcpy (result, curr_prefix);
519 return result;
522 else if (ISSLASH (pathname[orig_prefix_len]))
524 /* pathname starts with orig_prefix. */
525 const char *pathname_tail = &pathname[orig_prefix_len];
526 char *result =
527 (char *) xmalloc (curr_prefix_len + strlen (pathname_tail) + 1);
529 #ifdef NO_XMALLOC
530 if (result != NULL)
531 #endif
533 memcpy (result, curr_prefix, curr_prefix_len);
534 strcpy (result + curr_prefix_len, pathname_tail);
535 return result;
540 #ifdef __EMX__
541 # ifdef __KLIBC__
542 # undef strncmp
544 if (strncmp (pathname, "/@unixroot", 10) == 0
545 && (pathname[10] == '\0' || ISSLASH (pathname[10])))
547 /* kLIBC itself processes /@unixroot prefix */
548 return pathname;
550 else
551 # endif
552 if (ISSLASH (pathname[0]))
554 const char *unixroot = getenv ("UNIXROOT");
556 if (unixroot && HAS_DEVICE (unixroot) && unixroot[2] == '\0')
558 char *result = (char *) xmalloc (2 + strlen (pathname) + 1);
559 #ifdef NO_XMALLOC
560 if (result != NULL)
561 #endif
563 memcpy (result, unixroot, 2);
564 strcpy (result + 2, pathname);
565 return result;
569 #endif
571 /* Nothing to relocate. */
572 return pathname;
575 /* Returns the pathname, relocated according to the current installation
576 directory.
577 This function sets *ALLOCATEDP to the allocated memory, or to NULL if
578 no memory allocation occurs. So that, after you're done with the return
579 value, to reclaim allocated memory, you can do: free (*ALLOCATEDP). */
580 const char *
581 relocate2 (const char *pathname, char **allocatedp)
583 const char *result = relocate (pathname);
584 *allocatedp = (result != pathname ? (char *) result : NULL);
585 return result;
588 #endif