Bump to 1.14.1
[platform/upstream/augeas.git] / lib / relocatable.c
1 /* Provide relocatable packages.
2    Copyright (C) 2003-2006, 2008-2016 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 #ifdef __EMX__
51 # define INCL_DOS
52 # include <os2.h>
53
54 # define strcmp  stricmp
55 # define strncmp strnicmp
56 #endif
57
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
67
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
75
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.
79  */
80 #if ((defined _WIN32 || 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
95
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 __WIN32__) && !defined __CYGWIN__
103 #  define ENABLE_COSTLY_RELOCATABLE 1
104 # else
105 #  define ENABLE_COSTLY_RELOCATABLE 0
106 # endif
107 #endif
108
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.  */
117
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)
126 {
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)
131     {
132       /* Duplicate the argument strings.  */
133       char *memory;
134
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
141         {
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;
148         }
149     }
150   orig_prefix = NULL;
151   curr_prefix = NULL;
152   /* Don't worry about wasted memory here - this function is usually only
153      called once.  */
154 }
155
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)
163 {
164   set_this_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
165
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
176 }
177
178 #if !defined IN_LIBRARY || (defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE)
179
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)
193 {
194   char *curr_installdir;
195   const char *rel_installdir;
196
197   if (curr_pathname == NULL)
198     return NULL;
199
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);
208
209   /* Determine the current installation directory.  */
210   {
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;
214
215     while (p > p_base)
216       {
217         p--;
218         if (ISSLASH (*p))
219           break;
220       }
221
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;
230   }
231
232   /* Compute the current installation prefix by removing the trailing
233      rel_installdir from it.  */
234   {
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);
239
240     while (rp > rel_installdir && cp > cp_base)
241       {
242         bool same = false;
243         const char *rpi = rp;
244         const char *cpi = cp;
245
246         while (rpi > rel_installdir && cpi > cp_base)
247           {
248             rpi--;
249             cpi--;
250             if (ISSLASH (*rpi) || ISSLASH (*cpi))
251               {
252                 if (ISSLASH (*rpi) && ISSLASH (*cpi))
253                   same = true;
254                 break;
255               }
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 __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
268           }
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;
275       }
276
277     if (rp > rel_installdir)
278       {
279         /* Unexpected: The curr_installdir does not end with rel_installdir.  */
280         free (curr_installdir);
281         return NULL;
282       }
283
284     {
285       size_t curr_prefix_len = cp - curr_installdir;
286       char *curr_prefix;
287
288       curr_prefix = (char *) xmalloc (curr_prefix_len + 1);
289 #ifdef NO_XMALLOC
290       if (curr_prefix == NULL)
291         {
292           free (curr_installdir);
293           return NULL;
294         }
295 #endif
296       memcpy (curr_prefix, curr_installdir, curr_prefix_len);
297       curr_prefix[curr_prefix_len] = '\0';
298
299       free (curr_installdir);
300
301       return curr_prefix;
302     }
303   }
304 }
305
306 #endif /* !IN_LIBRARY || PIC */
307
308 #if defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE
309
310 /* Full pathname of shared library, or NULL.  */
311 static char *shared_library_fullname;
312
313 #if (defined _WIN32 || 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 <http://cygwin.com/ml/cygwin/2011-01/msg00410.html>).  */
319
320 /* Determine the full pathname of the shared library when it is loaded.  */
321
322 BOOL WINAPI
323 DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved)
324 {
325   (void) reserved;
326
327   if (event == DLL_PROCESS_ATTACH)
328     {
329       /* The DLL is being loaded into an application's address range.  */
330       static char location[MAX_PATH];
331
332       if (!GetModuleFileName (module_handle, location, sizeof (location)))
333         /* Shouldn't happen.  */
334         return FALSE;
335
336       if (!IS_PATH_WITH_DIR (location))
337         /* Shouldn't happen.  */
338         return FALSE;
339
340       shared_library_fullname = strdup (location);
341     }
342
343   return TRUE;
344 }
345
346 #elif defined __EMX__
347
348 extern int  _CRT_init (void);
349 extern void _CRT_term (void);
350 extern void __ctordtorInit (void);
351 extern void __ctordtorTerm (void);
352
353 unsigned long _System
354 _DLL_InitTerm (unsigned long hModule, unsigned long ulFlag)
355 {
356   static char location[CCHMAXPATH];
357
358   switch (ulFlag)
359     {
360       case 0:
361         if (_CRT_init () == -1)
362           return 0;
363
364         __ctordtorInit();
365
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;
370
371         _fnslashify (location);
372         shared_library_fullname = strdup (location);
373         break;
374
375       case 1:
376         __ctordtorTerm();
377
378         _CRT_term ();
379         break;
380     }
381
382   return 1;
383 }
384
385 #else /* Unix */
386
387 static void
388 find_shared_library_fullname ()
389 {
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;
397
398   /* Open the current process' maps file.  It describes one VMA per line.  */
399   fp = fopen ("/proc/self/maps", "r");
400   if (fp)
401     {
402       unsigned long address = (unsigned long) &find_shared_library_fullname;
403       for (;;)
404         {
405           unsigned long start, end;
406           int c;
407
408           if (fscanf (fp, "%lx-%lx", &start, &end) != 2)
409             break;
410           if (address >= start && address <= end - 1)
411             {
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 == '/')
416                 {
417                   size_t size;
418                   int len;
419
420                   ungetc (c, fp);
421                   shared_library_fullname = NULL; size = 0;
422                   len = getline (&shared_library_fullname, &size, fp);
423                   if (len >= 0)
424                     {
425                       /* Success: filled shared_library_fullname.  */
426                       if (len > 0 && shared_library_fullname[len - 1] == '\n')
427                         shared_library_fullname[len - 1] = '\0';
428                     }
429                 }
430               break;
431             }
432           while (c = getc (fp), c != EOF && c != '\n')
433             continue;
434         }
435       fclose (fp);
436     }
437 #endif
438 }
439
440 #endif /* Native Windows / EMX / Unix */
441
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 ()
447 {
448 #if (!((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) \
449      && !defined __EMX__)
450   static bool tried_find_shared_library_fullname;
451   if (!tried_find_shared_library_fullname)
452     {
453       find_shared_library_fullname ();
454       tried_find_shared_library_fullname = true;
455     }
456 #endif
457   return shared_library_fullname;
458 }
459
460 #endif /* PIC */
461
462 /* Returns the pathname, relocated according to the current installation
463    directory.
464    The returned string is either PATHNAME unmodified or a freshly allocated
465    string that you can free with free() after casting it to 'char *'.  */
466 const char *
467 relocate (const char *pathname)
468 {
469 #if defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE
470   static int initialized;
471
472   /* Initialization code for a shared library.  */
473   if (!initialized)
474     {
475       /* At this point, orig_prefix and curr_prefix likely have already been
476          set through the main program's set_program_name_and_installdir
477          function.  This is sufficient in the case that the library has
478          initially been installed in the same orig_prefix.  But we can do
479          better, to also cover the cases that 1. it has been installed
480          in a different prefix before being moved to orig_prefix and (later)
481          to curr_prefix, 2. unlike the program, it has not moved away from
482          orig_prefix.  */
483       const char *orig_installprefix = INSTALLPREFIX;
484       const char *orig_installdir = INSTALLDIR;
485       char *curr_prefix_better;
486
487       curr_prefix_better =
488         compute_curr_prefix (orig_installprefix, orig_installdir,
489                              get_shared_library_fullname ());
490
491       set_relocation_prefix (orig_installprefix,
492                              curr_prefix_better != NULL
493                              ? curr_prefix_better
494                              : curr_prefix);
495
496       if (curr_prefix_better != NULL)
497         free (curr_prefix_better);
498
499       initialized = 1;
500     }
501 #endif
502
503   /* Note: It is not necessary to perform case insensitive comparison here,
504      even for DOS-like file systems, because the pathname argument was
505      typically created from the same Makefile variable as orig_prefix came
506      from.  */
507   if (orig_prefix != NULL && curr_prefix != NULL
508       && strncmp (pathname, orig_prefix, orig_prefix_len) == 0)
509     {
510       if (pathname[orig_prefix_len] == '\0')
511         {
512           /* pathname equals orig_prefix.  */
513           char *result = (char *) xmalloc (strlen (curr_prefix) + 1);
514
515 #ifdef NO_XMALLOC
516           if (result != NULL)
517 #endif
518             {
519               strcpy (result, curr_prefix);
520               return result;
521             }
522         }
523       else if (ISSLASH (pathname[orig_prefix_len]))
524         {
525           /* pathname starts with orig_prefix.  */
526           const char *pathname_tail = &pathname[orig_prefix_len];
527           char *result =
528             (char *) xmalloc (curr_prefix_len + strlen (pathname_tail) + 1);
529
530 #ifdef NO_XMALLOC
531           if (result != NULL)
532 #endif
533             {
534               memcpy (result, curr_prefix, curr_prefix_len);
535               strcpy (result + curr_prefix_len, pathname_tail);
536               return result;
537             }
538         }
539     }
540
541 #ifdef __EMX__
542   if (pathname && ISSLASH (pathname[0]))
543     {
544       const char *unixroot = getenv ("UNIXROOT");
545
546       if (unixroot && HAS_DEVICE (unixroot) && !unixroot[2])
547         {
548           char *result = (char *) xmalloc (2 + strlen (pathname) + 1);
549 #ifdef NO_XMALLOC
550           if (result != NULL)
551 #endif
552             {
553               strcpy (result, unixroot);
554               strcpy (result + 2, pathname);
555               return result;
556             }
557         }
558     }
559 #endif
560
561   /* Nothing to relocate.  */
562   return pathname;
563 }
564
565 #endif