Skip to content

Commit bb8e49d

Browse files
committed
Fix behavior of krun_add_virtio_console_default
When using krun_add_virtio_console_default with file descriptors that weren't normal STDIN/STDOUT/STDERR we could get weird behavior that wasn't in line with the behavior specified in the header. This also makes sure to set the change the terminal mode actually associated with the provided file descriptors instead of changing the terminal mode associated with normal stdin/stdout/stderr. Signed-off-by: Matej Hrica <[email protected]> fixups Signed-off-by: Matej Hrica <[email protected]>
1 parent 4b7a886 commit bb8e49d

File tree

4 files changed

+51
-88
lines changed

4 files changed

+51
-88
lines changed

src/devices/src/virtio/console/device.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ use std::mem::{size_of, size_of_val};
55
use std::os::unix::io::{AsRawFd, RawFd};
66
use std::sync::Arc;
77

8-
use libc::TIOCGWINSZ;
9-
use nix::ioctl_read_bad;
108
use utils::eventfd::EventFd;
119
use vm_memory::{ByteValued, Bytes, GuestMemoryMmap};
1210

src/vmm/src/builder.rs

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ use crate::device_manager;
5252
use crate::signal_handler::register_sigint_handler;
5353
#[cfg(target_os = "linux")]
5454
use crate::signal_handler::register_sigwinch_handler;
55-
use crate::terminal::term_set_raw_mode;
55+
use crate::terminal::{term_restore_mode, term_set_raw_mode};
5656
#[cfg(feature = "blk")]
5757
use crate::vmm_config::block::BlockBuilder;
5858
#[cfg(not(any(feature = "tee", feature = "nitro")))]
@@ -1892,64 +1892,70 @@ fn attach_console_devices(
18921892
Some(c) => (c.input_fd, c.output_fd, c.err_fd),
18931893
None => (STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO),
18941894
};
1895-
let stdin_is_terminal =
1896-
isatty(unsafe { BorrowedFd::borrow_raw(input_fd) }).unwrap_or(false);
1897-
let stdout_is_terminal =
1898-
isatty(unsafe { BorrowedFd::borrow_raw(output_fd) }).unwrap_or(false);
1899-
let stderr_is_terminal = isatty(unsafe { BorrowedFd::borrow_raw(err_fd) }).unwrap_or(false);
1900-
1901-
if let Err(e) = term_set_raw_mode(!stdin_is_terminal) {
1902-
log::error!("Failed to set terminal to raw mode: {e}")
1903-
}
1895+
let input_is_terminal =
1896+
input_fd >= 0 && isatty(unsafe { BorrowedFd::borrow_raw(input_fd) }).unwrap_or(false);
1897+
let output_is_terminal =
1898+
output_fd >= 0 && isatty(unsafe { BorrowedFd::borrow_raw(output_fd) }).unwrap_or(false);
1899+
let error_is_terminal =
1900+
err_fd >= 0 && isatty(unsafe { BorrowedFd::borrow_raw(err_fd) }).unwrap_or(false);
1901+
1902+
let term_fd = if input_is_terminal {
1903+
Some(unsafe { BorrowedFd::borrow_raw(input_fd) })
1904+
} else if output_is_terminal {
1905+
Some(unsafe { BorrowedFd::borrow_raw(output_fd) })
1906+
} else if error_is_terminal {
1907+
Some(unsafe { BorrowedFd::borrow_raw(err_fd) })
1908+
} else {
1909+
None
1910+
};
19041911

