aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-05-06 14:15:42 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-05-06 14:15:42 +0000
commit21f0d4c55eceaf24f4f7e2b679032c55a104f1ac (patch)
tree347ba6d74433880a93084613329f2bf1baf0839b
parentb952835efe865a8303f69d7fdac75c7dc11265ce (diff)
downloadbusybox-w32-21f0d4c55eceaf24f4f7e2b679032c55a104f1ac.tar.gz
busybox-w32-21f0d4c55eceaf24f4f7e2b679032c55a104f1ac.tar.bz2
busybox-w32-21f0d4c55eceaf24f4f7e2b679032c55a104f1ac.zip
hush: fix double-free in "echo TEST &"
-rw-r--r--shell/README19
-rw-r--r--shell/hush.c183
2 files changed, 123 insertions, 79 deletions
diff --git a/shell/README b/shell/README
index 284c69145..d492671fb 100644
--- a/shell/README
+++ b/shell/README
@@ -1,7 +1,24 @@
1Various bits of what is known about busybox shells, in no particular order. 1Various bits of what is known about busybox shells, in no particular order.
2 2
32006-05-06
4hush: more bugs spotted. Comparison with bash:
5bash-3.2# echo "TEST`date;echo;echo`BEST"
6TESTSun May 6 09:21:05 CEST 2007BEST [we dont strip eols]
7bash-3.2# echo "TEST`echo '$(echo ZZ)'`BEST"
8TEST$(echo ZZ)BEST [we execute inner echo]
9bash-3.2# echo "TEST`echo "'"`BEST"
10TEST'BEST [we totally mess up this one]
11bash-3.2# echo `sleep 5`
12[Ctrl-C should work, Ctrl-Z should do nothing][we totally mess up this one]
13bash-3.2# if true; then
14> [Ctrl-C]
15bash-3.2# [we re-issue "> "]
16bash-3.2# if echo `sleep 5`; then
17> true; fi [we execute sleep before "> "]
18
32007-05-04 192007-05-04
4hush: make ctrl-Z/C work correctly for "while true; do true; done" 20hush: made ctrl-Z/C work correctly for "while true; do true; done"
21(namely, it backgrounds/interrupts entire "while")
5 22
62007-05-03 232007-05-03
7hush: new bug spotted: Ctrl-C on "while true; do true; done" doesn't 24hush: new bug spotted: Ctrl-C on "while true; do true; done" doesn't
diff --git a/shell/hush.c b/shell/hush.c
index a299b0123..7afcfbda1 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -87,34 +87,37 @@
87 * to perform debug printfs to stderr: */ 87 * to perform debug printfs to stderr: */
88#define debug_printf(...) do {} while (0) 88#define debug_printf(...) do {} while (0)
89/* Finer-grained debug switches */ 89/* Finer-grained debug switches */
90#define debug_printf_jobs(...) do {} while (0)
91#define debug_printf_exec(...) do {} while (0)
92#define debug_printf_parse(...) do {} while (0) 90#define debug_printf_parse(...) do {} while (0)
93#define debug_print_tree(a, b) do {} while (0) 91#define debug_print_tree(a, b) do {} while (0)
94 92#define debug_printf_exec(...) do {} while (0)
93#define debug_printf_jobs(...) do {} while (0)
94#define debug_printf_clean(...) do {} while (0)
95 95
96#ifndef debug_printf 96#ifndef debug_printf
97#define debug_printf(...) fprintf(stderr, __VA_ARGS__) 97#define debug_printf(...) fprintf(stderr, __VA_ARGS__)
98/* broken, of course, but OK for testing */
99static const char *indenter(int i)
100{
101 static const char blanks[] = " ";
102 return &blanks[sizeof(blanks) - i - 1];
103}
104#endif 98#endif
105#define final_printf debug_printf
106 99
107#ifndef debug_printf_jobs 100#ifndef debug_printf_parse
108#define debug_printf_jobs(...) fprintf(stderr, __VA_ARGS__) 101#define debug_printf_parse(...) fprintf(stderr, __VA_ARGS__)
109#define DEBUG_SHELL_JOBS 1
110#endif 102#endif
111 103
112#ifndef debug_printf_exec 104#ifndef debug_printf_exec
113#define debug_printf_exec(...) fprintf(stderr, __VA_ARGS__) 105#define debug_printf_exec(...) fprintf(stderr, __VA_ARGS__)
114#endif 106#endif
115 107
116#ifndef debug_printf_parse 108#ifndef debug_printf_jobs
117#define debug_printf_parse(...) fprintf(stderr, __VA_ARGS__) 109#define debug_printf_jobs(...) fprintf(stderr, __VA_ARGS__)
110#define DEBUG_SHELL_JOBS 1
111#endif
112
113#ifndef debug_printf_clean
114/* broken, of course, but OK for testing */
115static const char *indenter(int i)
116{
117 static const char blanks[] = " ";
118 return &blanks[sizeof(blanks) - i - 1];
119}
120#define debug_printf_clean(...) fprintf(stderr, __VA_ARGS__)
118#endif 121#endif
119 122
120 123
@@ -281,7 +284,7 @@ static unsigned last_bg_pid;
281enum { interactive_fd = 0 }; 284enum { interactive_fd = 0 };
282#else 285#else
283/* 'interactive_fd' is a fd# open to ctty, if we have one 286/* 'interactive_fd' is a fd# open to ctty, if we have one
284 * _AND_ if we decided to mess with job control */ 287 * _AND_ if we decided to act interactively */
285static int interactive_fd; 288static int interactive_fd;
286#if ENABLE_HUSH_JOB 289#if ENABLE_HUSH_JOB
287static pid_t saved_task_pgrp; 290static pid_t saved_task_pgrp;
@@ -379,6 +382,7 @@ static void mark_open(int fd);
379static void mark_closed(int fd); 382static void mark_closed(int fd);
380static void close_all(void); 383static void close_all(void);
381/* "run" the final data structures: */ 384/* "run" the final data structures: */
385//TODO: remove indent argument from non-debug build!
382static int free_pipe_list(struct pipe *head, int indent); 386static int free_pipe_list(struct pipe *head, int indent);
383static int free_pipe(struct pipe *pi, int indent); 387static int free_pipe(struct pipe *pi, int indent);
384/* really run the final data structures: */ 388/* really run the final data structures: */
@@ -537,10 +541,6 @@ static void handler_ctrl_z(int sig)
537 if (pid < 0) /* can't fork. Pretend there were no ctrl-Z */ 541 if (pid < 0) /* can't fork. Pretend there were no ctrl-Z */
538 return; 542 return;
539 ctrl_z_flag = 1; 543 ctrl_z_flag = 1;
540//vda: wrong!!
541// toplevel_list->running_progs = 1;
542// toplevel_list->stopped_progs = 0;
543//
544 if (!pid) { /* child */ 544 if (!pid) { /* child */
545 setpgrp(); 545 setpgrp();
546 debug_printf_jobs("set pgrp for child %d ok\n", getpid()); 546 debug_printf_jobs("set pgrp for child %d ok\n", getpid());
@@ -555,9 +555,6 @@ static void handler_ctrl_z(int sig)
555 /* finish filling up pipe info */ 555 /* finish filling up pipe info */
556 toplevel_list->pgrp = pid; /* child is in its own pgrp */ 556 toplevel_list->pgrp = pid; /* child is in its own pgrp */
557 toplevel_list->progs[0].pid = pid; 557 toplevel_list->progs[0].pid = pid;
558//vda: wrong!!
559// toplevel_list->running_progs = 1;
560// toplevel_list->stopped_progs = 0;
561 /* parent needs to longjmp out of running nofork. 558 /* parent needs to longjmp out of running nofork.
562 * we will "return" exitcode 0, with child put in background */ 559 * we will "return" exitcode 0, with child put in background */
563// as usual we can have all kinds of nasty problems with leaked malloc data here 560// as usual we can have all kinds of nasty problems with leaked malloc data here
@@ -1051,7 +1048,7 @@ static void cmdedit_set_initial_prompt(void)
1051 PS1 = "\\w \\$ "; 1048 PS1 = "\\w \\$ ";
1052#endif 1049#endif
1053} 1050}
1054#endif 1051#endif /* EDITING */
1055 1052
1056static const char* setup_prompt_string(int promptmode) 1053static const char* setup_prompt_string(int promptmode)
1057{ 1054{
@@ -1075,13 +1072,11 @@ static const char* setup_prompt_string(int promptmode)
1075 debug_printf("result %s\n", prompt_str); 1072 debug_printf("result %s\n", prompt_str);
1076 return prompt_str; 1073 return prompt_str;
1077} 1074}
1078#endif /* ENABLE_HUSH_INTERACTIVE */
1079 1075
1080#if ENABLE_FEATURE_EDITING 1076#if ENABLE_FEATURE_EDITING
1081static line_input_t *line_input_state; 1077static line_input_t *line_input_state;
1082#endif 1078#endif
1083 1079
1084#if ENABLE_HUSH_INTERACTIVE
1085static int get_user_input(struct in_str *i) 1080static int get_user_input(struct in_str *i)
1086{ 1081{
1087 static char the_command[ENABLE_FEATURE_EDITING ? BUFSIZ : 2]; 1082 static char the_command[ENABLE_FEATURE_EDITING ? BUFSIZ : 2];
@@ -1096,18 +1091,18 @@ static int get_user_input(struct in_str *i)
1096 ** atexit() handlers and other unwanted stuff to our 1091 ** atexit() handlers and other unwanted stuff to our
1097 ** child processes (rob@sysgo.de) 1092 ** child processes (rob@sysgo.de)
1098 */ 1093 */
1099 r = read_line_input(prompt_str, the_command, BUFSIZ, line_input_state); 1094 r = read_line_input(prompt_str, the_command, BUFSIZ-1, line_input_state);
1100#else 1095#else
1101 fputs(prompt_str, stdout); 1096 fputs(prompt_str, stdout);
1102 fflush(stdout); 1097 fflush(stdout);
1103 the_command[0] = r = fgetc(i->file); 1098 the_command[0] = r = fgetc(i->file);
1104 the_command[1] = '\0'; 1099 /*the_command[1] = '\0'; - already is and never changed */
1105#endif 1100#endif
1106 fflush(stdout); 1101 fflush(stdout);
1107 i->p = the_command; 1102 i->p = the_command;
1108 return r; /* < 0 == EOF. Not meaningful otherwise */ 1103 return r; /* < 0 == EOF. Not meaningful otherwise */
1109} 1104}
1110#endif 1105#endif /* INTERACTIVE */
1111 1106
1112/* This is the magic location that prints prompts 1107/* This is the magic location that prints prompts
1113 * and gets data back from the user */ 1108 * and gets data back from the user */
@@ -1279,7 +1274,7 @@ static void pseudo_exec_argv(char **argv)
1279 for (i = 0; is_assignment(argv[i]); i++) { 1274 for (i = 0; is_assignment(argv[i]); i++) {
1280 debug_printf("pid %d environment modification: %s\n", 1275 debug_printf("pid %d environment modification: %s\n",
1281 getpid(), argv[i]); 1276 getpid(), argv[i]);
1282 // FIXME: vfork case?? 1277// FIXME: vfork case??
1283 p = insert_var_value(argv[i]); 1278 p = insert_var_value(argv[i]);
1284 putenv(strdup(p)); 1279 putenv(strdup(p));
1285 if (p != argv[i]) 1280 if (p != argv[i])
@@ -1342,6 +1337,7 @@ static void pseudo_exec(struct child_prog *child)
1342 if (child->group) { 1337 if (child->group) {
1343 // FIXME: do not modify globals! Think vfork! 1338 // FIXME: do not modify globals! Think vfork!
1344#if ENABLE_HUSH_INTERACTIVE 1339#if ENABLE_HUSH_INTERACTIVE
1340 debug_printf_exec("pseudo_exec: setting interactive_fd=0\n");
1345 interactive_fd = 0; /* crucial!!!! */ 1341 interactive_fd = 0; /* crucial!!!! */
1346#endif 1342#endif
1347 debug_printf_exec("pseudo_exec: run_list_real\n"); 1343 debug_printf_exec("pseudo_exec: run_list_real\n");
@@ -1365,7 +1361,7 @@ static const char *get_cmdtext(struct pipe *pi)
1365 1361
1366 /* This is subtle. ->cmdtext is created only on first backgrounding. 1362 /* This is subtle. ->cmdtext is created only on first backgrounding.
1367 * (Think "cat, <ctrl-z>, fg, <ctrl-z>, fg, <ctrl-z>...." here...) 1363 * (Think "cat, <ctrl-z>, fg, <ctrl-z>, fg, <ctrl-z>...." here...)
1368 * On subsequent bg argv can be trashed, but we won't use it */ 1364 * On subsequent bg argv is trashed, but we won't use it */
1369 if (pi->cmdtext) 1365 if (pi->cmdtext)
1370 return pi->cmdtext; 1366 return pi->cmdtext;
1371 argv = pi->progs[0].argv; 1367 argv = pi->progs[0].argv;
@@ -1385,12 +1381,11 @@ static const char *get_cmdtext(struct pipe *pi)
1385 p[-1] = '\0'; 1381 p[-1] = '\0';
1386 return pi->cmdtext; 1382 return pi->cmdtext;
1387} 1383}
1388#endif
1389 1384
1390#if ENABLE_HUSH_JOB
1391static void insert_bg_job(struct pipe *pi) 1385static void insert_bg_job(struct pipe *pi)
1392{ 1386{
1393 struct pipe *thejob; 1387 struct pipe *thejob;
1388 int i;
1394 1389
1395 /* Linear search for the ID of the job to use */ 1390 /* Linear search for the ID of the job to use */
1396 pi->jobid = 1; 1391 pi->jobid = 1;
@@ -1398,7 +1393,7 @@ static void insert_bg_job(struct pipe *pi)
1398 if (thejob->jobid >= pi->jobid) 1393 if (thejob->jobid >= pi->jobid)
1399 pi->jobid = thejob->jobid + 1; 1394 pi->jobid = thejob->jobid + 1;
1400 1395
1401 /* add thejob to the list of running jobs */ 1396 /* Add thejob to the list of running jobs */
1402 if (!job_list) { 1397 if (!job_list) {
1403 thejob = job_list = xmalloc(sizeof(*thejob)); 1398 thejob = job_list = xmalloc(sizeof(*thejob));
1404 } else { 1399 } else {
@@ -1408,17 +1403,29 @@ static void insert_bg_job(struct pipe *pi)
1408 thejob = thejob->next; 1403 thejob = thejob->next;
1409 } 1404 }
1410 1405
1411 /* physically copy the struct job */ 1406 /* Physically copy the struct job */
1412 memcpy(thejob, pi, sizeof(struct pipe)); 1407 memcpy(thejob, pi, sizeof(struct pipe));
1413 thejob->progs = xmalloc(sizeof(pi->progs[0]) * pi->num_progs); 1408 thejob->progs = xzalloc(sizeof(pi->progs[0]) * pi->num_progs);
1414 memcpy(thejob->progs, pi->progs, sizeof(pi->progs[0]) * pi->num_progs); 1409 /* We cannot copy entire pi->progs[] vector! Double free()s will happen */
1410 for (i = 0; i < pi->num_progs; i++) {
1411// TODO: do we really need to have so many fields which are just dead weight
1412// at execution stage?
1413 thejob->progs[i].pid = pi->progs[i].pid;
1414 //rest:
1415 //char **argv; /* program name and arguments */
1416 //struct pipe *group; /* if non-NULL, first in group or subshell */
1417 //int subshell; /* flag, non-zero if group must be forked */
1418 //struct redir_struct *redirects; /* I/O redirections */
1419 //glob_t glob_result; /* result of parameter globbing */
1420 //int is_stopped; /* is the program currently running? */
1421 //struct pipe *family; /* pointer back to the child's parent pipe */
1422 //int sp; /* number of SPECIAL_VAR_SYMBOL */
1423 //int type;
1424 }
1415 thejob->next = NULL; 1425 thejob->next = NULL;
1416 /*seems to be wrong:*/
1417 /*thejob->running_progs = thejob->num_progs;*/
1418 /*thejob->stopped_progs = 0;*/
1419 thejob->cmdtext = xstrdup(get_cmdtext(pi)); 1426 thejob->cmdtext = xstrdup(get_cmdtext(pi));
1420 1427
1421 /* we don't wait for background thejobs to return -- append it 1428 /* We don't wait for background thejobs to return -- append it
1422 to the list of backgrounded thejobs and leave it alone */ 1429 to the list of backgrounded thejobs and leave it alone */
1423 printf("[%d] %d %s\n", thejob->jobid, thejob->progs[0].pid, thejob->cmdtext); 1430 printf("[%d] %d %s\n", thejob->jobid, thejob->progs[0].pid, thejob->cmdtext);
1424 last_bg_pid = thejob->progs[0].pid; 1431 last_bg_pid = thejob->progs[0].pid;
@@ -1451,7 +1458,7 @@ static void delete_finished_bg_job(struct pipe *pi)
1451 free_pipe(pi, 0); 1458 free_pipe(pi, 0);
1452 free(pi); 1459 free(pi);
1453} 1460}
1454#endif 1461#endif /* JOB */
1455 1462
1456/* Checks to see if any processes have exited -- if they 1463/* Checks to see if any processes have exited -- if they
1457 have, figure out why and see if a job has completed */ 1464 have, figure out why and see if a job has completed */
@@ -1622,7 +1629,7 @@ static int run_pipe_real(struct pipe *pi)
1622 int rcode; 1629 int rcode;
1623 const int single_fg = (pi->num_progs == 1 && pi->followup != PIPE_BG); 1630 const int single_fg = (pi->num_progs == 1 && pi->followup != PIPE_BG);
1624 1631
1625 debug_printf_exec("run_pipe_real start:\n"); 1632 debug_printf_exec("run_pipe_real start: single_fg=%d\n", single_fg);
1626 1633
1627 nextin = 0; 1634 nextin = 0;
1628#if ENABLE_HUSH_JOB 1635#if ENABLE_HUSH_JOB
@@ -1724,7 +1731,7 @@ static int run_pipe_real(struct pipe *pi)
1724 setup_redirects(child, squirrel); 1731 setup_redirects(child, squirrel);
1725 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv[i], argv[i+1]); 1732 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv[i], argv[i+1]);
1726 save_nofork_data(&nofork_save); 1733 save_nofork_data(&nofork_save);
1727 rcode = run_nofork_applet_prime(&nofork_save, a, argv); 1734 rcode = run_nofork_applet_prime(&nofork_save, a, argv + i);
1728 restore_redirects(squirrel); 1735 restore_redirects(squirrel);
1729 debug_printf_exec("run_pipe_real return %d\n", rcode); 1736 debug_printf_exec("run_pipe_real return %d\n", rcode);
1730 return rcode; 1737 return rcode;
@@ -1742,7 +1749,10 @@ static int run_pipe_real(struct pipe *pi)
1742 1749
1743 for (i = 0; i < pi->num_progs; i++) { 1750 for (i = 0; i < pi->num_progs; i++) {
1744 child = &(pi->progs[i]); 1751 child = &(pi->progs[i]);
1745 debug_printf_exec(": pipe member '%s' '%s'...\n", child->argv[0], child->argv[1]); 1752 if (child->argv)
1753 debug_printf_exec(": pipe member '%s' '%s'...\n", child->argv[0], child->argv[1]);
1754 else
1755 debug_printf_exec(": pipe member with no argv\n");
1746 1756
1747 /* pipes are inserted between pairs of commands */ 1757 /* pipes are inserted between pairs of commands */
1748 if ((i + 1) < pi->num_progs) { 1758 if ((i + 1) < pi->num_progs) {
@@ -1833,8 +1843,8 @@ static void debug_print_tree(struct pipe *pi, int lvl)
1833 static const char *PIPE[] = { 1843 static const char *PIPE[] = {
1834 [PIPE_SEQ] = "SEQ", 1844 [PIPE_SEQ] = "SEQ",
1835 [PIPE_AND] = "AND", 1845 [PIPE_AND] = "AND",
1836 [PIPE_OR ] = "OR", 1846 [PIPE_OR ] = "OR" ,
1837 [PIPE_BG ] = "BG", 1847 [PIPE_BG ] = "BG" ,
1838 }; 1848 };
1839 static const char *RES[] = { 1849 static const char *RES[] = {
1840 [RES_NONE ] = "NONE" , 1850 [RES_NONE ] = "NONE" ,
@@ -1914,14 +1924,15 @@ static int run_list_real(struct pipe *pi)
1914 if ((rpipe->r_mode == RES_IN || rpipe->r_mode == RES_FOR) 1924 if ((rpipe->r_mode == RES_IN || rpipe->r_mode == RES_FOR)
1915 && (rpipe->next == NULL) 1925 && (rpipe->next == NULL)
1916 ) { 1926 ) {
1917 syntax(); 1927 syntax(); /* unterminated FOR (no IN or no commands after IN) */
1918 debug_printf_exec("run_list_real lvl %d return 1\n", level); 1928 debug_printf_exec("run_list_real lvl %d return 1\n", level);
1919 return 1; 1929 return 1;
1920 } 1930 }
1921 if ((rpipe->r_mode == RES_IN && rpipe->next->r_mode == RES_IN && rpipe->next->progs->argv != NULL) 1931 if ((rpipe->r_mode == RES_IN && rpipe->next->r_mode == RES_IN && rpipe->next->progs[0].argv != NULL)
1922 || (rpipe->r_mode == RES_FOR && rpipe->next->r_mode != RES_IN) 1932 || (rpipe->r_mode == RES_FOR && rpipe->next->r_mode != RES_IN)
1923 ) { 1933 ) {
1924 syntax(); 1934 /* TODO: what is tested in the first condition? */
1935 syntax(); /* 2nd: malformed FOR (not followed by IN) */
1925 debug_printf_exec("run_list_real lvl %d return 1\n", level); 1936 debug_printf_exec("run_list_real lvl %d return 1\n", level);
1926 return 1; 1937 return 1;
1927 } 1938 }
@@ -1952,7 +1963,7 @@ static int run_list_real(struct pipe *pi)
1952 * Remember this child as background job */ 1963 * Remember this child as background job */
1953 insert_bg_job(pi); 1964 insert_bg_job(pi);
1954 } else { 1965 } else {
1955 /* ctrl-C. We just stop doing whatever we was doing */ 1966 /* ctrl-C. We just stop doing whatever we were doing */
1956 putchar('\n'); 1967 putchar('\n');
1957 } 1968 }
1958 rcode = 0; 1969 rcode = 0;
@@ -2018,8 +2029,7 @@ static int run_list_real(struct pipe *pi)
2018 continue; 2029 continue;
2019 } 2030 }
2020 /* insert new value from list for variable */ 2031 /* insert new value from list for variable */
2021 if (pi->progs->argv[0]) 2032 free(pi->progs->argv[0]);
2022 free(pi->progs->argv[0]);
2023 pi->progs->argv[0] = *list++; 2033 pi->progs->argv[0] = *list++;
2024 pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0]; 2034 pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0];
2025 } 2035 }
@@ -2045,16 +2055,21 @@ static int run_list_real(struct pipe *pi)
2045 /* We only ran a builtin: rcode was set by the return value 2055 /* We only ran a builtin: rcode was set by the return value
2046 * of run_pipe_real(), and we don't need to wait for anything. */ 2056 * of run_pipe_real(), and we don't need to wait for anything. */
2047 } else if (pi->followup == PIPE_BG) { 2057 } else if (pi->followup == PIPE_BG) {
2048 /* XXX check bash's behavior with nontrivial pipes */ 2058 /* What does bash do with attempts to background builtins? */
2049 /* XXX compute jobid */ 2059
2050 /* XXX what does bash do with attempts to background builtins? */ 2060 /* Even bash 3.2 doesn't do that well with nested bg:
2061 * try "{ { sleep 10; echo DEEP; } & echo HERE; } &".
2062 * I'm considering NOT treating inner bgs as jobs -
2063 * thus maybe "if (level == 1 && pi->followup == PIPE_BG)"
2064 * above? */
2051#if ENABLE_HUSH_JOB 2065#if ENABLE_HUSH_JOB
2052 insert_bg_job(pi); 2066 insert_bg_job(pi);
2053#endif 2067#endif
2054 rcode = EXIT_SUCCESS; 2068 rcode = EXIT_SUCCESS;
2055 } else { 2069 } else {
2056#if ENABLE_HUSH_JOB 2070#if ENABLE_HUSH_JOB
2057 if (interactive_fd) { 2071 /* Paranoia, just "interactive_fd" should be enough */
2072 if (level == 1 && interactive_fd) {
2058 rcode = checkjobs_and_fg_shell(pi); 2073 rcode = checkjobs_and_fg_shell(pi);
2059 } else 2074 } else
2060#endif 2075#endif
@@ -2103,33 +2118,33 @@ static int free_pipe(struct pipe *pi, int indent)
2103 2118
2104 if (pi->stopped_progs > 0) 2119 if (pi->stopped_progs > 0)
2105 return ret_code; 2120 return ret_code;
2106 final_printf("%s run pipe: (pid %d)\n", indenter(indent), getpid()); 2121 debug_printf_clean("%s run pipe: (pid %d)\n", indenter(indent), getpid());
2107 for (i = 0; i < pi->num_progs; i++) { 2122 for (i = 0; i < pi->num_progs; i++) {
2108 child = &pi->progs[i]; 2123 child = &pi->progs[i];
2109 final_printf("%s command %d:\n", indenter(indent), i); 2124 debug_printf_clean("%s command %d:\n", indenter(indent), i);
2110 if (child->argv) { 2125 if (child->argv) {
2111 for (a = 0, p = child->argv; *p; a++, p++) { 2126 for (a = 0, p = child->argv; *p; a++, p++) {
2112 final_printf("%s argv[%d] = %s\n", indenter(indent), a, *p); 2127 debug_printf_clean("%s argv[%d] = %s\n", indenter(indent), a, *p);
2113 } 2128 }
2114 globfree(&child->glob_result); 2129 globfree(&child->glob_result);
2115 child->argv = NULL; 2130 child->argv = NULL;
2116 } else if (child->group) { 2131 } else if (child->group) {
2117 final_printf("%s begin group (subshell:%d)\n", indenter(indent), child->subshell); 2132 debug_printf_clean("%s begin group (subshell:%d)\n", indenter(indent), child->subshell);
2118 ret_code = free_pipe_list(child->group, indent+3); 2133 ret_code = free_pipe_list(child->group, indent+3);
2119 final_printf("%s end group\n", indenter(indent)); 2134 debug_printf_clean("%s end group\n", indenter(indent));
2120 } else { 2135 } else {
2121 final_printf("%s (nil)\n", indenter(indent)); 2136 debug_printf_clean("%s (nil)\n", indenter(indent));
2122 } 2137 }
2123 for (r = child->redirects; r; r = rnext) { 2138 for (r = child->redirects; r; r = rnext) {
2124 final_printf("%s redirect %d%s", indenter(indent), r->fd, redir_table[r->type].descrip); 2139 debug_printf_clean("%s redirect %d%s", indenter(indent), r->fd, redir_table[r->type].descrip);
2125 if (r->dup == -1) { 2140 if (r->dup == -1) {
2126 /* guard against the case >$FOO, where foo is unset or blank */ 2141 /* guard against the case >$FOO, where foo is unset or blank */
2127 if (r->word.gl_pathv) { 2142 if (r->word.gl_pathv) {
2128 final_printf(" %s\n", *r->word.gl_pathv); 2143 debug_printf_clean(" %s\n", *r->word.gl_pathv);
2129 globfree(&r->word); 2144 globfree(&r->word);
2130 } 2145 }
2131 } else { 2146 } else {
2132 final_printf("&%d\n", r->dup); 2147 debug_printf_clean("&%d\n", r->dup);
2133 } 2148 }
2134 rnext = r->next; 2149 rnext = r->next;
2135 free(r); 2150 free(r);
@@ -2149,10 +2164,11 @@ static int free_pipe_list(struct pipe *head, int indent)
2149{ 2164{
2150 int rcode = 0; /* if list has no members */ 2165 int rcode = 0; /* if list has no members */
2151 struct pipe *pi, *next; 2166 struct pipe *pi, *next;
2167
2152 for (pi = head; pi; pi = next) { 2168 for (pi = head; pi; pi = next) {
2153 final_printf("%s pipe reserved mode %d\n", indenter(indent), pi->r_mode); 2169 debug_printf_clean("%s pipe reserved mode %d\n", indenter(indent), pi->r_mode);
2154 rcode = free_pipe(pi, indent); 2170 rcode = free_pipe(pi, indent);
2155 final_printf("%s pipe followup code %d\n", indenter(indent), pi->followup); 2171 debug_printf_clean("%s pipe followup code %d\n", indenter(indent), pi->followup);
2156 next = pi->next; 2172 next = pi->next;
2157 /*pi->next = NULL;*/ 2173 /*pi->next = NULL;*/
2158 free(pi); 2174 free(pi);
@@ -2164,14 +2180,16 @@ static int free_pipe_list(struct pipe *head, int indent)
2164static int run_list(struct pipe *pi) 2180static int run_list(struct pipe *pi)
2165{ 2181{
2166 int rcode = 0; 2182 int rcode = 0;
2183 debug_printf_exec("run_list entered\n");
2167 if (fake_mode == 0) { 2184 if (fake_mode == 0) {
2168 debug_printf_exec("run_list: run_list_real with %d members\n", pi->num_progs); 2185 debug_printf_exec(": run_list_real with %d members\n", pi->num_progs);
2169 rcode = run_list_real(pi); 2186 rcode = run_list_real(pi);
2170 } 2187 }
2171 /* free_pipe_list has the side effect of clearing memory 2188 /* free_pipe_list has the side effect of clearing memory.
2172 * In the long run that function can be merged with run_list_real, 2189 * In the long run that function can be merged with run_list_real,
2173 * but doing that now would hobble the debugging effort. */ 2190 * but doing that now would hobble the debugging effort. */
2174 free_pipe_list(pi, 0); 2191 free_pipe_list(pi, 0);
2192 debug_printf_exec("run_list return %d\n", rcode);
2175 return rcode; 2193 return rcode;
2176} 2194}
2177 2195
@@ -2201,7 +2219,7 @@ static int globhack(const char *src, int flags, glob_t *pglob)
2201 pglob->gl_offs = 0; 2219 pglob->gl_offs = 0;
2202 } 2220 }
2203 pathc = ++pglob->gl_pathc; 2221 pathc = ++pglob->gl_pathc;
2204 pglob->gl_pathv = realloc(pglob->gl_pathv, (pathc+1)*sizeof(*pglob->gl_pathv)); 2222 pglob->gl_pathv = realloc(pglob->gl_pathv, (pathc+1) * sizeof(*pglob->gl_pathv));
2205 if (pglob->gl_pathv == NULL) 2223 if (pglob->gl_pathv == NULL)
2206 return GLOB_NOSPACE; 2224 return GLOB_NOSPACE;
2207 pglob->gl_pathv[pathc-1] = dest; 2225 pglob->gl_pathv[pathc-1] = dest;
@@ -2821,8 +2839,7 @@ static FILE *generate_stream_from_list(struct pipe *head)
2821 return pf; 2839 return pf;
2822} 2840}
2823 2841
2824/* this version hacked for testing purposes */ 2842/* Return code is exit status of the process that is run. */
2825/* return code is exit status of the process that is run. */
2826static int process_command_subs(o_string *dest, struct p_context *ctx, 2843static int process_command_subs(o_string *dest, struct p_context *ctx,
2827 struct in_str *input, const char *subst_end) 2844 struct in_str *input, const char *subst_end)
2828{ 2845{
@@ -2843,9 +2860,19 @@ static int process_command_subs(o_string *dest, struct p_context *ctx,
2843 p = generate_stream_from_list(inner.list_head); 2860 p = generate_stream_from_list(inner.list_head);
2844 if (p == NULL) return 1; 2861 if (p == NULL) return 1;
2845 mark_open(fileno(p)); 2862 mark_open(fileno(p));
2863// FIXME: need to flag pipe_str to somehow discard all trailing newlines.
2864// Example: echo "TEST`date;echo;echo`BEST"
2865// must produce one line: TEST<date>BEST
2846 setup_file_in_str(&pipe_str, p); 2866 setup_file_in_str(&pipe_str, p);
2847 2867
2848 /* now send results of command back into original context */ 2868 /* now send results of command back into original context */
2869// FIXME: must not do quote parsing of the output!
2870// Example: echo "TEST`echo '$(echo ZZ)'`BEST"
2871// must produce TEST$(echo ZZ)BEST, not TESTZZBEST.
2872// Example: echo "TEST`echo "'"`BEST"
2873// must produce TEST'BEST
2874// (maybe by setting all chars flagged as literals in map[]?)
2875
2849 retcode = parse_stream(dest, ctx, &pipe_str, NULL); 2876 retcode = parse_stream(dest, ctx, &pipe_str, NULL);
2850 /* XXX In case of a syntax error, should we try to kill the child? 2877 /* XXX In case of a syntax error, should we try to kill the child?
2851 * That would be tough to do right, so just read until EOF. */ 2878 * That would be tough to do right, so just read until EOF. */
@@ -2864,7 +2891,6 @@ static int process_command_subs(o_string *dest, struct p_context *ctx,
2864 retcode = pclose(p); 2891 retcode = pclose(p);
2865 free_pipe_list(inner.list_head, 0); 2892 free_pipe_list(inner.list_head, 0);
2866 debug_printf("pclosed, retcode=%d\n", retcode); 2893 debug_printf("pclosed, retcode=%d\n", retcode);
2867 /* XXX this process fails to trim a single trailing newline */
2868 return retcode; 2894 return retcode;
2869} 2895}
2870 2896
@@ -2904,7 +2930,7 @@ static int parse_group(o_string *dest, struct p_context *ctx,
2904 /* child remains "open", available for possible redirects */ 2930 /* child remains "open", available for possible redirects */
2905} 2931}
2906 2932
2907/* basically useful version until someone wants to get fancier, 2933/* Basically useful version until someone wants to get fancier,
2908 * see the bash man page under "Parameter Expansion" */ 2934 * see the bash man page under "Parameter Expansion" */
2909static const char *lookup_param(const char *src) 2935static const char *lookup_param(const char *src)
2910{ 2936{
@@ -3272,8 +3298,8 @@ static int parse_stream_outer(struct in_str *inp, int parse_flag)
3272 if (rcode != 1 && ctx.old_flag == 0) { 3298 if (rcode != 1 && ctx.old_flag == 0) {
3273 done_word(&temp, &ctx); 3299 done_word(&temp, &ctx);
3274 done_pipe(&ctx, PIPE_SEQ); 3300 done_pipe(&ctx, PIPE_SEQ);
3275 debug_printf_exec("parse_stream_outer: run_list\n");
3276 debug_print_tree(ctx.list_head, 0); 3301 debug_print_tree(ctx.list_head, 0);
3302 debug_printf_exec("parse_stream_outer: run_list\n");
3277 run_list(ctx.list_head); 3303 run_list(ctx.list_head);
3278 } else { 3304 } else {
3279 if (ctx.old_flag != 0) { 3305 if (ctx.old_flag != 0) {
@@ -3392,7 +3418,7 @@ int hush_main(int argc, char **argv)
3392 last_return_code = EXIT_SUCCESS; 3418 last_return_code = EXIT_SUCCESS;
3393 3419
3394 if (argv[0] && argv[0][0] == '-') { 3420 if (argv[0] && argv[0][0] == '-') {
3395 debug_printf("\nsourcing /etc/profile\n"); 3421 debug_printf("sourcing /etc/profile\n");
3396 input = fopen("/etc/profile", "r"); 3422 input = fopen("/etc/profile", "r");
3397 if (input != NULL) { 3423 if (input != NULL) {
3398 mark_open(fileno(input)); 3424 mark_open(fileno(input));
@@ -3455,12 +3481,13 @@ int hush_main(int argc, char **argv)
3455 // to (inadvertently) close/redirect it 3481 // to (inadvertently) close/redirect it
3456 } 3482 }
3457 } 3483 }
3458 debug_printf("\ninteractive_fd=%d\n", interactive_fd); 3484 debug_printf("interactive_fd=%d\n", interactive_fd);
3459 if (interactive_fd) { 3485 if (interactive_fd) {
3460 /* Looks like they want an interactive shell */ 3486 /* Looks like they want an interactive shell */
3461 setup_job_control(); 3487 setup_job_control();
3462 /* Make xfuncs do cleanup on exit */ 3488 /* Make xfuncs do cleanup on exit */
3463 die_sleep = -1; /* flag */ 3489 die_sleep = -1; /* flag */
3490// FIXME: should we reset die_sleep = 0 whereever we fork?
3464 if (setjmp(die_jmp)) { 3491 if (setjmp(die_jmp)) {
3465 /* xfunc has failed! die die die */ 3492 /* xfunc has failed! die die die */
3466 hush_exit(xfunc_error_retval); 3493 hush_exit(xfunc_error_retval);