summaryrefslogtreecommitdiffstats
path: root/usr/klibc/execvpe.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/klibc/execvpe.c')
-rw-r--r--usr/klibc/execvpe.c75
1 files changed, 75 insertions, 0 deletions
diff --git a/usr/klibc/execvpe.c b/usr/klibc/execvpe.c
new file mode 100644
index 0000000..0b844f2
--- /dev/null
+++ b/usr/klibc/execvpe.c
@@ -0,0 +1,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;
+}