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 | |
parent | f5e8b4278822f2413bf7e47466f55cc1a0fcca9a (diff) | |
download | busybox-w32-a5060b8364faa7c677c8950f1315c451403b0660.tar.gz busybox-w32-a5060b8364faa7c677c8950f1315c451403b0660.tar.bz2 busybox-w32-a5060b8364faa7c677c8950f1315c451403b0660.zip |
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>
-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) | |||
2380 | /* | 2380 | /* |
2381 | * Generate a list of variables satisfying the given conditions. | 2381 | * Generate a list of variables satisfying the given conditions. |
2382 | */ | 2382 | */ |
2383 | #if !ENABLE_FEATURE_SH_NOFORK | ||
2384 | # define listvars(on, off, lp, end) listvars(on, off, end) | ||
2385 | #endif | ||
2383 | static char ** | 2386 | static char ** |
2384 | listvars(int on, int off, char ***end) | 2387 | listvars(int on, int off, struct strlist *lp, char ***end) |
2385 | { | 2388 | { |
2386 | struct var **vpp; | 2389 | struct var **vpp; |
2387 | struct var *vp; | 2390 | struct var *vp; |
@@ -2394,12 +2397,40 @@ listvars(int on, int off, char ***end) | |||
2394 | do { | 2397 | do { |
2395 | for (vp = *vpp; vp; vp = vp->next) { | 2398 | for (vp = *vpp; vp; vp = vp->next) { |
2396 | if ((vp->flags & mask) == on) { | 2399 | if ((vp->flags & mask) == on) { |
2400 | #if ENABLE_FEATURE_SH_NOFORK | ||
2401 | /* If variable with the same name is both | ||
2402 | * exported and temporarily set for a command: | ||
2403 | * export ZVAR=5 | ||
2404 | * ZVAR=6 printenv | ||
2405 | * then "ZVAR=6" will be both in vartab and | ||
2406 | * lp lists. Do not pass it twice to printenv. | ||
2407 | */ | ||
2408 | struct strlist *lp1 = lp; | ||
2409 | while (lp1) { | ||
2410 | if (strcmp(lp1->text, vp->var_text) == 0) | ||
2411 | goto skip; | ||
2412 | lp1 = lp1->next; | ||
2413 | } | ||
2414 | #endif | ||
2397 | if (ep == stackstrend()) | 2415 | if (ep == stackstrend()) |
2398 | ep = growstackstr(); | 2416 | ep = growstackstr(); |
2399 | *ep++ = (char*)vp->var_text; | 2417 | *ep++ = (char*)vp->var_text; |
2418 | #if ENABLE_FEATURE_SH_NOFORK | ||
2419 | skip: ; | ||
2420 | #endif | ||
2400 | } | 2421 | } |
2401 | } | 2422 | } |
2402 | } while (++vpp < vartab + VTABSIZE); | 2423 | } while (++vpp < vartab + VTABSIZE); |
2424 | |||
2425 | #if ENABLE_FEATURE_SH_NOFORK | ||
2426 | while (lp) { | ||
2427 | if (ep == stackstrend()) | ||
2428 | ep = growstackstr(); | ||
2429 | *ep++ = lp->text; | ||
2430 | lp = lp->next; | ||
2431 | } | ||
2432 | #endif | ||
2433 | |||
2403 | if (ep == stackstrend()) | 2434 | if (ep == stackstrend()) |
2404 | ep = growstackstr(); | 2435 | ep = growstackstr(); |
2405 | if (end) | 2436 | if (end) |
@@ -7860,7 +7891,7 @@ static void shellexec(char *prog, char **argv, const char *path, int idx) | |||
7860 | int exerrno; | 7891 | int exerrno; |
7861 | int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ | 7892 | int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ |
7862 | 7893 | ||
7863 | envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); | 7894 | envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL); |
7864 | if (strchr(prog, '/') != NULL | 7895 | if (strchr(prog, '/') != NULL |
7865 | #if ENABLE_FEATURE_SH_STANDALONE | 7896 | #if ENABLE_FEATURE_SH_STANDALONE |
7866 | || (applet_no = find_applet_by_name(prog)) >= 0 | 7897 | || (applet_no = find_applet_by_name(prog)) >= 0 |
@@ -9930,7 +9961,11 @@ evalcommand(union node *cmd, int flags) | |||
9930 | /* find_command() encodes applet_no as (-2 - applet_no) */ | 9961 | /* find_command() encodes applet_no as (-2 - applet_no) */ |
9931 | int applet_no = (- cmdentry.u.index - 2); | 9962 | int applet_no = (- cmdentry.u.index - 2); |
9932 | if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) { | 9963 | if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) { |
9933 | listsetvar(varlist.list, VEXPORT|VSTACK); | 9964 | char **sv_environ; |
9965 | |||
9966 | INT_OFF; | ||
9967 | sv_environ = environ; | ||
9968 | environ = listvars(VEXPORT, VUNSET, varlist.list, /*end:*/ NULL); | ||
9934 | /* | 9969 | /* |
9935 | * Run <applet>_main(). | 9970 | * Run <applet>_main(). |
9936 | * Signals (^C) can't interrupt here. | 9971 | * Signals (^C) can't interrupt here. |
@@ -9939,8 +9974,8 @@ evalcommand(union node *cmd, int flags) | |||
9939 | * and/or wait for user input ineligible for NOFORK: | 9974 | * and/or wait for user input ineligible for NOFORK: |
9940 | * for example, "yes" or "rm" (rm -i waits for input). | 9975 | * for example, "yes" or "rm" (rm -i waits for input). |
9941 | */ | 9976 | */ |
9942 | INT_OFF; | ||
9943 | status = run_nofork_applet(applet_no, argv); | 9977 | status = run_nofork_applet(applet_no, argv); |
9978 | environ = sv_environ; | ||
9944 | /* | 9979 | /* |
9945 | * Try enabling NOFORK for "yes" applet. | 9980 | * Try enabling NOFORK for "yes" applet. |
9946 | * ^C _will_ stop it (write returns EINTR), | 9981 | * ^C _will_ stop it (write returns EINTR), |
@@ -10854,7 +10889,7 @@ showvars(const char *sep_prefix, int on, int off) | |||
10854 | const char *sep; | 10889 | const char *sep; |
10855 | char **ep, **epend; | 10890 | char **ep, **epend; |
10856 | 10891 | ||
10857 | ep = listvars(on, off, &epend); | 10892 | ep = listvars(on, off, /*strlist:*/ NULL, &epend); |
10858 | qsort(ep, epend - ep, sizeof(char *), vpcmp); | 10893 | qsort(ep, epend - ep, sizeof(char *), vpcmp); |
10859 | 10894 | ||
10860 | sep = *sep_prefix ? " " : sep_prefix; | 10895 | 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 @@ | |||
1 | ZVAR=1 | ||
2 | ZVAR=2 | ||
3 | ZVAR=3 | ||
4 | ZVAR=4 | ||
5 | ZVAR=5 | ||
6 | ZVAR=6 | ||
7 | ZVAR=7 | ||
8 | ZVAR=8 | ||
9 | 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 @@ | |||
1 | # ash had a bug where NOFORKed applet (env/printenv) was not seeing new exported variables | ||
2 | |||
3 | (export ZVAR=1; printenv) | grep ^ZVAR= | ||
4 | (ZVAR=2 printenv) | grep ^ZVAR= | ||
5 | |||
6 | (export ZVAR=3; env) | grep ^ZVAR= | ||
7 | (ZVAR=4 env) | grep ^ZVAR= | ||
8 | |||
9 | export ZVAR=5; printenv | grep ^ZVAR= | ||
10 | ZVAR=6 printenv | grep ^ZVAR= | ||
11 | |||
12 | export ZVAR=7; env | grep ^ZVAR= | ||
13 | ZVAR=8 env | grep ^ZVAR= | ||
14 | |||
15 | 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 @@ | |||
1 | ZVAR=1 | ||
2 | ZVAR=2 | ||
3 | ZVAR=3 | ||
4 | ZVAR=4 | ||
5 | ZVAR=5 | ||
6 | ZVAR=6 | ||
7 | ZVAR=7 | ||
8 | ZVAR=8 | ||
9 | 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 @@ | |||
1 | # ash had a bug where NOFORKed applet (env/printenv) was not seeing new exported variables | ||
2 | |||
3 | (export ZVAR=1; printenv) | grep ^ZVAR= | ||
4 | (ZVAR=2 printenv) | grep ^ZVAR= | ||
5 | |||
6 | (export ZVAR=3; env) | grep ^ZVAR= | ||
7 | (ZVAR=4 env) | grep ^ZVAR= | ||
8 | |||
9 | export ZVAR=5; printenv | grep ^ZVAR= | ||
10 | ZVAR=6 printenv | grep ^ZVAR= | ||
11 | |||
12 | export ZVAR=7; env | grep ^ZVAR= | ||
13 | ZVAR=8 env | grep ^ZVAR= | ||
14 | |||
15 | echo Ok:$? | ||