aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2011-02-21 03:22:20 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2011-02-21 03:22:20 +0100
commitb12553faa8991e11c11f70a81f1d9d44078c7645 (patch)
tree4154d5308a9bad6bb46e2014cb6cc997dc9a92cd
parent55988aed472d9cd362f9a50f4999b5e47ca33abe (diff)
downloadbusybox-w32-b12553faa8991e11c11f70a81f1d9d44078c7645.tar.gz
busybox-w32-b12553faa8991e11c11f70a81f1d9d44078c7645.tar.bz2
busybox-w32-b12553faa8991e11c11f70a81f1d9d44078c7645.zip
ash: fix ash-signals/signal8 testcase failure
function old new delta killcmd 109 224 +115 kill_main 882 910 +28 changepath 194 195 +1 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/0 up/down: 144/0) Total: 144 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--procps/kill.c25
-rw-r--r--shell/ash.c58
-rw-r--r--shell/ash_test/ash-signals/sigint1.right1
-rwxr-xr-xshell/ash_test/ash-signals/sigint1.tests41
-rw-r--r--shell/hush_test/hush-misc/sigint1.right1
-rwxr-xr-xshell/hush_test/hush-misc/sigint1.tests41
6 files changed, 152 insertions, 15 deletions
diff --git a/procps/kill.c b/procps/kill.c
index b51d44a70..39538016e 100644
--- a/procps/kill.c
+++ b/procps/kill.c
@@ -206,9 +206,27 @@ int kill_main(int argc, char **argv)
206 206
207 /* Looks like they want to do a kill. Do that */ 207 /* Looks like they want to do a kill. Do that */
208 while (arg) { 208 while (arg) {
209 /* Support shell 'space' trick */ 209#if ENABLE_ASH || ENABLE_HUSH
210 if (arg[0] == ' ') 210 /*
211 arg++; 211 * We need to support shell's "hack formats" of
212 * " -PRGP_ID" (yes, with a leading space)
213 * and " PID1 PID2 PID3" (with degenerate case "")
214 */
215 while (*arg != '\0') {
216 char *end;
217 if (*arg == ' ')
218 arg++;
219 pid = bb_strtoi(arg, &end, 10);
220 if (errno && (errno != EINVAL || *end != ' ')) {
221 bb_error_msg("invalid number '%s'", arg);
222 errors++;
223 } else if (kill(pid, signo) != 0) {
224 bb_perror_msg("can't kill pid %d", (int)pid);
225 errors++;
226 }
227 arg = end; /* can only point to ' ' or '\0' now */
228 }
229#else
212 pid = bb_strtoi(arg, NULL, 10); 230 pid = bb_strtoi(arg, NULL, 10);
213 if (errno) { 231 if (errno) {
214 bb_error_msg("invalid number '%s'", arg); 232 bb_error_msg("invalid number '%s'", arg);
@@ -217,6 +235,7 @@ int kill_main(int argc, char **argv)
217 bb_perror_msg("can't kill pid %d", (int)pid); 235 bb_perror_msg("can't kill pid %d", (int)pid);
218 errors++; 236 errors++;
219 } 237 }
238#endif
220 arg = *++argv; 239 arg = *++argv;
221 } 240 }
222 return errors; 241 return errors;
diff --git a/shell/ash.c b/shell/ash.c
index cccd6dd79..98d2c7c29 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -3783,18 +3783,51 @@ setjobctl(int on)
3783static int FAST_FUNC 3783static int FAST_FUNC
3784killcmd(int argc, char **argv) 3784killcmd(int argc, char **argv)
3785{ 3785{
3786 int i = 1;
3787 if (argv[1] && strcmp(argv[1], "-l") != 0) { 3786 if (argv[1] && strcmp(argv[1], "-l") != 0) {
3787 int i = 1;
3788 do { 3788 do {
3789 if (argv[i][0] == '%') { 3789 if (argv[i][0] == '%') {
3790 struct job *jp = getjob(argv[i], 0); 3790 /*
3791 unsigned pid = jp->ps[0].ps_pid; 3791 * "kill %N" - job kill
3792 /* Enough space for ' -NNN<nul>' */ 3792 * Converting to pgrp / pid kill
3793 argv[i] = alloca(sizeof(int)*3 + 3); 3793 */
3794 /* kill_main has matching code to expect 3794 struct job *jp;
3795 * leading space. Needed to not confuse 3795 char *dst;
3796 * negative pids with "kill -SIGNAL_NO" syntax */ 3796 int j, n;
3797 sprintf(argv[i], " -%u", pid); 3797
3798 jp = getjob(argv[i], 0);
3799 /*
3800 * In jobs started under job control, we signal
3801 * entire process group by kill -PGRP_ID.
3802 * This happens, f.e., in interactive shell.
3803 *
3804 * Otherwise, we signal each child via
3805 * kill PID1 PID2 PID3.
3806 * Testcases:
3807 * sh -c 'sleep 1|sleep 1 & kill %1'
3808 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3809 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3810 */
3811 n = jp->nprocs; /* can't be 0 (I hope) */
3812 if (jp->jobctl)
3813 n = 1;
3814 dst = alloca(n * sizeof(int)*4);
3815 argv[i] = dst;
3816 for (j = 0; j < n; j++) {
3817 struct procstat *ps = &jp->ps[j];
3818 /* Skip non-running and not-stopped members
3819 * (i.e. dead members) of the job
3820 */
3821 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3822 continue;
3823 /*
3824 * kill_main has matching code to expect
3825 * leading space. Needed to not confuse
3826 * negative pids with "kill -SIGNAL_NO" syntax
3827 */
3828 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3829 }
3830 *dst = '\0';
3798 } 3831 }
3799 } while (argv[++i]); 3832 } while (argv[++i]);
3800 } 3833 }
@@ -4227,8 +4260,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
4227 break; 4260 break;
4228 job = job->prev_job; 4261 job = job->prev_job;
4229 } 4262 }
4230 } else 4263 } else {
4231 job = getjob(*argv, 0); 4264 job = getjob(*argv, 0);
4265 }
4232 /* loop until process terminated or stopped */ 4266 /* loop until process terminated or stopped */
4233 while (job->state == JOBRUNNING) 4267 while (job->state == JOBRUNNING)
4234 blocking_wait_with_raise_on_sig(); 4268 blocking_wait_with_raise_on_sig();
@@ -4724,7 +4758,7 @@ forkchild(struct job *jp, union node *n, int mode)
4724#if JOBS 4758#if JOBS
4725 /* do job control only in root shell */ 4759 /* do job control only in root shell */
4726 doing_jobctl = 0; 4760 doing_jobctl = 0;
4727 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) { 4761 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
4728 pid_t pgrp; 4762 pid_t pgrp;
4729 4763
4730 if (jp->nprocs == 0) 4764 if (jp->nprocs == 0)
@@ -4750,7 +4784,7 @@ forkchild(struct job *jp, union node *n, int mode)
4750 ash_msg_and_raise_error("can't open '%s'", bb_dev_null); 4784 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
4751 } 4785 }
4752 } 4786 }
4753 if (!oldlvl) { 4787 if (oldlvl == 0) {
4754 if (iflag) { /* why if iflag only? */ 4788 if (iflag) { /* why if iflag only? */
4755 setsignal(SIGINT); 4789 setsignal(SIGINT);
4756 setsignal(SIGTERM); 4790 setsignal(SIGTERM);
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..20e45d940
--- /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# (This is truly necessary only if SIGINT is generated by ^C,
7# in this testcase even bare "sleep 2" would do because
8# 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_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..20e45d940
--- /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# (This is truly necessary only if SIGINT is generated by ^C,
7# in this testcase even bare "sleep 2" would do because
8# 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