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.
This commit is contained in:
Kurtis Rader 2017-01-10 21:52:10 -08:00
parent 2e9a349dd0
commit 56e05dab02
3 changed files with 34 additions and 17 deletions

View file

@ -1710,7 +1710,9 @@ void restore_term_foreground_process_group(void) {
if (initial_fg_process_group != -1) { if (initial_fg_process_group != -1) {
// This is called during shutdown and from a signal handler. We don't bother to complain on // This is called during shutdown and from a signal handler. We don't bother to complain on
// failure. // 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); (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 /// Reopen stdin, stdout and/or stderr on /dev/null. This is invoked when we find that our tty has
/// invalid. /// become invalid.
void redirect_tty_output() { void redirect_tty_output() {
struct termios t; struct termios t;
int fd = open("/dev/null", O_WRONLY); int fd = open("/dev/null", O_WRONLY);
if (tcgetattr(STDIN_FILENO, &t) == -1) dup2(fd, STDIN_FILENO); if (tcgetattr(STDIN_FILENO, &t) == -1 && errno == EIO) dup2(fd, STDIN_FILENO);
if (tcgetattr(STDOUT_FILENO, &t) == -1) dup2(fd, STDOUT_FILENO); if (tcgetattr(STDOUT_FILENO, &t) == -1 && errno == EIO) dup2(fd, STDOUT_FILENO);
if (tcgetattr(STDERR_FILENO, &t) == -1) dup2(fd, STDERR_FILENO); if (tcgetattr(STDERR_FILENO, &t) == -1 && errno == EIO) dup2(fd, STDERR_FILENO);
close(fd); close(fd);
} }

View file

@ -820,7 +820,7 @@ static int terminal_return_from_job(job_t *j) {
// Save jobs terminal modes. // Save jobs terminal modes.
if (tcgetattr(STDIN_FILENO, &j->tmodes)) { 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")); debug(1, _(L"Could not return shell to foreground"));
wperror(L"tcgetattr"); wperror(L"tcgetattr");
return 0; return 0;
@ -832,7 +832,8 @@ static int terminal_return_from_job(job_t *j) {
// https://github.com/fish-shell/fish-shell/issues/121 // https://github.com/fish-shell/fish-shell/issues/121
#if 0 #if 0
// Restore the shell's terminal modes. // 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")); debug(1, _(L"Could not return shell to foreground"));
wperror(L"tcsetattr"); wperror(L"tcsetattr");
return 0; return 0;

View file

@ -318,7 +318,7 @@ static void term_donate() {
while (1) { while (1) {
if (tcsetattr(STDIN_FILENO, TCSANOW, &tty_modes_for_external_cmds) == -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) { if (errno != EINTR) {
debug(1, _(L"Could not set terminal mode for new job")); debug(1, _(L"Could not set terminal mode for new job"));
wperror(L"tcsetattr"); wperror(L"tcsetattr");
@ -347,7 +347,7 @@ static void update_buff_pos(editable_line_t *el, size_t buff_pos) {
static void term_steal() { static void term_steal() {
while (1) { while (1) {
if (tcsetattr(STDIN_FILENO, TCSANOW, &shell_modes) == -1) { if (tcsetattr(STDIN_FILENO, TCSANOW, &shell_modes) == -1) {
if (errno == ENOTTY) redirect_tty_output(); if (errno == EIO) redirect_tty_output();
if (errno != EINTR) { if (errno != EINTR) {
debug(1, _(L"Could not set terminal mode for shell")); debug(1, _(L"Could not set terminal mode for shell"));
perror("tcsetattr"); 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 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. // restore_foreground_process_group, otherwise we won't think we own the terminal.
if (getpid() == tcgetpgrp(STDIN_FILENO)) { 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(); redirect_tty_output();
} }
} }
@ -1590,8 +1590,9 @@ static void reader_interactive_init() {
for (unsigned long loop_count = 0;; loop_count++) { for (unsigned long loop_count = 0;; loop_count++) {
pid_t owner = tcgetpgrp(STDIN_FILENO); pid_t owner = tcgetpgrp(STDIN_FILENO);
shell_pgid = getpgrp(); shell_pgid = getpgrp();
if (owner < 0 && errno == ENOTTY) { if (owner == -1 && errno == ENOTTY) {
// No TTY, cannot be interactive? // No TTY, cannot be interactive?
redirect_tty_output();
debug(1, _(L"No TTY for interactive shell (tcgetpgrp failed)")); debug(1, _(L"No TTY for interactive shell (tcgetpgrp failed)"));
wperror(L"setpgid"); wperror(L"setpgid");
exit_without_destructors(1); exit_without_destructors(1);
@ -1643,7 +1644,7 @@ static void reader_interactive_init() {
// Set the new modes. // Set the new modes.
if (tcsetattr(0, TCSANOW, &shell_modes) == -1) { if (tcsetattr(0, TCSANOW, &shell_modes) == -1) {
if (errno == ENOTTY) redirect_tty_output(); if (errno == EIO) redirect_tty_output();
wperror(L"tcsetattr"); wperror(L"tcsetattr");
} }
@ -2383,10 +2384,10 @@ const wchar_t *reader_readline(int nchars) {
reader_repaint(); reader_repaint();
// Get the current terminal modes. These will be restored when the function returns. // 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. // Set the new modes.
if (tcsetattr(0, TCSANOW, &shell_modes) == -1) { if (tcsetattr(0, TCSANOW, &shell_modes) == -1) {
if (errno == ENOTTY) redirect_tty_output(); if (errno == EIO) redirect_tty_output();
wperror(L"tcsetattr"); wperror(L"tcsetattr");
} }
@ -3253,7 +3254,7 @@ const wchar_t *reader_readline(int nchars) {
if (!reader_exit_forced()) { if (!reader_exit_forced()) {
if (tcsetattr(0, TCSANOW, &old_modes) == -1) { 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 wperror(L"tcsetattr"); // return to previous mode
} }
set_color(rgb_color_t::reset(), rgb_color_t::reset()); 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 // If reader_read is called recursively through the '.' builtin, we need to preserve
// is_interactive. This, and signal handler setup is handled by // is_interactive. This, and signal handler setup is handled by
// proc_push_interactive/proc_pop_interactive. // 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); proc_push_interactive(inter);
res = shell_is_interactive() ? read_i() : read_ni(fd, io); res = shell_is_interactive() ? read_i() : read_ni(fd, io);