From 56e05dab02840443bb29beb6a596e8e3f35c5461 Mon Sep 17 00:00:00 2001 From: Kurtis Rader Date: Tue, 10 Jan 2017 21:52:10 -0800 Subject: [PATCH] another attempt to workaround a glibc bug This is another attempt to fix issue #3644 that we believe is due to issue https://sourceware.org/bugzilla/show_bug.cgi?id=20632. --- src/common.cpp | 14 ++++++++------ src/proc.cpp | 5 +++-- src/reader.cpp | 32 +++++++++++++++++++++++--------- 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/common.cpp b/src/common.cpp index c804d4909..b194e1cff 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -1710,7 +1710,9 @@ void restore_term_foreground_process_group(void) { if (initial_fg_process_group != -1) { // This is called during shutdown and from a signal handler. We don't bother to complain on // failure. - tcsetpgrp(STDIN_FILENO, initial_fg_process_group); + if (tcsetpgrp(STDIN_FILENO, initial_fg_process_group) == -1 && errno == ENOTTY) { + redirect_tty_output(); + } } } @@ -1943,13 +1945,13 @@ bool fish_reserved_codepoint(wchar_t c) { (c >= INPUT_COMMON_BASE && c < INPUT_COMMON_END); } -/// Reopen stdout and/or stderr on /dev/null. This is invoked when we find that our tty has become -/// invalid. +/// Reopen stdin, stdout and/or stderr on /dev/null. This is invoked when we find that our tty has +/// become invalid. void redirect_tty_output() { struct termios t; int fd = open("/dev/null", O_WRONLY); - if (tcgetattr(STDIN_FILENO, &t) == -1) dup2(fd, STDIN_FILENO); - if (tcgetattr(STDOUT_FILENO, &t) == -1) dup2(fd, STDOUT_FILENO); - if (tcgetattr(STDERR_FILENO, &t) == -1) dup2(fd, STDERR_FILENO); + if (tcgetattr(STDIN_FILENO, &t) == -1 && errno == EIO) dup2(fd, STDIN_FILENO); + if (tcgetattr(STDOUT_FILENO, &t) == -1 && errno == EIO) dup2(fd, STDOUT_FILENO); + if (tcgetattr(STDERR_FILENO, &t) == -1 && errno == EIO) dup2(fd, STDERR_FILENO); close(fd); } diff --git a/src/proc.cpp b/src/proc.cpp index 0237145bb..2d445c5eb 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -820,7 +820,7 @@ static int terminal_return_from_job(job_t *j) { // Save jobs terminal modes. if (tcgetattr(STDIN_FILENO, &j->tmodes)) { - if (errno == ENOTTY) redirect_tty_output(); + if (errno == EIO) redirect_tty_output(); debug(1, _(L"Could not return shell to foreground")); wperror(L"tcgetattr"); return 0; @@ -832,7 +832,8 @@ static int terminal_return_from_job(job_t *j) { // https://github.com/fish-shell/fish-shell/issues/121 #if 0 // Restore the shell's terminal modes. - if (tcsetattr(STDIN_FILENO, TCSADRAIN, &shell_modes)) { + if (tcsetattr(STDIN_FILENO, TCSADRAIN, &shell_modes) == -1) { + if (errno == EIO) redirect_tty_output(); debug(1, _(L"Could not return shell to foreground")); wperror(L"tcsetattr"); return 0; diff --git a/src/reader.cpp b/src/reader.cpp index 0b67d5be6..a550915d7 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -318,7 +318,7 @@ static void term_donate() { while (1) { if (tcsetattr(STDIN_FILENO, TCSANOW, &tty_modes_for_external_cmds) == -1) { - if (errno == ENOTTY) redirect_tty_output(); + if (errno == EIO) redirect_tty_output(); if (errno != EINTR) { debug(1, _(L"Could not set terminal mode for new job")); wperror(L"tcsetattr"); @@ -347,7 +347,7 @@ static void update_buff_pos(editable_line_t *el, size_t buff_pos) { static void term_steal() { while (1) { if (tcsetattr(STDIN_FILENO, TCSANOW, &shell_modes) == -1) { - if (errno == ENOTTY) redirect_tty_output(); + if (errno == EIO) redirect_tty_output(); if (errno != EINTR) { debug(1, _(L"Could not set terminal mode for shell")); perror("tcsetattr"); @@ -794,7 +794,7 @@ void restore_term_mode() { // Restore the term mode if we own the terminal. It's important we do this before // restore_foreground_process_group, otherwise we won't think we own the terminal. if (getpid() == tcgetpgrp(STDIN_FILENO)) { - if (tcsetattr(STDIN_FILENO, TCSANOW, &terminal_mode_on_startup) == -1 && errno == ENOTTY) { + if (tcsetattr(STDIN_FILENO, TCSANOW, &terminal_mode_on_startup) == -1 && errno == EIO) { redirect_tty_output(); } } @@ -1590,8 +1590,9 @@ static void reader_interactive_init() { for (unsigned long loop_count = 0;; loop_count++) { pid_t owner = tcgetpgrp(STDIN_FILENO); shell_pgid = getpgrp(); - if (owner < 0 && errno == ENOTTY) { + if (owner == -1 && errno == ENOTTY) { // No TTY, cannot be interactive? + redirect_tty_output(); debug(1, _(L"No TTY for interactive shell (tcgetpgrp failed)")); wperror(L"setpgid"); exit_without_destructors(1); @@ -1643,7 +1644,7 @@ static void reader_interactive_init() { // Set the new modes. if (tcsetattr(0, TCSANOW, &shell_modes) == -1) { - if (errno == ENOTTY) redirect_tty_output(); + if (errno == EIO) redirect_tty_output(); wperror(L"tcsetattr"); } @@ -2383,10 +2384,10 @@ const wchar_t *reader_readline(int nchars) { reader_repaint(); // Get the current terminal modes. These will be restored when the function returns. - tcgetattr(STDIN_FILENO, &old_modes); + if (tcgetattr(STDIN_FILENO, &old_modes) == -1 && errno == EIO) redirect_tty_output(); // Set the new modes. if (tcsetattr(0, TCSANOW, &shell_modes) == -1) { - if (errno == ENOTTY) redirect_tty_output(); + if (errno == EIO) redirect_tty_output(); wperror(L"tcsetattr"); } @@ -3253,7 +3254,7 @@ const wchar_t *reader_readline(int nchars) { if (!reader_exit_forced()) { if (tcsetattr(0, TCSANOW, &old_modes) == -1) { - if (errno == ENOTTY) redirect_tty_output(); + if (errno == EIO) redirect_tty_output(); wperror(L"tcsetattr"); // return to previous mode } set_color(rgb_color_t::reset(), rgb_color_t::reset()); @@ -3359,7 +3360,20 @@ int reader_read(int fd, const io_chain_t &io) { // If reader_read is called recursively through the '.' builtin, we need to preserve // is_interactive. This, and signal handler setup is handled by // proc_push_interactive/proc_pop_interactive. - int inter = ((fd == STDIN_FILENO) && isatty(STDIN_FILENO)); + int inter = 0; + // This block is a hack to work around https://sourceware.org/bugzilla/show_bug.cgi?id=20632. + // See also, commit 396bf12. Without the need for this workaround we would just write: + // int inter = ((fd == STDIN_FILENO) && isatty(STDIN_FILENO)); + if (fd == STDIN_FILENO) { + struct termios t; + int a_tty = isatty(STDIN_FILENO); + if (a_tty) { + inter = 1; + } else if (tcgetattr(STDIN_FILENO, &t) == -1 && errno == EIO) { + redirect_tty_output(); + inter = 1; + } + } proc_push_interactive(inter); res = shell_is_interactive() ? read_i() : read_ni(fd, io);