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 */ |
