aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shell/hush.c98
-rw-r--r--shell/hush_test/hush-misc/syntax_err.right2
2 files changed, 42 insertions, 58 deletions
diff --git a/shell/hush.c b/shell/hush.c
index c8bcf9b59..6734c9212 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -90,14 +90,6 @@
90#define SKIP_FEATURE_SH_STANDALONE(...) __VA_ARGS__ 90#define SKIP_FEATURE_SH_STANDALONE(...) __VA_ARGS__
91#endif 91#endif
92 92
93#if !BB_MMU && ENABLE_HUSH_TICK
94//#undef ENABLE_HUSH_TICK
95//#define ENABLE_HUSH_TICK 0
96#warning On NOMMU, hush command substitution is dangerous.
97#warning Dont use it for commands which produce lots of output.
98#warning For more info see shell/hush.c, generate_stream_from_list().
99#endif
100
101#if !ENABLE_HUSH_INTERACTIVE 93#if !ENABLE_HUSH_INTERACTIVE
102#undef ENABLE_FEATURE_EDITING 94#undef ENABLE_FEATURE_EDITING
103#define ENABLE_FEATURE_EDITING 0 95#define ENABLE_FEATURE_EDITING 0
@@ -1649,7 +1641,7 @@ static char **o_finalize_list(o_string *o, int n)
1649 1641
1650/* Expansion can recurse */ 1642/* Expansion can recurse */
1651#if ENABLE_HUSH_TICK 1643#if ENABLE_HUSH_TICK
1652static int process_command_subs(o_string *dest, struct in_str *input); 1644static int process_command_subs(o_string *dest, const char *s);
1653#endif 1645#endif
1654static char *expand_string_to_string(const char *str); 1646static char *expand_string_to_string(const char *str);
1655static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote_end); 1647static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote_end);
@@ -1798,18 +1790,15 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
1798 ored_ch = 0x80; 1790 ored_ch = 0x80;
1799 break; 1791 break;
1800#if ENABLE_HUSH_TICK 1792#if ENABLE_HUSH_TICK
1801 case '`': { /* <SPECIAL_VAR_SYMBOL>`cmd<SPECIAL_VAR_SYMBOL> */ 1793 case '`': /* <SPECIAL_VAR_SYMBOL>`cmd<SPECIAL_VAR_SYMBOL> */
1802 struct in_str input;
1803 *p = '\0'; 1794 *p = '\0';
1804 arg++; 1795 arg++;
1805//TODO: can we just stuff it into "output" directly? 1796//TODO: can we just stuff it into "output" directly?
1806 debug_printf_subst("SUBST '%s' first_ch %x\n", arg, first_ch); 1797 debug_printf_subst("SUBST '%s' first_ch %x\n", arg, first_ch);
1807 setup_string_in_str(&input, arg); 1798 process_command_subs(&subst_result, arg);
1808 process_command_subs(&subst_result, &input);
1809 debug_printf_subst("SUBST RES '%s'\n", subst_result.data); 1799 debug_printf_subst("SUBST RES '%s'\n", subst_result.data);
1810 val = subst_result.data; 1800 val = subst_result.data;
1811 goto store_val; 1801 goto store_val;
1812 }
1813#endif 1802#endif
1814#if ENABLE_SH_MATH_SUPPORT 1803#if ENABLE_SH_MATH_SUPPORT
1815 case '+': { /* <SPECIAL_VAR_SYMBOL>+cmd<SPECIAL_VAR_SYMBOL> */ 1804 case '+': { /* <SPECIAL_VAR_SYMBOL>+cmd<SPECIAL_VAR_SYMBOL> */
@@ -3711,35 +3700,20 @@ static int redirect_opt_num(o_string *o)
3711} 3700}
3712 3701
3713static struct pipe *parse_stream(struct in_str *input, int end_trigger); 3702static struct pipe *parse_stream(struct in_str *input, int end_trigger);
3703static void parse_and_run_string(const char *s);
3714 3704
3715#if ENABLE_HUSH_TICK 3705#if ENABLE_HUSH_TICK
3716static FILE *generate_stream_from_list(struct pipe *head) 3706static FILE *generate_stream_from_string(const char *s)
3717{ 3707{
3718 FILE *pf; 3708 FILE *pf;
3719 int pid, channel[2]; 3709 int pid, channel[2];
3720 3710
3721 xpipe(channel); 3711 xpipe(channel);
3722/* *** NOMMU WARNING *** */
3723/* By using vfork here, we suspend parent till child exits or execs.
3724 * If child will not do it before it fills the pipe, it can block forever
3725 * in write(STDOUT_FILENO), and parent (shell) will be also stuck.
3726 * Try this script:
3727 * yes "0123456789012345678901234567890" | dd bs=32 count=64k >TESTFILE
3728 * huge=`cat TESTFILE` # will block here forever
3729 * echo OK
3730 */
3731 pid = BB_MMU ? fork() : vfork(); 3712 pid = BB_MMU ? fork() : vfork();
3732 if (pid < 0) 3713 if (pid < 0)
3733 bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork"); 3714 bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork");
3715
3734 if (pid == 0) { /* child */ 3716 if (pid == 0) { /* child */
3735 if (ENABLE_HUSH_JOB)
3736 die_sleep = 0; /* let nofork's xfuncs die */
3737 close(channel[0]); /* NB: close _first_, then move fd! */
3738 xmove_fd(channel[1], 1);
3739 /* Prevent it from trying to handle ctrl-z etc */
3740#if ENABLE_HUSH_JOB
3741 G.run_list_level = 1;
3742#endif
3743 /* Process substitution is not considered to be usual 3717 /* Process substitution is not considered to be usual
3744 * 'command execution'. 3718 * 'command execution'.
3745 * SUSv3 says ctrl-Z should be ignored, ctrl-C should not. 3719 * SUSv3 says ctrl-Z should be ignored, ctrl-C should not.
@@ -3749,40 +3723,47 @@ static FILE *generate_stream_from_list(struct pipe *head)
3749 + (1 << SIGTTIN) 3723 + (1 << SIGTTIN)
3750 + (1 << SIGTTOU) 3724 + (1 << SIGTTOU)
3751 , SIG_IGN); 3725 , SIG_IGN);
3752 3726 if (ENABLE_HUSH_JOB)
3753 /* Note: freeing 'head' here would break NOMMU. */ 3727 die_sleep = 0; /* let nofork's xfuncs die */
3754 _exit(run_list(head)); 3728 close(channel[0]); /* NB: close _first_, then move fd! */
3729 xmove_fd(channel[1], 1);
3730 /* Prevent it from trying to handle ctrl-z etc */
3731 USE_HUSH_JOB(G.run_list_level = 1;)
3732#if BB_MMU
3733 parse_and_run_string(s);
3734 _exit(G.last_return_code);
3735#else
3736 /* We re-execute after vfork on NOMMU. This makes this script safe:
3737 * yes "0123456789012345678901234567890" | dd bs=32 count=64k >TESTFILE
3738 * huge=`cat TESTFILE` # was blocking here forever
3739 * echo OK
3740 */
3741//TODO: pass non-exported variables, traps, and functions
3742 execl(CONFIG_BUSYBOX_EXEC_PATH, "hush", "-c", s, NULL);
3743 _exit(127);
3744#endif
3755 } 3745 }
3746
3747 /* parent */
3756 close(channel[1]); 3748 close(channel[1]);
3757 pf = fdopen(channel[0], "r"); 3749 pf = fdopen(channel[0], "r");
3758 return pf; 3750 return pf;
3759 /* 'head' is freed by the caller */
3760} 3751}
3761 3752
3762/* Return code is exit status of the process that is run. */ 3753/* Return code is exit status of the process that is run. */
3763static int process_command_subs(o_string *dest, 3754static int process_command_subs(o_string *dest, const char *s)
3764 struct in_str *input)
3765{ 3755{
3766 int retcode, ch, eol_cnt; 3756 FILE *pf;
3767 struct pipe *pipe_list;
3768 FILE *p;
3769 struct in_str pipe_str; 3757 struct in_str pipe_str;
3758 int ch, eol_cnt;
3770 3759
3771 /* Recursion to generate command */ 3760 pf = generate_stream_from_string(s);
3772 pipe_list = parse_stream(input, '\0'); 3761 if (pf == NULL)
3773 if (pipe_list == NULL)
3774 return 0; /* EOF: empty `cmd`: ``, ` ` etc */
3775 if (pipe_list == ERR_PTR)
3776 return 1; /* parse error. can this really happen? */
3777
3778 p = generate_stream_from_list(pipe_list);
3779 free_pipe_list(pipe_list, /* indent: */ 0);
3780 if (p == NULL)
3781 return 1; 3762 return 1;
3782 close_on_exec_on(fileno(p)); 3763 close_on_exec_on(fileno(pf));
3783 3764
3784 /* Now send results of command back into original context */ 3765 /* Now send results of command back into original context */
3785 setup_file_in_str(&pipe_str, p); 3766 setup_file_in_str(&pipe_str, pf);
3786 eol_cnt = 0; 3767 eol_cnt = 0;
3787 while ((ch = i_getch(&pipe_str)) != EOF) { 3768 while ((ch = i_getch(&pipe_str)) != EOF) {
3788 if (ch == '\n') { 3769 if (ch == '\n') {
@@ -3799,12 +3780,13 @@ static int process_command_subs(o_string *dest,
3799 debug_printf("done reading from pipe, pclose()ing\n"); 3780 debug_printf("done reading from pipe, pclose()ing\n");
3800 /* Note: we got EOF, and we just close the read end of the pipe. 3781 /* Note: we got EOF, and we just close the read end of the pipe.
3801 * We do not wait for the `cmd` child to terminate. bash and ash do. 3782 * We do not wait for the `cmd` child to terminate. bash and ash do.
3802 * Try this: 3783 * Try these:
3803 * echo `echo Hi; exec 1>&-; sleep 2` 3784 * echo `echo Hi; exec 1>&-; sleep 2` - bash waits 2 sec
3785 * `false`; echo $? - bash outputs "1"
3804 */ 3786 */
3805 retcode = fclose(p); 3787 fclose(pf);
3806 debug_printf("closed FILE from child, retcode=%d\n", retcode); 3788 debug_printf("closed FILE from child. return 0\n");
3807 return retcode; 3789 return 0;
3808} 3790}
3809#endif 3791#endif
3810 3792
diff --git a/shell/hush_test/hush-misc/syntax_err.right b/shell/hush_test/hush-misc/syntax_err.right
index 08a270c31..680e7967d 100644
--- a/shell/hush_test/hush-misc/syntax_err.right
+++ b/shell/hush_test/hush-misc/syntax_err.right
@@ -1,2 +1,4 @@
1shown 1shown
2hush: syntax error: unterminated ' 2hush: syntax error: unterminated '
3test
4not shown