Maros Zatko
2016-Mar-08 19:49 UTC
[Libguestfs] [PATCH] fish: reset the console on ^Z RHBZ#1213844
Patch registers SIGTSTP hook where it sends reset terminal color control sequence using write and fsync. Handler is installed only if signal is not being ignored. Patch uses rl_free_line_state and rl_cleanup_after_signal to unhook readline from terminal, then it calls original TSTP handler using approach in URL below and again hooks readline using rl_reset_after_signal. Handling is based on code from: http://man7.org/tlpi/code/online/dist/pgsjc/handling_SIGTSTP.c.html This approach seems to mostly work. User is sometimes able to get readline into state when it doesn't correctly respond to newline. ^Z and subsequent fg helps there as reset command helps broken terminal. I haven't noticed this using previous approach copied from vi. If you know what is going on I'll be more than happy to fix it. Maros Maros Zatko (1): fish: reset the console on ^Z RHBZ#1213844 fish/fish.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) -- 2.5.0
Maros Zatko
2016-Mar-08 19:49 UTC
[Libguestfs] [PATCH] fish: reset the console on ^Z RHBZ#1213844
Patch registers SIGTSTP hook where it sends reset terminal color control sequence using write and fsync. Handler is installed only if signal is not being ignored. Patch uses rl_free_line_state and rl_cleanup_after_signal to unhook readline from terminal, then it calls original TSTP handler using approach in URL below and again hooks readline using rl_reset_after_signal. Handling is based on code from: http://man7.org/tlpi/code/online/dist/pgsjc/handling_SIGTSTP.c.html This approach seems to mostly work. User is sometimes able to get readline into state when it doesn't correctly respond to newline. ^Z and subsequent fg helps there as reset command helps broken terminal. --- fish/fish.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/fish/fish.c b/fish/fish.c index d26f8b3..ec855f4 100644 --- a/fish/fish.c +++ b/fish/fish.c @@ -73,6 +73,7 @@ static void cleanup_readline (void); static char *decode_ps1 (const char *); static void add_history_line (const char *); #endif +static void tstp_handler (int sig); static int override_progress_bars = -1; static struct progress_bar *bar = NULL; @@ -159,6 +160,65 @@ usage (int status) exit (status); } +/* Handler for SIGTSTP */ +static void +tstp_handler (int sig) +{ + /* Source: http://man7.org/tlpi/code/online/dist/pgsjc/handling_SIGTSTP.c.html */ + sigset_t tstp_mask, prev_mask; + int saved_errno; + struct sigaction sa; + + /* In case we change 'errno' here */ + saved_errno = errno; + +#ifdef HAVE_LIBREADLINE + /* Cleanup readline, unhook from terminal */ + rl_free_line_state (); + rl_cleanup_after_signal (); +#endif + + /* Reset terminal color */ +#define RESETCOLOR "\033[0m" + if (write (1, RESETCOLOR, sizeof RESETCOLOR) != sizeof RESETCOLOR) + perror ("write"); + fsync (1); + + /* Set handling to default */ + if (signal (SIGTSTP, SIG_DFL) == SIG_ERR) + perror ("signal"); + + /* Generate a further SIGTSTP */ + raise (SIGTSTP); + + /* Unblock SIGTSTP; the pending SIGTSTP immediately suspends the program */ + + sigemptyset (&tstp_mask); + sigaddset (&tstp_mask, SIGTSTP); + if (sigprocmask (SIG_UNBLOCK, &tstp_mask, &prev_mask) == -1) + perror ("sigprocmask"); + + /* Execution resumes here after SIGCONT */ + + /* Reblock SIGTSTP */ + if (sigprocmask (SIG_SETMASK, &prev_mask, NULL) == -1) + perror ("sigprocmask"); + + /* Reestablish handler */ + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sa.sa_handler = tstp_handler; + if (sigaction (SIGTSTP, &sa, NULL) == -1) + perror ("sigaction"); + +#ifdef HAVE_LIBREADLINE + /* Restore readline state */ + rl_reset_after_signal (); +#endif + + errno = saved_errno; +} + int main (int argc, char *argv[]) { @@ -439,6 +499,22 @@ main (int argc, char *argv[]) exit (EXIT_FAILURE); } + /* Register ^Z handler. We need it to reset terminal colors + */ + if (is_interactive) { + /* Only establish handler for SIGTSTP if it is not being ignored */ + if (sigaction(SIGTSTP, NULL, &sa) == -1) + perror ("sigaction"); + + if (sa.sa_handler != SIG_IGN) { + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sa.sa_handler = tstp_handler; + if (sigaction(SIGTSTP, &sa, NULL) == -1) + perror ("sigaction"); + } + } + /* Old-style -i syntax? Since -a/-d/-N and -i was disallowed * previously, if we have -i without any drives but with something * on the command line, it must be old-style syntax. -- 2.5.0