Mercurial > pidgin
comparison src/prefix.c @ 10245:c143a3fac58d
[gaim-migrate @ 11385]
Binary relocation, step one.
I had a fairly long commit message, and cvs ate it and said
Read from remote host cvs.sourceforge.net: Connection reset by peer
I'm displeased.
This is just method one, method two to follow tomorrow after I add a
way to register a fallback and try to push it upstream. That way
I don't have to put method 2 inside prefix.c.
As for as core/ui split goes, they can either each have their own copy
after the divorce is final, or the UI can use the core's. It'll work
either way, since #1 finds location of the caller, and #2 doesn't work
on libraries anyway. That's one advantage I forgot to mention, btw,
that #1 will let a library find its own location.
So, I'm sure something isn't quite right and someone will want to fix
it. So they can fix it while i implement phase two. Which won't take
long at all, but the autopackage guy is in bed, and I should be too.
committer: Tailor Script <tailor@pidgin.im>
| author | Tim Ringenbach <marv@pidgin.im> |
|---|---|
| date | Tue, 23 Nov 2004 05:53:59 +0000 |
| parents | |
| children | 645eb9804040 |
comparison
equal
deleted
inserted
replaced
| 10244:13cb42ebb537 | 10245:c143a3fac58d |
|---|---|
| 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 | |
| 59 #ifdef ENABLE_BINRELOC | |
| 60 #include <sys/types.h> | |
| 61 #include <sys/stat.h> | |
| 62 #include <sys/param.h> | |
| 63 #include <unistd.h> | |
| 64 | |
| 65 | |
| 66 /** | |
| 67 * br_locate: | |
| 68 * symbol: A symbol that belongs to the app/library you want to locate. | |
| 69 * Returns: A newly allocated string containing the full path of the | |
| 70 * app/library that func belongs to, or NULL on error. This | |
| 71 * string should be freed when not when no longer needed. | |
| 72 * | |
| 73 * Finds out to which application or library symbol belongs, then locate | |
| 74 * the full path of that application or library. | |
| 75 * Note that symbol cannot be a pointer to a function. That will not work. | |
| 76 * | |
| 77 * Example: | |
| 78 * --> main.c | |
| 79 * #include "prefix.h" | |
| 80 * #include "libfoo.h" | |
| 81 * | |
| 82 * int main (int argc, char *argv[]) { | |
| 83 * printf ("Full path of this app: %s\n", br_locate (&argc)); | |
| 84 * libfoo_start (); | |
| 85 * return 0; | |
| 86 * } | |
| 87 * | |
| 88 * --> libfoo.c starts here | |
| 89 * #include "prefix.h" | |
| 90 * | |
| 91 * void libfoo_start () { | |
| 92 * --> "" is a symbol that belongs to libfoo (because it's called | |
| 93 * --> from libfoo_start()); that's why this works. | |
| 94 * printf ("libfoo is located in: %s\n", br_locate ("")); | |
| 95 * } | |
| 96 */ | |
| 97 char * | |
| 98 br_locate (void *symbol) | |
| 99 { | |
| 100 char line[5000]; | |
| 101 FILE *f; | |
| 102 char *path; | |
| 103 | |
| 104 br_return_val_if_fail (symbol != NULL, NULL); | |
| 105 | |
| 106 f = fopen ("/proc/self/maps", "r"); | |
| 107 if (!f) | |
| 108 return NULL; | |
| 109 | |
| 110 while (!feof (f)) | |
| 111 { | |
| 112 unsigned long start, end; | |
| 113 | |
| 114 if (!fgets (line, sizeof (line), f)) | |
| 115 continue; | |
| 116 if (!strstr (line, " r-xp ") || !strchr (line, '/')) | |
| 117 continue; | |
| 118 | |
| 119 sscanf (line, "%lx-%lx ", &start, &end); | |
| 120 if (symbol >= (void *) start && symbol < (void *) end) | |
| 121 { | |
| 122 char *tmp; | |
| 123 size_t len; | |
| 124 | |
| 125 /* Extract the filename; it is always an absolute path */ | |
| 126 path = strchr (line, '/'); | |
| 127 | |
| 128 /* Get rid of the newline */ | |
| 129 tmp = strrchr (path, '\n'); | |
| 130 if (tmp) *tmp = 0; | |
| 131 | |
| 132 /* Get rid of "(deleted)" */ | |
| 133 len = strlen (path); | |
| 134 if (len > 10 && strcmp (path + len - 10, " (deleted)") == 0) | |
| 135 { | |
| 136 tmp = path + len - 10; | |
| 137 *tmp = 0; | |
| 138 } | |
| 139 | |
| 140 fclose(f); | |
| 141 return strdup (path); | |
| 142 } | |
| 143 } | |
| 144 | |
| 145 fclose (f); | |
| 146 return NULL; | |
| 147 } | |
| 148 | |
| 149 | |
| 150 /** | |
| 151 * br_locate_prefix: | |
| 152 * symbol: A symbol that belongs to the app/library you want to locate. | |
| 153 * Returns: A prefix. This string should be freed when no longer needed. | |
| 154 * | |
| 155 * Locates the full path of the app/library that symbol belongs to, and return | |
| 156 * the prefix of that path, or NULL on error. | |
| 157 * Note that symbol cannot be a pointer to a function. That will not work. | |
| 158 * | |
| 159 * Example: | |
| 160 * --> This application is located in /usr/bin/foo | |
| 161 * br_locate_prefix (&argc); --> returns: "/usr" | |
| 162 */ | |
| 163 char * | |
| 164 br_locate_prefix (void *symbol) | |
| 165 { | |
| 166 char *path, *prefix; | |
| 167 | |
| 168 br_return_val_if_fail (symbol != NULL, NULL); | |
| 169 | |
| 170 path = br_locate (symbol); | |
| 171 if (!path) return NULL; | |
| 172 | |
| 173 prefix = br_extract_prefix (path); | |
| 174 free (path); | |
| 175 return prefix; | |
| 176 } | |
| 177 | |
| 178 | |
| 179 /** | |
| 180 * br_prepend_prefix: | |
| 181 * symbol: A symbol that belongs to the app/library you want to locate. | |
| 182 * path: The path that you want to prepend the prefix to. | |
| 183 * Returns: The new path, or NULL on error. This string should be freed when no | |
| 184 * longer needed. | |
| 185 * | |
| 186 * Gets the prefix of the app/library that symbol belongs to. Prepend that prefix to path. | |
| 187 * Note that symbol cannot be a pointer to a function. That will not work. | |
| 188 * | |
| 189 * Example: | |
| 190 * --> The application is /usr/bin/foo | |
| 191 * br_prepend_prefix (&argc, "/share/foo/data.png"); --> Returns "/usr/share/foo/data.png" | |
| 192 */ | |
| 193 char * | |
| 194 br_prepend_prefix (void *symbol, char *path) | |
| 195 { | |
| 196 char *tmp, *newpath; | |
| 197 | |
| 198 br_return_val_if_fail (symbol != NULL, NULL); | |
| 199 br_return_val_if_fail (path != NULL, NULL); | |
| 200 | |
| 201 tmp = br_locate_prefix (symbol); | |
| 202 if (!tmp) return NULL; | |
| 203 | |
| 204 if (strcmp (tmp, "/") == 0) | |
| 205 newpath = strdup (path); | |
| 206 else | |
| 207 newpath = br_strcat (tmp, path); | |
| 208 | |
| 209 /* Get rid of compiler warning ("br_prepend_prefix never used") */ | |
| 210 if (0) br_prepend_prefix (NULL, NULL); | |
| 211 | |
| 212 free (tmp); | |
| 213 return newpath; | |
| 214 } | |
| 215 | |
| 216 #endif /* ENABLE_BINRELOC */ | |
| 217 | |
| 218 | |
| 219 /* Pthread stuff for thread safetiness */ | |
| 220 #if BR_PTHREADS | |
| 221 | |
| 222 #include <pthread.h> | |
| 223 | |
| 224 static pthread_key_t br_thread_key; | |
| 225 static pthread_once_t br_thread_key_once = PTHREAD_ONCE_INIT; | |
| 226 | |
| 227 | |
| 228 static void | |
| 229 br_thread_local_store_fini () | |
| 230 { | |
| 231 char *specific; | |
| 232 | |
| 233 specific = (char *) pthread_getspecific (br_thread_key); | |
| 234 if (specific) | |
| 235 { | |
| 236 free (specific); | |
| 237 pthread_setspecific (br_thread_key, NULL); | |
| 238 } | |
| 239 pthread_key_delete (br_thread_key); | |
| 240 br_thread_key = 0; | |
| 241 } | |
| 242 | |
| 243 | |
| 244 static void | |
| 245 br_str_free (void *str) | |
| 246 { | |
| 247 if (str) | |
| 248 free (str); | |
| 249 } | |
| 250 | |
| 251 | |
| 252 static void | |
| 253 br_thread_local_store_init () | |
| 254 { | |
| 255 if (pthread_key_create (&br_thread_key, br_str_free) == 0) | |
| 256 atexit (br_thread_local_store_fini); | |
| 257 } | |
| 258 | |
| 259 #else /* BR_PTHREADS */ | |
| 260 | |
| 261 static char *br_last_value = (char *) NULL; | |
| 262 | |
| 263 static void | |
| 264 br_free_last_value () | |
| 265 { | |
| 266 if (br_last_value) | |
| 267 free (br_last_value); | |
| 268 } | |
| 269 | |
| 270 #endif /* BR_PTHREADS */ | |
| 271 | |
| 272 | |
| 273 /** | |
| 274 * br_thread_local_store: | |
| 275 * str: A dynamically allocated string. | |
| 276 * Returns: str. This return value must not be freed. | |
| 277 * | |
| 278 * Store str in a thread-local variable and return str. The next | |
| 279 * you run this function, that variable is freed too. | |
| 280 * This function is created so you don't have to worry about freeing | |
| 281 * strings. | |
| 282 * | |
| 283 * Example: | |
| 284 * char *foo; | |
| 285 * foo = thread_local_store (strdup ("hello")); --> foo == "hello" | |
| 286 * foo = thread_local_store (strdup ("world")); --> foo == "world"; "hello" is now freed. | |
| 287 */ | |
| 288 const char * | |
| 289 br_thread_local_store (char *str) | |
| 290 { | |
| 291 #if BR_PTHREADS | |
| 292 char *specific; | |
| 293 | |
| 294 pthread_once (&br_thread_key_once, br_thread_local_store_init); | |
| 295 | |
| 296 specific = (char *) pthread_getspecific (br_thread_key); | |
| 297 br_str_free (specific); | |
| 298 pthread_setspecific (br_thread_key, str); | |
| 299 | |
| 300 #else /* BR_PTHREADS */ | |
| 301 static int initialized = 0; | |
| 302 | |
| 303 if (!initialized) | |
| 304 { | |
| 305 atexit (br_free_last_value); | |
| 306 initialized = 1; | |
| 307 } | |
| 308 | |
| 309 if (br_last_value) | |
| 310 free (br_last_value); | |
| 311 br_last_value = str; | |
| 312 #endif /* BR_PTHREADS */ | |
| 313 | |
| 314 return (const char *) str; | |
| 315 } | |
| 316 | |
| 317 | |
| 318 /** | |
| 319 * br_strcat: | |
| 320 * str1: A string. | |
| 321 * str2: Another string. | |
| 322 * Returns: A newly-allocated string. This string should be freed when no longer needed. | |
| 323 * | |
| 324 * Concatenate str1 and str2 to a newly allocated string. | |
| 325 */ | |
| 326 char * | |
| 327 br_strcat (const char *str1, const char *str2) | |
| 328 { | |
| 329 char *result; | |
| 330 size_t len1, len2; | |
| 331 | |
| 332 if (!str1) str1 = ""; | |
| 333 if (!str2) str2 = ""; | |
| 334 | |
| 335 len1 = strlen (str1); | |
| 336 len2 = strlen (str2); | |
| 337 | |
| 338 result = (char *) malloc (len1 + len2 + 1); | |
| 339 memcpy (result, str1, len1); | |
| 340 memcpy (result + len1, str2, len2); | |
| 341 result[len1 + len2] = '\0'; | |
| 342 | |
| 343 return result; | |
| 344 } | |
| 345 | |
| 346 | |
| 347 /* Emulates glibc's strndup() */ | |
| 348 static char * | |
| 349 br_strndup (char *str, size_t size) | |
| 350 { | |
| 351 char *result = (char *) NULL; | |
| 352 size_t len; | |
| 353 | |
| 354 br_return_val_if_fail (str != (char *) NULL, (char *) NULL); | |
| 355 | |
| 356 len = strlen (str); | |
| 357 if (!len) return strdup (""); | |
| 358 if (size > len) size = len; | |
| 359 | |
| 360 result = (char *) calloc (sizeof (char), len + 1); | |
| 361 memcpy (result, str, size); | |
| 362 return result; | |
| 363 } | |
| 364 | |
| 365 | |
| 366 /** | |
| 367 * br_extract_dir: | |
| 368 * path: A path. | |
| 369 * Returns: A directory name. This string should be freed when no longer needed. | |
| 370 * | |
| 371 * Extracts the directory component of path. Similar to g_dirname() or the dirname | |
| 372 * commandline application. | |
| 373 * | |
| 374 * Example: | |
| 375 * br_extract_dir ("/usr/local/foobar"); --> Returns: "/usr/local" | |
| 376 */ | |
| 377 char * | |
| 378 br_extract_dir (const char *path) | |
| 379 { | |
| 380 char *end, *result; | |
| 381 | |
| 382 br_return_val_if_fail (path != (char *) NULL, (char *) NULL); | |
| 383 | |
| 384 end = strrchr (path, '/'); | |
| 385 if (!end) return strdup ("."); | |
| 386 | |
| 387 while (end > path && *end == '/') | |
| 388 end--; | |
| 389 result = br_strndup ((char *) path, end - path + 1); | |
| 390 if (!*result) | |
| 391 { | |
| 392 free (result); | |
| 393 return strdup ("/"); | |
| 394 } else | |
| 395 return result; | |
| 396 } | |
| 397 | |
| 398 | |
| 399 /** | |
| 400 * br_extract_prefix: | |
| 401 * path: The full path of an executable or library. | |
| 402 * Returns: The prefix, or NULL on error. This string should be freed when no longer needed. | |
| 403 * | |
| 404 * Extracts the prefix from path. This function assumes that your executable | |
| 405 * or library is installed in an LSB-compatible directory structure. | |
| 406 * | |
| 407 * Example: | |
| 408 * br_extract_prefix ("/usr/bin/gnome-panel"); --> Returns "/usr" | |
| 409 * br_extract_prefix ("/usr/local/lib/libfoo.so"); --> Returns "/usr/local" | |
| 410 * br_extract_prefix ("/usr/local/libfoo.so"); --> Returns "/usr" | |
| 411 */ | |
| 412 char * | |
| 413 br_extract_prefix (const char *path) | |
| 414 { | |
| 415 char *end, *tmp, *result; | |
| 416 | |
| 417 br_return_val_if_fail (path != (char *) NULL, (char *) NULL); | |
| 418 | |
| 419 if (!*path) return strdup ("/"); | |
| 420 end = strrchr (path, '/'); | |
| 421 if (!end) return strdup (path); | |
| 422 | |
| 423 tmp = br_strndup ((char *) path, end - path); | |
| 424 if (!*tmp) | |
| 425 { | |
| 426 free (tmp); | |
| 427 return strdup ("/"); | |
| 428 } | |
| 429 end = strrchr (tmp, '/'); | |
| 430 if (!end) return tmp; | |
| 431 | |
| 432 result = br_strndup (tmp, end - tmp); | |
| 433 free (tmp); | |
| 434 | |
| 435 if (!*result) | |
| 436 { | |
| 437 free (result); | |
| 438 result = strdup ("/"); | |
| 439 } | |
| 440 | |
| 441 return result; | |
| 442 } | |
| 443 | |
| 444 | |
| 445 #ifdef __cplusplus | |
| 446 } | |
| 447 #endif /* __cplusplus */ | |
| 448 | |
| 449 #endif /* _PREFIX_C */ |
