Annotation of embedaddon/libiconv/srclib/progreloc.c, revision 1.1.1.1

1.1       misho       1: /* Provide relocatable programs.
                      2:    Copyright (C) 2003-2009 Free Software Foundation, Inc.
                      3:    Written by Bruno Haible <bruno@clisp.org>, 2003.
                      4: 
                      5:    This program is free software: you can redistribute it and/or modify
                      6:    it under the terms of the GNU General Public License as published by
                      7:    the Free Software Foundation; either version 3 of the License, or
                      8:    (at your option) any later version.
                      9: 
                     10:    This program is distributed in the hope that it will be useful,
                     11:    but WITHOUT ANY WARRANTY; without even the implied warranty of
                     12:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     13:    GNU General Public License for more details.
                     14: 
                     15:    You should have received a copy of the GNU General Public License
                     16:    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
                     17: 
                     18: 
                     19: #include <config.h>
                     20: 
                     21: /* Specification.  */
                     22: #include "progname.h"
                     23: 
                     24: #include <stdbool.h>
                     25: #include <stdio.h>
                     26: #include <stdlib.h>
                     27: #include <string.h>
                     28: #include <fcntl.h>
                     29: #include <unistd.h>
                     30: #include <sys/stat.h>
                     31: 
                     32: /* Get declaration of _NSGetExecutablePath on MacOS X 10.2 or newer.  */
                     33: #if HAVE_MACH_O_DYLD_H
                     34: # include <mach-o/dyld.h>
                     35: #endif
                     36: 
                     37: #if defined _WIN32 || defined __WIN32__
                     38: # define WIN32_NATIVE
                     39: #endif
                     40: 
                     41: #if defined WIN32_NATIVE || defined __CYGWIN__
                     42: # define WIN32_LEAN_AND_MEAN
                     43: # include <windows.h>
                     44: #endif
                     45: 
                     46: #include "canonicalize.h"
                     47: #include "relocatable.h"
                     48: 
                     49: #ifdef NO_XMALLOC
                     50: # include "areadlink.h"
                     51: # define xreadlink areadlink
                     52: #else
                     53: # include "xreadlink.h"
                     54: #endif
                     55: 
                     56: #ifdef NO_XMALLOC
                     57: # define xmalloc malloc
                     58: # define xstrdup strdup
                     59: #else
                     60: # include "xalloc.h"
                     61: #endif
                     62: 
                     63: /* Pathname support.
                     64:    ISSLASH(C)           tests whether C is a directory separator character.
                     65:    IS_PATH_WITH_DIR(P)  tests whether P contains a directory specification.
                     66:  */
                     67: #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
                     68:   /* Win32, Cygwin, OS/2, DOS */
                     69: # define ISSLASH(C) ((C) == '/' || (C) == '\\')
                     70: # define HAS_DEVICE(P) \
                     71:     ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
                     72:      && (P)[1] == ':')
                     73: # define IS_PATH_WITH_DIR(P) \
                     74:     (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
                     75: # define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
                     76: #else
                     77:   /* Unix */
                     78: # define ISSLASH(C) ((C) == '/')
                     79: # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
                     80: # define FILE_SYSTEM_PREFIX_LEN(P) 0
                     81: #endif
                     82: 
                     83: /* The results of open() in this file are not used with fchdir,
                     84:    therefore save some unnecessary work in fchdir.c.  */
                     85: #undef open
                     86: #undef close
                     87: 
                     88: #undef set_program_name
                     89: 
                     90: 
                     91: #if ENABLE_RELOCATABLE
                     92: 
                     93: #ifdef __linux__
                     94: /* File descriptor of the executable.
                     95:    (Only used to verify that we find the correct executable.)  */
                     96: static int executable_fd = -1;
                     97: #endif
                     98: 
                     99: /* Tests whether a given pathname may belong to the executable.  */
                    100: static bool
                    101: maybe_executable (const char *filename)
                    102: {
                    103:   /* Woe32 lacks the access() function, but Cygwin doesn't.  */
                    104: #if !(defined WIN32_NATIVE && !defined __CYGWIN__)
                    105:   if (access (filename, X_OK) < 0)
                    106:     return false;
                    107: 
                    108: #ifdef __linux__
                    109:   if (executable_fd >= 0)
                    110:     {
                    111:       /* If we already have an executable_fd, check that filename points to
                    112:         the same inode.  */
                    113:       struct stat statexe;
                    114:       struct stat statfile;
                    115: 
                    116:       if (fstat (executable_fd, &statexe) >= 0)
                    117:        {
                    118:          if (stat (filename, &statfile) < 0)
                    119:            return false;
                    120:          if (!(statfile.st_dev
                    121:                && statfile.st_dev == statexe.st_dev
                    122:                && statfile.st_ino == statexe.st_ino))
                    123:            return false;
                    124:        }
                    125:     }
                    126: #endif
                    127: #endif
                    128: 
                    129:   return true;
                    130: }
                    131: 
                    132: /* Determine the full pathname of the current executable, freshly allocated.
                    133:    Return NULL if unknown.
                    134:    Guaranteed to work on Linux and Woe32.  Likely to work on the other
                    135:    Unixes (maybe except BeOS), under most conditions.  */
                    136: static char *
                    137: find_executable (const char *argv0)
                    138: {
                    139: #if defined WIN32_NATIVE || defined __CYGWIN__
                    140:   char location[MAX_PATH];
                    141:   int length = GetModuleFileName (NULL, location, sizeof (location));
                    142:   if (length < 0)
                    143:     return NULL;
                    144:   if (!IS_PATH_WITH_DIR (location))
                    145:     /* Shouldn't happen.  */
                    146:     return NULL;
                    147:   {
                    148: #if defined __CYGWIN__
                    149:     /* cygwin-1.5.13 (2005-03-01) or newer would also allow a Linux-like
                    150:        implementation: readlink of "/proc/self/exe".  But using the
                    151:        result of the Win32 system call is simpler and is consistent with the
                    152:        code in relocatable.c.  */
                    153:     /* On Cygwin, we need to convert paths coming from Win32 system calls
                    154:        to the Unix-like slashified notation.  */
                    155:     static char location_as_posix_path[2 * MAX_PATH];
                    156:     /* There's no error return defined for cygwin_conv_to_posix_path.
                    157:        See cygwin-api/func-cygwin-conv-to-posix-path.html.
                    158:        Does it overflow the buffer of expected size MAX_PATH or does it
                    159:        truncate the path?  I don't know.  Let's catch both.  */
                    160:     cygwin_conv_to_posix_path (location, location_as_posix_path);
                    161:     location_as_posix_path[MAX_PATH - 1] = '\0';
                    162:     if (strlen (location_as_posix_path) >= MAX_PATH - 1)
                    163:       /* A sign of buffer overflow or path truncation.  */
                    164:       return NULL;
                    165:     /* Call canonicalize_file_name, because Cygwin supports symbolic links.  */
                    166:     return canonicalize_file_name (location_as_posix_path);
                    167: #else
                    168:     return xstrdup (location);
                    169: #endif
                    170:   }
                    171: #else /* Unix && !Cygwin */
                    172: #ifdef __linux__
                    173:   /* The executable is accessible as /proc/<pid>/exe.  In newer Linux
                    174:      versions, also as /proc/self/exe.  Linux >= 2.1 provides a symlink
                    175:      to the true pathname; older Linux versions give only device and ino,
                    176:      enclosed in brackets, which we cannot use here.  */
                    177:   {
                    178:     char *link;
                    179: 
                    180:     link = xreadlink ("/proc/self/exe");
                    181:     if (link != NULL && link[0] != '[')
                    182:       return link;
                    183:     if (executable_fd < 0)
                    184:       executable_fd = open ("/proc/self/exe", O_RDONLY, 0);
                    185: 
                    186:     {
                    187:       char buf[6+10+5];
                    188:       sprintf (buf, "/proc/%d/exe", getpid ());
                    189:       link = xreadlink (buf);
                    190:       if (link != NULL && link[0] != '[')
                    191:        return link;
                    192:       if (executable_fd < 0)
                    193:        executable_fd = open (buf, O_RDONLY, 0);
                    194:     }
                    195:   }
                    196: #endif
                    197: #if HAVE_MACH_O_DYLD_H && HAVE__NSGETEXECUTABLEPATH
                    198:   /* On MacOS X 10.2 or newer, the function
                    199:        int _NSGetExecutablePath (char *buf, uint32_t *bufsize);
                    200:      can be used to retrieve the executable's full path.  */
                    201:   char location[4096];
                    202:   unsigned int length = sizeof (location);
                    203:   if (_NSGetExecutablePath (location, &length) == 0
                    204:       && location[0] == '/')
                    205:     return canonicalize_file_name (location);
                    206: #endif
                    207:   /* Guess the executable's full path.  We assume the executable has been
                    208:      called via execlp() or execvp() with properly set up argv[0].  The
                    209:      login(1) convention to add a '-' prefix to argv[0] is not supported.  */
                    210:   {
                    211:     bool has_slash = false;
                    212:     {
                    213:       const char *p;
                    214:       for (p = argv0; *p; p++)
                    215:        if (*p == '/')
                    216:          {
                    217:            has_slash = true;
                    218:            break;
                    219:          }
                    220:     }
                    221:     if (!has_slash)
                    222:       {
                    223:        /* exec searches paths without slashes in the directory list given
                    224:           by $PATH.  */
                    225:        const char *path = getenv ("PATH");
                    226: 
                    227:        if (path != NULL)
                    228:          {
                    229:            const char *p;
                    230:            const char *p_next;
                    231: 
                    232:            for (p = path; *p; p = p_next)
                    233:              {
                    234:                const char *q;
                    235:                size_t p_len;
                    236:                char *concat_name;
                    237: 
                    238:                for (q = p; *q; q++)
                    239:                  if (*q == ':')
                    240:                    break;
                    241:                p_len = q - p;
                    242:                p_next = (*q == '\0' ? q : q + 1);
                    243: 
                    244:                /* We have a path item at p, of length p_len.
                    245:                   Now concatenate the path item and argv0.  */
                    246:                concat_name = (char *) xmalloc (p_len + strlen (argv0) + 2);
                    247: #ifdef NO_XMALLOC
                    248:                if (concat_name == NULL)
                    249:                  return NULL;
                    250: #endif
                    251:                if (p_len == 0)
                    252:                  /* An empty PATH element designates the current directory.  */
                    253:                  strcpy (concat_name, argv0);
                    254:                else
                    255:                  {
                    256:                    memcpy (concat_name, p, p_len);
                    257:                    concat_name[p_len] = '/';
                    258:                    strcpy (concat_name + p_len + 1, argv0);
                    259:                  }
                    260:                if (maybe_executable (concat_name))
                    261:                  return canonicalize_file_name (concat_name);
                    262:                free (concat_name);
                    263:              }
                    264:          }
                    265:        /* Not found in the PATH, assume the current directory.  */
                    266:       }
                    267:     /* exec treats paths containing slashes as relative to the current
                    268:        directory.  */
                    269:     if (maybe_executable (argv0))
                    270:       return canonicalize_file_name (argv0);
                    271:   }
                    272:   /* No way to find the executable.  */
                    273:   return NULL;
                    274: #endif
                    275: }
                    276: 
                    277: /* Full pathname of executable, or NULL.  */
                    278: static char *executable_fullname;
                    279: 
                    280: static void
                    281: prepare_relocate (const char *orig_installprefix, const char *orig_installdir,
                    282:                  const char *argv0)
                    283: {
                    284:   char *curr_prefix;
                    285: 
                    286:   /* Determine the full pathname of the current executable.  */
                    287:   executable_fullname = find_executable (argv0);
                    288: 
                    289:   /* Determine the current installation prefix from it.  */
                    290:   curr_prefix = compute_curr_prefix (orig_installprefix, orig_installdir,
                    291:                                     executable_fullname);
                    292:   if (curr_prefix != NULL)
                    293:     {
                    294:       /* Now pass this prefix to all copies of the relocate.c source file.  */
                    295:       set_relocation_prefix (orig_installprefix, curr_prefix);
                    296: 
                    297:       free (curr_prefix);
                    298:     }
                    299: }
                    300: 
                    301: /* Set program_name, based on argv[0], and original installation prefix and
                    302:    directory, for relocatability.  */
                    303: void
                    304: set_program_name_and_installdir (const char *argv0,
                    305:                                 const char *orig_installprefix,
                    306:                                 const char *orig_installdir)
                    307: {
                    308:   const char *argv0_stripped = argv0;
                    309: 
                    310:   /* Relocatable programs are renamed to .bin by install-reloc.  Or, more
                    311:      generally, their suffix is changed from $exeext to .bin$exeext.
                    312:      Remove the ".bin" here.  */
                    313:   {
                    314:     size_t argv0_len = strlen (argv0);
                    315:     const size_t exeext_len = sizeof (EXEEXT) - sizeof ("");
                    316:     if (argv0_len > 4 + exeext_len)
                    317:       if (memcmp (argv0 + argv0_len - exeext_len - 4, ".bin", 4) == 0)
                    318:        {
                    319:          if (sizeof (EXEEXT) > sizeof (""))
                    320:            {
                    321:              /* Compare using an inlined copy of c_strncasecmp(), because
                    322:                 the filenames may have undergone a case conversion since
                    323:                 they were packaged.  In other words, EXEEXT may be ".exe"
                    324:                 on one system and ".EXE" on another.  */
                    325:              static const char exeext[] = EXEEXT;
                    326:              const char *s1 = argv0 + argv0_len - exeext_len;
                    327:              const char *s2 = exeext;
                    328:              for (; *s1 != '\0'; s1++, s2++)
                    329:                {
                    330:                  unsigned char c1 = *s1;
                    331:                  unsigned char c2 = *s2;
                    332:                  if ((c1 >= 'A' && c1 <= 'Z' ? c1 - 'A' + 'a' : c1)
                    333:                      != (c2 >= 'A' && c2 <= 'Z' ? c2 - 'A' + 'a' : c2))
                    334:                    goto done_stripping;
                    335:                }
                    336:            }
                    337:          /* Remove ".bin" before EXEEXT or its equivalent.  */
                    338:          {
                    339:            char *shorter = (char *) xmalloc (argv0_len - 4 + 1);
                    340: #ifdef NO_XMALLOC
                    341:            if (shorter != NULL)
                    342: #endif
                    343:              {
                    344:                memcpy (shorter, argv0, argv0_len - exeext_len - 4);
                    345:                if (sizeof (EXEEXT) > sizeof (""))
                    346:                  memcpy (shorter + argv0_len - exeext_len - 4,
                    347:                          argv0 + argv0_len - exeext_len - 4,
                    348:                          exeext_len);
                    349:                shorter[argv0_len - 4] = '\0';
                    350:                argv0_stripped = shorter;
                    351:              }
                    352:          }
                    353:         done_stripping: ;
                    354:       }
                    355:   }
                    356: 
                    357:   set_program_name (argv0_stripped);
                    358: 
                    359:   prepare_relocate (orig_installprefix, orig_installdir, argv0);
                    360: }
                    361: 
                    362: /* Return the full pathname of the current executable, based on the earlier
                    363:    call to set_program_name_and_installdir.  Return NULL if unknown.  */
                    364: char *
                    365: get_full_program_name (void)
                    366: {
                    367:   return executable_fullname;
                    368: }
                    369: 
                    370: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>