aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2012-03-22 13:15:08 +0000
committerRon Yorston <rmy@pobox.com>2012-03-22 13:15:08 +0000
commitc0d4367d6b581eb5989c02815880cf0fa2851ae8 (patch)
tree868c266e627e2d7f65ba5a4d5f98a1c421453181 /shell
parentf6bad5ef766b0447158e3de2f55c35f1f6cecb58 (diff)
parentda4441c44f6efccb6f7b7588404d9c6bfb7b6af8 (diff)
downloadbusybox-w32-c0d4367d6b581eb5989c02815880cf0fa2851ae8.tar.gz
busybox-w32-c0d4367d6b581eb5989c02815880cf0fa2851ae8.tar.bz2
busybox-w32-c0d4367d6b581eb5989c02815880cf0fa2851ae8.zip
Merge commit 'da4441c44f6efccb6f7b7588404d9c6bfb7b6af8' into merge
Conflicts: libbb/vfork_daemon_rexec.c networking/wget.c procps/ps.c
Diffstat (limited to 'shell')
-rw-r--r--shell/Config.src9
-rw-r--r--shell/ash.c122
-rw-r--r--shell/ash_test/ash-misc/echo_write_error.right2
-rw-r--r--shell/ash_test/ash-misc/echo_write_error.tests7
-rw-r--r--shell/ash_test/ash-redir/redir.right1
-rw-r--r--shell/ash_test/ash-signals/sigint1.right1
-rwxr-xr-xshell/ash_test/ash-signals/sigint1.tests41
-rw-r--r--shell/hush.c27
-rw-r--r--shell/hush_test/hush-misc/echo_write_error.right2
-rwxr-xr-xshell/hush_test/hush-misc/echo_write_error.tests7
-rw-r--r--shell/hush_test/hush-misc/sigint1.right1
-rwxr-xr-xshell/hush_test/hush-misc/sigint1.tests41
-rw-r--r--shell/shell_common.c6
13 files changed, 220 insertions, 47 deletions
diff --git a/shell/Config.src b/shell/Config.src
index c9c2439e7..e96c21620 100644
--- a/shell/Config.src
+++ b/shell/Config.src
@@ -123,9 +123,9 @@ config FEATURE_SH_NOFORK
123 default n 123 default n
124 depends on (HUSH || ASH) && FEATURE_PREFER_APPLETS 124 depends on (HUSH || ASH) && FEATURE_PREFER_APPLETS
125 help 125 help
126 This option causes busybox shells [currently only ash] 126 This option causes busybox shells to not execute typical
127 to not execute typical fork/exec/wait sequence, but call <applet>_main 127 fork/exec/wait sequence, but call <applet>_main directly,
128 directly, if possible. (Sometimes it is not possible: for example, 128 if possible. (Sometimes it is not possible: for example,
129 this is not possible in pipes). 129 this is not possible in pipes).
130 130
131 This will be done only for some applets (those which are marked 131 This will be done only for some applets (those which are marked
@@ -133,6 +133,7 @@ config FEATURE_SH_NOFORK
133 133
134 This may significantly speed up some shell scripts. 134 This may significantly speed up some shell scripts.
135 135
136 This feature is relatively new. Use with care. 136 This feature is relatively new. Use with care. Report bugs
137 to project mailing list.
137 138
138endmenu 139endmenu
diff --git a/shell/ash.c b/shell/ash.c
index 28f988698..fd9141661 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -111,6 +111,13 @@
111//config: help 111//config: help
112//config: Enable bash-compatible extensions. 112//config: Enable bash-compatible extensions.
113//config: 113//config:
114//config:config ASH_IDLE_TIMEOUT
115//config: bool "Idle timeout variable"
116//config: default n
117//config: depends on ASH
118//config: help
119//config: Enables bash-like auto-logout after $TMOUT seconds of idle time.
120//config:
114//config:config ASH_JOB_CONTROL 121//config:config ASH_JOB_CONTROL
115//config: bool "Job control" 122//config: bool "Job control"
116//config: default y 123//config: default y
@@ -119,7 +126,7 @@
119//config: Enable job control in the ash shell. 126//config: Enable job control in the ash shell.
120//config: 127//config:
121//config:config ASH_ALIAS 128//config:config ASH_ALIAS
122//config: bool "alias support" 129//config: bool "Alias support"
123//config: default y 130//config: default y
124//config: depends on ASH 131//config: depends on ASH
125//config: help 132//config: help
@@ -130,28 +137,28 @@
130//config: default y 137//config: default y
131//config: depends on ASH 138//config: depends on ASH
132//config: help 139//config: help
133//config: Enable getopts builtin in the ash shell. 140//config: Enable support for getopts builtin in ash.
134//config: 141//config:
135//config:config ASH_BUILTIN_ECHO 142//config:config ASH_BUILTIN_ECHO
136//config: bool "Builtin version of 'echo'" 143//config: bool "Builtin version of 'echo'"
137//config: default y 144//config: default y
138//config: depends on ASH 145//config: depends on ASH
139//config: help 146//config: help
140//config: Enable support for echo, builtin to ash. 147//config: Enable support for echo builtin in ash.
141//config: 148//config:
142//config:config ASH_BUILTIN_PRINTF 149//config:config ASH_BUILTIN_PRINTF
143//config: bool "Builtin version of 'printf'" 150//config: bool "Builtin version of 'printf'"
144//config: default y 151//config: default y
145//config: depends on ASH 152//config: depends on ASH
146//config: help 153//config: help
147//config: Enable support for printf, builtin to ash. 154//config: Enable support for printf builtin in ash.
148//config: 155//config:
149//config:config ASH_BUILTIN_TEST 156//config:config ASH_BUILTIN_TEST
150//config: bool "Builtin version of 'test'" 157//config: bool "Builtin version of 'test'"
151//config: default y 158//config: default y
152//config: depends on ASH 159//config: depends on ASH
153//config: help 160//config: help
154//config: Enable support for test, builtin to ash. 161//config: Enable support for test builtin in ash.
155//config: 162//config:
156//config:config ASH_CMDCMD 163//config:config ASH_CMDCMD
157//config: bool "'command' command to override shell builtins" 164//config: bool "'command' command to override shell builtins"
@@ -167,7 +174,7 @@
167//config: default n 174//config: default n
168//config: depends on ASH 175//config: depends on ASH
169//config: help 176//config: help
170//config: Enable "check for new mail" in the ash shell. 177//config: Enable "check for new mail" function in the ash shell.
171//config: 178//config:
172//config:config ASH_OPTIMIZE_FOR_SIZE 179//config:config ASH_OPTIMIZE_FOR_SIZE
173//config: bool "Optimize for size instead of speed" 180//config: bool "Optimize for size instead of speed"
@@ -449,6 +456,9 @@ static const char *var_end(const char *var)
449 456
450 457
451/* ============ Interrupts / exceptions */ 458/* ============ Interrupts / exceptions */
459
460static void exitshell(void) NORETURN;
461
452/* 462/*
453 * These macros allow the user to suspend the handling of interrupt signals 463 * These macros allow the user to suspend the handling of interrupt signals
454 * over a period of time. This is similar to SIGHOLD or to sigblock, but 464 * over a period of time. This is similar to SIGHOLD or to sigblock, but
@@ -1929,7 +1939,9 @@ change_lc_ctype(const char *value)
1929#endif 1939#endif
1930#if ENABLE_ASH_MAIL 1940#if ENABLE_ASH_MAIL
1931static void chkmail(void); 1941static void chkmail(void);
1932static void changemail(const char *) FAST_FUNC; 1942static void changemail(const char *var_value) FAST_FUNC;
1943#else
1944# define chkmail() ((void)0)
1933#endif 1945#endif
1934static void changepath(const char *) FAST_FUNC; 1946static void changepath(const char *) FAST_FUNC;
1935#if ENABLE_ASH_RANDOM_SUPPORT 1947#if ENABLE_ASH_RANDOM_SUPPORT
@@ -3937,18 +3949,51 @@ setjobctl(int on)
3937static int FAST_FUNC 3949static int FAST_FUNC
3938killcmd(int argc, char **argv) 3950killcmd(int argc, char **argv)
3939{ 3951{
3940 int i = 1;
3941 if (argv[1] && strcmp(argv[1], "-l") != 0) { 3952 if (argv[1] && strcmp(argv[1], "-l") != 0) {
3953 int i = 1;
3942 do { 3954 do {
3943 if (argv[i][0] == '%') { 3955 if (argv[i][0] == '%') {
3944 struct job *jp = getjob(argv[i], 0); 3956 /*
3945 unsigned pid = jp->ps[0].ps_pid; 3957 * "kill %N" - job kill
3946 /* Enough space for ' -NNN<nul>' */ 3958 * Converting to pgrp / pid kill
3947 argv[i] = alloca(sizeof(int)*3 + 3); 3959 */
3948 /* kill_main has matching code to expect 3960 struct job *jp;
3949 * leading space. Needed to not confuse 3961 char *dst;
3950 * negative pids with "kill -SIGNAL_NO" syntax */ 3962 int j, n;
3951 sprintf(argv[i], " -%u", pid); 3963
3964 jp = getjob(argv[i], 0);
3965 /*
3966 * In jobs started under job control, we signal
3967 * entire process group by kill -PGRP_ID.
3968 * This happens, f.e., in interactive shell.
3969 *
3970 * Otherwise, we signal each child via
3971 * kill PID1 PID2 PID3.
3972 * Testcases:
3973 * sh -c 'sleep 1|sleep 1 & kill %1'
3974 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3975 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3976 */
3977 n = jp->nprocs; /* can't be 0 (I hope) */
3978 if (jp->jobctl)
3979 n = 1;
3980 dst = alloca(n * sizeof(int)*4);
3981 argv[i] = dst;
3982 for (j = 0; j < n; j++) {
3983 struct procstat *ps = &jp->ps[j];
3984 /* Skip non-running and not-stopped members
3985 * (i.e. dead members) of the job
3986 */
3987 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3988 continue;
3989 /*
3990 * kill_main has matching code to expect
3991 * leading space. Needed to not confuse
3992 * negative pids with "kill -SIGNAL_NO" syntax
3993 */
3994 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3995 }
3996 *dst = '\0';
3952 } 3997 }
3953 } while (argv[++i]); 3998 } while (argv[++i]);
3954 } 3999 }
@@ -4046,6 +4091,7 @@ sprint_status(char *s, int status, int sigonly)
4046#endif 4091#endif
4047 } 4092 }
4048 st &= 0x7f; 4093 st &= 0x7f;
4094//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
4049 col = fmtstr(s, 32, strsignal(st)); 4095 col = fmtstr(s, 32, strsignal(st));
4050 if (WCOREDUMP(status)) { 4096 if (WCOREDUMP(status)) {
4051 col += fmtstr(s + col, 16, " (core dumped)"); 4097 col += fmtstr(s + col, 16, " (core dumped)");
@@ -4462,8 +4508,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
4462 break; 4508 break;
4463 job = job->prev_job; 4509 job = job->prev_job;
4464 } 4510 }
4465 } else 4511 } else {
4466 job = getjob(*argv, 0); 4512 job = getjob(*argv, 0);
4513 }
4467 /* loop until process terminated or stopped */ 4514 /* loop until process terminated or stopped */
4468 while (job->state == JOBRUNNING) 4515 while (job->state == JOBRUNNING)
4469 blocking_wait_with_raise_on_sig(); 4516 blocking_wait_with_raise_on_sig();
@@ -4959,7 +5006,7 @@ forkchild(struct job *jp, union node *n, int mode)
4959#if JOBS 5006#if JOBS
4960 /* do job control only in root shell */ 5007 /* do job control only in root shell */
4961 doing_jobctl = 0; 5008 doing_jobctl = 0;
4962 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) { 5009 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
4963 pid_t pgrp; 5010 pid_t pgrp;
4964 5011
4965 if (jp->nprocs == 0) 5012 if (jp->nprocs == 0)
@@ -4985,7 +5032,7 @@ forkchild(struct job *jp, union node *n, int mode)
4985 ash_msg_and_raise_error("can't open '%s'", bb_dev_null); 5032 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
4986 } 5033 }
4987 } 5034 }
4988 if (!oldlvl) { 5035 if (oldlvl == 0) {
4989 if (iflag) { /* why if iflag only? */ 5036 if (iflag) { /* why if iflag only? */
4990 setsignal(SIGINT); 5037 setsignal(SIGINT);
4991 setsignal(SIGTERM); 5038 setsignal(SIGTERM);
@@ -10065,10 +10112,21 @@ preadfd(void)
10065 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) 10112 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
10066 nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); 10113 nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
10067 else { 10114 else {
10068#if ENABLE_FEATURE_TAB_COMPLETION 10115 int timeout = -1;
10116# if ENABLE_ASH_IDLE_TIMEOUT
10117 if (iflag) {
10118 const char *tmout_var = lookupvar("TMOUT");
10119 if (tmout_var) {
10120 timeout = atoi(tmout_var) * 1000;
10121 if (timeout <= 0)
10122 timeout = -1;
10123 }
10124 }
10125# endif
10126# if ENABLE_FEATURE_TAB_COMPLETION
10069 line_input_state->path_lookup = pathval(); 10127 line_input_state->path_lookup = pathval();
10070#endif 10128# endif
10071 nr = read_line_input(cmdedit_prompt, buf, IBUFSIZ, line_input_state); 10129 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
10072 if (nr == 0) { 10130 if (nr == 0) {
10073 /* Ctrl+C pressed */ 10131 /* Ctrl+C pressed */
10074 if (trap[SIGINT]) { 10132 if (trap[SIGINT]) {
@@ -10079,17 +10137,24 @@ preadfd(void)
10079 } 10137 }
10080 goto retry; 10138 goto retry;
10081 } 10139 }
10082 if (nr < 0 && errno == 0) { 10140 if (nr < 0) {
10083 /* Ctrl+D pressed */ 10141 if (errno == 0) {
10084 nr = 0; 10142 /* Ctrl+D pressed */
10143 nr = 0;
10144 }
10145# if ENABLE_ASH_IDLE_TIMEOUT
10146 else if (errno == EAGAIN && timeout > 0) {
10147 printf("\007timed out waiting for input: auto-logout\n");
10148 exitshell();
10149 }
10150# endif
10085 } 10151 }
10086 } 10152 }
10087#else 10153#else
10088 nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); 10154 nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
10089#endif 10155#endif
10090 10156
10091#if 0 10157#if 0 /* disabled: nonblock_safe_read() handles this problem */
10092/* nonblock_safe_read() handles this problem */
10093 if (nr < 0) { 10158 if (nr < 0) {
10094 if (parsefile->fd == 0 && errno == EWOULDBLOCK) { 10159 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
10095 int flags = fcntl(0, F_GETFL); 10160 int flags = fcntl(0, F_GETFL);
@@ -12574,9 +12639,7 @@ cmdloop(int top)
12574 inter = 0; 12639 inter = 0;
12575 if (iflag && top) { 12640 if (iflag && top) {
12576 inter++; 12641 inter++;
12577#if ENABLE_ASH_MAIL
12578 chkmail(); 12642 chkmail();
12579#endif
12580 } 12643 }
12581 n = parsecmd(inter); 12644 n = parsecmd(inter);
12582#if DEBUG 12645#if DEBUG
@@ -13346,7 +13409,6 @@ ulimitcmd(int argc UNUSED_PARAM, char **argv)
13346/* 13409/*
13347 * Called to exit the shell. 13410 * Called to exit the shell.
13348 */ 13411 */
13349static void exitshell(void) NORETURN;
13350static void 13412static void
13351exitshell(void) 13413exitshell(void)
13352{ 13414{
diff --git a/shell/ash_test/ash-misc/echo_write_error.right b/shell/ash_test/ash-misc/echo_write_error.right
new file mode 100644
index 000000000..3e91a13d3
--- /dev/null
+++ b/shell/ash_test/ash-misc/echo_write_error.right
@@ -0,0 +1,2 @@
1ash: write error: Broken pipe
2Ok: 1
diff --git a/shell/ash_test/ash-misc/echo_write_error.tests b/shell/ash_test/ash-misc/echo_write_error.tests
new file mode 100644
index 000000000..0a40c9ff7
--- /dev/null
+++ b/shell/ash_test/ash-misc/echo_write_error.tests
@@ -0,0 +1,7 @@
1trap "" PIPE
2
3{
4sleep 1
5echo Cant write this - get EPIPE
6echo Ok: $? >&2
7} | { true; }
diff --git a/shell/ash_test/ash-redir/redir.right b/shell/ash_test/ash-redir/redir.right
index 2a02d41ce..c1a6e729a 100644
--- a/shell/ash_test/ash-redir/redir.right
+++ b/shell/ash_test/ash-redir/redir.right
@@ -1 +1,2 @@
1ash: write error: Bad file descriptor
1TEST 2TEST
diff --git a/shell/ash_test/ash-signals/sigint1.right b/shell/ash_test/ash-signals/sigint1.right
new file mode 100644
index 000000000..a9094b056
--- /dev/null
+++ b/shell/ash_test/ash-signals/sigint1.right
@@ -0,0 +1 @@
Sending SIGINT to main shell PID
diff --git a/shell/ash_test/ash-signals/sigint1.tests b/shell/ash_test/ash-signals/sigint1.tests
new file mode 100755
index 000000000..3d483d32a
--- /dev/null
+++ b/shell/ash_test/ash-signals/sigint1.tests
@@ -0,0 +1,41 @@
1# What should happen if non-interactive shell gets SIGINT?
2
3(sleep 1; echo Sending SIGINT to main shell PID; exec kill -INT $$) &
4
5# We create a child which exits with 0 even on SIGINT
6# (The complex command is necessary only if SIGINT is generated by ^C,
7# in this testcase even bare "sleep 2" would do because
8# in the testcase we don't send SIGINT *to the child*...)
9$THIS_SH -c 'trap "exit 0" SIGINT; sleep 2'
10
11# In one second, we (main shell) get SIGINT here.
12# The question is whether we should, or should not, exit.
13
14# bash will not stop here. It will execute next command(s).
15
16# The rationale for this is described here:
17# http://www.cons.org/cracauer/sigint.html
18#
19# Basically, bash will not exit on SIGINT immediately if it waits
20# for a child. It will wait for the child to exit.
21# If child exits NOT by dying on SIGINT, then bash will not exit.
22#
23# The idea is that the following script:
24# | emacs file.txt
25# | more cmds
26# User may use ^C to interrupt editor's ops like search. But then
27# emacs exits normally. User expects that script doesn't stop.
28#
29# This is a nice idea, but detecting "did process really exit
30# with SIGINT?" is racy. Consider:
31# | bash -c 'while true; do /bin/true; done'
32# When ^C is pressed while bash waits for /bin/true to exit,
33# it may happen that /bin/true exits with exitcode 0 before
34# ^C is delivered to it as SIGINT. bash will see SIGINT, then
35# it will see that child exited with 0, and bash will NOT EXIT.
36
37# Therefore we do not implement bash behavior.
38# I'd say that emacs need to put itself into a separate pgrp
39# to isolate shell from getting stray SIGINTs from ^C.
40
41echo Next command after SIGINT was executed
diff --git a/shell/hush.c b/shell/hush.c
index 1709fd9d1..4d9e5f8c7 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -1418,6 +1418,7 @@ static void sigexit(int sig)
1418static void hush_exit(int exitcode) NORETURN; 1418static void hush_exit(int exitcode) NORETURN;
1419static void hush_exit(int exitcode) 1419static void hush_exit(int exitcode)
1420{ 1420{
1421 fflush_all();
1421 if (G.exiting <= 0 && G.traps && G.traps[0] && G.traps[0][0]) { 1422 if (G.exiting <= 0 && G.traps && G.traps[0] && G.traps[0][0]) {
1422 /* Prevent recursion: 1423 /* Prevent recursion:
1423 * trap "echo Hi; exit" EXIT; exit 1424 * trap "echo Hi; exit" EXIT; exit
@@ -1901,7 +1902,7 @@ static void get_user_input(struct in_str *i)
1901 G.flag_SIGINT = 0; 1902 G.flag_SIGINT = 0;
1902 /* buglet: SIGINT will not make new prompt to appear _at once_, 1903 /* buglet: SIGINT will not make new prompt to appear _at once_,
1903 * only after <Enter>. (^C will work) */ 1904 * only after <Enter>. (^C will work) */
1904 r = read_line_input(prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, G.line_input_state); 1905 r = read_line_input(G.line_input_state, prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, /*timeout*/ -1);
1905 /* catch *SIGINT* etc (^C is handled by read_line_input) */ 1906 /* catch *SIGINT* etc (^C is handled by read_line_input) */
1906 check_and_run_traps(0); 1907 check_and_run_traps(0);
1907 } while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */ 1908 } while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */
@@ -6105,10 +6106,13 @@ static void exec_builtin(char ***to_free,
6105 char **argv) 6106 char **argv)
6106{ 6107{
6107#if BB_MMU 6108#if BB_MMU
6108 int rcode = x->b_function(argv); 6109 int rcode;
6110 fflush_all();
6111 rcode = x->b_function(argv);
6109 fflush_all(); 6112 fflush_all();
6110 _exit(rcode); 6113 _exit(rcode);
6111#else 6114#else
6115 fflush_all();
6112 /* On NOMMU, we must never block! 6116 /* On NOMMU, we must never block!
6113 * Example: { sleep 99 | read line; } & echo Ok 6117 * Example: { sleep 99 | read line; } & echo Ok
6114 */ 6118 */
@@ -6500,13 +6504,15 @@ static int checkjobs(struct pipe *fg_pipe)
6500 fg_pipe->alive_cmds--; 6504 fg_pipe->alive_cmds--;
6501 ex = WEXITSTATUS(status); 6505 ex = WEXITSTATUS(status);
6502 /* bash prints killer signal's name for *last* 6506 /* bash prints killer signal's name for *last*
6503 * process in pipe (prints just newline for SIGINT). 6507 * process in pipe (prints just newline for SIGINT/SIGPIPE).
6504 * Mimic this. Example: "sleep 5" + (^\ or kill -QUIT) 6508 * Mimic this. Example: "sleep 5" + (^\ or kill -QUIT)
6505 */ 6509 */
6506 if (WIFSIGNALED(status)) { 6510 if (WIFSIGNALED(status)) {
6507 int sig = WTERMSIG(status); 6511 int sig = WTERMSIG(status);
6508 if (i == fg_pipe->num_cmds-1) 6512 if (i == fg_pipe->num_cmds-1)
6509 printf("%s\n", sig == SIGINT ? "" : get_signame(sig)); 6513 /* TODO: use strsignal() instead for bash compat? but that's bloat... */
6514 printf("%s\n", sig == SIGINT || sig == SIGPIPE ? "" : get_signame(sig));
6515 /* TODO: if (WCOREDUMP(status)) + " (core dumped)"; */
6510 /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here? 6516 /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here?
6511 * Maybe we need to use sig | 128? */ 6517 * Maybe we need to use sig | 128? */
6512 ex = sig + 128; 6518 ex = sig + 128;
@@ -6615,7 +6621,7 @@ static int checkjobs_and_fg_shell(struct pipe *fg_pipe)
6615 * cmd ; ... { list } ; ... 6621 * cmd ; ... { list } ; ...
6616 * cmd && ... { list } && ... 6622 * cmd && ... { list } && ...
6617 * cmd || ... { list } || ... 6623 * cmd || ... { list } || ...
6618 * If it is, then we can run cmd as a builtin, NOFORK [do we do this?], 6624 * If it is, then we can run cmd as a builtin, NOFORK,
6619 * or (if SH_STANDALONE) an applet, and we can run the { list } 6625 * or (if SH_STANDALONE) an applet, and we can run the { list }
6620 * with run_list. If it isn't one of these, we fork and exec cmd. 6626 * with run_list. If it isn't one of these, we fork and exec cmd.
6621 * 6627 *
@@ -6797,13 +6803,12 @@ static NOINLINE int run_pipe(struct pipe *pi)
6797 } 6803 }
6798 6804
6799 /* Expand the rest into (possibly) many strings each */ 6805 /* Expand the rest into (possibly) many strings each */
6800 if (0) {}
6801#if ENABLE_HUSH_BASH_COMPAT 6806#if ENABLE_HUSH_BASH_COMPAT
6802 else if (command->cmd_type == CMD_SINGLEWORD_NOGLOB) { 6807 if (command->cmd_type == CMD_SINGLEWORD_NOGLOB) {
6803 argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt); 6808 argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt);
6804 } 6809 } else
6805#endif 6810#endif
6806 else { 6811 {
6807 argv_expanded = expand_strvec_to_strvec(argv + command->assignment_cnt); 6812 argv_expanded = expand_strvec_to_strvec(argv + command->assignment_cnt);
6808 } 6813 }
6809 6814
@@ -6833,6 +6838,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
6833 if (!funcp) { 6838 if (!funcp) {
6834 debug_printf_exec(": builtin '%s' '%s'...\n", 6839 debug_printf_exec(": builtin '%s' '%s'...\n",
6835 x->b_cmd, argv_expanded[1]); 6840 x->b_cmd, argv_expanded[1]);
6841 fflush_all();
6836 rcode = x->b_function(argv_expanded) & 0xff; 6842 rcode = x->b_function(argv_expanded) & 0xff;
6837 fflush_all(); 6843 fflush_all();
6838 } 6844 }
@@ -6865,7 +6871,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
6865 return rcode; 6871 return rcode;
6866 } 6872 }
6867 6873
6868 if (ENABLE_FEATURE_SH_STANDALONE) { 6874 if (ENABLE_FEATURE_SH_NOFORK) {
6869 int n = find_applet_by_name(argv_expanded[0]); 6875 int n = find_applet_by_name(argv_expanded[0]);
6870 if (n >= 0 && APPLET_IS_NOFORK(n)) { 6876 if (n >= 0 && APPLET_IS_NOFORK(n)) {
6871 rcode = redirect_and_varexp_helper(&new_env, &old_vars, command, squirrel, argv_expanded); 6877 rcode = redirect_and_varexp_helper(&new_env, &old_vars, command, squirrel, argv_expanded);
@@ -7642,6 +7648,7 @@ int hush_main(int argc, char **argv)
7642 G.global_argc -= builtin_argc; /* skip [BARGV...] "" */ 7648 G.global_argc -= builtin_argc; /* skip [BARGV...] "" */
7643 G.global_argv += builtin_argc; 7649 G.global_argv += builtin_argc;
7644 G.global_argv[-1] = NULL; /* replace "" */ 7650 G.global_argv[-1] = NULL; /* replace "" */
7651 fflush_all();
7645 G.last_exitcode = x->b_function(argv + optind - 1); 7652 G.last_exitcode = x->b_function(argv + optind - 1);
7646 } 7653 }
7647 goto final_return; 7654 goto final_return;
diff --git a/shell/hush_test/hush-misc/echo_write_error.right b/shell/hush_test/hush-misc/echo_write_error.right
new file mode 100644
index 000000000..ddcad4363
--- /dev/null
+++ b/shell/hush_test/hush-misc/echo_write_error.right
@@ -0,0 +1,2 @@
1hush: write error: Broken pipe
2Ok: 1
diff --git a/shell/hush_test/hush-misc/echo_write_error.tests b/shell/hush_test/hush-misc/echo_write_error.tests
new file mode 100755
index 000000000..0a40c9ff7
--- /dev/null
+++ b/shell/hush_test/hush-misc/echo_write_error.tests
@@ -0,0 +1,7 @@
1trap "" PIPE
2
3{
4sleep 1
5echo Cant write this - get EPIPE
6echo Ok: $? >&2
7} | { true; }
diff --git a/shell/hush_test/hush-misc/sigint1.right b/shell/hush_test/hush-misc/sigint1.right
new file mode 100644
index 000000000..a9094b056
--- /dev/null
+++ b/shell/hush_test/hush-misc/sigint1.right
@@ -0,0 +1 @@
Sending SIGINT to main shell PID
diff --git a/shell/hush_test/hush-misc/sigint1.tests b/shell/hush_test/hush-misc/sigint1.tests
new file mode 100755
index 000000000..3d483d32a
--- /dev/null
+++ b/shell/hush_test/hush-misc/sigint1.tests
@@ -0,0 +1,41 @@
1# What should happen if non-interactive shell gets SIGINT?
2
3(sleep 1; echo Sending SIGINT to main shell PID; exec kill -INT $$) &
4
5# We create a child which exits with 0 even on SIGINT
6# (The complex command is necessary only if SIGINT is generated by ^C,
7# in this testcase even bare "sleep 2" would do because
8# in the testcase we don't send SIGINT *to the child*...)
9$THIS_SH -c 'trap "exit 0" SIGINT; sleep 2'
10
11# In one second, we (main shell) get SIGINT here.
12# The question is whether we should, or should not, exit.
13
14# bash will not stop here. It will execute next command(s).
15
16# The rationale for this is described here:
17# http://www.cons.org/cracauer/sigint.html
18#
19# Basically, bash will not exit on SIGINT immediately if it waits
20# for a child. It will wait for the child to exit.
21# If child exits NOT by dying on SIGINT, then bash will not exit.
22#
23# The idea is that the following script:
24# | emacs file.txt
25# | more cmds
26# User may use ^C to interrupt editor's ops like search. But then
27# emacs exits normally. User expects that script doesn't stop.
28#
29# This is a nice idea, but detecting "did process really exit
30# with SIGINT?" is racy. Consider:
31# | bash -c 'while true; do /bin/true; done'
32# When ^C is pressed while bash waits for /bin/true to exit,
33# it may happen that /bin/true exits with exitcode 0 before
34# ^C is delivered to it as SIGINT. bash will see SIGINT, then
35# it will see that child exited with 0, and bash will NOT EXIT.
36
37# Therefore we do not implement bash behavior.
38# I'd say that emacs need to put itself into a separate pgrp
39# to isolate shell from getting stray SIGINTs from ^C.
40
41echo Next command after SIGINT was executed
diff --git a/shell/shell_common.c b/shell/shell_common.c
index 2d5c0db0f..c7b5b6122 100644
--- a/shell/shell_common.c
+++ b/shell/shell_common.c
@@ -375,9 +375,9 @@ shell_builtin_ulimit(char **argv)
375#endif 375#endif
376 /* optarg = NULL; opterr = 0; optopt = 0; - do we need this?? */ 376 /* optarg = NULL; opterr = 0; optopt = 0; - do we need this?? */
377 377
378 argc = 1; 378 argc = 1;
379 while (argv[argc]) 379 while (argv[argc])
380 argc++; 380 argc++;
381 381
382 opts = 0; 382 opts = 0;
383 while (1) { 383 while (1) {