Fix double panic lockup in clients panic handler (#1433)
* Fix possible lockup in the clients panic handler When the pty the client was running in disappears, reading from stdin causes a panic, which triggers the custom panic handler. This handler attempts to print a backtrace to the terminal and tries to unset the raw mode for that. Since the pty has already disappeared, the tcsetattr call fails and causes a second panic, which locks everything up. This commit fixes this by returning an Result from the unset_raw_mode function, allowing the calling panic handler to handle any error gracefully. * Log any client panics to file Since we are now aware of the fact that panics may happen / are handled after the pty has disappeared, logging them to file seems useful: there is no other other place to show them to the user. * fix tests and improve function return type
This commit is contained in:
parent
69ec7c7e3a
commit
eab464b11a
3 changed files with 15 additions and 14 deletions
|
|
@ -5,6 +5,7 @@ mod input_handler;
|
|||
mod stdin_ansi_parser;
|
||||
mod stdin_handler;
|
||||
|
||||
use log::error;
|
||||
use log::info;
|
||||
use std::env::current_exe;
|
||||
use std::io::{self, Write};
|
||||
|
|
@ -124,7 +125,7 @@ pub fn start_client(
|
|||
let clear_client_terminal_attributes = "\u{1b}[?1l\u{1b}=\u{1b}[r\u{1b}12l\u{1b}[?1000l\u{1b}[?1002l\u{1b}[?1003l\u{1b}[?1005l\u{1b}[?1006l\u{1b}[?12l";
|
||||
let take_snapshot = "\u{1b}[?1049h";
|
||||
let bracketed_paste = "\u{1b}[?2004h";
|
||||
os_input.unset_raw_mode(0);
|
||||
os_input.unset_raw_mode(0).unwrap();
|
||||
|
||||
let _ = os_input
|
||||
.get_stdout_writer()
|
||||
|
|
@ -201,8 +202,10 @@ pub fn start_client(
|
|||
let send_client_instructions = send_client_instructions.clone();
|
||||
let os_input = os_input.clone();
|
||||
Box::new(move |info| {
|
||||
os_input.unset_raw_mode(0);
|
||||
handle_panic(info, &send_client_instructions);
|
||||
error!("Panic occured in client:\n{:?}", info);
|
||||
if let Ok(()) = os_input.unset_raw_mode(0) {
|
||||
handle_panic(info, &send_client_instructions);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
|
@ -293,7 +296,7 @@ pub fn start_client(
|
|||
.unwrap();
|
||||
|
||||
let handle_error = |backtrace: String| {
|
||||
os_input.unset_raw_mode(0);
|
||||
os_input.unset_raw_mode(0).unwrap();
|
||||
let goto_start_of_last_line = format!("\u{1b}[{};{}H", full_screen_ws.rows, 1);
|
||||
let restore_snapshot = "\u{1b}[?1049l";
|
||||
os_input.disable_mouse();
|
||||
|
|
@ -364,7 +367,7 @@ pub fn start_client(
|
|||
|
||||
os_input.disable_mouse();
|
||||
info!("{}", exit_msg);
|
||||
os_input.unset_raw_mode(0);
|
||||
os_input.unset_raw_mode(0).unwrap();
|
||||
let mut stdout = os_input.get_stdout_writer();
|
||||
let _ = stdout.write(goodbye_message.as_bytes()).unwrap();
|
||||
stdout.flush().unwrap();
|
||||
|
|
|
|||
|
|
@ -32,11 +32,8 @@ fn into_raw_mode(pid: RawFd) {
|
|||
};
|
||||
}
|
||||
|
||||
fn unset_raw_mode(pid: RawFd, orig_termios: termios::Termios) {
|
||||
match termios::tcsetattr(pid, termios::SetArg::TCSANOW, &orig_termios) {
|
||||
Ok(_) => {}
|
||||
Err(e) => panic!("error {:?}", e),
|
||||
};
|
||||
fn unset_raw_mode(pid: RawFd, orig_termios: termios::Termios) -> Result<(), nix::Error> {
|
||||
termios::tcsetattr(pid, termios::SetArg::TCSANOW, &orig_termios)
|
||||
}
|
||||
|
||||
pub(crate) fn get_terminal_size_using_fd(fd: RawFd) -> Size {
|
||||
|
|
@ -81,7 +78,7 @@ pub trait ClientOsApi: Send + Sync {
|
|||
fn set_raw_mode(&mut self, fd: RawFd);
|
||||
/// Set the terminal associated to file descriptor `fd` to
|
||||
/// [cooked mode](https://en.wikipedia.org/wiki/Terminal_mode).
|
||||
fn unset_raw_mode(&self, fd: RawFd);
|
||||
fn unset_raw_mode(&self, fd: RawFd) -> Result<(), nix::Error>;
|
||||
/// Returns the writer that allows writing to standard output.
|
||||
fn get_stdout_writer(&self) -> Box<dyn io::Write>;
|
||||
fn get_stdin_reader(&self) -> Box<dyn io::Read>;
|
||||
|
|
@ -111,9 +108,9 @@ impl ClientOsApi for ClientOsInputOutput {
|
|||
fn set_raw_mode(&mut self, fd: RawFd) {
|
||||
into_raw_mode(fd);
|
||||
}
|
||||
fn unset_raw_mode(&self, fd: RawFd) {
|
||||
fn unset_raw_mode(&self, fd: RawFd) -> Result<(), nix::Error> {
|
||||
let orig_termios = self.orig_termios.lock().unwrap();
|
||||
unset_raw_mode(fd, orig_termios.clone());
|
||||
unset_raw_mode(fd, orig_termios.clone())
|
||||
}
|
||||
fn box_clone(&self) -> Box<dyn ClientOsApi> {
|
||||
Box::new((*self).clone())
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use super::input_loop;
|
|||
use zellij_utils::input::actions::{Action, Direction};
|
||||
use zellij_utils::input::config::Config;
|
||||
use zellij_utils::input::options::Options;
|
||||
use zellij_utils::nix;
|
||||
use zellij_utils::pane_size::{Size, SizeInPixels};
|
||||
use zellij_utils::termwiz::input::{InputEvent, KeyCode, KeyEvent, Modifiers};
|
||||
use zellij_utils::zellij_tile::data::Palette;
|
||||
|
|
@ -125,7 +126,7 @@ impl ClientOsApi for FakeClientOsApi {
|
|||
fn set_raw_mode(&mut self, _fd: RawFd) {
|
||||
unimplemented!()
|
||||
}
|
||||
fn unset_raw_mode(&self, _fd: RawFd) {
|
||||
fn unset_raw_mode(&self, _fd: RawFd) -> Result<(), nix::Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn get_stdout_writer(&self) -> Box<dyn io::Write> {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue