aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2009-04-04 19:29:21 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2009-04-04 19:29:21 +0000
commit552433bc5af76c8e5b52278b3d609e9a18c19dc2 (patch)
treea12123629e6ce6779a9385ed17775ca8e9313808 /shell
parenta24c8caeb29a11fafc748399ab6b30e6b8e638f0 (diff)
downloadbusybox-w32-552433bc5af76c8e5b52278b3d609e9a18c19dc2.tar.gz
busybox-w32-552433bc5af76c8e5b52278b3d609e9a18c19dc2.tar.bz2
busybox-w32-552433bc5af76c8e5b52278b3d609e9a18c19dc2.zip
hush: fix "var=val >file" not creating file
function old new delta static.null_ptr - 4 +4 run_list 2018 2020 +2 handle_dollar 667 626 -41 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 1/1 up/down: 6/-41) Total: -35 bytes
Diffstat (limited to 'shell')
-rw-r--r--shell/hush.c128
-rw-r--r--shell/hush_test/hush-misc/redir1.right10
-rwxr-xr-xshell/hush_test/hush-misc/redir1.tests32
3 files changed, 121 insertions, 49 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 0ac42c90b..61db928b2 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -593,7 +593,6 @@ static const struct built_in_command bltins[] = {
593}; 593};
594 594
595 595
596/* Normal */
597static void maybe_die(const char *notice, const char *msg) 596static void maybe_die(const char *notice, const char *msg)
598{ 597{
599 /* Was using fancy stuff: 598 /* Was using fancy stuff:
@@ -615,6 +614,7 @@ static void maybe_die(const char *notice, const char *msg)
615#define syntax(msg) _syntax(msg, __LINE__) 614#define syntax(msg) _syntax(msg, __LINE__)
616#endif 615#endif
617 616
617
618static int glob_needed(const char *s) 618static int glob_needed(const char *s)
619{ 619{
620 while (*s) { 620 while (*s) {
@@ -816,7 +816,7 @@ static void free_strings(char **strings)
816 * sigset_t blocked_set: current blocked signal set 816 * sigset_t blocked_set: current blocked signal set
817 * 817 *
818 * "trap - SIGxxx": 818 * "trap - SIGxxx":
819 * clear bit in blocked_set unless it is also in non_DFL 819 * clear bit in blocked_set unless it is also in non_DFL_mask
820 * "trap 'cmd' SIGxxx": 820 * "trap 'cmd' SIGxxx":
821 * set bit in blocked_set (even if 'cmd' is '') 821 * set bit in blocked_set (even if 'cmd' is '')
822 * after [v]fork, if we plan to be a shell: 822 * after [v]fork, if we plan to be a shell:
@@ -2292,24 +2292,33 @@ static void pseudo_exec(nommu_save_t *nommu_save,
2292 struct command *command, 2292 struct command *command,
2293 char **argv_expanded) 2293 char **argv_expanded)
2294{ 2294{
2295 if (command->argv) 2295 if (command->argv) {
2296 pseudo_exec_argv(nommu_save, command->argv, command->assignment_cnt, argv_expanded); 2296 pseudo_exec_argv(nommu_save, command->argv,
2297 command->assignment_cnt, argv_expanded);
2298 }
2297 2299
2298 if (command->group) { 2300 if (command->group) {
2299#if !BB_MMU 2301 /* Cases when we are here:
2300 bb_error_msg_and_die("nested lists are not supported on NOMMU"); 2302 * ( list )
2301#else 2303 * { list } &
2304 * ... | ( list ) | ...
2305 * ... | { list } | ...
2306 */
2307#if BB_MMU
2302 int rcode; 2308 int rcode;
2303 debug_printf_exec("pseudo_exec: run_list\n"); 2309 debug_printf_exec("pseudo_exec: run_list\n");
2304 rcode = run_list(command->group); 2310 rcode = run_list(command->group);
2305 /* OK to leak memory by not calling free_pipe_list, 2311 /* OK to leak memory by not calling free_pipe_list,
2306 * since this process is about to exit */ 2312 * since this process is about to exit */
2307 _exit(rcode); 2313 _exit(rcode);
2314#else
2315//TODO: re-exec "hush -c command->group_as_a_string"
2316 bb_error_msg_and_die("nested lists are not supported on NOMMU");
2308#endif 2317#endif
2309 } 2318 }
2310 2319
2311 /* Can happen. See what bash does with ">foo" by itself. */ 2320 /* Can happen. See what bash does with ">foo" by itself. */
2312 debug_printf("trying to pseudo_exec null command\n"); 2321 debug_printf("pseudo_exec'ed null command\n");
2313 _exit(EXIT_SUCCESS); 2322 _exit(EXIT_SUCCESS);
2314} 2323}
2315 2324
@@ -2563,61 +2572,72 @@ static int checkjobs_and_fg_shell(struct pipe* fg_pipe)
2563/* run_pipe() starts all the jobs, but doesn't wait for anything 2572/* run_pipe() starts all the jobs, but doesn't wait for anything
2564 * to finish. See checkjobs(). 2573 * to finish. See checkjobs().
2565 * 2574 *
2566 * return code is normally -1, when the caller has to wait for children 2575 * Return code is normally -1, when the caller has to wait for children
2567 * to finish to determine the exit status of the pipe. If the pipe 2576 * to finish to determine the exit status of the pipe. If the pipe
2568 * is a simple builtin command, however, the action is done by the 2577 * is a simple builtin command, however, the action is done by the
2569 * time run_pipe returns, and the exit code is provided as the 2578 * time run_pipe returns, and the exit code is provided as the
2570 * return value. 2579 * return value.
2571 * 2580 *
2572 * The input of the pipe is always stdin, the output is always
2573 * stdout. The outpipe[] mechanism in BusyBox-0.48 lash is bogus,
2574 * because it tries to avoid running the command substitution in
2575 * subshell, when that is in fact necessary. The subshell process
2576 * now has its stdout directed to the input of the appropriate pipe,
2577 * so this routine is noticeably simpler.
2578 *
2579 * Returns -1 only if started some children. IOW: we have to 2581 * Returns -1 only if started some children. IOW: we have to
2580 * mask out retvals of builtins etc with 0xff! 2582 * mask out retvals of builtins etc with 0xff!
2583 *
2584 * The only case when we do not need to [v]fork is when the pipe
2585 * is single, non-backgrounded, non-subshell command. Examples:
2586 * cmd ; ... { list } ; ...
2587 * cmd && ... { list } && ...
2588 * cmd || ... { list } || ...
2589 * If it is, then we can run cmd as a builtin, NOFORK [do we do this?],
2590 * or (if SH_STANDALONE) an applet, and we can run the { list }
2591 * with run_list(). Otherwise, we fork and exec cmd.
2592 *
2593 * Cases when we must fork:
2594 * non-single: cmd | cmd
2595 * backgrounded: cmd & { list } &
2596 * subshell: ( list ) [&]
2581 */ 2597 */
2582static int run_pipe(struct pipe *pi) 2598static int run_pipe(struct pipe *pi)
2583{ 2599{
2600 static const char *const null_ptr = NULL;
2584 int i; 2601 int i;
2585 int nextin; 2602 int nextin;
2586 int pipefds[2]; /* pipefds[0] is for reading */ 2603 int pipefds[2]; /* pipefds[0] is for reading */
2587 struct command *command; 2604 struct command *command;
2588 char **argv_expanded; 2605 char **argv_expanded;
2589 char **argv; 2606 char **argv;
2590 const struct built_in_command *x;
2591 char *p; 2607 char *p;
2592 /* it is not always needed, but we aim to smaller code */ 2608 /* it is not always needed, but we aim to smaller code */
2593 int squirrel[] = { -1, -1, -1 }; 2609 int squirrel[] = { -1, -1, -1 };
2594 int rcode; 2610 int rcode;
2595 const int single_and_fg = (pi->num_cmds == 1 && pi->followup != PIPE_BG);
2596 2611
2597 debug_printf_exec("run_pipe start: single_and_fg=%d\n", single_and_fg); 2612 debug_printf_exec("run_pipe start: members:%d\n", pi->num_cmds);
2598 2613
2599#if ENABLE_HUSH_JOB 2614 USE_HUSH_JOB(pi->pgrp = -1;)
2600 pi->pgrp = -1;
2601#endif
2602 pi->alive_cmds = 1;
2603 pi->stopped_cmds = 0; 2615 pi->stopped_cmds = 0;
2604
2605 /* Check if this is a simple builtin (not part of a pipe).
2606 * Builtins within pipes have to fork anyway, and are handled in
2607 * pseudo_exec. "echo foo | read bar" doesn't work on bash, either.
2608 */
2609 command = &(pi->cmds[0]); 2616 command = &(pi->cmds[0]);
2617 argv_expanded = NULL;
2610 2618
2611#if ENABLE_HUSH_FUNCTIONS 2619 if (pi->num_cmds != 1
2612 if (single_and_fg && command->group && command->grp_type == GRP_FUNCTION) { 2620 || pi->followup == PIPE_BG
2613 /* We "execute" function definition */ 2621 || command->grp_type == GRP_SUBSHELL
2614 bb_error_msg("here we ought to remember function definition, and go on"); 2622 ) {
2615 return EXIT_SUCCESS; 2623 goto must_fork;
2616 } 2624 }
2617#endif
2618 2625
2619 if (single_and_fg && command->group && command->grp_type == GRP_NORMAL) { 2626 pi->alive_cmds = 1;
2620 debug_printf("non-subshell grouping\n"); 2627
2628 debug_printf_exec(": group:%p argv:'%s'\n",
2629 command->group, command->argv ? command->argv[0] : "NONE");
2630
2631 if (command->group) {
2632#if ENABLE_HUSH_FUNCTIONS
2633 if (command->grp_type == GRP_FUNCTION) {
2634 /* func () { list } */
2635 bb_error_msg("here we ought to remember function definition, and go on");
2636 return EXIT_SUCCESS;
2637 }
2638#endif
2639 /* { list } */
2640 debug_printf("non-subshell group\n");
2621 setup_redirects(command, squirrel); 2641 setup_redirects(command, squirrel);
2622 debug_printf_exec(": run_list\n"); 2642 debug_printf_exec(": run_list\n");
2623 rcode = run_list(command->group) & 0xff; 2643 rcode = run_list(command->group) & 0xff;
@@ -2627,26 +2647,33 @@ static int run_pipe(struct pipe *pi)
2627 return rcode; 2647 return rcode;
2628 } 2648 }
2629 2649
2630 argv = command->argv; 2650 argv = command->argv ? command->argv : (char **) &null_ptr;
2631 argv_expanded = NULL; 2651 {
2632 2652 const struct built_in_command *x;
2633 if (single_and_fg && argv != NULL) {
2634 char **new_env = NULL; 2653 char **new_env = NULL;
2635 char **old_env = NULL; 2654 char **old_env = NULL;
2636 2655
2637 i = command->assignment_cnt; 2656 if (argv[command->assignment_cnt] == NULL) {
2638 if (i != 0 && argv[i] == NULL) { 2657 /* Assignments, but no command */
2639 /* assignments, but no command: set local environment */ 2658 /* Ensure redirects take effect. Try "a=t >file" */
2640 for (i = 0; argv[i] != NULL; i++) { 2659 setup_redirects(command, squirrel);
2641 debug_printf("local environment set: %s\n", argv[i]); 2660 restore_redirects(squirrel);
2642 p = expand_string_to_string(argv[i]); 2661 /* Set shell variables */
2662 while (*argv) {
2663 p = expand_string_to_string(*argv);
2664 debug_printf_exec("set shell var:'%s'->'%s'\n",
2665 *argv, p);
2643 set_local_var(p, 0); 2666 set_local_var(p, 0);
2667 argv++;
2644 } 2668 }
2645 return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */ 2669 /* Do we need to flag set_local_var() errors?
2670 * "assignment to readonly var" and "putenv error"
2671 */
2672 return EXIT_SUCCESS;
2646 } 2673 }
2647 2674
2648 /* Expand the rest into (possibly) many strings each */ 2675 /* Expand the rest into (possibly) many strings each */
2649 argv_expanded = expand_strvec_to_strvec(argv + i); 2676 argv_expanded = expand_strvec_to_strvec(argv + command->assignment_cnt);
2650 2677
2651 for (x = bltins; x != &bltins[ARRAY_SIZE(bltins)]; x++) { 2678 for (x = bltins; x != &bltins[ARRAY_SIZE(bltins)]; x++) {
2652 if (strcmp(argv_expanded[0], x->cmd) != 0) 2679 if (strcmp(argv_expanded[0], x->cmd) != 0)
@@ -2694,8 +2721,10 @@ static int run_pipe(struct pipe *pi)
2694 goto clean_up_and_ret; 2721 goto clean_up_and_ret;
2695 } 2722 }
2696#endif 2723#endif
2724 /* It is neither builtin nor applet. We must fork. */
2697 } 2725 }
2698 2726
2727 must_fork:
2699 /* NB: argv_expanded may already be created, and that 2728 /* NB: argv_expanded may already be created, and that
2700 * might include `cmd` runs! Do not rerun it! We *must* 2729 * might include `cmd` runs! Do not rerun it! We *must*
2701 * use argv_expanded if it's non-NULL */ 2730 * use argv_expanded if it's non-NULL */
@@ -2715,8 +2744,9 @@ static int run_pipe(struct pipe *pi)
2715 if (command->argv) { 2744 if (command->argv) {
2716 debug_printf_exec(": pipe member '%s' '%s'...\n", 2745 debug_printf_exec(": pipe member '%s' '%s'...\n",
2717 command->argv[0], command->argv[1]); 2746 command->argv[0], command->argv[1]);
2718 } else 2747 } else {
2719 debug_printf_exec(": pipe member with no argv\n"); 2748 debug_printf_exec(": pipe member with no argv\n");
2749 }
2720 2750
2721 /* pipes are inserted between pairs of commands */ 2751 /* pipes are inserted between pairs of commands */
2722 pipefds[0] = 0; 2752 pipefds[0] = 0;
diff --git a/shell/hush_test/hush-misc/redir1.right b/shell/hush_test/hush-misc/redir1.right
new file mode 100644
index 000000000..ac90b4a0a
--- /dev/null
+++ b/shell/hush_test/hush-misc/redir1.right
@@ -0,0 +1,10 @@
1Test 1: var:ok
2File created:ok
3Test 2: var:ok
4File created:ok
5Test 3: var:ok
6File created:ok
7Test 4: var:ok
8File created:ok
9Test 5: var:ok
10File created:ok
diff --git a/shell/hush_test/hush-misc/redir1.tests b/shell/hush_test/hush-misc/redir1.tests
new file mode 100755
index 000000000..5f6c20612
--- /dev/null
+++ b/shell/hush_test/hush-misc/redir1.tests
@@ -0,0 +1,32 @@
1rm shell_test_$$ 2>/dev/null
2var=bad
3var=ok >shell_test_$$
4echo "Test 1: var:$var"
5test -f shell_test_$$ && echo "File created:ok"
6
7rm shell_test_$$ 2>/dev/null
8var=ok
9true | var=bad >shell_test_$$
10echo "Test 2: var:$var"
11test -f shell_test_$$ && echo "File created:ok"
12
13rm shell_test_$$ 2>/dev/null
14var=bad
15{ var=ok >shell_test_$$; }
16echo "Test 3: var:$var"
17test -f shell_test_$$ && echo "File created:ok"
18
19rm shell_test_$$ 2>/dev/null
20var=ok
21{ var=bad >shell_test_$$; } &
22usleep 100000
23echo "Test 4: var:$var"
24test -f shell_test_$$ && echo "File created:ok"
25
26rm shell_test_$$ 2>/dev/null
27var=ok
28( var=bad >shell_test_$$ )
29echo "Test 5: var:$var"
30test -f shell_test_$$ && echo "File created:ok"
31
32rm shell_test_$$ 2>/dev/null