diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2017-11-03 14:16:25 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2017-11-03 14:16:25 +0100 |
commit | a5060b8364faa7c677c8950f1315c451403b0660 (patch) | |
tree | f62638268fb4edd79cd1a062d63092df1a5b4513 /shell | |
parent | f5e8b4278822f2413bf7e47466f55cc1a0fcca9a (diff) |
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>
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash.c | 45 | ||||
-rw-r--r-- | shell/ash_test/ash-standalone/nofork_env.right | 9 | ||||
-rwxr-xr-x | shell/ash_test/ash-standalone/nofork_env.tests | 15 | ||||
-rw-r--r-- | shell/hush_test/hush-standalone/nofork_env.right | 9 | ||||
-rwxr-xr-x | shell/hush_test/hush-standalone/nofork_env.tests | 15 |
5 files changed, 88 insertions, 5 deletions
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 <applet>_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:$? |