00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #ifndef __BINRELOC_C__
00014 #define __BINRELOC_C__
00015
00016 #include "config.h"
00017
00018 #ifdef ENABLE_BINRELOC
00019 #include <sys/types.h>
00020 #include <sys/stat.h>
00021 #include <unistd.h>
00022 #endif
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <limits.h>
00026 #include <string.h>
00027 #include "binreloc.h"
00028
00029 #ifdef __cplusplus
00030 extern "C" {
00031 #endif
00032
00033
00034 #ifdef OS_WIN32
00035 # define DIRSEP "\\"
00036 # define DIRSEP_C '\\'
00037 #else
00038 # define DIRSEP "/"
00039 # define DIRSEP_C '/'
00040 #endif
00041
00047 static char *
00048 _br_find_exe (BrInitError *error)
00049 {
00050 #ifndef ENABLE_BINRELOC
00051 if (error)
00052 *error = BR_INIT_ERROR_DISABLED;
00053 return NULL;
00054 #else
00055 char *path, *path2, *line, *result;
00056 size_t buf_size;
00057 ssize_t size;
00058 struct stat stat_buf;
00059 FILE *f;
00060
00061
00062 if (sizeof (path) > SSIZE_MAX)
00063 buf_size = SSIZE_MAX - 1;
00064 else
00065 buf_size = PATH_MAX - 1;
00066 path = (char *) malloc (buf_size);
00067 if (path == NULL) {
00068
00069 if (error)
00070 *error = BR_INIT_ERROR_NOMEM;
00071 return NULL;
00072 }
00073 path2 = (char *) malloc (buf_size);
00074 if (path2 == NULL) {
00075
00076 if (error)
00077 *error = BR_INIT_ERROR_NOMEM;
00078 free (path);
00079 return NULL;
00080 }
00081
00082 strncpy (path2, "/proc/self/exe", buf_size - 1);
00083
00084 while (1) {
00085 int i;
00086
00087 size = readlink (path2, path, buf_size - 1);
00088 if (size == -1) {
00089
00090 free (path2);
00091 break;
00092 }
00093
00094
00095 path[size] = '\0';
00096
00097
00098
00099 i = stat (path, &stat_buf);
00100 if (i == -1) {
00101
00102 free (path2);
00103 break;
00104 }
00105
00106
00107 if (!S_ISLNK (stat_buf.st_mode)) {
00108
00109 free (path2);
00110 return path;
00111 }
00112
00113
00114 strncpy (path, path2, buf_size - 1);
00115 }
00116
00117
00118
00119
00120
00121 buf_size = PATH_MAX + 128;
00122 line = (char *) realloc (path, buf_size);
00123 if (line == NULL) {
00124
00125 free (path);
00126 if (error)
00127 *error = BR_INIT_ERROR_NOMEM;
00128 return NULL;
00129 }
00130
00131 f = fopen ("/proc/self/maps", "r");
00132 if (f == NULL) {
00133 free (line);
00134 if (error)
00135 *error = BR_INIT_ERROR_OPEN_MAPS;
00136 return NULL;
00137 }
00138
00139
00140 result = fgets (line, (int) buf_size, f);
00141 if (result == NULL) {
00142 fclose (f);
00143 free (line);
00144 if (error)
00145 *error = BR_INIT_ERROR_READ_MAPS;
00146 return NULL;
00147 }
00148
00149
00150 buf_size = strlen (line);
00151 if (buf_size <= 0) {
00152
00153 fclose (f);
00154 free (line);
00155 if (error)
00156 *error = BR_INIT_ERROR_INVALID_MAPS;
00157 return NULL;
00158 }
00159 if (line[buf_size - 1] == 10)
00160 line[buf_size - 1] = 0;
00161
00162
00163 path = strchr (line, DIRSEP_C);
00164
00165
00166 if (strstr (line, " r-xp ") == NULL || path == NULL) {
00167 fclose (f);
00168 free (line);
00169 if (error)
00170 *error = BR_INIT_ERROR_INVALID_MAPS;
00171 return NULL;
00172 }
00173
00174 path = strdup (path);
00175 free (line);
00176 fclose (f);
00177 return path;
00178 #endif
00179 }
00180
00181
00186 static char *
00187 _br_find_exe_for_symbol (const void *symbol, BrInitError *error)
00188 {
00189 #ifndef ENABLE_BINRELOC
00190 if (error)
00191 *error = BR_INIT_ERROR_DISABLED;
00192 return (char *) NULL;
00193 #else
00194 #define SIZE PATH_MAX + 100
00195 FILE *f;
00196 size_t address_string_len;
00197 char *address_string, line[SIZE], *found;
00198
00199 if (symbol == NULL)
00200 return (char *) NULL;
00201
00202 f = fopen ("/proc/self/maps", "r");
00203 if (f == NULL)
00204 return (char *) NULL;
00205
00206 address_string_len = 4;
00207 address_string = (char *) malloc (address_string_len);
00208 found = (char *) NULL;
00209
00210 while (!feof (f)) {
00211 char *start_addr, *end_addr, *end_addr_end, *file;
00212 void *start_addr_p, *end_addr_p;
00213 size_t len;
00214
00215 if (fgets (line, SIZE, f) == NULL)
00216 break;
00217
00218
00219 if (strstr (line, " r-xp ") == NULL || strchr (line, '/') == NULL)
00220 continue;
00221
00222
00223 start_addr = line;
00224 end_addr = strchr (line, '-');
00225 file = strchr (line, '/');
00226
00227
00228 if (!(file > end_addr && end_addr != NULL && end_addr[0] == '-'))
00229 continue;
00230
00231 end_addr[0] = '\0';
00232 end_addr++;
00233 end_addr_end = strchr (end_addr, ' ');
00234 if (end_addr_end == NULL)
00235 continue;
00236
00237 end_addr_end[0] = '\0';
00238 len = strlen (file);
00239 if (len == 0)
00240 continue;
00241 if (file[len - 1] == '\n')
00242 file[len - 1] = '\0';
00243
00244
00245 len = strlen (file);
00246 if (len > 10 && strcmp (file + len - 10, " (deleted)") == 0)
00247 file[len - 10] = '\0';
00248
00249
00250 len = strlen (start_addr);
00251 if (len != strlen (end_addr))
00252 continue;
00253
00254
00255
00256
00257 if (address_string_len < len + 3) {
00258 address_string_len = len + 3;
00259 address_string = (char *) realloc (address_string, address_string_len);
00260 }
00261
00262 memcpy (address_string, "0x", 2);
00263 memcpy (address_string + 2, start_addr, len);
00264 address_string[2 + len] = '\0';
00265 sscanf (address_string, "%p", &start_addr_p);
00266
00267 memcpy (address_string, "0x", 2);
00268 memcpy (address_string + 2, end_addr, len);
00269 address_string[2 + len] = '\0';
00270 sscanf (address_string, "%p", &end_addr_p);
00271
00272
00273 if (symbol >= start_addr_p && symbol < end_addr_p) {
00274 found = file;
00275 break;
00276 }
00277 }
00278
00279 free (address_string);
00280 fclose (f);
00281
00282 if (found == NULL)
00283 return (char *) NULL;
00284 else
00285 return strdup (found);
00286 #endif
00287 }
00288
00289
00290 #ifndef BINRELOC_RUNNING_DOXYGEN
00291 #undef NULL
00292 #define NULL ((void *) 0)
00293 #endif
00294
00295 static char *exe = (char *) NULL;
00296
00297
00312 int
00313 br_init (BrInitError *error)
00314 {
00315 exe = _br_find_exe (error);
00316 return exe != NULL;
00317 }
00318
00319
00334 int
00335 br_init_lib (BrInitError *error)
00336 {
00337 exe = _br_find_exe_for_symbol ((const void *) "", error);
00338 return exe != NULL;
00339 }
00340
00341
00351 char *
00352 br_find_exe (const char *default_exe)
00353 {
00354 if (exe == (char *) NULL) {
00355
00356 if (default_exe != (const char *) NULL)
00357 return strdup (default_exe);
00358 else
00359 return (char *) NULL;
00360 }
00361 return strdup (exe);
00362 }
00363
00364
00379 char *
00380 br_find_exe_dir (const char *default_dir)
00381 {
00382 if (exe == NULL) {
00383
00384 if (default_dir != NULL)
00385 return strdup (default_dir);
00386 else
00387 return NULL;
00388 }
00389
00390 return br_dirname (exe);
00391 }
00392
00393
00407 char *
00408 br_find_prefix (const char *default_prefix)
00409 {
00410 char *dir1, *dir2;
00411
00412 if (exe == (char *) NULL) {
00413
00414 if (default_prefix != (const char *) NULL)
00415 return strdup (default_prefix);
00416 else
00417 return (char *) NULL;
00418 }
00419
00420 dir1 = br_dirname (exe);
00421 dir2 = br_dirname (dir1);
00422 free (dir1);
00423 return dir2;
00424 }
00425
00426
00440 char *
00441 br_find_bin_dir (const char *default_bin_dir)
00442 {
00443 char *prefix, *dir;
00444
00445 prefix = br_find_prefix ((const char *) NULL);
00446 if (prefix == (char *) NULL) {
00447
00448 if (default_bin_dir != (const char *) NULL)
00449 return strdup (default_bin_dir);
00450 else
00451 return (char *) NULL;
00452 }
00453
00454 dir = br_build_path (prefix, "bin");
00455 free (prefix);
00456 return dir;
00457 }
00458
00459
00473 char *
00474 br_find_sbin_dir (const char *default_sbin_dir)
00475 {
00476 char *prefix, *dir;
00477
00478 prefix = br_find_prefix ((const char *) NULL);
00479 if (prefix == (char *) NULL) {
00480
00481 if (default_sbin_dir != (const char *) NULL)
00482 return strdup (default_sbin_dir);
00483 else
00484 return (char *) NULL;
00485 }
00486
00487 dir = br_build_path (prefix, "sbin");
00488 free (prefix);
00489 return dir;
00490 }
00491
00492
00507 char *
00508 br_find_data_dir (const char *default_data_dir)
00509 {
00510 char *prefix, *dir;
00511
00512 prefix = br_find_prefix ((const char *) NULL);
00513 if (prefix == (char *) NULL) {
00514
00515 if (default_data_dir != (const char *) NULL)
00516 return strdup (default_data_dir);
00517 else
00518 return (char *) NULL;
00519 }
00520
00521 dir = br_build_path (prefix, "share");
00522 free (prefix);
00523 return dir;
00524 }
00525
00526
00540 char *
00541 br_find_locale_dir (const char *default_locale_dir)
00542 {
00543 char *data_dir, *dir;
00544
00545 data_dir = br_find_data_dir ((const char *) NULL);
00546 if (data_dir == (char *) NULL) {
00547
00548 if (default_locale_dir != (const char *) NULL)
00549 return strdup (default_locale_dir);
00550 else
00551 return (char *) NULL;
00552 }
00553
00554 dir = br_build_path (data_dir, "locale");
00555 free (data_dir);
00556 return dir;
00557 }
00558
00559
00573 char *
00574 br_find_lib_dir (const char *default_lib_dir)
00575 {
00576 char *prefix, *dir;
00577
00578 prefix = br_find_prefix ((const char *) NULL);
00579 if (prefix == (char *) NULL) {
00580
00581 if (default_lib_dir != (const char *) NULL)
00582 return strdup (default_lib_dir);
00583 else
00584 return (char *) NULL;
00585 }
00586
00587 dir = br_build_path (prefix, "lib");
00588 free (prefix);
00589 return dir;
00590 }
00591
00592
00606 char *
00607 br_find_libexec_dir (const char *default_libexec_dir)
00608 {
00609 char *prefix, *dir;
00610
00611 prefix = br_find_prefix ((const char *) NULL);
00612 if (prefix == (char *) NULL) {
00613
00614 if (default_libexec_dir != (const char *) NULL)
00615 return strdup (default_libexec_dir);
00616 else
00617 return (char *) NULL;
00618 }
00619
00620 dir = br_build_path (prefix, "libexec");
00621 free (prefix);
00622 return dir;
00623 }
00624
00625
00639 char *
00640 br_find_etc_dir (const char *default_etc_dir)
00641 {
00642 char *prefix, *dir;
00643
00644 prefix = br_find_prefix ((const char *) NULL);
00645 if (prefix == (char *) NULL) {
00646
00647 if (default_etc_dir != (const char *) NULL)
00648 return strdup (default_etc_dir);
00649 else
00650 return (char *) NULL;
00651 }
00652
00653 dir = br_build_path (prefix, "etc");
00654 free (prefix);
00655 return dir;
00656 }
00657
00658
00659
00660
00661
00662
00669 char *
00670 br_strcat (const char *str1, const char *str2)
00671 {
00672 char *result;
00673 size_t len1, len2;
00674
00675 if (str1 == NULL)
00676 str1 = "";
00677 if (str2 == NULL)
00678 str2 = "";
00679
00680 len1 = strlen (str1);
00681 len2 = strlen (str2);
00682
00683 result = (char *) malloc (len1 + len2 + 1);
00684 memcpy (result, str1, len1);
00685 memcpy (result + len1, str2, len2);
00686 result[len1 + len2] = '\0';
00687
00688 return result;
00689 }
00690
00691
00692 char *
00693 br_build_path (const char *dir, const char *file)
00694 {
00695 char *dir2, *result;
00696 size_t len;
00697 int must_free = 0;
00698
00699 len = strlen (dir);
00700 if (len > 0 && dir[len - 1] != DIRSEP_C) {
00701 dir2 = br_strcat (dir, DIRSEP );
00702 must_free = 1;
00703 } else
00704 dir2 = (char *) dir;
00705
00706 result = br_strcat (dir2, file);
00707 if (must_free)
00708 free (dir2);
00709 return result;
00710 }
00711
00712
00713
00714 static char *
00715 br_strndup (const char *str, size_t size)
00716 {
00717 char *result = (char *) NULL;
00718 size_t len;
00719
00720 if (str == (const char *) NULL)
00721 return (char *) NULL;
00722
00723 len = strlen (str);
00724 if (len == 0)
00725 return strdup ("");
00726 if (size > len)
00727 size = len;
00728
00729 result = (char *) malloc (len + 1);
00730 memcpy (result, str, size);
00731 result[size] = '\0';
00732 return result;
00733 }
00734
00735
00748 char *
00749 br_dirname (const char *path)
00750 {
00751 char *end, *result;
00752
00753 if (path == (const char *) NULL)
00754 return (char *) NULL;
00755
00756 end = strrchr (path, DIRSEP_C);
00757 if (end == (const char *) NULL)
00758 return strdup (".");
00759
00760 while (end > path && *end == DIRSEP_C)
00761 end--;
00762 result = br_strndup (path, end - path + 1);
00763 if (result[0] == 0) {
00764 free (result);
00765 return strdup (DIRSEP);
00766 } else
00767 return result;
00768 }
00769
00770
00771 #ifdef __cplusplus
00772 }
00773 #endif
00774
00775 #endif