]> git.uio.no Git - u/mrichter/AliRoot.git/blame - LHAPDF/lhapdf5.5.1/src/binreloc.c
EPS09 added.
[u/mrichter/AliRoot.git] / LHAPDF / lhapdf5.5.1 / src / binreloc.c
CommitLineData
0caf84a5 1/*
2 * BinReloc - a library for creating relocatable executables
3 * Written by: Hongli Lai <h.lai@chello.nl>
4 * http://autopackage.org/
5 *
6 * This source code is public domain. You can relicense this code
7 * under whatever license you want.
8 *
9 * See http://autopackage.org/docs/binreloc/ for
10 * more information and how to use this.
11 */
12
13#ifndef __BINRELOC_C__
14#define __BINRELOC_C__
15
16#ifdef ENABLE_BINRELOC
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <unistd.h>
20#endif /* ENABLE_BINRELOC */
21#include <stdio.h>
22#include <stdlib.h>
23#include <limits.h>
24#include <string.h>
25#include "binreloc.h"
26
27#ifdef __cplusplus
28extern "C" {
29#endif /* __cplusplus */
30
03f930e4 31extern char* strdup(const char*);
0caf84a5 32
33/** @internal
34 * Find the canonical filename of the executable. Returns the filename
35 * (which must be freed) or NULL on error. If the parameter 'error' is
36 * not NULL, the error code will be stored there, if an error occured.
37 */
38static char *
39_br_find_exe (BrInitError *error)
40{
41#ifndef ENABLE_BINRELOC
42 if (error)
43 *error = BR_INIT_ERROR_DISABLED;
44 return NULL;
45#else
46 char *path, *path2, *line, *result;
47 size_t buf_size;
48 ssize_t size;
49 struct stat stat_buf;
50 FILE *f;
51
52 /* Read from /proc/self/exe (symlink) */
53 if (sizeof (path) > SSIZE_MAX)
54 buf_size = SSIZE_MAX - 1;
55 else
56 buf_size = PATH_MAX - 1;
57 path = (char *) malloc (buf_size);
58 if (path == NULL) {
59 /* Cannot allocate memory. */
60 if (error)
61 *error = BR_INIT_ERROR_NOMEM;
62 return NULL;
63 }
64 path2 = (char *) malloc (buf_size);
65 if (path2 == NULL) {
66 /* Cannot allocate memory. */
67 if (error)
68 *error = BR_INIT_ERROR_NOMEM;
69 free (path);
70 return NULL;
71 }
72
73 strncpy (path2, "/proc/self/exe", buf_size - 1);
74
75 while (1) {
76 int i;
77
78 size = readlink (path2, path, buf_size - 1);
79 if (size == -1) {
80 /* Error. */
81 free (path2);
82 break;
83 }
84
85 /* readlink() success. */
86 path[size] = '\0';
87
88 /* Check whether the symlink's target is also a symlink.
89 * We want to get the final target. */
90 i = stat (path, &stat_buf);
91 if (i == -1) {
92 /* Error. */
93 free (path2);
94 break;
95 }
96
97 /* stat() success. */
98 if (!S_ISLNK (stat_buf.st_mode)) {
99 /* path is not a symlink. Done. */
100 free (path2);
101 return path;
102 }
103
104 /* path is a symlink. Continue loop and resolve this. */
105 strncpy (path, path2, buf_size - 1);
106 }
107
108
109 /* readlink() or stat() failed; this can happen when the program is
110 * running in Valgrind 2.2. Read from /proc/self/maps as fallback. */
111
112 buf_size = PATH_MAX + 128;
113 line = (char *) realloc (path, buf_size);
114 if (line == NULL) {
115 /* Cannot allocate memory. */
116 free (path);
117 if (error)
118 *error = BR_INIT_ERROR_NOMEM;
119 return NULL;
120 }
121
122 f = fopen ("/proc/self/maps", "r");
123 if (f == NULL) {
124 free (line);
125 if (error)
126 *error = BR_INIT_ERROR_OPEN_MAPS;
127 return NULL;
128 }
129
130 /* The first entry should be the executable name. */
131 result = fgets (line, (int) buf_size, f);
132 if (result == NULL) {
133 fclose (f);
134 free (line);
135 if (error)
136 *error = BR_INIT_ERROR_READ_MAPS;
137 return NULL;
138 }
139
140 /* Get rid of newline character. */
141 buf_size = strlen (line);
142 if (buf_size <= 0) {
143 /* Huh? An empty string? */
144 fclose (f);
145 free (line);
146 if (error)
147 *error = BR_INIT_ERROR_INVALID_MAPS;
148 return NULL;
149 }
150 if (line[buf_size - 1] == 10)
151 line[buf_size - 1] = 0;
152
153 /* Extract the filename; it is always an absolute path. */
154 path = strchr (line, '/');
155
156 /* Sanity check. */
157 if (strstr (line, " r-xp ") == NULL || path == NULL) {
158 fclose (f);
159 free (line);
160 if (error)
161 *error = BR_INIT_ERROR_INVALID_MAPS;
162 return NULL;
163 }
164
165 path = strdup (path);
166 free (line);
167 fclose (f);
168 return path;
169#endif /* ENABLE_BINRELOC */
170}
171
172
173/** @internal
174 * Find the canonical filename of the executable which owns symbol.
175 * Returns a filename which must be freed, or NULL on error.
176 */
177static char *
178_br_find_exe_for_symbol (const void *symbol, BrInitError *error)
179{
180#ifndef ENABLE_BINRELOC
181 if (error)
182 *error = BR_INIT_ERROR_DISABLED;
183 return (char *) NULL;
184#else
185 #define SIZE PATH_MAX + 100
186 FILE *f;
187 size_t address_string_len;
188 char *address_string, line[SIZE], *found;
189
190 if (symbol == NULL)
191 return (char *) NULL;
192
193 f = fopen ("/proc/self/maps", "r");
194 if (f == NULL)
195 return (char *) NULL;
196
197 address_string_len = 4;
198 address_string = (char *) malloc (address_string_len);
199 found = (char *) NULL;
200
201 while (!feof (f)) {
202 char *start_addr, *end_addr, *end_addr_end, *file;
203 void *start_addr_p, *end_addr_p;
204 size_t len;
205
206 if (fgets (line, SIZE, f) == NULL)
207 break;
208
209 /* Sanity check. */
210 if (strstr (line, " r-xp ") == NULL || strchr (line, '/') == NULL)
211 continue;
212
213 /* Parse line. */
214 start_addr = line;
215 end_addr = strchr (line, '-');
216 file = strchr (line, '/');
217
218 /* More sanity check. */
219 if (!(file > end_addr && end_addr != NULL && end_addr[0] == '-'))
220 continue;
221
222 end_addr[0] = '\0';
223 end_addr++;
224 end_addr_end = strchr (end_addr, ' ');
225 if (end_addr_end == NULL)
226 continue;
227
228 end_addr_end[0] = '\0';
229 len = strlen (file);
230 if (len == 0)
231 continue;
232 if (file[len - 1] == '\n')
233 file[len - 1] = '\0';
234
235 /* Get rid of "(deleted)" from the filename. */
236 len = strlen (file);
237 if (len > 10 && strcmp (file + len - 10, " (deleted)") == 0)
238 file[len - 10] = '\0';
239
240 /* I don't know whether this can happen but better safe than sorry. */
241 len = strlen (start_addr);
242 if (len != strlen (end_addr))
243 continue;
244
245
246 /* Transform the addresses into a string in the form of 0xdeadbeef,
247 * then transform that into a pointer. */
248 if (address_string_len < len + 3) {
249 address_string_len = len + 3;
250 address_string = (char *) realloc (address_string, address_string_len);
251 }
252
253 memcpy (address_string, "0x", 2);
254 memcpy (address_string + 2, start_addr, len);
255 address_string[2 + len] = '\0';
256 sscanf (address_string, "%p", &start_addr_p);
257
258 memcpy (address_string, "0x", 2);
259 memcpy (address_string + 2, end_addr, len);
260 address_string[2 + len] = '\0';
261 sscanf (address_string, "%p", &end_addr_p);
262
263
264 if (symbol >= start_addr_p && symbol < end_addr_p) {
265 found = file;
266 break;
267 }
268 }
269
270 free (address_string);
271 fclose (f);
272
273 if (found == NULL)
274 return (char *) NULL;
275 else
276 return strdup (found);
277#endif /* ENABLE_BINRELOC */
278}
279
280
281#ifndef BINRELOC_RUNNING_DOXYGEN
282 #undef NULL
283 #define NULL ((void *) 0) /* typecasted as char* for C++ type safeness */
284#endif
285
286static char *exe = (char *) NULL;
287
288
289/** Initialize the BinReloc library (for applications).
290 *
291 * This function must be called before using any other BinReloc functions.
292 * It attempts to locate the application's canonical filename.
293 *
294 * @note If you want to use BinReloc for a library, then you should call
295 * br_init_lib() instead.
296 *
297 * @param error If BinReloc failed to initialize, then the error code will
298 * be stored in this variable. Set to NULL if you want to
299 * ignore this. See #BrInitError for a list of error codes.
300 *
301 * @returns 1 on success, 0 if BinReloc failed to initialize.
302 */
303int
304br_init (BrInitError *error)
305{
306 exe = _br_find_exe (error);
307 return exe != NULL;
308}
309
310
311/** Initialize the BinReloc library (for libraries).
312 *
313 * This function must be called before using any other BinReloc functions.
314 * It attempts to locate the calling library's canonical filename.
315 *
316 * @note The BinReloc source code MUST be included in your library, or this
317 * function won't work correctly.
318 *
319 * @param error If BinReloc failed to initialize, then the error code will
320 * be stored in this variable. Set to NULL if you want to
321 * ignore this. See #BrInitError for a list of error codes.
322 *
323 * @returns 1 on success, 0 if a filename cannot be found.
324 */
325int
326br_init_lib (BrInitError *error)
327{
328 exe = _br_find_exe_for_symbol ((const void *) "", error);
329 return exe != NULL;
330}
331
332
333/** Find the canonical filename of the current application.
334 *
335 * @param default_exe A default filename which will be used as fallback.
336 * @returns A string containing the application's canonical filename,
337 * which must be freed when no longer necessary. If BinReloc is
338 * not initialized, or if br_init() failed, then a copy of
339 * default_exe will be returned. If default_exe is NULL, then
340 * NULL will be returned.
341 */
342char *
343br_find_exe (const char *default_exe)
344{
345 if (exe == (char *) NULL) {
346 /* BinReloc is not initialized. */
347 if (default_exe != (const char *) NULL)
348 return strdup (default_exe);
349 else
350 return (char *) NULL;
351 }
352 return strdup (exe);
353}
354
355
356/** Locate the directory in which the current application is installed.
357 *
358 * The prefix is generated by the following pseudo-code evaluation:
359 * \code
360 * dirname(exename)
361 * \endcode
362 *
363 * @param default_dir A default directory which will used as fallback.
364 * @return A string containing the directory, which must be freed when no
365 * longer necessary. If BinReloc is not initialized, or if the
366 * initialization function failed, then a copy of default_dir
367 * will be returned. If default_dir is NULL, then NULL will be
368 * returned.
369 */
370char *
371br_find_exe_dir (const char *default_dir)
372{
373 if (exe == NULL) {
374 /* BinReloc not initialized. */
375 if (default_dir != NULL)
376 return strdup (default_dir);
377 else
378 return NULL;
379 }
380
381 return br_dirname (exe);
382}
383
384
385/** Locate the prefix in which the current application is installed.
386 *
387 * The prefix is generated by the following pseudo-code evaluation:
388 * \code
389 * dirname(dirname(exename))
390 * \endcode
391 *
392 * @param default_prefix A default prefix which will used as fallback.
393 * @return A string containing the prefix, which must be freed when no
394 * longer necessary. If BinReloc is not initialized, or if
395 * the initialization function failed, then a copy of default_prefix
396 * will be returned. If default_prefix is NULL, then NULL will be returned.
397 */
398char *
399br_find_prefix (const char *default_prefix)
400{
401 char *dir1, *dir2;
402
403 if (exe == (char *) NULL) {
404 /* BinReloc not initialized. */
405 if (default_prefix != (const char *) NULL)
406 return strdup (default_prefix);
407 else
408 return (char *) NULL;
409 }
410
411 dir1 = br_dirname (exe);
412 dir2 = br_dirname (dir1);
413 free (dir1);
414 return dir2;
415}
416
417
418/** Locate the application's binary folder.
419 *
420 * The path is generated by the following pseudo-code evaluation:
421 * \code
422 * prefix + "/bin"
423 * \endcode
424 *
425 * @param default_bin_dir A default path which will used as fallback.
426 * @return A string containing the bin folder's path, which must be freed when
427 * no longer necessary. If BinReloc is not initialized, or if
428 * the initialization function failed, then a copy of default_bin_dir will
429 * be returned. If default_bin_dir is NULL, then NULL will be returned.
430 */
431char *
432br_find_bin_dir (const char *default_bin_dir)
433{
434 char *prefix, *dir;
435
436 prefix = br_find_prefix ((const char *) NULL);
437 if (prefix == (char *) NULL) {
438 /* BinReloc not initialized. */
439 if (default_bin_dir != (const char *) NULL)
440 return strdup (default_bin_dir);
441 else
442 return (char *) NULL;
443 }
444
445 dir = br_build_path (prefix, "bin");
446 free (prefix);
447 return dir;
448}
449
450
451/** Locate the application's superuser binary folder.
452 *
453 * The path is generated by the following pseudo-code evaluation:
454 * \code
455 * prefix + "/sbin"
456 * \endcode
457 *
458 * @param default_sbin_dir A default path which will used as fallback.
459 * @return A string containing the sbin folder's path, which must be freed when
460 * no longer necessary. If BinReloc is not initialized, or if the
461 * initialization function failed, then a copy of default_sbin_dir will
462 * be returned. If default_bin_dir is NULL, then NULL will be returned.
463 */
464char *
465br_find_sbin_dir (const char *default_sbin_dir)
466{
467 char *prefix, *dir;
468
469 prefix = br_find_prefix ((const char *) NULL);
470 if (prefix == (char *) NULL) {
471 /* BinReloc not initialized. */
472 if (default_sbin_dir != (const char *) NULL)
473 return strdup (default_sbin_dir);
474 else
475 return (char *) NULL;
476 }
477
478 dir = br_build_path (prefix, "sbin");
479 free (prefix);
480 return dir;
481}
482
483
484/** Locate the application's data folder.
485 *
486 * The path is generated by the following pseudo-code evaluation:
487 * \code
488 * prefix + "/share"
489 * \endcode
490 *
491 * @param default_data_dir A default path which will used as fallback.
492 * @return A string containing the data folder's path, which must be freed when
493 * no longer necessary. If BinReloc is not initialized, or if the
494 * initialization function failed, then a copy of default_data_dir
495 * will be returned. If default_data_dir is NULL, then NULL will be
496 * returned.
497 */
498char *
499br_find_data_dir (const char *default_data_dir)
500{
501 char *prefix, *dir;
502
503 prefix = br_find_prefix ((const char *) NULL);
504 if (prefix == (char *) NULL) {
505 /* BinReloc not initialized. */
506 if (default_data_dir != (const char *) NULL)
507 return strdup (default_data_dir);
508 else
509 return (char *) NULL;
510 }
511
512 dir = br_build_path (prefix, "share");
513 free (prefix);
514 return dir;
515}
516
517
518/** Locate the application's localization folder.
519 *
520 * The path is generated by the following pseudo-code evaluation:
521 * \code
522 * prefix + "/share/locale"
523 * \endcode
524 *
525 * @param default_locale_dir A default path which will used as fallback.
526 * @return A string containing the localization folder's path, which must be freed when
527 * no longer necessary. If BinReloc is not initialized, or if the
528 * initialization function failed, then a copy of default_locale_dir will be returned.
529 * If default_locale_dir is NULL, then NULL will be returned.
530 */
531char *
532br_find_locale_dir (const char *default_locale_dir)
533{
534 char *data_dir, *dir;
535
536 data_dir = br_find_data_dir ((const char *) NULL);
537 if (data_dir == (char *) NULL) {
538 /* BinReloc not initialized. */
539 if (default_locale_dir != (const char *) NULL)
540 return strdup (default_locale_dir);
541 else
542 return (char *) NULL;
543 }
544
545 dir = br_build_path (data_dir, "locale");
546 free (data_dir);
547 return dir;
548}
549
550
551/** Locate the application's library folder.
552 *
553 * The path is generated by the following pseudo-code evaluation:
554 * \code
555 * prefix + "/lib"
556 * \endcode
557 *
558 * @param default_lib_dir A default path which will used as fallback.
559 * @return A string containing the library folder's path, which must be freed when
560 * no longer necessary. If BinReloc is not initialized, or if the initialization
561 * function failed, then a copy of default_lib_dir will be returned.
562 * If default_lib_dir is NULL, then NULL will be returned.
563 */
564char *
565br_find_lib_dir (const char *default_lib_dir)
566{
567 char *prefix, *dir;
568
569 prefix = br_find_prefix ((const char *) NULL);
570 if (prefix == (char *) NULL) {
571 /* BinReloc not initialized. */
572 if (default_lib_dir != (const char *) NULL)
573 return strdup (default_lib_dir);
574 else
575 return (char *) NULL;
576 }
577
578 dir = br_build_path (prefix, "lib");
579 free (prefix);
580 return dir;
581}
582
583
584/** Locate the application's libexec folder.
585 *
586 * The path is generated by the following pseudo-code evaluation:
587 * \code
588 * prefix + "/libexec"
589 * \endcode
590 *
591 * @param default_libexec_dir A default path which will used as fallback.
592 * @return A string containing the libexec folder's path, which must be freed when
593 * no longer necessary. If BinReloc is not initialized, or if the initialization
594 * function failed, then a copy of default_libexec_dir will be returned.
595 * If default_libexec_dir is NULL, then NULL will be returned.
596 */
597char *
598br_find_libexec_dir (const char *default_libexec_dir)
599{
600 char *prefix, *dir;
601
602 prefix = br_find_prefix ((const char *) NULL);
603 if (prefix == (char *) NULL) {
604 /* BinReloc not initialized. */
605 if (default_libexec_dir != (const char *) NULL)
606 return strdup (default_libexec_dir);
607 else
608 return (char *) NULL;
609 }
610
611 dir = br_build_path (prefix, "libexec");
612 free (prefix);
613 return dir;
614}
615
616
617/** Locate the application's configuration files folder.
618 *
619 * The path is generated by the following pseudo-code evaluation:
620 * \code
621 * prefix + "/etc"
622 * \endcode
623 *
624 * @param default_etc_dir A default path which will used as fallback.
625 * @return A string containing the etc folder's path, which must be freed when
626 * no longer necessary. If BinReloc is not initialized, or if the initialization
627 * function failed, then a copy of default_etc_dir will be returned.
628 * If default_etc_dir is NULL, then NULL will be returned.
629 */
630char *
631br_find_etc_dir (const char *default_etc_dir)
632{
633 char *prefix, *dir;
634
635 prefix = br_find_prefix ((const char *) NULL);
636 if (prefix == (char *) NULL) {
637 /* BinReloc not initialized. */
638 if (default_etc_dir != (const char *) NULL)
639 return strdup (default_etc_dir);
640 else
641 return (char *) NULL;
642 }
643
644 dir = br_build_path (prefix, "etc");
645 free (prefix);
646 return dir;
647}
648
649
650/***********************
651 * Utility functions
652 ***********************/
653
654/** Concatenate str1 and str2 to a newly allocated string.
655 *
656 * @param str1 A string.
657 * @param str2 Another string.
658 * @returns A newly-allocated string. This string should be freed when no longer needed.
659 */
660char *
661br_strcat (const char *str1, const char *str2)
662{
663 char *result;
664 size_t len1, len2;
665
666 if (str1 == NULL)
667 str1 = "";
668 if (str2 == NULL)
669 str2 = "";
670
671 len1 = strlen (str1);
672 len2 = strlen (str2);
673
674 result = (char *) malloc (len1 + len2 + 1);
675 memcpy (result, str1, len1);
676 memcpy (result + len1, str2, len2);
677 result[len1 + len2] = '\0';
678
679 return result;
680}
681
682
683char *
684br_build_path (const char *dir, const char *file)
685{
686 char *dir2, *result;
687 size_t len;
688 int must_free = 0;
689
690 len = strlen (dir);
691 if (len > 0 && dir[len - 1] != '/') {
692 dir2 = br_strcat (dir, "/");
693 must_free = 1;
694 } else
695 dir2 = (char *) dir;
696
697 result = br_strcat (dir2, file);
698 if (must_free)
699 free (dir2);
700 return result;
701}
702
703
704/* Emulates glibc's strndup() */
705static char *
706br_strndup (const char *str, size_t size)
707{
708 char *result = (char *) NULL;
709 size_t len;
710
711 if (str == (const char *) NULL)
712 return (char *) NULL;
713
714 len = strlen (str);
715 if (len == 0)
716 return strdup ("");
717 if (size > len)
718 size = len;
719
720 result = (char *) malloc (len + 1);
721 memcpy (result, str, size);
722 result[size] = '\0';
723 return result;
724}
725
726
727/** Extracts the directory component of a path.
728 *
729 * Similar to g_dirname() or the dirname commandline application.
730 *
731 * Example:
732 * \code
733 * br_dirname ("/usr/local/foobar"); --> Returns: "/usr/local"
734 * \endcode
735 *
736 * @param path A path.
737 * @returns A directory name. This string should be freed when no longer needed.
738 */
739char *
740br_dirname (const char *path)
741{
742 char *end, *result;
743
744 if (path == (const char *) NULL)
745 return (char *) NULL;
746
747 end = strrchr (path, '/');
748 if (end == (const char *) NULL)
749 return strdup (".");
750
751 while (end > path && *end == '/')
752 end--;
753 result = br_strndup (path, end - path + 1);
754 if (result[0] == 0) {
755 free (result);
756 return strdup ("/");
757 } else
758 return result;
759}
760
761
762#ifdef __cplusplus
763}
764#endif /* __cplusplus */
765
766#endif /* __BINRELOC_C__ */