Upstream windows serial device

Bug: b:213149155
Test: cargo test and presubmit
Upstream-Crate: devices
Change-Id: I1420fee814271dae9502878963872449dae8218e
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3527444
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Vikram Auradkar <auradkar@google.com>
This commit is contained in:
Vikram Auradkar 2022-03-16 02:33:27 +00:00 committed by Chromeos LUCI
parent 626f014a48
commit 3a29174a7b
13 changed files with 398 additions and 203 deletions

View file

@ -42,6 +42,7 @@ pub fn set_default_serial_parameters(
console: true,
earlycon: false,
stdin: true,
out_timestamp: false,
});
}
@ -59,6 +60,7 @@ pub fn set_default_serial_parameters(
console: false,
earlycon: false,
stdin: false,
out_timestamp: false,
});
}
}
@ -230,6 +232,7 @@ mod tests {
console: true,
earlycon: false,
stdin: true,
out_timestamp: false,
},
);
@ -258,6 +261,7 @@ mod tests {
console: true,
earlycon: false,
stdin: true,
out_timestamp: false,
},
);
@ -273,6 +277,7 @@ mod tests {
console: false,
earlycon: true,
stdin: false,
out_timestamp: false,
},
);
@ -302,6 +307,7 @@ mod tests {
console: false,
earlycon: true,
stdin: true,
out_timestamp: false,
},
);

View file

@ -28,6 +28,7 @@ audio_streams = "*"
balloon_control = { path = "../common/balloon_control" }
base = { path = "../base" }
bit_field = { path = "../bit_field" }
cfg-if = "1.0.0"
cros_async = { path = "../cros_async" }
data_model = { path = "../common/data_model" }
dbus = { version = "0.9", optional = true }

View file

@ -25,6 +25,7 @@ pub mod acpi;
pub mod bat;
mod serial;
pub mod serial_device;
mod sys;
#[cfg(feature = "usb")]
pub mod usb;
#[cfg(feature = "usb")]

View file

