Back to index

glibc  2.9
Functions
execvp.c File Reference
#include <alloca.h>
#include <unistd.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <paths.h>

Go to the source code of this file.

Functions

static void internal_function scripts_argv (const char *file, char *const argv[], int argc, char **new_argv)
int execvp (char *file, argv) const

Function Documentation

int execvp ( char *  file,
argv   
) const

Definition at line 50 of file execvp.c.

{
  if (*file == '\0')
    {
      /* We check the simple case first. */
      __set_errno (ENOENT);
      return -1;
    }

  if (strchr (file, '/') != NULL)
    {
      /* Don't search when it contains a slash.  */
      __execve (file, argv, __environ);

      if (errno == ENOEXEC)
       {
         /* Count the arguments.  */
         int argc = 0;
         while (argv[argc++])
           ;
         size_t len = (argc + 1) * sizeof (char *);
         char **script_argv;
         void *ptr = NULL;
         if (__libc_use_alloca (len))
           script_argv = alloca (len);
         else
           script_argv = ptr = malloc (len);

         if (script_argv != NULL)
           {
             scripts_argv (file, argv, argc, script_argv);
             __execve (script_argv[0], script_argv, __environ);

             free (ptr);
           }
       }
    }
  else
    {
      size_t pathlen;
      size_t alloclen = 0;
      char *path = getenv ("PATH");
      if (path == NULL)
       {
         pathlen = confstr (_CS_PATH, (char *) NULL, 0);
         alloclen = pathlen + 1;
       }
      else
       pathlen = strlen (path);

      size_t len = strlen (file) + 1;
      alloclen += pathlen + len + 1;

      char *name;
      char *path_malloc = NULL;
      if (__libc_use_alloca (alloclen))
       name = alloca (alloclen);
      else
       {
         path_malloc = name = malloc (alloclen);
         if (name == NULL)
           return -1;
       }

      if (path == NULL)
       {
         /* There is no `PATH' in the environment.
            The default search path is the current directory
            followed by the path `confstr' returns for `_CS_PATH'.  */
         path = name + pathlen + len + 1;
         path[0] = ':';
         (void) confstr (_CS_PATH, path + 1, pathlen);
       }

      /* Copy the file name at the top.  */
      name = (char *) memcpy (name + pathlen + 1, file, len);
      /* And add the slash.  */
      *--name = '/';

      char **script_argv = NULL;
      void *script_argv_malloc = NULL;
      bool got_eacces = false;
      char *p = path;
      do
       {
         char *startp;

         path = p;
         p = __strchrnul (path, ':');

         if (p == path)
           /* Two adjacent colons, or a colon at the beginning or the end
              of `PATH' means to search the current directory.  */
           startp = name + 1;
         else
           startp = (char *) memcpy (name - (p - path), path, p - path);

         /* Try to execute this name.  If it works, execve will not return. */
         __execve (startp, argv, __environ);

         if (errno == ENOEXEC)
           {
             if (script_argv == NULL)
              {
                /* Count the arguments.  */
                int argc = 0;
                while (argv[argc++])
                  ;
                size_t arglen = (argc + 1) * sizeof (char *);
                if (__libc_use_alloca (alloclen + arglen))
                  script_argv = alloca (arglen);
                else
                  script_argv = script_argv_malloc = malloc (arglen);
                if (script_argv == NULL)
                  {
                    /* A possible EACCES error is not as important as
                      the ENOMEM.  */
                    got_eacces = false;
                    break;
                  }
                scripts_argv (startp, argv, argc, script_argv);
              }

             __execve (script_argv[0], script_argv, __environ);
           }

         switch (errno)
           {
           case EACCES:
             /* Record the we got a `Permission denied' error.  If we end
               up finding no executable we can use, we want to diagnose
               that we did find one but were denied access.  */
             got_eacces = true;
           case ENOENT:
           case ESTALE:
           case ENOTDIR:
             /* Those errors indicate the file is missing or not executable
               by us, in which case we want to just try the next path
               directory.  */
           case ENODEV:
           case ETIMEDOUT:
             /* Some strange filesystems like AFS return even
               stranger error numbers.  They cannot reasonably mean
               anything else so ignore those, too.  */
             break;

           default:
             /* Some other error means we found an executable file, but
               something went wrong executing it; return the error to our
               caller.  */
             return -1;
           }
       }
      while (*p++ != '\0');

      /* We tried every element and none of them worked.  */
      if (got_eacces)
       /* At least one failure was due to permissions, so report that
          error.  */
       __set_errno (EACCES);

      free (script_argv_malloc);
      free (path_malloc);
    }

  /* Return the error from the last attempt (probably ENOENT).  */
  return -1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void internal_function scripts_argv ( const char *  file,
char *const  argv[],
int  argc,
char **  new_argv 
) [static]

Definition at line 34 of file execvp.c.

{
  /* Construct an argument list for the shell.  */
  new_argv[0] = (char *) _PATH_BSHELL;
  new_argv[1] = (char *) file;
  while (argc > 1)
    {
      new_argv[argc] = argv[argc - 1];
      --argc;
    }
}

Here is the caller graph for this function: