00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #ifndef __BINRELOC_C__
00014 #define __BINRELOC_C__
00015
00016 #ifdef ENABLE_BINRELOC
00017 #include <sys/types.h>
00018 #include <sys/stat.h>
00019 #include <unistd.h>
00020 #endif
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <limits.h>
00024 #include <string.h>
00025 #include "binreloc.h"
00026
00027 #ifdef __cplusplus
00028 extern "C" {
00029 #endif
00030
00031
00032
00038 static char *
00039 _br_find_exe (BrInitError *error)
00040 {
00041 #ifndef ENABLE_BINRELOC
00042 if (error)
00043 *error = BR_INIT_ERROR_DISABLED;
00044 return NULL;
00045 #else
00046 char *path, *path2, *line, *result;
00047 size_t buf_size;
00048 ssize_t size;
00049 struct stat stat_buf;
00050 FILE *f;
00051
00052
00053 if (sizeof (path) > SSIZE_MAX)
00054 buf_size = SSIZE_MAX - 1;
00055 else
00056 buf_size = PATH_MAX - 1;
00057 path = (char *) malloc (buf_size);
00058 if (path == NULL) {
00059
00060 if (error)
00061 *error = BR_INIT_ERROR_NOMEM;
00062 return NULL;
00063 }
00064 path2 = (char *) malloc (buf_size);
00065 if (path2 == NULL) {
00066
00067 if (error)
00068 *error = BR_INIT_ERROR_NOMEM;
00069 free (path);
00070 return NULL;
00071 }
00072
00073 strncpy (path2, "/proc/self/exe", buf_size - 1);
00074
00075 while (1) {
00076 int i;
00077
00078 size = readlink (path2, path, buf_size - 1);
00079 if (size == -1) {
00080
00081 free (path2);
00082 break;
00083 }
00084
00085
00086 path[size] = '\0';
00087
00088
00089
00090 i = stat (path, &stat_buf);
00091 if (i == -1) {
00092
00093 free (path2);
00094 break;
00095 }
00096
00097
00098 if (!S_ISLNK (stat_buf.st_mode)) {
00099
00100 free (path2);
00101 return path;
00102 }
00103
00104
00105 strncpy (path, path2, buf_size - 1);
00106 }
00107
00108
00109
00110
00111
00112 buf_size = PATH_MAX + 128;
00113 line = (char *) realloc (path, buf_size);
00114 if (line == NULL) {
00115
00116 free (path);
00117 if (error)
00118 *error = BR_INIT_ERROR_NOMEM;
00119 return NULL;
00120 }
00121
00122 f = fopen ("/proc/self/maps", "r");
00123 if (f == NULL) {
00124 free (line);
00125 if (error)
00126 *error = BR_INIT_ERROR_OPEN_MAPS;
00127 return NULL;
00128 }
00129
00130
00131 result = fgets (line, (int) buf_size, f);
00132 if (result == NULL) {
00133 fclose (f);
00134 free (line);
00135 if (error)
00136 *error = BR_INIT_ERROR_READ_MAPS;
00137 return NULL;
00138 }
00139
00140
00141 buf_size = strlen (line);
00142 if (buf_size <= 0) {
00143
00144 fclose (f);
00145 free (line);
00146 if (error)
00147 *error = BR_INIT_ERROR_INVALID_MAPS;
00148 return NULL;
00149 }
00150 if (line[buf_size - 1] == 10)
00151 line[buf_size - 1] = 0;
00152
00153
00154 path = strchr (line, '/');
00155
00156
00157 if (strstr (line, " r-xp ") == NULL || path == NULL) {
00158 fclose (f);
00159 free (line);
00160 if (error)
00161 *error = BR_INIT_ERROR_INVALID_MAPS;
00162 return NULL;
00163 }
00164
00165 path = strdup (path);
00166 free (line);
00167 fclose (f);
00168 return path;
00169 #endif
00170 }
00171
00172
00177 static char *
00178 _br_find_exe_for_symbol (const void *symbol, BrInitError *error)
00179 {
00180 #ifndef ENABLE_BINRELOC
00181 if (error)
00182 *error = BR_INIT_ERROR_DISABLED;
00183 return (char *) NULL;
00184 #else
00185 #define SIZE PATH_MAX + 100
00186 FILE *f;
00187 size_t address_string_len;
00188 char *address_string, line[SIZE], *found;
00189
00190 if (symbol == NULL)
00191 return (char *) NULL;
00192
00193 f = fopen ("/proc/self/maps", "r");
00194 if (f == NULL)
00195 return (char *) NULL;
00196
00197 address_string_len = 4;
00198 address_string = (char *) malloc (address_string_len);
00199 found = (char *) NULL;
00200
00201 while (!feof (f)) {
00202 char *start_addr, *end_addr, *end_addr_end, *file;
00203 void *start_addr_p, *end_addr_p;
00204 size_t len;
00205
00206 if (fgets (line, SIZE, f) == NULL)
00207 break;
00208
00209
00210 if (strstr (line, " r-xp ") == NULL || strchr (line, '/') == NULL)
00211 continue;
00212
00213
00214 start_addr = line;
00215 end_addr = strchr (line, '-');
00216 file = strchr (line, '/');
00217
00218
00219 if (!(file > end_addr && end_addr != NULL && end_addr[0] == '-'))
00220 continue;
00221
00222 end_addr[0] = '\0';
00223 end_addr++;
00224 end_addr_end = strchr (end_addr, ' ');
00225 if (end_addr_end == NULL)
00226 continue;
00227
00228 end_addr_end[0] = '\0';
00229 len = strlen (file);
00230 if (len == 0)
00231 continue;
00232 if (file[len - 1] == '\n')
00233 file[len - 1] = '\0';
00234
00235
00236 len = strlen (file);
00237 if (len > 10 && strcmp (file + len - 10, " (deleted)") == 0)
00238 file[len - 10] = '\0';
00239
00240
00241 len = strlen (start_addr);
00242 if (len != strlen (end_addr))
00243 continue;
00244
00245
00246
00247
00248 if (address_string_len < len + 3) {
00249 address_string_len = len + 3;
00250 address_string = (char *) realloc (address_string, address_string_len);
00251 }
00252
00253 memcpy (address_string, "0x", 2);
00254 memcpy (address_string + 2, start_addr, len);
00255 address_string[2 + len] = '\0';
00256 sscanf (address_string, "%p", &start_addr_p);
00257
00258 memcpy (address_string, "0x", 2);
00259 memcpy (address_string + 2, end_addr, len);
00260 address_string[2 + len] = '\0';
00261 sscanf (address_string, "%p", &end_addr_p);
00262
00263
00264 if (symbol >= start_addr_p && symbol < end_addr_p) {
00265 found = file;
00266 break;
00267 }
00268 }
00269
00270 free (address_string);
00271 fclose (f);
00272
00273 if (found == NULL)
00274 return (char *) NULL;
00275 else
00276 return strdup (found);
00277 #endif
00278 }
00279
00280
00281 #ifndef BINRELOC_RUNNING_DOXYGEN
00282 #undef NULL
00283 #define NULL ((void *) 0)
00284 #endif
00285
00286 static char *exe = (char *) NULL;
00287
00288
00303 int
00304 br_init (BrInitError *error)
00305 {
00306 exe = _br_find_exe (error);
00307 return exe != NULL;
00308 }
00309
00310
00325 int
00326 br_init_lib (BrInitError *error)
00327 {
00328 exe = _br_find_exe_for_symbol ((const void *) "", error);
00329 return exe != NULL;
00330 }
00331
00332
00342 char *
00343 br_find_exe (const char *default_exe)
00344 {
00345 if (exe == (char *) NULL) {
00346
00347 if (default_exe != (const char *) NULL)
00348 return strdup (default_exe);
00349 else
00350 return (char *) NULL;
00351 }
00352 return strdup (exe);
00353 }
00354
00355
00370 char *
00371 br_find_exe_dir (const char *default_dir)
00372 {
00373 if (exe == NULL) {
00374
00375 if (default_dir != NULL)
00376 return strdup (default_dir);
00377 else
00378 return NULL;
00379 }
00380
00381 return br_dirname (exe);
00382 }
00383
00384
00398 char *
00399 br_find_prefix (const char *default_prefix)
00400 {
00401 char *dir1, *dir2;
00402
00403 if (exe == (char *) NULL) {
00404
00405 if (default_prefix != (const char *) NULL)
00406 return strdup (default_prefix);
00407 else
00408 return (char *) NULL;
00409 }
00410
00411 dir1 = br_dirname (exe);
00412 dir2 = br_dirname (dir1);
00413 free (dir1);
00414 return dir2;
00415 }
00416
00417
00431 char *
00432 br_find_bin_dir (const char *default_bin_dir)
00433 {
00434 char *prefix, *dir;
00435
00436 prefix = br_find_prefix ((const char *) NULL);
00437 if (prefix == (char *) NULL) {
00438
00439 if (default_bin_dir != (const char *) NULL)
00440 return strdup (default_bin_dir);
00441 else
00442 return (char *) NULL;
00443 }
00444
00445 dir = br_build_path (prefix, "bin");
00446 free (prefix);
00447 return dir;
00448 }
00449
00450
00464 char *
00465 br_find_sbin_dir (const char *default_sbin_dir)
00466 {
00467 char *prefix, *dir;
00468
00469 prefix = br_find_prefix ((const char *) NULL);
00470 if (prefix == (char *) NULL) {
00471
00472 if (default_sbin_dir != (const char *) NULL)
00473 return strdup (default_sbin_dir);
00474 else
00475 return (char *) NULL;
00476 }
00477
00478 dir = br_build_path (prefix, "sbin");
00479 free (prefix);
00480 return dir;
00481 }
00482
00483
00498 char *
00499 br_find_data_dir (const char *default_data_dir)
00500 {
00501 char *prefix, *dir;
00502
00503 prefix = br_find_prefix ((const char *) NULL);
00504 if (prefix == (char *) NULL) {
00505
00506 if (default_data_dir != (const char *) NULL)
00507 return strdup (default_data_dir);
00508 else
00509 return (char *) NULL;
00510 }
00511
00512 dir = br_build_path (prefix, "share");
00513 free (prefix);
00514 return dir;
00515 }
00516
00517
00531 char *
00532 br_find_locale_dir (const char *default_locale_dir)
00533 {
00534 char *data_dir, *dir;
00535
00536 data_dir = br_find_data_dir ((const char *) NULL);
00537 if (data_dir == (char *) NULL) {
00538
00539 if (default_locale_dir != (const char *) NULL)
00540 return strdup (default_locale_dir);
00541 else
00542 return (char *) NULL;
00543 }
00544
00545 dir = br_build_path (data_dir, "locale");
00546 free (data_dir);
00547 return dir;
00548 }
00549
00550
00564 char *
00565 br_find_lib_dir (const char *default_lib_dir)
00566 {
00567 char *prefix, *dir;
00568
00569 prefix = br_find_prefix ((const char *) NULL);
00570 if (prefix == (char *) NULL) {
00571
00572 if (default_lib_dir != (const char *) NULL)
00573 return strdup (default_lib_dir);
00574 else
00575 return (char *) NULL;
00576 }
00577
00578 dir = br_build_path (prefix, "lib");
00579 free (prefix);
00580 return dir;
00581 }
00582
00583
00597 char *
00598 br_find_libexec_dir (const char *default_libexec_dir)
00599 {
00600 char *prefix, *dir;
00601
00602 prefix = br_find_prefix ((const char *) NULL);
00603 if (prefix == (char *) NULL) {
00604
00605 if (default_libexec_dir != (const char *) NULL)
00606 return strdup (default_libexec_dir);
00607 else
00608 return (char *) NULL;
00609 }
00610
00611 dir = br_build_path (prefix, "libexec");
00612 free (prefix);
00613 return dir;
00614 }
00615
00616
00630 char *
00631 br_find_etc_dir (const char *default_etc_dir)
00632 {
00633 char *prefix, *dir;
00634
00635 prefix = br_find_prefix ((const char *) NULL);
00636 if (prefix == (char *) NULL) {
00637
00638 if (default_etc_dir != (const char *) NULL)
00639 return strdup (default_etc_dir);
00640 else
00641 return (char *) NULL;
00642 }
00643
00644 dir = br_build_path (prefix, "etc");
00645 free (prefix);
00646 return dir;
00647 }
00648
00649
00650
00651
00652
00653
00660 char *
00661 br_strcat (const char *str1, const char *str2)
00662 {
00663 char *result;
00664 size_t len1, len2;
00665
00666 if (str1 == NULL)
00667 str1 = "";
00668 if (str2 == NULL)
00669 str2 = "";
00670
00671 len1 = strlen (str1);
00672 len2 = strlen (str2);
00673
00674 result = (char *) malloc (len1 + len2 + 1);
00675 memcpy (result, str1, len1);
00676 memcpy (result + len1, str2, len2);
00677 result[len1 + len2] = '\0';
00678
00679 return result;
00680 }
00681
00682
00683 char *
00684 br_build_path (const char *dir, const char *file)
00685 {
00686 char *dir2, *result;
00687 size_t len;
00688 int must_free = 0;
00689
00690 len = strlen (dir);
00691 if (len > 0 && dir[len - 1] != '/') {
00692 dir2 = br_strcat (dir, "/");
00693 must_free = 1;
00694 } else
00695 dir2 = (char *) dir;
00696
00697 result = br_strcat (dir2, file);
00698 if (must_free)
00699 free (dir2);
00700 return result;
00701 }
00702
00703
00704
00705 static char *
00706 br_strndup (const char *str, size_t size)
00707 {
00708 char *result = (char *) NULL;
00709 size_t len;
00710
00711 if (str == (const char *) NULL)
00712 return (char *) NULL;
00713
00714 len = strlen (str);
00715 if (len == 0)
00716 return strdup ("");
00717 if (size > len)
00718 size = len;
00719
00720 result = (char *) malloc (len + 1);
00721 memcpy (result, str, size);
00722 result[size] = '\0';
00723 return result;
00724 }
00725
00726
00739 char *
00740 br_dirname (const char *path)
00741 {
00742 char *end, *result;
00743
00744 if (path == (const char *) NULL)
00745 return (char *) NULL;
00746
00747 end = strrchr (path, '/');
00748 if (end == (const char *) NULL)
00749 return strdup (".");
00750
00751 while (end > path && *end == '/')
00752 end--;
00753 result = br_strndup (path, end - path + 1);
00754 if (result[0] == 0) {
00755 free (result);
00756 return strdup ("/");
00757 } else
00758 return result;
00759 }
00760
00761
00762 #ifdef __cplusplus
00763 }
00764 #endif
00765
00766 #endif