diff options
author | Ron Yorston <rmy@pobox.com> | 2020-06-20 12:13:57 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2020-06-20 12:13:57 +0100 |
commit | 53aca1b56db730b0103f5ec2e692327237a775e2 (patch) | |
tree | 3f84a84b3e2728f424db141e19dfb5118e964025 | |
parent | da7c8cdf631fc0754d30d5b997ee71a085699469 (diff) | |
download | busybox-w32-53aca1b56db730b0103f5ec2e692327237a775e2.tar.gz busybox-w32-53aca1b56db730b0103f5ec2e692327237a775e2.tar.bz2 busybox-w32-53aca1b56db730b0103f5ec2e692327237a775e2.zip |
ash: changes to ctrl-c handling
Make ctrl-c handling more like Unix. Remove the hSIGINT event and the
code in waitpid_child() to catch it. Add a call to raise_interrupt()
in ctrl_handler().
Prior to these changes interrupts in a child shell weren't properly
handled. In release FRP-3466-g53c09d0e1 interrupting a sleep in a
child shell results in both shells competing for input:
~ $ sh
~ $ sleep 10
^C^C
~ $ ~ $ pwd
sh: w: not found
~ $
sh: pd: not found
~ $
With recent changes:
~ $ sh
~ $ sleep 10
^C
~ $ echo $?
130
~ $ exit
^C
~ $ echo $?
130
~ $
The error return from the parent shell is due to the lack of job
control. Upstream BusyBox ash and dash both do the same when job
control is disabled.
-rw-r--r-- | shell/ash.c | 70 |
1 files changed, 13 insertions, 57 deletions
diff --git a/shell/ash.c b/shell/ash.c index f11449530..decd6c0f7 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -771,6 +771,10 @@ raise_interrupt(void) | |||
771 | signal(SIGINT, SIG_DFL); | 771 | signal(SIGINT, SIG_DFL); |
772 | raise(SIGINT); | 772 | raise(SIGINT); |
773 | } | 773 | } |
774 | #if ENABLE_PLATFORM_MINGW32 | ||
775 | if (iflag) | ||
776 | write(STDOUT_FILENO, "^C", 2); | ||
777 | #endif | ||
774 | /* bash: ^C even on empty command line sets $? */ | 778 | /* bash: ^C even on empty command line sets $? */ |
775 | exitstatus = SIGINT + 128; | 779 | exitstatus = SIGINT + 128; |
776 | raise_exception(EXINT); | 780 | raise_exception(EXINT); |
@@ -4656,14 +4660,12 @@ sprint_status48(char *os, int status, int sigonly) | |||
4656 | } | 4660 | } |
4657 | 4661 | ||
4658 | #if ENABLE_PLATFORM_MINGW32 | 4662 | #if ENABLE_PLATFORM_MINGW32 |
4659 | |||
4660 | HANDLE hSIGINT; /* Ctrl-C is pressed */ | ||
4661 | |||
4662 | static BOOL WINAPI ctrl_handler(DWORD dwCtrlType) | 4663 | static BOOL WINAPI ctrl_handler(DWORD dwCtrlType) |
4663 | { | 4664 | { |
4664 | if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) { | 4665 | if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) { |
4666 | if (!suppress_int) | ||
4667 | raise_interrupt(); /* does not return */ | ||
4665 | pending_int = 1; | 4668 | pending_int = 1; |
4666 | SetEvent(hSIGINT); | ||
4667 | return TRUE; | 4669 | return TRUE; |
4668 | } | 4670 | } |
4669 | return FALSE; | 4671 | return FALSE; |
@@ -4683,21 +4685,19 @@ waitpid_child(int *status, int wait_flags) | |||
4683 | HANDLE *proclist; | 4685 | HANDLE *proclist; |
4684 | pid_t pid = -1; | 4686 | pid_t pid = -1; |
4685 | DWORD win_status, idx; | 4687 | DWORD win_status, idx; |
4686 | int i, delay; | 4688 | int i; |
4687 | 4689 | ||
4688 | for (jb = curjob; jb; jb = jb->prev_job) { | 4690 | for (jb = curjob; jb; jb = jb->prev_job) { |
4689 | if (jb->state != JOBDONE) | 4691 | if (jb->state != JOBDONE) |
4690 | pid_nr += jb->nprocs; | 4692 | pid_nr += jb->nprocs; |
4691 | } | 4693 | } |
4692 | if ( pid_nr++ == 0 ) | 4694 | if (pid_nr == 0) |
4693 | return -1; | 4695 | return -1; |
4694 | 4696 | ||
4695 | pidlist = ckmalloc(sizeof(*pidlist)*pid_nr); | 4697 | pidlist = ckmalloc(sizeof(*pidlist)*pid_nr); |
4696 | proclist = ckmalloc(sizeof(*proclist)*pid_nr); | 4698 | proclist = ckmalloc(sizeof(*proclist)*pid_nr); |
4697 | 4699 | ||
4698 | pidlist[0] = -1; | 4700 | pid_nr = 0; |
4699 | proclist[0] = hSIGINT; | ||
4700 | pid_nr = 1; | ||
4701 | for (jb = curjob; jb; jb = jb->prev_job) { | 4701 | for (jb = curjob; jb; jb = jb->prev_job) { |
4702 | if (jb->state == JOBDONE) | 4702 | if (jb->state == JOBDONE) |
4703 | continue; | 4703 | continue; |
@@ -4710,56 +4710,15 @@ waitpid_child(int *status, int wait_flags) | |||
4710 | } | 4710 | } |
4711 | } | 4711 | } |
4712 | 4712 | ||
4713 | if (pid_nr == 1) | 4713 | if (pid_nr == 0) |
4714 | goto done; | 4714 | goto done; |
4715 | 4715 | ||
4716 | idx = WaitForMultipleObjects(pid_nr, proclist, FALSE, | 4716 | idx = WaitForMultipleObjects(pid_nr, proclist, FALSE, |
4717 | wait_flags&WNOHANG ? 1 : INFINITE); | 4717 | wait_flags&WNOHANG ? 1 : INFINITE); |
4718 | if (idx < pid_nr) { | 4718 | if (idx < pid_nr) { |
4719 | if (idx == 0) { /* hSIGINT */ | 4719 | GetExitCodeProcess(proclist[idx], &win_status); |
4720 | ResetEvent(hSIGINT); | 4720 | *status = (int)win_status << 8; |
4721 | 4721 | pid = pidlist[idx]; | |
4722 | ps = curjob->ps; | ||
4723 | for (i = 0; i < curjob->nprocs; ++i) { | ||
4724 | if (ps[i].ps_proc) { | ||
4725 | kill_SIGTERM_by_handle(ps[i].ps_proc, 128+SIGINT); | ||
4726 | pid = ps[i].ps_pid; /* remember last valid pid */ | ||
4727 | } | ||
4728 | } | ||
4729 | |||
4730 | Sleep(200); | ||
4731 | delay = FALSE; | ||
4732 | for (i = 0; i < curjob->nprocs; ++i) { | ||
4733 | DWORD code; | ||
4734 | if (ps[i].ps_proc && | ||
4735 | GetExitCodeProcess(ps[i].ps_proc, &code) && | ||
4736 | code == STILL_ACTIVE) { | ||
4737 | TerminateProcess(ps[i].ps_proc, 128+SIGINT); | ||
4738 | delay = TRUE; | ||
4739 | } | ||
4740 | } | ||
4741 | |||
4742 | if (delay) | ||
4743 | Sleep(200); | ||
4744 | for (i = 0; i < curjob->nprocs; ++i) { | ||
4745 | /* mark all pids dead except the one we'll return */ | ||
4746 | if (ps[i].ps_pid != pid) { | ||
4747 | ps[i].ps_status = 128 + SIGINT; | ||
4748 | ps[i].ps_pid = -1; | ||
4749 | CloseHandle(ps[i].ps_proc); | ||
4750 | ps[i].ps_proc = NULL; | ||
4751 | } | ||
4752 | } | ||
4753 | |||
4754 | *status = 128 + SIGINT; /* terminated by a signal */ | ||
4755 | if (iflag) | ||
4756 | write(STDOUT_FILENO, "^C", 2); | ||
4757 | } | ||
4758 | else { /* valid pid index */ | ||
4759 | GetExitCodeProcess(proclist[idx], &win_status); | ||
4760 | *status = (int)win_status << 8; | ||
4761 | pid = pidlist[idx]; | ||
4762 | } | ||
4763 | } | 4722 | } |
4764 | done: | 4723 | done: |
4765 | free(pidlist); | 4724 | free(pidlist); |
@@ -14821,7 +14780,6 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
14821 | if ((uintptr_t)r == 2) { | 14780 | if ((uintptr_t)r == 2) { |
14822 | /* ^C pressed, propagate event */ | 14781 | /* ^C pressed, propagate event */ |
14823 | if (iflag) { | 14782 | if (iflag) { |
14824 | write(STDOUT_FILENO, "^C", 2); | ||
14825 | raise_interrupt(); | 14783 | raise_interrupt(); |
14826 | } | 14784 | } |
14827 | else { | 14785 | else { |
@@ -15269,8 +15227,6 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
15269 | basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); | 15227 | basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); |
15270 | basepf.linno = 1; | 15228 | basepf.linno = 1; |
15271 | 15229 | ||
15272 | hSIGINT = CreateEvent(NULL, TRUE, FALSE, NULL); | ||
15273 | |||
15274 | if (argc == 3 && !strcmp(argv[1], "--fs")) { | 15230 | if (argc == 3 && !strcmp(argv[1], "--fs")) { |
15275 | forkshell_init(argv[2]); | 15231 | forkshell_init(argv[2]); |
15276 | /* only reached in case of error */ | 15232 | /* only reached in case of error */ |