summaryrefslogtreecommitdiffstats
path: root/zellij-client/src
diff options
context:
space:
mode:
authorraphCode <15750438+raphCode@users.noreply.github.com>2022-05-24 14:10:37 +0200
committerGitHub <noreply@github.com>2022-05-24 14:10:37 +0200
commiteab464b11adb28e504cefdc39b596d5e5787a2bb (patch)
tree5c10a63ecbd7db2c9baf1fc292f052d3e4b6ea3e /zellij-client/src
parent69ec7c7e3afa4cdc0d5ea070c328693785330ccc (diff)
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
Diffstat (limited to 'zellij-client/src')
-rw-r--r--zellij-client/src/lib.rs13
-rw-r--r--zellij-client/src/os_input_output.rs13
-rw-r--r--zellij-client/src/unit/input_handler_tests.rs3
3 files changed, 15 insertions, 14 deletions
diff --git a/zellij-client/src/lib.rs b/zellij-client/src/lib.rs
index bd5b04f54..5ddaa5fee 100644
--- a/zellij-client/src/lib.rs
+++ b/zellij-client/src/lib.rs
@@ -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();
diff --git a/zellij-client/src/os_input_output.rs b/zellij-client/src/os_input_output.rs
index b93b6121d..f3e916c48 100644
--- a/zellij-client/src/os_input_output.rs
+++ b/zellij-client/src/os_input_output.rs
@@ -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())
diff --git a/zellij-client/src/unit/input_handler_tests.rs b/zellij-client/src/unit/input_handler_tests.rs
index 4b830656f..ba5ac11c2 100644
--- a/zellij-client/src/unit/input_handler_tests.rs
+++ b/zellij-client/src/unit/input_handler_tests.rs
@@ -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> {