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; const char **memp;
size_t cnt, lp, ln; size_t cnt, lp, ln;
int eacces, save_errno; int eacces, save_errno;
char *cur, buf[MAXPATHLEN]; char buf[MAXPATHLEN];
const char *p, *bp; const char *bp, *np, *op, *p;
struct stat sb; struct stat sb;
eacces = 0; 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 it's an absolute or relative path name, it's easy. */
if (strchr(name, '/')) { if (strchr(name, '/')) {
bp = name; bp = name;
cur = NULL; op = NULL;
goto retry; goto retry;
} }
bp = buf; bp = buf;
@ -72,23 +72,30 @@ execvPe(const char *name, const char *path, char * const *argv,
return (-1); return (-1);
} }
cur = alloca(strlen(path) + 1); op = path;
if (cur == NULL) { ln = strlen(name);
errno = ENOMEM; while (op != NULL) {
return (-1); np = strchrnul(op, ':');
}
strcpy(cur, path);
while ((p = strsep(&cur, ":")) != NULL) {
/* /*
* It's a SHELL path -- double, leading and trailing colons * It's a SHELL path -- double, leading and trailing colons
* mean the current directory. * mean the current directory.
*/ */
if (*p == '\0') { if (np == op) {
/* Empty component. */
p = "."; p = ".";
lp = 1; lp = 1;
} else } else {
lp = strlen(p); /* Non-empty component. */
ln = strlen(name); 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 * If the path is too long complain. This is a possible
@ -118,15 +125,31 @@ retry: (void) execve(bp, argv, envp);
case ENOEXEC: case ENOEXEC:
for (cnt = 0; argv[cnt]; ++cnt) 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) { if (memp == NULL) {
/* errno = ENOMEM; XXX override ENOEXEC? */ /* errno = ENOMEM; XXX override ENOEXEC? */
goto done; goto done;
} }
memp[0] = "sh"; if (cnt > 0) {
memp[1] = bp; memp[0] = argv[0];
bcopy(argv + 1, memp + 2, cnt * sizeof (char *)); memp[1] = bp;
execve(_PATH_BSHELL, __DECONST(char **, memp), envp); 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; goto done;
case ENOMEM: case ENOMEM:
goto done; goto done;