Sat, 20 Jan 2007 02:32:10 +0000
Rename gtk/ and libgaim/ to pidgin/ and libpurple/
| 10245 | 1 | /* |
| 2 | * BinReloc - a library for creating relocatable executables | |
| 3 | * Written by: Mike Hearn <mike@theoretic.com> | |
| 4 | * Hongli Lai <h.lai@chello.nl> | |
| 5 | * http://autopackage.org/ | |
| 6 | * | |
| 7 | * This source code is public domain. You can relicense this code | |
| 8 | * under whatever license you want. | |
| 9 | * | |
| 10 | * NOTE: if you're using C++ and are getting "undefined reference | |
| 11 | * to br_*", try renaming prefix.c to prefix.cpp | |
| 12 | */ | |
| 13 | ||
| 14 | /* WARNING, BEFORE YOU MODIFY PREFIX.C: | |
| 15 | * | |
| 16 | * If you make changes to any of the functions in prefix.c, you MUST | |
| 17 | * change the BR_NAMESPACE macro (in prefix.h). | |
| 18 | * This way you can avoid symbol table conflicts with other libraries | |
| 19 | * that also happen to use BinReloc. | |
| 20 | * | |
| 21 | * Example: | |
| 22 | * #define BR_NAMESPACE(funcName) foobar_ ## funcName | |
| 23 | * --> expands br_locate to foobar_br_locate | |
| 24 | */ | |
| 25 | ||
| 26 | #ifndef _PREFIX_C_ | |
| 27 | #define _PREFIX_C_ | |
| 28 | ||
| 29 | #ifdef HAVE_CONFIG_H | |
| 30 | #include "config.h" | |
| 31 | #endif | |
| 32 | ||
| 33 | #ifndef BR_PTHREADS | |
| 34 | /* Change 1 to 0 if you don't want pthread support */ | |
| 35 | #define BR_PTHREADS 1 | |
| 36 | #endif /* BR_PTHREADS */ | |
| 37 | ||
| 38 | #include <stdlib.h> | |
| 39 | #include <stdio.h> | |
| 40 | #include <limits.h> | |
| 41 | #include <string.h> | |
| 42 | #include "prefix.h" | |
| 43 | ||
| 44 | #ifdef __cplusplus | |
| 45 | extern "C" { | |
| 46 | #endif /* __cplusplus */ | |
| 47 | ||
| 48 | ||
| 49 | #undef NULL | |
| 50 | #define NULL ((void *) 0) | |
| 51 | ||
| 52 | #ifdef __GNUC__ | |
| 53 | #define br_return_val_if_fail(expr,val) if (!(expr)) {fprintf (stderr, "** BinReloc (%s): assertion %s failed\n", __PRETTY_FUNCTION__, #expr); return val;} | |
| 54 | #else | |
| 55 | #define br_return_val_if_fail(expr,val) if (!(expr)) return val | |
| 56 | #endif /* __GNUC__ */ | |
| 57 | ||
| 58 | ||
| 10257 | 59 | static br_locate_fallback_func fallback_func = NULL; |
| 60 | static void *fallback_data = NULL; | |
| 61 | ||
| 62 | ||
| 10245 | 63 | #ifdef ENABLE_BINRELOC |
| 64 | #include <sys/types.h> | |
| 65 | #include <sys/stat.h> | |
| 66 | #include <sys/param.h> | |
| 67 | #include <unistd.h> | |
| 68 | ||
| 69 | ||
| 70 | /** | |
| 71 | * br_locate: | |
| 72 | * symbol: A symbol that belongs to the app/library you want to locate. | |
| 73 | * Returns: A newly allocated string containing the full path of the | |
| 74 | * app/library that func belongs to, or NULL on error. This | |
| 75 | * string should be freed when not when no longer needed. | |
| 76 | * | |
| 77 | * Finds out to which application or library symbol belongs, then locate | |
| 78 | * the full path of that application or library. | |
| 79 | * Note that symbol cannot be a pointer to a function. That will not work. | |
| 80 | * | |
| 81 | * Example: | |
| 82 | * --> main.c | |
| 83 | * #include "prefix.h" | |
| 84 | * #include "libfoo.h" | |
| 85 | * | |
| 86 | * int main (int argc, char *argv[]) { | |
| 87 | * printf ("Full path of this app: %s\n", br_locate (&argc)); | |
| 88 | * libfoo_start (); | |
| 89 | * return 0; | |
| 90 | * } | |
| 91 | * | |
| 92 | * --> libfoo.c starts here | |
| 93 | * #include "prefix.h" | |
| 94 | * | |
| 95 | * void libfoo_start () { | |
| 96 | * --> "" is a symbol that belongs to libfoo (because it's called | |
| 97 | * --> from libfoo_start()); that's why this works. | |
| 98 | * printf ("libfoo is located in: %s\n", br_locate ("")); | |
| 99 | * } | |
| 100 | */ | |
| 101 | char * | |
| 102 | br_locate (void *symbol) | |
| 103 | { | |
| 104 | char line[5000]; | |
| 105 | FILE *f; | |
| 106 | char *path; | |
| 107 | ||
| 108 | br_return_val_if_fail (symbol != NULL, NULL); | |
| 109 | ||
| 110 | f = fopen ("/proc/self/maps", "r"); | |
| 10251 | 111 | if (!f) { |
| 112 | if (fallback_func) | |
| 113 | return fallback_func(symbol, fallback_data); | |
| 114 | else | |
| 115 | return NULL; | |
| 116 | } | |
| 10245 | 117 | |
| 118 | while (!feof (f)) | |
| 119 | { | |
| 120 | unsigned long start, end; | |
| 121 | ||
| 122 | if (!fgets (line, sizeof (line), f)) | |
| 123 | continue; | |
| 124 | if (!strstr (line, " r-xp ") || !strchr (line, '/')) | |
| 125 | continue; | |
| 126 | ||
| 127 | sscanf (line, "%lx-%lx ", &start, &end); | |
| 128 | if (symbol >= (void *) start && symbol < (void *) end) | |
| 129 | { | |
| 130 | char *tmp; | |
| 131 | size_t len; | |
| 132 | ||
| 133 | /* Extract the filename; it is always an absolute path */ | |
| 134 | path = strchr (line, '/'); | |
| 135 | ||
| 136 | /* Get rid of the newline */ | |
| 137 | tmp = strrchr (path, '\n'); | |
| 138 | if (tmp) *tmp = 0; | |
| 139 | ||
| 140 | /* Get rid of "(deleted)" */ | |
| 141 | len = strlen (path); | |
| 142 | if (len > 10 && strcmp (path + len - 10, " (deleted)") == 0) | |
| 143 | { | |
| 144 | tmp = path + len - 10; | |
| 145 | *tmp = 0; | |
| 146 | } | |
| 147 | ||
| 148 | fclose(f); | |
| 149 | return strdup (path); | |
| 150 | } | |
| 151 | } | |
| 152 | ||
| 153 | fclose (f); | |
| 154 | return NULL; | |
| 155 | } | |
| 156 | ||
| 157 | ||
| 158 | /** | |
| 159 | * br_locate_prefix: | |
| 160 | * symbol: A symbol that belongs to the app/library you want to locate. | |
| 161 | * Returns: A prefix. This string should be freed when no longer needed. | |
| 162 | * | |
| 163 | * Locates the full path of the app/library that symbol belongs to, and return | |
| 164 | * the prefix of that path, or NULL on error. | |
| 165 | * Note that symbol cannot be a pointer to a function. That will not work. | |
| 166 | * | |
| 167 | * Example: | |
| 168 | * --> This application is located in /usr/bin/foo | |
| 169 | * br_locate_prefix (&argc); --> returns: "/usr" | |
| 170 | */ | |
| 171 | char * | |
| 172 | br_locate_prefix (void *symbol) | |
| 173 | { | |
| 174 | char *path, *prefix; | |
| 175 | ||
| 176 | br_return_val_if_fail (symbol != NULL, NULL); | |
| 177 | ||
| 178 | path = br_locate (symbol); | |
| 179 | if (!path) return NULL; | |
| 180 | ||
| 181 | prefix = br_extract_prefix (path); | |
| 182 | free (path); | |
| 183 | return prefix; | |
| 184 | } | |
| 185 | ||
| 186 | ||
| 187 | /** | |
| 188 | * br_prepend_prefix: | |
| 189 | * symbol: A symbol that belongs to the app/library you want to locate. | |
| 190 | * path: The path that you want to prepend the prefix to. | |
| 191 | * Returns: The new path, or NULL on error. This string should be freed when no | |
| 192 | * longer needed. | |
| 193 | * | |
| 194 | * Gets the prefix of the app/library that symbol belongs to. Prepend that prefix to path. | |
| 195 | * Note that symbol cannot be a pointer to a function. That will not work. | |
| 196 | * | |
| 197 | * Example: | |
| 198 | * --> The application is /usr/bin/foo | |
| 199 | * br_prepend_prefix (&argc, "/share/foo/data.png"); --> Returns "/usr/share/foo/data.png" | |
| 200 | */ | |
| 201 | char * | |
| 202 | br_prepend_prefix (void *symbol, char *path) | |
| 203 | { | |
| 204 | char *tmp, *newpath; | |
| 205 | ||
| 206 | br_return_val_if_fail (symbol != NULL, NULL); | |
| 207 | br_return_val_if_fail (path != NULL, NULL); | |
| 208 | ||
| 209 | tmp = br_locate_prefix (symbol); | |
| 210 | if (!tmp) return NULL; | |
| 211 | ||
| 212 | if (strcmp (tmp, "/") == 0) | |
| 213 | newpath = strdup (path); | |
| 214 | else | |
| 215 | newpath = br_strcat (tmp, path); | |
| 216 | ||
| 217 | /* Get rid of compiler warning ("br_prepend_prefix never used") */ | |
| 218 | if (0) br_prepend_prefix (NULL, NULL); | |
| 219 | ||
| 220 | free (tmp); | |
| 221 | return newpath; | |
| 222 | } | |
| 223 | ||
| 224 | #endif /* ENABLE_BINRELOC */ | |
| 225 | ||
| 226 | ||
| 227 | /* Pthread stuff for thread safetiness */ | |
| 228 | #if BR_PTHREADS | |
| 229 | ||
| 230 | #include <pthread.h> | |
| 231 | ||
| 232 | static pthread_key_t br_thread_key; | |
| 233 | static pthread_once_t br_thread_key_once = PTHREAD_ONCE_INIT; | |
| 234 | ||
| 235 | ||
| 236 | static void | |
| 237 | br_thread_local_store_fini () | |
| 238 | { | |
| 239 | char *specific; | |
| 240 | ||
| 241 | specific = (char *) pthread_getspecific (br_thread_key); | |
| 242 | if (specific) | |
| 243 | { | |
| 244 | free (specific); | |
| 245 | pthread_setspecific (br_thread_key, NULL); | |
| 246 | } | |
| 247 | pthread_key_delete (br_thread_key); | |
| 248 | br_thread_key = 0; | |
| 249 | } | |
| 250 | ||
| 251 | ||
| 252 | static void | |
| 253 | br_str_free (void *str) | |
| 254 | { | |
| 255 | if (str) | |
| 256 | free (str); | |
| 257 | } | |
| 258 | ||
| 259 | ||
| 260 | static void | |
| 261 | br_thread_local_store_init () | |
| 262 | { | |
| 263 | if (pthread_key_create (&br_thread_key, br_str_free) == 0) | |
| 264 | atexit (br_thread_local_store_fini); | |
| 265 | } | |
| 266 | ||
| 267 | #else /* BR_PTHREADS */ | |
| 268 | ||
| 269 | static char *br_last_value = (char *) NULL; | |
| 270 | ||
| 271 | static void | |
| 272 | br_free_last_value () | |
| 273 | { | |
| 274 | if (br_last_value) | |
| 275 | free (br_last_value); | |
| 276 | } | |
| 277 | ||
| 278 | #endif /* BR_PTHREADS */ | |
| 279 | ||
| 280 | ||
| 281 | /** | |
| 282 | * br_thread_local_store: | |
| 283 | * str: A dynamically allocated string. | |
| 284 | * Returns: str. This return value must not be freed. | |
| 285 | * | |
| 286 | * Store str in a thread-local variable and return str. The next | |
| 287 | * you run this function, that variable is freed too. | |
| 288 | * This function is created so you don't have to worry about freeing | |
| 10262 | 289 | * strings. Just be careful about doing this sort of thing: |
| 290 | * | |
| 291 | * some_function( BR_DATADIR("/one.png"), BR_DATADIR("/two.png") ) | |
| 10245 | 292 | * |
| 10262 | 293 | * Examples: |
| 10245 | 294 | * char *foo; |
| 10262 | 295 | * foo = br_thread_local_store (strdup ("hello")); --> foo == "hello" |
| 296 | * foo = br_thread_local_store (strdup ("world")); --> foo == "world"; "hello" is now freed. | |
| 10245 | 297 | */ |
| 298 | const char * | |
| 299 | br_thread_local_store (char *str) | |
| 300 | { | |
| 301 | #if BR_PTHREADS | |
| 302 | char *specific; | |
| 303 | ||
| 304 | pthread_once (&br_thread_key_once, br_thread_local_store_init); | |
| 305 | ||
| 306 | specific = (char *) pthread_getspecific (br_thread_key); | |
| 307 | br_str_free (specific); | |
| 308 | pthread_setspecific (br_thread_key, str); | |
| 309 | ||
| 310 | #else /* BR_PTHREADS */ | |
| 311 | static int initialized = 0; | |
| 312 | ||
| 313 | if (!initialized) | |
| 314 | { | |
| 315 | atexit (br_free_last_value); | |
| 316 | initialized = 1; | |
| 317 | } | |
| 318 | ||
| 319 | if (br_last_value) | |
| 320 | free (br_last_value); | |
| 321 | br_last_value = str; | |
| 322 | #endif /* BR_PTHREADS */ | |
| 323 | ||
| 324 | return (const char *) str; | |
| 325 | } | |
| 326 | ||
| 327 | ||
| 328 | /** | |
| 329 | * br_strcat: | |
| 330 | * str1: A string. | |
| 331 | * str2: Another string. | |
| 332 | * Returns: A newly-allocated string. This string should be freed when no longer needed. | |
| 333 | * | |
| 334 | * Concatenate str1 and str2 to a newly allocated string. | |
| 335 | */ | |
| 336 | char * | |
| 337 | br_strcat (const char *str1, const char *str2) | |
| 338 | { | |
| 339 | char *result; | |
| 340 | size_t len1, len2; | |
| 341 | ||
| 342 | if (!str1) str1 = ""; | |
| 343 | if (!str2) str2 = ""; | |
| 344 | ||
| 345 | len1 = strlen (str1); | |
| 346 | len2 = strlen (str2); | |
| 347 | ||
| 348 | result = (char *) malloc (len1 + len2 + 1); | |
| 349 | memcpy (result, str1, len1); | |
| 350 | memcpy (result + len1, str2, len2); | |
| 351 | result[len1 + len2] = '\0'; | |
| 352 | ||
| 353 | return result; | |
| 354 | } | |
| 355 | ||
| 356 | ||
| 357 | /* Emulates glibc's strndup() */ | |
| 358 | static char * | |
| 359 | br_strndup (char *str, size_t size) | |
| 360 | { | |
| 361 | char *result = (char *) NULL; | |
| 362 | size_t len; | |
| 363 | ||
| 364 | br_return_val_if_fail (str != (char *) NULL, (char *) NULL); | |
| 365 | ||
| 366 | len = strlen (str); | |
| 367 | if (!len) return strdup (""); | |
| 368 | if (size > len) size = len; | |
| 369 | ||
| 370 | result = (char *) calloc (sizeof (char), len + 1); | |
| 371 | memcpy (result, str, size); | |
| 372 | return result; | |
| 373 | } | |
| 374 | ||
| 375 | ||
| 376 | /** | |
| 377 | * br_extract_dir: | |
| 378 | * path: A path. | |
| 379 | * Returns: A directory name. This string should be freed when no longer needed. | |
| 380 | * | |
| 381 | * Extracts the directory component of path. Similar to g_dirname() or the dirname | |
| 382 | * commandline application. | |
| 383 | * | |
| 384 | * Example: | |
| 385 | * br_extract_dir ("/usr/local/foobar"); --> Returns: "/usr/local" | |
| 386 | */ | |
| 387 | char * | |
| 388 | br_extract_dir (const char *path) | |
| 389 | { | |
| 390 | char *end, *result; | |
| 391 | ||
| 392 | br_return_val_if_fail (path != (char *) NULL, (char *) NULL); | |
| 393 | ||
| 394 | end = strrchr (path, '/'); | |
| 395 | if (!end) return strdup ("."); | |
| 396 | ||
| 397 | while (end > path && *end == '/') | |
| 398 | end--; | |
| 399 | result = br_strndup ((char *) path, end - path + 1); | |
| 400 | if (!*result) | |
| 401 | { | |
| 402 | free (result); | |
| 403 | return strdup ("/"); | |
| 404 | } else | |
| 405 | return result; | |
| 406 | } | |
| 407 | ||
| 408 | ||
| 409 | /** | |
| 410 | * br_extract_prefix: | |
| 411 | * path: The full path of an executable or library. | |
| 412 | * Returns: The prefix, or NULL on error. This string should be freed when no longer needed. | |
| 413 | * | |
| 414 | * Extracts the prefix from path. This function assumes that your executable | |
| 415 | * or library is installed in an LSB-compatible directory structure. | |
| 416 | * | |
| 417 | * Example: | |
| 418 | * br_extract_prefix ("/usr/bin/gnome-panel"); --> Returns "/usr" | |
| 419 | * br_extract_prefix ("/usr/local/lib/libfoo.so"); --> Returns "/usr/local" | |
| 420 | * br_extract_prefix ("/usr/local/libfoo.so"); --> Returns "/usr" | |
| 421 | */ | |
| 422 | char * | |
| 423 | br_extract_prefix (const char *path) | |
| 424 | { | |
| 425 | char *end, *tmp, *result; | |
| 426 | ||
| 427 | br_return_val_if_fail (path != (char *) NULL, (char *) NULL); | |
| 428 | ||
| 429 | if (!*path) return strdup ("/"); | |
| 430 | end = strrchr (path, '/'); | |
| 431 | if (!end) return strdup (path); | |
| 432 | ||
| 433 | tmp = br_strndup ((char *) path, end - path); | |
| 434 | if (!*tmp) | |
| 435 | { | |
| 436 | free (tmp); | |
| 437 | return strdup ("/"); | |
| 438 | } | |
| 439 | end = strrchr (tmp, '/'); | |
| 440 | if (!end) return tmp; | |
| 441 | ||
| 442 | result = br_strndup (tmp, end - tmp); | |
| 443 | free (tmp); | |
| 444 | ||
| 445 | if (!*result) | |
| 446 | { | |
| 447 | free (result); | |
| 448 | result = strdup ("/"); | |
| 449 | } | |
| 450 | ||
| 451 | return result; | |
| 452 | } | |
| 453 | ||
| 454 | ||
| 10257 | 455 | /** |
| 456 | * br_set_fallback_function: | |
| 457 | * func: A function to call to find the binary. | |
| 458 | * data: User data to pass to func. | |
| 459 | * | |
| 460 | * Sets a function to call to find the path to the binary, in | |
| 461 | * case "/proc/self/maps" can't be opened. The function set should | |
| 462 | * return a string that is safe to free with free(). | |
| 463 | */ | |
| 464 | void | |
| 465 | br_set_locate_fallback_func (br_locate_fallback_func func, void *data) | |
| 466 | { | |
| 467 | fallback_func = func; | |
| 468 | fallback_data = data; | |
| 469 | } | |
| 470 | ||
| 471 | ||
| 10245 | 472 | #ifdef __cplusplus |
| 473 | } | |
| 474 | #endif /* __cplusplus */ | |
| 475 | ||
| 476 | #endif /* _PREFIX_C */ |