LTP GCOV extension - code coverage report
Current view: directory - trunk/src - binreloc.c
Test: lcov.info
Date: 2007-05-09 Instrumented lines: 147
Code covered: 13.6 % Executed lines: 20

       1                 : /*
       2                 :  * BinReloc - a library for creating relocatable executables
       3                 :  * Written by: Hongli Lai <h.lai@chello.nl>
       4                 :  * http://autopackage.org/
       5                 :  *
       6                 :  * This source code is public domain. You can relicense this code
       7                 :  * under whatever license you want.
       8                 :  *
       9                 :  * See http://autopackage.org/docs/binreloc/ for
      10                 :  * more information and how to use this.
      11                 :  */
      12                 : 
      13                 : #ifndef __BINRELOC_C__
      14                 : #define __BINRELOC_C__
      15                 : 
      16                 : # ifdef HAVE_CONFIG_H
      17                 : #  include <config.h>
      18                 : # endif
      19                 : 
      20                 : #ifdef ENABLE_BINRELOC
      21                 :         #include <sys/types.h>
      22                 :         #include <sys/stat.h>
      23                 :         #include <unistd.h>
      24                 : #endif /* ENABLE_BINRELOC */
      25                 : #include <stdio.h>
      26                 : #include <stdlib.h>
      27                 : #include <limits.h>
      28                 : #include <string.h>
      29                 : #include "binreloc.h"
      30                 : 
      31                 : #ifdef __cplusplus
      32                 : extern "C" {
      33                 : #endif /* __cplusplus */
      34                 : 
      35                 : 
      36                 : 
      37                 : /** @internal
      38                 :  * Find the canonical filename of the executable. Returns the filename
      39                 :  * (which must be freed) or NULL on error. If the parameter 'error' is
      40                 :  * not NULL, the error code will be stored there, if an error occured.
      41                 :  */
      42                 : static char *
      43                 : _br_find_exe (BrInitError *error)
      44               3 : {
      45                 : #ifndef ENABLE_BINRELOC
      46               3 :         if (error)
      47               0 :                 *error = BR_INIT_ERROR_DISABLED;
      48               3 :         return NULL;
      49                 : #else
      50                 :         char *path, *path2, *line, *result;
      51                 :         size_t buf_size;
      52                 :         ssize_t size;
      53                 :         struct stat stat_buf;
      54                 :         FILE *f;
      55                 : 
      56                 :         /* Read from /proc/self/exe (symlink) */
      57                 :         if (sizeof (path) > SSIZE_MAX)
      58                 :                 buf_size = SSIZE_MAX - 1;
      59                 :         else
      60                 :                 buf_size = PATH_MAX - 1;
      61                 :         path = (char *) malloc (buf_size);
      62                 :         if (path == NULL) {
      63                 :                 /* Cannot allocate memory. */
      64                 :                 if (error)
      65                 :                         *error = BR_INIT_ERROR_NOMEM;
      66                 :                 return NULL;
      67                 :         }
      68                 :         path2 = (char *) malloc (buf_size);
      69                 :         if (path2 == NULL) {
      70                 :                 /* Cannot allocate memory. */
      71                 :                 if (error)
      72                 :                         *error = BR_INIT_ERROR_NOMEM;
      73                 :                 free (path);
      74                 :                 return NULL;
      75                 :         }
      76                 : 
      77                 :         strncpy (path2, "/proc/self/exe", buf_size - 1);
      78                 : 
      79                 :         while (1) {
      80                 :                 int i;
      81                 : 
      82                 :                 size = readlink (path2, path, buf_size - 1);
      83                 :                 if (size == -1) {
      84                 :                         /* Error. */
      85                 :                         free (path2);
      86                 :                         break;
      87                 :                 }
      88                 : 
      89                 :                 /* readlink() success. */
      90                 :                 path[size] = '\0';
      91                 : 
      92                 :                 /* Check whether the symlink's target is also a symlink.
      93                 :                  * We want to get the final target. */
      94                 :                 i = stat (path, &stat_buf);
      95                 :                 if (i == -1) {
      96                 :                         /* Error. */
      97                 :                         free (path2);
      98                 :                         break;
      99                 :                 }
     100                 : 
     101                 :                 /* stat() success. */
     102                 :                 if (!S_ISLNK (stat_buf.st_mode)) {
     103                 :                         /* path is not a symlink. Done. */
     104                 :                         free (path2);
     105                 :                         return path;
     106                 :                 }
     107                 : 
     108                 :                 /* path is a symlink. Continue loop and resolve this. */
     109                 :                 strncpy (path, path2, buf_size - 1);
     110                 :         }
     111                 : 
     112                 : 
     113                 :         /* readlink() or stat() failed; this can happen when the program is
     114                 :          * running in Valgrind 2.2. Read from /proc/self/maps as fallback. */
     115                 : 
     116                 :         buf_size = PATH_MAX + 128;
     117                 :         line = (char *) realloc (path, buf_size);
     118                 :         if (line == NULL) {
     119                 :                 /* Cannot allocate memory. */
     120                 :                 free (path);
     121                 :                 if (error)
     122                 :                         *error = BR_INIT_ERROR_NOMEM;
     123                 :                 return NULL;
     124                 :         }
     125                 : 
     126                 :         f = fopen ("/proc/self/maps", "r");
     127                 :         if (f == NULL) {
     128                 :                 free (line);
     129                 :                 if (error)
     130                 :                         *error = BR_INIT_ERROR_OPEN_MAPS;
     131                 :                 return NULL;
     132                 :         }
     133                 : 
     134                 :         /* The first entry should be the executable name. */
     135                 :         result = fgets (line, (int) buf_size, f);
     136                 :         if (result == NULL) {
     137                 :                 fclose (f);
     138                 :                 free (line);
     139                 :                 if (error)
     140                 :                         *error = BR_INIT_ERROR_READ_MAPS;
     141                 :                 return NULL;
     142                 :         }
     143                 : 
     144                 :         /* Get rid of newline character. */
     145                 :         buf_size = strlen (line);
     146                 :         if (buf_size <= 0) {
     147                 :                 /* Huh? An empty string? */
     148                 :                 fclose (f);
     149                 :                 free (line);
     150                 :                 if (error)
     151                 :                         *error = BR_INIT_ERROR_INVALID_MAPS;
     152                 :                 return NULL;
     153                 :         }
     154                 :         if (line[buf_size - 1] == 10)
     155                 :                 line[buf_size - 1] = 0;
     156                 : 
     157                 :         /* Extract the filename; it is always an absolute path. */
     158                 :         path = strchr (line, '/');
     159                 : 
     160                 :         /* Sanity check. */
     161                 :         if (strstr (line, " r-xp ") == NULL || path == NULL) {
     162                 :                 fclose (f);
     163                 :                 free (line);
     164                 :                 if (error)
     165                 :                         *error = BR_INIT_ERROR_INVALID_MAPS;
     166                 :                 return NULL;
     167                 :         }
     168                 : 
     169                 :         path = strdup (path);
     170                 :         free (line);
     171                 :         fclose (f);
     172                 :         return path;
     173                 : #endif /* ENABLE_BINRELOC */
     174                 : }
     175                 : 
     176                 : 
     177                 : /** @internal
     178                 :  * Find the canonical filename of the executable which owns symbol.
     179                 :  * Returns a filename which must be freed, or NULL on error.
     180                 :  */
     181                 : static char *
     182                 : _br_find_exe_for_symbol (const void *symbol, BrInitError *error)
     183               0 : {
     184                 : #ifndef ENABLE_BINRELOC
     185                 :         (void)symbol;
     186               0 :         if (error)
     187               0 :                 *error = BR_INIT_ERROR_DISABLED;
     188               0 :         return (char *) NULL;
     189                 : #else
     190                 :         #define SIZE PATH_MAX + 100
     191                 :         FILE *f;
     192                 :         size_t address_string_len;
     193                 :         char *address_string, line[SIZE], *found;
     194                 : 
     195                 :         (void)error;
     196                 :         if (symbol == NULL)
     197                 :                 return (char *) NULL;
     198                 : 
     199                 :         f = fopen ("/proc/self/maps", "r");
     200                 :         if (f == NULL)
     201                 :                 return (char *) NULL;
     202                 : 
     203                 :         address_string_len = 4;
     204                 :         address_string = (char *) malloc (address_string_len);
     205                 :         found = (char *) NULL;
     206                 : 
     207                 :         while (!feof (f)) {
     208                 :                 char *start_addr, *end_addr, *end_addr_end, *file;
     209                 :                 void *start_addr_p, *end_addr_p;
     210                 :                 size_t len;
     211                 : 
     212                 :                 if (fgets (line, SIZE, f) == NULL)
     213                 :                         break;
     214                 : 
     215                 :                 /* Sanity check. */
     216                 :                 if (strstr (line, " r-xp ") == NULL || strchr (line, '/') == NULL)
     217                 :                         continue;
     218                 : 
     219                 :                 /* Parse line. */
     220                 :                 start_addr = line;
     221                 :                 end_addr = strchr (line, '-');
     222                 :                 file = strchr (line, '/');
     223                 : 
     224                 :                 /* More sanity check. */
     225                 :                 if (!(file > end_addr && end_addr != NULL && end_addr[0] == '-'))
     226                 :                         continue;
     227                 : 
     228                 :                 end_addr[0] = '\0';
     229                 :                 end_addr++;
     230                 :                 end_addr_end = strchr (end_addr, ' ');
     231                 :                 if (end_addr_end == NULL)
     232                 :                         continue;
     233                 : 
     234                 :                 end_addr_end[0] = '\0';
     235                 :                 len = strlen (file);
     236                 :                 if (len == 0)
     237                 :                         continue;
     238                 :                 if (file[len - 1] == '\n')
     239                 :                         file[len - 1] = '\0';
     240                 : 
     241                 :                 /* Get rid of "(deleted)" from the filename. */
     242                 :                 len = strlen (file);
     243                 :                 if (len > 10 && strcmp (file + len - 10, " (deleted)") == 0)
     244                 :                         file[len - 10] = '\0';
     245                 : 
     246                 :                 /* I don't know whether this can happen but better safe than sorry. */
     247                 :                 len = strlen (start_addr);
     248                 :                 if (len != strlen (end_addr))
     249                 :                         continue;
     250                 : 
     251                 : 
     252                 :                 /* Transform the addresses into a string in the form of 0xdeadbeef,
     253                 :                  * then transform that into a pointer. */
     254                 :                 if (address_string_len < len + 3) {
     255                 :                         address_string_len = len + 3;
     256                 :                         address_string = (char *) realloc (address_string, address_string_len);
     257                 :                 }
     258                 : 
     259                 :                 memcpy (address_string, "0x", 2);
     260                 :                 memcpy (address_string + 2, start_addr, len);
     261                 :                 address_string[2 + len] = '\0';
     262                 :                 sscanf (address_string, "%p", &start_addr_p);
     263                 : 
     264                 :                 memcpy (address_string, "0x", 2);
     265                 :                 memcpy (address_string + 2, end_addr, len);
     266                 :                 address_string[2 + len] = '\0';
     267                 :                 sscanf (address_string, "%p", &end_addr_p);
     268                 : 
     269                 : 
     270                 :                 if (symbol >= start_addr_p && symbol < end_addr_p) {
     271                 :                         found = file;
     272                 :                         break;
     273                 :                 }
     274                 :         }
     275                 : 
     276                 :         free (address_string);
     277                 :         fclose (f);
     278                 : 
     279                 :         if (found == NULL)
     280                 :                 return (char *) NULL;
     281                 :         else
     282                 :                 return strdup (found);
     283                 : #endif /* ENABLE_BINRELOC */
     284                 : }
     285                 : 
     286                 : 
     287                 : #ifndef BINRELOC_RUNNING_DOXYGEN
     288                 :         #undef NULL
     289                 :         #define NULL ((void *) 0) /* typecasted as char* for C++ type safeness */
     290                 : #endif
     291                 : 
     292                 : static char *exe = (char *) NULL;
     293                 : 
     294                 : 
     295                 : /** Initialize the BinReloc library (for applications).
     296                 :  *
     297                 :  * This function must be called before using any other BinReloc functions.
     298                 :  * It attempts to locate the application's canonical filename.
     299                 :  *
     300                 :  * @note If you want to use BinReloc for a library, then you should call
     301                 :  *       br_init_lib() instead.
     302                 :  *
     303                 :  * @param error  If BinReloc failed to initialize, then the error code will
     304                 :  *               be stored in this variable. Set to NULL if you want to
     305                 :  *               ignore this. See #BrInitError for a list of error codes.
     306                 :  *
     307                 :  * @returns 1 on success, 0 if BinReloc failed to initialize.
     308                 :  */
     309                 : int
     310                 : br_init (BrInitError *error)
     311               3 : {
     312               3 :         exe = _br_find_exe (error);
     313               3 :         return exe != NULL;
     314                 : }
     315                 : 
     316                 : 
     317                 : /** Initialize the BinReloc library (for libraries).
     318                 :  *
     319                 :  * This function must be called before using any other BinReloc functions.
     320                 :  * It attempts to locate the calling library's canonical filename.
     321                 :  *
     322                 :  * @note The BinReloc source code MUST be included in your library, or this
     323                 :  *       function won't work correctly.
     324                 :  *
     325                 :  * @param error  If BinReloc failed to initialize, then the error code will
     326                 :  *               be stored in this variable. Set to NULL if you want to
     327                 :  *               ignore this. See #BrInitError for a list of error codes.
     328                 :  *
     329                 :  * @returns 1 on success, 0 if a filename cannot be found.
     330                 :  */
     331                 : int
     332                 : br_init_lib (BrInitError *error)
     333               0 : {
     334               0 :         exe = _br_find_exe_for_symbol ((const void *) "", error);
     335               0 :         return exe != NULL;
     336                 : }
     337                 : 
     338                 : 
     339                 : /** Find the canonical filename of the current application.
     340                 :  *
     341                 :  * @param default_exe  A default filename which will be used as fallback.
     342                 :  * @returns A string containing the application's canonical filename,
     343                 :  *          which must be freed when no longer necessary. If BinReloc is
     344                 :  *          not initialized, or if br_init() failed, then a copy of
     345                 :  *          default_exe will be returned. If default_exe is NULL, then
     346                 :  *          NULL will be returned.
     347                 :  */
     348                 : char *
     349                 : br_find_exe (const char *default_exe)
     350               0 : {
     351               0 :         if (exe == (char *) NULL) {
     352                 :                 /* BinReloc is not initialized. */
     353               0 :                 if (default_exe != (const char *) NULL)
     354               0 :                         return strdup (default_exe);
     355                 :                 else
     356               0 :                         return (char *) NULL;
     357                 :         }
     358               0 :         return strdup (exe);
     359                 : }
     360                 : 
     361                 : 
     362                 : /** Locate the directory in which the current application is installed.
     363                 :  *
     364                 :  * The prefix is generated by the following pseudo-code evaluation:
     365                 :  * \code
     366                 :  * dirname(exename)
     367                 :  * \endcode
     368                 :  *
     369                 :  * @param default_dir  A default directory which will used as fallback.
     370                 :  * @return A string containing the directory, which must be freed when no
     371                 :  *         longer necessary. If BinReloc is not initialized, or if the
     372                 :  *         initialization function failed, then a copy of default_dir
     373                 :  *         will be returned. If default_dir is NULL, then NULL will be
     374                 :  *         returned.
     375                 :  */
     376                 : char *
     377                 : br_find_exe_dir (const char *default_dir)
     378               0 : {
     379               0 :         if (exe == NULL) {
     380                 :                 /* BinReloc not initialized. */
     381               0 :                 if (default_dir != NULL)
     382               0 :                         return strdup (default_dir);
     383                 :                 else
     384               0 :                         return NULL;
     385                 :         }
     386                 : 
     387               0 :         return br_dirname (exe);
     388                 : }
     389                 : 
     390                 : 
     391                 : /** Locate the prefix in which the current application is installed.
     392                 :  *
     393                 :  * The prefix is generated by the following pseudo-code evaluation:
     394                 :  * \code
     395                 :  * dirname(dirname(exename))
     396                 :  * \endcode
     397                 :  *
     398                 :  * @param default_prefix  A default prefix which will used as fallback.
     399                 :  * @return A string containing the prefix, which must be freed when no
     400                 :  *         longer necessary. If BinReloc is not initialized, or if
     401                 :  *         the initialization function failed, then a copy of default_prefix
     402                 :  *         will be returned. If default_prefix is NULL, then NULL will be returned.
     403                 :  */
     404                 : char *
     405                 : br_find_prefix (const char *default_prefix)
     406               3 : {
     407                 :         char *dir1, *dir2;
     408                 : 
     409               3 :         if (exe == (char *) NULL) {
     410                 :                 /* BinReloc not initialized. */
     411               3 :                 if (default_prefix != (const char *) NULL)
     412               0 :                         return strdup (default_prefix);
     413                 :                 else
     414               3 :                         return (char *) NULL;
     415                 :         }
     416                 : 
     417               0 :         dir1 = br_dirname (exe);
     418               0 :         dir2 = br_dirname (dir1);
     419               0 :         free (dir1);
     420               0 :         return dir2;
     421                 : }
     422                 : 
     423                 : 
     424                 : /** Locate the application's binary folder.
     425                 :  *
     426                 :  * The path is generated by the following pseudo-code evaluation:
     427                 :  * \code
     428                 :  * prefix + "/bin"
     429                 :  * \endcode
     430                 :  *
     431                 :  * @param default_bin_dir  A default path which will used as fallback.
     432                 :  * @return A string containing the bin folder's path, which must be freed when
     433                 :  *         no longer necessary. If BinReloc is not initialized, or if
     434                 :  *         the initialization function failed, then a copy of default_bin_dir will
     435                 :  *         be returned. If default_bin_dir is NULL, then NULL will be returned.
     436                 :  */
     437                 : char *
     438                 : br_find_bin_dir (const char *default_bin_dir)
     439               0 : {
     440                 :         char *prefix, *dir;
     441                 : 
     442               0 :         prefix = br_find_prefix ((const char *) NULL);
     443               0 :         if (prefix == (char *) NULL) {
     444                 :                 /* BinReloc not initialized. */
     445               0 :                 if (default_bin_dir != (const char *) NULL)
     446               0 :                         return strdup (default_bin_dir);
     447                 :                 else
     448               0 :                         return (char *) NULL;
     449                 :         }
     450                 : 
     451               0 :         dir = br_build_path (prefix, "bin");
     452               0 :         free (prefix);
     453               0 :         return dir;
     454                 : }
     455                 : 
     456                 : 
     457                 : /** Locate the application's superuser binary folder.
     458                 :  *
     459                 :  * The path is generated by the following pseudo-code evaluation:
     460                 :  * \code
     461                 :  * prefix + "/sbin"
     462                 :  * \endcode
     463                 :  *
     464                 :  * @param default_sbin_dir  A default path which will used as fallback.
     465                 :  * @return A string containing the sbin folder's path, which must be freed when
     466                 :  *         no longer necessary. If BinReloc is not initialized, or if the
     467                 :  *         initialization function failed, then a copy of default_sbin_dir will
     468                 :  *         be returned. If default_bin_dir is NULL, then NULL will be returned.
     469                 :  */
     470                 : char *
     471                 : br_find_sbin_dir (const char *default_sbin_dir)
     472               0 : {
     473                 :         char *prefix, *dir;
     474                 : 
     475               0 :         prefix = br_find_prefix ((const char *) NULL);
     476               0 :         if (prefix == (char *) NULL) {
     477                 :                 /* BinReloc not initialized. */
     478               0 :                 if (default_sbin_dir != (const char *) NULL)
     479               0 :                         return strdup (default_sbin_dir);
     480                 :                 else
     481               0 :                         return (char *) NULL;
     482                 :         }
     483                 : 
     484               0 :         dir = br_build_path (prefix, "sbin");
     485               0 :         free (prefix);
     486               0 :         return dir;
     487                 : }
     488                 : 
     489                 : 
     490                 : /** Locate the application's data folder.
     491                 :  *
     492                 :  * The path is generated by the following pseudo-code evaluation:
     493                 :  * \code
     494                 :  * prefix + "/share"
     495                 :  * \endcode
     496                 :  *
     497                 :  * @param default_data_dir  A default path which will used as fallback.
     498                 :  * @return A string containing the data folder's path, which must be freed when
     499                 :  *         no longer necessary. If BinReloc is not initialized, or if the
     500                 :  *         initialization function failed, then a copy of default_data_dir
     501                 :  *         will be returned. If default_data_dir is NULL, then NULL will be
     502                 :  *         returned.
     503                 :  */
     504                 : char *
     505                 : br_find_data_dir (const char *default_data_dir)
     506               3 : {
     507                 :         char *prefix, *dir;
     508                 : 
     509               3 :         prefix = br_find_prefix ((const char *) NULL);
     510               3 :         if (prefix == (char *) NULL) {
     511                 :                 /* BinReloc not initialized. */
     512               3 :                 if (default_data_dir != (const char *) NULL)
     513               0 :                         return strdup (default_data_dir);
     514                 :                 else
     515               3 :                         return (char *) NULL;
     516                 :         }
     517                 : 
     518               0 :         dir = br_build_path (prefix, "share");
     519               0 :         free (prefix);
     520               0 :         return dir;
     521                 : }
     522                 : 
     523                 : 
     524                 : /** Locate the application's localization folder.
     525                 :  *
     526                 :  * The path is generated by the following pseudo-code evaluation:
     527                 :  * \code
     528                 :  * prefix + "/share/locale"
     529                 :  * \endcode
     530                 :  *
     531                 :  * @param default_locale_dir  A default path which will used as fallback.
     532                 :  * @return A string containing the localization folder's path, which must be freed when
     533                 :  *         no longer necessary. If BinReloc is not initialized, or if the
     534                 :  *         initialization function failed, then a copy of default_locale_dir will be returned.
     535                 :  *         If default_locale_dir is NULL, then NULL will be returned.
     536                 :  */
     537                 : char *
     538                 : br_find_locale_dir (const char *default_locale_dir)
     539               3 : {
     540                 :         char *data_dir, *dir;
     541                 : 
     542               3 :         data_dir = br_find_data_dir ((const char *) NULL);
     543               3 :         if (data_dir == (char *) NULL) {
     544                 :                 /* BinReloc not initialized. */
     545               3 :                 if (default_locale_dir != (const char *) NULL)
     546               3 :                         return strdup (default_locale_dir);
     547                 :                 else
     548               0 :                         return (char *) NULL;
     549                 :         }
     550                 : 
     551               0 :         dir = br_build_path (data_dir, "locale");
     552               0 :         free (data_dir);
     553               0 :         return dir;
     554                 : }
     555                 : 
     556                 : 
     557                 : /** Locate the application's library folder.
     558                 :  *
     559                 :  * The path is generated by the following pseudo-code evaluation:
     560                 :  * \code
     561                 :  * prefix + "/lib"
     562                 :  * \endcode
     563                 :  *
     564                 :  * @param default_lib_dir  A default path which will used as fallback.
     565                 :  * @return A string containing the library folder's path, which must be freed when
     566                 :  *         no longer necessary. If BinReloc is not initialized, or if the initialization
     567                 :  *         function failed, then a copy of default_lib_dir will be returned.
     568                 :  *         If default_lib_dir is NULL, then NULL will be returned.
     569                 :  */
     570                 : char *
     571                 : br_find_lib_dir (const char *default_lib_dir)
     572               0 : {
     573                 :         char *prefix, *dir;
     574                 : 
     575               0 :         prefix = br_find_prefix ((const char *) NULL);
     576               0 :         if (prefix == (char *) NULL) {
     577                 :                 /* BinReloc not initialized. */
     578               0 :                 if (default_lib_dir != (const char *) NULL)
     579               0 :                         return strdup (default_lib_dir);
     580                 :                 else
     581               0 :                         return (char *) NULL;
     582                 :         }
     583                 : 
     584               0 :         dir = br_build_path (prefix, "lib");
     585               0 :         free (prefix);
     586               0 :         return dir;
     587                 : }
     588                 : 
     589                 : 
     590                 : /** Locate the application's libexec folder.
     591                 :  *
     592                 :  * The path is generated by the following pseudo-code evaluation:
     593                 :  * \code
     594                 :  * prefix + "/libexec"
     595                 :  * \endcode
     596                 :  *
     597                 :  * @param default_libexec_dir  A default path which will used as fallback.
     598                 :  * @return A string containing the libexec folder's path, which must be freed when
     599                 :  *         no longer necessary. If BinReloc is not initialized, or if the initialization
     600                 :  *         function failed, then a copy of default_libexec_dir will be returned.
     601                 :  *         If default_libexec_dir is NULL, then NULL will be returned.
     602                 :  */
     603                 : char *
     604                 : br_find_libexec_dir (const char *default_libexec_dir)
     605               0 : {
     606                 :         char *prefix, *dir;
     607                 : 
     608               0 :         prefix = br_find_prefix ((const char *) NULL);
     609               0 :         if (prefix == (char *) NULL) {
     610                 :                 /* BinReloc not initialized. */
     611               0 :                 if (default_libexec_dir != (const char *) NULL)
     612               0 :                         return strdup (default_libexec_dir);
     613                 :                 else
     614               0 :                         return (char *) NULL;
     615                 :         }
     616                 : 
     617               0 :         dir = br_build_path (prefix, "libexec");
     618               0 :         free (prefix);
     619               0 :         return dir;
     620                 : }
     621                 : 
     622                 : 
     623                 : /** Locate the application's configuration files folder.
     624                 :  *
     625                 :  * The path is generated by the following pseudo-code evaluation:
     626                 :  * \code
     627                 :  * prefix + "/etc"
     628                 :  * \endcode
     629                 :  *
     630                 :  * @param default_etc_dir  A default path which will used as fallback.
     631                 :  * @return A string containing the etc folder's path, which must be freed when
     632                 :  *         no longer necessary. If BinReloc is not initialized, or if the initialization
     633                 :  *         function failed, then a copy of default_etc_dir will be returned.
     634                 :  *         If default_etc_dir is NULL, then NULL will be returned.
     635                 :  */
     636                 : char *
     637                 : br_find_etc_dir (const char *default_etc_dir)
     638               0 : {
     639                 :         char *prefix, *dir;
     640                 : 
     641               0 :         prefix = br_find_prefix ((const char *) NULL);
     642               0 :         if (prefix == (char *) NULL) {
     643                 :                 /* BinReloc not initialized. */
     644               0 :                 if (default_etc_dir != (const char *) NULL)
     645               0 :                         return strdup (default_etc_dir);
     646                 :                 else
     647               0 :                         return (char *) NULL;
     648                 :         }
     649                 : 
     650               0 :         dir = br_build_path (prefix, "etc");
     651               0 :         free (prefix);
     652               0 :         return dir;
     653                 : }
     654                 : 
     655                 : 
     656                 : /***********************
     657                 :  * Utility functions
     658                 :  ***********************/
     659                 : 
     660                 : /** Concatenate str1 and str2 to a newly allocated string.
     661                 :  *
     662                 :  * @param str1 A string.
     663                 :  * @param str2 Another string.
     664                 :  * @returns A newly-allocated string. This string should be freed when no longer needed.
     665                 :  */
     666                 : char *
     667                 : br_strcat (const char *str1, const char *str2)
     668               0 : {
     669                 :         char *result;
     670                 :         size_t len1, len2;
     671                 : 
     672               0 :         if (str1 == NULL)
     673               0 :                 str1 = "";
     674               0 :         if (str2 == NULL)
     675               0 :                 str2 = "";
     676                 : 
     677               0 :         len1 = strlen (str1);
     678               0 :         len2 = strlen (str2);
     679                 : 
     680               0 :         result = (char *) malloc (len1 + len2 + 1);
     681               0 :         memcpy (result, str1, len1);
     682               0 :         memcpy (result + len1, str2, len2);
     683               0 :         result[len1 + len2] = '\0';
     684                 : 
     685               0 :         return result;
     686                 : }
     687                 : 
     688                 : 
     689                 : char *
     690                 : br_build_path (const char *dir, const char *file)
     691               0 : {
     692                 :         char *dir2, *result;
     693                 :         size_t len;
     694               0 :         int must_free = 0;
     695                 : 
     696               0 :         len = strlen (dir);
     697               0 :         if (len > 0 && dir[len - 1] != '/') {
     698               0 :                 dir2 = br_strcat (dir, "/");
     699               0 :                 must_free = 1;
     700                 :         } else
     701               0 :                 dir2 = (char *) dir;
     702                 : 
     703               0 :         result = br_strcat (dir2, file);
     704               0 :         if (must_free)
     705               0 :                 free (dir2);
     706               0 :         return result;
     707                 : }
     708                 : 
     709                 : 
     710                 : /* Emulates glibc's strndup() */
     711                 : static char *
     712                 : br_strndup (const char *str, size_t size)
     713               0 : {
     714               0 :         char *result = (char *) NULL;
     715                 :         size_t len;
     716                 : 
     717               0 :         if (str == (const char *) NULL)
     718               0 :                 return (char *) NULL;
     719                 : 
     720               0 :         len = strlen (str);
     721               0 :         if (len == 0)
     722               0 :                 return strdup ("");
     723               0 :         if (size > len)
     724               0 :                 size = len;
     725                 : 
     726               0 :         result = (char *) malloc (len + 1);
     727               0 :         memcpy (result, str, size);
     728               0 :         result[size] = '\0';
     729               0 :         return result;
     730                 : }
     731                 : 
     732                 : 
     733                 : /** Extracts the directory component of a path.
     734                 :  *
     735                 :  * Similar to g_dirname() or the dirname commandline application.
     736                 :  *
     737                 :  * Example:
     738                 :  * \code
     739                 :  * br_dirname ("/usr/local/foobar");  --> Returns: "/usr/local"
     740                 :  * \endcode
     741                 :  *
     742                 :  * @param path  A path.
     743                 :  * @returns     A directory name. This string should be freed when no longer needed.
     744                 :  */
     745                 : char *
     746                 : br_dirname (const char *path)
     747               0 : {
     748                 :         char *end, *result;
     749                 : 
     750               0 :         if (path == (const char *) NULL)
     751               0 :                 return (char *) NULL;
     752                 : 
     753               0 :         end = strrchr (path, '/');
     754               0 :         if (end == (const char *) NULL)
     755               0 :                 return strdup (".");
     756                 : 
     757               0 :         while (end > path && *end == '/')
     758               0 :                 end--;
     759               0 :         result = br_strndup (path, end - path + 1);
     760               0 :         if (result[0] == 0) {
     761               0 :                 free (result);
     762               0 :                 return strdup ("/");
     763                 :         } else
     764               0 :                 return result;
     765                 : }
     766                 : 
     767                 : 
     768                 : #ifdef __cplusplus
     769                 : }
     770                 : #endif /* __cplusplus */
     771                 : 
     772                 : #endif /* __BINRELOC_C__ */

Generated by: LTP GCOV extension version 1.5