gwenhywfar  4.99.8beta
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 #ifdef ENABLE_BINRELOC
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <unistd.h>
22 #endif /* ENABLE_BINRELOC */
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <limits.h>
26 #include <string.h>
27 #include "binreloc.h"
28 
29 #ifdef __cplusplus
30 extern "C" {
31 #endif /* __cplusplus */
32 
33 
34 #ifdef OS_WIN32
35 # define DIRSEP "\\"
36 # define DIRSEP_C '\\'
37 #else
38 # define DIRSEP "/"
39 # define DIRSEP_C '/'
40 #endif
41 
47 static char *
49 #ifndef ENABLE_BINRELOC
50  if (error)
51  *error = BR_INIT_ERROR_DISABLED;
52  return NULL;
53 #else
54  char *path, *path2, *line, *result;
55  size_t buf_size;
56  ssize_t size;
57  struct stat stat_buf;
58  FILE *f;
59 
60  /* Read from /proc/self/exe (symlink) */
61  if (sizeof (path) > SSIZE_MAX)
62  buf_size = SSIZE_MAX - 1;
63  else
64  buf_size = PATH_MAX - 1;
65  path = (char *) malloc (buf_size);
66  if (path == NULL) {
67  /* Cannot allocate memory. */
68  if (error)
69  *error = BR_INIT_ERROR_NOMEM;
70  return NULL;
71  }
72  path2 = (char *) malloc (buf_size);
73  if (path2 == NULL) {
74  /* Cannot allocate memory. */
75  if (error)
76  *error = BR_INIT_ERROR_NOMEM;
77  free (path);
78  return NULL;
79  }
80 
81  strncpy (path2, "/proc/self/exe", buf_size - 1);
82 
83  while (1) {
84  int i;
85 
86  size = readlink (path2, path, buf_size - 1);
87  if (size == -1) {
88  /* Error. */
89  free (path2);
90  break;
91  }
92 
93  /* readlink() success. */
94  path[size] = '\0';
95 
96  /* Check whether the symlink's target is also a symlink.
97  * We want to get the final target. */
98  i = stat (path, &stat_buf);
99  if (i == -1) {
100  /* Error. */
101  free (path2);
102  break;
103  }
104 
105  /* stat() success. */
106  if (!S_ISLNK (stat_buf.st_mode)) {
107  /* path is not a symlink. Done. */
108  free (path2);
109  return path;
110  }
111 
112  /* path is a symlink. Continue loop and resolve this. */
113  strncpy (path, path2, buf_size - 1);
114  }
115 
116 
117  /* readlink() or stat() failed; this can happen when the program is
118  * running in Valgrind 2.2. Read from /proc/self/maps as fallback. */
119 
120  buf_size = PATH_MAX + 128;
121  line = (char *) realloc (path, buf_size);
122  if (line == NULL) {
123  /* Cannot allocate memory. */
124  free (path);
125  if (error)
126  *error = BR_INIT_ERROR_NOMEM;
127  return NULL;
128  }
129 
130  f = fopen ("/proc/self/maps", "r");
131  if (f == NULL) {
132  free (line);
133  if (error)
134  *error = BR_INIT_ERROR_OPEN_MAPS;
135  return NULL;
136  }
137 
138  /* The first entry should be the executable name. */
139  result = fgets (line, (int) buf_size, f);
140  if (result == NULL) {
141  fclose (f);
142  free (line);
143  if (error)
144  *error = BR_INIT_ERROR_READ_MAPS;
145  return NULL;
146  }
147 
148  /* Get rid of newline character. */
149  buf_size = strlen (line);
150  if (buf_size <= 0) {
151  /* Huh? An empty string? */
152  fclose (f);
153  free (line);
154  if (error)
156  return NULL;
157  }
158  if (line[buf_size - 1] == 10)
159  line[buf_size - 1] = 0;
160 
161  /* Extract the filename; it is always an absolute path. */
162  path = strchr (line, DIRSEP_C);
163 
164  /* Sanity check. */
165  if (strstr (line, " r-xp ") == NULL || path == NULL) {
166  fclose (f);
167  free (line);
168  if (error)
170  return NULL;
171  }
172 
173  path = strdup (path);
174  free (line);
175  fclose (f);
176  return path;
177 #endif /* ENABLE_BINRELOC */
178 }
179 
180 
185 static char *
186 _br_find_exe_for_symbol (const void *symbol, BrInitError *error) {
187 #ifndef ENABLE_BINRELOC
188  if (error)
189  *error = BR_INIT_ERROR_DISABLED;
190  return (char *) NULL;
191 #else
192 #define SIZE PATH_MAX + 100
193  FILE *f;
194  size_t address_string_len;
195  char *address_string, line[SIZE], *found;
196 
197  if (symbol == NULL)
198  return (char *) NULL;
199 
200  f = fopen ("/proc/self/maps", "r");
201  if (f == NULL)
202  return (char *) NULL;
203 
204  address_string_len = 4;
205  address_string = (char *) malloc (address_string_len);
206  found = (char *) NULL;
207 
208  while (!feof (f)) {
209  char *start_addr, *end_addr, *end_addr_end, *file;
210  void *start_addr_p, *end_addr_p;
211  size_t len;
212 
213  if (fgets (line, SIZE, f) == NULL)
214  break;
215 
216  /* Sanity check. */
217  if (strstr (line, " r-xp ") == NULL || strchr (line, '/') == NULL)
218  continue;
219 
220  /* Parse line. */
221  start_addr = line;
222  end_addr = strchr (line, '-');
223  file = strchr (line, '/');
224 
225  /* More sanity check. */
226  if (!(file > end_addr && end_addr != NULL && end_addr[0] == '-'))
227  continue;
228 
229  end_addr[0] = '\0';
230  end_addr++;
231  end_addr_end = strchr (end_addr, ' ');
232  if (end_addr_end == NULL)
233  continue;
234 
235  end_addr_end[0] = '\0';
236  len = strlen (file);
237  if (len == 0)
238  continue;
239  if (file[len - 1] == '\n')
240  file[len - 1] = '\0';
241 
242  /* Get rid of "(deleted)" from the filename. */
243  len = strlen (file);
244  if (len > 10 && strcmp (file + len - 10, " (deleted)") == 0)
245  file[len - 10] = '\0';
246 
247  /* I don't know whether this can happen but better safe than sorry. */
248  len = strlen (start_addr);
249  if (len != strlen (end_addr))
250  continue;
251 
252 
253  /* Transform the addresses into a string in the form of 0xdeadbeef,
254  * then transform that into a pointer. */
255  if (address_string_len < len + 3) {
256  address_string_len = len + 3;
257  address_string = (char *) realloc (address_string, address_string_len);
258  }
259 
260  memcpy (address_string, "0x", 2);
261  memcpy (address_string + 2, start_addr, len);
262  address_string[2 + len] = '\0';
263  sscanf (address_string, "%p", &start_addr_p);
264 
265  memcpy (address_string, "0x", 2);
266  memcpy (address_string + 2, end_addr, len);
267  address_string[2 + len] = '\0';
268  sscanf (address_string, "%p", &end_addr_p);
269 
270 
271  if (symbol >= start_addr_p && symbol < end_addr_p) {
272  found = file;
273  break;
274  }
275  }
276 
277  free (address_string);
278  fclose (f);
279 
280  if (found == NULL)
281  return (char *) NULL;
282  else
283  return strdup (found);
284 #endif /* ENABLE_BINRELOC */
285 }
286 
287 
288 #ifndef BINRELOC_RUNNING_DOXYGEN
289 #undef NULL
290 #define NULL ((void *) 0) /* typecasted as char* for C++ type safeness */
291 #endif
292 
293 static char *exe = (char *) NULL;
294 
295 
310 int
312  exe = _br_find_exe (error);
313  return exe != NULL;
314 }
315 
316 
331 int
333  exe = _br_find_exe_for_symbol ((const void *) "", error);
334  return exe != NULL;
335 }
336 
337 
347 char *
348 br_find_exe (const char *default_exe) {
349  if (exe == (char *) NULL) {
350  /* BinReloc is not initialized. */
351  if (default_exe != (const char *) NULL)
352  return strdup (default_exe);
353  else
354  return (char *) NULL;
355  }
356  return strdup (exe);
357 }
358 
359 
374 char *
375 br_find_exe_dir (const char *default_dir) {
376  if (exe == NULL) {
377  /* BinReloc not initialized. */
378  if (default_dir != NULL)
379  return strdup (default_dir);
380  else
381  return NULL;
382  }
383 
384  return br_dirname (exe);
385 }
386 
387 
401 char *
402 br_find_prefix (const char *default_prefix) {
403  char *dir1, *dir2;
404 
405  if (exe == (char *) NULL) {
406  /* BinReloc not initialized. */
407  if (default_prefix != (const char *) NULL)
408  return strdup (default_prefix);
409  else
410  return (char *) NULL;
411  }
412 
413  dir1 = br_dirname (exe);
414  dir2 = br_dirname (dir1);
415  free (dir1);
416  return dir2;
417 }
418 
419 
433 char *
434 br_find_bin_dir (const char *default_bin_dir) {
435  char *prefix, *dir;
436 
437  prefix = br_find_prefix ((const char *) NULL);
438  if (prefix == (char *) NULL) {
439  /* BinReloc not initialized. */
440  if (default_bin_dir != (const char *) NULL)
441  return strdup (default_bin_dir);
442  else
443  return (char *) NULL;
444  }
445 
446  dir = br_build_path (prefix, "bin");
447  free (prefix);
448  return dir;
449 }
450 
451 
465 char *
466 br_find_sbin_dir (const char *default_sbin_dir) {
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 
498 char *
499 br_find_data_dir (const char *default_data_dir) {
500  char *prefix, *dir;
501 
502  prefix = br_find_prefix ((const char *) NULL);
503  if (prefix == (char *) NULL) {
504  /* BinReloc not initialized. */
505  if (default_data_dir != (const char *) NULL)
506  return strdup (default_data_dir);
507  else
508  return (char *) NULL;
509  }
510 
511  dir = br_build_path (prefix, "share");
512  free (prefix);
513  return dir;
514 }
515 
516 
530 char *
531 br_find_locale_dir (const char *default_locale_dir) {
532  char *data_dir, *dir;
533 
534  data_dir = br_find_data_dir ((const char *) NULL);
535  if (data_dir == (char *) NULL) {
536  /* BinReloc not initialized. */
537  if (default_locale_dir != (const char *) NULL)
538  return strdup (default_locale_dir);
539  else
540  return (char *) NULL;
541  }
542 
543  dir = br_build_path (data_dir, "locale");
544  free (data_dir);
545  return dir;
546 }
547 
548 
562 char *
563 br_find_lib_dir (const char *default_lib_dir) {
564  char *prefix, *dir;
565 
566  prefix = br_find_prefix ((const char *) NULL);
567  if (prefix == (char *) NULL) {
568  /* BinReloc not initialized. */
569  if (default_lib_dir != (const char *) NULL)
570  return strdup (default_lib_dir);
571  else
572  return (char *) NULL;
573  }
574 
575  dir = br_build_path (prefix, "lib");
576  free (prefix);
577  return dir;
578 }
579 
580 
594 char *
595 br_find_libexec_dir (const char *default_libexec_dir) {
596  char *prefix, *dir;
597 
598  prefix = br_find_prefix ((const char *) NULL);
599  if (prefix == (char *) NULL) {
600  /* BinReloc not initialized. */
601  if (default_libexec_dir != (const char *) NULL)
602  return strdup (default_libexec_dir);
603  else
604  return (char *) NULL;
605  }
606 
607  dir = br_build_path (prefix, "libexec");
608  free (prefix);
609  return dir;
610 }
611 
612 
626 char *
627 br_find_etc_dir (const char *default_etc_dir) {
628  char *prefix, *dir;
629 
630  prefix = br_find_prefix ((const char *) NULL);
631  if (prefix == (char *) NULL) {
632  /* BinReloc not initialized. */
633  if (default_etc_dir != (const char *) NULL)
634  return strdup (default_etc_dir);
635  else
636  return (char *) NULL;
637  }
638 
639  dir = br_build_path (prefix, "etc");
640  free (prefix);
641  return dir;
642 }
643 
644 
645 /***********************
646  * Utility functions
647  ***********************/
648 
655 char *
656 br_strcat (const char *str1, const char *str2) {
657  char *result;
658  size_t len1, len2;
659 
660  if (str1 == NULL)
661  str1 = "";
662  if (str2 == NULL)
663  str2 = "";
664 
665  len1 = strlen (str1);
666  len2 = strlen (str2);
667 
668  result = (char *) malloc (len1 + len2 + 1);
669  memcpy (result, str1, len1);
670  memcpy (result + len1, str2, len2);
671  result[len1 + len2] = '\0';
672 
673  return result;
674 }
675 
676 
677 char *
678 br_build_path (const char *dir, const char *file) {
679  char *dir2, *result;
680  size_t len;
681  int must_free = 0;
682 
683  len = strlen (dir);
684  if (len > 0 && dir[len - 1] != DIRSEP_C) {
685  dir2 = br_strcat (dir, DIRSEP );
686  must_free = 1;
687  }
688  else
689  dir2 = (char *) dir;
690 
691  result = br_strcat (dir2, file);
692  if (must_free)
693  free (dir2);
694  return result;
695 }
696 
697 
698 /* Emulates glibc's strndup() */
699 static char *
700 br_strndup (const char *str, size_t size) {
701  char *result = (char *) NULL;
702  size_t len;
703 
704  if (str == (const char *) NULL)
705  return (char *) NULL;
706 
707  len = strlen (str);
708  if (len == 0)
709  return strdup ("");
710  if (size > len)
711  size = len;
712 
713  result = (char *) malloc (len + 1);
714  memcpy (result, str, size);
715  result[size] = '\0';
716  return result;
717 }
718 
719 
732 char *
733 br_dirname (const char *path) {
734  char *end, *result;
735 
736  if (path == (const char *) NULL)
737  return (char *) NULL;
738 
739  end = strrchr (path, DIRSEP_C);
740  if (end == (const char *) NULL)
741  return strdup (".");
742 
743  while (end > path && *end == DIRSEP_C)
744  end--;
745  result = br_strndup (path, end - path + 1);
746  if (result[0] == 0) {
747  free (result);
748  return strdup (DIRSEP);
749  }
750  else
751  return result;
752 }
753 
754 
755 #ifdef __cplusplus
756 }
757 #endif /* __cplusplus */
758 
759 #endif /* __BINRELOC_C__ */
char * br_find_bin_dir(const char *default_bin_dir)
Definition: binreloc.c:434
char * br_find_exe_dir(const char *default_dir)
Definition: binreloc.c:375
char * br_dirname(const char *path)
Definition: binreloc.c:733
char * br_find_exe(const char *default_exe)
Definition: binreloc.c:348
#define NULL
Definition: binreloc.c:290
char * br_find_locale_dir(const char *default_locale_dir)
Definition: binreloc.c:531
char * br_find_libexec_dir(const char *default_libexec_dir)
Definition: binreloc.c:595
static char * exe
Definition: binreloc.c:293
int br_init_lib(BrInitError *error)
Definition: binreloc.c:332
#define DIRSEP_C
Definition: binreloc.c:39
char * br_find_etc_dir(const char *default_etc_dir)
Definition: binreloc.c:627
static char * br_strndup(const char *str, size_t size)
Definition: binreloc.c:700
static char * _br_find_exe(BrInitError *error)
Definition: binreloc.c:48
char * br_find_data_dir(const char *default_data_dir)
Definition: binreloc.c:499
BrInitError
Definition: binreloc.h:22
char * br_find_lib_dir(const char *default_lib_dir)
Definition: binreloc.c:563
char * br_find_prefix(const char *default_prefix)
Definition: binreloc.c:402
char * br_build_path(const char *dir, const char *file)
Definition: binreloc.c:678
char * br_find_sbin_dir(const char *default_sbin_dir)
Definition: binreloc.c:466
#define DIRSEP
Definition: binreloc.c:38
static char * _br_find_exe_for_symbol(const void *symbol, BrInitError *error)
Definition: binreloc.c:186
int br_init(BrInitError *error)
Definition: binreloc.c:311
char * br_strcat(const char *str1, const char *str2)
Definition: binreloc.c:656