mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm: reset to the original termios
Previously, we used two different functions for configuring ttys.
vmm_sys_util::terminal::Terminal::set_raw_mode() was used to configure
stdio ttys, and cfmakeraw() was used to configure ptys created by
cloud-hypervisor. When I centralized the stdio tty cleanup, I also
switched to using cfmakeraw() everywhere, to avoid duplication.
cfmakeraw sets the OPOST flag, but when we later reset the ttys, we
used vmm_sys_util::terminal::Terminal::set_canon_mode(), which does
not unset this flag. This meant that the terminal was getting mostly,
but not fully, reset.
To fix this without depending on the implementation of cfmakeraw(),
let's just store the original termios for stdio terminals, and restore
them to exactly the state we found them in when cloud-hypervisor exits.
Fixes: b6feae0a ("vmm: only touch the tty flags if it's being used")
Signed-off-by: Alyssa Ross <hi@alyssa.is>
This commit is contained in:
committed by
Rob Bradford
parent
dc7931f592
commit
c90a0ffff6
+25
-18
@@ -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;
|
||||
@@ -422,13 +420,17 @@ pub struct Vmm {
|
||||
activate_evt: EventFd,
|
||||
signals: Option<Handle>,
|
||||
threads: Vec<thread::JoinHandle<()>>,
|
||||
on_tty: Arc<AtomicBool>,
|
||||
original_termios_opt: Arc<Mutex<Option<termios>>>,
|
||||
}
|
||||
|
||||
impl Vmm {
|
||||
pub const HANDLED_SIGNALS: [i32; 2] = [SIGTERM, SIGINT];
|
||||
|
||||
fn signal_handler(mut signals: Signals, on_tty: Arc<AtomicBool>, exit_evt: &EventFd) {
|
||||
fn signal_handler(
|
||||
mut signals: Signals,
|
||||
original_termios_opt: Arc<Mutex<Option<termios>>>,
|
||||
exit_evt: &EventFd,
|
||||
) {
|
||||
for sig in &Self::HANDLED_SIGNALS {
|
||||
unblock_signal(*sig).unwrap();
|
||||
}
|
||||
@@ -438,12 +440,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);
|
||||
}
|
||||
}
|
||||
@@ -458,7 +465,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,
|
||||
@@ -480,7 +487,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");
|
||||
@@ -547,7 +554,7 @@ impl Vmm {
|
||||
activate_evt,
|
||||
signals: None,
|
||||
threads: vec![],
|
||||
on_tty: Arc::new(AtomicBool::new(false)),
|
||||
original_termios_opt: Arc::new(Mutex::new(None)),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -598,7 +605,7 @@ impl Vmm {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Arc::clone(&self.on_tty),
|
||||
Arc::clone(&self.original_termios_opt),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
@@ -697,7 +704,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),
|
||||
@@ -778,7 +785,7 @@ impl Vmm {
|
||||
serial_pty,
|
||||
console_pty,
|
||||
console_resize_pipe,
|
||||
Arc::clone(&self.on_tty),
|
||||
Arc::clone(&self.original_termios_opt),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
@@ -1288,7 +1295,7 @@ impl Vmm {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Arc::clone(&self.on_tty),
|
||||
Arc::clone(&self.original_termios_opt),
|
||||
Some(snapshot),
|
||||
)
|
||||
.map_err(|e| {
|
||||
|
||||
Reference in New Issue
Block a user