aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-04-05 14:41:21 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2018-04-05 14:41:21 +0200
commit41d8f1081378ec79586d59e7d2a31380b6f95577 (patch)
tree947c94f2d458ee834a8bb31986241af958cae853
parent929a41d5770c0531f037c2e7db25bf98f9029c9e (diff)
downloadbusybox-w32-41d8f1081378ec79586d59e7d2a31380b6f95577.tar.gz
busybox-w32-41d8f1081378ec79586d59e7d2a31380b6f95577.tar.bz2
busybox-w32-41d8f1081378ec79586d59e7d2a31380b6f95577.zip
hush: fix corner cases with exec in empty expansions
Cases like these: var=val exec >redir var=val `` >redir function old new delta run_pipe 1701 1723 +22 redirect_and_varexp_helper 56 55 -1 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/1 up/down: 22/-1) Total: 21 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--shell/ash_test/ash-redir/redir_exec1.right2
-rwxr-xr-xshell/ash_test/ash-redir/redir_exec1.tests2
-rw-r--r--shell/hush.c43
-rw-r--r--shell/hush_test/hush-redir/redir_exec1.right3
-rwxr-xr-xshell/hush_test/hush-redir/redir_exec1.tests2
5 files changed, 35 insertions, 17 deletions
diff --git a/shell/ash_test/ash-redir/redir_exec1.right b/shell/ash_test/ash-redir/redir_exec1.right
new file mode 100644
index 000000000..d4393d10c
--- /dev/null
+++ b/shell/ash_test/ash-redir/redir_exec1.right
@@ -0,0 +1,2 @@
1redir_exec1.tests: line 1: can't create /cant/be/created: nonexistent directory
2First
diff --git a/shell/ash_test/ash-redir/redir_exec1.tests b/shell/ash_test/ash-redir/redir_exec1.tests
new file mode 100755
index 000000000..290e1cb39
--- /dev/null
+++ b/shell/ash_test/ash-redir/redir_exec1.tests
@@ -0,0 +1,2 @@
1v=`echo First >&2` exec >/cant/be/created
2echo One:$?
diff --git a/shell/hush.c b/shell/hush.c
index 24ae237d7..43702360a 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -8200,19 +8200,21 @@ static int redirect_and_varexp_helper(
8200 struct squirrel **sqp, 8200 struct squirrel **sqp,
8201 char **argv_expanded) 8201 char **argv_expanded)
8202{ 8202{
8203 /* Assignments occur before redirects. Try:
8204 * a=`sleep 1` sleep 2 3>/qwe/rty
8205 */
8206
8207 char **new_env = expand_assignments(command->argv, command->assignment_cnt);
8208 dump_cmd_in_x_mode(new_env);
8209 dump_cmd_in_x_mode(argv_expanded);
8210 /* this takes ownership of new_env[i] elements, and frees new_env: */
8211 set_vars_and_save_old(new_env);
8212
8203 /* setup_redirects acts on file descriptors, not FILEs. 8213 /* setup_redirects acts on file descriptors, not FILEs.
8204 * This is perfect for work that comes after exec(). 8214 * This is perfect for work that comes after exec().
8205 * Is it really safe for inline use? Experimentally, 8215 * Is it really safe for inline use? Experimentally,
8206 * things seem to work. */ 8216 * things seem to work. */
8207 int rcode = setup_redirects(command, sqp); 8217 return setup_redirects(command, sqp);
8208 if (rcode == 0) {
8209 char **new_env = expand_assignments(command->argv, command->assignment_cnt);
8210 dump_cmd_in_x_mode(new_env);
8211 dump_cmd_in_x_mode(argv_expanded);
8212 /* this takes ownership of new_env[i] elements, and frees new_env: */
8213 set_vars_and_save_old(new_env);
8214 }
8215 return rcode;
8216} 8218}
8217static NOINLINE int run_pipe(struct pipe *pi) 8219static NOINLINE int run_pipe(struct pipe *pi)
8218{ 8220{
@@ -8315,6 +8317,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
8315 * Ensure redirects take effect (that is, create files). 8317 * Ensure redirects take effect (that is, create files).
8316 * Try "a=t >file" 8318 * Try "a=t >file"
8317 */ 8319 */
8320 only_assignments:
8318 G.expand_exitcode = 0; 8321 G.expand_exitcode = 0;
8319 8322
8320 rcode = setup_redirects(command, &squirrel); 8323 rcode = setup_redirects(command, &squirrel);
@@ -8359,12 +8362,10 @@ static NOINLINE int run_pipe(struct pipe *pi)
8359#endif 8362#endif
8360 argv_expanded = expand_strvec_to_strvec(argv + command->assignment_cnt); 8363 argv_expanded = expand_strvec_to_strvec(argv + command->assignment_cnt);
8361 8364
8362 /* if someone gives us an empty string: `cmd with empty output` */ 8365 /* If someone gives us an empty string: `cmd with empty output` */
8363//TODO: what about: var=EXPR `` >FILE ? will var be set? Will FILE be created?
8364 if (!argv_expanded[0]) { 8366 if (!argv_expanded[0]) {
8365 free(argv_expanded); 8367 free(argv_expanded);
8366 debug_leave(); 8368 goto only_assignments;
8367 return G.last_exitcode;
8368 } 8369 }
8369 8370
8370 old_vars = NULL; 8371 old_vars = NULL;
@@ -8378,9 +8379,17 @@ static NOINLINE int run_pipe(struct pipe *pi)
8378 if (x || funcp) { 8379 if (x || funcp) {
8379 if (x && x->b_function == builtin_exec && argv_expanded[1] == NULL) { 8380 if (x && x->b_function == builtin_exec && argv_expanded[1] == NULL) {
8380 debug_printf("exec with redirects only\n"); 8381 debug_printf("exec with redirects only\n");
8381 rcode = setup_redirects(command, NULL); 8382 /*
8382//TODO: what about: var=EXPR exec >FILE ? will var be set? 8383 * Variable assignments are executed, but then "forgotten":
8384 * a=`sleep 1;echo A` exec 3>&-; echo $a
8385 * sleeps, but prints nothing.
8386 */
8387 enter_var_nest_level();
8388 G.shadowed_vars_pp = &old_vars;
8389 rcode = redirect_and_varexp_helper(command, /*squirrel:*/ NULL, argv_expanded);
8390 G.shadowed_vars_pp = sv_shadowed;
8383 /* rcode=1 can be if redir file can't be opened */ 8391 /* rcode=1 can be if redir file can't be opened */
8392
8384 goto clean_up_and_ret1; 8393 goto clean_up_and_ret1;
8385 } 8394 }
8386 8395
@@ -8452,9 +8461,10 @@ static NOINLINE int run_pipe(struct pipe *pi)
8452 } else 8461 } else
8453 goto must_fork; 8462 goto must_fork;
8454 8463
8464 restore_redirects(squirrel);
8465 clean_up_and_ret1:
8455 leave_var_nest_level(); 8466 leave_var_nest_level();
8456 add_vars(old_vars); 8467 add_vars(old_vars);
8457 restore_redirects(squirrel);
8458 8468
8459 /* 8469 /*
8460 * Try "usleep 99999999" + ^C + "echo $?" 8470 * Try "usleep 99999999" + ^C + "echo $?"
@@ -8474,7 +8484,6 @@ static NOINLINE int run_pipe(struct pipe *pi)
8474 if (sigismember(&G.pending_set, SIGINT)) 8484 if (sigismember(&G.pending_set, SIGINT))
8475 rcode = 128 + SIGINT; 8485 rcode = 128 + SIGINT;
8476 } 8486 }
8477 clean_up_and_ret1:
8478 free(argv_expanded); 8487 free(argv_expanded);
8479 IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) 8488 IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;)
8480 debug_leave(); 8489 debug_leave();
diff --git a/shell/hush_test/hush-redir/redir_exec1.right b/shell/hush_test/hush-redir/redir_exec1.right
new file mode 100644
index 000000000..6ff8fc832
--- /dev/null
+++ b/shell/hush_test/hush-redir/redir_exec1.right
@@ -0,0 +1,3 @@
1First
2hush: can't open '/cant/be/created': No such file or directory
3One:1
diff --git a/shell/hush_test/hush-redir/redir_exec1.tests b/shell/hush_test/hush-redir/redir_exec1.tests
new file mode 100755
index 000000000..290e1cb39
--- /dev/null
+++ b/shell/hush_test/hush-redir/redir_exec1.tests
@@ -0,0 +1,2 @@
1v=`echo First >&2` exec >/cant/be/created
2echo One:$?