-
Notifications
You must be signed in to change notification settings - Fork 30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Interactive ksh terminates on ^C when SIGINT is ignored on entry #343
Comments
I can confirm that this bug is present in the Red Hat CentOS's patched stock version of ksh 93u+ 2012-08-01. |
The following change from that commit introduced the bug: --- a/src/cmd/ksh93/edit/edit.c
+++ b/src/cmd/ksh93/edit/edit.c
@@ -1056,7 +1056,7 @@ int ed_getchar(register Edit_t *ep,int mode)
{
if(mode<=0 && -c == ep->e_intr)
{
- sh_fault(SIGINT);
+ killpg(getpgrp(),SIGINT);
siglongjmp(ep->e_env, UINTR);
}
if(mode<=0 && ep->sh->st.trap[SH_KEYTRAP]) Reverting it fixes this bug, but reintroduces the original bug, rhbz#960034 – unfortunately one of those private Red Hat bugs, but I was granted access for backporting RedHat patches. The original bug reintroduced by reverting this change is this one: With the monitor option off ( Now, for some reason that I don't understand yet, if So one way to fix it would be to issue Actually excluding the current process from a Patch: --- a/src/cmd/ksh93/edit/edit.c
+++ b/src/cmd/ksh93/edit/edit.c
@@ -1120,7 +1120,12 @@ int ed_getchar(register Edit_t *ep,int mode)
{
if(mode<=0 && -c == ep->e_intr)
{
+ /* avoid potentially killing main shell: issue SIGINT to process group except self */
+ sigblock(SIGINT);
killpg(getpgrp(),SIGINT);
+ sigrelease(SIGINT);
+ /* now handle SIGINT in current process */
+ sh_fault(SIGINT);
siglongjmp(ep->e_env, UINTR);
}
if(mode<=0 && ep->sh->st.trap[SH_KEYTRAP]) |
Actually, this seems to be a more efficient way to accomplish the same thing. Somehow SIGINT got reset to default, so just restore the expected sh_fault handler. --- a/src/cmd/ksh93/edit/edit.c
+++ b/src/cmd/ksh93/edit/edit.c
@@ -1120,6 +1120,7 @@ int ed_getchar(register Edit_t *ep,int mode)
{
if(mode<=0 && -c == ep->e_intr)
{
+ signal(SIGINT,sh_fault);
killpg(getpgrp(),SIGINT);
siglongjmp(ep->e_env, UINTR);
} |
Even with either patch, there is still a bug left, and it is not in the original ksh:
The child shell still exits (with status 0) after trapping SIGINT. On my system, this bug was introduced by commit ff385e5. A ksh compiled immediately before that commit does not have the bug. I find that mysterious, as that commit seems unrelated to any signal handling. I'm in over my head here and would appreciate some more eyes on this. Ping @JohnoKing @hyenias @hvdijk |
I have reproduced this bug on Linux in ksh93u+m, ksh93u+, ksh93v- and ksh2020 (commit ff385e5 doesn't introduce the bug on my system). |
I also tried out CTRL+C within a child shell and all of my systems that I have tested exit back to the parent shell (FreeBSD, Debian, Ubuntu) with a recent ksh93u+m or ksh93v-. Default system ksh93u+ on macOS and Ubuntu 18.04 returned a new editor line after I issued a CTRL+C. I tried the following for the subshells and both performed in the same manner:
|
I have been experimenting with this issue and have found another reproducer and a related issue. Trapping # This reproducer works as expected in ksh93t+ 2010-03-05, but breaks from ksh93t+ 2010-06-14 onwards
$ exec ksh -o emacs
$ trap '' INT
$ <Ctrl+C> # This causes ksh93t+ 2010-06-14 and ksh93u+m to exit Additionally, modifying the trap to run a dummy command causes the prompt to act strangely (this behavior is similar to #202): # This bug exists in all versions of ksh I've tested, including ksh93n- 2002-06-28
$ exec ksh -o emacs
$ trap 'true' INT
$ <Ctrl+C * 10>
$ $ $ $ $ $ $ $ $ $ $ # An extra '$ ' is added for each Ctrl+C |
sh_main() calls exfile() and then sh_done(), and that exfile() call is the entire shell session, so the fix is to stop exfile() from returning. I've experimentally determined that Ctrl+C with SIGINT ignored causes an sfio error code of 256. I can't find where that happens, but all the same, the following patch fixes all the above reproducers for me. edit: actually, that 256 is probably --- a/src/cmd/ksh93/sh/main.c
+++ b/src/cmd/ksh93/sh/main.c
@@ -536,6 +536,12 @@ static void exfile(register Shell_t *shp, register Sfio_t *iop,register int fno)
if(tdone || !sfreserve(iop,0,0))
{
eof_or_error:
+ if(sh_isstate(SH_INTERACTIVE) && sferror(iop)==SH_EXITSIG)
+ {
+ /* Ctrl+C with SIGINT ignored */
+ sfputc(sfstderr,'\n');
+ continue;
+ }
if(sh_isstate(SH_INTERACTIVE) && !sferror(iop))
{
if(--maxtry>0 && sh_isoption(SH_IGNOREEOF) && |
The killpg(getpgrp(),SIGINT) call added to ed_getchar() in that commit caused the interactive shell to exit on ^C even if SIGINT is being ignored. We cannot revert or remove that call without breaking job control. This commit applies a new fix instead. Reproducers fixed by this commit: SIGINT ignored by child: $ PS1='childshell$ ' ksh childshell$ trap '' INT childshell$ (press Ctrl+C) $ SIGINT ignored by parent: $ (trap '' INT; ENV=/./dev/null PS1='childshell$ ' ksh) childshell$ (press Ctrl+C) $ SIGINT ignored by parent, trapped in child: $ (trap '' INT; ENV=/./dev/null PS1='childshell$ ' ksh) childshell$ trap 'echo test' INT childshell$ (press Ctrl+C) $ I've experimentally determined that, under these conditions, the SFIO stream error state is set to 256 == 0400 == SH_EXITSIG. src/cmd/ksh93/sh/main.c: exfile(): - On EOF or error, do not return (exiting the shell) if the shell state is interactive and if sferror(iop)==SH_EXITSIG. - Refactor that block a little to make the new check fit in nicely. src/cmd/ksh93/tests/pty.sh: - Test the above three reproducers. Fixes: #343
Symptom (at least on macOS):
The child shell exited (with status 0) upon pressing Ctrl+C.
This bug was introduced by a Red Hat patch that I applied in 7e5fd3e. We need to figure out how to fix it without reintroducing the bug that it fixed.
The text was updated successfully, but these errors were encountered: