relocatable.c 18 KB

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