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 /shell | |
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.
Diffstat (limited to 'shell')
-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: |