Annotation of embedaddon/libiconv/srclib/relocatable.c, revision 1.1.1.3
1.1 misho 1: /* Provide relocatable packages.
1.1.1.3 ! misho 2: Copyright (C) 2003-2006, 2008-2019 Free Software Foundation, Inc.
1.1 misho 3: Written by Bruno Haible <bruno@clisp.org>, 2003.
4:
1.1.1.2 misho 5: This program is free software: you can redistribute it and/or modify
6: it under the terms of the GNU General Public License as published by
7: the Free Software Foundation; either version 3 of the License, or
8: (at your option) any later version.
1.1 misho 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
1.1.1.2 misho 12: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13: GNU General Public License for more details.
1.1 misho 14:
1.1.1.2 misho 15: You should have received a copy of the GNU General Public License
1.1.1.3 ! misho 16: along with this program. If not, see <https://www.gnu.org/licenses/>. */
1.1 misho 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
1.1.1.2 misho 23: # define _GNU_SOURCE 1
1.1 misho 24: #endif
25:
1.1.1.2 misho 26: #define _GL_USE_STDLIB_ALLOC 1
1.1 misho 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:
1.1.1.3 ! misho 45: #if defined _WIN32 && !defined __CYGWIN__
1.1 misho 46: # define WIN32_LEAN_AND_MEAN
47: # include <windows.h>
48: #endif
49:
1.1.1.3 ! misho 50: #ifdef __EMX__
! 51: # define INCL_DOS
! 52: # include <os2.h>
! 53:
! 54: # define strcmp stricmp
! 55: # define strncmp strnicmp
! 56: #endif
! 57:
1.1 misho 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: */
1.1.1.3 ! misho 80: #if (defined _WIN32 && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__
! 81: /* Native Windows, OS/2, DOS */
1.1 misho 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:
1.1.1.3 ! misho 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 __CYGWIN__
! 103: # define ENABLE_COSTLY_RELOCATABLE 1
! 104: # else
! 105: # define ENABLE_COSTLY_RELOCATABLE 0
! 106: # endif
! 107: #endif
! 108:
1.1 misho 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,
1.1.1.2 misho 125: const char *curr_prefix_arg)
1.1 misho 126: {
127: if (orig_prefix_arg != NULL && curr_prefix_arg != NULL
128: /* Optimization: if orig_prefix and curr_prefix are equal, the
1.1.1.2 misho 129: relocation is a nop. */
1.1 misho 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
1.1.1.2 misho 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: }
1.1 misho 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:
1.1.1.3 ! misho 178: #if !defined IN_LIBRARY || (defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE)
1.1 misho 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,
1.1.1.2 misho 191: const char *orig_installdir,
192: const char *curr_pathname)
1.1 misho 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: {
1.1.1.2 misho 217: p--;
218: if (ISSLASH (*p))
219: break;
1.1 misho 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: {
1.1.1.2 misho 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. */
1.1.1.3 ! misho 259: #if defined _WIN32 || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
! 260: /* Native Windows, Cygwin, OS/2, DOS - case insignificant file system */
1.1.1.2 misho 261: if ((*rpi >= 'a' && *rpi <= 'z' ? *rpi - 'a' + 'A' : *rpi)
262: != (*cpi >= 'a' && *cpi <= 'z' ? *cpi - 'a' + 'A' : *cpi))
263: break;
1.1 misho 264: #else
1.1.1.2 misho 265: if (*rpi != *cpi)
266: break;
1.1 misho 267: #endif
1.1.1.2 misho 268: }
269: if (!same)
270: break;
1.1.1.3 ! misho 271: /* The last pathname component was the same. rpi and cpi now point
1.1.1.2 misho 272: to the slash before it. */
273: rp = rpi;
274: cp = cpi;
1.1 misho 275: }
276:
277: if (rp > rel_installdir)
278: {
1.1.1.2 misho 279: /* Unexpected: The curr_installdir does not end with rel_installdir. */
280: free (curr_installdir);
281: return NULL;
1.1 misho 282: }
283:
284: {
1.1.1.3 ! misho 285: size_t computed_curr_prefix_len = cp - curr_installdir;
! 286: char *computed_curr_prefix;
1.1 misho 287:
1.1.1.3 ! misho 288: computed_curr_prefix = (char *) xmalloc (computed_curr_prefix_len + 1);
1.1 misho 289: #ifdef NO_XMALLOC
1.1.1.3 ! misho 290: if (computed_curr_prefix == NULL)
1.1.1.2 misho 291: {
292: free (curr_installdir);
293: return NULL;
294: }
1.1 misho 295: #endif
1.1.1.3 ! misho 296: memcpy (computed_curr_prefix, curr_installdir, computed_curr_prefix_len);
! 297: computed_curr_prefix[computed_curr_prefix_len] = '\0';
1.1 misho 298:
299: free (curr_installdir);
300:
1.1.1.3 ! misho 301: return computed_curr_prefix;
1.1 misho 302: }
303: }
304: }
305:
306: #endif /* !IN_LIBRARY || PIC */
307:
1.1.1.3 ! misho 308: #if defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE
1.1 misho 309:
310: /* Full pathname of shared library, or NULL. */
311: static char *shared_library_fullname;
312:
1.1.1.3 ! misho 313: #if defined _WIN32 && !defined __CYGWIN__
! 314: /* Native Windows only.
1.1.1.2 misho 315: On Cygwin, it is better to use the Cygwin provided /proc interface, than
1.1.1.3 ! misho 316: to use native Windows API and cygwin_conv_to_posix_path, because it
! 317: supports longer file names
! 318: (see <https://cygwin.com/ml/cygwin/2011-01/msg00410.html>). */
1.1 misho 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)))
1.1.1.2 misho 333: /* Shouldn't happen. */
334: return FALSE;
1.1 misho 335:
336: if (!IS_PATH_WITH_DIR (location))
1.1.1.2 misho 337: /* Shouldn't happen. */
338: return FALSE;
1.1 misho 339:
1.1.1.2 misho 340: shared_library_fullname = strdup (location);
1.1 misho 341: }
342:
343: return TRUE;
344: }
345:
1.1.1.3 ! misho 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:
1.1.1.2 misho 385: #else /* Unix */
1.1 misho 386:
387: static void
388: find_shared_library_fullname ()
389: {
1.1.1.2 misho 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.
1.1.1.3 ! misho 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. */
1.1 misho 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 (;;)
1.1.1.2 misho 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: }
1.1 misho 435: fclose (fp);
436: }
437: #endif
438: }
439:
1.1.1.3 ! misho 440: #endif /* Native Windows / EMX / Unix */
1.1 misho 441:
442: /* Return the full pathname of the current shared library.
443: Return NULL if unknown.
1.1.1.3 ! misho 444: Guaranteed to work only on Linux, EMX, Cygwin, and native Windows. */
1.1 misho 445: static char *
446: get_shared_library_fullname ()
447: {
1.1.1.3 ! misho 448: #if !(defined _WIN32 && !defined __CYGWIN__) && !defined __EMX__
1.1 misho 449: static bool tried_find_shared_library_fullname;
450: if (!tried_find_shared_library_fullname)
451: {
452: find_shared_library_fullname ();
453: tried_find_shared_library_fullname = true;
454: }
455: #endif
456: return shared_library_fullname;
457: }
458:
459: #endif /* PIC */
460:
461: /* Returns the pathname, relocated according to the current installation
462: directory.
463: The returned string is either PATHNAME unmodified or a freshly allocated
464: string that you can free with free() after casting it to 'char *'. */
465: const char *
466: relocate (const char *pathname)
467: {
1.1.1.3 ! misho 468: #if defined PIC && defined INSTALLDIR && ENABLE_COSTLY_RELOCATABLE
1.1 misho 469: static int initialized;
470:
471: /* Initialization code for a shared library. */
472: if (!initialized)
473: {
474: /* At this point, orig_prefix and curr_prefix likely have already been
1.1.1.2 misho 475: set through the main program's set_program_name_and_installdir
476: function. This is sufficient in the case that the library has
477: initially been installed in the same orig_prefix. But we can do
478: better, to also cover the cases that 1. it has been installed
479: in a different prefix before being moved to orig_prefix and (later)
480: to curr_prefix, 2. unlike the program, it has not moved away from
481: orig_prefix. */
1.1 misho 482: const char *orig_installprefix = INSTALLPREFIX;
483: const char *orig_installdir = INSTALLDIR;
484: char *curr_prefix_better;
485:
486: curr_prefix_better =
1.1.1.2 misho 487: compute_curr_prefix (orig_installprefix, orig_installdir,
488: get_shared_library_fullname ());
1.1 misho 489:
490: set_relocation_prefix (orig_installprefix,
1.1.1.2 misho 491: curr_prefix_better != NULL
492: ? curr_prefix_better
493: : curr_prefix);
1.1 misho 494:
495: if (curr_prefix_better != NULL)
1.1.1.2 misho 496: free (curr_prefix_better);
1.1 misho 497:
498: initialized = 1;
499: }
500: #endif
501:
502: /* Note: It is not necessary to perform case insensitive comparison here,
1.1.1.2 misho 503: even for DOS-like file systems, because the pathname argument was
1.1 misho 504: typically created from the same Makefile variable as orig_prefix came
505: from. */
506: if (orig_prefix != NULL && curr_prefix != NULL
507: && strncmp (pathname, orig_prefix, orig_prefix_len) == 0)
508: {
509: if (pathname[orig_prefix_len] == '\0')
1.1.1.2 misho 510: {
511: /* pathname equals orig_prefix. */
512: char *result = (char *) xmalloc (strlen (curr_prefix) + 1);
1.1 misho 513:
514: #ifdef NO_XMALLOC
1.1.1.2 misho 515: if (result != NULL)
1.1 misho 516: #endif
1.1.1.2 misho 517: {
518: strcpy (result, curr_prefix);
519: return result;
520: }
521: }
1.1 misho 522: else if (ISSLASH (pathname[orig_prefix_len]))
1.1.1.2 misho 523: {
524: /* pathname starts with orig_prefix. */
525: const char *pathname_tail = &pathname[orig_prefix_len];
526: char *result =
527: (char *) xmalloc (curr_prefix_len + strlen (pathname_tail) + 1);
1.1 misho 528:
529: #ifdef NO_XMALLOC
1.1.1.2 misho 530: if (result != NULL)
1.1 misho 531: #endif
1.1.1.2 misho 532: {
533: memcpy (result, curr_prefix, curr_prefix_len);
534: strcpy (result + curr_prefix_len, pathname_tail);
535: return result;
536: }
537: }
1.1 misho 538: }
1.1.1.3 ! misho 539:
! 540: #ifdef __EMX__
! 541: # ifdef __KLIBC__
! 542: # undef strncmp
! 543:
! 544: if (strncmp (pathname, "/@unixroot", 10) == 0
! 545: && (pathname[10] == '\0' || ISSLASH (pathname[10])))
! 546: {
! 547: /* kLIBC itself processes /@unixroot prefix */
! 548: return pathname;
! 549: }
! 550: else
! 551: # endif
! 552: if (ISSLASH (pathname[0]))
! 553: {
! 554: const char *unixroot = getenv ("UNIXROOT");
! 555:
! 556: if (unixroot && HAS_DEVICE (unixroot) && unixroot[2] == '\0')
! 557: {
! 558: char *result = (char *) xmalloc (2 + strlen (pathname) + 1);
! 559: #ifdef NO_XMALLOC
! 560: if (result != NULL)
! 561: #endif
! 562: {
! 563: memcpy (result, unixroot, 2);
! 564: strcpy (result + 2, pathname);
! 565: return result;
! 566: }
! 567: }
! 568: }
! 569: #endif
! 570:
1.1 misho 571: /* Nothing to relocate. */
572: return pathname;
573: }
574:
1.1.1.3 ! misho 575: /* Returns the pathname, relocated according to the current installation
! 576: directory.
! 577: This function sets *ALLOCATEDP to the allocated memory, or to NULL if
! 578: no memory allocation occurs. So that, after you're done with the return
! 579: value, to reclaim allocated memory, you can do: free (*ALLOCATEDP). */
! 580: const char *
! 581: relocate2 (const char *pathname, char **allocatedp)
! 582: {
! 583: const char *result = relocate (pathname);
! 584: *allocatedp = (result != pathname ? (char *) result : NULL);
! 585: return result;
! 586: }
! 587:
1.1 misho 588: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>