ldexpl; Update regarding AIX.
[gnulib.git] / lib / relocatable.c
1 /* Provide relocatable packages.
2    Copyright (C) 2003-2006, 2008-2010 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
348   /* Linux has /proc/self/maps. glibc 2 has the getline() function.  */
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 /* (WIN32 or Cygwin) / (Unix except Cygwin) */
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 Woe32.  */
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
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