diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-04 21:37:27 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-04 21:37:27 +0000 |
commit | ac0e5ab96ac35d46a6e0755f6f24f016ce788d90 (patch) | |
tree | accdf0c9bacae6e89a658d0382cbe343c062a84f /shell/hush.c | |
parent | 3349fc4da948eb1393cd9201cd9c2615c0056c97 (diff) | |
download | busybox-w32-ac0e5ab96ac35d46a6e0755f6f24f016ce788d90.tar.gz busybox-w32-ac0e5ab96ac35d46a6e0755f6f24f016ce788d90.tar.bz2 busybox-w32-ac0e5ab96ac35d46a6e0755f6f24f016ce788d90.zip |
hush: fix "while true; do true; done" + ctrl-z
Diffstat (limited to 'shell/hush.c')
-rw-r--r-- | shell/hush.c | 212 |
1 files changed, 120 insertions, 92 deletions
diff --git a/shell/hush.c b/shell/hush.c index c51ed1a51..78531e864 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -468,7 +468,6 @@ static const struct built_in_command bltins[] = { | |||
468 | 468 | ||
469 | #if ENABLE_HUSH_JOB | 469 | #if ENABLE_HUSH_JOB |
470 | 470 | ||
471 | #if ENABLE_FEATURE_SH_STANDALONE | ||
472 | /* move to libbb? */ | 471 | /* move to libbb? */ |
473 | static void signal_SA_RESTART(int sig, void (*handler)(int)) | 472 | static void signal_SA_RESTART(int sig, void (*handler)(int)) |
474 | { | 473 | { |
@@ -478,7 +477,6 @@ static void signal_SA_RESTART(int sig, void (*handler)(int)) | |||
478 | sigemptyset(&sa.sa_mask); | 477 | sigemptyset(&sa.sa_mask); |
479 | sigaction(sig, &sa, NULL); | 478 | sigaction(sig, &sa, NULL); |
480 | } | 479 | } |
481 | #endif | ||
482 | 480 | ||
483 | /* Signals are grouped, we handle them in batches */ | 481 | /* Signals are grouped, we handle them in batches */ |
484 | static void set_fatal_sighandler(void (*handler)(int)) | 482 | static void set_fatal_sighandler(void (*handler)(int)) |
@@ -508,7 +506,6 @@ static void set_misc_sighandler(void (*handler)(int)) | |||
508 | } | 506 | } |
509 | /* SIGCHLD is special and handled separately */ | 507 | /* SIGCHLD is special and handled separately */ |
510 | 508 | ||
511 | #if ENABLE_FEATURE_SH_STANDALONE | ||
512 | static void set_every_sighandler(void (*handler)(int)) | 509 | static void set_every_sighandler(void (*handler)(int)) |
513 | { | 510 | { |
514 | set_fatal_sighandler(handler); | 511 | set_fatal_sighandler(handler); |
@@ -517,53 +514,57 @@ static void set_every_sighandler(void (*handler)(int)) | |||
517 | signal(SIGCHLD, handler); | 514 | signal(SIGCHLD, handler); |
518 | } | 515 | } |
519 | 516 | ||
520 | static struct pipe *nofork_pipe; | 517 | static struct pipe *toplevel_list; |
518 | static sigjmp_buf toplevel_jb; | ||
519 | smallint ctrl_z_flag; | ||
520 | #if ENABLE_FEATURE_SH_STANDALONE | ||
521 | struct nofork_save_area nofork_save; | 521 | struct nofork_save_area nofork_save; |
522 | static sigjmp_buf nofork_jb; | 522 | #endif |
523 | 523 | ||
524 | static void handler_ctrl_c(int sig) | 524 | static void handler_ctrl_c(int sig) |
525 | { | 525 | { |
526 | debug_printf_jobs("got sig %d\n", sig); | 526 | debug_printf_jobs("got sig %d\n", sig); |
527 | // as usual we can have all kinds of nasty problems with leaked malloc data here | 527 | // as usual we can have all kinds of nasty problems with leaked malloc data here |
528 | siglongjmp(nofork_jb, 1); | 528 | siglongjmp(toplevel_jb, 1); |
529 | } | 529 | } |
530 | 530 | ||
531 | static void handler_ctrl_z(int sig) | 531 | static void handler_ctrl_z(int sig) |
532 | { | 532 | { |
533 | pid_t pid; | 533 | pid_t pid; |
534 | 534 | ||
535 | debug_printf_jobs("got tty sig %d\n", sig); | 535 | debug_printf_jobs("got tty sig %d in pid %d\n", sig, getpid()); |
536 | pid = fork(); | 536 | pid = fork(); |
537 | if (pid < 0) /* can't fork. Pretend there were no Ctrl-Z */ | 537 | if (pid < 0) /* can't fork. Pretend there were no ctrl-Z */ |
538 | return; | 538 | return; |
539 | debug_printf_jobs("bg'ing nofork\n"); | 539 | ctrl_z_flag = 1; |
540 | nofork_save.saved = 0; /* flag the fact that Ctrl-Z was handled */ | 540 | //vda: wrong!! |
541 | nofork_pipe->running_progs = 1; | 541 | // toplevel_list->running_progs = 1; |
542 | nofork_pipe->stopped_progs = 0; | 542 | // toplevel_list->stopped_progs = 0; |
543 | // | ||
543 | if (!pid) { /* child */ | 544 | if (!pid) { /* child */ |
544 | debug_printf_jobs("setting pgrp for child\n"); | ||
545 | setpgrp(); | 545 | setpgrp(); |
546 | debug_printf_jobs("set pgrp for child %d ok\n", getpid()); | ||
546 | set_every_sighandler(SIG_DFL); | 547 | set_every_sighandler(SIG_DFL); |
547 | raise(SIGTSTP); /* resend TSTP so that child will be stopped */ | 548 | raise(SIGTSTP); /* resend TSTP so that child will be stopped */ |
548 | debug_printf_jobs("returning to child\n"); | 549 | debug_printf_jobs("returning in child\n"); |
549 | /* return to nofork, it will eventually exit now, | 550 | /* return to nofork, it will eventually exit now, |
550 | * not return back to shell */ | 551 | * not return back to shell */ |
551 | return; | 552 | return; |
552 | } | 553 | } |
553 | /* parent */ | 554 | /* parent */ |
554 | /* finish filling up pipe info */ | 555 | /* finish filling up pipe info */ |
555 | nofork_pipe->pgrp = pid; /* child is in its own pgrp */ | 556 | toplevel_list->pgrp = pid; /* child is in its own pgrp */ |
556 | nofork_pipe->progs[0].pid = pid; | 557 | toplevel_list->progs[0].pid = pid; |
557 | nofork_pipe->running_progs = 1; | 558 | //vda: wrong!! |
558 | nofork_pipe->stopped_progs = 0; | 559 | // toplevel_list->running_progs = 1; |
560 | // toplevel_list->stopped_progs = 0; | ||
559 | /* parent needs to longjmp out of running nofork. | 561 | /* parent needs to longjmp out of running nofork. |
560 | * we will "return" exitcode 0, with child put in background */ | 562 | * we will "return" exitcode 0, with child put in background */ |
561 | // as usual we can have all kinds of nasty problems with leaked malloc data here | 563 | // as usual we can have all kinds of nasty problems with leaked malloc data here |
562 | siglongjmp(nofork_jb, 1); | 564 | debug_printf_jobs("siglongjmp in parent\n"); |
565 | siglongjmp(toplevel_jb, 1); | ||
563 | } | 566 | } |
564 | 567 | ||
565 | #endif | ||
566 | |||
567 | /* Restores tty foreground process group, and exits. | 568 | /* Restores tty foreground process group, and exits. |
568 | * May be called as signal handler for fatal signal | 569 | * May be called as signal handler for fatal signal |
569 | * (will faithfully resend signal to itself, producing correct exit state) | 570 | * (will faithfully resend signal to itself, producing correct exit state) |
@@ -1039,6 +1040,7 @@ static int static_peek(struct in_str *i) | |||
1039 | } | 1040 | } |
1040 | 1041 | ||
1041 | #if ENABLE_HUSH_INTERACTIVE | 1042 | #if ENABLE_HUSH_INTERACTIVE |
1043 | #if ENABLE_FEATURE_EDITING | ||
1042 | static void cmdedit_set_initial_prompt(void) | 1044 | static void cmdedit_set_initial_prompt(void) |
1043 | { | 1045 | { |
1044 | #if !ENABLE_FEATURE_EDITING_FANCY_PROMPT | 1046 | #if !ENABLE_FEATURE_EDITING_FANCY_PROMPT |
@@ -1049,6 +1051,7 @@ static void cmdedit_set_initial_prompt(void) | |||
1049 | PS1 = "\\w \\$ "; | 1051 | PS1 = "\\w \\$ "; |
1050 | #endif | 1052 | #endif |
1051 | } | 1053 | } |
1054 | #endif | ||
1052 | 1055 | ||
1053 | static const char* setup_prompt_string(int promptmode) | 1056 | static const char* setup_prompt_string(int promptmode) |
1054 | { | 1057 | { |
@@ -1072,7 +1075,7 @@ static const char* setup_prompt_string(int promptmode) | |||
1072 | debug_printf("result %s\n", prompt_str); | 1075 | debug_printf("result %s\n", prompt_str); |
1073 | return prompt_str; | 1076 | return prompt_str; |
1074 | } | 1077 | } |
1075 | #endif | 1078 | #endif /* ENABLE_HUSH_INTERACTIVE */ |
1076 | 1079 | ||
1077 | #if ENABLE_FEATURE_EDITING | 1080 | #if ENABLE_FEATURE_EDITING |
1078 | static line_input_t *line_input_state; | 1081 | static line_input_t *line_input_state; |
@@ -1470,7 +1473,7 @@ static int checkjobs(struct pipe* fg_pipe) | |||
1470 | 1473 | ||
1471 | /* Do we do this right? | 1474 | /* Do we do this right? |
1472 | * bash-3.00# sleep 20 | false | 1475 | * bash-3.00# sleep 20 | false |
1473 | * <Ctrl-Z pressed> | 1476 | * <ctrl-Z pressed> |
1474 | * [3]+ Stopped sleep 20 | false | 1477 | * [3]+ Stopped sleep 20 | false |
1475 | * bash-3.00# echo $? | 1478 | * bash-3.00# echo $? |
1476 | * 1 <========== bg pipe is not fully done, but exitcode is already known! | 1479 | * 1 <========== bg pipe is not fully done, but exitcode is already known! |
@@ -1590,43 +1593,6 @@ static int checkjobs_and_fg_shell(struct pipe* fg_pipe) | |||
1590 | } | 1593 | } |
1591 | #endif | 1594 | #endif |
1592 | 1595 | ||
1593 | #if ENABLE_FEATURE_SH_STANDALONE | ||
1594 | /* run_pipe_real's helper */ | ||
1595 | static int run_single_fg_nofork(struct pipe *pi, const struct bb_applet *a, | ||
1596 | char **argv) | ||
1597 | { | ||
1598 | #if ENABLE_HUSH_JOB | ||
1599 | int rcode; | ||
1600 | /* TSTP handler will store pid etc in pi */ | ||
1601 | nofork_pipe = pi; | ||
1602 | save_nofork_data(&nofork_save); | ||
1603 | if (sigsetjmp(nofork_jb, 1) == 0) { | ||
1604 | signal_SA_RESTART(SIGTSTP, handler_ctrl_z); | ||
1605 | signal(SIGINT, handler_ctrl_c); | ||
1606 | rcode = run_nofork_applet_prime(&nofork_save, a, argv); | ||
1607 | if (--nofork_save.saved != 0) { | ||
1608 | /* Ctrl-Z forked, we are child */ | ||
1609 | exit(rcode); | ||
1610 | } | ||
1611 | return rcode; | ||
1612 | } | ||
1613 | /* Ctrl-Z forked, we are parent; or Ctrl-C. | ||
1614 | * Sighandler has longjmped us here */ | ||
1615 | signal(SIGINT, SIG_IGN); | ||
1616 | signal(SIGTSTP, SIG_IGN); | ||
1617 | debug_printf_jobs("Exiting nofork early\n"); | ||
1618 | restore_nofork_data(&nofork_save); | ||
1619 | if (nofork_save.saved == 0) /* Ctrl-Z, not Ctrl-C */ | ||
1620 | insert_bg_job(pi); | ||
1621 | else | ||
1622 | putchar('\n'); /* bash does this on Ctrl-C */ | ||
1623 | return 0; | ||
1624 | #else | ||
1625 | return run_nofork_applet(a, argv); | ||
1626 | #endif | ||
1627 | } | ||
1628 | #endif | ||
1629 | |||
1630 | /* run_pipe_real() starts all the jobs, but doesn't wait for anything | 1596 | /* run_pipe_real() starts all the jobs, but doesn't wait for anything |
1631 | * to finish. See checkjobs(). | 1597 | * to finish. See checkjobs(). |
1632 | * | 1598 | * |
@@ -1662,7 +1628,7 @@ static int run_pipe_real(struct pipe *pi) | |||
1662 | #if ENABLE_HUSH_JOB | 1628 | #if ENABLE_HUSH_JOB |
1663 | pi->pgrp = -1; | 1629 | pi->pgrp = -1; |
1664 | #endif | 1630 | #endif |
1665 | pi->running_progs = 0; | 1631 | pi->running_progs = 1; |
1666 | pi->stopped_progs = 0; | 1632 | pi->stopped_progs = 0; |
1667 | 1633 | ||
1668 | /* Check if this is a simple builtin (not part of a pipe). | 1634 | /* Check if this is a simple builtin (not part of a pipe). |
@@ -1673,8 +1639,6 @@ static int run_pipe_real(struct pipe *pi) | |||
1673 | if (single_fg && child->group && child->subshell == 0) { | 1639 | if (single_fg && child->group && child->subshell == 0) { |
1674 | debug_printf("non-subshell grouping\n"); | 1640 | debug_printf("non-subshell grouping\n"); |
1675 | setup_redirects(child, squirrel); | 1641 | setup_redirects(child, squirrel); |
1676 | /* XXX could we merge code with following builtin case, | ||
1677 | * by creating a pseudo builtin that calls run_list_real? */ | ||
1678 | debug_printf_exec(": run_list_real\n"); | 1642 | debug_printf_exec(": run_list_real\n"); |
1679 | rcode = run_list_real(child->group); | 1643 | rcode = run_list_real(child->group); |
1680 | restore_redirects(squirrel); | 1644 | restore_redirects(squirrel); |
@@ -1758,8 +1722,9 @@ static int run_pipe_real(struct pipe *pi) | |||
1758 | const struct bb_applet *a = find_applet_by_name(argv[i]); | 1722 | const struct bb_applet *a = find_applet_by_name(argv[i]); |
1759 | if (a && a->nofork) { | 1723 | if (a && a->nofork) { |
1760 | setup_redirects(child, squirrel); | 1724 | setup_redirects(child, squirrel); |
1761 | debug_printf_exec(": run_single_fg_nofork '%s' '%s'...\n", argv[i], argv[i+1]); | 1725 | debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv[i], argv[i+1]); |
1762 | rcode = run_single_fg_nofork(pi, a, argv + i); | 1726 | save_nofork_data(&nofork_save); |
1727 | rcode = run_nofork_applet_prime(&nofork_save, a, argv); | ||
1763 | restore_redirects(squirrel); | 1728 | restore_redirects(squirrel); |
1764 | debug_printf_exec("run_pipe_real return %d\n", rcode); | 1729 | debug_printf_exec("run_pipe_real return %d\n", rcode); |
1765 | return rcode; | 1730 | return rcode; |
@@ -1769,6 +1734,7 @@ static int run_pipe_real(struct pipe *pi) | |||
1769 | } | 1734 | } |
1770 | 1735 | ||
1771 | /* Going to fork a child per each pipe member */ | 1736 | /* Going to fork a child per each pipe member */ |
1737 | pi->running_progs = 0; | ||
1772 | 1738 | ||
1773 | /* Disable job control signals for shell (parent) and | 1739 | /* Disable job control signals for shell (parent) and |
1774 | * for initial child code after fork */ | 1740 | * for initial child code after fork */ |
@@ -1865,26 +1831,26 @@ static int run_pipe_real(struct pipe *pi) | |||
1865 | static void debug_print_tree(struct pipe *pi, int lvl) | 1831 | static void debug_print_tree(struct pipe *pi, int lvl) |
1866 | { | 1832 | { |
1867 | static const char *PIPE[] = { | 1833 | static const char *PIPE[] = { |
1868 | [PIPE_SEQ] = "SEQ", | 1834 | [PIPE_SEQ] = "SEQ", |
1869 | [PIPE_AND] = "AND", | 1835 | [PIPE_AND] = "AND", |
1870 | [PIPE_OR ] = "OR", | 1836 | [PIPE_OR ] = "OR", |
1871 | [PIPE_BG ] = "BG", | 1837 | [PIPE_BG ] = "BG", |
1872 | }; | 1838 | }; |
1873 | static const char *RES[] = { | 1839 | static const char *RES[] = { |
1874 | [RES_NONE ] = "NONE" , | 1840 | [RES_NONE ] = "NONE" , |
1875 | [RES_IF ] = "IF" , | 1841 | [RES_IF ] = "IF" , |
1876 | [RES_THEN ] = "THEN" , | 1842 | [RES_THEN ] = "THEN" , |
1877 | [RES_ELIF ] = "ELIF" , | 1843 | [RES_ELIF ] = "ELIF" , |
1878 | [RES_ELSE ] = "ELSE" , | 1844 | [RES_ELSE ] = "ELSE" , |
1879 | [RES_FI ] = "FI" , | 1845 | [RES_FI ] = "FI" , |
1880 | [RES_FOR ] = "FOR" , | 1846 | [RES_FOR ] = "FOR" , |
1881 | [RES_WHILE] = "WHILE", | 1847 | [RES_WHILE] = "WHILE", |
1882 | [RES_UNTIL] = "UNTIL", | 1848 | [RES_UNTIL] = "UNTIL", |
1883 | [RES_DO ] = "DO" , | 1849 | [RES_DO ] = "DO" , |
1884 | [RES_DONE ] = "DONE" , | 1850 | [RES_DONE ] = "DONE" , |
1885 | [RES_XXXX ] = "XXXX" , | 1851 | [RES_XXXX ] = "XXXX" , |
1886 | [RES_IN ] = "IN" , | 1852 | [RES_IN ] = "IN" , |
1887 | [RES_SNTX ] = "SNTX" , | 1853 | [RES_SNTX ] = "SNTX" , |
1888 | }; | 1854 | }; |
1889 | 1855 | ||
1890 | int pin, prn; | 1856 | int pin, prn; |
@@ -1897,7 +1863,9 @@ static void debug_print_tree(struct pipe *pi, int lvl) | |||
1897 | while (prn < pi->num_progs) { | 1863 | while (prn < pi->num_progs) { |
1898 | fprintf(stderr, "%*s prog %d", lvl*2, "", prn); | 1864 | fprintf(stderr, "%*s prog %d", lvl*2, "", prn); |
1899 | if (pi->progs[prn].group) { | 1865 | if (pi->progs[prn].group) { |
1900 | fprintf(stderr, " group: (argv=%p)\n", pi->progs[prn].argv); | 1866 | fprintf(stderr, " group %s: (argv=%p)\n", |
1867 | (pi->subshell ? "()" : "{}"), | ||
1868 | pi->progs[prn].argv); | ||
1901 | debug_print_tree(pi->progs[prn].group, lvl+1); | 1869 | debug_print_tree(pi->progs[prn].group, lvl+1); |
1902 | prn++; | 1870 | prn++; |
1903 | continue; | 1871 | continue; |
@@ -1920,18 +1888,25 @@ static void debug_print_tree(struct pipe *pi, int lvl) | |||
1920 | // global data until exec/_exit (we can be a child after vfork!) | 1888 | // global data until exec/_exit (we can be a child after vfork!) |
1921 | static int run_list_real(struct pipe *pi) | 1889 | static int run_list_real(struct pipe *pi) |
1922 | { | 1890 | { |
1891 | #if ENABLE_HUSH_JOB | ||
1892 | static int level; | ||
1893 | #else | ||
1894 | enum { level = 0 }; | ||
1895 | #endif | ||
1896 | |||
1923 | char *save_name = NULL; | 1897 | char *save_name = NULL; |
1924 | char **list = NULL; | 1898 | char **list = NULL; |
1925 | char **save_list = NULL; | 1899 | char **save_list = NULL; |
1926 | struct pipe *rpipe; | 1900 | struct pipe *rpipe; |
1927 | int flag_rep = 0; | 1901 | int flag_rep = 0; |
1928 | int save_num_progs; | 1902 | int save_num_progs; |
1929 | int rcode = 0, flag_skip = 1; | 1903 | int flag_skip = 1; |
1904 | int rcode = 0; /* probaly for gcc only */ | ||
1930 | int flag_restore = 0; | 1905 | int flag_restore = 0; |
1931 | int if_code = 0, next_if_code = 0; /* need double-buffer to handle elif */ | 1906 | int if_code = 0, next_if_code = 0; /* need double-buffer to handle elif */ |
1932 | reserved_style rmode, skip_more_in_this_rmode = RES_XXXX; | 1907 | reserved_style rmode, skip_more_in_this_rmode = RES_XXXX; |
1933 | 1908 | ||
1934 | debug_printf_exec("run_list_real start:\n"); | 1909 | debug_printf_exec("run_list_real start lvl %d\n", level + 1); |
1935 | 1910 | ||
1936 | /* check syntax for "for" */ | 1911 | /* check syntax for "for" */ |
1937 | for (rpipe = pi; rpipe; rpipe = rpipe->next) { | 1912 | for (rpipe = pi; rpipe; rpipe = rpipe->next) { |
@@ -1939,17 +1914,60 @@ static int run_list_real(struct pipe *pi) | |||
1939 | && (rpipe->next == NULL) | 1914 | && (rpipe->next == NULL) |
1940 | ) { | 1915 | ) { |
1941 | syntax(); | 1916 | syntax(); |
1942 | debug_printf_exec("run_list_real return 1\n"); | 1917 | debug_printf_exec("run_list_real lvl %d return 1\n", level); |
1943 | return 1; | 1918 | return 1; |
1944 | } | 1919 | } |
1945 | if ((rpipe->r_mode == RES_IN && rpipe->next->r_mode == RES_IN && rpipe->next->progs->argv != NULL) | 1920 | if ((rpipe->r_mode == RES_IN && rpipe->next->r_mode == RES_IN && rpipe->next->progs->argv != NULL) |
1946 | || (rpipe->r_mode == RES_FOR && rpipe->next->r_mode != RES_IN) | 1921 | || (rpipe->r_mode == RES_FOR && rpipe->next->r_mode != RES_IN) |
1947 | ) { | 1922 | ) { |
1948 | syntax(); | 1923 | syntax(); |
1949 | debug_printf_exec("run_list_real return 1\n"); | 1924 | debug_printf_exec("run_list_real lvl %d return 1\n", level); |
1950 | return 1; | 1925 | return 1; |
1951 | } | 1926 | } |
1952 | } | 1927 | } |
1928 | |||
1929 | #if ENABLE_HUSH_JOB | ||
1930 | /* Example of nested list: "while true; do { sleep 1 | exit 2; } done". | ||
1931 | * We are saving state before entering outermost list ("while...done") | ||
1932 | * so that ctrl-Z will correctly background _entire_ outermost list, | ||
1933 | * not just a part of it (like "sleep 1 | exit 2") */ | ||
1934 | if (++level == 1 && interactive_fd) { | ||
1935 | if (sigsetjmp(toplevel_jb, 1)) { | ||
1936 | /* ctrl-Z forked and we are parent; or ctrl-C. | ||
1937 | * Sighandler has longjmped us here */ | ||
1938 | signal(SIGINT, SIG_IGN); | ||
1939 | signal(SIGTSTP, SIG_IGN); | ||
1940 | /* Restore level (we can be coming from deep inside | ||
1941 | * nested levels) */ | ||
1942 | level = 1; | ||
1943 | #if ENABLE_FEATURE_SH_STANDALONE | ||
1944 | if (nofork_save.saved) { /* if save area is valid */ | ||
1945 | debug_printf_jobs("exiting nofork early\n"); | ||
1946 | restore_nofork_data(&nofork_save); | ||
1947 | } | ||
1948 | #endif | ||
1949 | if (ctrl_z_flag) { | ||
1950 | /* ctrl-Z has forked and stored pid of the child in pi->pid. | ||
1951 | * Remember this child as background job */ | ||
1952 | insert_bg_job(pi); | ||
1953 | } else { | ||
1954 | /* ctrl-C. We just stop doing whatever we was doing */ | ||
1955 | putchar('\n'); | ||
1956 | } | ||
1957 | rcode = 0; | ||
1958 | goto ret; | ||
1959 | } | ||
1960 | /* ctrl-Z handler will store pid etc in pi */ | ||
1961 | toplevel_list = pi; | ||
1962 | ctrl_z_flag = 0; | ||
1963 | #if ENABLE_FEATURE_SH_STANDALONE | ||
1964 | nofork_save.saved = 0; /* in case we will run a nofork later */ | ||
1965 | #endif | ||
1966 | signal_SA_RESTART(SIGTSTP, handler_ctrl_z); | ||
1967 | signal(SIGINT, handler_ctrl_c); | ||
1968 | } | ||
1969 | #endif | ||
1970 | |||
1953 | for (; pi; pi = (flag_restore != 0) ? rpipe : pi->next) { | 1971 | for (; pi; pi = (flag_restore != 0) ? rpipe : pi->next) { |
1954 | if (pi->r_mode == RES_WHILE || pi->r_mode == RES_UNTIL | 1972 | if (pi->r_mode == RES_WHILE || pi->r_mode == RES_UNTIL |
1955 | || pi->r_mode == RES_FOR | 1973 | || pi->r_mode == RES_FOR |
@@ -1961,7 +1979,7 @@ static int run_list_real(struct pipe *pi) | |||
1961 | } | 1979 | } |
1962 | } | 1980 | } |
1963 | rmode = pi->r_mode; | 1981 | rmode = pi->r_mode; |
1964 | debug_printf("rmode=%d if_code=%d next_if_code=%d skip_more=%d\n", | 1982 | debug_printf_exec(": rmode=%d if_code=%d next_if_code=%d skip_more=%d\n", |
1965 | rmode, if_code, next_if_code, skip_more_in_this_rmode); | 1983 | rmode, if_code, next_if_code, skip_more_in_this_rmode); |
1966 | if (rmode == skip_more_in_this_rmode && flag_skip) { | 1984 | if (rmode == skip_more_in_this_rmode && flag_skip) { |
1967 | if (pi->followup == PIPE_SEQ) | 1985 | if (pi->followup == PIPE_SEQ) |
@@ -2044,9 +2062,9 @@ static int run_list_real(struct pipe *pi) | |||
2044 | { | 2062 | { |
2045 | rcode = checkjobs(pi); | 2063 | rcode = checkjobs(pi); |
2046 | } | 2064 | } |
2047 | debug_printf_exec("checkjobs returned %d\n", rcode); | 2065 | debug_printf_exec(": checkjobs returned %d\n", rcode); |
2048 | } | 2066 | } |
2049 | debug_printf_exec("setting last_return_code=%d\n", rcode); | 2067 | debug_printf_exec(": setting last_return_code=%d\n", rcode); |
2050 | last_return_code = rcode; | 2068 | last_return_code = rcode; |
2051 | pi->num_progs = save_num_progs; /* restore number of programs */ | 2069 | pi->num_progs = save_num_progs; /* restore number of programs */ |
2052 | if (rmode == RES_IF || rmode == RES_ELIF) | 2070 | if (rmode == RES_IF || rmode == RES_ELIF) |
@@ -2062,7 +2080,17 @@ static int run_list_real(struct pipe *pi) | |||
2062 | } | 2080 | } |
2063 | checkjobs(NULL); | 2081 | checkjobs(NULL); |
2064 | } | 2082 | } |
2065 | debug_printf_exec("run_list_real return %d\n", rcode); | 2083 | |
2084 | #if ENABLE_HUSH_JOB | ||
2085 | if (ctrl_z_flag) { | ||
2086 | /* ctrl-Z forked somewhere in the past, we are the child, | ||
2087 | * and now we completed running the list. Exit. */ | ||
2088 | exit(rcode); | ||
2089 | } | ||
2090 | ret: | ||
2091 | level--; | ||
2092 | #endif | ||
2093 | debug_printf_exec("run_list_real lvl %d return %d\n", level + 1, rcode); | ||
2066 | return rcode; | 2094 | return rcode; |
2067 | } | 2095 | } |
2068 | 2096 | ||