aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-02-10 12:10:08 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-02-10 12:10:08 +0000
commit05743d79496cf96e9f6f645b6bbc165d51e6aa5c (patch)
tree50fb492810d898cdcafe63009bbb08a1dde039ca
parent68e8e96d7fba018b5b2354434fe0ae95fdfffc4f (diff)
downloadbusybox-w32-05743d79496cf96e9f6f645b6bbc165d51e6aa5c.tar.gz
busybox-w32-05743d79496cf96e9f6f645b6bbc165d51e6aa5c.tar.bz2
busybox-w32-05743d79496cf96e9f6f645b6bbc165d51e6aa5c.zip
hush: reinstate `cmd` handling for NOMMU (with fat big warning).
hush: fix a case where none of pipe members could be started because of fork failure hush: rename functions: xxx_real -> xxx hush: try to add a bit more of vfork-friendliness hush: add rudimentary design docs hush: add TODO (newly discovered bug with globbing)
-rw-r--r--include/libbb.h3
-rw-r--r--shell/hush.c192
-rw-r--r--shell/hush_doc.txt39
-rwxr-xr-xshell/hush_test/run-all5
-rw-r--r--shell/hush_test/zbad219
5 files changed, 166 insertions, 92 deletions
diff --git a/include/libbb.h b/include/libbb.h
index 3ef03d6c9..b405df541 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -664,6 +664,9 @@ enum {
664 void re_exec(char **argv) ATTRIBUTE_NORETURN; 664 void re_exec(char **argv) ATTRIBUTE_NORETURN;
665 void forkexit_or_rexec(char **argv); 665 void forkexit_or_rexec(char **argv);
666 extern bool re_execed; 666 extern bool re_execed;
667 int BUG_fork_is_unavailable_on_nommu(void);
668 int BUG_daemon_is_unavailable_on_nommu(void);
669 void BUG_bb_daemonize_is_unavailable_on_nommu(void);
667# define fork() BUG_fork_is_unavailable_on_nommu() 670# define fork() BUG_fork_is_unavailable_on_nommu()
668# define daemon(a,b) BUG_daemon_is_unavailable_on_nommu() 671# define daemon(a,b) BUG_daemon_is_unavailable_on_nommu()
669# define bb_daemonize(a) BUG_bb_daemonize_is_unavailable_on_nommu() 672# define bb_daemonize(a) BUG_bb_daemonize_is_unavailable_on_nommu()
diff --git a/shell/hush.c b/shell/hush.c
index a75407634..f3ea1a212 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -84,12 +84,24 @@
84#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ 84#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */
85 85
86 86
87#if !BB_MMU 87#if !BB_MMU && ENABLE_HUSH_TICK
88/* A bit drastic. Can allow some simpler commands 88//#undef ENABLE_HUSH_TICK
89 * by analysing command in generate_stream_from_list() 89//#define ENABLE_HUSH_TICK 0
90 */ 90#warning On NOMMU, hush command substitution is dangerous.
91#undef ENABLE_HUSH_TICK 91#warning Dont use it for commands which produce lots of output.
92#define ENABLE_HUSH_TICK 0 92#warning For more info see shell/hush.c, generate_stream_from_list().
93#endif
94
95#if !BB_MMU && ENABLE_HUSH_JOB
96#undef ENABLE_HUSH_JOB
97#define ENABLE_HUSH_JOB 0
98#endif
99
100#if !ENABLE_HUSH_INTERACTIVE
101#undef ENABLE_FEATURE_EDITING
102#define ENABLE_FEATURE_EDITING 0
103#undef ENABLE_FEATURE_EDITING_FANCY_PROMPT
104#define ENABLE_FEATURE_EDITING_FANCY_PROMPT 0
93#endif 105#endif
94 106
95 107
@@ -176,13 +188,6 @@ void xxfree(void *ptr)
176#endif 188#endif
177 189
178 190
179#if !ENABLE_HUSH_INTERACTIVE
180#undef ENABLE_FEATURE_EDITING
181#define ENABLE_FEATURE_EDITING 0
182#undef ENABLE_FEATURE_EDITING_FANCY_PROMPT
183#define ENABLE_FEATURE_EDITING_FANCY_PROMPT 0
184#endif
185
186#define SPECIAL_VAR_SYMBOL 3 191#define SPECIAL_VAR_SYMBOL 3
187 192
188#define PARSEFLAG_EXIT_FROM_LOOP 1 193#define PARSEFLAG_EXIT_FROM_LOOP 1
@@ -508,10 +513,10 @@ static int free_pipe_list(struct pipe *head, int indent);
508static int free_pipe(struct pipe *pi, int indent); 513static int free_pipe(struct pipe *pi, int indent);
509/* really run the final data structures: */ 514/* really run the final data structures: */
510static int setup_redirects(struct child_prog *prog, int squirrel[]); 515static int setup_redirects(struct child_prog *prog, int squirrel[]);
511static int run_list_real(struct pipe *pi); 516static int run_list(struct pipe *pi);
512static void pseudo_exec_argv(char **argv) ATTRIBUTE_NORETURN; 517static void pseudo_exec_argv(char **argv) ATTRIBUTE_NORETURN;
513static void pseudo_exec(struct child_prog *child) ATTRIBUTE_NORETURN; 518static void pseudo_exec(struct child_prog *child) ATTRIBUTE_NORETURN;
514static int run_pipe_real(struct pipe *pi); 519static int run_pipe(struct pipe *pi);
515/* extended glob support: */ 520/* extended glob support: */
516static char **globhack(const char *src, char **strings); 521static char **globhack(const char *src, char **strings);
517static int glob_needed(const char *s); 522static int glob_needed(const char *s);
@@ -1416,7 +1421,7 @@ static void restore_redirects(int squirrel[])
1416 } 1421 }
1417} 1422}
1418 1423
1419/* Called after [v]fork() in run_pipe_real(), or from builtin_exec(). 1424/* Called after [v]fork() in run_pipe(), or from builtin_exec().
1420 * Never returns. 1425 * Never returns.
1421 * XXX no exit() here. If you don't exec, use _exit instead. 1426 * XXX no exit() here. If you don't exec, use _exit instead.
1422 * The at_exit handlers apparently confuse the calling process, 1427 * The at_exit handlers apparently confuse the calling process,
@@ -1438,9 +1443,8 @@ static void pseudo_exec_argv(char **argv)
1438 /* If a variable is assigned in a forest, and nobody listens, 1443 /* If a variable is assigned in a forest, and nobody listens,
1439 * was it ever really set? 1444 * was it ever really set?
1440 */ 1445 */
1441 if (argv[0] == NULL) { 1446 if (!argv[0])
1442 _exit(EXIT_SUCCESS); 1447 _exit(EXIT_SUCCESS);
1443 }
1444 1448
1445 argv = expand_strvec_to_strvec(argv); 1449 argv = expand_strvec_to_strvec(argv);
1446 1450
@@ -1484,15 +1488,15 @@ static void pseudo_exec_argv(char **argv)
1484 _exit(1); 1488 _exit(1);
1485} 1489}
1486 1490
1487/* Called after [v]fork() in run_pipe_real() 1491/* Called after [v]fork() in run_pipe()
1488 */ 1492 */
1489static void pseudo_exec(struct child_prog *child) 1493static void pseudo_exec(struct child_prog *child)
1490{ 1494{
1491// FIXME: buggy wrt NOMMU! Must not modify any global data 1495// FIXME: buggy wrt NOMMU! Must not modify any global data
1492// until it does exec/_exit, but currently it does. 1496// until it does exec/_exit, but currently it does
1493 if (child->argv) { 1497// (puts malloc'ed stuff into environment)
1498 if (child->argv)
1494 pseudo_exec_argv(child->argv); 1499 pseudo_exec_argv(child->argv);
1495 }
1496 1500
1497 if (child->group) { 1501 if (child->group) {
1498#if !BB_MMU 1502#if !BB_MMU
@@ -1501,11 +1505,12 @@ static void pseudo_exec(struct child_prog *child)
1501 int rcode; 1505 int rcode;
1502 1506
1503#if ENABLE_HUSH_INTERACTIVE 1507#if ENABLE_HUSH_INTERACTIVE
1504 debug_printf_exec("pseudo_exec: setting interactive_fd=0\n"); 1508// run_list_level now takes care of it?
1505 interactive_fd = 0; /* crucial!!!! */ 1509// debug_printf_exec("pseudo_exec: setting interactive_fd=0\n");
1510// interactive_fd = 0; /* crucial!!!! */
1506#endif 1511#endif
1507 debug_printf_exec("pseudo_exec: run_list_real\n"); 1512 debug_printf_exec("pseudo_exec: run_list\n");
1508 rcode = run_list_real(child->group); 1513 rcode = run_list(child->group);
1509 /* OK to leak memory by not calling free_pipe_list, 1514 /* OK to leak memory by not calling free_pipe_list,
1510 * since this process is about to exit */ 1515 * since this process is about to exit */
1511 _exit(rcode); 1516 _exit(rcode);
@@ -1672,7 +1677,7 @@ static int checkjobs(struct pipe* fg_pipe)
1672 if (dead) { 1677 if (dead) {
1673 fg_pipe->progs[i].pid = 0; 1678 fg_pipe->progs[i].pid = 0;
1674 fg_pipe->running_progs--; 1679 fg_pipe->running_progs--;
1675 if (i == fg_pipe->num_progs-1) 1680 if (i == fg_pipe->num_progs - 1)
1676 /* last process gives overall exitstatus */ 1681 /* last process gives overall exitstatus */
1677 rcode = WEXITSTATUS(status); 1682 rcode = WEXITSTATUS(status);
1678 } else { 1683 } else {
@@ -1753,13 +1758,13 @@ static int checkjobs_and_fg_shell(struct pipe* fg_pipe)
1753} 1758}
1754#endif 1759#endif
1755 1760
1756/* run_pipe_real() starts all the jobs, but doesn't wait for anything 1761/* run_pipe() starts all the jobs, but doesn't wait for anything
1757 * to finish. See checkjobs(). 1762 * to finish. See checkjobs().
1758 * 1763 *
1759 * return code is normally -1, when the caller has to wait for children 1764 * return code is normally -1, when the caller has to wait for children
1760 * to finish to determine the exit status of the pipe. If the pipe 1765 * to finish to determine the exit status of the pipe. If the pipe
1761 * is a simple builtin command, however, the action is done by the 1766 * is a simple builtin command, however, the action is done by the
1762 * time run_pipe_real returns, and the exit code is provided as the 1767 * time run_pipe returns, and the exit code is provided as the
1763 * return value. 1768 * return value.
1764 * 1769 *
1765 * The input of the pipe is always stdin, the output is always 1770 * The input of the pipe is always stdin, the output is always
@@ -1772,7 +1777,7 @@ static int checkjobs_and_fg_shell(struct pipe* fg_pipe)
1772 * Returns -1 only if started some children. IOW: we have to 1777 * Returns -1 only if started some children. IOW: we have to
1773 * mask out retvals of builtins etc with 0xff! 1778 * mask out retvals of builtins etc with 0xff!
1774 */ 1779 */
1775static int run_pipe_real(struct pipe *pi) 1780static int run_pipe(struct pipe *pi)
1776{ 1781{
1777 int i; 1782 int i;
1778 int nextin; 1783 int nextin;
@@ -1785,7 +1790,7 @@ static int run_pipe_real(struct pipe *pi)
1785 int rcode; 1790 int rcode;
1786 const int single_fg = (pi->num_progs == 1 && pi->followup != PIPE_BG); 1791 const int single_fg = (pi->num_progs == 1 && pi->followup != PIPE_BG);
1787 1792
1788 debug_printf_exec("run_pipe_real start: single_fg=%d\n", single_fg); 1793 debug_printf_exec("run_pipe start: single_fg=%d\n", single_fg);
1789 1794
1790#if ENABLE_HUSH_JOB 1795#if ENABLE_HUSH_JOB
1791 pi->pgrp = -1; 1796 pi->pgrp = -1;
@@ -1801,11 +1806,11 @@ static int run_pipe_real(struct pipe *pi)
1801 if (single_fg && child->group && child->subshell == 0) { 1806 if (single_fg && child->group && child->subshell == 0) {
1802 debug_printf("non-subshell grouping\n"); 1807 debug_printf("non-subshell grouping\n");
1803 setup_redirects(child, squirrel); 1808 setup_redirects(child, squirrel);
1804 debug_printf_exec(": run_list_real\n"); 1809 debug_printf_exec(": run_list\n");
1805 rcode = run_list_real(child->group); 1810 rcode = run_list(child->group) & 0xff;
1806 restore_redirects(squirrel); 1811 restore_redirects(squirrel);
1807 debug_printf_exec("run_pipe_real return %d\n", rcode); 1812 debug_printf_exec("run_pipe return %d\n", rcode);
1808 return rcode; // do we need to add '... & 0xff' ? 1813 return rcode;
1809 } 1814 }
1810 1815
1811 if (single_fg && child->argv != NULL) { 1816 if (single_fg && child->argv != NULL) {
@@ -1847,7 +1852,7 @@ static int run_pipe_real(struct pipe *pi)
1847 rcode = x->function(argv_expanded) & 0xff; 1852 rcode = x->function(argv_expanded) & 0xff;
1848 free(argv_expanded); 1853 free(argv_expanded);
1849 restore_redirects(squirrel); 1854 restore_redirects(squirrel);
1850 debug_printf_exec("run_pipe_real return %d\n", rcode); 1855 debug_printf_exec("run_pipe return %d\n", rcode);
1851 return rcode; 1856 return rcode;
1852 } 1857 }
1853 } 1858 }
@@ -1864,7 +1869,7 @@ static int run_pipe_real(struct pipe *pi)
1864 rcode = run_nofork_applet_prime(&nofork_save, a, argv_expanded) & 0xff; 1869 rcode = run_nofork_applet_prime(&nofork_save, a, argv_expanded) & 0xff;
1865 free(argv_expanded); 1870 free(argv_expanded);
1866 restore_redirects(squirrel); 1871 restore_redirects(squirrel);
1867 debug_printf_exec("run_pipe_real return %d\n", rcode); 1872 debug_printf_exec("run_pipe return %d\n", rcode);
1868 return rcode; 1873 return rcode;
1869 } 1874 }
1870 } 1875 }
@@ -1892,24 +1897,22 @@ static int run_pipe_real(struct pipe *pi)
1892 if ((i + 1) < pi->num_progs) 1897 if ((i + 1) < pi->num_progs)
1893 xpipe(pipefds); 1898 xpipe(pipefds);
1894 1899
1895#if BB_MMU 1900 child->pid = BB_MMU ? fork() : vfork();
1896 child->pid = fork();
1897#else
1898 child->pid = vfork();
1899#endif
1900 if (!child->pid) { /* child */ 1901 if (!child->pid) { /* child */
1901#if ENABLE_HUSH_JOB 1902#if ENABLE_HUSH_JOB
1902 /* Every child adds itself to new process group 1903 /* Every child adds itself to new process group
1903 * with pgid == pid of first child in pipe */ 1904 * with pgid == pid_of_first_child_in_pipe */
1904 if (run_list_level == 1 && interactive_fd) { 1905 if (run_list_level == 1 && interactive_fd) {
1906 pid_t pgrp;
1905 /* Don't do pgrp restore anymore on fatal signals */ 1907 /* Don't do pgrp restore anymore on fatal signals */
1906 set_fatal_sighandler(SIG_DFL); 1908 set_fatal_sighandler(SIG_DFL);
1907 if (pi->pgrp < 0) /* true for 1st process only */ 1909 pgrp = pi->pgrp;
1908 pi->pgrp = getpid(); 1910 if (pgrp < 0) /* true for 1st process only */
1909 if (setpgid(0, pi->pgrp) == 0 && pi->followup != PIPE_BG) { 1911 pgrp = getpid();
1912 if (setpgid(0, pgrp) == 0 && pi->followup != PIPE_BG) {
1910 /* We do it in *every* child, not just first, 1913 /* We do it in *every* child, not just first,
1911 * to avoid races */ 1914 * to avoid races */
1912 tcsetpgrp(interactive_fd, pi->pgrp); 1915 tcsetpgrp(interactive_fd, pgrp);
1913 } 1916 }
1914 } 1917 }
1915#endif 1918#endif
@@ -1930,7 +1933,7 @@ static int run_pipe_real(struct pipe *pi)
1930 1933
1931 if (child->pid < 0) { /* [v]fork failed */ 1934 if (child->pid < 0) { /* [v]fork failed */
1932 /* Clearly indicate, was it fork or vfork */ 1935 /* Clearly indicate, was it fork or vfork */
1933 bb_perror_msg(BB_MMU ? "cannot fork" : "cannot vfork"); 1936 bb_perror_msg(BB_MMU ? "fork" : "vfork");
1934 } else { 1937 } else {
1935 pi->running_progs++; 1938 pi->running_progs++;
1936#if ENABLE_HUSH_JOB 1939#if ENABLE_HUSH_JOB
@@ -1948,7 +1951,12 @@ static int run_pipe_real(struct pipe *pi)
1948 nextin = pipefds[0]; 1951 nextin = pipefds[0];
1949 } 1952 }
1950 1953
1951 debug_printf_exec("run_pipe_real return -1\n"); 1954 if (!pi->running_progs) {
1955 debug_printf_exec("run_pipe return 1 (all forks failed, no children)\n");
1956 return 1;
1957 }
1958
1959 debug_printf_exec("run_pipe return -1 (%u children started)\n", pi->running_progs);
1952 return -1; 1960 return -1;
1953} 1961}
1954 1962
@@ -2017,7 +2025,7 @@ static void debug_print_tree(struct pipe *pi, int lvl)
2017 2025
2018/* NB: called by pseudo_exec, and therefore must not modify any 2026/* NB: called by pseudo_exec, and therefore must not modify any
2019 * global data until exec/_exit (we can be a child after vfork!) */ 2027 * global data until exec/_exit (we can be a child after vfork!) */
2020static int run_list_real(struct pipe *pi) 2028static int run_list(struct pipe *pi)
2021{ 2029{
2022 struct pipe *rpipe; 2030 struct pipe *rpipe;
2023#if ENABLE_HUSH_LOOPS 2031#if ENABLE_HUSH_LOOPS
@@ -2026,7 +2034,6 @@ static int run_list_real(struct pipe *pi)
2026 char **for_list = NULL; 2034 char **for_list = NULL;
2027 int flag_rep = 0; 2035 int flag_rep = 0;
2028#endif 2036#endif
2029 int save_num_progs;
2030 int flag_skip = 1; 2037 int flag_skip = 1;
2031 int rcode = 0; /* probably for gcc only */ 2038 int rcode = 0; /* probably for gcc only */
2032 int flag_restore = 0; 2039 int flag_restore = 0;
@@ -2038,7 +2045,7 @@ static int run_list_real(struct pipe *pi)
2038 reserved_style rword; 2045 reserved_style rword;
2039 reserved_style skip_more_for_this_rword = RES_XXXX; 2046 reserved_style skip_more_for_this_rword = RES_XXXX;
2040 2047
2041 debug_printf_exec("run_list_real start lvl %d\n", run_list_level + 1); 2048 debug_printf_exec("run_list start lvl %d\n", run_list_level + 1);
2042 2049
2043#if ENABLE_HUSH_LOOPS 2050#if ENABLE_HUSH_LOOPS
2044 /* check syntax for "for" */ 2051 /* check syntax for "for" */
@@ -2047,7 +2054,7 @@ static int run_list_real(struct pipe *pi)
2047 && (rpipe->next == NULL) 2054 && (rpipe->next == NULL)
2048 ) { 2055 ) {
2049 syntax("malformed for"); /* no IN or no commands after IN */ 2056 syntax("malformed for"); /* no IN or no commands after IN */
2050 debug_printf_exec("run_list_real lvl %d return 1\n", run_list_level); 2057 debug_printf_exec("run_list lvl %d return 1\n", run_list_level);
2051 return 1; 2058 return 1;
2052 } 2059 }
2053 if ((rpipe->res_word == RES_IN && rpipe->next->res_word == RES_IN && rpipe->next->progs[0].argv != NULL) 2060 if ((rpipe->res_word == RES_IN && rpipe->next->res_word == RES_IN && rpipe->next->progs[0].argv != NULL)
@@ -2055,7 +2062,7 @@ static int run_list_real(struct pipe *pi)
2055 ) { 2062 ) {
2056 /* TODO: what is tested in the first condition? */ 2063 /* TODO: what is tested in the first condition? */
2057 syntax("malformed for"); /* 2nd condition: not followed by IN */ 2064 syntax("malformed for"); /* 2nd condition: not followed by IN */
2058 debug_printf_exec("run_list_real lvl %d return 1\n", run_list_level); 2065 debug_printf_exec("run_list lvl %d return 1\n", run_list_level);
2059 return 1; 2066 return 1;
2060 } 2067 }
2061 } 2068 }
@@ -2103,9 +2110,10 @@ static int run_list_real(struct pipe *pi)
2103 signal_SA_RESTART(SIGTSTP, handler_ctrl_z); 2110 signal_SA_RESTART(SIGTSTP, handler_ctrl_z);
2104 signal(SIGINT, handler_ctrl_c); 2111 signal(SIGINT, handler_ctrl_c);
2105 } 2112 }
2106#endif 2113#endif /* JOB */
2107 2114
2108 for (; pi; pi = flag_restore ? rpipe : pi->next) { 2115 for (; pi; pi = flag_restore ? rpipe : pi->next) {
2116//why? int save_num_progs;
2109 rword = pi->res_word; 2117 rword = pi->res_word;
2110#if ENABLE_HUSH_LOOPS 2118#if ENABLE_HUSH_LOOPS
2111 if (rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR) { 2119 if (rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR) {
@@ -2178,12 +2186,12 @@ static int run_list_real(struct pipe *pi)
2178#endif 2186#endif
2179 if (pi->num_progs == 0) 2187 if (pi->num_progs == 0)
2180 continue; 2188 continue;
2181 save_num_progs = pi->num_progs; /* save number of programs */ 2189//why? save_num_progs = pi->num_progs;
2182 debug_printf_exec(": run_pipe_real with %d members\n", pi->num_progs); 2190 debug_printf_exec(": run_pipe with %d members\n", pi->num_progs);
2183 rcode = run_pipe_real(pi); 2191 rcode = run_pipe(pi);
2184 if (rcode != -1) { 2192 if (rcode != -1) {
2185 /* We only ran a builtin: rcode was set by the return value 2193 /* We only ran a builtin: rcode was set by the return value
2186 * of run_pipe_real(), and we don't need to wait for anything. */ 2194 * of run_pipe(), and we don't need to wait for anything. */
2187 } else if (pi->followup == PIPE_BG) { 2195 } else if (pi->followup == PIPE_BG) {
2188 /* What does bash do with attempts to background builtins? */ 2196 /* What does bash do with attempts to background builtins? */
2189 /* Even bash 3.2 doesn't do that well with nested bg: 2197 /* Even bash 3.2 doesn't do that well with nested bg:
@@ -2196,7 +2204,6 @@ static int run_list_real(struct pipe *pi)
2196 rcode = EXIT_SUCCESS; 2204 rcode = EXIT_SUCCESS;
2197 } else { 2205 } else {
2198#if ENABLE_HUSH_JOB 2206#if ENABLE_HUSH_JOB
2199 /* Paranoia, just "interactive_fd" should be enough? */
2200 if (run_list_level == 1 && interactive_fd) { 2207 if (run_list_level == 1 && interactive_fd) {
2201 /* waits for completion, then fg's main shell */ 2208 /* waits for completion, then fg's main shell */
2202 rcode = checkjobs_and_fg_shell(pi); 2209 rcode = checkjobs_and_fg_shell(pi);
@@ -2210,7 +2217,7 @@ static int run_list_real(struct pipe *pi)
2210 } 2217 }
2211 debug_printf_exec(": setting last_return_code=%d\n", rcode); 2218 debug_printf_exec(": setting last_return_code=%d\n", rcode);
2212 last_return_code = rcode; 2219 last_return_code = rcode;
2213 pi->num_progs = save_num_progs; /* restore number of programs */ 2220//why? pi->num_progs = save_num_progs;
2214#if ENABLE_HUSH_IF 2221#if ENABLE_HUSH_IF
2215 if (rword == RES_IF || rword == RES_ELIF) 2222 if (rword == RES_IF || rword == RES_ELIF)
2216 next_if_code = rcode; /* can be overwritten a number of times */ 2223 next_if_code = rcode; /* can be overwritten a number of times */
@@ -2241,7 +2248,7 @@ static int run_list_real(struct pipe *pi)
2241 signal(SIGINT, SIG_IGN); 2248 signal(SIGINT, SIG_IGN);
2242 } 2249 }
2243#endif 2250#endif
2244 debug_printf_exec("run_list_real lvl %d return %d\n", run_list_level + 1, rcode); 2251 debug_printf_exec("run_list lvl %d return %d\n", run_list_level + 1, rcode);
2245 return rcode; 2252 return rcode;
2246} 2253}
2247 2254
@@ -2315,19 +2322,19 @@ static int free_pipe_list(struct pipe *head, int indent)
2315} 2322}
2316 2323
2317/* Select which version we will use */ 2324/* Select which version we will use */
2318static int run_list(struct pipe *pi) 2325static int run_and_free_list(struct pipe *pi)
2319{ 2326{
2320 int rcode = 0; 2327 int rcode = 0;
2321 debug_printf_exec("run_list entered\n"); 2328 debug_printf_exec("run_and_free_list entered\n");
2322 if (fake_mode == 0) { 2329 if (!fake_mode) {
2323 debug_printf_exec(": run_list_real with %d members\n", pi->num_progs); 2330 debug_printf_exec(": run_list with %d members\n", pi->num_progs);
2324 rcode = run_list_real(pi); 2331 rcode = run_list(pi);
2325 } 2332 }
2326 /* free_pipe_list has the side effect of clearing memory. 2333 /* free_pipe_list has the side effect of clearing memory.
2327 * In the long run that function can be merged with run_list_real, 2334 * In the long run that function can be merged with run_list,
2328 * but doing that now would hobble the debugging effort. */ 2335 * but doing that now would hobble the debugging effort. */
2329 free_pipe_list(pi, 0); 2336 free_pipe_list(pi, /* indent: */ 0);
2330 debug_printf_exec("run_list return %d\n", rcode); 2337 debug_printf_exec("run_nad_free_list return %d\n", rcode);
2331 return rcode; 2338 return rcode;
2332} 2339}
2333 2340
@@ -3221,15 +3228,17 @@ static FILE *generate_stream_from_list(struct pipe *head)
3221 int pid, channel[2]; 3228 int pid, channel[2];
3222 3229
3223 xpipe(channel); 3230 xpipe(channel);
3224 pid = fork(); 3231/* *** NOMMU WARNING *** */
3225 if (pid < 0) { 3232/* By using vfork here, we suspend parent till child exits or execs.
3226 bb_perror_msg_and_die("fork"); 3233 * If child will not do it before it fills the pipe, it can block forever
3227 } else if (pid == 0) { 3234 * in write(STDOUT_FILENO), and parent (shell) will be also stuck.
3235 */
3236 pid = BB_MMU ? fork() : vfork();
3237 if (pid < 0)
3238 bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork");
3239 if (pid == 0) { /* child */
3228 close(channel[0]); 3240 close(channel[0]);
3229 if (channel[1] != 1) { 3241 xmove_fd(channel[1], 1);
3230 dup2(channel[1], 1);
3231 close(channel[1]);
3232 }
3233 /* Prevent it from trying to handle ctrl-z etc */ 3242 /* Prevent it from trying to handle ctrl-z etc */
3234#if ENABLE_HUSH_JOB 3243#if ENABLE_HUSH_JOB
3235 run_list_level = 1; 3244 run_list_level = 1;
@@ -3241,11 +3250,12 @@ static FILE *generate_stream_from_list(struct pipe *head)
3241 * everywhere outside actual command execution. */ 3250 * everywhere outside actual command execution. */
3242 /*set_jobctrl_sighandler(SIG_IGN);*/ 3251 /*set_jobctrl_sighandler(SIG_IGN);*/
3243 set_misc_sighandler(SIG_DFL); 3252 set_misc_sighandler(SIG_DFL);
3244 _exit(run_list_real(head)); /* leaks memory */ 3253 _exit(run_list(head)); /* leaks memory */
3245 } 3254 }
3246 close(channel[1]); 3255 close(channel[1]);
3247 pf = fdopen(channel[0], "r"); 3256 pf = fdopen(channel[0], "r");
3248 return pf; 3257 return pf;
3258 /* head is freed by the caller */
3249} 3259}
3250 3260
3251/* Return code is exit status of the process that is run. */ 3261/* Return code is exit status of the process that is run. */
@@ -3269,7 +3279,8 @@ static int process_command_subs(o_string *dest, struct p_context *ctx,
3269 b_free(&result); 3279 b_free(&result);
3270 3280
3271 p = generate_stream_from_list(inner.list_head); 3281 p = generate_stream_from_list(inner.list_head);
3272 if (p == NULL) return 1; 3282 if (p == NULL)
3283 return 1;
3273 close_on_exec_on(fileno(p)); 3284 close_on_exec_on(fileno(p));
3274 setup_file_in_str(&pipe_str, p); 3285 setup_file_in_str(&pipe_str, p);
3275 3286
@@ -3294,7 +3305,7 @@ static int process_command_subs(o_string *dest, struct p_context *ctx,
3294 * at the same time. That would be a lot of work, and contrary 3305 * at the same time. That would be a lot of work, and contrary
3295 * to the KISS philosophy of this program. */ 3306 * to the KISS philosophy of this program. */
3296 retcode = fclose(p); 3307 retcode = fclose(p);
3297 free_pipe_list(inner.list_head, 0); 3308 free_pipe_list(inner.list_head, /* indent: */ 0);
3298 debug_printf("closed FILE from child, retcode=%d\n", retcode); 3309 debug_printf("closed FILE from child, retcode=%d\n", retcode);
3299 return retcode; 3310 return retcode;
3300} 3311}
@@ -3674,8 +3685,8 @@ static int parse_and_run_stream(struct in_str *inp, int parse_flag)
3674 done_word(&temp, &ctx); 3685 done_word(&temp, &ctx);
3675 done_pipe(&ctx, PIPE_SEQ); 3686 done_pipe(&ctx, PIPE_SEQ);
3676 debug_print_tree(ctx.list_head, 0); 3687 debug_print_tree(ctx.list_head, 0);
3677 debug_printf_exec("parse_stream_outer: run_list\n"); 3688 debug_printf_exec("parse_stream_outer: run_and_free_list\n");
3678 run_list(ctx.list_head); 3689 run_and_free_list(ctx.list_head);
3679 } else { 3690 } else {
3680 if (ctx.old_flag != 0) { 3691 if (ctx.old_flag != 0) {
3681 free(ctx.stack); 3692 free(ctx.stack);
@@ -3684,7 +3695,7 @@ static int parse_and_run_stream(struct in_str *inp, int parse_flag)
3684 temp.nonnull = 0; 3695 temp.nonnull = 0;
3685 temp.o_quote = 0; 3696 temp.o_quote = 0;
3686 inp->p = NULL; 3697 inp->p = NULL;
3687 free_pipe_list(ctx.list_head, 0); 3698 free_pipe_list(ctx.list_head, /* indent: */ 0);
3688 } 3699 }
3689 b_free(&temp); 3700 b_free(&temp);
3690 } while (rcode != -1 && !(parse_flag & PARSEFLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */ 3701 } while (rcode != -1 && !(parse_flag & PARSEFLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */
@@ -3898,15 +3909,14 @@ int hush_main(int argc, char **argv)
3898 3909
3899 if (argv[optind] == NULL) { 3910 if (argv[optind] == NULL) {
3900 opt = parse_and_run_file(stdin); 3911 opt = parse_and_run_file(stdin);
3901 goto final_return; 3912 } else {
3913 debug_printf("\nrunning script '%s'\n", argv[optind]);
3914 global_argv = argv + optind;
3915 global_argc = argc - optind;
3916 input = xfopen(argv[optind], "r");
3917 opt = parse_and_run_file(input);
3902 } 3918 }
3903 3919
3904 debug_printf("\nrunning script '%s'\n", argv[optind]);
3905 global_argv = argv + optind;
3906 global_argc = argc - optind;
3907 input = xfopen(argv[optind], "r");
3908 opt = parse_and_run_file(input);
3909
3910 final_return: 3920 final_return:
3911 3921
3912#if ENABLE_FEATURE_CLEAN_UP 3922#if ENABLE_FEATURE_CLEAN_UP
diff --git a/shell/hush_doc.txt b/shell/hush_doc.txt
new file mode 100644
index 000000000..a3ead590c
--- /dev/null
+++ b/shell/hush_doc.txt
@@ -0,0 +1,39 @@
1 This is how hush runs commands:
2
3/* callsite: process_command_subs */
4generate_stream_from_list(struct pipe *head) - handles `cmds`
5 create UNIX pipe
6 [v]fork
7 child:
8 redirect pipe output to stdout
9 _exit(run_list(head)); /* leaks memory */
10 parent:
11 return UNIX pipe's output fd
12 /* head is freed by the caller */
13
14/* callsite: parse_and_run_stream */
15run_and_free_list(struct pipe *)
16 run_list(struct pipe *)
17 free_pipe_list(struct pipe *)
18
19/* callsites: generate_stream_from_list, run_and_free_list, pseudo_exec, run_pipe */
20run_list(struct pipe *) - handles "cmd; cmd2 && cmd3", while/for/do loops
21 run_pipe - for every pipe in list
22
23/* callsite: run_list */
24run_pipe - runs "cmd1 | cmd2 | cmd3 [&]"
25 run_list - used if only one cmd and it is of the form "{ cmd4; cmd5 && cmd6; }"
26 forks for every cmd if more than one cmd or if & is there
27 pseudo_exec - runs each "cmdN" (handles builtins etc)
28
29/* callsite: run_pipe_real */
30pseudo_exec - runs "cmd" (handles builtins etc)
31 exec - execs external programs
32 run_list - used if cmdN is "(cmds)" or "{cmds;}"
33 /* problem: putenv's malloced strings into environ -
34 ** with vfork they will leak into parent process
35 */
36 /* problem with ENABLE_FEATURE_SH_STANDALONE:
37 ** run_applet_no_and_exit(a, argv) uses exit - this can interfere
38 ** with vfork - switch to _exit there?
39 */
diff --git a/shell/hush_test/run-all b/shell/hush_test/run-all
index c75d81e55..805f75ad5 100755
--- a/shell/hush_test/run-all
+++ b/shell/hush_test/run-all
@@ -1,6 +1,9 @@
1#!/bin/sh 1#!/bin/sh
2 2
3test -x hush || { echo "No ./hush?!"; exit; } 3test -x hush || {
4 echo "No ./hush?! Perhaps you want to run 'ln -s ../../busybox hush'"
5 exit
6}
4 7
5PATH="$PWD:$PATH" # for hush and recho/zecho/printenv 8PATH="$PWD:$PATH" # for hush and recho/zecho/printenv
6export PATH 9export PATH
diff --git a/shell/hush_test/zbad2 b/shell/hush_test/zbad2
new file mode 100644
index 000000000..c30fa85a0
--- /dev/null
+++ b/shell/hush_test/zbad2
@@ -0,0 +1,19 @@
1## TODO: fix and add to testsuite
2
3## # bash zbad2
4## ZVAR=z.map
5## *.map
6## # hush zbad2
7## ZVAR=z.map
8## z.map <====== !!!
9
10## hush does globbing for "VAR=val" too!
11## it should do it only for non-assignments.
12## even if word looks like assignment, it can be non-assignemnt:
13## ZVAR=*.map /bin/echo ZVAR=*.map
14## ^dont_glob ^glob
15
16>ZVAR=z.map
17ZVAR=*.map /bin/echo ZVAR=*.map
18ZVAR=*.map
19echo "$ZVAR"