1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
/*
* 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;
}
|