@ -9,7 +9,7 @@ use std::sync::mpsc::{channel, Receiver, TryRecvError};
use std::sync::Arc;
use std::thread::{self};
use base::{error, Event, RawDescriptor, Result};
use base::{error, Event, FileSync, RawDescriptor, Result};
use hypervisor::ProtectionType;
use crate::bus::BusAccessInfo;
@ -89,6 +89,8 @@ impl SerialDevice for Serial {
interrupt_evt: Event,
input: Option<Box<dyn io::Read + Send>>,
out: Option<Box<dyn io::Write + Send>>,
_sync: Option<Box<dyn FileSync + Send>>,
_out_timestamp: bool,
_keep_rds: Vec<RawDescriptor>,
) -> Serial {
Serial {
@ -424,6 +426,8 @@ mod tests {
intr_evt,
None,
Some(Box::new(serial_out.clone())),
None,
false,
Vec::new(),
);
@ -443,6 +447,8 @@ mod tests {
intr_evt.try_clone().unwrap(),
None,
Some(Box::new(serial_out)),
None,
false,
Vec::new(),
);

View file

@ -2,24 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::borrow::Cow;
use std::fmt::{self, Display};
use std::fs::{File, OpenOptions};
use std::io::{self, stdin, stdout, ErrorKind};
use std::os::unix::net::UnixDatagram;
use std::path::{Path, PathBuf};
use std::thread;
use std::time::Duration;
use std::io::{self, stdin, stdout};
use std::path::PathBuf;
use base::{
error, info, read_raw_stdin, safe_descriptor_from_path, syslog, AsRawDescriptor, Event,
RawDescriptor,
};
use base::{error, syslog, AsRawDescriptor, Event, FileSync, RawDescriptor};
use hypervisor::ProtectionType;
use remain::sorted;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use thiserror::Error as ThisError;
pub use crate::sys::serial_device::SerialDevice;
use crate::sys::serial_device::*;
#[sorted]
#[derive(ThisError, Debug)]
pub enum Error {
@ -37,32 +33,23 @@ pub enum Error {
PathRequired,
#[error("Failed to create unbound socket")]
SocketCreateFailed,
#[error("Unable to open system type serial: {0}")]
SystemTypeError(std::io::Error),
#[error("Serial device type {0} not implemented")]
Unimplemented(SerialType),
}
/// Abstraction over serial-like devices that can be created given an event and optional input and
/// output streams.
pub trait SerialDevice {
fn new(
protected_vm: ProtectionType,
interrupt_evt: Event,
input: Option<Box<dyn io::Read + Send>>,
output: Option<Box<dyn io::Write + Send>>,
keep_rds: Vec<RawDescriptor>,
) -> Self;
}
/// Enum for possible type of serial devices
#[derive(Clone, Debug, PartialEq, Deserialize)]
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum SerialType {
File,
Stdout,
Sink,
Syslog,
#[serde(rename = "unix")]
UnixSocket,
#[cfg_attr(unix, serde(rename = "unix"))]
#[cfg_attr(windows, serde(rename = "namedpipe"))]
SystemSerialType,
}
impl Default for SerialType {
@ -78,7 +65,7 @@ impl Display for SerialType {
SerialType::Stdout => "Stdout".to_string(),
SerialType::Sink => "Sink".to_string(),
SerialType::Syslog => "Syslog".to_string(),
SerialType::UnixSocket => "UnixSocket".to_string(),
SerialType::SystemSerialType => SYSTEM_SERIAL_TYPE_NAME.to_string(),
};
write!(f, "{}", s)
@ -86,7 +73,7 @@ impl Display for SerialType {
}
/// Serial device hardware types
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Deserialize)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum SerialHardware {
Serial, // Standard PC-style (8250/16550 compatible) UART
@ -110,73 +97,6 @@ impl Display for SerialHardware {
}
}
struct WriteSocket {
sock: UnixDatagram,
buf: String,
}
const BUF_CAPACITY: usize = 1024;
impl WriteSocket {
pub fn new(s: UnixDatagram) -> WriteSocket {
WriteSocket {
sock: s,
buf: String::with_capacity(BUF_CAPACITY),
}
}
pub fn send_buf(&self, buf: &[u8]) -> io::Result<usize> {
const SEND_RETRY: usize = 2;
let mut sent = 0;
for _ in 0..SEND_RETRY {
match self.sock.send(buf) {
Ok(bytes_sent) => {
sent = bytes_sent;
break;
}
Err(e) => info!("Send error: {:?}", e),
}
}
Ok(sent)
}
}
impl io::Write for WriteSocket {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let parsed_str = String::from_utf8_lossy(buf);
let last_newline_idx = match parsed_str.rfind('\n') {
Some(newline_idx) => Some(self.buf.len() + newline_idx),
None => None,
};
self.buf.push_str(&parsed_str);
match last_newline_idx {
Some(last_newline_idx) => {
for line in (self.buf[..last_newline_idx]).lines() {
if self.send_buf(line.as_bytes()).is_err() {
break;
}
}
self.buf.drain(..=last_newline_idx);
}
None => {
if self.buf.len() >= BUF_CAPACITY {
if let Err(e) = self.send_buf(self.buf.as_bytes()) {
info!("Couldn't send full buffer. {:?}", e);
}
self.buf.clear();
}
}
}
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
fn serial_parameters_default_num() -> u8 {
1
}
@ -194,20 +114,16 @@ pub struct SerialParameters {
pub console: bool,
pub earlycon: bool,
pub stdin: bool,
pub out_timestamp: bool,
}
// The maximum length of a path that can be used as the address of a
// unix socket. Note that this includes the null-terminator.
const MAX_SOCKET_PATH_LENGTH: usize = 108;
impl SerialParameters {
/// Helper function to create a serial device from the defined parameters.
///
/// # Arguments
/// * `evt` - event used for interrupt events
/// * `keep_rds` - Vector of descriptors required by this device if it were sandboxed
/// in a child process. `evt` will always be added to this vector by
/// this function.
/// * `keep_rds` - Vector of FDs required by this device if it were sandboxed in a child
/// process. `evt` will always be added to this vector by this function.
pub fn create_serial_device<T: SerialDevice>(
&self,
protected_vm: ProtectionType,
@ -218,130 +134,74 @@ impl SerialParameters {
keep_rds.push(evt.as_raw_descriptor());
let input: Option<Box<dyn io::Read + Send>> = if let Some(input_path) = &self.input {
let input_path = input_path.as_path();
let input_file = if let Some(fd) =
safe_descriptor_from_path(input_path).map_err(|e| Error::FileError(e.into()))?
{
fd.into()
let input_file = if let Some(file) = file_from_path(input_path)? {
file
} else {
File::open(input_path).map_err(Error::FileError)?
};
keep_rds.push(input_file.as_raw_descriptor());
Some(Box::new(input_file))
} else if self.stdin {
keep_rds.push(stdin().as_raw_descriptor());
// This wrapper is used in place of the libstd native version because we don't want
// buffering for stdin.
struct StdinWrapper;
impl io::Read for StdinWrapper {
fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
read_raw_stdin(out).map_err(|e| e.into())
}
}
Some(Box::new(StdinWrapper))
Some(Box::new(ConsoleInput))
} else {
None
};
let output: Option<Box<dyn io::Write + Send>> = match self.type_ {
let (output, sync): (
Option<Box<dyn io::Write + Send>>,
Option<Box<dyn FileSync + Send>>,
) = match self.type_ {
SerialType::Stdout => {
keep_rds.push(stdout().as_raw_descriptor());
Some(Box::new(stdout()))
(Some(Box::new(stdout())), None)
}
SerialType::Sink => None,
SerialType::Sink => (None, None),
SerialType::Syslog => {
syslog::push_descriptors(keep_rds);
Some(Box::new(syslog::Syslogger::new(
syslog::Priority::Info,
syslog::Facility::Daemon,
)))
(
Some(Box::new(syslog::Syslogger::new(
syslog::Priority::Info,
syslog::Facility::Daemon,
))),
None,
)
}
SerialType::File => match &self.path {
Some(path) => {
let path = path.as_path();
let file = if let Some(fd) =
safe_descriptor_from_path(path).map_err(|e| Error::FileError(e.into()))?
{
fd.into()
let file = if let Some(file) = file_from_path(path.as_path())? {
file
} else {
OpenOptions::new()
.append(true)
.create(true)
.open(path)
.open(path.as_path())
.map_err(Error::FileError)?
};
let sync = file.try_clone().map_err(Error::FileError)?;
keep_rds.push(file.as_raw_descriptor());
Some(Box::new(file))
keep_rds.push(sync.as_raw_descriptor());
(Some(Box::new(file)), Some(Box::new(sync)))
}
None => return Err(Error::PathRequired),
},
SerialType::UnixSocket => {
match &self.path {
Some(path) => {
// If the path is longer than 107 characters,
// then we won't be able to connect directly
// to it. Instead we can shorten the path by
// opening the containing directory and using
// /proc/self/fd/*/ to access it via a shorter
// path.
let mut path_cow = Cow::<Path>::Borrowed(path);
let mut _dir_fd = None;
if path.as_os_str().len() >= MAX_SOCKET_PATH_LENGTH {
let mut short_path = PathBuf::with_capacity(MAX_SOCKET_PATH_LENGTH);
short_path.push("/proc/self/fd/");
// We don't actually want to open this
// directory for reading, but the stdlib
// requires all files be opened as at
// least one of readable, writeable, or
// appeandable.
let dir = OpenOptions::new()
.read(true)
.open(path.parent().ok_or(Error::InvalidPath)?)
.map_err(Error::FileError)?;
short_path.push(dir.as_raw_descriptor().to_string());
short_path.push(path.file_name().ok_or(Error::InvalidPath)?);
path_cow = Cow::Owned(short_path);
_dir_fd = Some(dir);
}
// The shortened path may still be too long,
// in which case we must give up here.
if path_cow.as_os_str().len() >= MAX_SOCKET_PATH_LENGTH {
return Err(Error::InvalidPath);
}
// There's a race condition between
// vmlog_forwarder making the logging socket and
// crosvm starting up, so we loop here until it's
// available.
let sock = UnixDatagram::unbound().map_err(Error::FileError)?;
loop {
match sock.connect(&path_cow) {
Ok(_) => break,
Err(e) => {
match e.kind() {
ErrorKind::NotFound | ErrorKind::ConnectionRefused => {
// logging socket doesn't
// exist yet, sleep for 10 ms
// and try again.
thread::sleep(Duration::from_millis(10))
}
_ => {
error!("Unexpected error connecting to logging socket: {:?}", e);
return Err(Error::FileError(e));
}
}
}
};
}
keep_rds.push(sock.as_raw_descriptor());
Some(Box::new(WriteSocket::new(sock)))
}
None => return Err(Error::PathRequired),
}
SerialType::SystemSerialType => {
return create_system_type_serial_device(self, protected_vm, evt, input, keep_rds);
}
};
Ok(T::new(protected_vm, evt, input, output, keep_rds.to_vec()))
Ok(T::new(
protected_vm,
evt,
input,
output,
sync,
self.out_timestamp,
keep_rds.to_vec(),
))
}
}
@ -369,6 +229,7 @@ mod tests {
console: false,
earlycon: false,
stdin: false,
out_timestamp: false,
}
);
@ -381,8 +242,12 @@ mod tests {
assert_eq!(params.type_, SerialType::Sink);
let params = from_serial_arg("type=syslog").unwrap();
assert_eq!(params.type_, SerialType::Syslog);
let params = from_serial_arg("type=unix").unwrap();
assert_eq!(params.type_, SerialType::UnixSocket);
#[cfg(unix)]
let opt = "type=unix";
#[cfg(window)]
let opt = "type=namedpipe";
let params = from_serial_arg(opt).unwrap();
assert_eq!(params.type_, SerialType::SystemSerialType);
let params = from_serial_arg("type=foobar");
assert!(params.is_err());
@ -437,7 +302,7 @@ mod tests {
assert!(params.is_err());
// all together
let params = from_serial_arg("type=stdout,path=/some/path,hardware=virtio-console,num=5,earlycon,console,stdin,input=/some/input").unwrap();
let params = from_serial_arg("type=stdout,path=/some/path,hardware=virtio-console,num=5,earlycon,console,stdin,input=/some/input,out_timestamp").unwrap();
assert_eq!(
params,
SerialParameters {
@ -449,6 +314,7 @@ mod tests {
console: true,
earlycon: true,
stdin: true,
out_timestamp: true,
}
);

13
devices/src/sys.rs Normal file
View file

@ -0,0 +1,13 @@
// Copyright 2022 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
cfg_if::cfg_if! {
if #[cfg(unix)] {
mod unix;
pub(crate) use unix::*;
} else if #[cfg(windows)] {
mod windows;
pub(crate) use windows::*;
}
}

5
devices/src/sys/unix.rs Normal file
View file

@ -0,0 +1,5 @@
// Copyright 2022 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
pub(crate) mod serial_device;

View file

@ -0,0 +1,202 @@
// Copyright 2022 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::serial_device::{Error, SerialParameters};
use base::{error, AsRawDescriptor, Event, FileSync, RawDescriptor};
use base::{info, read_raw_stdin, safe_descriptor_from_path};
use hypervisor::ProtectionType;
use std::borrow::Cow;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::{ErrorKind, Write};
use std::os::unix::net::UnixDatagram;
use std::path::{Path, PathBuf};
use std::thread;
use std::time::Duration;
pub const SYSTEM_SERIAL_TYPE_NAME: &str = "UnixSocket";
// This wrapper is used in place of the libstd native version because we don't want
// buffering for stdin.
pub struct ConsoleInput;
impl io::Read for ConsoleInput {
fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
read_raw_stdin(out).map_err(|e| e.into())
}
}
/// Abstraction over serial-like devices that can be created given an event and optional input and
/// output streams.
pub trait SerialDevice {
fn new(
protected_vm: ProtectionType,
interrupt_evt: Event,
input: Option<Box<dyn io::Read + Send>>,
output: Option<Box<dyn io::Write + Send>>,
sync: Option<Box<dyn FileSync + Send>>,
out_timestamp: bool,
keep_rds: Vec<RawDescriptor>,
) -> Self;
}
// The maximum length of a path that can be used as the address of a
// unix socket. Note that this includes the null-terminator.
pub const MAX_SOCKET_PATH_LENGTH: usize = 108;
struct WriteSocket {
sock: UnixDatagram,
buf: String,
}
const BUF_CAPACITY: usize = 1024;
impl WriteSocket {
pub fn new(s: UnixDatagram) -> WriteSocket {
WriteSocket {
sock: s,
buf: String::with_capacity(BUF_CAPACITY),
}
}
pub fn send_buf(&self, buf: &[u8]) -> io::Result<usize> {
const SEND_RETRY: usize = 2;
let mut sent = 0;
for _ in 0..SEND_RETRY {
match self.sock.send(buf) {
Ok(bytes_sent) => {
sent = bytes_sent;
break;
}
Err(e) => info!("Send error: {:?}", e),
}
}
Ok(sent)
}
}
impl io::Write for WriteSocket {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let parsed_str = String::from_utf8_lossy(buf);
let last_newline_idx = match parsed_str.rfind('\n') {
Some(newline_idx) => Some(self.buf.len() + newline_idx),
None => None,
};
self.buf.push_str(&parsed_str);
match last_newline_idx {
Some(last_newline_idx) => {
for line in (self.buf[..last_newline_idx]).lines() {
if self.send_buf(line.as_bytes()).is_err() {
break;
}
}
self.buf.drain(..=last_newline_idx);
}
None => {
if self.buf.len() >= BUF_CAPACITY {
if let Err(e) = self.send_buf(self.buf.as_bytes()) {
info!("Couldn't send full buffer. {:?}", e);
}
self.buf.clear();
}
}
}
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
pub(crate) fn create_system_type_serial_device<T: SerialDevice>(
param: &SerialParameters,
protected_vm: ProtectionType,
evt: Event,
input: Option<Box<dyn io::Read + Send>>,
keep_rds: &mut Vec<RawDescriptor>,
) -> std::result::Result<T, Error> {
match &param.path {
Some(path) => {
// If the path is longer than 107 characters,
// then we won't be able to connect directly
// to it. Instead we can shorten the path by
// opening the containing directory and using
// /proc/self/fd/*/ to access it via a shorter
// path.
let mut path_cow = Cow::<Path>::Borrowed(path);
let mut _dir_fd = None;
if path.as_os_str().len() >= MAX_SOCKET_PATH_LENGTH {
let mut short_path = PathBuf::with_capacity(MAX_SOCKET_PATH_LENGTH);
short_path.push("/proc/self/fd/");
// We don't actually want to open this
// directory for reading, but the stdlib
// requires all files be opened as at
// least one of readable, writeable, or
// appeandable.
let dir = OpenOptions::new()
.read(true)
.open(path.parent().ok_or(Error::InvalidPath)?)
.map_err(Error::FileError)?;
short_path.push(dir.as_raw_descriptor().to_string());
short_path.push(path.file_name().ok_or(Error::InvalidPath)?);
path_cow = Cow::Owned(short_path);
_dir_fd = Some(dir);
}
// The shortened path may still be too long,
// in which case we must give up here.
if path_cow.as_os_str().len() >= MAX_SOCKET_PATH_LENGTH {
return Err(Error::InvalidPath);
}
// There's a race condition between
// vmlog_forwarder making the logging socket and
// crosvm starting up, so we loop here until it's
// available.
let sock = UnixDatagram::unbound().map_err(Error::FileError)?;
loop {
match sock.connect(&path_cow) {
Ok(_) => break,
Err(e) => {
match e.kind() {
ErrorKind::NotFound | ErrorKind::ConnectionRefused => {
// logging socket doesn't
// exist yet, sleep for 10 ms
// and try again.
thread::sleep(Duration::from_millis(10))
}
_ => {
error!("Unexpected error connecting to logging socket: {:?}", e);
return Err(Error::FileError(e));
}
}
}
};
}
keep_rds.push(sock.as_raw_descriptor());
let output: Option<Box<dyn Write + Send>> = Some(Box::new(WriteSocket::new(sock)));
return Ok(T::new(
protected_vm,
evt,
input,
output,
None,
false,
keep_rds.to_vec(),
));
}
None => return Err(Error::PathRequired),
}
}
pub(crate) fn file_from_path(path: &Path) -> Result<Option<File>, Error> {
if let Some(fd) = safe_descriptor_from_path(path).map_err(|e| Error::FileError(e.into()))? {
return Ok(Some(fd.into()));
}
Ok(None)
}

View file

@ -0,0 +1,5 @@
// Copyright 2022 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
pub(crate) mod serial_device;

View file

@ -0,0 +1,85 @@
// Copyright 2022 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::serial_device::{Error, SerialParameters};
use base::named_pipes;
use base::named_pipes::{BlockingMode, FramingMode};
use base::FileSync;
use base::{AsRawDescriptor, Event, RawDescriptor};
use hypervisor::ProtectionType;
use std::fs::File;
use std::io::{self};
use std::path::Path;
pub use base::Console as ConsoleInput;
pub const SYSTEM_SERIAL_TYPE_NAME: &str = "NamedPipe";
/// Abstraction over serial-like devices that can be created given an event and optional input and
/// output streams.
pub trait SerialDevice {
fn new(
protected_vm: ProtectionType,
interrupt_evt: Event,
input: Option<Box<dyn io::Read + Send>>,
output: Option<Box<dyn io::Write + Send>>,
sync: Option<Box<dyn FileSync + Send>>,
out_timestamp: bool,
keep_rds: Vec<RawDescriptor>,
) -> Self;
fn new_pipe(
protected_vm: ProtectionType,
interrupt_evt: Event,
pipe_in: named_pipes::PipeConnection,
pipe_out: named_pipes::PipeConnection,
keep_rds: Vec<RawDescriptor>,
) -> Self;
}
pub(crate) fn create_system_type_serial_device<T: SerialDevice>(
param: &SerialParameters,
protected_vm: ProtectionType,
evt: Event,
_input: Option<Box<dyn io::Read + Send>>,
keep_rds: &mut Vec<RawDescriptor>,
) -> std::result::Result<T, Error> {
match &param.path {
None => return Err(Error::PathRequired),
Some(path) => {
// We must create this pipe in non-blocking mode because a blocking
// read in one thread will block a write in another thread having a
// handle to the same end of the pipe, which will hang the
// emulator. This does mean that the event loop writing to the
// pipe's output will need to swallow errors caused by writing to
// the pipe when it's not ready; but in practice this does not seem
// to cause a problem.
let pipe_in = named_pipes::create_server_pipe(
path.to_str().unwrap(),
&FramingMode::Byte,
&BlockingMode::NoWait,
0, // default timeout
named_pipes::DEFAULT_BUFFER_SIZE,
false,
)
.map_err(Error::SystemTypeError)?;
let pipe_out = pipe_in.try_clone().map_err(Error::SystemTypeError)?;
keep_rds.push(pipe_in.as_raw_descriptor());
keep_rds.push(pipe_out.as_raw_descriptor());
return Ok(T::new_pipe(
protected_vm,
evt,
pipe_in,
pipe_out,
keep_rds.to_vec(),
));
}
}
}
pub(crate) fn file_from_path(_path: &Path) -> Result<Option<File>, Error> {
Ok(None)
}

View file

@ -9,7 +9,7 @@ use std::result;
use std::sync::Arc;
use std::thread;
use base::{error, Event, PollToken, RawDescriptor, WaitContext};
use base::{error, Event, FileSync, PollToken, RawDescriptor, WaitContext};
use data_model::{DataInit, Le16, Le32};
use hypervisor::ProtectionType;
use remain::sorted;
@ -376,6 +376,8 @@ impl SerialDevice for Console {
_evt: Event,
input: Option<Box<dyn io::Read + Send>>,
output: Option<Box<dyn io::Write + Send>>,
_sync: Option<Box<dyn FileSync + Send>>,
_out_timestamp: bool,
keep_rds: Vec<RawDescriptor>,
) -> Console {
Console {

View file

@ -9,7 +9,7 @@ use std::path::PathBuf;
use std::sync::Arc;
use anyhow::{anyhow, bail, Context};
use base::{error, warn, Event, RawDescriptor, Terminal};
use base::{error, warn, Event, FileSync, RawDescriptor, Terminal};
use cros_async::{EventAsync, Executor};
use data_model::DataInit;
@ -83,6 +83,8 @@ impl SerialDevice for ConsoleDevice {
_evt: Event,
input: Option<Box<dyn io::Read + Send>>,
output: Option<Box<dyn io::Write + Send>>,
_sync: Option<Box<dyn FileSync + Send>>,
_out_timestamp: bool,
_keep_rds: Vec<RawDescriptor>,
) -> ConsoleDevice {
let avail_features = 1u64 << crate::virtio::VIRTIO_F_VERSION_1
@ -308,6 +310,7 @@ pub fn run_console_device(program_name: &str, args: &[&str]) -> anyhow::Result<(
earlycon: false,
// We do not support stdin-less mode
stdin: true,
out_timestamp: false,
};
let console = match params.create_serial_device::<ConsoleDevice>(

View file

@ -1021,7 +1021,7 @@ pub fn create_iommu_device(
fn add_bind_mounts(param: &SerialParameters, jail: &mut Minijail) -> Result<(), minijail::Error> {
if let Some(path) = &param.path {
if let SerialType::UnixSocket = param.type_ {
if let SerialType::SystemSerialType = param.type_ {
if let Some(parent) = path.as_path().parent() {
if parent.exists() {
info!("Bind mounting dir {}", parent.display());