00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #ifndef __BINRELOC_C__
00014 #define __BINRELOC_C__
00015 #include "config.h"
00016
00017 #ifdef ENABLE_BINRELOC
00018 #include <sys/types.h>
00019 #include <sys/stat.h>
00020 #include <unistd.h>
00021 #endif
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <limits.h>
00025 #include <string.h>
00026 #include "binreloc.h"
00027 #include <glib.h>
00028
00029 G_BEGIN_DECLS
00030
00031
00037 static char *
00038 _br_find_exe (GbrInitError *error)
00039 {
00040 #ifndef ENABLE_BINRELOC
00041 if (error)
00042 *error = GBR_INIT_ERROR_DISABLED;
00043 return NULL;
00044 #else
00045 #ifdef G_OS_WIN32
00046
00047
00048
00049
00050
00051 gchar *prefix;
00052 gchar *result;
00053
00054
00055
00056
00057
00058 prefix = g_win32_get_package_installation_directory ("GnuCash", NULL);
00059 result = g_build_filename (prefix,
00060 "bin", "gnucash-bin.exe",
00061 (char*)NULL);
00062 g_free (prefix);
00063 return result;
00064 #else
00065 char *path, *path2, *line, *result;
00066 size_t buf_size;
00067 ssize_t size;
00068 struct stat stat_buf;
00069 FILE *f;
00070
00071
00072 if (sizeof (path) > SSIZE_MAX)
00073 buf_size = SSIZE_MAX - 1;
00074 else
00075 buf_size = PATH_MAX - 1;
00076 path = (char *) g_try_malloc (buf_size);
00077 if (path == NULL) {
00078
00079 if (error)
00080 *error = GBR_INIT_ERROR_NOMEM;
00081 return NULL;
00082 }
00083 path2 = (char *) g_try_malloc (buf_size);
00084 if (path2 == NULL) {
00085
00086 if (error)
00087 *error = GBR_INIT_ERROR_NOMEM;
00088 g_free (path);
00089 return NULL;
00090 }
00091
00092 strncpy (path2, "/proc/self/exe", buf_size - 1);
00093
00094 while (1) {
00095 int i;
00096
00097 size = readlink (path2, path, buf_size - 1);
00098 if (size == -1) {
00099
00100 g_free (path2);
00101 break;
00102 }
00103
00104
00105 path[size] = '\0';
00106
00107
00108
00109 i = stat (path, &stat_buf);
00110 if (i == -1) {
00111
00112 g_free (path2);
00113 break;
00114 }
00115
00116
00117 if (!S_ISLNK (stat_buf.st_mode)) {
00118
00119 g_free (path2);
00120 return path;
00121 }
00122
00123
00124 strncpy (path, path2, buf_size - 1);
00125 }
00126
00127
00128
00129
00130
00131 buf_size = PATH_MAX + 128;
00132 line = (char *) g_try_realloc (path, buf_size);
00133 if (line == NULL) {
00134
00135 g_free (path);
00136 if (error)
00137 *error = GBR_INIT_ERROR_NOMEM;
00138 return NULL;
00139 }
00140
00141 f = fopen ("/proc/self/maps", "r");
00142 if (f == NULL) {
00143 g_free (line);
00144 if (error)
00145 *error = GBR_INIT_ERROR_OPEN_MAPS;
00146 return NULL;
00147 }
00148
00149
00150 result = fgets (line, (int) buf_size, f);
00151 if (result == NULL) {
00152 fclose (f);
00153 g_free (line);
00154 if (error)
00155 *error = GBR_INIT_ERROR_READ_MAPS;
00156 return NULL;
00157 }
00158
00159
00160 buf_size = strlen (line);
00161 if (buf_size <= 0) {
00162
00163 fclose (f);
00164 g_free (line);
00165 if (error)
00166 *error = GBR_INIT_ERROR_INVALID_MAPS;
00167 return NULL;
00168 }
00169 if (line[buf_size - 1] == 10)
00170 line[buf_size - 1] = 0;
00171
00172
00173 path = strchr (line, '/');
00174
00175
00176 if (strstr (line, " r-xp ") == NULL || path == NULL) {
00177 fclose (f);
00178 g_free (line);
00179 if (error)
00180 *error = GBR_INIT_ERROR_INVALID_MAPS;
00181 return NULL;
00182 }
00183
00184 path = g_strdup (path);
00185 g_free (line);
00186 fclose (f);
00187 return path;
00188 #endif
00189 #endif
00190 }
00191
00192
00197 static char *
00198 _br_find_exe_for_symbol (const void *symbol, GbrInitError *error)
00199 {
00200 #ifndef ENABLE_BINRELOC
00201 if (error)
00202 *error = GBR_INIT_ERROR_DISABLED;
00203 return (char *) NULL;
00204 #else
00205 #ifdef G_OS_WIN32
00206 g_warning ("_br_find_exe_for_symbol not implemented on win32.");
00207 if (error)
00208 *error = GBR_INIT_ERROR_DISABLED;
00209 return (char *) NULL;
00210 #else
00211 #define SIZE PATH_MAX + 100
00212 FILE *f;
00213 size_t address_string_len;
00214 char *address_string, line[SIZE], *found;
00215
00216 if (symbol == NULL)
00217 return (char *) NULL;
00218
00219 f = fopen ("/proc/self/maps", "r");
00220 if (f == NULL)
00221 return (char *) NULL;
00222
00223 address_string_len = 4;
00224 address_string = (char *) g_try_malloc (address_string_len);
00225 found = (char *) NULL;
00226
00227 while (!feof (f)) {
00228 char *start_addr, *end_addr, *end_addr_end, *file;
00229 void *start_addr_p, *end_addr_p;
00230 size_t len;
00231
00232 if (fgets (line, SIZE, f) == NULL)
00233 break;
00234
00235
00236 if (strstr (line, " r-xp ") == NULL || strchr (line, '/') == NULL)
00237 continue;
00238
00239
00240 start_addr = line;
00241 end_addr = strchr (line, '-');
00242 file = strchr (line, '/');
00243
00244
00245 if (!(file > end_addr && end_addr != NULL && end_addr[0] == '-'))
00246 continue;
00247
00248 end_addr[0] = '\0';
00249 end_addr++;
00250 end_addr_end = strchr (end_addr, ' ');
00251 if (end_addr_end == NULL)
00252 continue;
00253
00254 end_addr_end[0] = '\0';
00255 len = strlen (file);
00256 if (len == 0)
00257 continue;
00258 if (file[len - 1] == '\n')
00259 file[len - 1] = '\0';
00260
00261
00262 len = strlen (file);
00263 if (len > 10 && strcmp (file + len - 10, " (deleted)") == 0)
00264 file[len - 10] = '\0';
00265
00266
00267 len = strlen (start_addr);
00268 if (len != strlen (end_addr))
00269 continue;
00270
00271
00272
00273
00274 if (address_string_len < len + 3) {
00275 address_string_len = len + 3;
00276 address_string = (char *) g_try_realloc (address_string, address_string_len);
00277 }
00278
00279 memcpy (address_string, "0x", 2);
00280 memcpy (address_string + 2, start_addr, len);
00281 address_string[2 + len] = '\0';
00282 sscanf (address_string, "%p", &start_addr_p);
00283
00284 memcpy (address_string, "0x", 2);
00285 memcpy (address_string + 2, end_addr, len);
00286 address_string[2 + len] = '\0';
00287 sscanf (address_string, "%p", &end_addr_p);
00288
00289
00290 if (symbol >= start_addr_p && symbol < end_addr_p) {
00291 found = file;
00292 break;
00293 }
00294 }
00295
00296 g_free (address_string);
00297 fclose (f);
00298
00299 if (found == NULL)
00300 return (char *) NULL;
00301 else
00302 return g_strdup (found);
00303 #endif
00304 #endif
00305 }
00306
00307
00308 static gchar *exe = NULL;
00309
00310 static void set_gerror (GError **error, GbrInitError errcode);
00311
00312
00328 gboolean
00329 gbr_init (GError **error)
00330 {
00331 GbrInitError errcode = 0;
00332
00333
00334 exe = _br_find_exe (&errcode);
00335 if (exe != NULL)
00336
00337 return TRUE;
00338 else {
00339
00340 set_gerror (error, errcode);
00341 return FALSE;
00342 }
00343 }
00344
00345
00356 gboolean
00357 gbr_init_lib (GError **error)
00358 {
00359 GbrInitError errcode = 0;
00360
00361 exe = _br_find_exe_for_symbol ((const void *) "", &errcode);
00362 if (exe != NULL)
00363
00364 return TRUE;
00365 else {
00366
00367 set_gerror (error, errcode);
00368 return exe != NULL;
00369 }
00370 }
00371
00372
00373 static void
00374 set_gerror (GError **error, GbrInitError errcode)
00375 {
00376 gchar *error_message;
00377
00378 if (error == NULL)
00379 return;
00380
00381 switch (errcode) {
00382 case GBR_INIT_ERROR_NOMEM:
00383 error_message = "Cannot allocate memory.";
00384 break;
00385 case GBR_INIT_ERROR_OPEN_MAPS:
00386 error_message = "Unable to open /proc/self/maps for reading.";
00387 break;
00388 case GBR_INIT_ERROR_READ_MAPS:
00389 error_message = "Unable to read from /proc/self/maps.";
00390 break;
00391 case GBR_INIT_ERROR_INVALID_MAPS:
00392 error_message = "The file format of /proc/self/maps is invalid.";
00393 break;
00394 case GBR_INIT_ERROR_DISABLED:
00395 error_message = "Binary relocation support is disabled.";
00396 break;
00397 default:
00398 error_message = "Unknown error.";
00399 break;
00400 };
00401 g_set_error (error, g_quark_from_static_string ("GBinReloc"),
00402 errcode, "%s", error_message);
00403 }
00404
00405
00415 gchar *
00416 gbr_find_exe (const gchar *default_exe)
00417 {
00418 if (exe == NULL) {
00419
00420 if (default_exe != NULL)
00421 return g_strdup (default_exe);
00422 else
00423 return NULL;
00424 }
00425 return g_strdup (exe);
00426 }
00427
00428
00443 gchar *
00444 gbr_find_exe_dir (const gchar *default_dir)
00445 {
00446 if (exe == NULL) {
00447
00448 if (default_dir != NULL)
00449 return g_strdup (default_dir);
00450 else
00451 return NULL;
00452 }
00453
00454 return g_path_get_dirname (exe);
00455 }
00456
00457
00472 gchar *
00473 gbr_find_prefix (const gchar *default_prefix)
00474 {
00475 gchar *dir1, *dir2;
00476
00477 if (exe == NULL) {
00478
00479 if (default_prefix != NULL)
00480 return g_strdup (default_prefix);
00481 else
00482 return NULL;
00483 }
00484
00485 dir1 = g_path_get_dirname (exe);
00486 dir2 = g_path_get_dirname (dir1);
00487 g_free (dir1);
00488 return dir2;
00489 }
00490
00491
00505 gchar *
00506 gbr_find_bin_dir (const gchar *default_bin_dir)
00507 {
00508 gchar *prefix, *dir;
00509
00510 prefix = gbr_find_prefix (NULL);
00511 if (prefix == NULL) {
00512
00513 if (default_bin_dir != NULL)
00514 return g_strdup (default_bin_dir);
00515 else
00516 return NULL;
00517 }
00518
00519 dir = g_build_filename (prefix, "bin", NULL);
00520 g_free (prefix);
00521 return dir;
00522 }
00523
00524
00538 gchar *
00539 gbr_find_sbin_dir (const gchar *default_sbin_dir)
00540 {
00541 gchar *prefix, *dir;
00542
00543 prefix = gbr_find_prefix (NULL);
00544 if (prefix == NULL) {
00545
00546 if (default_sbin_dir != NULL)
00547 return g_strdup (default_sbin_dir);
00548 else
00549 return NULL;
00550 }
00551
00552 dir = g_build_filename (prefix, "sbin", NULL);
00553 g_free (prefix);
00554 return dir;
00555 }
00556
00557
00572 gchar *
00573 gbr_find_data_dir (const gchar *default_data_dir)
00574 {
00575 gchar *prefix, *dir;
00576
00577 prefix = gbr_find_prefix (NULL);
00578 if (prefix == NULL) {
00579
00580 if (default_data_dir != NULL)
00581 return g_strdup (default_data_dir);
00582 else
00583 return NULL;
00584 }
00585
00586 dir = g_build_filename (prefix, "share", NULL);
00587 g_free (prefix);
00588 return dir;
00589 }
00590
00591
00605 gchar *
00606 gbr_find_lib_dir (const gchar *default_lib_dir)
00607 {
00608 gchar *prefix, *dir;
00609
00610 prefix = gbr_find_prefix (NULL);
00611 if (prefix == NULL) {
00612
00613 if (default_lib_dir != NULL)
00614 return g_strdup (default_lib_dir);
00615 else
00616 return NULL;
00617 }
00618
00619 dir = g_build_filename (prefix, "lib", NULL);
00620 g_free (prefix);
00621 return dir;
00622 }
00623
00624
00638 gchar *
00639 gbr_find_libexec_dir (const gchar *default_libexec_dir)
00640 {
00641 gchar *prefix, *dir;
00642
00643 prefix = gbr_find_prefix (NULL);
00644 if (prefix == NULL) {
00645
00646 if (default_libexec_dir != NULL)
00647 return g_strdup (default_libexec_dir);
00648 else
00649 return NULL;
00650 }
00651
00652 dir = g_build_filename (prefix, "libexec", NULL);
00653 g_free (prefix);
00654 return dir;
00655 }
00656
00657
00671 gchar *
00672 gbr_find_etc_dir (const gchar *default_etc_dir)
00673 {
00674 gchar *prefix, *dir;
00675
00676 prefix = gbr_find_prefix (NULL);
00677 if (prefix == NULL) {
00678
00679 if (default_etc_dir != NULL)
00680 return g_strdup (default_etc_dir);
00681 else
00682 return NULL;
00683 }
00684
00685 dir = g_build_filename (prefix, "etc", NULL);
00686 g_free (prefix);
00687 return dir;
00688 }
00689
00690
00691 G_END_DECLS
00692
00693 #endif