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 /shell/ash.c | |
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.
Diffstat (limited to 'shell/ash.c')
-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 */ |