gwenhywfar  5.10.1
binreloc.c
Go to the documentation of this file.
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 #include "config.h"
17 
18 #include <gwenhywfar/gwenhywfarapi.h>
19 
20 
21 #ifdef ENABLE_BINRELOC
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <unistd.h>
25 #endif /* ENABLE_BINRELOC */
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <limits.h>
29 #include <string.h>
30 #include "binreloc.h"
31 
32 #ifdef __cplusplus
33 extern "C" {
34 #endif /* __cplusplus */
35 
36 
37 #ifdef OS_WIN32
38 # define DIRSEP "\\"
39 # define DIRSEP_C '\\'
40 #else
41 # define DIRSEP "/"
42 # define DIRSEP_C '/'
43 #endif
44 
50 static char *
52 {
53 #ifndef ENABLE_BINRELOC
54  if (error)
55  *error = BR_INIT_ERROR_DISABLED;
56  return NULL;
57 #else
58  char *path, *path2, *line, *result;
59  size_t buf_size;
60  ssize_t size;
61  struct stat stat_buf;
62  FILE *f;
63 
64  /* Read from /proc/self/exe (symlink) */
65  if (sizeof(path) > SSIZE_MAX)
66  buf_size = SSIZE_MAX - 1;
67  else
68  buf_size = PATH_MAX - 1;
69  path = (char *) malloc(buf_size);
70  if (path == NULL) {
71  /* Cannot allocate memory. */
72  if (error)
73  *error = BR_INIT_ERROR_NOMEM;
74  return NULL;
75  }
76  path2 = (char *) malloc(buf_size);
77  if (path2 == NULL) {
78  /* Cannot allocate memory. */
79  if (error)
80  *error = BR_INIT_ERROR_NOMEM;
81  free(path);
82  return NULL;
83  }
84 
85  strncpy(path2, "/proc/self/exe", buf_size - 1);
86 
87  while (1) {
88  int i;
89 
90  size = readlink(path2, path, buf_size - 1);
91  if (size == -1) {
92  /* Error. */
93  free(path2);
94  break;
95  }
96 
97  /* readlink() success. */
98  path[size] = '\0';
99 
100  /* Check whether the symlink's target is also a symlink.
101  * We want to get the final target. */
102  i = stat(path, &stat_buf);
103  if (i == -1) {
104  /* Error. */
105  free(path2);
106  break;
107  }
108 
109  /* stat() success. */
110  if (!S_ISLNK(stat_buf.st_mode)) {
111  /* path is not a symlink. Done. */
112  free(path2);
113  return path;
114  }
115 
116  /* path is a symlink. Continue loop and resolve this. */
117  strncpy(path, path2, buf_size - 1);
118  }
119 
120 
121  /* readlink() or stat() failed; this can happen when the program is
122  * running in Valgrind 2.2. Read from /proc/self/maps as fallback. */
123 
124  buf_size = PATH_MAX + 128;
125  line = (char *) realloc(path, buf_size);
126  if (line == NULL) {
127  /* Cannot allocate memory. */
128  free(path);
129  if (error)
130  *error = BR_INIT_ERROR_NOMEM;
131  return NULL;
132  }
133 
134  f = fopen("/proc/self/maps", "r");
135  if (f == NULL) {
136  free(line);
137  if (error)
138  *error = BR_INIT_ERROR_OPEN_MAPS;
139  return NULL;
140  }
141 
142  /* The first entry should be the executable name. */
143  result = fgets(line, (int) buf_size, f);
144  if (result == NULL) {
145  fclose(f);
146  free(line);
147  if (error)
148  *error = BR_INIT_ERROR_READ_MAPS;
149  return NULL;
150  }
151 
152  /* Get rid of newline character. */
153  buf_size = strlen(line);
154  if (buf_size <= 0) {
155  /* Huh? An empty string? */
156  fclose(f);
157  free(line);
158  if (error)
160  return NULL;
161  }
162  if (line[buf_size - 1] == 10)
163  line[buf_size - 1] = 0;
164 
165  /* Extract the filename; it is always an absolute path. */
166  path = strchr(line, DIRSEP_C);
167 
168  /* Sanity check. */
169  if (strstr(line, " r-xp ") == NULL || path == NULL) {
170  fclose(f);
171  free(line);
172  if (error)
174  return NULL;
175  }
176 
177  path = strdup(path);
178  free(line);
179  fclose(f);
180  return path;
181 #endif /* ENABLE_BINRELOC */
182 }
183 
184 
189 static char *
191 {
192 #ifndef ENABLE_BINRELOC
193  if (error)
194  *error = BR_INIT_ERROR_DISABLED;
195  return (char *) NULL;
196 #else
197 #define SIZE PATH_MAX + 100
198  FILE *f;
199  size_t address_string_len;
200  char *address_string, line[SIZE], *found;
201 
202  if (symbol == NULL)
203  return (char *) NULL;
204 
205  f = fopen("/proc/self/maps", "r");
206  if (f == NULL)
207  return (char *) NULL;
208 
209  address_string_len = 4;
210  address_string = (char *) malloc(address_string_len);
211  found = (char *) NULL;
212 
213  while (!feof(f)) {
214  char *start_addr, *end_addr, *end_addr_end, *file;
215  void *start_addr_p, *end_addr_p;
216  size_t len;
217 
218  if (fgets(line, SIZE, f) == NULL)
219  break;
220 
221  /* Sanity check. */
222  if (strstr(line, " r-xp ") == NULL || strchr(line, '/') == NULL)
223  continue;
224 
225  /* Parse line. */
226  start_addr = line;
227  end_addr = strchr(line, '-');
228  file = strchr(line, '/');
229 
230  /* More sanity check. */
231  if (!(file > end_addr && end_addr != NULL && end_addr[0] == '-'))
232  continue;
233 
234  end_addr[0] = '\0';
235  end_addr++;
236  end_addr_end = strchr(end_addr, ' ');
237  if (end_addr_end == NULL)
238  continue;
239 
240  end_addr_end[0] = '\0';
241  len = strlen(file);
242  if (len == 0)
243  continue;
244  if (file[len - 1] == '\n')
245  file[len - 1] = '\0';
246 
247  /* Get rid of "(deleted)" from the filename. */
248  len = strlen(file);
249  if (len > 10 && strcmp(file + len - 10, " (deleted)") == 0)
250  file[len - 10] = '\0';
251 
252  /* I don't know whether this can happen but better safe than sorry. */
253  len = strlen(start_addr);
254  if (len != strlen(end_addr))
255  continue;
256 
257 
258  /* Transform the addresses into a string in the form of 0xdeadbeef,
259  * then transform that into a pointer. */
260  if (address_string_len < len + 3) {
261  char *tmp_address_string;
262 
263  address_string_len = len + 3;
264  tmp_address_string = (char *) realloc(address_string, address_string_len);
265  if (tmp_address_string==NULL)
266  free(address_string);
267  address_string = tmp_address_string;
268  }
269 
270  memcpy(address_string, "0x", 2);
271  memcpy(address_string + 2, start_addr, len);
272  address_string[2 + len] = '\0';
273  sscanf(address_string, "%p", &start_addr_p);
274 
275  memcpy(address_string, "0x", 2);
276  memcpy(address_string + 2, end_addr, len);
277  address_string[2 + len] = '\0';
278  sscanf(address_string, "%p", &end_addr_p);
279 
280 
281  if (symbol >= start_addr_p && symbol < end_addr_p) {
282  found = file;
283  break;
284  }
285  }
286 
287  free(address_string);
288  fclose(f);
289 
290  if (found == NULL)
291  return (char *) NULL;
292  else
293  return strdup(found);
294 #endif /* ENABLE_BINRELOC */
295 }
296 
297 
298 #ifndef BINRELOC_RUNNING_DOXYGEN
299 #undef NULL
300 #define NULL ((void *) 0) /* typecasted as char* for C++ type safeness */
301 #endif
302 
303 static char *exe = (char *) NULL;
304 
305 
320 int
322 {
323  exe = _br_find_exe(error);
324  return exe != NULL;
325 }
326 
327 
342 int
344 {
345  exe = _br_find_exe_for_symbol((const void *) "", error);
346  return exe != NULL;
347 }
348 
349 
359 char *
360 br_find_exe(const char *default_exe)
361 {
362  if (exe == (char *) NULL) {
363  /* BinReloc is not initialized. */
364  if (default_exe != (const char *) NULL)
365  return strdup(default_exe);
366  else
367  return (char *) NULL;
368  }
369  return strdup(exe);
370 }
371 
372 
387 char *
388 br_find_exe_dir(const char *default_dir)
389 {
390  if (exe == NULL) {
391  /* BinReloc not initialized. */
392  if (default_dir != NULL)
393  return strdup(default_dir);
394  else
395  return NULL;
396  }
397 
398  return br_dirname(exe);
399 }
400 
401 
415 char *
416 br_find_prefix(const char *default_prefix)
417 {
418  char *dir1, *dir2;
419 
420  if (exe == (char *) NULL) {
421  /* BinReloc not initialized. */
422  if (default_prefix != (const char *) NULL)
423  return strdup(default_prefix);
424  else
425  return (char *) NULL;
426  }
427 
428  dir1 = br_dirname(exe);
429  dir2 = br_dirname(dir1);
430  free(dir1);
431  return dir2;
432 }
433 
434 
448 char *
449 br_find_bin_dir(const char *default_bin_dir)
450 {
451  char *prefix, *dir;
452 
453  prefix = br_find_prefix((const char *) NULL);
454  if (prefix == (char *) NULL) {
455  /* BinReloc not initialized. */
456  if (default_bin_dir != (const char *) NULL)
457  return strdup(default_bin_dir);
458  else
459  return (char *) NULL;
460  }
461 
462  dir = br_build_path(prefix, "bin");
463  free(prefix);
464  return dir;
465 }
466 
467 
481 char *
482 br_find_sbin_dir(const char *default_sbin_dir)
483 {
484  char *prefix, *dir;
485 
486  prefix = br_find_prefix((const char *) NULL);
487  if (prefix == (char *) NULL) {
488  /* BinReloc not initialized. */
489  if (default_sbin_dir != (const char *) NULL)
490  return strdup(default_sbin_dir);
491  else
492  return (char *) NULL;
493  }
494 
495  dir = br_build_path(prefix, "sbin");
496  free(prefix);
497  return dir;
498 }
499 
500 
515 char *
516 br_find_data_dir(const char *default_data_dir)
517 {
518  char *prefix, *dir;
519 
520  prefix = br_find_prefix((const char *) NULL);
521  if (prefix == (char *) NULL) {
522  /* BinReloc not initialized. */
523  if (default_data_dir != (const char *) NULL)
524  return strdup(default_data_dir);
525  else
526  return (char *) NULL;
527  }
528 
529  dir = br_build_path(prefix, "share");
530  free(prefix);
531  return dir;
532 }
533 
534 
548 char *
549 br_find_locale_dir(const char *default_locale_dir)
550 {
551  char *data_dir, *dir;
552 
553  data_dir = br_find_data_dir((const char *) NULL);
554  if (data_dir == (char *) NULL) {
555  /* BinReloc not initialized. */
556  if (default_locale_dir != (const char *) NULL)
557  return strdup(default_locale_dir);
558  else
559  return (char *) NULL;
560  }
561 
562  dir = br_build_path(data_dir, "locale");
563  free(data_dir);
564  return dir;
565 }
566 
567 
581 char *
582 br_find_lib_dir(const char *default_lib_dir)
583 {
584  char *prefix, *dir;
585 
586  prefix = br_find_prefix((const char *) NULL);
587  if (prefix == (char *) NULL) {
588  /* BinReloc not initialized. */
589  if (default_lib_dir != (const char *) NULL)
590  return strdup(default_lib_dir);
591  else
592  return (char *) NULL;
593  }
594 
595  dir = br_build_path(prefix, "lib");
596  free(prefix);
597  return dir;
598 }
599 
600 
614 char *
615 br_find_libexec_dir(const char *default_libexec_dir)
616 {
617  char *prefix, *dir;
618 
619  prefix = br_find_prefix((const char *) NULL);
620  if (prefix == (char *) NULL) {
621  /* BinReloc not initialized. */
622  if (default_libexec_dir != (const char *) NULL)
623  return strdup(default_libexec_dir);
624  else
625  return (char *) NULL;
626  }
627 
628  dir = br_build_path(prefix, "libexec");
629  free(prefix);
630  return dir;
631 }
632 
633 
647 char *
648 br_find_etc_dir(const char *default_etc_dir)
649 {
650  char *prefix, *dir;
651 
652  prefix = br_find_prefix((const char *) NULL);
653  if (prefix == (char *) NULL) {
654  /* BinReloc not initialized. */
655  if (default_etc_dir != (const char *) NULL)
656  return strdup(default_etc_dir);
657  else
658  return (char *) NULL;
659  }
660 
661  dir = br_build_path(prefix, "etc");
662  free(prefix);
663  return dir;
664 }
665 
666 
667 /***********************
668  * Utility functions
669  ***********************/
670 
677 char *
678 br_strcat(const char *str1, const char *str2)
679 {
680  char *result;
681  size_t len1, len2;
682 
683  if (str1 == NULL)
684  str1 = "";
685  if (str2 == NULL)
686  str2 = "";
687 
688  len1 = strlen(str1);
689  len2 = strlen(str2);
690 
691  result = (char *) malloc(len1 + len2 + 1);
692  memcpy(result, str1, len1);
693  memcpy(result + len1, str2, len2);
694  result[len1 + len2] = '\0';
695 
696  return result;
697 }
698 
699 
700 char *
701 br_build_path(const char *dir, const char *file)
702 {
703  char *dir2, *result;
704  size_t len;
705  int must_free = 0;
706 
707  len = strlen(dir);
708  if (len > 0 && dir[len - 1] != DIRSEP_C) {
709  dir2 = br_strcat(dir, DIRSEP);
710  must_free = 1;
711  }
712  else
713  dir2 = (char *) dir;
714 
715  result = br_strcat(dir2, file);
716  if (must_free)
717  free(dir2);
718  return result;
719 }
720 
721 
722 /* Emulates glibc's strndup() */
723 static char *
724 br_strndup(const char *str, size_t size)
725 {
726  char *result = (char *) NULL;
727  size_t len;
728 
729  if (str == (const char *) NULL)
730  return (char *) NULL;
731 
732  len = strlen(str);
733  if (len == 0)
734  return strdup("");
735  if (size > len)
736  size = len;
737 
738  result = (char *) malloc(len + 1);
739  memcpy(result, str, size);
740  result[size] = '\0';
741  return result;
742 }
743 
744 
757 char *
758 br_dirname(const char *path)
759 {
760  char *end, *result;
761 
762  if (path == (const char *) NULL)
763  return (char *) NULL;
764 
765  end = strrchr(path, DIRSEP_C);
766  if (end == (const char *) NULL)
767  return strdup(".");
768 
769  while (end > path && *end == DIRSEP_C)
770  end--;
771  result = br_strndup(path, end - path + 1);
772  if (result[0] == 0) {
773  free(result);
774  return strdup(DIRSEP);
775  }
776  else
777  return result;
778 }
779 
780 
781 #ifdef __cplusplus
782 }
783 #endif /* __cplusplus */
784 
785 #endif /* __BINRELOC_C__ */
char * br_find_bin_dir(const char *default_bin_dir)
Definition: binreloc.c:449
char * br_find_exe_dir(const char *default_dir)
Definition: binreloc.c:388
char * br_dirname(const char *path)
Definition: binreloc.c:758
char * br_find_exe(const char *default_exe)
Definition: binreloc.c:360
#define NULL
Definition: binreloc.c:300
char * br_find_locale_dir(const char *default_locale_dir)
Definition: binreloc.c:549
char * br_find_libexec_dir(const char *default_libexec_dir)
Definition: binreloc.c:615
static char * exe
Definition: binreloc.c:303
int br_init_lib(BrInitError *error)
Definition: binreloc.c:343
#define DIRSEP_C
Definition: binreloc.c:42
char * br_find_etc_dir(const char *default_etc_dir)
Definition: binreloc.c:648
static char * br_strndup(const char *str, size_t size)
Definition: binreloc.c:724
static char * _br_find_exe(BrInitError *error)
Definition: binreloc.c:51
char * br_find_data_dir(const char *default_data_dir)
Definition: binreloc.c:516
BrInitError
Definition: binreloc.h:22
char * br_find_lib_dir(const char *default_lib_dir)
Definition: binreloc.c:582
char * br_find_prefix(const char *default_prefix)
Definition: binreloc.c:416
char * br_build_path(const char *dir, const char *file)
Definition: binreloc.c:701
char * br_find_sbin_dir(const char *default_sbin_dir)
Definition: binreloc.c:482
#define DIRSEP
Definition: binreloc.c:41
int br_init(BrInitError *error)
Definition: binreloc.c:321
#define GWEN_UNUSED
static char * _br_find_exe_for_symbol(const void *symbol, GWEN_UNUSED BrInitError *error)
Definition: binreloc.c:190
char * br_strcat(const char *str1, const char *str2)
Definition: binreloc.c:678