diff options
-rw-r--r-- | lib/libc/gen/exec.3 | 68 | ||||
-rw-r--r-- | lib/libc/gen/exec.c | 45 |
2 files changed, 87 insertions, 26 deletions
diff --git a/lib/libc/gen/exec.3 b/lib/libc/gen/exec.3 index 2ac124b..66541ad 100644 --- a/lib/libc/gen/exec.3 +++ b/lib/libc/gen/exec.3 @@ -30,6 +30,7 @@ .\" SUCH DAMAGE. .\" .\" @(#)exec.3 8.3 (Berkeley) 1/24/94 +.\" $Id$ .\" .Dd January 24, 1994 .Dt EXEC 3 @@ -147,16 +148,30 @@ is used. In addition, certain errors are treated specially. .Pp -If permission is denied for a file (the attempted +If an error is ambiguous (for simplicity, we shall consider all +errors except +.Er ENOEXEC +as being ambiguous here, although only the critical error +.Er EACCES +is really ambiguous), +then these functions will act as if they stat the file to determine +whether the file exists and has suitable execute permissions. +If it does, they will return immediately with the global variable +.Va errno +restored to the value set by +.Fn execve . +Otherwise, the search will be continued. +If the search completes without performing a successful .Fn execve -returned -.Er EACCES ) , -these functions will continue searching the rest of -the search path. -If no other file is found, however, they will return with the global variable +or terminating due to an error, +these functions will return with the global variable .Va errno set to -.Er EACCES . +.Er EACCES +or +.Er ENOENT +according to whether at least one file with suitable execute permissions +was found. .Pp If the header of a file isn't recognized (the attempted .Fn execve @@ -166,13 +181,6 @@ these functions will execute the shell with the path of the file as its first argument. (If this attempt fails, no further searching is done.) .Pp -If the file is currently busy (the attempted -.Fn execve -returned -.Er ETXTBUSY ) , -these functions will sleep for several seconds, -periodically re-attempting to execute the file. -.Pp The function .Fn exect executes a file with the program tracing facilities enabled (see @@ -230,8 +238,8 @@ The behavior of .Fn execlp and .Fn execvp -when errors occur while attempting to execute the file is historic -practice, but has not traditionally been documented and is not specified +when errors occur while attempting to execute the file is not quite historic +practice, and has not traditionally been documented and is not specified by the .Tn POSIX standard. @@ -241,11 +249,37 @@ Traditionally, the functions and .Fn execvp ignored all errors except for the ones described above and +.Er ETXTBSY , +upon which they retried after sleeping for several seconds, and .Er ENOMEM and .Er E2BIG , upon which they returned. -They now return if any error other than the ones described above occurs. +They now return for +.Er ETXTBSY , +and determine existence and executability more carefully. +In particular, +.Er EACCES +for inaccessible directories in the path prefix is no longer +confused with +.Er EACCES +for files with unsuitable execute permissions. +In +.Bx 4.4 , +they returned upon all errors except +.Er EACCES , +.Er ENOENT , +.Er ENOEXEC +and +.Er ETXTBSY . +This was inferior to the traditional error handling, +since it it breaks the ignoring of errors for path prefixes +and only improves the handling of the unusual ambiguous error +.Er EFAULT +and the unusual error +.Er EIO . +The behaviour was changed to match the behaviour of +.Xr sh 1 . .Sh STANDARDS .Fn Execl , .Fn execv , diff --git a/lib/libc/gen/exec.c b/lib/libc/gen/exec.c index 72b6db4..c083957 100644 --- a/lib/libc/gen/exec.c +++ b/lib/libc/gen/exec.c @@ -32,11 +32,16 @@ */ #if defined(LIBC_SCCS) && !defined(lint) +#if 0 static char sccsid[] = "@(#)exec.c 8.1 (Berkeley) 6/4/93"; +#endif +static const char rcsid[] = + "$Id$"; #endif /* LIBC_SCCS and not lint */ #include <sys/param.h> #include <sys/types.h> +#include <sys/stat.h> #include <errno.h> #include <unistd.h> #include <stdlib.h> @@ -187,10 +192,11 @@ execvp(name, argv) char **memp; register int cnt, lp, ln; register char *p; - int eacces, etxtbsy; + int eacces, save_errno; char *bp, *cur, *path, buf[MAXPATHLEN]; + struct stat sb; - eacces = etxtbsy = 0; + eacces = 0; /* If it's an absolute or relative path name, it's easy. */ if (index(name, '/')) { @@ -241,9 +247,10 @@ execvp(name, argv) retry: (void)execve(bp, argv, environ); switch(errno) { - case EACCES: - eacces = 1; - break; + case E2BIG: + goto done; + case ELOOP: + case ENAMETOOLONG: case ENOENT: break; case ENOEXEC: @@ -258,17 +265,37 @@ retry: (void)execve(bp, argv, environ); (void)execve(_PATH_BSHELL, memp, environ); free(memp); goto done; + case ENOMEM: + goto done; + case ENOTDIR: + break; case ETXTBSY: - if (etxtbsy < 3) - (void)sleep(++etxtbsy); - goto retry; + /* + * We used to retry here, but sh(1) doesn't. + */ + goto done; default: + /* + * EACCES may be for an inaccessible directory or + * a non-executable file. Call stat() to decide + * which. This also handles ambiguities for EFAULT + * and EIO, and undocumented errors like ESTALE. + * We hope that the race for a stat() is unimportant. + */ + save_errno = errno; + if (stat(argv[0], &sb) != 0) + break; + if (save_errno == EACCES) { + eacces = 1; + continue; + } + errno = save_errno; goto done; } } if (eacces) errno = EACCES; - else if (!errno) + else errno = ENOENT; done: if (path) free(path); |