Loading...
--- Libc/Libc-763.13/gen/FreeBSD/exec.c
+++ Libc/Libc-1725.40.4/gen/FreeBSD/exec.c
@@ -1,4 +1,6 @@
/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -10,7 +12,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
@@ -35,7 +37,6 @@
#include "namespace.h"
#include <sys/param.h>
-#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
@@ -48,7 +49,14 @@
#include "un-namespace.h"
#include "libc_private.h"
-extern char **environ;
+#include <crt_externs.h>
+#define environ (*_NSGetEnviron())
+
+static const char execvPe_err_preamble[] = "execvP: ";
+static const char execvPe_err_trailer[] = ": path too long\n";
+
+int
+_execvpe(const char *name, char * const argv[], char * const envp[]);
int
execl(const char *name, const char *arg, ...)
@@ -131,9 +139,7 @@
}
int
-execv(name, argv)
- const char *name;
- char * const *argv;
+execv(const char *name, char * const *argv)
{
(void)_execve(name, argv, environ);
return (-1);
@@ -152,16 +158,20 @@
const char **memp;
size_t cnt, lp, ln;
int eacces, save_errno;
- char *cur, buf[MAXPATHLEN];
- const char *p, *bp;
+ char buf[MAXPATHLEN];
+ const char *bp, *np, *op, *p;
struct stat sb;
eacces = 0;
/* If it's an absolute or relative path name, it's easy. */
- if (index(name, '/')) {
+ if (strchr(name, '/')) {
bp = name;
- cur = NULL;
+#ifdef __APPLE__
+ /* Used to differentiate PATH search vs. not afterwards. */
+ path = NULL;
+#endif
+ op = NULL;
goto retry;
}
bp = buf;
@@ -172,23 +182,30 @@
return (-1);
}
- cur = alloca(strlen(path) + 1);
- if (cur == NULL) {
- errno = ENOMEM;
- return (-1);
- }
- strcpy(cur, path);
- while ((p = strsep(&cur, ":")) != NULL) {
+ op = path;
+ ln = strlen(name);
+ while (op != NULL) {
+ np = strchrnul(op, ':');
+
/*
* It's a SHELL path -- double, leading and trailing colons
* mean the current directory.
*/
- if (*p == '\0') {
+ if (np == op) {
+ /* Empty component. */
p = ".";
lp = 1;
- } else
- lp = strlen(p);
- ln = strlen(name);
+ } else {
+ /* Non-empty component. */
+ p = op;
+ lp = np - op;
+ }
+
+ /* Advance to the next component or terminate after this. */
+ if (*np == '\0')
+ op = NULL;
+ else
+ op = np + 1;
/*
* If the path is too long complain. This is a possible
@@ -196,10 +213,11 @@
* the user may execute the wrong program.
*/
if (lp + ln + 2 > sizeof(buf)) {
- (void)_write(STDERR_FILENO, "execvP: ", 8);
+ (void)_write(STDERR_FILENO, execvPe_err_preamble,
+ sizeof(execvPe_err_preamble) - 1);
(void)_write(STDERR_FILENO, p, lp);
- (void)_write(STDERR_FILENO, ": path too long\n",
- 16);
+ (void)_write(STDERR_FILENO, execvPe_err_trailer,
+ sizeof(execvPe_err_trailer) - 1);
continue;
}
bcopy(p, buf, lp);
@@ -218,14 +236,28 @@
case ENOEXEC:
for (cnt = 0; argv[cnt]; ++cnt)
;
- memp = alloca((cnt + 2) * sizeof(char *));
+
+ /*
+ * cnt may be 0 above; always allocate at least
+ * 3 entries so that we can at least fit "sh", bp, and
+ * the NULL terminator. We can rely on cnt to take into
+ * account the NULL terminator in all other scenarios,
+ * as we drop argv[0].
+ */
+ memp = alloca(MAX(3, cnt + 2) * sizeof(char *));
if (memp == NULL) {
/* errno = ENOMEM; XXX override ENOEXEC? */
goto done;
}
- memp[0] = "sh";
- memp[1] = bp;
- bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
+ if (cnt > 0) {
+ memp[0] = argv[0];
+ memp[1] = bp;
+ bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
+ } else {
+ memp[0] = "sh";
+ memp[1] = bp;
+ memp[2] = NULL;
+ }
(void)_execve(_PATH_BSHELL,
__DECONST(char **, memp), envp);
goto done;
@@ -257,10 +289,22 @@
goto done;
}
}
+
if (eacces)
errno = EACCES;
+#ifdef __APPLE__
+ /*
+ * Preserve errno from execve(2) if it wasn't a PATH search, or
+ * if it was a PATH search and we bailed out early. Note that every
+ * branch in the loop jumps to the `done` label to preserve errno, so
+ * this is more of a defensive check.
+ */
+ else if (path != NULL && op == NULL)
+#else
else
+#endif
errno = ENOENT;
+ /* else use existing errno from _execve */
done:
return (-1);
}
@@ -271,7 +315,7 @@
return execvPe(name, path, argv, environ);
}
-int
+__private_extern__ int
_execvpe(const char *name, char * const argv[], char * const envp[])
{
const char *path;