mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-22 12:41:08 +08:00
Make SIGTERM handler async-signal-safe again
Some checks failed
make test / ubuntu (push) Waiting to run
make test / ubuntu-32bit-static-pcre2 (push) Waiting to run
make test / ubuntu-asan (push) Waiting to run
make test / macos (push) Waiting to run
Rust checks / rustfmt (push) Waiting to run
Rust checks / clippy (push) Waiting to run
Lock threads / lock (push) Has been cancelled
Some checks failed
make test / ubuntu (push) Waiting to run
make test / ubuntu-32bit-static-pcre2 (push) Waiting to run
make test / ubuntu-asan (push) Waiting to run
make test / macos (push) Waiting to run
Rust checks / rustfmt (push) Waiting to run
Rust checks / clippy (push) Waiting to run
Lock threads / lock (push) Has been cancelled
This commit is contained in:
parent
ae7b401029
commit
30cba03bf9
|
@ -21,7 +21,6 @@ use bitflags::bitflags;
|
||||||
use core::slice;
|
use core::slice;
|
||||||
use libc::{EIO, O_WRONLY, SIGTTOU, SIG_IGN, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO};
|
use libc::{EIO, O_WRONLY, SIGTTOU, SIG_IGN, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO};
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use std::env;
|
|
||||||
use std::ffi::{CStr, CString, OsStr, OsString};
|
use std::ffi::{CStr, CString, OsStr, OsString};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
@ -30,6 +29,7 @@ use std::path::{Path, PathBuf};
|
||||||
use std::sync::atomic::{AtomicI32, AtomicU32, Ordering};
|
use std::sync::atomic::{AtomicI32, AtomicU32, Ordering};
|
||||||
use std::sync::{Arc, MutexGuard};
|
use std::sync::{Arc, MutexGuard};
|
||||||
use std::time;
|
use std::time;
|
||||||
|
use std::{env, process};
|
||||||
|
|
||||||
pub const PACKAGE_NAME: &str = env!("CARGO_PKG_NAME");
|
pub const PACKAGE_NAME: &str = env!("CARGO_PKG_NAME");
|
||||||
|
|
||||||
|
@ -1634,12 +1634,16 @@ pub fn fish_reserved_codepoint(c: char) -> bool {
|
||||||
|| (c >= key::Backspace && c < ENCODE_DIRECT_END)
|
|| (c >= key::Backspace && c < ENCODE_DIRECT_END)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn redirect_tty_output() {
|
pub fn redirect_tty_output(in_signal_handler: bool) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut t: libc::termios = mem::zeroed();
|
let mut t: libc::termios = mem::zeroed();
|
||||||
let s = CString::new("/dev/null").unwrap();
|
let s = CStr::from_bytes_with_nul(b"/dev/null\0").unwrap();
|
||||||
let fd = libc::open(s.as_ptr(), O_WRONLY);
|
let fd = libc::open(s.as_ptr(), O_WRONLY);
|
||||||
assert!(fd != -1, "Could not open /dev/null!");
|
if in_signal_handler && fd == -1 {
|
||||||
|
process::abort();
|
||||||
|
} else {
|
||||||
|
assert!(fd != -1, "Could not open /dev/null!");
|
||||||
|
}
|
||||||
for stdfd in [STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO] {
|
for stdfd in [STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO] {
|
||||||
if libc::tcgetattr(stdfd, &mut t) == -1 && errno::errno().0 == EIO {
|
if libc::tcgetattr(stdfd, &mut t) == -1 && errno::errno().0 == EIO {
|
||||||
libc::dup2(fd, stdfd);
|
libc::dup2(fd, stdfd);
|
||||||
|
|
|
@ -440,7 +440,7 @@ fn launch_process_nofork(vars: &EnvStack, p: &Process) -> ! {
|
||||||
let actual_cmd = wcs2zstring(&p.actual_cmd);
|
let actual_cmd = wcs2zstring(&p.actual_cmd);
|
||||||
|
|
||||||
// Ensure the terminal modes are what they were before we changed them.
|
// Ensure the terminal modes are what they were before we changed them.
|
||||||
restore_term_mode();
|
restore_term_mode(false);
|
||||||
// Bounce to launch_process. This never returns.
|
// Bounce to launch_process. This never returns.
|
||||||
safe_launch_process(p, &actual_cmd, &argv, &*envp);
|
safe_launch_process(p, &actual_cmd, &argv, &*envp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// This concerns posix_spawn support, and async-signal
|
// This concerns posix_spawn support, and async-signal
|
||||||
// safe code which happens in between fork and exec.
|
// safe code which happens in between fork and exec.
|
||||||
|
|
||||||
mod flog_safe;
|
pub mod flog_safe;
|
||||||
pub mod postfork;
|
pub mod postfork;
|
||||||
pub mod spawn;
|
pub mod spawn;
|
||||||
use crate::proc::Job;
|
use crate::proc::Job;
|
||||||
|
|
|
@ -7,6 +7,7 @@ use crate::common::{
|
||||||
use crate::env::{EnvStack, Environment};
|
use crate::env::{EnvStack, Environment};
|
||||||
use crate::fd_readable_set::FdReadableSet;
|
use crate::fd_readable_set::FdReadableSet;
|
||||||
use crate::flog::FLOG;
|
use crate::flog::FLOG;
|
||||||
|
use crate::fork_exec::flog_safe::FLOG_SAFE;
|
||||||
use crate::global_safety::RelaxedAtomicBool;
|
use crate::global_safety::RelaxedAtomicBool;
|
||||||
use crate::key::{
|
use crate::key::{
|
||||||
self, alt, canonicalize_control_char, canonicalize_keyed_control_char, function_key, shift,
|
self, alt, canonicalize_control_char, canonicalize_keyed_control_char, function_key, shift,
|
||||||
|
@ -485,13 +486,7 @@ pub fn terminal_protocols_enable_ifn() {
|
||||||
"\x1b=", // set application keypad mode, so the keypad keys send unique codes
|
"\x1b=", // set application keypad mode, so the keypad keys send unique codes
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
FLOG!(
|
FLOG!(term_protocols, "Enabling extended keys and bracketed paste");
|
||||||
term_protocols,
|
|
||||||
format!(
|
|
||||||
"Enabling extended keys and bracketed paste: {:?}",
|
|
||||||
sequences
|
|
||||||
)
|
|
||||||
);
|
|
||||||
let _ = write_to_fd(sequences.as_bytes(), STDOUT_FILENO);
|
let _ = write_to_fd(sequences.as_bytes(), STDOUT_FILENO);
|
||||||
if IS_TMUX.load() {
|
if IS_TMUX.load() {
|
||||||
let _ = write_to_fd("\x1b[?1004h".as_bytes(), STDOUT_FILENO);
|
let _ = write_to_fd("\x1b[?1004h".as_bytes(), STDOUT_FILENO);
|
||||||
|
@ -513,12 +508,9 @@ pub(crate) fn terminal_protocols_disable_ifn() {
|
||||||
"\x1b>", // application keypad mode
|
"\x1b>", // application keypad mode
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
FLOG!(
|
FLOG_SAFE!(
|
||||||
term_protocols,
|
term_protocols,
|
||||||
format!(
|
"Disabling extended keys and bracketed paste"
|
||||||
"Disabling extended keys and bracketed paste: {:?}",
|
|
||||||
sequences
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
let _ = write_to_fd(sequences.as_bytes(), STDOUT_FILENO);
|
let _ = write_to_fd(sequences.as_bytes(), STDOUT_FILENO);
|
||||||
if IS_TMUX.load() {
|
if IS_TMUX.load() {
|
||||||
|
|
|
@ -13,7 +13,7 @@ use crate::{
|
||||||
threads::{asan_maybe_exit, is_main_thread},
|
threads::{asan_maybe_exit, is_main_thread},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub static AT_EXIT: OnceCell<Box<dyn Fn() + Send + Sync>> = OnceCell::new();
|
pub static AT_EXIT: OnceCell<Box<dyn Fn(bool) + Send + Sync>> = OnceCell::new();
|
||||||
|
|
||||||
pub fn panic_handler(main: impl FnOnce() -> i32 + UnwindSafe) -> ! {
|
pub fn panic_handler(main: impl FnOnce() -> i32 + UnwindSafe) -> ! {
|
||||||
if isatty(STDIN_FILENO) {
|
if isatty(STDIN_FILENO) {
|
||||||
|
@ -28,7 +28,7 @@ pub fn panic_handler(main: impl FnOnce() -> i32 + UnwindSafe) -> ! {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Some(at_exit) = AT_EXIT.get() {
|
if let Some(at_exit) = AT_EXIT.get() {
|
||||||
(at_exit)();
|
(at_exit)(false);
|
||||||
}
|
}
|
||||||
eprintf!(
|
eprintf!(
|
||||||
"%s crashed, please report a bug.",
|
"%s crashed, please report a bug.",
|
||||||
|
@ -54,7 +54,7 @@ pub fn panic_handler(main: impl FnOnce() -> i32 + UnwindSafe) -> ! {
|
||||||
}
|
}
|
||||||
let exit_status = main();
|
let exit_status = main();
|
||||||
if let Some(at_exit) = AT_EXIT.get() {
|
if let Some(at_exit) = AT_EXIT.get() {
|
||||||
(at_exit)();
|
(at_exit)(false);
|
||||||
}
|
}
|
||||||
asan_maybe_exit(exit_status);
|
asan_maybe_exit(exit_status);
|
||||||
std::process::exit(exit_status)
|
std::process::exit(exit_status)
|
||||||
|
|
|
@ -425,7 +425,7 @@ impl TtyTransfer {
|
||||||
}
|
}
|
||||||
EBADF => {
|
EBADF => {
|
||||||
// stdin has been closed. Workaround a glibc bug - see #3644.
|
// stdin has been closed. Workaround a glibc bug - see #3644.
|
||||||
redirect_tty_output();
|
redirect_tty_output(false);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
@ -200,7 +200,7 @@ fn redirect_tty_after_sighup() {
|
||||||
assert!(reader_received_sighup(), "SIGHUP not received");
|
assert!(reader_received_sighup(), "SIGHUP not received");
|
||||||
static TTY_REDIRECTED: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
|
static TTY_REDIRECTED: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
|
||||||
if !TTY_REDIRECTED.swap(true) {
|
if !TTY_REDIRECTED.swap(true) {
|
||||||
redirect_tty_output();
|
redirect_tty_output(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -585,7 +585,7 @@ pub fn reader_read(parser: &Parser, fd: RawFd, io: &IoChain) -> c_int {
|
||||||
if isatty(STDIN_FILENO) {
|
if isatty(STDIN_FILENO) {
|
||||||
interactive = true;
|
interactive = true;
|
||||||
} else if unsafe { libc::tcgetattr(STDIN_FILENO, &mut t) } == -1 && errno().0 == EIO {
|
} else if unsafe { libc::tcgetattr(STDIN_FILENO, &mut t) } == -1 && errno().0 == EIO {
|
||||||
redirect_tty_output();
|
redirect_tty_output(false);
|
||||||
interactive = true;
|
interactive = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -793,7 +793,11 @@ pub fn reader_init(will_restore_foreground_pgroup: bool) {
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
assert!(AT_EXIT.get().is_none());
|
assert!(AT_EXIT.get().is_none());
|
||||||
AT_EXIT.get_or_init(|| Box::new(move || reader_deinit(will_restore_foreground_pgroup)));
|
AT_EXIT.get_or_init(|| {
|
||||||
|
Box::new(move |in_signal_handler| {
|
||||||
|
reader_deinit(in_signal_handler, will_restore_foreground_pgroup)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
// Set the mode used for program execution, initialized to the current mode.
|
// Set the mode used for program execution, initialized to the current mode.
|
||||||
let mut tty_modes_for_external_cmds = TTY_MODES_FOR_EXTERNAL_CMDS.lock().unwrap();
|
let mut tty_modes_for_external_cmds = TTY_MODES_FOR_EXTERNAL_CMDS.lock().unwrap();
|
||||||
|
@ -821,8 +825,8 @@ pub fn reader_init(will_restore_foreground_pgroup: bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reader_deinit(restore_foreground_pgroup: bool) {
|
pub fn reader_deinit(in_signal_handler: bool, restore_foreground_pgroup: bool) {
|
||||||
restore_term_mode();
|
restore_term_mode(in_signal_handler);
|
||||||
crate::input_common::terminal_protocols_disable_ifn();
|
crate::input_common::terminal_protocols_disable_ifn();
|
||||||
if restore_foreground_pgroup {
|
if restore_foreground_pgroup {
|
||||||
restore_term_foreground_process_group_for_exit();
|
restore_term_foreground_process_group_for_exit();
|
||||||
|
@ -832,7 +836,7 @@ pub fn reader_deinit(restore_foreground_pgroup: bool) {
|
||||||
/// Restore the term mode if we own the terminal and are interactive (#8705).
|
/// Restore the term mode if we own the terminal and are interactive (#8705).
|
||||||
/// It's important we do this before restore_foreground_process_group,
|
/// It's important we do this before restore_foreground_process_group,
|
||||||
/// otherwise we won't think we own the terminal.
|
/// otherwise we won't think we own the terminal.
|
||||||
pub fn restore_term_mode() {
|
pub fn restore_term_mode(in_signal_handler: bool) {
|
||||||
if !is_interactive_session() || unsafe { libc::getpgrp() != libc::tcgetpgrp(STDIN_FILENO) } {
|
if !is_interactive_session() || unsafe { libc::getpgrp() != libc::tcgetpgrp(STDIN_FILENO) } {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -845,7 +849,7 @@ pub fn restore_term_mode() {
|
||||||
) == -1
|
) == -1
|
||||||
} && errno().0 == EIO
|
} && errno().0 == EIO
|
||||||
{
|
{
|
||||||
redirect_tty_output();
|
redirect_tty_output(in_signal_handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1889,14 +1893,14 @@ impl<'a> Reader<'a> {
|
||||||
// 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.
|
||||||
let mut old_modes: libc::termios = unsafe { std::mem::zeroed() };
|
let mut old_modes: libc::termios = unsafe { std::mem::zeroed() };
|
||||||
if unsafe { libc::tcgetattr(zelf.conf.inputfd, &mut old_modes) } == -1 && errno().0 == EIO {
|
if unsafe { libc::tcgetattr(zelf.conf.inputfd, &mut old_modes) } == -1 && errno().0 == EIO {
|
||||||
redirect_tty_output();
|
redirect_tty_output(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the new modes.
|
// Set the new modes.
|
||||||
if unsafe { libc::tcsetattr(zelf.conf.inputfd, TCSANOW, &*shell_modes()) } == -1 {
|
if unsafe { libc::tcsetattr(zelf.conf.inputfd, TCSANOW, &*shell_modes()) } == -1 {
|
||||||
let err = errno().0;
|
let err = errno().0;
|
||||||
if err == EIO {
|
if err == EIO {
|
||||||
redirect_tty_output();
|
redirect_tty_output(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This check is required to work around certain issues with fish's approach to
|
// This check is required to work around certain issues with fish's approach to
|
||||||
|
@ -1974,7 +1978,7 @@ impl<'a> Reader<'a> {
|
||||||
&& is_interactive_session()
|
&& is_interactive_session()
|
||||||
{
|
{
|
||||||
if errno().0 == EIO {
|
if errno().0 == EIO {
|
||||||
redirect_tty_output();
|
redirect_tty_output(false);
|
||||||
}
|
}
|
||||||
perror("tcsetattr"); // return to previous mode
|
perror("tcsetattr"); // return to previous mode
|
||||||
}
|
}
|
||||||
|
@ -3758,7 +3762,7 @@ fn term_donate(quiet: bool /* = false */) {
|
||||||
} == -1
|
} == -1
|
||||||
{
|
{
|
||||||
if errno().0 == EIO {
|
if errno().0 == EIO {
|
||||||
redirect_tty_output();
|
redirect_tty_output(false);
|
||||||
}
|
}
|
||||||
if errno().0 != EINTR {
|
if errno().0 != EINTR {
|
||||||
if !quiet {
|
if !quiet {
|
||||||
|
@ -3804,7 +3808,7 @@ fn term_steal(copy_modes: bool) {
|
||||||
}
|
}
|
||||||
while unsafe { libc::tcsetattr(STDIN_FILENO, TCSANOW, &*shell_modes()) } == -1 {
|
while unsafe { libc::tcsetattr(STDIN_FILENO, TCSANOW, &*shell_modes()) } == -1 {
|
||||||
if errno().0 == EIO {
|
if errno().0 == EIO {
|
||||||
redirect_tty_output();
|
redirect_tty_output(false);
|
||||||
}
|
}
|
||||||
if errno().0 != EINTR {
|
if errno().0 != EINTR {
|
||||||
FLOG!(warning, wgettext!("Could not set terminal mode for shell"));
|
FLOG!(warning, wgettext!("Could not set terminal mode for shell"));
|
||||||
|
@ -3875,7 +3879,7 @@ fn acquire_tty_or_exit(shell_pgid: libc::pid_t) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// No TTY, cannot be interactive?
|
// No TTY, cannot be interactive?
|
||||||
redirect_tty_output();
|
redirect_tty_output(false);
|
||||||
FLOG!(
|
FLOG!(
|
||||||
warning,
|
warning,
|
||||||
wgettext!("No TTY for interactive shell (tcgetpgrp failed)")
|
wgettext!("No TTY for interactive shell (tcgetpgrp failed)")
|
||||||
|
@ -3941,7 +3945,7 @@ fn reader_interactive_init(parser: &Parser) {
|
||||||
// Take control of the terminal
|
// Take control of the terminal
|
||||||
if unsafe { libc::tcsetpgrp(STDIN_FILENO, shell_pgid) } == -1 {
|
if unsafe { libc::tcsetpgrp(STDIN_FILENO, shell_pgid) } == -1 {
|
||||||
if errno().0 == ENOTTY {
|
if errno().0 == ENOTTY {
|
||||||
redirect_tty_output();
|
redirect_tty_output(false);
|
||||||
}
|
}
|
||||||
FLOG!(error, wgettext!("Failed to take control of the terminal"));
|
FLOG!(error, wgettext!("Failed to take control of the terminal"));
|
||||||
perror("tcsetpgrp");
|
perror("tcsetpgrp");
|
||||||
|
@ -3951,7 +3955,7 @@ fn reader_interactive_init(parser: &Parser) {
|
||||||
// Configure terminal attributes
|
// Configure terminal attributes
|
||||||
if unsafe { libc::tcsetattr(STDIN_FILENO, TCSANOW, &*shell_modes()) } == -1 {
|
if unsafe { libc::tcsetattr(STDIN_FILENO, TCSANOW, &*shell_modes()) } == -1 {
|
||||||
if errno().0 == EIO {
|
if errno().0 == EIO {
|
||||||
redirect_tty_output();
|
redirect_tty_output(false);
|
||||||
}
|
}
|
||||||
FLOG!(warning, wgettext!("Failed to set startup terminal mode!"));
|
FLOG!(warning, wgettext!("Failed to set startup terminal mode!"));
|
||||||
perror("tcsetattr");
|
perror("tcsetattr");
|
||||||
|
|
|
@ -89,7 +89,7 @@ extern "C" fn fish_signal_handler(
|
||||||
// Handle sigterm. The only thing we do is restore the front process ID, then die.
|
// Handle sigterm. The only thing we do is restore the front process ID, then die.
|
||||||
if !observed {
|
if !observed {
|
||||||
if let Some(at_exit) = AT_EXIT.get() {
|
if let Some(at_exit) = AT_EXIT.get() {
|
||||||
(at_exit)();
|
(at_exit)(true);
|
||||||
}
|
}
|
||||||
// Safety: signal() and raise() are async-signal-safe.
|
// Safety: signal() and raise() are async-signal-safe.
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -111,7 +111,7 @@ pub mod prelude {
|
||||||
});
|
});
|
||||||
reader_init(false);
|
reader_init(false);
|
||||||
ScopeGuard::new((), |()| {
|
ScopeGuard::new((), |()| {
|
||||||
reader_deinit(false);
|
reader_deinit(false, false);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user