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:
parent
f172c3088f
commit
671ea40f62
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue