freebsd/libzfs: import execvPe() from FreeBSD 13

It allocates less and properly deals with argv={NULL}

With minor cosmetic changes to match cstyle, remove whitespace damage,
and restore direct string printing

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Ryan Moeller <ryan@ixsystems.com>
Reviewed-by: Tony Nguyen <tony.nguyen@delphix.com>
Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
Closes #12051
This commit is contained in:
наб 2021-05-26 19:03:47 +02:00 committed by GitHub
parent f172c3088f
commit 671ea40f62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 42 additions and 19 deletions

View File

@ -52,8 +52,8 @@ execvPe(const char *name, const char *path, char * const *argv,
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;
@ -61,7 +61,7 @@ execvPe(const char *name, const char *path, char * const *argv,
/* If it's an absolute or relative path name, it's easy. */
if (strchr(name, '/')) {
bp = name;
cur = NULL;
op = NULL;
goto retry;
}
bp = buf;
@ -72,23 +72,30 @@ execvPe(const char *name, const char *path, char * const *argv,
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
@ -118,15 +125,31 @@ retry: (void) execve(bp, argv, envp);
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 *));
execve(_PATH_BSHELL, __DECONST(char **, memp), envp);
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;
case ENOMEM:
goto done;