binreloc.c

Go to the documentation of this file.
00001 // $Id: binreloc.c 757 2006-04-01 16:04:45Z alex $
00002 // The following line makes normalize.pl skip type fixing
00003 /* SKIPFIXTYPES: START */
00004 // $Id: appstate.cpp 836 2006-04-18 16:06:15Z gerry $
00005 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00006 ================================XARAHEADERSTART===========================
00007  
00008                Xara LX, a vector drawing and manipulation program.
00009                     Copyright (C) 1993-2006 Xara Group Ltd.
00010        Copyright on certain contributions may be held in joint with their
00011               respective authors. See AUTHORS file for details.
00012 
00013 LICENSE TO USE AND MODIFY SOFTWARE
00014 ----------------------------------
00015 
00016 This file is part of Xara LX.
00017 
00018 Xara LX is free software; you can redistribute it and/or modify it
00019 under the terms of the GNU General Public License version 2 as published
00020 by the Free Software Foundation.
00021 
00022 Xara LX and its component source files are distributed in the hope
00023 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00024 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00025 See the GNU General Public License for more details.
00026 
00027 You should have received a copy of the GNU General Public License along
00028 with Xara LX (see the file GPL in the root directory of the
00029 distribution); if not, write to the Free Software Foundation, Inc., 51
00030 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00031 
00032 
00033 ADDITIONAL RIGHTS
00034 -----------------
00035 
00036 Conditional upon your continuing compliance with the GNU General Public
00037 License described above, Xara Group Ltd grants to you certain additional
00038 rights. 
00039 
00040 The additional rights are to use, modify, and distribute the software
00041 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00042 library and any other such library that any version of Xara LX relased
00043 by Xara Group Ltd requires in order to compile and execute, including
00044 the static linking of that library to XaraLX. In the case of the
00045 "CDraw" library, you may satisfy obligation under the GNU General Public
00046 License to provide source code by providing a binary copy of the library
00047 concerned and a copy of the license accompanying it.
00048 
00049 Nothing in this section restricts any of the rights you have under
00050 the GNU General Public License.
00051 
00052 
00053 SCOPE OF LICENSE
00054 ----------------
00055 
00056 This license applies to this program (XaraLX) and its constituent source
00057 files only, and does not necessarily apply to other Xara products which may
00058 in part share the same code base, and are subject to their own licensing
00059 terms.
00060 
00061 This license does not apply to files in the wxXtra directory, which
00062 are built into a separate library, and are subject to the wxWindows
00063 license contained within that directory in the file "WXXTRA-LICENSE".
00064 
00065 This license does not apply to the binary libraries (if any) within
00066 the "libs" directory, which are subject to a separate license contained
00067 within that directory in the file "LIBS-LICENSE".
00068 
00069 
00070 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00071 ----------------------------------------------
00072 
00073 Subject to the terms of the GNU Public License (see above), you are
00074 free to do whatever you like with your modifications. However, you may
00075 (at your option) wish contribute them to Xara's source tree. You can
00076 find details of how to do this at:
00077   http://www.xaraxtreme.org/developers/
00078 
00079 Prior to contributing your modifications, you will need to complete our
00080 contributor agreement. This can be found at:
00081   http://www.xaraxtreme.org/developers/contribute/
00082 
00083 Please note that Xara will not accept modifications which modify any of
00084 the text between the start and end of this header (marked
00085 XARAHEADERSTART and XARAHEADEREND).
00086 
00087 
00088 MARKS
00089 -----
00090 
00091 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00092 designs are registered or unregistered trademarks, design-marks, and/or
00093 service marks of Xara Group Ltd. All rights in these marks are reserved.
00094 
00095 
00096       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00097                         http://www.xara.com/
00098 
00099 =================================XARAHEADEREND============================
00100 */
00101 /*
00102  * BinReloc - a library for creating relocatable executables
00103  * Written by: Hongli Lai <h.lai@chello.nl>
00104  * http://autopackage.org/
00105  *
00106  * This source code is public domain. You can relicense this code
00107  * under whatever license you want.
00108  *
00109  * See http://autopackage.org/docs/binreloc/ for
00110  * more information and how to use this.
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 /* ENABLE_BINRELOC */
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 /* __cplusplus */
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     /* Read from /proc/self/exe (symlink) */
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         /* Cannot allocate memory. */
00160         if (error)
00161             *error = BR_INIT_ERROR_NOMEM;
00162         return NULL;
00163     }
00164     path2 = (char *) malloc (buf_size);
00165     if (path2 == NULL) {
00166         /* Cannot allocate memory. */
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             /* Error. */
00181             free (path2);
00182             break;
00183         }
00184 
00185         /* readlink() success. */
00186         path[size] = '\0';
00187 
00188         /* Check whether the symlink's target is also a symlink.
00189          * We want to get the final target. */
00190         i = stat (path, &stat_buf);
00191         if (i == -1) {
00192             /* Error. */
00193             free (path2);
00194             break;
00195         }
00196 
00197         /* stat() success. */
00198         if (!S_ISLNK (stat_buf.st_mode)) {
00199             /* path is not a symlink. Done. */
00200             free (path2);
00201             return path;
00202         }
00203 
00204         /* path is a symlink. Continue loop and resolve this. */
00205         strncpy (path, path2, buf_size - 1);
00206     }
00207 
00208 
00209     /* readlink() or stat() failed; this can happen when the program is
00210      * running in Valgrind 2.2. Read from /proc/self/maps as fallback. */
00211 
00212     buf_size = PATH_MAX + 128;
00213     line = (char *) realloc (path, buf_size);
00214     if (line == NULL) {
00215         /* Cannot allocate memory. */
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     /* The first entry should be the executable name. */
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     /* Get rid of newline character. */
00241     buf_size = strlen (line);
00242     if (buf_size <= 0) {
00243         /* Huh? An empty string? */
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     /* Extract the filename; it is always an absolute path. */
00254     path = strchr (line, '/');
00255 
00256     /* Sanity check. */
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 /* ENABLE_BINRELOC */
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         /* Sanity check. */
00310         if (strstr (line, " r-xp ") == NULL || strchr (line, '/') == NULL)
00311             continue;
00312 
00313         /* Parse line. */
00314         start_addr = line;
00315         end_addr = strchr (line, '-');
00316         file = strchr (line, '/');
00317 
00318         /* More sanity check. */
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         /* Get rid of "(deleted)" from the filename. */
00336         len = strlen (file);
00337         if (len > 10 && strcmp (file + len - 10, " (deleted)") == 0)
00338             file[len - 10] = '\0';
00339 
00340         /* I don't know whether this can happen but better safe than sorry. */
00341         len = strlen (start_addr);
00342         if (len != strlen (end_addr))
00343             continue;
00344 
00345 
00346         /* Transform the addresses into a string in the form of 0xdeadbeef,
00347          * then transform that into a pointer. */
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 /* ENABLE_BINRELOC */
00378 }
00379 
00380 
00381 #ifndef BINRELOC_RUNNING_DOXYGEN
00382     #undef NULL
00383     #define NULL ((void *) 0) /* typecasted as char* for C++ type safeness */
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         /* BinReloc is not initialized. */
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         /* BinReloc not initialized. */
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         /* BinReloc not initialized. */
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         /* BinReloc not initialized. */
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         /* BinReloc not initialized. */
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         /* BinReloc not initialized. */
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         /* BinReloc not initialized. */
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         /* BinReloc not initialized. */
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         /* BinReloc not initialized. */
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         /* BinReloc not initialized. */
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  * Utility functions
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 /* Emulates glibc's strndup() */
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 /* __cplusplus */
00865 
00866 #endif /* __BINRELOC_C__ */

Generated on Sat Nov 10 03:48:06 2007 for Camelot by  doxygen 1.4.4