Annotation of embedaddon/libiconv/srclib/progreloc.c, revision 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>