1905-
let console_input = if stdin_is_terminal {
1906-
Some(port_io::stdin().unwrap())
1907-
} else if input_fd < 0 {
1908-
Some(port_io::input_empty().unwrap())
1909-
} else if input_fd != STDIN_FILENO {
1912+
let forwarding_sigint;
1913+
let console_input = if input_is_terminal && input_fd >= 0 {
1914+
forwarding_sigint = false;
19101915
Some(port_io::input_to_raw_fd_dup(input_fd).unwrap())
19111916
} else {
19121917
#[cfg(target_os = "linux")]
19131918
{
1919+
forwarding_sigint = true;
19141920
let sigint_input = port_io::PortInputSigInt::new();
19151921
let sigint_input_fd = sigint_input.sigint_evt().as_raw_fd();
19161922
register_sigint_handler(sigint_input_fd).map_err(RegisterFsSigwinch)?;
19171923
Some(Box::new(sigint_input) as _)
19181924
}
19191925
#[cfg(not(target_os = "linux"))]
1920-
Some(port_io::input_empty().unwrap())
1926+
{
1927+
forwarding_sigint = false;
1928+
Some(port_io::input_empty().unwrap())
1929+
}
19211930
};
19221931

1923-
let console_output = if stdout_is_terminal {
1924-
Some(port_io::stdout().unwrap())
1925-
} else if output_fd != STDOUT_FILENO && output_fd > 0 {
1932+
let console_output = if output_is_terminal && output_fd >= 0 {
19261933
Some(port_io::output_to_raw_fd_dup(output_fd).unwrap())
19271934
} else {
19281935
Some(port_io::output_to_log_as_err())
19291936
};
19301937

19311938
let mut ports = vec![PortDescription::console(console_input, console_output)];
19321939

1933-
let console_err = if stderr_is_terminal {
1934-
Some(port_io::stderr().unwrap())
1935-
} else if err_fd != STDERR_FILENO && err_fd > 0 {
1936-
Some(port_io::output_to_raw_fd_dup(err_fd).unwrap())
1937-
} else {
1938-
None
1939-
};
1940-
1941-
ports.push(PortDescription::console(None, console_err));
1942-
1943-
if !stdin_is_terminal && input_fd == STDIN_FILENO {
1944-
ports.push(PortDescription::input_pipe("krun-stdin", port_io::stdin().unwrap()));
1940+
if input_fd >= 0 && !input_is_terminal {
1941+
ports.push(PortDescription::input_pipe(
1942+
"krun-stdin",
1943+
port_io::input_to_raw_fd_dup(input_fd).unwrap(),
1944+
));
19451945
}
19461946

1947-
if !stdout_is_terminal && output_fd == STDOUT_FILENO {
1948-
ports.push(PortDescription::output_pipe("krun-stdout", port_io::stdout().unwrap()));
1947+
if output_fd >= 0 && !output_is_terminal {
1948+
ports.push(PortDescription::output_pipe(
1949+
"krun-stdout",
1950+
port_io::output_to_raw_fd_dup(output_fd).unwrap(),
1951+
));
19491952
};
19501953

1951-
if !stderr_is_terminal && err_fd == STDERR_FILENO {
1952-
ports.push(PortDescription::output_pipe("krun-stderr", port_io::stderr().unwrap()));
1954+
if err_fd >= 0 && !error_is_terminal {
1955+
ports.push(PortDescription::output_pipe(
1956+
"krun-stderr",
1957+
port_io::output_to_raw_fd_dup(err_fd).unwrap(),
1958+
));
19531959
}
19541960

19551961
ports

src/vmm/src/lib.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ use std::time::Duration;
4747
#[cfg(target_arch = "x86_64")]
4848
use crate::device_manager::legacy::PortIODeviceManager;
4949
use crate::device_manager::mmio::MMIODeviceManager;
50-
use crate::terminal::term_set_canonical_mode;
5150
#[cfg(target_os = "linux")]
5251
use crate::vstate::VcpuEvent;
5352
use crate::vstate::{Vcpu, VcpuHandle, VcpuResponse, Vm};
@@ -360,10 +359,6 @@ impl Vmm {
360359
pub fn stop(&mut self, exit_code: i32) {
361360
info!("Vmm is stopping.");
362361

363-
if let Err(e) = term_set_canonical_mode() {
364-
log::error!("Failed to restore terminal to canonical mode: {e}")
365-
}
366-
367362
for observer in &self.exit_observers {
368363
observer
369364
.lock()

src/vmm/src/terminal.rs

Lines changed: 10 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,16 @@
1-
use libc::{STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO};
2-
use nix::sys::termios::{tcgetattr, tcsetattr, LocalFlags, SetArg};
3-
use nix::unistd::isatty;
1+
use nix::sys::termios::{tcgetattr, tcsetattr, LocalFlags, SetArg, Termios};
42
use std::os::fd::BorrowedFd;
53

6-
pub fn term_set_raw_mode(handle_signals_by_terminal: bool) -> Result<(), nix::Error> {
7-
if let Some(fd) = get_connected_term_fd() {
8-
term_fd_set_raw_mode(fd, handle_signals_by_terminal)
9-
} else {
10-
Ok(())
11-
}
12-
}
13-
14-
pub fn term_set_canonical_mode() -> Result<(), nix::Error> {
15-
if let Some(fd) = get_connected_term_fd() {
16-
term_fd_set_canonical_mode(fd)
17-
} else {
18-
Ok(())
19-
}
20-
}
4+
#[must_use]
5+
pub struct TerminalMode(Termios);
216

22-
pub fn term_fd_set_raw_mode(
7+
// Enable raw mode for the terminal and return the old state to be restored
8+
pub fn term_set_raw_mode(
239
term: BorrowedFd,
2410
handle_signals_by_terminal: bool,
25-
) -> Result<(), nix::Error> {
11+
) -> Result<TerminalMode, nix::Error> {
2612
let mut termios = tcgetattr(term)?;
13+
let old_state = termios.clone();
2714

2815
let mut mask = LocalFlags::ECHO | LocalFlags::ICANON;
2916
if !handle_signals_by_terminal {
@@ -32,32 +19,9 @@ pub fn term_fd_set_raw_mode(
3219

3320
termios.local_flags &= !mask;
3421
tcsetattr(term, SetArg::TCSANOW, &termios)?;
35-
Ok(())
22+
Ok(TerminalMode(old_state))
3623
}
3724

38-
pub fn term_fd_set_canonical_mode(term: BorrowedFd) -> Result<(), nix::Error> {
39-
let mut termios = tcgetattr(term)?;
40-
termios.local_flags |= LocalFlags::ECHO | LocalFlags::ICANON | LocalFlags::ISIG;
41-
tcsetattr(term, SetArg::TCSANOW, &termios)?;
42-
Ok(())
43-
}
44-
45-
pub fn get_connected_term_fd() -> Option<BorrowedFd<'static>> {
46-
let (stdin, stdout, stderr) = unsafe {
47-
(
48-
BorrowedFd::borrow_raw(STDIN_FILENO),
49-
BorrowedFd::borrow_raw(STDOUT_FILENO),
50-
BorrowedFd::borrow_raw(STDERR_FILENO),
51-
)
52-
};
53-
54-
if isatty(stdin).unwrap_or(false) {
55-
Some(stdin)
56-
} else if isatty(stdout).unwrap_or(false) {
57-
Some(stdout)
58-
} else if isatty(stderr).unwrap_or(false) {
59-
Some(stderr)
60-
} else {
61-
None
62-
}
25+
pub fn term_restore_mode(term: BorrowedFd, restore: &TerminalMode) -> Result<(), nix::Error> {
26+
tcsetattr(term, SetArg::TCSANOW, &restore.0)
6327
}

0 commit comments

Comments
 (0)