Back to index

glibc  2.9
execvp.c
Go to the documentation of this file.
00001 /* Copyright (C) 1991,92, 1995-99, 2002, 2004, 2005, 2007
00002    Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <alloca.h>
00021 #include <unistd.h>
00022 #include <stdarg.h>
00023 #include <stdbool.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <errno.h>
00027 #include <paths.h>
00028 
00029 
00030 /* The file is accessible but it is not an executable file.  Invoke
00031    the shell to interpret it as a script.  */
00032 static void
00033 internal_function
00034 scripts_argv (const char *file, char *const argv[], int argc, char **new_argv)
00035 {
00036   /* Construct an argument list for the shell.  */
00037   new_argv[0] = (char *) _PATH_BSHELL;
00038   new_argv[1] = (char *) file;
00039   while (argc > 1)
00040     {
00041       new_argv[argc] = argv[argc - 1];
00042       --argc;
00043     }
00044 }
00045 
00046 
00047 /* Execute FILE, searching in the `PATH' environment variable if it contains
00048    no slashes, with arguments ARGV and environment from `environ'.  */
00049 int
00050 execvp (file, argv)
00051      const char *file;
00052      char *const argv[];
00053 {
00054   if (*file == '\0')
00055     {
00056       /* We check the simple case first. */
00057       __set_errno (ENOENT);
00058       return -1;
00059     }
00060 
00061   if (strchr (file, '/') != NULL)
00062     {
00063       /* Don't search when it contains a slash.  */
00064       __execve (file, argv, __environ);
00065 
00066       if (errno == ENOEXEC)
00067        {
00068          /* Count the arguments.  */
00069          int argc = 0;
00070          while (argv[argc++])
00071            ;
00072          size_t len = (argc + 1) * sizeof (char *);
00073          char **script_argv;
00074          void *ptr = NULL;
00075          if (__libc_use_alloca (len))
00076            script_argv = alloca (len);
00077          else
00078            script_argv = ptr = malloc (len);
00079 
00080          if (script_argv != NULL)
00081            {
00082              scripts_argv (file, argv, argc, script_argv);
00083              __execve (script_argv[0], script_argv, __environ);
00084 
00085              free (ptr);
00086            }
00087        }
00088     }
00089   else
00090     {
00091       size_t pathlen;
00092       size_t alloclen = 0;
00093       char *path = getenv ("PATH");
00094       if (path == NULL)
00095        {
00096          pathlen = confstr (_CS_PATH, (char *) NULL, 0);
00097          alloclen = pathlen + 1;
00098        }
00099       else
00100        pathlen = strlen (path);
00101 
00102       size_t len = strlen (file) + 1;
00103       alloclen += pathlen + len + 1;
00104 
00105       char *name;
00106       char *path_malloc = NULL;
00107       if (__libc_use_alloca (alloclen))
00108        name = alloca (alloclen);
00109       else
00110        {
00111          path_malloc = name = malloc (alloclen);
00112          if (name == NULL)
00113            return -1;
00114        }
00115 
00116       if (path == NULL)
00117        {
00118          /* There is no `PATH' in the environment.
00119             The default search path is the current directory
00120             followed by the path `confstr' returns for `_CS_PATH'.  */
00121          path = name + pathlen + len + 1;
00122          path[0] = ':';
00123          (void) confstr (_CS_PATH, path + 1, pathlen);
00124        }
00125 
00126       /* Copy the file name at the top.  */
00127       name = (char *) memcpy (name + pathlen + 1, file, len);
00128       /* And add the slash.  */
00129       *--name = '/';
00130 
00131       char **script_argv = NULL;
00132       void *script_argv_malloc = NULL;
00133       bool got_eacces = false;
00134       char *p = path;
00135       do
00136        {
00137          char *startp;
00138 
00139          path = p;
00140          p = __strchrnul (path, ':');
00141 
00142          if (p == path)
00143            /* Two adjacent colons, or a colon at the beginning or the end
00144               of `PATH' means to search the current directory.  */
00145            startp = name + 1;
00146          else
00147            startp = (char *) memcpy (name - (p - path), path, p - path);
00148 
00149          /* Try to execute this name.  If it works, execve will not return. */
00150          __execve (startp, argv, __environ);
00151 
00152          if (errno == ENOEXEC)
00153            {
00154              if (script_argv == NULL)
00155               {
00156                 /* Count the arguments.  */
00157                 int argc = 0;
00158                 while (argv[argc++])
00159                   ;
00160                 size_t arglen = (argc + 1) * sizeof (char *);
00161                 if (__libc_use_alloca (alloclen + arglen))
00162                   script_argv = alloca (arglen);
00163                 else
00164                   script_argv = script_argv_malloc = malloc (arglen);
00165                 if (script_argv == NULL)
00166                   {
00167                     /* A possible EACCES error is not as important as
00168                       the ENOMEM.  */
00169                     got_eacces = false;
00170                     break;
00171                   }
00172                 scripts_argv (startp, argv, argc, script_argv);
00173               }
00174 
00175              __execve (script_argv[0], script_argv, __environ);
00176            }
00177 
00178          switch (errno)
00179            {
00180            case EACCES:
00181              /* Record the we got a `Permission denied' error.  If we end
00182                up finding no executable we can use, we want to diagnose
00183                that we did find one but were denied access.  */
00184              got_eacces = true;
00185            case ENOENT:
00186            case ESTALE:
00187            case ENOTDIR:
00188              /* Those errors indicate the file is missing or not executable
00189                by us, in which case we want to just try the next path
00190                directory.  */
00191            case ENODEV:
00192            case ETIMEDOUT:
00193              /* Some strange filesystems like AFS return even
00194                stranger error numbers.  They cannot reasonably mean
00195                anything else so ignore those, too.  */
00196              break;
00197 
00198            default:
00199              /* Some other error means we found an executable file, but
00200                something went wrong executing it; return the error to our
00201                caller.  */
00202              return -1;
00203            }
00204        }
00205       while (*p++ != '\0');
00206 
00207       /* We tried every element and none of them worked.  */
00208       if (got_eacces)
00209        /* At least one failure was due to permissions, so report that
00210           error.  */
00211        __set_errno (EACCES);
00212 
00213       free (script_argv_malloc);
00214       free (path_malloc);
00215     }
00216 
00217   /* Return the error from the last attempt (probably ENOENT).  */
00218   return -1;
00219 }
00220 libc_hidden_def (execvp)