00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113 #ifndef __BINRELOC_C__
00114 #define __BINRELOC_C__
00115
00116 #ifdef ENABLE_BINRELOC
00117 #include <sys/types.h>
00118 #include <sys/stat.h>
00119 #include <unistd.h>
00120 #endif
00121 #include <stdio.h>
00122 #include <stdlib.h>
00123 #include <limits.h>
00124 #include <string.h>
00125 #include "binreloc.h"
00126
00127 #ifdef __cplusplus
00128 extern "C" {
00129 #endif
00130
00131
00132
00138 static char *
00139 _br_find_exe (BrInitError *error)
00140 {
00141 #ifndef ENABLE_BINRELOC
00142 if (error)
00143 *error = BR_INIT_ERROR_DISABLED;
00144 return NULL;
00145 #else
00146 char *path, *path2, *line, *result;
00147 size_t buf_size;
00148 ssize_t size;
00149 struct stat stat_buf;
00150 FILE *f;
00151
00152
00153 if (sizeof (path) > SSIZE_MAX)
00154 buf_size = SSIZE_MAX - 1;
00155 else
00156 buf_size = PATH_MAX - 1;
00157 path = (char *) malloc (buf_size);
00158 if (path == NULL) {
00159
00160 if (error)
00161 *error = BR_INIT_ERROR_NOMEM;
00162 return NULL;
00163 }
00164 path2 = (char *) malloc (buf_size);
00165 if (path2 == NULL) {
00166
00167 if (error)
00168 *error = BR_INIT_ERROR_NOMEM;
00169 free (path);
00170 return NULL;
00171 }
00172
00173 strncpy (path2, "/proc/self/exe", buf_size - 1);
00174
00175 while (1) {
00176 int i;
00177
00178 size = readlink (path2, path, buf_size - 1);
00179 if (size == -1) {
00180
00181 free (path2);
00182 break;
00183 }
00184
00185
00186 path[size] = '\0';
00187
00188
00189
00190 i = stat (path, &stat_buf);
00191 if (i == -1) {
00192
00193 free (path2);
00194 break;
00195 }
00196
00197
00198 if (!S_ISLNK (stat_buf.st_mode)) {
00199
00200 free (path2);
00201 return path;
00202 }
00203
00204
00205 strncpy (path, path2, buf_size - 1);
00206 }
00207
00208
00209
00210
00211
00212 buf_size = PATH_MAX + 128;
00213 line = (char *) realloc (path, buf_size);
00214 if (line == NULL) {
00215
00216 free (path);
00217 if (error)
00218 *error = BR_INIT_ERROR_NOMEM;
00219 return NULL;
00220 }
00221
00222 f = fopen ("/proc/self/maps", "r");
00223 if (f == NULL) {
00224 free (line);
00225 if (error)
00226 *error = BR_INIT_ERROR_OPEN_MAPS;
00227 return NULL;
00228 }
00229
00230
00231 result = fgets (line, (int) buf_size, f);
00232 if (result == NULL) {
00233 fclose (f);
00234 free (line);
00235 if (error)
00236 *error = BR_INIT_ERROR_READ_MAPS;
00237 return NULL;
00238 }
00239
00240
00241 buf_size = strlen (line);
00242 if (buf_size <= 0) {
00243
00244 fclose (f);
00245 free (line);
00246 if (error)
00247 *error = BR_INIT_ERROR_INVALID_MAPS;
00248 return NULL;
00249 }
00250 if (line[buf_size - 1] == 10)
00251 line[buf_size - 1] = 0;
00252
00253
00254 path = strchr (line, '/');
00255
00256
00257 if (strstr (line, " r-xp ") == NULL || path == NULL) {
00258 fclose (f);
00259 free (line);
00260 if (error)
00261 *error = BR_INIT_ERROR_INVALID_MAPS;
00262 return NULL;
00263 }
00264
00265 path = strdup (path);
00266 free (line);
00267 fclose (f);
00268 return path;
00269 #endif
00270 }
00271
00272
00277 static char *
00278 _br_find_exe_for_symbol (const void *symbol, BrInitError *error)
00279 {
00280 #ifndef ENABLE_BINRELOC
00281 if (error)
00282 *error = BR_INIT_ERROR_DISABLED;
00283 return (char *) NULL;
00284 #else
00285 #define SIZE PATH_MAX + 100
00286 FILE *f;
00287 size_t address_string_len;
00288 char *address_string, line[SIZE], *found;
00289
00290 if (symbol == NULL)
00291 return (char *) NULL;
00292
00293 f = fopen ("/proc/self/maps", "r");
00294 if (f == NULL)
00295 return (char *) NULL;
00296
00297 address_string_len = 4;
00298 address_string = (char *) malloc (address_string_len);
00299 found = (char *) NULL;
00300
00301 while (!feof (f)) {
00302 char *start_addr, *end_addr, *end_addr_end, *file;
00303 void *start_addr_p, *end_addr_p;
00304 size_t len;
00305
00306 if (fgets (line, SIZE, f) == NULL)
00307 break;
00308
00309
00310 if (strstr (line, " r-xp ") == NULL || strchr (line, '/') == NULL)
00311 continue;
00312
00313
00314 start_addr = line;
00315 end_addr = strchr (line, '-');
00316 file = strchr (line, '/');
00317
00318
00319 if (!(file > end_addr && end_addr != NULL && end_addr[0] == '-'))
00320 continue;
00321
00322 end_addr[0] = '\0';
00323 end_addr++;
00324 end_addr_end = strchr (end_addr, ' ');
00325 if (end_addr_end == NULL)
00326 continue;
00327
00328 end_addr_end[0] = '\0';
00329 len = strlen (file);
00330 if (len == 0)
00331 continue;
00332 if (file[len - 1] == '\n')
00333 file[len - 1] = '\0';
00334
00335
00336 len = strlen (file);
00337 if (len > 10 && strcmp (file + len - 10, " (deleted)") == 0)
00338 file[len - 10] = '\0';
00339
00340
00341 len = strlen (start_addr);
00342 if (len != strlen (end_addr))
00343 continue;
00344
00345
00346
00347
00348 if (address_string_len < len + 3) {
00349 address_string_len = len + 3;
00350 address_string = (char *) realloc (address_string, address_string_len);
00351 }
00352
00353 memcpy (address_string, "0x", 2);
00354 memcpy (address_string + 2, start_addr, len);
00355 address_string[2 + len] = '\0';
00356 sscanf (address_string, "%p", &start_addr_p);
00357
00358 memcpy (address_string, "0x", 2);
00359 memcpy (address_string + 2, end_addr, len);
00360 address_string[2 + len] = '\0';
00361 sscanf (address_string, "%p", &end_addr_p);
00362
00363
00364 if (symbol >= start_addr_p && symbol < end_addr_p) {
00365 found = file;
00366 break;
00367 }
00368 }
00369
00370 free (address_string);
00371 fclose (f);
00372
00373 if (found == NULL)
00374 return (char *) NULL;
00375 else
00376 return strdup (found);
00377 #endif
00378 }
00379
00380
00381 #ifndef BINRELOC_RUNNING_DOXYGEN
00382 #undef NULL
00383 #define NULL ((void *) 0)
00384 #endif
00385
00386 static char *exe = (char *) NULL;
00387
00388
00403 int
00404 br_init (BrInitError *error)
00405 {
00406 exe = _br_find_exe (error);
00407 return exe != NULL;
00408 }
00409
00410
00425 int
00426 br_init_lib (BrInitError *error)
00427 {
00428 exe = _br_find_exe_for_symbol ((const void *) "", error);
00429 return exe != NULL;
00430 }
00431
00432
00442 char *
00443 br_find_exe (const char *default_exe)
00444 {
00445 if (exe == (char *) NULL) {
00446
00447 if (default_exe != (const char *) NULL)
00448 return strdup (default_exe);
00449 else
00450 return (char *) NULL;
00451 }
00452 return strdup (exe);
00453 }
00454
00455
00470 char *
00471 br_find_exe_dir (const char *default_dir)
00472 {
00473 if (exe == NULL) {
00474
00475 if (default_dir != NULL)
00476 return strdup (default_dir);
00477 else
00478 return NULL;
00479 }
00480
00481 return br_dirname (exe);
00482 }
00483
00484
00498 char *
00499 br_find_prefix (const char *default_prefix)
00500 {
00501 char *dir1, *dir2;
00502
00503 if (exe == (char *) NULL) {
00504
00505 if (default_prefix != (const char *) NULL)
00506 return strdup (default_prefix);
00507 else
00508 return (char *) NULL;
00509 }
00510
00511 dir1 = br_dirname (exe);
00512 dir2 = br_dirname (dir1);
00513 free (dir1);
00514 return dir2;
00515 }
00516
00517
00531 char *
00532 br_find_bin_dir (const char *default_bin_dir)
00533 {
00534 char *prefix, *dir;
00535
00536 prefix = br_find_prefix ((const char *) NULL);
00537 if (prefix == (char *) NULL) {
00538
00539 if (default_bin_dir != (const char *) NULL)
00540 return strdup (default_bin_dir);
00541 else
00542 return (char *) NULL;
00543 }
00544
00545 dir = br_build_path (prefix, "bin");
00546 free (prefix);
00547 return dir;
00548 }
00549
00550
00564 char *
00565 br_find_sbin_dir (const char *default_sbin_dir)
00566 {
00567 char *prefix, *dir;
00568
00569 prefix = br_find_prefix ((const char *) NULL);
00570 if (prefix == (char *) NULL) {
00571
00572 if (default_sbin_dir != (const char *) NULL)
00573 return strdup (default_sbin_dir);
00574 else
00575 return (char *) NULL;
00576 }
00577
00578 dir = br_build_path (prefix, "sbin");
00579 free (prefix);
00580 return dir;
00581 }
00582
00583
00598 char *
00599 br_find_data_dir (const char *default_data_dir)
00600 {
00601 char *prefix, *dir;
00602
00603 prefix = br_find_prefix ((const char *) NULL);
00604 if (prefix == (char *) NULL) {
00605
00606 if (default_data_dir != (const char *) NULL)
00607 return strdup (default_data_dir);
00608 else
00609 return (char *) NULL;
00610 }
00611
00612 dir = br_build_path (prefix, "share");
00613 free (prefix);
00614 return dir;
00615 }
00616
00617
00631 char *
00632 br_find_locale_dir (const char *default_locale_dir)
00633 {
00634 char *data_dir, *dir;
00635
00636 data_dir = br_find_data_dir ((const char *) NULL);
00637 if (data_dir == (char *) NULL) {
00638
00639 if (default_locale_dir != (const char *) NULL)
00640 return strdup (default_locale_dir);
00641 else
00642 return (char *) NULL;
00643 }
00644
00645 dir = br_build_path (data_dir, "locale");
00646 free (data_dir);
00647 return dir;
00648 }
00649
00650
00664 char *
00665 br_find_lib_dir (const char *default_lib_dir)
00666 {
00667 char *prefix, *dir;
00668
00669 prefix = br_find_prefix ((const char *) NULL);
00670 if (prefix == (char *) NULL) {
00671
00672 if (default_lib_dir != (const char *) NULL)
00673 return strdup (default_lib_dir);
00674 else
00675 return (char *) NULL;
00676 }
00677
00678 dir = br_build_path (prefix, "lib");
00679 free (prefix);
00680 return dir;
00681 }
00682
00683
00697 char *
00698 br_find_libexec_dir (const char *default_libexec_dir)
00699 {
00700 char *prefix, *dir;
00701
00702 prefix = br_find_prefix ((const char *) NULL);
00703 if (prefix == (char *) NULL) {
00704
00705 if (default_libexec_dir != (const char *) NULL)
00706 return strdup (default_libexec_dir);
00707 else
00708 return (char *) NULL;
00709 }
00710
00711 dir = br_build_path (prefix, "libexec");
00712 free (prefix);
00713 return dir;
00714 }
00715
00716
00730 char *
00731 br_find_etc_dir (const char *default_etc_dir)
00732 {
00733 char *prefix, *dir;
00734
00735 prefix = br_find_prefix ((const char *) NULL);
00736 if (prefix == (char *) NULL) {
00737
00738 if (default_etc_dir != (const char *) NULL)
00739 return strdup (default_etc_dir);
00740 else
00741 return (char *) NULL;
00742 }
00743
00744 dir = br_build_path (prefix, "etc");
00745 free (prefix);
00746 return dir;
00747 }
00748
00749
00750
00751
00752
00753
00760 char *
00761 br_strcat (const char *str1, const char *str2)
00762 {
00763 char *result;
00764 size_t len1, len2;
00765
00766 if (str1 == NULL)
00767 str1 = "";
00768 if (str2 == NULL)
00769 str2 = "";
00770
00771 len1 = strlen (str1);
00772 len2 = strlen (str2);
00773
00774 result = (char *) malloc (len1 + len2 + 1);
00775 memcpy (result, str1, len1);
00776 memcpy (result + len1, str2, len2);
00777 result[len1 + len2] = '\0';
00778
00779 return result;
00780 }
00781
00782
00783 char *
00784 br_build_path (const char *dir, const char *file)
00785 {
00786 char *dir2, *result;
00787 size_t len;
00788 int must_free = 0;
00789
00790 len = strlen (dir);
00791 if (len > 0 && dir[len - 1] != '/') {
00792 dir2 = br_strcat (dir, "/");
00793 must_free = 1;
00794 } else
00795 dir2 = (char *) dir;
00796
00797 result = br_strcat (dir2, file);
00798 if (must_free)
00799 free (dir2);
00800 return result;
00801 }
00802
00803
00804
00805 static char *
00806 br_strndup (const char *str, size_t size)
00807 {
00808 char *result = (char *) NULL;
00809 size_t len;
00810
00811 if (str == (const char *) NULL)
00812 return (char *) NULL;
00813
00814 len = strlen (str);
00815 if (len == 0)
00816 return strdup ("");
00817 if (size > len)
00818 size = len;
00819
00820 result = (char *) malloc (len + 1);
00821 memcpy (result, str, size);
00822 result[size] = '\0';
00823 return result;
00824 }
00825
00826
00839 char *
00840 br_dirname (const char *path)
00841 {
00842 char *end, *result;
00843
00844 if (path == (const char *) NULL)
00845 return (char *) NULL;
00846
00847 end = strrchr (path, '/');
00848 if (end == (const char *) NULL)
00849 return strdup (".");
00850
00851 while (end > path && *end == '/')
00852 end--;
00853 result = br_strndup (path, end - path + 1);
00854 if (result[0] == 0) {
00855 free (result);
00856 return strdup ("/");
00857 } else
00858 return result;
00859 }
00860
00861
00862 #ifdef __cplusplus
00863 }
00864 #endif
00865
00866 #endif