X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fprogreloc.c;h=cb97959992d36d9f4d5ca5eb737275b0671b17b9;hb=96540edb37f9bcc02b5f35bd3dcda5aaac5dac2c;hp=18e73599a121fbda02ec9aa5cced498ad27a58bd;hpb=222b0486b7db1b09293e05512873d633440efcb3;p=gnulib.git diff --git a/lib/progreloc.c b/lib/progreloc.c index 18e73599a..cb9795999 100644 --- a/lib/progreloc.c +++ b/lib/progreloc.c @@ -1,5 +1,5 @@ /* Provide relocatable programs. - Copyright (C) 2003-2004 Free Software Foundation, Inc. + Copyright (C) 2003-2006 Free Software Foundation, Inc. Written by Bruno Haible , 2003. This program is free software; you can redistribute it and/or modify @@ -17,9 +17,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CONFIG_H -# include -#endif +#include /* Specification. */ #include "progname.h" @@ -34,12 +32,16 @@ #endif #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 @@ -75,6 +77,11 @@ # 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 +97,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 +133,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 +191,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, unsigned long *bufsize); + can be used to retrieve the executable's full path. */ + char location[4096]; + unsigned long 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. */ @@ -259,21 +300,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: ; } }