Merge commit 'a39d4083cab589d7cd6a13e8a4b8db8875261d75'
[gnulib.git] / lib / relocatable.c
1 /* Provide relocatable packages.
2    Copyright (C) 2003-2006, 2008-2014 Free Software Foundation, Inc.
3    Written by Bruno Haible <bruno@clisp.org>, 2003.
4
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU Lesser General Public License as published by
7    the Free Software Foundation; either version 2.1 of the License, or
8    (at your option) any later version.
9
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 Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18
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
25
26 #define _GL_USE_STDLIB_ALLOC 1
27 #include <config.h>
28
29 /* Specification.  */
30 #include "relocatable.h"
31
32 #if ENABLE_RELOCATABLE
33
34 #include <stddef.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #ifdef NO_XMALLOC
40 # define xmalloc malloc
41 #else
42 # include "xalloc.h"
43 #endif
44
45 #if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__
46 # define WIN32_LEAN_AND_MEAN
47 # include <windows.h>
48 #endif
49
50 #if DEPENDS_ON_LIBCHARSET
51 # include <libcharset.h>
52 #endif
53 #if DEPENDS_ON_LIBICONV && HAVE_ICONV
54 # include <iconv.h>
55 #endif
56 #if DEPENDS_ON_LIBINTL && ENABLE_NLS
57 # include <libintl.h>
58 #endif
59
60 /* Faked cheap 'bool'.  */
61 #undef bool
62 #undef false
63 #undef true
64 #define bool int
65 #define false 0
66 #define true 1
67
68 /* Pathname support.
69    ISSLASH(C)           tests whether C is a directory separator character.
70    IS_PATH_WITH_DIR(P)  tests whether P contains a directory specification.
71  */
72 #if ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__
73   /* Native Windows, OS/2, DOS */
74 # define ISSLASH(C) ((C) == '/' || (C) == '\\')
75 # define HAS_DEVICE(P) \
76     ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
77      && (P)[1] == ':')
78 # define IS_PATH_WITH_DIR(P) \
79     (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
80 # define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
81 #else
82   /* Unix */
83 # define ISSLASH(C) ((C) == '/')
84 # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
85 # define FILE_SYSTEM_PREFIX_LEN(P) 0
86 #endif
87
88 /* Whether to enable the more costly support for relocatable libraries.
89    It allows libraries to be have been installed with a different original
90    prefix than the program.  But it is quite costly, especially on Cygwin
91    platforms, see below.  Therefore we enable it by default only on native
92    Windows platforms.  */
93 #ifndef ENABLE_COSTLY_RELOCATABLE
94 # if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__
95 #  define ENABLE_COSTLY_RELOCATABLE 1
96 # else
97 #  define ENABLE_COSTLY_RELOCATABLE 0
98 # endif
99 #endif
100
101 /* Original installation prefix.  */
102 static char *orig_prefix;
103 static size_t orig_prefix_len;
104 /* Current installation prefix.  */
105 static char *curr_prefix;
106 static size_t curr_prefix_len;
107 /* These prefixes do not end in a slash.  Anything that will be concatenated
108    to them must start with a slash.  */
109
110 /* Sets the original and the current installation prefix of this module.
111    Relocation simply replaces a pathname starting with the original prefix
112    by the corresponding pathname with the current prefix instead.  Both
113    prefixes should be directory names without trailing slash (i.e. use ""
114    instead of "/").  */
115 static void
116 set_this_relocation_prefix (const char *orig_prefix_arg,
117                             const char *curr_prefix_arg)
118 {
119   if (orig_prefix_arg != NULL && curr_prefix_arg != NULL
120       /* Optimization: if orig_prefix and curr_prefix are equal, the
121          relocation is a nop.  */
122       && strcmp (orig_prefix_arg, curr_prefix_arg) != 0)
123     {
124       /* Duplicate the argument strings.  */
125       char *memory;
126
127       orig_prefix_len = strlen (orig_prefix_arg);
128       curr_prefix_len = strlen (curr_prefix_arg);
129       memory = (char *) xmalloc (orig_prefix_len + 1 + curr_prefix_len + 1);
130 #ifdef NO_XMALLOC
131       if (memory != NULL)
132 #endif
133         {
134           memcpy (memory, orig_prefix_arg, orig_prefix_len + 1);
135           orig_prefix = memory;
136           memory += orig_prefix_len + 1;
137           memcpy (memory, curr_prefix_arg, curr_prefix_len + 1);
138           curr_prefix = memory;
139           return;
140         }
141     }
142   orig_prefix = NULL;
143   curr_prefix = NULL;
144   /* Don't worry about wasted memory here - this function is usually only
145      called once.  */
146 }
147
148 /* Sets the original and the current installation prefix of the package.
149    Relocation simply replaces a pathname starting with the original prefix
150    by the corresponding pathname with the current prefix instead.  Both
151    prefixes should be directory names without trailing slash (i.e. use ""
152    instead of "/").  */
153 void
154 set_relocation_prefix (const char *orig_prefix_arg, const char *curr_prefix_arg)
155 {
156   set_this_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
157
158   /* Now notify all dependent libraries.  */
159 #if DEPENDS_ON_LIBCHARSET
160   libcharset_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
161 #endif
162 #if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109
163   libiconv_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
164 #endif
165 #if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_prefix
166   libintl_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
167 #endif
168 }
169
170 #if !defined IN_LIBRARY || (defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE)
171
172 /* Convenience function:
173    Computes the current installation prefix, based on the original
174    installation prefix, the original installation directory of a particular
175    file, and the current pathname of this file.
176    Returns it, freshly allocated.  Returns NULL upon failure.  */
177 #ifdef IN_LIBRARY
178 #define compute_curr_prefix local_compute_curr_prefix
179 static
180 #endif
181 char *
182 compute_curr_prefix (const char *orig_installprefix,
183                      const char *orig_installdir,
184                      const char *curr_pathname)
185 {
186   char *curr_installdir;
187   const char *rel_installdir;
188
189   if (curr_pathname == NULL)
190     return NULL;
191
192   /* Determine the relative installation directory, relative to the prefix.
193      This is simply the difference between orig_installprefix and
194      orig_installdir.  */
195   if (strncmp (orig_installprefix, orig_installdir, strlen (orig_installprefix))
196       != 0)
197     /* Shouldn't happen - nothing should be installed outside $(prefix).  */
198     return NULL;
199   rel_installdir = orig_installdir + strlen (orig_installprefix);
200
201   /* Determine the current installation directory.  */
202   {
203     const char *p_base = curr_pathname + FILE_SYSTEM_PREFIX_LEN (curr_pathname);
204     const char *p = curr_pathname + strlen (curr_pathname);
205     char *q;
206
207     while (p > p_base)
208       {
209         p--;
210         if (ISSLASH (*p))
211           break;
212       }
213
214     q = (char *) xmalloc (p - curr_pathname + 1);
215 #ifdef NO_XMALLOC
216     if (q == NULL)
217       return NULL;
218 #endif
219     memcpy (q, curr_pathname, p - curr_pathname);
220     q[p - curr_pathname] = '\0';
221     curr_installdir = q;
222   }
223
224   /* Compute the current installation prefix by removing the trailing
225      rel_installdir from it.  */
226   {
227     const char *rp = rel_installdir + strlen (rel_installdir);
228     const char *cp = curr_installdir + strlen (curr_installdir);
229     const char *cp_base =
230       curr_installdir + FILE_SYSTEM_PREFIX_LEN (curr_installdir);
231
232     while (rp > rel_installdir && cp > cp_base)
233       {
234         bool same = false;
235         const char *rpi = rp;
236         const char *cpi = cp;
237
238         while (rpi > rel_installdir && cpi > cp_base)
239           {
240             rpi--;
241             cpi--;
242             if (ISSLASH (*rpi) || ISSLASH (*cpi))
243               {
244                 if (ISSLASH (*rpi) && ISSLASH (*cpi))
245                   same = true;
246                 break;
247               }
248             /* Do case-insensitive comparison if the file system is always or
249                often case-insensitive.  It's better to accept the comparison
250                if the difference is only in case, rather than to fail.  */
251 #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
252             /* Native Windows, Cygwin, OS/2, DOS - case insignificant file system */
253             if ((*rpi >= 'a' && *rpi <= 'z' ? *rpi - 'a' + 'A' : *rpi)
254                 != (*cpi >= 'a' && *cpi <= 'z' ? *cpi - 'a' + 'A' : *cpi))
255               break;
256 #else
257             if (*rpi != *cpi)
258               break;
259 #endif
260           }
261         if (!same)
262           break;
263         /* The last pathname component was the same.  opi and cpi now point
264            to the slash before it.  */
265         rp = rpi;
266         cp = cpi;
267       }
268
269     if (rp > rel_installdir)
270       {
271         /* Unexpected: The curr_installdir does not end with rel_installdir.  */
272         free (curr_installdir);
273         return NULL;
274       }
275
276     {
277       size_t curr_prefix_len = cp - curr_installdir;
278       char *curr_prefix;
279
280       curr_prefix = (char *) xmalloc (curr_prefix_len + 1);
281 #ifdef NO_XMALLOC
282       if (curr_prefix == NULL)
283         {
284           free (curr_installdir);
285           return NULL;
286         }
287 #endif
288       memcpy (curr_prefix, curr_installdir, curr_prefix_len);
289       curr_prefix[curr_prefix_len] = '\0';
290
291       free (curr_installdir);
292
293       return curr_prefix;
294     }
295   }
296 }
297
298 #endif /* !IN_LIBRARY || PIC */
299
300 #if defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE
301
302 /* Full pathname of shared library, or NULL.  */
303 static char *shared_library_fullname;
304
305 #if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__
306 /* Native Windows only.
307    On Cygwin, it is better to use the Cygwin provided /proc interface, than
308    to use native Windows API and cygwin_conv_to_posix_path, because it
309    supports longer file names
310    (see <http://cygwin.com/ml/cygwin/2011-01/msg00410.html>).  */
311
312 /* Determine the full pathname of the shared library when it is loaded.  */
313
314 BOOL WINAPI
315 DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved)
316 {
317   (void) reserved;
318
319   if (event == DLL_PROCESS_ATTACH)
320     {
321       /* The DLL is being loaded into an application's address range.  */
322       static char location[MAX_PATH];
323
324       if (!GetModuleFileName (module_handle, location, sizeof (location)))
325         /* Shouldn't happen.  */
326         return FALSE;
327
328       if (!IS_PATH_WITH_DIR (location))
329         /* Shouldn't happen.  */
330         return FALSE;
331
332       shared_library_fullname = strdup (location);
333     }
334
335   return TRUE;
336 }
337
338 #else /* Unix */
339
340 static void
341 find_shared_library_fullname ()
342 {
343 #if (defined __linux__ && (__GLIBC__ >= 2 || defined __UCLIBC__)) || defined __CYGWIN__
344   /* Linux has /proc/self/maps. glibc 2 and uClibc have the getline()
345      function.
346      Cygwin >= 1.5 has /proc/self/maps and the getline() function too.
347      But it is costly: ca. 0.3 ms on Linux, 3 ms on Cygwin 1.5, and 5 ms on
348      Cygwin 1.7.  */
349   FILE *fp;
350
351   /* Open the current process' maps file.  It describes one VMA per line.  */
352   fp = fopen ("/proc/self/maps", "r");
353   if (fp)
354     {
355       unsigned long address = (unsigned long) &find_shared_library_fullname;
356       for (;;)
357         {
358           unsigned long start, end;
359           int c;
360
361           if (fscanf (fp, "%lx-%lx", &start, &end) != 2)
362             break;
363           if (address >= start && address <= end - 1)
364             {
365               /* Found it.  Now see if this line contains a filename.  */
366               while (c = getc (fp), c != EOF && c != '\n' && c != '/')
367                 continue;
368               if (c == '/')
369                 {
370                   size_t size;
371                   int len;
372
373                   ungetc (c, fp);
374                   shared_library_fullname = NULL; size = 0;
375                   len = getline (&shared_library_fullname, &size, fp);
376                   if (len >= 0)
377                     {
378                       /* Success: filled shared_library_fullname.  */
379                       if (len > 0 && shared_library_fullname[len - 1] == '\n')
380                         shared_library_fullname[len - 1] = '\0';
381                     }
382                 }
383               break;
384             }
385           while (c = getc (fp), c != EOF && c != '\n')
386             continue;
387         }
388       fclose (fp);
389     }
390 #endif
391 }
392
393 #endif /* Native Windows / Unix */
394
395 /* Return the full pathname of the current shared library.
396    Return NULL if unknown.
397    Guaranteed to work only on Linux, Cygwin, and native Windows.  */
398 static char *
399 get_shared_library_fullname ()
400 {
401 #if !((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__)
402   static bool tried_find_shared_library_fullname;
403   if (!tried_find_shared_library_fullname)
404     {
405       find_shared_library_fullname ();
406       tried_find_shared_library_fullname = true;
407     }
408 #endif
409   return shared_library_fullname;
410 }
411
412 #endif /* PIC */
413
414 /* Returns the pathname, relocated according to the current installation
415    directory.
416    The returned string is either PATHNAME unmodified or a freshly allocated
417    string that you can free with free() after casting it to 'char *'.  */
418 const char *
419 relocate (const char *pathname)
420 {
421 #if defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE
422   static int initialized;
423
424   /* Initialization code for a shared library.  */
425   if (!initialized)
426     {
427       /* At this point, orig_prefix and curr_prefix likely have already been
428          set through the main program's set_program_name_and_installdir
429          function.  This is sufficient in the case that the library has
430          initially been installed in the same orig_prefix.  But we can do
431          better, to also cover the cases that 1. it has been installed
432          in a different prefix before being moved to orig_prefix and (later)
433          to curr_prefix, 2. unlike the program, it has not moved away from
434          orig_prefix.  */
435       const char *orig_installprefix = INSTALLPREFIX;
436       const char *orig_installdir = INSTALLDIR;
437       char *curr_prefix_better;
438
439       curr_prefix_better =
440         compute_curr_prefix (orig_installprefix, orig_installdir,
441                              get_shared_library_fullname ());
442
443       set_relocation_prefix (orig_installprefix,
444                              curr_prefix_better != NULL
445                              ? curr_prefix_better
446                              : curr_prefix);
447
448       if (curr_prefix_better != NULL)
449         free (curr_prefix_better);
450
451       initialized = 1;
452     }
453 #endif
454
455   /* Note: It is not necessary to perform case insensitive comparison here,
456      even for DOS-like file systems, because the pathname argument was
457      typically created from the same Makefile variable as orig_prefix came
458      from.  */
459   if (orig_prefix != NULL && curr_prefix != NULL
460       && strncmp (pathname, orig_prefix, orig_prefix_len) == 0)
461     {
462       if (pathname[orig_prefix_len] == '\0')
463         {
464           /* pathname equals orig_prefix.  */
465           char *result = (char *) xmalloc (strlen (curr_prefix) + 1);
466
467 #ifdef NO_XMALLOC
468           if (result != NULL)
469 #endif
470             {
471               strcpy (result, curr_prefix);
472               return result;
473             }
474         }
475       else if (ISSLASH (pathname[orig_prefix_len]))
476         {
477           /* pathname starts with orig_prefix.  */
478           const char *pathname_tail = &pathname[orig_prefix_len];
479           char *result =
480             (char *) xmalloc (curr_prefix_len + strlen (pathname_tail) + 1);
481
482 #ifdef NO_XMALLOC
483           if (result != NULL)
484 #endif
485             {
486               memcpy (result, curr_prefix, curr_prefix_len);
487               strcpy (result + curr_prefix_len, pathname_tail);
488               return result;
489             }
490         }
491     }
492   /* Nothing to relocate.  */
493   return pathname;
494 }
495
496 #endif