ash: fix nofork bug where environment is not properly passed to a command
function old new delta listvars 144 252 +108 evalcommand 1500 1546 +46 showvars 142 147 +5 shellexec 242 245 +3 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 4/0 up/down: 162/0) Total: 162 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
f5e8b42788
commit
a5060b8364
45
shell/ash.c
45
shell/ash.c
@ -2380,8 +2380,11 @@ listsetvar(struct strlist *list_set_var, int flags)
|
|||||||
/*
|
/*
|
||||||
* Generate a list of variables satisfying the given conditions.
|
* Generate a list of variables satisfying the given conditions.
|
||||||
*/
|
*/
|
||||||
|
#if !ENABLE_FEATURE_SH_NOFORK
|
||||||
|
# define listvars(on, off, lp, end) listvars(on, off, end)
|
||||||
|
#endif
|
||||||
static char **
|
static char **
|
||||||
listvars(int on, int off, char ***end)
|
listvars(int on, int off, struct strlist *lp, char ***end)
|
||||||
{
|
{
|
||||||
struct var **vpp;
|
struct var **vpp;
|
||||||
struct var *vp;
|
struct var *vp;
|
||||||
@ -2394,12 +2397,40 @@ listvars(int on, int off, char ***end)
|
|||||||
do {
|
do {
|
||||||
for (vp = *vpp; vp; vp = vp->next) {
|
for (vp = *vpp; vp; vp = vp->next) {
|
||||||
if ((vp->flags & mask) == on) {
|
if ((vp->flags & mask) == on) {
|
||||||
|
#if ENABLE_FEATURE_SH_NOFORK
|
||||||
|
/* If variable with the same name is both
|
||||||
|
* exported and temporarily set for a command:
|
||||||
|
* export ZVAR=5
|
||||||
|
* ZVAR=6 printenv
|
||||||
|
* then "ZVAR=6" will be both in vartab and
|
||||||
|
* lp lists. Do not pass it twice to printenv.
|
||||||
|
*/
|
||||||
|
struct strlist *lp1 = lp;
|
||||||
|
while (lp1) {
|
||||||
|
if (strcmp(lp1->text, vp->var_text) == 0)
|
||||||
|
goto skip;
|
||||||
|
lp1 = lp1->next;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (ep == stackstrend())
|
if (ep == stackstrend())
|
||||||
ep = growstackstr();
|
ep = growstackstr();
|
||||||
*ep++ = (char*)vp->var_text;
|
*ep++ = (char*)vp->var_text;
|
||||||
|
#if ENABLE_FEATURE_SH_NOFORK
|
||||||
|
skip: ;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (++vpp < vartab + VTABSIZE);
|
} while (++vpp < vartab + VTABSIZE);
|
||||||
|
|
||||||
|
#if ENABLE_FEATURE_SH_NOFORK
|
||||||
|
while (lp) {
|
||||||
|
if (ep == stackstrend())
|
||||||
|
ep = growstackstr();
|
||||||
|
*ep++ = lp->text;
|
||||||
|
lp = lp->next;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (ep == stackstrend())
|
if (ep == stackstrend())
|
||||||
ep = growstackstr();
|
ep = growstackstr();
|
||||||
if (end)
|
if (end)
|
||||||
@ -7860,7 +7891,7 @@ static void shellexec(char *prog, char **argv, const char *path, int idx)
|
|||||||
int exerrno;
|
int exerrno;
|
||||||
int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
|
int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
|
||||||
|
|
||||||
envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
|
envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL);
|
||||||
if (strchr(prog, '/') != NULL
|
if (strchr(prog, '/') != NULL
|
||||||
#if ENABLE_FEATURE_SH_STANDALONE
|
#if ENABLE_FEATURE_SH_STANDALONE
|
||||||
|| (applet_no = find_applet_by_name(prog)) >= 0
|
|| (applet_no = find_applet_by_name(prog)) >= 0
|
||||||
@ -9930,7 +9961,11 @@ evalcommand(union node *cmd, int flags)
|
|||||||
/* find_command() encodes applet_no as (-2 - applet_no) */
|
/* find_command() encodes applet_no as (-2 - applet_no) */
|
||||||
int applet_no = (- cmdentry.u.index - 2);
|
int applet_no = (- cmdentry.u.index - 2);
|
||||||
if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
|
if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
|
||||||
listsetvar(varlist.list, VEXPORT|VSTACK);
|
char **sv_environ;
|
||||||
|
|
||||||
|
INT_OFF;
|
||||||
|
sv_environ = environ;
|
||||||
|
environ = listvars(VEXPORT, VUNSET, varlist.list, /*end:*/ NULL);
|
||||||
/*
|
/*
|
||||||
* Run <applet>_main().
|
* Run <applet>_main().
|
||||||
* Signals (^C) can't interrupt here.
|
* Signals (^C) can't interrupt here.
|
||||||
@ -9939,8 +9974,8 @@ evalcommand(union node *cmd, int flags)
|
|||||||
* and/or wait for user input ineligible for NOFORK:
|
* and/or wait for user input ineligible for NOFORK:
|
||||||
* for example, "yes" or "rm" (rm -i waits for input).
|
* for example, "yes" or "rm" (rm -i waits for input).
|
||||||
*/
|
*/
|
||||||
INT_OFF;
|
|
||||||
status = run_nofork_applet(applet_no, argv);
|
status = run_nofork_applet(applet_no, argv);
|
||||||
|
environ = sv_environ;
|
||||||
/*
|
/*
|
||||||
* Try enabling NOFORK for "yes" applet.
|
* Try enabling NOFORK for "yes" applet.
|
||||||
* ^C _will_ stop it (write returns EINTR),
|
* ^C _will_ stop it (write returns EINTR),
|
||||||
@ -10854,7 +10889,7 @@ showvars(const char *sep_prefix, int on, int off)
|
|||||||
const char *sep;
|
const char *sep;
|
||||||
char **ep, **epend;
|
char **ep, **epend;
|
||||||
|
|
||||||
ep = listvars(on, off, &epend);
|
ep = listvars(on, off, /*strlist:*/ NULL, &epend);
|
||||||
qsort(ep, epend - ep, sizeof(char *), vpcmp);
|
qsort(ep, epend - ep, sizeof(char *), vpcmp);
|
||||||
|
|
||||||
sep = *sep_prefix ? " " : sep_prefix;
|
sep = *sep_prefix ? " " : sep_prefix;
|
||||||
|
9
shell/ash_test/ash-standalone/nofork_env.right
Normal file
9
shell/ash_test/ash-standalone/nofork_env.right
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
ZVAR=1
|
||||||
|
ZVAR=2
|
||||||
|
ZVAR=3
|
||||||
|
ZVAR=4
|
||||||
|
ZVAR=5
|
||||||
|
ZVAR=6
|
||||||
|
ZVAR=7
|
||||||
|
ZVAR=8
|
||||||
|
Ok:0
|
15
shell/ash_test/ash-standalone/nofork_env.tests
Executable file
15
shell/ash_test/ash-standalone/nofork_env.tests
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
# ash had a bug where NOFORKed applet (env/printenv) was not seeing new exported variables
|
||||||
|
|
||||||
|
(export ZVAR=1; printenv) | grep ^ZVAR=
|
||||||
|
(ZVAR=2 printenv) | grep ^ZVAR=
|
||||||
|
|
||||||
|
(export ZVAR=3; env) | grep ^ZVAR=
|
||||||
|
(ZVAR=4 env) | grep ^ZVAR=
|
||||||
|
|
||||||
|
export ZVAR=5; printenv | grep ^ZVAR=
|
||||||
|
ZVAR=6 printenv | grep ^ZVAR=
|
||||||
|
|
||||||
|
export ZVAR=7; env | grep ^ZVAR=
|
||||||
|
ZVAR=8 env | grep ^ZVAR=
|
||||||
|
|
||||||
|
echo Ok:$?
|
9
shell/hush_test/hush-standalone/nofork_env.right
Normal file
9
shell/hush_test/hush-standalone/nofork_env.right
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
ZVAR=1
|
||||||
|
ZVAR=2
|
||||||
|
ZVAR=3
|
||||||
|
ZVAR=4
|
||||||
|
ZVAR=5
|
||||||
|
ZVAR=6
|
||||||
|
ZVAR=7
|
||||||
|
ZVAR=8
|
||||||
|
Ok:0
|
15
shell/hush_test/hush-standalone/nofork_env.tests
Executable file
15
shell/hush_test/hush-standalone/nofork_env.tests
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
# ash had a bug where NOFORKed applet (env/printenv) was not seeing new exported variables
|
||||||
|
|
||||||
|
(export ZVAR=1; printenv) | grep ^ZVAR=
|
||||||
|
(ZVAR=2 printenv) | grep ^ZVAR=
|
||||||
|
|
||||||
|
(export ZVAR=3; env) | grep ^ZVAR=
|
||||||
|
(ZVAR=4 env) | grep ^ZVAR=
|
||||||
|
|
||||||
|
export ZVAR=5; printenv | grep ^ZVAR=
|
||||||
|
ZVAR=6 printenv | grep ^ZVAR=
|
||||||
|
|
||||||
|
export ZVAR=7; env | grep ^ZVAR=
|
||||||
|
ZVAR=8 env | grep ^ZVAR=
|
||||||
|
|
||||||
|
echo Ok:$?
|
Loading…
Reference in New Issue
Block a user