diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index 964cc7699..b5e0cb7d3 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -70,7 +70,6 @@ use std::os::unix::fs::OpenOptionsExt; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::path::PathBuf; use std::result; -use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex}; use std::time::Instant; use tracer::trace_scoped; @@ -101,7 +100,6 @@ use vm_migration::{ use vm_virtio::AccessPlatform; use vm_virtio::VirtioDeviceType; use vmm_sys_util::eventfd::EventFd; -use vmm_sys_util::terminal::Terminal; #[cfg(target_arch = "aarch64")] const MMIO_LEN: u64 = 0x1000; @@ -833,8 +831,8 @@ pub struct DeviceManager { // pty foreground status, console_resize_pipe: Option>, - // Are any devices using the tty? - on_tty: Option>, + // To restore on exit. + original_termios_opt: Arc>>, // Interrupt controller #[cfg(target_arch = "x86_64")] @@ -1120,7 +1118,7 @@ impl DeviceManager { serial_manager: None, console_pty: None, console_resize_pipe: None, - on_tty: None, + original_termios_opt: Arc::new(Mutex::new(None)), virtio_mem_devices: Vec::new(), #[cfg(target_arch = "aarch64")] gpio_device: None, @@ -1168,7 +1166,7 @@ impl DeviceManager { serial_pty: Option, console_pty: Option, console_resize_pipe: Option, - on_tty: Arc, + original_termios_opt: Arc>>, ) -> DeviceManagerResult<()> { trace_scoped!("create_devices"); @@ -1224,15 +1222,15 @@ impl DeviceManager { )?; } + self.original_termios_opt = original_termios_opt; + self.console = self.add_console_device( &legacy_interrupt_manager, &mut virtio_devices, serial_pty, console_pty, console_resize_pipe, - &on_tty, )?; - self.on_tty = Some(on_tty); if let Some(tpm) = self.config.clone().lock().unwrap().tpm.as_ref() { let tpm_dev = self.add_tpm_device(tpm.socket.clone())?; @@ -1845,7 +1843,7 @@ impl DeviceManager { } fn modify_mode( - &self, + &mut self, fd: RawFd, f: F, ) -> vmm_sys_util::errno::Result<()> { @@ -1862,6 +1860,10 @@ impl DeviceManager { if ret < 0 { return vmm_sys_util::errno::errno_result(); } + let mut original_termios_opt = self.original_termios_opt.lock().unwrap(); + if original_termios_opt.is_none() { + *original_termios_opt = Some(termios); + } f(&mut termios); // SAFETY: Safe because the syscall will only read the extent of termios and we check // the return result. @@ -1873,7 +1875,7 @@ impl DeviceManager { Ok(()) } - fn set_raw_mode(&self, f: &mut dyn AsRawFd) -> vmm_sys_util::errno::Result<()> { + fn set_raw_mode(&mut self, f: &mut dyn AsRawFd) -> vmm_sys_util::errno::Result<()> { // SAFETY: FFI call. Variable t is guaranteed to be a valid termios from modify_mode. self.modify_mode(f.as_raw_fd(), |t| unsafe { cfmakeraw(t) }) } @@ -1897,7 +1899,6 @@ impl DeviceManager { virtio_devices: &mut Vec, console_pty: Option, resize_pipe: Option, - on_tty: &Arc, ) -> DeviceManagerResult>> { let console_config = self.config.lock().unwrap().console.clone(); let endpoint = match console_config.mode { @@ -1938,8 +1939,6 @@ impl DeviceManager { // SAFETY: stdout is valid and owned solely by us. let mut stdout = unsafe { File::from_raw_fd(stdout) }; - on_tty.store(true, Ordering::SeqCst); - // Make sure stdout is in raw mode, if it's a terminal. let _ = self.set_raw_mode(&mut stdout); @@ -2019,7 +2018,6 @@ impl DeviceManager { serial_pty: Option, console_pty: Option, console_resize_pipe: Option, - on_tty: &Arc, ) -> DeviceManagerResult> { let serial_config = self.config.lock().unwrap().serial.clone(); let serial_writer: Option> = match serial_config.mode { @@ -2043,7 +2041,6 @@ impl DeviceManager { } ConsoleOutputMode::Tty => { let mut out = stdout(); - on_tty.store(true, Ordering::SeqCst); let _ = self.set_raw_mode(&mut out); Some(Box::new(out)) } @@ -2073,12 +2070,8 @@ impl DeviceManager { }; } - let console_resizer = self.add_virtio_console_device( - virtio_devices, - console_pty, - console_resize_pipe, - on_tty, - )?; + let console_resizer = + self.add_virtio_console_device(virtio_devices, console_pty, console_resize_pipe)?; Ok(Arc::new(Console { console_resizer })) } @@ -4662,10 +4655,9 @@ impl Drop for DeviceManager { handle.virtio_device.lock().unwrap().shutdown(); } - if let Some(ref on_tty) = self.on_tty { - if on_tty.load(Ordering::SeqCst) { - let _ = std::io::stdin().lock().set_canon_mode(); - } + if let Some(termios) = *self.original_termios_opt.lock().unwrap() { + // SAFETY: FFI call + let _ = unsafe { tcsetattr(stdout().lock().as_raw_fd(), TCSANOW, &termios) }; } } } diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 723cd4e79..ce5c65d28 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -25,7 +25,7 @@ use crate::migration::{recv_vm_config, recv_vm_state}; use crate::seccomp_filters::{get_seccomp_filter, Thread}; use crate::vm::{Error as VmError, Vm, VmState}; use anyhow::anyhow; -use libc::{EFD_NONBLOCK, SIGINT, SIGTERM}; +use libc::{tcsetattr, termios, EFD_NONBLOCK, SIGINT, SIGTERM, TCSANOW}; use memory_manager::MemoryManagerSnapshotData; use pci::PciBdf; use seccompiler::{apply_filter, SeccompAction}; @@ -35,13 +35,12 @@ use signal_hook::iterator::{Handle, Signals}; use std::collections::HashMap; use std::fs::File; use std::io; -use std::io::{Read, Write}; +use std::io::{stdout, Read, Write}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::os::unix::net::UnixListener; use std::os::unix::net::UnixStream; use std::panic::AssertUnwindSafe; use std::path::PathBuf; -use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::mpsc::{Receiver, RecvError, SendError, Sender}; use std::sync::{Arc, Mutex}; use std::time::Instant; @@ -54,7 +53,6 @@ use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable, Transport use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::signal::unblock_signal; use vmm_sys_util::sock_ctrl_msg::ScmSocket; -use vmm_sys_util::terminal::Terminal; mod acpi; pub mod api; @@ -408,13 +406,17 @@ pub struct Vmm { activate_evt: EventFd, signals: Option, threads: Vec>, - on_tty: Arc, + original_termios_opt: Arc>>, } impl Vmm { pub const HANDLED_SIGNALS: [i32; 2] = [SIGTERM, SIGINT]; - fn signal_handler(mut signals: Signals, on_tty: Arc, exit_evt: &EventFd) { + fn signal_handler( + mut signals: Signals, + original_termios_opt: Arc>>, + exit_evt: &EventFd, + ) { for sig in &Self::HANDLED_SIGNALS { unblock_signal(*sig).unwrap(); } @@ -424,12 +426,17 @@ impl Vmm { SIGTERM | SIGINT => { if exit_evt.write(1).is_err() { // Resetting the terminal is usually done as the VMM exits - if on_tty.load(Ordering::SeqCst) { - io::stdin() - .lock() - .set_canon_mode() - .expect("failed to restore terminal mode"); + if let Ok(lock) = original_termios_opt.lock() { + if let Some(termios) = *lock { + // SAFETY: FFI call + let _ = unsafe { + tcsetattr(stdout().lock().as_raw_fd(), TCSANOW, &termios) + }; + } + } else { + warn!("Failed to lock original termios"); } + std::process::exit(1); } } @@ -444,7 +451,7 @@ impl Vmm { Ok(signals) => { self.signals = Some(signals.handle()); let exit_evt = self.exit_evt.try_clone().map_err(Error::EventFdClone)?; - let on_tty = Arc::clone(&self.on_tty); + let original_termios_opt = Arc::clone(&self.original_termios_opt); let signal_handler_seccomp_filter = get_seccomp_filter( &self.seccomp_action, @@ -466,7 +473,7 @@ impl Vmm { } } std::panic::catch_unwind(AssertUnwindSafe(|| { - Vmm::signal_handler(signals, on_tty, &exit_evt); + Vmm::signal_handler(signals, original_termios_opt, &exit_evt); })) .map_err(|_| { error!("vmm signal_handler thread panicked"); @@ -533,7 +540,7 @@ impl Vmm { activate_evt, signals: None, threads: vec![], - on_tty: Arc::new(AtomicBool::new(false)), + original_termios_opt: Arc::new(Mutex::new(None)), }) } @@ -584,7 +591,7 @@ impl Vmm { None, None, None, - Arc::clone(&self.on_tty), + Arc::clone(&self.original_termios_opt), None, None, None, @@ -683,7 +690,7 @@ impl Vmm { None, None, None, - Arc::clone(&self.on_tty), + Arc::clone(&self.original_termios_opt), Some(snapshot), Some(source_url), Some(restore_cfg.prefault), @@ -764,7 +771,7 @@ impl Vmm { serial_pty, console_pty, console_resize_pipe, - Arc::clone(&self.on_tty), + Arc::clone(&self.original_termios_opt), None, None, None, @@ -1267,7 +1274,7 @@ impl Vmm { None, None, None, - Arc::clone(&self.on_tty), + Arc::clone(&self.original_termios_opt), Some(snapshot), ) .map_err(|e| { diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index 767c0a8df..dfb51ef2d 100644 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -55,7 +55,7 @@ use gdbstub_arch::aarch64::reg::AArch64CoreRegs as CoreRegs; #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))] use gdbstub_arch::x86::reg::X86_64CoreRegs as CoreRegs; use hypervisor::{HypervisorVmError, VmOps}; -use libc::SIGWINCH; +use libc::{termios, SIGWINCH}; use linux_loader::cmdline::Cmdline; #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))] use linux_loader::elf; @@ -79,7 +79,6 @@ use std::mem::size_of; use std::num::Wrapping; use std::ops::Deref; use std::os::unix::net::UnixStream; -use std::sync::atomic::AtomicBool; use std::sync::{Arc, Mutex, RwLock}; use std::time::Instant; use std::{result, str, thread}; @@ -464,7 +463,7 @@ impl Vm { serial_pty: Option, console_pty: Option, console_resize_pipe: Option, - on_tty: Arc, + original_termios: Arc>>, snapshot: Option, ) -> Result { trace_scoped!("Vm::new_from_memory_manager"); @@ -586,7 +585,12 @@ impl Vm { device_manager .lock() .unwrap() - .create_devices(serial_pty, console_pty, console_resize_pipe, on_tty) + .create_devices( + serial_pty, + console_pty, + console_resize_pipe, + original_termios, + ) .map_err(Error::DeviceManager)?; #[cfg(feature = "tdx")] @@ -736,7 +740,7 @@ impl Vm { serial_pty: Option, console_pty: Option, console_resize_pipe: Option, - on_tty: Arc, + original_termios: Arc>>, snapshot: Option, source_url: Option<&str>, prefault: Option, @@ -806,7 +810,7 @@ impl Vm { serial_pty, console_pty, console_resize_pipe, - on_tty, + original_termios, snapshot, ) }