From: Denys Vlasenko Date: Fri, 3 Nov 2017 13:16:25 +0000 (+0100) Subject: ash: fix nofork bug where environment is not properly passed to a command X-Git-Tag: 1_28_0~16 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=a5060b8364faa7c677c8950f1315c451403b0660;p=oweals%2Fbusybox.git 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 --- diff --git a/shell/ash.c b/shell/ash.c index 7a0b88c68..e69ddb4ff 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -2380,8 +2380,11 @@ listsetvar(struct strlist *list_set_var, int flags) /* * 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 ** -listvars(int on, int off, char ***end) +listvars(int on, int off, struct strlist *lp, char ***end) { struct var **vpp; struct var *vp; @@ -2394,12 +2397,40 @@ listvars(int on, int off, char ***end) do { for (vp = *vpp; vp; vp = vp->next) { 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()) ep = growstackstr(); *ep++ = (char*)vp->var_text; +#if ENABLE_FEATURE_SH_NOFORK + skip: ; +#endif } } } 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()) ep = growstackstr(); if (end) @@ -7860,7 +7891,7 @@ static void shellexec(char *prog, char **argv, const char *path, int idx) int exerrno; 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 ENABLE_FEATURE_SH_STANDALONE || (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) */ int applet_no = (- cmdentry.u.index - 2); 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 _main(). * 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: * for example, "yes" or "rm" (rm -i waits for input). */ - INT_OFF; status = run_nofork_applet(applet_no, argv); + environ = sv_environ; /* * Try enabling NOFORK for "yes" applet. * ^C _will_ stop it (write returns EINTR), @@ -10854,7 +10889,7 @@ showvars(const char *sep_prefix, int on, int off) const char *sep; char **ep, **epend; - ep = listvars(on, off, &epend); + ep = listvars(on, off, /*strlist:*/ NULL, &epend); qsort(ep, epend - ep, sizeof(char *), vpcmp); sep = *sep_prefix ? " " : sep_prefix; diff --git a/shell/ash_test/ash-standalone/nofork_env.right b/shell/ash_test/ash-standalone/nofork_env.right new file mode 100644 index 000000000..3f16ff458 --- /dev/null +++ b/shell/ash_test/ash-standalone/nofork_env.right @@ -0,0 +1,9 @@ +ZVAR=1 +ZVAR=2 +ZVAR=3 +ZVAR=4 +ZVAR=5 +ZVAR=6 +ZVAR=7 +ZVAR=8 +Ok:0 diff --git a/shell/ash_test/ash-standalone/nofork_env.tests b/shell/ash_test/ash-standalone/nofork_env.tests new file mode 100755 index 000000000..111e564d2 --- /dev/null +++ b/shell/ash_test/ash-standalone/nofork_env.tests @@ -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:$? diff --git a/shell/hush_test/hush-standalone/nofork_env.right b/shell/hush_test/hush-standalone/nofork_env.right new file mode 100644 index 000000000..3f16ff458 --- /dev/null +++ b/shell/hush_test/hush-standalone/nofork_env.right @@ -0,0 +1,9 @@ +ZVAR=1 +ZVAR=2 +ZVAR=3 +ZVAR=4 +ZVAR=5 +ZVAR=6 +ZVAR=7 +ZVAR=8 +Ok:0 diff --git a/shell/hush_test/hush-standalone/nofork_env.tests b/shell/hush_test/hush-standalone/nofork_env.tests new file mode 100755 index 000000000..111e564d2 --- /dev/null +++ b/shell/hush_test/hush-standalone/nofork_env.tests @@ -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:$?