• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Provide relocatable packages.
2    Copyright (C) 2003-2006, 2008-2020 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 <https://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 __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 #if defined _WIN32 && !defined __CYGWIN__
69 /* Don't assume that UNICODE is not defined.  */
70 # undef GetModuleFileName
71 # define GetModuleFileName GetModuleFileNameA
72 #endif
73 
74 /* Faked cheap 'bool'.  */
75 #undef bool
76 #undef false
77 #undef true
78 #define bool int
79 #define false 0
80 #define true 1
81 
82 /* Pathname support.
83    ISSLASH(C)                tests whether C is a directory separator character.
84    IS_FILE_NAME_WITH_DIR(P)  tests whether P contains a directory specification.
85  */
86 #if (defined _WIN32 && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__
87   /* Native Windows, OS/2, DOS */
88 # define ISSLASH(C) ((C) == '/' || (C) == '\\')
89 # define HAS_DEVICE(P) \
90     ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
91      && (P)[1] == ':')
92 # define IS_FILE_NAME_WITH_DIR(P) \
93     (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
94 # define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
95 #else
96   /* Unix */
97 # define ISSLASH(C) ((C) == '/')
98 # define IS_FILE_NAME_WITH_DIR(P) (strchr (P, '/') != NULL)
99 # define FILE_SYSTEM_PREFIX_LEN(P) 0
100 #endif
101 
102 /* Whether to enable the more costly support for relocatable libraries.
103    It allows libraries to be have been installed with a different original
104    prefix than the program.  But it is quite costly, especially on Cygwin
105    platforms, see below.  Therefore we enable it by default only on native
106    Windows platforms.  */
107 #ifndef ENABLE_COSTLY_RELOCATABLE
108 # if defined _WIN32 && !defined __CYGWIN__
109 #  define ENABLE_COSTLY_RELOCATABLE 1
110 # else
111 #  define ENABLE_COSTLY_RELOCATABLE 0
112 # endif
113 #endif
114 
115 /* Original installation prefix.  */
116 static char *orig_prefix;
117 static size_t orig_prefix_len;
118 /* Current installation prefix.  */
119 static char *curr_prefix;
120 static size_t curr_prefix_len;
121 /* These prefixes do not end in a slash.  Anything that will be concatenated
122    to them must start with a slash.  */
123 
124 /* Sets the original and the current installation prefix of this module.
125    Relocation simply replaces a pathname starting with the original prefix
126    by the corresponding pathname with the current prefix instead.  Both
127    prefixes should be directory names without trailing slash (i.e. use ""
128    instead of "/").  */
129 static void
set_this_relocation_prefix(const char * orig_prefix_arg,const char * curr_prefix_arg)130 set_this_relocation_prefix (const char *orig_prefix_arg,
131                             const char *curr_prefix_arg)
132 {
133   if (orig_prefix_arg != NULL && curr_prefix_arg != NULL
134       /* Optimization: if orig_prefix and curr_prefix are equal, the
135          relocation is a nop.  */
136       && strcmp (orig_prefix_arg, curr_prefix_arg) != 0)
137     {
138       /* Duplicate the argument strings.  */
139       char *memory;
140 
141       orig_prefix_len = strlen (orig_prefix_arg);
142       curr_prefix_len = strlen (curr_prefix_arg);
143       memory = (char *) xmalloc (orig_prefix_len + 1 + curr_prefix_len + 1);
144 #ifdef NO_XMALLOC
145       if (memory != NULL)
146 #endif
147         {
148           memcpy (memory, orig_prefix_arg, orig_prefix_len + 1);
149           orig_prefix = memory;
150           memory += orig_prefix_len + 1;
151           memcpy (memory, curr_prefix_arg, curr_prefix_len + 1);
152           curr_prefix = memory;
153           return;
154         }
155     }
156   orig_prefix = NULL;
157   curr_prefix = NULL;
158   /* Don't worry about wasted memory here - this function is usually only
159      called once.  */
160 }
161 
162 /* Sets the original and the current installation prefix of the package.
163    Relocation simply replaces a pathname starting with the original prefix
164    by the corresponding pathname with the current prefix instead.  Both
165    prefixes should be directory names without trailing slash (i.e. use ""
166    instead of "/").  */
167 void
set_relocation_prefix(const char * orig_prefix_arg,const char * curr_prefix_arg)168 set_relocation_prefix (const char *orig_prefix_arg, const char *curr_prefix_arg)
169 {
170   set_this_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
171 
172   /* Now notify all dependent libraries.  */
173 #if DEPENDS_ON_LIBCHARSET
174   libcharset_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
175 #endif
176 #if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109
177   libiconv_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
178 #endif
179 #if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_prefix
180   libintl_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
181 #endif
182 }
183 
184 #if !defined IN_LIBRARY || (defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE)
185 
186 /* Convenience function:
187    Computes the current installation prefix, based on the original
188    installation prefix, the original installation directory of a particular
189    file, and the current pathname of this file.
190    Returns it, freshly allocated.  Returns NULL upon failure.  */
191 #ifdef IN_LIBRARY
192 #define compute_curr_prefix local_compute_curr_prefix
193 static
194 #endif
195 char *
compute_curr_prefix(const char * orig_installprefix,const char * orig_installdir,const char * curr_pathname)196 compute_curr_prefix (const char *orig_installprefix,
197                      const char *orig_installdir,
198                      const char *curr_pathname)
199 {
200   char *curr_installdir;
201   const char *rel_installdir;
202 
203   if (curr_pathname == NULL)
204     return NULL;
205 
206   /* Determine the relative installation directory, relative to the prefix.
207      This is simply the difference between orig_installprefix and
208      orig_installdir.  */
209   if (strncmp (orig_installprefix, orig_installdir, strlen (orig_installprefix))
210       != 0)
211     /* Shouldn't happen - nothing should be installed outside $(prefix).  */
212     return NULL;
213   rel_installdir = orig_installdir + strlen (orig_installprefix);
214 
215   /* Determine the current installation directory.  */
216   {
217     const char *p_base = curr_pathname + FILE_SYSTEM_PREFIX_LEN (curr_pathname);
218     const char *p = curr_pathname + strlen (curr_pathname);
219     char *q;
220 
221     while (p > p_base)
222       {
223         p--;
224         if (ISSLASH (*p))
225           break;
226       }
227 
228     q = (char *) xmalloc (p - curr_pathname + 1);
229 #ifdef NO_XMALLOC
230     if (q == NULL)
231       return NULL;
232 #endif
233     memcpy (q, curr_pathname, p - curr_pathname);
234     q[p - curr_pathname] = '\0';
235     curr_installdir = q;
236   }
237 
238   /* Compute the current installation prefix by removing the trailing
239      rel_installdir from it.  */
240   {
241     const char *rp = rel_installdir + strlen (rel_installdir);
242     const char *cp = curr_installdir + strlen (curr_installdir);
243     const char *cp_base =
244       curr_installdir + FILE_SYSTEM_PREFIX_LEN (curr_installdir);
245 
246     while (rp > rel_installdir && cp > cp_base)
247       {
248         bool same = false;
249         const char *rpi = rp;
250         const char *cpi = cp;
251 
252         while (rpi > rel_installdir && cpi > cp_base)
253           {
254             rpi--;
255             cpi--;
256             if (ISSLASH (*rpi) || ISSLASH (*cpi))
257               {
258                 if (ISSLASH (*rpi) && ISSLASH (*cpi))
259                   same = true;
260                 break;
261               }
262             /* Do case-insensitive comparison if the file system is always or
263                often case-insensitive.  It's better to accept the comparison
264                if the difference is only in case, rather than to fail.  */
265 #if defined _WIN32 || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
266             /* Native Windows, Cygwin, OS/2, DOS - case insignificant file system */
267             if ((*rpi >= 'a' && *rpi <= 'z' ? *rpi - 'a' + 'A' : *rpi)
268                 != (*cpi >= 'a' && *cpi <= 'z' ? *cpi - 'a' + 'A' : *cpi))
269               break;
270 #else
271             if (*rpi != *cpi)
272               break;
273 #endif
274           }
275         if (!same)
276           break;
277         /* The last pathname component was the same.  rpi and cpi now point
278            to the slash before it.  */
279         rp = rpi;
280         cp = cpi;
281       }
282 
283     if (rp > rel_installdir)
284       {
285         /* Unexpected: The curr_installdir does not end with rel_installdir.  */
286         free (curr_installdir);
287         return NULL;
288       }
289 
290     {
291       size_t computed_curr_prefix_len = cp - curr_installdir;
292       char *computed_curr_prefix;
293 
294       computed_curr_prefix = (char *) xmalloc (computed_curr_prefix_len + 1);
295 #ifdef NO_XMALLOC
296       if (computed_curr_prefix == NULL)
297         {
298           free (curr_installdir);
299           return NULL;
300         }
301 #endif
302       memcpy (computed_curr_prefix, curr_installdir, computed_curr_prefix_len);
303       computed_curr_prefix[computed_curr_prefix_len] = '\0';
304 
305       free (curr_installdir);
306 
307       return computed_curr_prefix;
308     }
309   }
310 }
311 
312 #endif /* !IN_LIBRARY || PIC */
313 
314 #if defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE
315 
316 /* Full pathname of shared library, or NULL.  */
317 static char *shared_library_fullname;
318 
319 #if defined _WIN32 && !defined __CYGWIN__
320 /* Native Windows only.
321    On Cygwin, it is better to use the Cygwin provided /proc interface, than
322    to use native Windows API and cygwin_conv_to_posix_path, because it
323    supports longer file names
324    (see <https://cygwin.com/ml/cygwin/2011-01/msg00410.html>).  */
325 
326 /* Determine the full pathname of the shared library when it is loaded.  */
327 
328 BOOL WINAPI
DllMain(HINSTANCE module_handle,DWORD event,LPVOID reserved)329 DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved)
330 {
331   (void) reserved;
332 
333   if (event == DLL_PROCESS_ATTACH)
334     {
335       /* The DLL is being loaded into an application's address range.  */
336       static char location[MAX_PATH];
337 
338       if (!GetModuleFileName (module_handle, location, sizeof (location)))
339         /* Shouldn't happen.  */
340         return FALSE;
341 
342       if (!IS_FILE_NAME_WITH_DIR (location))
343         /* Shouldn't happen.  */
344         return FALSE;
345 
346       shared_library_fullname = strdup (location);
347     }
348 
349   return TRUE;
350 }
351 
352 #elif defined __EMX__
353 
354 extern int  _CRT_init (void);
355 extern void _CRT_term (void);
356 extern void __ctordtorInit (void);
357 extern void __ctordtorTerm (void);
358 
359 unsigned long _System
_DLL_InitTerm(unsigned long hModule,unsigned long ulFlag)360 _DLL_InitTerm (unsigned long hModule, unsigned long ulFlag)
361 {
362   static char location[CCHMAXPATH];
363 
364   switch (ulFlag)
365     {
366       case 0:
367         if (_CRT_init () == -1)
368           return 0;
369 
370         __ctordtorInit();
371 
372         /* See http://cyberkinetica.homeunix.net/os2tk45/cp1/1247_L2H_DosQueryModuleNameSy.html
373            for specification of DosQueryModuleName(). */
374         if (DosQueryModuleName (hModule, sizeof (location), location))
375           return 0;
376 
377         _fnslashify (location);
378         shared_library_fullname = strdup (location);
379         break;
380 
381       case 1:
382         __ctordtorTerm();
383 
384         _CRT_term ();
385         break;
386     }
387 
388   return 1;
389 }
390 
391 #else /* Unix */
392 
393 static void
find_shared_library_fullname()394 find_shared_library_fullname ()
395 {
396 #if (defined __linux__ && (__GLIBC__ >= 2 || defined __UCLIBC__)) || defined __CYGWIN__
397   /* Linux has /proc/self/maps. glibc 2 and uClibc have the getline()
398      function.
399      Cygwin >= 1.5 has /proc/self/maps and the getline() function too.
400      But it is costly: ca. 0.3 ms on Linux, 3 ms on Cygwin 1.5, and 5 ms on
401      Cygwin 1.7.  */
402   FILE *fp;
403 
404   /* Open the current process' maps file.  It describes one VMA per line.  */
405   fp = fopen ("/proc/self/maps", "r");
406   if (fp)
407     {
408       unsigned long address = (unsigned long) &find_shared_library_fullname;
409       for (;;)
410         {
411           unsigned long start, end;
412           int c;
413 
414           if (fscanf (fp, "%lx-%lx", &start, &end) != 2)
415             break;
416           if (address >= start && address <= end - 1)
417             {
418               /* Found it.  Now see if this line contains a filename.  */
419               while (c = getc (fp), c != EOF && c != '\n' && c != '/')
420                 continue;
421               if (c == '/')
422                 {
423                   size_t size;
424                   int len;
425 
426                   ungetc (c, fp);
427                   shared_library_fullname = NULL; size = 0;
428                   len = getline (&shared_library_fullname, &size, fp);
429                   if (len >= 0)
430                     {
431                       /* Success: filled shared_library_fullname.  */
432                       if (len > 0 && shared_library_fullname[len - 1] == '\n')
433                         shared_library_fullname[len - 1] = '\0';
434                     }
435                 }
436               break;
437             }
438           while (c = getc (fp), c != EOF && c != '\n')
439             continue;
440         }
441       fclose (fp);
442     }
443 #endif
444 }
445 
446 #endif /* Native Windows / EMX / Unix */
447 
448 /* Return the full pathname of the current shared library.
449    Return NULL if unknown.
450    Guaranteed to work only on Linux, EMX, Cygwin, and native Windows.  */
451 static char *
get_shared_library_fullname()452 get_shared_library_fullname ()
453 {
454 #if !(defined _WIN32 && !defined __CYGWIN__) && !defined __EMX__
455   static bool tried_find_shared_library_fullname;
456   if (!tried_find_shared_library_fullname)
457     {
458       find_shared_library_fullname ();
459       tried_find_shared_library_fullname = true;
460     }
461 #endif
462   return shared_library_fullname;
463 }
464 
465 #endif /* PIC */
466 
467 /* Returns the pathname, relocated according to the current installation
468    directory.
469    The returned string is either PATHNAME unmodified or a freshly allocated
470    string that you can free with free() after casting it to 'char *'.  */
471 const char *
relocate(const char * pathname)472 relocate (const char *pathname)
473 {
474 #if defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE
475   static int initialized;
476 
477   /* Initialization code for a shared library.  */
478   if (!initialized)
479     {
480       /* At this point, orig_prefix and curr_prefix likely have already been
481          set through the main program's set_program_name_and_installdir
482          function.  This is sufficient in the case that the library has
483          initially been installed in the same orig_prefix.  But we can do
484          better, to also cover the cases that 1. it has been installed
485          in a different prefix before being moved to orig_prefix and (later)
486          to curr_prefix, 2. unlike the program, it has not moved away from
487          orig_prefix.  */
488       const char *orig_installprefix = INSTALLPREFIX;
489       const char *orig_installdir = INSTALLDIR;
490       char *curr_prefix_better;
491 
492       curr_prefix_better =
493         compute_curr_prefix (orig_installprefix, orig_installdir,
494                              get_shared_library_fullname ());
495 
496       set_relocation_prefix (orig_installprefix,
497                              curr_prefix_better != NULL
498                              ? curr_prefix_better
499                              : curr_prefix);
500 
501       if (curr_prefix_better != NULL)
502         free (curr_prefix_better);
503 
504       initialized = 1;
505     }
506 #endif
507 
508   /* Note: It is not necessary to perform case insensitive comparison here,
509      even for DOS-like file systems, because the pathname argument was
510      typically created from the same Makefile variable as orig_prefix came
511      from.  */
512   if (orig_prefix != NULL && curr_prefix != NULL
513       && strncmp (pathname, orig_prefix, orig_prefix_len) == 0)
514     {
515       if (pathname[orig_prefix_len] == '\0')
516         {
517           /* pathname equals orig_prefix.  */
518           char *result = (char *) xmalloc (strlen (curr_prefix) + 1);
519 
520 #ifdef NO_XMALLOC
521           if (result != NULL)
522 #endif
523             {
524               strcpy (result, curr_prefix);
525               return result;
526             }
527         }
528       else if (ISSLASH (pathname[orig_prefix_len]))
529         {
530           /* pathname starts with orig_prefix.  */
531           const char *pathname_tail = &pathname[orig_prefix_len];
532           char *result =
533             (char *) xmalloc (curr_prefix_len + strlen (pathname_tail) + 1);
534 
535 #ifdef NO_XMALLOC
536           if (result != NULL)
537 #endif
538             {
539               memcpy (result, curr_prefix, curr_prefix_len);
540               strcpy (result + curr_prefix_len, pathname_tail);
541               return result;
542             }
543         }
544     }
545 
546 #ifdef __EMX__
547 # ifdef __KLIBC__
548 #  undef strncmp
549 
550   if (strncmp (pathname, "/@unixroot", 10) == 0
551       && (pathname[10] == '\0' || ISSLASH (pathname[10])))
552     {
553       /* kLIBC itself processes /@unixroot prefix */
554       return pathname;
555     }
556   else
557 # endif
558   if (ISSLASH (pathname[0]))
559     {
560       const char *unixroot = getenv ("UNIXROOT");
561 
562       if (unixroot && HAS_DEVICE (unixroot) && unixroot[2] == '\0')
563         {
564           char *result = (char *) xmalloc (2 + strlen (pathname) + 1);
565 #ifdef NO_XMALLOC
566           if (result != NULL)
567 #endif
568             {
569               memcpy (result, unixroot, 2);
570               strcpy (result + 2, pathname);
571               return result;
572             }
573         }
574     }
575 #endif
576 
577   /* Nothing to relocate.  */
578   return pathname;
579 }
580 
581 /* Returns the pathname, relocated according to the current installation
582    directory.
583    This function sets *ALLOCATEDP to the allocated memory, or to NULL if
584    no memory allocation occurs.  So that, after you're done with the return
585    value, to reclaim allocated memory, you can do: free (*ALLOCATEDP).  */
586 const char *
relocate2(const char * pathname,char ** allocatedp)587 relocate2 (const char *pathname, char **allocatedp)
588 {
589   const char *result = relocate (pathname);
590   *allocatedp = (result != pathname ? (char *) result : NULL);
591   return result;
592 }
593 
594 #endif
595