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