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

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

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