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) {
// 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);
}

View file

@ -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;

View file

@ -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);