diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2011-02-21 03:22:20 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2011-02-21 03:22:20 +0100 |
commit | b12553faa8991e11c11f70a81f1d9d44078c7645 (patch) | |
tree | 4154d5308a9bad6bb46e2014cb6cc997dc9a92cd | |
parent | 55988aed472d9cd362f9a50f4999b5e47ca33abe (diff) | |
download | busybox-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.c | 25 | ||||
-rw-r--r-- | shell/ash.c | 58 | ||||
-rw-r--r-- | shell/ash_test/ash-signals/sigint1.right | 1 | ||||
-rwxr-xr-x | shell/ash_test/ash-signals/sigint1.tests | 41 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/sigint1.right | 1 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/sigint1.tests | 41 |
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) | |||
3783 | static int FAST_FUNC | 3783 | static int FAST_FUNC |
3784 | killcmd(int argc, char **argv) | 3784 | killcmd(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 | |||
41 | echo 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 | |||
41 | echo Next command after SIGINT was executed | ||