aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shell/ash.c45
-rw-r--r--shell/ash_test/ash-standalone/nofork_env.right9
-rwxr-xr-xshell/ash_test/ash-standalone/nofork_env.tests15
-rw-r--r--shell/hush_test/hush-standalone/nofork_env.right9
-rwxr-xr-xshell/hush_test/hush-standalone/nofork_env.tests15
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:$?