diff --git a/Cargo.toml b/Cargo.toml index 3603bc8..f376766 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,8 @@ backhand = "0.14.2" byteorder = "1" bytes = "1.5.0" cli-tables = "0.2.1" +crossterm = "0.27.0" +ctrlc = "3.4.4" directories = "5.0.1" elf = "0.7.4" env_logger = "0.11.0" diff --git a/crates/kratactl/Cargo.toml b/crates/kratactl/Cargo.toml index a453326..010493e 100644 --- a/crates/kratactl/Cargo.toml +++ b/crates/kratactl/Cargo.toml @@ -9,19 +9,19 @@ anyhow = { workspace = true } async-stream = { workspace = true } clap = { workspace = true } cli-tables = { workspace = true } +crossterm = { workspace = true } +ctrlc = { workspace = true, features = ["termination"] } env_logger = { workspace = true } krata = { path = "../krata" } log = { workspace = true } serde = { workspace = true } +signal-hook = { workspace = true } tokio = { workspace = true } tokio-stream = { workspace = true } tonic = { workspace = true } tower = { workspace = true } url = { workspace = true } -[target.'cfg(unix)'.dependencies] -termion = { workspace = true } - [lib] name = "kratactl" diff --git a/crates/kratactl/src/cli/console.rs b/crates/kratactl/src/cli/console.rs index fc8fb67..83e45a3 100644 --- a/crates/kratactl/src/cli/console.rs +++ b/crates/kratactl/src/cli/console.rs @@ -32,6 +32,7 @@ impl ConsoleCommand { }, x = exit_hook_task => x? }; + StdioConsoleStream::restore_terminal_mode(); std::process::exit(code.unwrap_or(0)); } } diff --git a/crates/kratactl/src/cli/launch.rs b/crates/kratactl/src/cli/launch.rs index c545b94..30e34d7 100644 --- a/crates/kratactl/src/cli/launch.rs +++ b/crates/kratactl/src/cli/launch.rs @@ -71,6 +71,7 @@ impl LauchCommand { println!("created guest: {}", id); None }; + StdioConsoleStream::restore_terminal_mode(); std::process::exit(code.unwrap_or(0)); } } diff --git a/crates/kratactl/src/console.rs b/crates/kratactl/src/console.rs index f41d17d..ece348b 100644 --- a/crates/kratactl/src/console.rs +++ b/crates/kratactl/src/console.rs @@ -1,18 +1,16 @@ use anyhow::Result; use async_stream::stream; +use crossterm::{ + terminal::{disable_raw_mode, enable_raw_mode, is_raw_mode_enabled}, + tty::IsTty, +}; use krata::{ common::GuestStatus, control::{watch_events_reply::Event, ConsoleDataReply, ConsoleDataRequest}, }; use log::debug; -#[cfg(unix)] -use std::os::fd::{AsRawFd, FromRawFd}; -#[cfg(unix)] -use termion::raw::IntoRawMode; -#[cfg(unix)] -use tokio::fs::File; use tokio::{ - io::{stdin, AsyncReadExt, AsyncWriteExt}, + io::{stdin, stdout, AsyncReadExt, AsyncWriteExt}, task::JoinHandle, }; use tokio_stream::{Stream, StreamExt}; @@ -47,14 +45,11 @@ impl StdioConsoleStream { } pub async fn stdout(mut stream: Streaming) -> Result<()> { - #[cfg(unix)] - let terminal = std::io::stdout().into_raw_mode()?; - #[cfg(unix)] - let mut stdout = - unsafe { File::from_std(std::fs::File::from_raw_fd(terminal.as_raw_fd())) }; - #[cfg(not(unix))] - let mut stdout = tokio::io::stdout(); - + if stdin().is_tty() { + enable_raw_mode()?; + StdioConsoleStream::register_terminal_restore_hook()?; + } + let mut stdout = stdout(); while let Some(reply) = stream.next().await { let reply = reply?; if reply.data.is_empty() { @@ -101,4 +96,19 @@ impl StdioConsoleStream { None })) } + + fn register_terminal_restore_hook() -> Result<()> { + if stdin().is_tty() { + ctrlc::set_handler(move || { + StdioConsoleStream::restore_terminal_mode(); + })?; + } + Ok(()) + } + + pub fn restore_terminal_mode() { + if is_raw_mode_enabled().unwrap_or(false) { + let _ = disable_raw_mode(); + } + } }