|
Atrinik Client 2.5
|
00001 /************************************************************************ 00002 * Atrinik, a Multiplayer Online Role Playing Game * 00003 * * 00004 * Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team * 00005 * * 00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game) * 00007 * and Crossfire (Multiplayer game for X-windows). * 00008 * * 00009 * This program is free software; you can redistribute it and/or modify * 00010 * it under the terms of the GNU General Public License as published by * 00011 * the Free Software Foundation; either version 2 of the License, or * 00012 * (at your option) any later version. * 00013 * * 00014 * This program is distributed in the hope that it will be useful, * 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00017 * GNU General Public License for more details. * 00018 * * 00019 * You should have received a copy of the GNU General Public License * 00020 * along with this program; if not, write to the Free Software * 00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 00022 * * 00023 * The author can be reached at admin@atrinik.org * 00024 ************************************************************************/ 00025 00039 #include <global.h> 00040 00046 static char * 00047 _br_find_exe (BrInitError *error) 00048 { 00049 #ifndef ENABLE_BINRELOC 00050 if (error) 00051 *error = BR_INIT_ERROR_DISABLED; 00052 return NULL; 00053 #else 00054 char *path, *path2, *line, *result; 00055 size_t buf_size; 00056 ssize_t size; 00057 struct stat stat_buf; 00058 FILE *f; 00059 00060 /* Read from /proc/self/exe (symlink) */ 00061 if (sizeof (path) > SSIZE_MAX) 00062 buf_size = SSIZE_MAX - 1; 00063 else 00064 buf_size = PATH_MAX - 1; 00065 path = (char *) malloc (buf_size); 00066 if (path == NULL) { 00067 /* Cannot allocate memory. */ 00068 if (error) 00069 *error = BR_INIT_ERROR_NOMEM; 00070 return NULL; 00071 } 00072 path2 = (char *) malloc (buf_size); 00073 if (path2 == NULL) { 00074 /* Cannot allocate memory. */ 00075 if (error) 00076 *error = BR_INIT_ERROR_NOMEM; 00077 free (path); 00078 return NULL; 00079 } 00080 00081 strncpy (path2, "/proc/self/exe", buf_size - 1); 00082 00083 while (1) { 00084 int i; 00085 00086 size = readlink (path2, path, buf_size - 1); 00087 if (size == -1) { 00088 /* Error. */ 00089 free (path2); 00090 break; 00091 } 00092 00093 /* readlink() success. */ 00094 path[size] = '\0'; 00095 00096 /* Check whether the symlink's target is also a symlink. 00097 * We want to get the final target. */ 00098 i = stat (path, &stat_buf); 00099 if (i == -1) { 00100 /* Error. */ 00101 free (path2); 00102 break; 00103 } 00104 00105 /* stat() success. */ 00106 if (!S_ISLNK (stat_buf.st_mode)) { 00107 /* path is not a symlink. Done. */ 00108 free (path2); 00109 return path; 00110 } 00111 00112 /* path is a symlink. Continue loop and resolve this. */ 00113 strncpy (path, path2, buf_size - 1); 00114 } 00115 00116 00117 /* readlink() or stat() failed; this can happen when the program is 00118 * running in Valgrind 2.2. Read from /proc/self/maps as fallback. */ 00119 00120 buf_size = PATH_MAX + 128; 00121 line = (char *) realloc (path, buf_size); 00122 if (line == NULL) { 00123 /* Cannot allocate memory. */ 00124 free (path); 00125 if (error) 00126 *error = BR_INIT_ERROR_NOMEM; 00127 return NULL; 00128 } 00129 00130 f = fopen ("/proc/self/maps", "r"); 00131 if (f == NULL) { 00132 free (line); 00133 if (error) 00134 *error = BR_INIT_ERROR_OPEN_MAPS; 00135 return NULL; 00136 } 00137 00138 /* The first entry should be the executable name. */ 00139 result = fgets (line, (int) buf_size, f); 00140 if (result == NULL) { 00141 fclose (f); 00142 free (line); 00143 if (error) 00144 *error = BR_INIT_ERROR_READ_MAPS; 00145 return NULL; 00146 } 00147 00148 /* Get rid of newline character. */ 00149 buf_size = strlen (line); 00150 if (buf_size <= 0) { 00151 /* Huh? An empty string? */ 00152 fclose (f); 00153 free (line); 00154 if (error) 00155 *error = BR_INIT_ERROR_INVALID_MAPS; 00156 return NULL; 00157 } 00158 if (line[buf_size - 1] == 10) 00159 line[buf_size - 1] = 0; 00160 00161 /* Extract the filename; it is always an absolute path. */ 00162 path = strchr (line, '/'); 00163 00164 /* Sanity check. */ 00165 if (strstr (line, " r-xp ") == NULL || path == NULL) { 00166 fclose (f); 00167 free (line); 00168 if (error) 00169 *error = BR_INIT_ERROR_INVALID_MAPS; 00170 return NULL; 00171 } 00172 00173 path = strdup (path); 00174 free (line); 00175 fclose (f); 00176 return path; 00177 #endif /* ENABLE_BINRELOC */ 00178 } 00179 00180 00185 static char * 00186 _br_find_exe_for_symbol (const void *symbol, BrInitError *error) 00187 { 00188 #ifndef ENABLE_BINRELOC 00189 (void) symbol; 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 (void) error; 00200 00201 if (symbol == NULL) 00202 return (char *) NULL; 00203 00204 f = fopen ("/proc/self/maps", "r"); 00205 if (f == NULL) 00206 return (char *) NULL; 00207 00208 address_string_len = 4; 00209 address_string = (char *) malloc (address_string_len); 00210 found = (char *) NULL; 00211 00212 while (!feof (f)) { 00213 char *start_addr, *end_addr, *end_addr_end, *file; 00214 void *start_addr_p, *end_addr_p; 00215 size_t len; 00216 00217 if (fgets (line, SIZE, f) == NULL) 00218 break; 00219 00220 /* Sanity check. */ 00221 if (strstr (line, " r-xp ") == NULL || strchr (line, '/') == NULL) 00222 continue; 00223 00224 /* Parse line. */ 00225 start_addr = line; 00226 end_addr = strchr (line, '-'); 00227 file = strchr (line, '/'); 00228 00229 /* More sanity check. */ 00230 if (!(file > end_addr && end_addr != NULL && end_addr[0] == '-')) 00231 continue; 00232 00233 end_addr[0] = '\0'; 00234 end_addr++; 00235 end_addr_end = strchr (end_addr, ' '); 00236 if (end_addr_end == NULL) 00237 continue; 00238 00239 end_addr_end[0] = '\0'; 00240 len = strlen (file); 00241 if (len == 0) 00242 continue; 00243 if (file[len - 1] == '\n') 00244 file[len - 1] = '\0'; 00245 00246 /* Get rid of "(deleted)" from the filename. */ 00247 len = strlen (file); 00248 if (len > 10 && strcmp (file + len - 10, " (deleted)") == 0) 00249 file[len - 10] = '\0'; 00250 00251 /* I don't know whether this can happen but better safe than sorry. */ 00252 len = strlen (start_addr); 00253 if (len != strlen (end_addr)) 00254 continue; 00255 00256 00257 /* Transform the addresses into a string in the form of 0xdeadbeef, 00258 * then transform that into a pointer. */ 00259 if (address_string_len < len + 3) { 00260 address_string_len = len + 3; 00261 address_string = (char *) realloc (address_string, address_string_len); 00262 } 00263 00264 memcpy (address_string, "0x", 2); 00265 memcpy (address_string + 2, start_addr, len); 00266 address_string[2 + len] = '\0'; 00267 sscanf (address_string, "%p", &start_addr_p); 00268 00269 memcpy (address_string, "0x", 2); 00270 memcpy (address_string + 2, end_addr, len); 00271 address_string[2 + len] = '\0'; 00272 sscanf (address_string, "%p", &end_addr_p); 00273 00274 00275 if (symbol >= start_addr_p && symbol < end_addr_p) { 00276 found = file; 00277 break; 00278 } 00279 } 00280 00281 free (address_string); 00282 fclose (f); 00283 00284 if (found == NULL) 00285 return (char *) NULL; 00286 else 00287 return strdup (found); 00288 #endif /* ENABLE_BINRELOC */ 00289 } 00290 00291 static char *exe = (char *) NULL; 00292 00293 00308 int 00309 br_init (BrInitError *error) 00310 { 00311 exe = _br_find_exe (error); 00312 return exe != NULL; 00313 } 00314 00315 00330 int 00331 br_init_lib (BrInitError *error) 00332 { 00333 exe = _br_find_exe_for_symbol ((const void *) "", error); 00334 return exe != NULL; 00335 } 00336 00337 00347 char * 00348 br_find_exe (const char *default_exe) 00349 { 00350 if (exe == (char *) NULL) { 00351 /* BinReloc is not initialized. */ 00352 if (default_exe != (const char *) NULL) 00353 return strdup (default_exe); 00354 else 00355 return (char *) NULL; 00356 } 00357 return strdup (exe); 00358 } 00359 00360 00375 char * 00376 br_find_exe_dir (const char *default_dir) 00377 { 00378 if (exe == NULL) { 00379 /* BinReloc not initialized. */ 00380 if (default_dir != NULL) 00381 return strdup (default_dir); 00382 else 00383 return NULL; 00384 } 00385 00386 return br_dirname (exe); 00387 } 00388 00389 00403 char * 00404 br_find_prefix (const char *default_prefix) 00405 { 00406 char *dir1, *dir2; 00407 00408 if (exe == (char *) NULL) { 00409 /* BinReloc not initialized. */ 00410 if (default_prefix != (const char *) NULL) 00411 return strdup (default_prefix); 00412 else 00413 return (char *) NULL; 00414 } 00415 00416 dir1 = br_dirname (exe); 00417 dir2 = br_dirname (dir1); 00418 free (dir1); 00419 return dir2; 00420 } 00421 00422 00436 char * 00437 br_find_bin_dir (const char *default_bin_dir) 00438 { 00439 char *prefix, *dir; 00440 00441 prefix = br_find_prefix ((const char *) NULL); 00442 if (prefix == (char *) NULL) { 00443 /* BinReloc not initialized. */ 00444 if (default_bin_dir != (const char *) NULL) 00445 return strdup (default_bin_dir); 00446 else 00447 return (char *) NULL; 00448 } 00449 00450 dir = br_build_path (prefix, "bin"); 00451 free (prefix); 00452 return dir; 00453 } 00454 00455 00469 char * 00470 br_find_sbin_dir (const char *default_sbin_dir) 00471 { 00472 char *prefix, *dir; 00473 00474 prefix = br_find_prefix ((const char *) NULL); 00475 if (prefix == (char *) NULL) { 00476 /* BinReloc not initialized. */ 00477 if (default_sbin_dir != (const char *) NULL) 00478 return strdup (default_sbin_dir); 00479 else 00480 return (char *) NULL; 00481 } 00482 00483 dir = br_build_path (prefix, "sbin"); 00484 free (prefix); 00485 return dir; 00486 } 00487 00488 00503 char * 00504 br_find_data_dir (const char *default_data_dir) 00505 { 00506 char *prefix, *dir; 00507 00508 prefix = br_find_prefix ((const char *) NULL); 00509 if (prefix == (char *) NULL) { 00510 /* BinReloc not initialized. */ 00511 if (default_data_dir != (const char *) NULL) 00512 return strdup (default_data_dir); 00513 else 00514 return (char *) NULL; 00515 } 00516 00517 dir = br_build_path (prefix, "share"); 00518 free (prefix); 00519 return dir; 00520 } 00521 00522 00536 char * 00537 br_find_locale_dir (const char *default_locale_dir) 00538 { 00539 char *data_dir, *dir; 00540 00541 data_dir = br_find_data_dir ((const char *) NULL); 00542 if (data_dir == (char *) NULL) { 00543 /* BinReloc not initialized. */ 00544 if (default_locale_dir != (const char *) NULL) 00545 return strdup (default_locale_dir); 00546 else 00547 return (char *) NULL; 00548 } 00549 00550 dir = br_build_path (data_dir, "locale"); 00551 free (data_dir); 00552 return dir; 00553 } 00554 00555 00569 char * 00570 br_find_lib_dir (const char *default_lib_dir) 00571 { 00572 char *prefix, *dir; 00573 00574 prefix = br_find_prefix ((const char *) NULL); 00575 if (prefix == (char *) NULL) { 00576 /* BinReloc not initialized. */ 00577 if (default_lib_dir != (const char *) NULL) 00578 return strdup (default_lib_dir); 00579 else 00580 return (char *) NULL; 00581 } 00582 00583 dir = br_build_path (prefix, "lib"); 00584 free (prefix); 00585 return dir; 00586 } 00587 00588 00602 char * 00603 br_find_libexec_dir (const char *default_libexec_dir) 00604 { 00605 char *prefix, *dir; 00606 00607 prefix = br_find_prefix ((const char *) NULL); 00608 if (prefix == (char *) NULL) { 00609 /* BinReloc not initialized. */ 00610 if (default_libexec_dir != (const char *) NULL) 00611 return strdup (default_libexec_dir); 00612 else 00613 return (char *) NULL; 00614 } 00615 00616 dir = br_build_path (prefix, "libexec"); 00617 free (prefix); 00618 return dir; 00619 } 00620 00621 00635 char * 00636 br_find_etc_dir (const char *default_etc_dir) 00637 { 00638 char *prefix, *dir; 00639 00640 prefix = br_find_prefix ((const char *) NULL); 00641 if (prefix == (char *) NULL) { 00642 /* BinReloc not initialized. */ 00643 if (default_etc_dir != (const char *) NULL) 00644 return strdup (default_etc_dir); 00645 else 00646 return (char *) NULL; 00647 } 00648 00649 dir = br_build_path (prefix, "etc"); 00650 free (prefix); 00651 return dir; 00652 } 00653 00654 00655 /*********************** 00656 * Utility functions 00657 ***********************/ 00658 00665 char * 00666 br_strcat (const char *str1, const char *str2) 00667 { 00668 char *result; 00669 size_t len1, len2; 00670 00671 if (str1 == NULL) 00672 str1 = ""; 00673 if (str2 == NULL) 00674 str2 = ""; 00675 00676 len1 = strlen (str1); 00677 len2 = strlen (str2); 00678 00679 result = (char *) malloc (len1 + len2 + 1); 00680 memcpy (result, str1, len1); 00681 memcpy (result + len1, str2, len2); 00682 result[len1 + len2] = '\0'; 00683 00684 return result; 00685 } 00686 00687 00688 char * 00689 br_build_path (const char *dir, const char *file) 00690 { 00691 char *dir2, *result; 00692 size_t len; 00693 int must_free = 0; 00694 00695 len = strlen (dir); 00696 if (len > 0 && dir[len - 1] != '/') { 00697 dir2 = br_strcat (dir, "/"); 00698 must_free = 1; 00699 } else 00700 dir2 = (char *) dir; 00701 00702 result = br_strcat (dir2, file); 00703 if (must_free) 00704 free (dir2); 00705 return result; 00706 } 00707 00708 00709 /* Emulates glibc's strndup() */ 00710 static char * 00711 br_strndup (const char *str, size_t size) 00712 { 00713 char *result = (char *) NULL; 00714 size_t len; 00715 00716 if (str == (const char *) NULL) 00717 return (char *) NULL; 00718 00719 len = strlen (str); 00720 if (len == 0) 00721 return strdup (""); 00722 if (size > len) 00723 size = len; 00724 00725 result = (char *) malloc (len + 1); 00726 memcpy (result, str, size); 00727 result[size] = '\0'; 00728 return result; 00729 } 00730 00731 00744 char * 00745 br_dirname (const char *path) 00746 { 00747 char *end, *result; 00748 00749 if (path == (const char *) NULL) 00750 return (char *) NULL; 00751 00752 end = strrchr (path, '/'); 00753 if (end == (const char *) NULL) 00754 return strdup ("."); 00755 00756 while (end > path && *end == '/') 00757 end--; 00758 result = br_strndup (path, end - path + 1); 00759 if (result[0] == 0) { 00760 free (result); 00761 return strdup ("/"); 00762 } else 00763 return result; 00764 }
1.7.4