X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fprogreloc.c;h=a79ef7a2c9f2ff6fab449436011d5b0093b9536d;hb=f32c9d0ea73465c6855a08d1ead5997f7af0503a;hp=0f87c1c92c2955bffa01cfa41ca319676525c62f;hpb=dc76e6e4a571b134102aa89a6b500478fb49a73a;p=gnulib.git diff --git a/lib/progreloc.c b/lib/progreloc.c index 0f87c1c92..a79ef7a2c 100644 --- a/lib/progreloc.c +++ b/lib/progreloc.c @@ -1,26 +1,22 @@ /* Provide relocatable programs. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003-2009 Free Software Foundation, Inc. Written by Bruno Haible , 2003. - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2, or (at your option) - any later version. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU Library General Public - License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. */ + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif +#include /* Specification. */ #include "progname.h" @@ -30,29 +26,38 @@ #include #include #include -#if HAVE_UNISTD_H -# include -#endif +#include #include +/* Get declaration of _NSGetExecutablePath on MacOS X 10.2 or newer. */ +#if HAVE_MACH_O_DYLD_H +# include +#endif + #if defined _WIN32 || defined __WIN32__ -# undef WIN32 /* avoid warning on mingw32 */ -# define WIN32 +# define WIN32_NATIVE #endif -#ifdef WIN32 +#if defined WIN32_NATIVE || defined __CYGWIN__ # define WIN32_LEAN_AND_MEAN # include #endif -#include "xreadlink.h" #include "canonicalize.h" #include "relocatable.h" #ifdef NO_XMALLOC +# include "areadlink.h" +# define xreadlink areadlink +#else +# include "xreadlink.h" +#endif + +#ifdef NO_XMALLOC # define xmalloc malloc +# define xstrdup strdup #else -# include "xmalloc.h" +# include "xalloc.h" #endif /* Pathname support. @@ -67,14 +72,19 @@ && (P)[1] == ':') # define IS_PATH_WITH_DIR(P) \ (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P)) -# define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0) +# define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0) #else /* Unix */ # define ISSLASH(C) ((C) == '/') # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL) -# define FILESYSTEM_PREFIX_LEN(P) 0 +# define FILE_SYSTEM_PREFIX_LEN(P) 0 #endif +/* The results of open() in this file are not used with fchdir, + therefore save some unnecessary work in fchdir.c. */ +#undef open +#undef close + #undef set_program_name @@ -90,7 +100,8 @@ static int executable_fd = -1; static bool maybe_executable (const char *filename) { -#if !defined WIN32 + /* Woe32 lacks the access() function, but Cygwin doesn't. */ +#if !(defined WIN32_NATIVE && !defined __CYGWIN__) if (access (filename, X_OK) < 0) return false; @@ -125,16 +136,39 @@ maybe_executable (const char *filename) static char * find_executable (const char *argv0) { -#ifdef WIN32 - char buf[1024]; - int length = GetModuleFileName (NULL, buf, sizeof (buf)); +#if defined WIN32_NATIVE || defined __CYGWIN__ + char location[MAX_PATH]; + int length = GetModuleFileName (NULL, location, sizeof (location)); if (length < 0) return NULL; - if (!IS_PATH_WITH_DIR (buf)) + if (!IS_PATH_WITH_DIR (location)) /* Shouldn't happen. */ return NULL; - return xstrdup (buf); -#else /* Unix */ + { +#if defined __CYGWIN__ + /* cygwin-1.5.13 (2005-03-01) or newer would also allow a Linux-like + implementation: readlink of "/proc/self/exe". But using the + result of the Win32 system call is simpler and is consistent with the + code in relocatable.c. */ + /* On Cygwin, we need to convert paths coming from Win32 system calls + to the Unix-like slashified notation. */ + static char location_as_posix_path[2 * MAX_PATH]; + /* There's no error return defined for cygwin_conv_to_posix_path. + See cygwin-api/func-cygwin-conv-to-posix-path.html. + Does it overflow the buffer of expected size MAX_PATH or does it + truncate the path? I don't know. Let's catch both. */ + cygwin_conv_to_posix_path (location, location_as_posix_path); + location_as_posix_path[MAX_PATH - 1] = '\0'; + if (strlen (location_as_posix_path) >= MAX_PATH - 1) + /* A sign of buffer overflow or path truncation. */ + return NULL; + /* Call canonicalize_file_name, because Cygwin supports symbolic links. */ + return canonicalize_file_name (location_as_posix_path); +#else + return xstrdup (location); +#endif + } +#else /* Unix && !Cygwin */ #ifdef __linux__ /* The executable is accessible as /proc//exe. In newer Linux versions, also as /proc/self/exe. Linux >= 2.1 provides a symlink @@ -160,6 +194,16 @@ find_executable (const char *argv0) } } #endif +#if HAVE_MACH_O_DYLD_H && HAVE__NSGETEXECUTABLEPATH + /* On MacOS X 10.2 or newer, the function + int _NSGetExecutablePath (char *buf, uint32_t *bufsize); + can be used to retrieve the executable's full path. */ + char location[4096]; + unsigned int length = sizeof (location); + if (_NSGetExecutablePath (location, &length) == 0 + && location[0] == '/') + return canonicalize_file_name (location); +#endif /* Guess the executable's full path. We assume the executable has been called via execlp() or execvp() with properly set up argv[0]. The login(1) convention to add a '-' prefix to argv[0] is not supported. */ @@ -237,7 +281,7 @@ static void prepare_relocate (const char *orig_installprefix, const char *orig_installdir, const char *argv0) { - const char *curr_prefix; + char *curr_prefix; /* Determine the full pathname of the current executable. */ executable_fullname = find_executable (argv0); @@ -246,8 +290,12 @@ prepare_relocate (const char *orig_installprefix, const char *orig_installdir, curr_prefix = compute_curr_prefix (orig_installprefix, orig_installdir, executable_fullname); if (curr_prefix != NULL) - /* Now pass this prefix to all copies of the relocate.c source file. */ - set_relocation_prefix (orig_installprefix, curr_prefix); + { + /* Now pass this prefix to all copies of the relocate.c source file. */ + set_relocation_prefix (orig_installprefix, curr_prefix); + + free (curr_prefix); + } } /* Set program_name, based on argv[0], and original installation prefix and @@ -259,21 +307,50 @@ set_program_name_and_installdir (const char *argv0, { const char *argv0_stripped = argv0; - /* Relocatable programs are renamed to .bin by install-reloc. Remove - this suffix here. */ + /* Relocatable programs are renamed to .bin by install-reloc. Or, more + generally, their suffix is changed from $exeext to .bin$exeext. + Remove the ".bin" here. */ { size_t argv0_len = strlen (argv0); - if (argv0_len > 4 && memcmp (argv0 + argv0_len - 4, ".bin", 4) == 0) - { - char *shorter = (char *) xmalloc (argv0_len - 4 + 1); + const size_t exeext_len = sizeof (EXEEXT) - sizeof (""); + if (argv0_len > 4 + exeext_len) + if (memcmp (argv0 + argv0_len - exeext_len - 4, ".bin", 4) == 0) + { + if (sizeof (EXEEXT) > sizeof ("")) + { + /* Compare using an inlined copy of c_strncasecmp(), because + the filenames may have undergone a case conversion since + they were packaged. In other words, EXEEXT may be ".exe" + on one system and ".EXE" on another. */ + static const char exeext[] = EXEEXT; + const char *s1 = argv0 + argv0_len - exeext_len; + const char *s2 = exeext; + for (; *s1 != '\0'; s1++, s2++) + { + unsigned char c1 = *s1; + unsigned char c2 = *s2; + if ((c1 >= 'A' && c1 <= 'Z' ? c1 - 'A' + 'a' : c1) + != (c2 >= 'A' && c2 <= 'Z' ? c2 - 'A' + 'a' : c2)) + goto done_stripping; + } + } + /* Remove ".bin" before EXEEXT or its equivalent. */ + { + char *shorter = (char *) xmalloc (argv0_len - 4 + 1); #ifdef NO_XMALLOC - if (shorter != NULL) + if (shorter != NULL) #endif - { - memcpy (shorter, argv0, argv0_len - 4); - shorter[argv0_len - 4] = '\0'; - argv0_stripped = shorter; + { + memcpy (shorter, argv0, argv0_len - exeext_len - 4); + if (sizeof (EXEEXT) > sizeof ("")) + memcpy (shorter + argv0_len - exeext_len - 4, + argv0 + argv0_len - exeext_len - 4, + exeext_len); + shorter[argv0_len - 4] = '\0'; + argv0_stripped = shorter; + } } + done_stripping: ; } }