blob: 0b844f23ba5663a873a379656f371ebe472be1eb [file] [log] [blame]
/*
* execvpe.c
*
* execvpe() function (from which we build execlp, execlpe, execvp).
*
* This version of execvpe() will *not* spawn /bin/sh if the command
* return ENOEXEC. That's what #! is for, folks!
*
* Since execlpe() and execvpe() aren't in POSIX, nor in glibc,
* I have followed QNX precedent in the implementation of the PATH:
* the PATH that is used is the one in the current environment, not
* in the new environment. Otherwise it would be impossible to pass
* a different PATH to the new process than the one one would want to
* use to search.
*/
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#define DEFAULT_PATH "/bin:/usr/bin:."
int execvpe(const char *file, char *const *argv, char *const *envp)
{
char path[PATH_MAX];
const char *searchpath, *esp;
size_t prefixlen, filelen, totallen;
if (strchr(file, '/')) /* Specific path */
return execve(file, argv, envp);
filelen = strlen(file);
searchpath = getenv("PATH");
if (!searchpath)
searchpath = DEFAULT_PATH;
errno = ENOENT; /* Default errno, if execve() doesn't
change it */
do {
esp = strchr(searchpath, ':');
if (esp)
prefixlen = esp - searchpath;
else
prefixlen = strlen(searchpath);
if (prefixlen == 0 || searchpath[prefixlen - 1] == '/') {
totallen = prefixlen + filelen;
if (totallen >= PATH_MAX)
continue;
memcpy(path, searchpath, prefixlen);
memcpy(path + prefixlen, file, filelen);
} else {
totallen = prefixlen + filelen + 1;
if (totallen >= PATH_MAX)
continue;
memcpy(path, searchpath, prefixlen);
path[prefixlen] = '/';
memcpy(path + prefixlen + 1, file, filelen);
}
path[totallen] = '\0';
execve(path, argv, envp);
if (errno == E2BIG || errno == ENOEXEC ||
errno == ENOMEM || errno == ETXTBSY)
break; /* Report this as an error, no more search */
searchpath = esp + 1;
} while (esp);
return -1;
}