diff options
author | Ron Yorston <rmy@pobox.com> | 2018-12-15 15:01:53 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2018-12-15 15:39:28 +0000 |
commit | 65189dacb44708743313c81ec1ccaff87a68be8d (patch) | |
tree | b1330575c61bce5adc7d5be815490ac7cb431852 | |
parent | a236242374daf911a01e998fabb1cc1268b2be7b (diff) | |
download | busybox-w32-65189dacb44708743313c81ec1ccaff87a68be8d.tar.gz busybox-w32-65189dacb44708743313c81ec1ccaff87a68be8d.tar.bz2 busybox-w32-65189dacb44708743313c81ec1ccaff87a68be8d.zip |
ash: fix local PATH assignments
The previous commit included code to use PATH values assigned to
local variables:
PATH=/new/path:$PATH new_binary
It didn't work in the case when no fork was needed, for example:
(PATH=/new/path:$PATH new_binary)
because the call to listsetvar() freed the PATH value that was
passed to shellexec(). The forking case only worked because the
spawn_forkshell() mechanism in busybox-w32 didn't allow the PATH
value to be freed.
Rewrite the code so it works whether or not a fork is needed. The
code would also work on POSIX systems.
A cleaner solution could be extracted from dash commit cbb71a8
'eval: Add assignment built-in support again' but neither that nor
the current patch are suitable for submission to upstream BusyBox.
This one is preferred because it requires fewer changes from
upstream.
-rw-r--r-- | shell/ash.c | 27 |
1 files changed, 20 insertions, 7 deletions
diff --git a/shell/ash.c b/shell/ash.c index a659fd703..5195a8557 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -10531,6 +10531,9 @@ evalcommand(union node *cmd, int flags) | |||
10531 | int status; | 10531 | int status; |
10532 | char **nargv; | 10532 | char **nargv; |
10533 | smallint cmd_is_exec; | 10533 | smallint cmd_is_exec; |
10534 | #if ENABLE_PLATFORM_MINGW32 | ||
10535 | int cmdpath; | ||
10536 | #endif | ||
10534 | 10537 | ||
10535 | errlinno = lineno = cmd->ncmd.linno; | 10538 | errlinno = lineno = cmd->ncmd.linno; |
10536 | if (funcline) | 10539 | if (funcline) |
@@ -10599,6 +10602,7 @@ evalcommand(union node *cmd, int flags) | |||
10599 | } | 10602 | } |
10600 | status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2); | 10603 | status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2); |
10601 | 10604 | ||
10605 | #if !ENABLE_PLATFORM_MINGW32 | ||
10602 | path = vpath.var_text; | 10606 | path = vpath.var_text; |
10603 | for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) { | 10607 | for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) { |
10604 | struct strlist **spp; | 10608 | struct strlist **spp; |
@@ -10615,14 +10619,17 @@ evalcommand(union node *cmd, int flags) | |||
10615 | */ | 10619 | */ |
10616 | p = (*spp)->text; | 10620 | p = (*spp)->text; |
10617 | if (varcmp(p, path) == 0) | 10621 | if (varcmp(p, path) == 0) |
10618 | #if !ENABLE_PLATFORM_MINGW32 | ||
10619 | path = p; | 10622 | path = p; |
10623 | } | ||
10620 | #else | 10624 | #else |
10621 | /* fix_pathvar may have modified the value of the local | 10625 | /* Set path after any local PATH= has been processed. */ |
10622 | * variable so we look it up again */ | 10626 | for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) { |
10623 | path = vpath.var_text; | 10627 | struct strlist **spp = varlist.lastp; |
10624 | #endif | 10628 | expandarg(argp, &varlist, EXP_VARTILDE); |
10629 | mklocal((*spp)->text); | ||
10625 | } | 10630 | } |
10631 | path = vpath.var_text; | ||
10632 | #endif | ||
10626 | 10633 | ||
10627 | /* Print the command if xflag is set. */ | 10634 | /* Print the command if xflag is set. */ |
10628 | if (xflag) { | 10635 | if (xflag) { |
@@ -10780,7 +10787,13 @@ evalcommand(union node *cmd, int flags) | |||
10780 | TRACE(("forked child exited with %d\n", status)); | 10787 | TRACE(("forked child exited with %d\n", status)); |
10781 | break; | 10788 | break; |
10782 | } | 10789 | } |
10783 | /* goes through to shellexec() */ | 10790 | /* If we're running 'command -p' we need to use the value stored |
10791 | * in path by parse_command_args(). If PATH is a local variable | ||
10792 | * listsetvar() will free the value currently in path so we need | ||
10793 | * to fetch the updated version. */ | ||
10794 | cmdpath = (path != pathval()); | ||
10795 | listsetvar(varlist.list, VEXPORT|VSTACK); | ||
10796 | shellexec(argv[0], argv, cmdpath ? path : pathval(), cmdentry.u.index); | ||
10784 | #else | 10797 | #else |
10785 | if (!(flags & EV_EXIT) || may_have_traps) { | 10798 | if (!(flags & EV_EXIT) || may_have_traps) { |
10786 | /* No, forking off a child is necessary */ | 10799 | /* No, forking off a child is necessary */ |
@@ -10798,9 +10811,9 @@ evalcommand(union node *cmd, int flags) | |||
10798 | FORCE_INT_ON; | 10811 | FORCE_INT_ON; |
10799 | /* fall through to exec'ing external program */ | 10812 | /* fall through to exec'ing external program */ |
10800 | } | 10813 | } |
10801 | #endif | ||
10802 | listsetvar(varlist.list, VEXPORT|VSTACK); | 10814 | listsetvar(varlist.list, VEXPORT|VSTACK); |
10803 | shellexec(argv[0], argv, path, cmdentry.u.index); | 10815 | shellexec(argv[0], argv, path, cmdentry.u.index); |
10816 | #endif | ||
10804 | /* NOTREACHED */ | 10817 | /* NOTREACHED */ |
10805 | } /* default */ | 10818 | } /* default */ |
10806 | case CMDBUILTIN: | 10819 | case CMDBUILTIN: |