Пример #1
0
/* 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.  */
static char *
find_executable (const char *argv0)
{
#if defined WIN32_NATIVE
  /* Native Win32 only.
     On Cygwin, it is better to use the Cygwin provided /proc interface, than
     to use native Win32 API and cygwin_conv_to_posix_path, because it supports
     longer file names
     (see <http://cygwin.com/ml/cygwin/2011-01/msg00410.html>).  */
  char location[MAX_PATH];
  int length = GetModuleFileName (NULL, location, sizeof (location));
  if (length < 0)
    return NULL;
  if (!IS_PATH_WITH_DIR (location))
    /* Shouldn't happen.  */
    return NULL;
  return xstrdup (location);
#else /* Unix */
# ifdef __linux__
  /* The executable is accessible as /proc/<pid>/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,
     enclosed in brackets, which we cannot use here.  */
  {
    char *link;

    link = xreadlink ("/proc/self/exe");
    if (link != NULL && link[0] != '[')
      return link;
    if (executable_fd < 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;
      if (executable_fd < 0)
        executable_fd = open (buf, O_EXEC, 0);
    }
  }
# endif
# ifdef __CYGWIN__
  /* The executable is accessible as /proc/<pid>/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 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.  */
  {
    bool has_slash = false;
    {
      const char *p;
      for (p = argv0; *p; p++)
        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 treats paths containing slashes as relative to the current
       directory.  */
    if (maybe_executable (argv0))
      return canonicalize_file_name (argv0);
  }
  /* No way to find the executable.  */
  return NULL;
#endif
}
/* 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.  */
static char *
find_executable (const char *argv0)
{
#ifdef WIN32
  char buf[1024];
  int length = GetModuleFileName (NULL, buf, sizeof (buf));
  if (length < 0)
    return NULL;
  if (!IS_PATH_WITH_DIR (buf))
    /* Shouldn't happen.  */
    return NULL;
  return xstrdup (buf);
#else /* Unix */
#ifdef __linux__
  /* The executable is accessible as /proc/<pid>/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,
     enclosed in brackets, which we cannot use here.  */
  {
    char *link;

    link = xreadlink ("/proc/self/exe");
    if (link != NULL && link[0] != '[')
      return link;
    if (executable_fd < 0)
      executable_fd = open ("/proc/self/exe", O_RDONLY, 0);

    {
      char buf[6+10+5];
      sprintf (buf, "/proc/%d/exe", getpid ());
      link = xreadlink (buf);
      if (link != NULL && link[0] != '[')
	return link;
      if (executable_fd < 0)
	executable_fd = open (buf, O_RDONLY, 0);
    }
  }
#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.  */
  {
    bool has_slash = false;
    {
      const char *p;
      for (p = argv0; *p; p++)
	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 treats paths containing slashes as relative to the current
       directory.  */
    if (maybe_executable (argv0))
      return canonicalize_file_name (argv0);
  }
  /* No way to find the executable.  */
  return NULL;
#endif
}
Пример #3
0
/* 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.  */
static char *
find_executable (const char *argv0)
{
#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 (location))
    /* Shouldn't happen.  */
    return NULL;
  {
#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/<pid>/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,
     enclosed in brackets, which we cannot use here.  */
  {
    char *link;

    link = xreadlink ("/proc/self/exe");
    if (link != NULL && link[0] != '[')
      return link;
    if (executable_fd < 0)
      executable_fd = open ("/proc/self/exe", O_RDONLY, 0);

    {
      char buf[6+10+5];
      sprintf (buf, "/proc/%d/exe", getpid ());
      link = xreadlink (buf);
      if (link != NULL && link[0] != '[')
	return link;
      if (executable_fd < 0)
	executable_fd = open (buf, O_RDONLY, 0);
    }
  }
#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.  */
  {
    bool has_slash = false;
    {
      const char *p;
      for (p = argv0; *p; p++)
	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 treats paths containing slashes as relative to the current
       directory.  */
    if (maybe_executable (argv0))
      return canonicalize_file_name (argv0);
  }
  /* No way to find the executable.  */
  return NULL;
#endif
}
Пример #4
0
/* find_executable(program_name)
 is to be called immediately after the program starts,
 with program_name = argv[0],
 before any chdir() operation and before any setenv("PATH",...).
 It determines the full program path and opens a file descriptor to
 the executable, for later use.
 Return value is 0 if successful, -1 and errno set if not. */
int find_executable (const char * program_name) {
  /* Do not need to execute this more than once. */
  if (executable_name != NULL) return 0;
#if defined(WIN32_NATIVE)
  { /* an illustration that win32 API can be sometimes useful */
    char execname[MAX_PATH];
    if (!GetModuleFileName(NULL,execname,MAX_PATH))
      goto notfound;
    executable_name = (char*)malloc(strlen(execname)+1);
    strcpy(executable_name,execname);
    return 0;  }
#elif defined(UNIX)
 #if defined(UNIX_LINUX) || defined(UNIX_CYGWIN32)
  { /* The executable is accessible as /proc/<pid>/exe. We try this first
   because it is safer: no race condition w.r.t. the file system. It may
   fail, however, if the user has not compiled /proc support into his
   kernel. */
    int fd = open("/proc/self/exe",O_RDONLY,my_open_mask);
    if (fd >= 0)
      executable_fd = fd;
  }
 #endif
  { /* Now we 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. */
    const char * p;
    for (p = program_name; *p; p++)
      if (*p == '/')
        goto 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;
        unsigned long p_len;
        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 program_name. */
          char * concat_name =
            (char*) malloc(p_len + strlen(program_name) + 2);
          if (concat_name == NULL) { errno = ENOMEM; goto notfound; }
          if (p_len == 0) {
            /* empty PATH element designates the current directory */
            strcpy(concat_name,program_name);
          } else {
            memcpy(concat_name, p, p_len);
            concat_name[p_len] = '/';
            strcpy(concat_name+p_len+1, program_name);
          }
          if (maybe_executable(concat_name)) {
            /* Assume we have found the executable */
            program_name = concat_name; goto resolve;
          }
          free(concat_name);
        }
      }
    }
    /* Not found in the PATH, assume the current directory. */
  }
 has_slash:
  /* exec treats paths containing slashes as relative to the current
     directory */
  if (maybe_executable(program_name)) {
   resolve:
    /* resolve program_name: */
#  if !defined(MAXPATHLEN)
#   define MAXPATHLEN 1024      /* see unix.d */
#  endif
    executable_name = (char*) malloc(MAXPATHLEN);
    if (executable_name == NULL) { errno = ENOMEM; goto notfound; }
    if (realpath(program_name,executable_name) == NULL) {
      free(executable_name); goto notfound;
    }
#if defined(UNIX_CYGWIN32)
    { /* cygwin does not append ".exe" on its own */
      int len = strlen(executable_name);
      if (!(len > 4 && (executable_name[len-4] == '.') &&
            (executable_name[len-1] == 'e' || executable_name[len-1] == 'E') &&
            (executable_name[len-2] == 'x' || executable_name[len-2] == 'X') &&
            (executable_name[len-3] == 'e' || executable_name[len-3] == 'E')))
        strcat(executable_name,".exe");
    }
#endif
    return 0;
  }
  errno = ENOENT;
#else
  #error "not implemented: find_executable()"
#endif
 notfound:
  executable_name = default_executable_name; return -1;
}