musl/src/process/execvp.c
Rich Felker 14a0117117 make execvp continue PATH search on EACCES rather than issuing an errror
the specification for execvp itself is unclear as to whether
encountering a file that cannot be executed due to EACCES during the
PATH search is a mandatory error condition; however, XBD 8.3's
specification of the PATH environment variable clarifies that the
search continues until a file with "appropriate execution permissions"
is found.

since it seems undesirable/erroneous to report ENOENT rather than
EACCES when an early path element has a non-executable file and all
later path elements lack any file by the requested name, the new code
stores a flag indicating that EACCES was seen and sets errno back to
EACCES in this case.
2015-02-03 00:31:35 -05:00

56 lines
1.1 KiB
C

#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include "libc.h"
extern char **__environ;
int __execvpe(const char *file, char *const argv[], char *const envp[])
{
const char *p, *z, *path = getenv("PATH");
size_t l, k;
int seen_eacces = 0;
errno = ENOENT;
if (!*file) return -1;
if (strchr(file, '/'))
return execve(file, argv, envp);
if (!path) path = "/usr/local/bin:/bin:/usr/bin";
k = strnlen(file, NAME_MAX+1);
if (k > NAME_MAX) {
errno = ENAMETOOLONG;
return -1;
}
l = strnlen(path, PATH_MAX-1)+1;
for(p=path; ; p=z) {
char b[l+k+1];
z = strchr(p, ':');
if (!z) z = p+strlen(p);
if (z-p >= l) {
if (!*z++) break;
continue;
}
memcpy(b, p, z-p);
b[z-p] = '/';
memcpy(b+(z-p)+(z>p), file, k+1);
execve(b, argv, envp);
if (errno == EACCES) seen_eacces = 1;
else if (errno != ENOENT) return -1;
if (!*z++) break;
}
if (seen_eacces) errno = EACCES;
return -1;
}
int execvp(const char *file, char *const argv[])
{
return __execvpe(file, argv, __environ);
}
weak_alias(__execvpe, execvpe);