X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fprogreloc.c;h=dcfe3099364d1f2bdc57471cbba41258aed17c80;hb=1276a2c5f24c0c932426aca9c899fa524d2443f2;hp=f9bf5b2e7052c5d5f6e67be434a9faec92e31bc2;hpb=e0576a6aeae094c5fc5a95fae6bae82eabdce5bb;p=gnulib.git diff --git a/lib/progreloc.c b/lib/progreloc.c index f9bf5b2e7..dcfe30993 100644 --- a/lib/progreloc.c +++ b/lib/progreloc.c @@ -1,26 +1,23 @@ /* Provide relocatable programs. - Copyright (C) 2003-2004 Free Software Foundation, Inc. + Copyright (C) 2003-2014 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 +#define _GL_USE_STDLIB_ALLOC 1 +#include /* Specification. */ #include "progname.h" @@ -30,37 +27,54 @@ #include #include #include -#if HAVE_UNISTD_H -# include -#endif +#include #include -#if defined _WIN32 || defined __WIN32__ -# undef WIN32 /* avoid warning on mingw32 */ -# define WIN32 +/* Get declaration of _NSGetExecutablePath on Mac OS X 10.2 or newer. */ +#if HAVE_MACH_O_DYLD_H +# include +#endif + +#if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__ +# define WINDOWS_NATIVE #endif -#ifdef WIN32 +#ifdef WINDOWS_NATIVE # 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 +#ifndef O_EXEC +# define O_EXEC O_RDONLY /* This is often close enough in older systems. */ +#endif + +/* Declare canonicalize_file_name. + The included above may be the system's one, not the gnulib + one. */ +extern char * canonicalize_file_name (const char *name); + /* Pathname support. ISSLASH(C) tests whether C is a directory separator character. IS_PATH_WITH_DIR(P) tests whether P contains a directory specification. */ -#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__ - /* Win32, Cygwin, OS/2, DOS */ +#if ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__ + /* Native Windows, OS/2, DOS */ # define ISSLASH(C) ((C) == '/' || (C) == '\\') # define HAS_DEVICE(P) \ ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \ @@ -75,12 +89,20 @@ # 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 + +/* Use the system functions, not the gnulib overrides in this file. */ +#undef sprintf + #undef set_program_name #if ENABLE_RELOCATABLE -#ifdef __linux__ +#if defined __linux__ || defined __CYGWIN__ /* File descriptor of the executable. (Only used to verify that we find the correct executable.) */ static int executable_fd = -1; @@ -90,52 +112,58 @@ static int executable_fd = -1; static bool maybe_executable (const char *filename) { -#if !defined WIN32 + /* The native Windows API lacks the access() function. */ +#if !defined WINDOWS_NATIVE if (access (filename, X_OK) < 0) return false; +#endif -#ifdef __linux__ +#if defined __linux__ || defined __CYGWIN__ if (executable_fd >= 0) { /* If we already have an executable_fd, check that filename points to - the same inode. */ + the same inode. */ struct stat statexe; struct stat statfile; if (fstat (executable_fd, &statexe) >= 0) - { - if (stat (filename, &statfile) < 0) - return false; - if (!(statfile.st_dev - && statfile.st_dev == statexe.st_dev - && statfile.st_ino == statexe.st_ino)) - return false; - } + { + if (stat (filename, &statfile) < 0) + return false; + if (!(statfile.st_dev + && statfile.st_dev == statexe.st_dev + && statfile.st_ino == statexe.st_ino)) + return false; + } } #endif -#endif return true; } /* Determine the full pathname of the current executable, freshly allocated. Return NULL if unknown. - Guaranteed to work on Linux and Woe32. Likely to work on the other - Unixes (maybe except BeOS), under most conditions. */ + Guaranteed to work on Linux and native Windows. Likely to work on the + other Unixes (maybe except BeOS), under most conditions. */ static char * find_executable (const char *argv0) { -#ifdef WIN32 - char buf[1024]; - int length = GetModuleFileName (NULL, buf, sizeof (buf)); +#if defined WINDOWS_NATIVE + /* Native Windows only. + On Cygwin, it is better to use the Cygwin provided /proc interface, than + to use native Windows API and cygwin_conv_to_posix_path, because it + supports longer file names + (see ). */ + 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); + return xstrdup (location); #else /* Unix */ -#ifdef __linux__ +# ifdef __linux__ /* The executable is accessible as /proc//exe. In newer Linux versions, also as /proc/self/exe. Linux >= 2.1 provides a symlink to the true pathname; older Linux versions give only device and ino, @@ -147,19 +175,42 @@ find_executable (const char *argv0) if (link != NULL && link[0] != '[') return link; if (executable_fd < 0) - executable_fd = open ("/proc/self/exe", O_RDONLY, 0); + executable_fd = open ("/proc/self/exe", O_EXEC, 0); { char buf[6+10+5]; sprintf (buf, "/proc/%d/exe", getpid ()); link = xreadlink (buf); if (link != NULL && link[0] != '[') - return link; + return link; if (executable_fd < 0) - executable_fd = open (buf, O_RDONLY, 0); + executable_fd = open (buf, O_EXEC, 0); } } -#endif +# endif +# ifdef __CYGWIN__ + /* The executable is accessible as /proc//exe, at least in + Cygwin >= 1.5. */ + { + char *link; + + link = xreadlink ("/proc/self/exe"); + if (link != NULL) + return link; + if (executable_fd < 0) + executable_fd = open ("/proc/self/exe", O_EXEC, 0); + } +# endif +# if HAVE_MACH_O_DYLD_H && HAVE__NSGETEXECUTABLEPATH + /* On Mac OS 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. */ @@ -168,57 +219,57 @@ find_executable (const char *argv0) { const char *p; for (p = argv0; *p; p++) - if (*p == '/') - { - has_slash = true; - break; - } + if (*p == '/') + { + has_slash = true; + break; + } } if (!has_slash) { - /* exec searches paths without slashes in the directory list given - by $PATH. */ - const char *path = getenv ("PATH"); - - if (path != NULL) - { - const char *p; - const char *p_next; - - for (p = path; *p; p = p_next) - { - const char *q; - size_t p_len; - char *concat_name; - - for (q = p; *q; q++) - if (*q == ':') - break; - p_len = q - p; - p_next = (*q == '\0' ? q : q + 1); - - /* We have a path item at p, of length p_len. - Now concatenate the path item and argv0. */ - concat_name = (char *) xmalloc (p_len + strlen (argv0) + 2); -#ifdef NO_XMALLOC - if (concat_name == NULL) - return NULL; -#endif - if (p_len == 0) - /* An empty PATH element designates the current directory. */ - strcpy (concat_name, argv0); - else - { - memcpy (concat_name, p, p_len); - concat_name[p_len] = '/'; - strcpy (concat_name + p_len + 1, argv0); - } - if (maybe_executable (concat_name)) - return canonicalize_file_name (concat_name); - free (concat_name); - } - } - /* Not found in the PATH, assume the current directory. */ + /* exec searches paths without slashes in the directory list given + by $PATH. */ + const char *path = getenv ("PATH"); + + if (path != NULL) + { + const char *p; + const char *p_next; + + for (p = path; *p; p = p_next) + { + const char *q; + size_t p_len; + char *concat_name; + + for (q = p; *q; q++) + if (*q == ':') + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + + /* We have a path item at p, of length p_len. + Now concatenate the path item and argv0. */ + concat_name = (char *) xmalloc (p_len + strlen (argv0) + 2); +# ifdef NO_XMALLOC + if (concat_name == NULL) + return NULL; +# endif + if (p_len == 0) + /* An empty PATH element designates the current directory. */ + strcpy (concat_name, argv0); + else + { + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, argv0); + } + if (maybe_executable (concat_name)) + return canonicalize_file_name (concat_name); + free (concat_name); + } + } + /* Not found in the PATH, assume the current directory. */ } /* exec treats paths containing slashes as relative to the current directory. */ @@ -235,45 +286,78 @@ static char *executable_fullname; static void prepare_relocate (const char *orig_installprefix, const char *orig_installdir, - const char *argv0) + const char *argv0) { - const char *curr_prefix; + char *curr_prefix; /* Determine the full pathname of the current executable. */ executable_fullname = find_executable (argv0); /* Determine the current installation prefix from it. */ curr_prefix = compute_curr_prefix (orig_installprefix, orig_installdir, - executable_fullname); + 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 directory, for relocatability. */ void set_program_name_and_installdir (const char *argv0, - const char *orig_installprefix, - const char *orig_installdir) + const char *orig_installprefix, + const char *orig_installdir) { 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: ; } }