You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

relocatable.c 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. /* Provide relocatable packages.
  2. Copyright (C) 2003 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 Library 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. Library General Public License for more details.
  12. You should have received a copy of the GNU Library General Public
  13. License along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  15. USA. */
  16. /* Tell glibc's <stdio.h> to provide a prototype for getline().
  17. This must come before <config.h> because <config.h> may include
  18. <features.h>, and once <features.h> has been included, it's too late. */
  19. #ifndef _GNU_SOURCE
  20. # define _GNU_SOURCE 1
  21. #endif
  22. #ifdef HAVE_CONFIG_H
  23. # include "config.h"
  24. #endif
  25. /* Specification. */
  26. #include "relocatable.h"
  27. #if ENABLE_RELOCATABLE
  28. #include <stddef.h>
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #ifdef NO_XMALLOC
  33. # define xmalloc malloc
  34. #else
  35. # include "xalloc.h"
  36. #endif
  37. #if defined _WIN32 || defined __WIN32__
  38. # define WIN32_LEAN_AND_MEAN
  39. # include <windows.h>
  40. #endif
  41. #if DEPENDS_ON_LIBCHARSET
  42. # include <libcharset.h>
  43. #endif
  44. #if DEPENDS_ON_LIBICONV && HAVE_ICONV
  45. # include <iconv.h>
  46. #endif
  47. #if DEPENDS_ON_LIBINTL && ENABLE_NLS
  48. # include <libintl.h>
  49. #endif
  50. /* Faked cheap 'bool'. */
  51. #undef bool
  52. #undef false
  53. #undef true
  54. #define bool int
  55. #define false 0
  56. #define true 1
  57. /* Pathname support.
  58. ISSLASH(C) tests whether C is a directory separator character.
  59. IS_PATH_WITH_DIR(P) tests whether P contains a directory specification.
  60. */
  61. #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
  62. /* Win32, OS/2, DOS */
  63. # define ISSLASH(C) ((C) == '/' || (C) == '\\')
  64. # define HAS_DEVICE(P) \
  65. ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
  66. && (P)[1] == ':')
  67. # define IS_PATH_WITH_DIR(P) \
  68. (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
  69. # define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
  70. #else
  71. /* Unix */
  72. # define ISSLASH(C) ((C) == '/')
  73. # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
  74. # define FILESYSTEM_PREFIX_LEN(P) 0
  75. #endif
  76. /* Original installation prefix. */
  77. static char *orig_prefix;
  78. static size_t orig_prefix_len;
  79. /* Current installation prefix. */
  80. static char *curr_prefix;
  81. static size_t curr_prefix_len;
  82. /* These prefixes do not end in a slash. Anything that will be concatenated
  83. to them must start with a slash. */
  84. /* Sets the original and the current installation prefix of this module.
  85. Relocation simply replaces a pathname starting with the original prefix
  86. by the corresponding pathname with the current prefix instead. Both
  87. prefixes should be directory names without trailing slash (i.e. use ""
  88. instead of "/"). */
  89. static void
  90. set_this_relocation_prefix (const char *orig_prefix_arg,
  91. const char *curr_prefix_arg)
  92. {
  93. if (orig_prefix_arg != NULL && curr_prefix_arg != NULL
  94. /* Optimization: if orig_prefix and curr_prefix are equal, the
  95. relocation is a nop. */
  96. && strcmp (orig_prefix_arg, curr_prefix_arg) != 0)
  97. {
  98. /* Duplicate the argument strings. */
  99. char *memory;
  100. orig_prefix_len = strlen (orig_prefix_arg);
  101. curr_prefix_len = strlen (curr_prefix_arg);
  102. memory = (char *) xmalloc (orig_prefix_len + 1 + curr_prefix_len + 1);
  103. #ifdef NO_XMALLOC
  104. if (memory != NULL)
  105. #endif
  106. {
  107. memcpy (memory, orig_prefix_arg, orig_prefix_len + 1);
  108. orig_prefix = memory;
  109. memory += orig_prefix_len + 1;
  110. memcpy (memory, curr_prefix_arg, curr_prefix_len + 1);
  111. curr_prefix = memory;
  112. return;
  113. }
  114. }
  115. orig_prefix = NULL;
  116. curr_prefix = NULL;
  117. /* Don't worry about wasted memory here - this function is usually only
  118. called once. */
  119. }
  120. /* Sets the original and the current installation prefix of the package.
  121. Relocation simply replaces a pathname starting with the original prefix
  122. by the corresponding pathname with the current prefix instead. Both
  123. prefixes should be directory names without trailing slash (i.e. use ""
  124. instead of "/"). */
  125. void
  126. set_relocation_prefix (const char *orig_prefix_arg, const char *curr_prefix_arg)
  127. {
  128. set_this_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
  129. /* Now notify all dependent libraries. */
  130. #if DEPENDS_ON_LIBCHARSET
  131. libcharset_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
  132. #endif
  133. #if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109
  134. libiconv_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
  135. #endif
  136. #if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_prefix
  137. libintl_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
  138. #endif
  139. }
  140. #if !defined IN_LIBRARY || (defined PIC && defined INSTALLDIR)
  141. /* Convenience function:
  142. Computes the current installation prefix, based on the original
  143. installation prefix, the original installation directory of a particular
  144. file, and the current pathname of this file. Returns NULL upon failure. */
  145. #ifdef IN_LIBRARY
  146. #define compute_curr_prefix local_compute_curr_prefix
  147. static
  148. #endif
  149. const char *
  150. compute_curr_prefix (const char *orig_installprefix,
  151. const char *orig_installdir,
  152. const char *curr_pathname)
  153. {
  154. const char *curr_installdir;
  155. const char *rel_installdir;
  156. if (curr_pathname == NULL)
  157. return NULL;
  158. /* Determine the relative installation directory, relative to the prefix.
  159. This is simply the difference between orig_installprefix and
  160. orig_installdir. */
  161. if (strncmp (orig_installprefix, orig_installdir, strlen (orig_installprefix))
  162. != 0)
  163. /* Shouldn't happen - nothing should be installed outside $(prefix). */
  164. return NULL;
  165. rel_installdir = orig_installdir + strlen (orig_installprefix);
  166. /* Determine the current installation directory. */
  167. {
  168. const char *p_base = curr_pathname + FILESYSTEM_PREFIX_LEN (curr_pathname);
  169. const char *p = curr_pathname + strlen (curr_pathname);
  170. char *q;
  171. while (p > p_base)
  172. {
  173. p--;
  174. if (ISSLASH (*p))
  175. break;
  176. }
  177. q = (char *) xmalloc (p - curr_pathname + 1);
  178. #ifdef NO_XMALLOC
  179. if (q == NULL)
  180. return NULL;
  181. #endif
  182. memcpy (q, curr_pathname, p - curr_pathname);
  183. q[p - curr_pathname] = '\0';
  184. curr_installdir = q;
  185. }
  186. /* Compute the current installation prefix by removing the trailing
  187. rel_installdir from it. */
  188. {
  189. const char *rp = rel_installdir + strlen (rel_installdir);
  190. const char *cp = curr_installdir + strlen (curr_installdir);
  191. const char *cp_base =
  192. curr_installdir + FILESYSTEM_PREFIX_LEN (curr_installdir);
  193. while (rp > rel_installdir && cp > cp_base)
  194. {
  195. bool same = false;
  196. const char *rpi = rp;
  197. const char *cpi = cp;
  198. while (rpi > rel_installdir && cpi > cp_base)
  199. {
  200. rpi--;
  201. cpi--;
  202. if (ISSLASH (*rpi) || ISSLASH (*cpi))
  203. {
  204. if (ISSLASH (*rpi) && ISSLASH (*cpi))
  205. same = true;
  206. break;
  207. }
  208. #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
  209. /* Win32, OS/2, DOS - case insignificant filesystem */
  210. if ((*rpi >= 'a' && *rpi <= 'z' ? *rpi - 'a' + 'A' : *rpi)
  211. != (*cpi >= 'a' && *cpi <= 'z' ? *cpi - 'a' + 'A' : *cpi))
  212. break;
  213. #else
  214. if (*rpi != *cpi)
  215. break;
  216. #endif
  217. }
  218. if (!same)
  219. break;
  220. /* The last pathname component was the same. opi and cpi now point
  221. to the slash before it. */
  222. rp = rpi;
  223. cp = cpi;
  224. }
  225. if (rp > rel_installdir)
  226. /* Unexpected: The curr_installdir does not end with rel_installdir. */
  227. return NULL;
  228. {
  229. size_t curr_prefix_len = cp - curr_installdir;
  230. char *curr_prefix;
  231. curr_prefix = (char *) xmalloc (curr_prefix_len + 1);
  232. #ifdef NO_XMALLOC
  233. if (curr_prefix == NULL)
  234. return NULL;
  235. #endif
  236. memcpy (curr_prefix, curr_installdir, curr_prefix_len);
  237. curr_prefix[curr_prefix_len] = '\0';
  238. return curr_prefix;
  239. }
  240. }
  241. }
  242. #endif /* !IN_LIBRARY || PIC */
  243. #if defined PIC && defined INSTALLDIR
  244. /* Full pathname of shared library, or NULL. */
  245. static char *shared_library_fullname;
  246. #if defined _WIN32 || defined __WIN32__
  247. /* Determine the full pathname of the shared library when it is loaded. */
  248. BOOL WINAPI
  249. DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved)
  250. {
  251. (void) reserved;
  252. if (event == DLL_PROCESS_ATTACH)
  253. {
  254. /* The DLL is being loaded into an application's address range. */
  255. static char location[MAX_PATH];
  256. if (!GetModuleFileName (module_handle, location, sizeof (location)))
  257. /* Shouldn't happen. */
  258. return FALSE;
  259. if (!IS_PATH_WITH_DIR (location))
  260. /* Shouldn't happen. */
  261. return FALSE;
  262. shared_library_fullname = strdup (location);
  263. }
  264. return TRUE;
  265. }
  266. #else /* Unix */
  267. static void
  268. find_shared_library_fullname ()
  269. {
  270. #if defined __linux__ && __GLIBC__ >= 2
  271. /* Linux has /proc/self/maps. glibc 2 has the getline() function. */
  272. FILE *fp;
  273. /* Open the current process' maps file. It describes one VMA per line. */
  274. fp = fopen ("/proc/self/maps", "r");
  275. if (fp)
  276. {
  277. unsigned long address = (unsigned long) &find_shared_library_fullname;
  278. for (;;)
  279. {
  280. unsigned long start, end;
  281. int c;
  282. if (fscanf (fp, "%lx-%lx", &start, &end) != 2)
  283. break;
  284. if (address >= start && address <= end - 1)
  285. {
  286. /* Found it. Now see if this line contains a filename. */
  287. while (c = getc (fp), c != EOF && c != '\n' && c != '/')
  288. continue;
  289. if (c == '/')
  290. {
  291. size_t size;
  292. int len;
  293. ungetc (c, fp);
  294. shared_library_fullname = NULL; size = 0;
  295. len = getline (&shared_library_fullname, &size, fp);
  296. if (len >= 0)
  297. {
  298. /* Success: filled shared_library_fullname. */
  299. if (len > 0 && shared_library_fullname[len - 1] == '\n')
  300. shared_library_fullname[len - 1] = '\0';
  301. }
  302. }
  303. break;
  304. }
  305. while (c = getc (fp), c != EOF && c != '\n')
  306. continue;
  307. }
  308. fclose (fp);
  309. }
  310. #endif
  311. }
  312. #endif /* WIN32 / Unix */
  313. /* Return the full pathname of the current shared library.
  314. Return NULL if unknown.
  315. Guaranteed to work only on Linux and Woe32. */
  316. static char *
  317. get_shared_library_fullname ()
  318. {
  319. #if !(defined _WIN32 || defined __WIN32__)
  320. static bool tried_find_shared_library_fullname;
  321. if (!tried_find_shared_library_fullname)
  322. {
  323. find_shared_library_fullname ();
  324. tried_find_shared_library_fullname = true;
  325. }
  326. #endif
  327. return shared_library_fullname;
  328. }
  329. #endif /* PIC */
  330. /* Returns the pathname, relocated according to the current installation
  331. directory. */
  332. const char *
  333. relocate (const char *pathname)
  334. {
  335. #if defined PIC && defined INSTALLDIR
  336. static int initialized;
  337. /* Initialization code for a shared library. */
  338. if (!initialized)
  339. {
  340. /* At this point, orig_prefix and curr_prefix likely have already been
  341. set through the main program's set_program_name_and_installdir
  342. function. This is sufficient in the case that the library has
  343. initially been installed in the same orig_prefix. But we can do
  344. better, to also cover the cases that 1. it has been installed
  345. in a different prefix before being moved to orig_prefix and (later)
  346. to curr_prefix, 2. unlike the program, it has not moved away from
  347. orig_prefix. */
  348. const char *orig_installprefix = INSTALLPREFIX;
  349. const char *orig_installdir = INSTALLDIR;
  350. const char *curr_prefix_better;
  351. curr_prefix_better =
  352. compute_curr_prefix (orig_installprefix, orig_installdir,
  353. get_shared_library_fullname ());
  354. if (curr_prefix_better == NULL)
  355. curr_prefix_better = curr_prefix;
  356. set_relocation_prefix (orig_installprefix, curr_prefix_better);
  357. initialized = 1;
  358. }
  359. #endif
  360. /* Note: It is not necessary to perform case insensitive comparison here,
  361. even for DOS-like filesystems, because the pathname argument was
  362. typically created from the same Makefile variable as orig_prefix came
  363. from. */
  364. if (orig_prefix != NULL && curr_prefix != NULL
  365. && strncmp (pathname, orig_prefix, orig_prefix_len) == 0)
  366. {
  367. if (pathname[orig_prefix_len] == '\0')
  368. /* pathname equals orig_prefix. */
  369. return curr_prefix;
  370. if (ISSLASH (pathname[orig_prefix_len]))
  371. {
  372. /* pathname starts with orig_prefix. */
  373. const char *pathname_tail = &pathname[orig_prefix_len];
  374. char *result =
  375. (char *) xmalloc (curr_prefix_len + strlen (pathname_tail) + 1);
  376. #ifdef NO_XMALLOC
  377. if (result != NULL)
  378. #endif
  379. {
  380. memcpy (result, curr_prefix, curr_prefix_len);
  381. strcpy (result + curr_prefix_len, pathname_tail);
  382. return result;
  383. }
  384. }
  385. }
  386. /* Nothing to relocate. */
  387. return pathname;
  388. }
  389. #endif