1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2020 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker
5*bb4ee6a4SAndroid Build Coastguard Worker use std::fmt;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::fmt::Display;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::File;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::OpenOptions;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::io;
10*bb4ee6a4SAndroid Build Coastguard Worker use std::io::stdin;
11*bb4ee6a4SAndroid Build Coastguard Worker use std::io::stdout;
12*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(unix)]
13*bb4ee6a4SAndroid Build Coastguard Worker use std::os::unix::net::UnixStream;
14*bb4ee6a4SAndroid Build Coastguard Worker use std::path::PathBuf;
15*bb4ee6a4SAndroid Build Coastguard Worker
16*bb4ee6a4SAndroid Build Coastguard Worker use base::error;
17*bb4ee6a4SAndroid Build Coastguard Worker use base::open_file_or_duplicate;
18*bb4ee6a4SAndroid Build Coastguard Worker use base::syslog;
19*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(windows)]
20*bb4ee6a4SAndroid Build Coastguard Worker use base::windows::Console as WinConsole;
21*bb4ee6a4SAndroid Build Coastguard Worker use base::AsRawDescriptor;
22*bb4ee6a4SAndroid Build Coastguard Worker use base::Event;
23*bb4ee6a4SAndroid Build Coastguard Worker use base::FileSync;
24*bb4ee6a4SAndroid Build Coastguard Worker use base::RawDescriptor;
25*bb4ee6a4SAndroid Build Coastguard Worker use base::ReadNotifier;
26*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::ProtectionType;
27*bb4ee6a4SAndroid Build Coastguard Worker use remain::sorted;
28*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserialize;
29*bb4ee6a4SAndroid Build Coastguard Worker use serde::Serialize;
30*bb4ee6a4SAndroid Build Coastguard Worker use serde_keyvalue::FromKeyValues;
31*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error as ThisError;
32*bb4ee6a4SAndroid Build Coastguard Worker
33*bb4ee6a4SAndroid Build Coastguard Worker pub use crate::sys::serial_device::SerialDevice;
34*bb4ee6a4SAndroid Build Coastguard Worker use crate::sys::serial_device::*;
35*bb4ee6a4SAndroid Build Coastguard Worker use crate::PciAddress;
36*bb4ee6a4SAndroid Build Coastguard Worker
37*bb4ee6a4SAndroid Build Coastguard Worker #[sorted]
38*bb4ee6a4SAndroid Build Coastguard Worker #[derive(ThisError, Debug)]
39*bb4ee6a4SAndroid Build Coastguard Worker pub enum Error {
40*bb4ee6a4SAndroid Build Coastguard Worker #[error("Unable to clone an Event: {0}")]
41*bb4ee6a4SAndroid Build Coastguard Worker CloneEvent(base::Error),
42*bb4ee6a4SAndroid Build Coastguard Worker #[error("Unable to clone a Unix Stream: {0}")]
43*bb4ee6a4SAndroid Build Coastguard Worker CloneUnixStream(std::io::Error),
44*bb4ee6a4SAndroid Build Coastguard Worker #[error("Unable to clone file: {0}")]
45*bb4ee6a4SAndroid Build Coastguard Worker FileClone(std::io::Error),
46*bb4ee6a4SAndroid Build Coastguard Worker #[error("Unable to create file '{1}': {0}")]
47*bb4ee6a4SAndroid Build Coastguard Worker FileCreate(std::io::Error, PathBuf),
48*bb4ee6a4SAndroid Build Coastguard Worker #[error("Unable to open file '{1}': {0}")]
49*bb4ee6a4SAndroid Build Coastguard Worker FileOpen(std::io::Error, PathBuf),
50*bb4ee6a4SAndroid Build Coastguard Worker #[error("Invalid serial config specified: {0}")]
51*bb4ee6a4SAndroid Build Coastguard Worker InvalidConfig(String),
52*bb4ee6a4SAndroid Build Coastguard Worker #[error("Serial device path '{0} is invalid")]
53*bb4ee6a4SAndroid Build Coastguard Worker InvalidPath(PathBuf),
54*bb4ee6a4SAndroid Build Coastguard Worker #[error("Invalid serial hardware: {0}")]
55*bb4ee6a4SAndroid Build Coastguard Worker InvalidSerialHardware(String),
56*bb4ee6a4SAndroid Build Coastguard Worker #[error("Invalid serial type: {0}")]
57*bb4ee6a4SAndroid Build Coastguard Worker InvalidSerialType(String),
58*bb4ee6a4SAndroid Build Coastguard Worker #[error("Serial device type file requires a path")]
59*bb4ee6a4SAndroid Build Coastguard Worker PathRequired,
60*bb4ee6a4SAndroid Build Coastguard Worker #[error("Failed to connect to socket: {0}")]
61*bb4ee6a4SAndroid Build Coastguard Worker SocketConnect(std::io::Error),
62*bb4ee6a4SAndroid Build Coastguard Worker #[error("Failed to create unbound socket: {0}")]
63*bb4ee6a4SAndroid Build Coastguard Worker SocketCreate(std::io::Error),
64*bb4ee6a4SAndroid Build Coastguard Worker #[error("Unable to open system type serial: {0}")]
65*bb4ee6a4SAndroid Build Coastguard Worker SystemTypeError(std::io::Error),
66*bb4ee6a4SAndroid Build Coastguard Worker #[error("Serial device type {0} not implemented")]
67*bb4ee6a4SAndroid Build Coastguard Worker Unimplemented(SerialType),
68*bb4ee6a4SAndroid Build Coastguard Worker }
69*bb4ee6a4SAndroid Build Coastguard Worker
70*bb4ee6a4SAndroid Build Coastguard Worker /// Trait for types that can be used as input for a serial device.
71*bb4ee6a4SAndroid Build Coastguard Worker pub trait SerialInput: io::Read + ReadNotifier + Send {}
72*bb4ee6a4SAndroid Build Coastguard Worker impl SerialInput for File {}
73*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(unix)]
74*bb4ee6a4SAndroid Build Coastguard Worker impl SerialInput for UnixStream {}
75*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(windows)]
76*bb4ee6a4SAndroid Build Coastguard Worker impl SerialInput for WinConsole {}
77*bb4ee6a4SAndroid Build Coastguard Worker
78*bb4ee6a4SAndroid Build Coastguard Worker /// Enum for possible type of serial devices
79*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
80*bb4ee6a4SAndroid Build Coastguard Worker #[serde(rename_all = "kebab-case")]
81*bb4ee6a4SAndroid Build Coastguard Worker pub enum SerialType {
82*bb4ee6a4SAndroid Build Coastguard Worker File,
83*bb4ee6a4SAndroid Build Coastguard Worker Stdout,
84*bb4ee6a4SAndroid Build Coastguard Worker Sink,
85*bb4ee6a4SAndroid Build Coastguard Worker Syslog,
86*bb4ee6a4SAndroid Build Coastguard Worker #[cfg_attr(unix, serde(rename = "unix"))]
87*bb4ee6a4SAndroid Build Coastguard Worker #[cfg_attr(windows, serde(rename = "namedpipe"))]
88*bb4ee6a4SAndroid Build Coastguard Worker SystemSerialType,
89*bb4ee6a4SAndroid Build Coastguard Worker // Use the same Unix domain socket for input and output.
90*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(unix)]
91*bb4ee6a4SAndroid Build Coastguard Worker UnixStream,
92*bb4ee6a4SAndroid Build Coastguard Worker }
93*bb4ee6a4SAndroid Build Coastguard Worker
94*bb4ee6a4SAndroid Build Coastguard Worker impl Default for SerialType {
default() -> Self95*bb4ee6a4SAndroid Build Coastguard Worker fn default() -> Self {
96*bb4ee6a4SAndroid Build Coastguard Worker Self::Sink
97*bb4ee6a4SAndroid Build Coastguard Worker }
98*bb4ee6a4SAndroid Build Coastguard Worker }
99*bb4ee6a4SAndroid Build Coastguard Worker
100*bb4ee6a4SAndroid Build Coastguard Worker impl Display for SerialType {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result101*bb4ee6a4SAndroid Build Coastguard Worker fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
102*bb4ee6a4SAndroid Build Coastguard Worker let s = match &self {
103*bb4ee6a4SAndroid Build Coastguard Worker SerialType::File => "File".to_string(),
104*bb4ee6a4SAndroid Build Coastguard Worker SerialType::Stdout => "Stdout".to_string(),
105*bb4ee6a4SAndroid Build Coastguard Worker SerialType::Sink => "Sink".to_string(),
106*bb4ee6a4SAndroid Build Coastguard Worker SerialType::Syslog => "Syslog".to_string(),
107*bb4ee6a4SAndroid Build Coastguard Worker SerialType::SystemSerialType => SYSTEM_SERIAL_TYPE_NAME.to_string(),
108*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(unix)]
109*bb4ee6a4SAndroid Build Coastguard Worker SerialType::UnixStream => "UnixStream".to_string(),
110*bb4ee6a4SAndroid Build Coastguard Worker };
111*bb4ee6a4SAndroid Build Coastguard Worker
112*bb4ee6a4SAndroid Build Coastguard Worker write!(f, "{}", s)
113*bb4ee6a4SAndroid Build Coastguard Worker }
114*bb4ee6a4SAndroid Build Coastguard Worker }
115*bb4ee6a4SAndroid Build Coastguard Worker
116*bb4ee6a4SAndroid Build Coastguard Worker /// Serial device hardware types
117*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
118*bb4ee6a4SAndroid Build Coastguard Worker #[serde(rename_all = "kebab-case")]
119*bb4ee6a4SAndroid Build Coastguard Worker pub enum SerialHardware {
120*bb4ee6a4SAndroid Build Coastguard Worker /// Standard PC-style (8250/16550 compatible) UART
121*bb4ee6a4SAndroid Build Coastguard Worker Serial,
122*bb4ee6a4SAndroid Build Coastguard Worker
123*bb4ee6a4SAndroid Build Coastguard Worker /// virtio-console device
124*bb4ee6a4SAndroid Build Coastguard Worker #[serde(alias = "legacy-virtio-console")]
125*bb4ee6a4SAndroid Build Coastguard Worker VirtioConsole,
126*bb4ee6a4SAndroid Build Coastguard Worker
127*bb4ee6a4SAndroid Build Coastguard Worker /// Bochs style debug port
128*bb4ee6a4SAndroid Build Coastguard Worker Debugcon,
129*bb4ee6a4SAndroid Build Coastguard Worker }
130*bb4ee6a4SAndroid Build Coastguard Worker
131*bb4ee6a4SAndroid Build Coastguard Worker impl Default for SerialHardware {
default() -> Self132*bb4ee6a4SAndroid Build Coastguard Worker fn default() -> Self {
133*bb4ee6a4SAndroid Build Coastguard Worker Self::Serial
134*bb4ee6a4SAndroid Build Coastguard Worker }
135*bb4ee6a4SAndroid Build Coastguard Worker }
136*bb4ee6a4SAndroid Build Coastguard Worker
137*bb4ee6a4SAndroid Build Coastguard Worker impl Display for SerialHardware {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result138*bb4ee6a4SAndroid Build Coastguard Worker fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
139*bb4ee6a4SAndroid Build Coastguard Worker let s = match &self {
140*bb4ee6a4SAndroid Build Coastguard Worker SerialHardware::Serial => "serial".to_string(),
141*bb4ee6a4SAndroid Build Coastguard Worker SerialHardware::VirtioConsole => "virtio-console".to_string(),
142*bb4ee6a4SAndroid Build Coastguard Worker SerialHardware::Debugcon => "debugcon".to_string(),
143*bb4ee6a4SAndroid Build Coastguard Worker };
144*bb4ee6a4SAndroid Build Coastguard Worker
145*bb4ee6a4SAndroid Build Coastguard Worker write!(f, "{}", s)
146*bb4ee6a4SAndroid Build Coastguard Worker }
147*bb4ee6a4SAndroid Build Coastguard Worker }
148*bb4ee6a4SAndroid Build Coastguard Worker
serial_parameters_default_num() -> u8149*bb4ee6a4SAndroid Build Coastguard Worker fn serial_parameters_default_num() -> u8 {
150*bb4ee6a4SAndroid Build Coastguard Worker 1
151*bb4ee6a4SAndroid Build Coastguard Worker }
152*bb4ee6a4SAndroid Build Coastguard Worker
serial_parameters_default_debugcon_port() -> u16153*bb4ee6a4SAndroid Build Coastguard Worker fn serial_parameters_default_debugcon_port() -> u16 {
154*bb4ee6a4SAndroid Build Coastguard Worker // Default to the port OVMF expects.
155*bb4ee6a4SAndroid Build Coastguard Worker 0x402
156*bb4ee6a4SAndroid Build Coastguard Worker }
157*bb4ee6a4SAndroid Build Coastguard Worker
158*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, FromKeyValues)]
159*bb4ee6a4SAndroid Build Coastguard Worker #[serde(deny_unknown_fields, rename_all = "kebab-case", default)]
160*bb4ee6a4SAndroid Build Coastguard Worker pub struct SerialParameters {
161*bb4ee6a4SAndroid Build Coastguard Worker #[serde(rename = "type")]
162*bb4ee6a4SAndroid Build Coastguard Worker pub type_: SerialType,
163*bb4ee6a4SAndroid Build Coastguard Worker pub hardware: SerialHardware,
164*bb4ee6a4SAndroid Build Coastguard Worker pub name: Option<String>,
165*bb4ee6a4SAndroid Build Coastguard Worker pub path: Option<PathBuf>,
166*bb4ee6a4SAndroid Build Coastguard Worker pub input: Option<PathBuf>,
167*bb4ee6a4SAndroid Build Coastguard Worker /// Use the given `UnixStream` as input as well as output.
168*bb4ee6a4SAndroid Build Coastguard Worker /// This flag can be used only when `type_` is `UnixStream`.
169*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(unix)]
170*bb4ee6a4SAndroid Build Coastguard Worker pub input_unix_stream: bool,
171*bb4ee6a4SAndroid Build Coastguard Worker #[serde(default = "serial_parameters_default_num")]
172*bb4ee6a4SAndroid Build Coastguard Worker pub num: u8,
173*bb4ee6a4SAndroid Build Coastguard Worker pub console: bool,
174*bb4ee6a4SAndroid Build Coastguard Worker pub earlycon: bool,
175*bb4ee6a4SAndroid Build Coastguard Worker pub stdin: bool,
176*bb4ee6a4SAndroid Build Coastguard Worker #[serde(alias = "out_timestamp")]
177*bb4ee6a4SAndroid Build Coastguard Worker pub out_timestamp: bool,
178*bb4ee6a4SAndroid Build Coastguard Worker #[serde(
179*bb4ee6a4SAndroid Build Coastguard Worker alias = "debugcon_port",
180*bb4ee6a4SAndroid Build Coastguard Worker default = "serial_parameters_default_debugcon_port"
181*bb4ee6a4SAndroid Build Coastguard Worker )]
182*bb4ee6a4SAndroid Build Coastguard Worker pub debugcon_port: u16,
183*bb4ee6a4SAndroid Build Coastguard Worker pub pci_address: Option<PciAddress>,
184*bb4ee6a4SAndroid Build Coastguard Worker }
185*bb4ee6a4SAndroid Build Coastguard Worker
186*bb4ee6a4SAndroid Build Coastguard Worker /// Temporary structure containing the parameters of a serial port for easy passing to
187*bb4ee6a4SAndroid Build Coastguard Worker /// `SerialDevice::new`.
188*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Default)]
189*bb4ee6a4SAndroid Build Coastguard Worker pub struct SerialOptions {
190*bb4ee6a4SAndroid Build Coastguard Worker pub name: Option<String>,
191*bb4ee6a4SAndroid Build Coastguard Worker pub out_timestamp: bool,
192*bb4ee6a4SAndroid Build Coastguard Worker pub console: bool,
193*bb4ee6a4SAndroid Build Coastguard Worker pub pci_address: Option<PciAddress>,
194*bb4ee6a4SAndroid Build Coastguard Worker }
195*bb4ee6a4SAndroid Build Coastguard Worker
196*bb4ee6a4SAndroid Build Coastguard Worker impl SerialParameters {
197*bb4ee6a4SAndroid Build Coastguard Worker /// Helper function to create a serial device from the defined parameters.
198*bb4ee6a4SAndroid Build Coastguard Worker ///
199*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments
200*bb4ee6a4SAndroid Build Coastguard Worker /// * `evt` - event used for interrupt events
201*bb4ee6a4SAndroid Build Coastguard Worker /// * `keep_rds` - Vector of FDs required by this device if it were sandboxed in a child
202*bb4ee6a4SAndroid Build Coastguard Worker /// process. `evt` will always be added to this vector by this function.
create_serial_device<T: SerialDevice>( &self, protection_type: ProtectionType, evt: &Event, keep_rds: &mut Vec<RawDescriptor>, ) -> std::result::Result<T, Error>203*bb4ee6a4SAndroid Build Coastguard Worker pub fn create_serial_device<T: SerialDevice>(
204*bb4ee6a4SAndroid Build Coastguard Worker &self,
205*bb4ee6a4SAndroid Build Coastguard Worker protection_type: ProtectionType,
206*bb4ee6a4SAndroid Build Coastguard Worker evt: &Event,
207*bb4ee6a4SAndroid Build Coastguard Worker keep_rds: &mut Vec<RawDescriptor>,
208*bb4ee6a4SAndroid Build Coastguard Worker ) -> std::result::Result<T, Error> {
209*bb4ee6a4SAndroid Build Coastguard Worker let evt = evt.try_clone().map_err(Error::CloneEvent)?;
210*bb4ee6a4SAndroid Build Coastguard Worker keep_rds.push(evt.as_raw_descriptor());
211*bb4ee6a4SAndroid Build Coastguard Worker cros_tracing::push_descriptors!(keep_rds);
212*bb4ee6a4SAndroid Build Coastguard Worker metrics::push_descriptors(keep_rds);
213*bb4ee6a4SAndroid Build Coastguard Worker
214*bb4ee6a4SAndroid Build Coastguard Worker // When `self.input_unix_stream` is specified, use `self.path` for both output and input.
215*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(unix)]
216*bb4ee6a4SAndroid Build Coastguard Worker if self.input_unix_stream {
217*bb4ee6a4SAndroid Build Coastguard Worker if self.input.is_some() {
218*bb4ee6a4SAndroid Build Coastguard Worker return Err(Error::InvalidConfig(
219*bb4ee6a4SAndroid Build Coastguard Worker "input-unix-stream can't be passed when input is specified".to_string(),
220*bb4ee6a4SAndroid Build Coastguard Worker ));
221*bb4ee6a4SAndroid Build Coastguard Worker }
222*bb4ee6a4SAndroid Build Coastguard Worker if self.type_ != SerialType::UnixStream {
223*bb4ee6a4SAndroid Build Coastguard Worker return Err(Error::InvalidConfig(
224*bb4ee6a4SAndroid Build Coastguard Worker "input-unix-stream must be used with type=unix-stream".to_string(),
225*bb4ee6a4SAndroid Build Coastguard Worker ));
226*bb4ee6a4SAndroid Build Coastguard Worker }
227*bb4ee6a4SAndroid Build Coastguard Worker
228*bb4ee6a4SAndroid Build Coastguard Worker return create_unix_stream_serial_device(self, protection_type, evt, keep_rds);
229*bb4ee6a4SAndroid Build Coastguard Worker }
230*bb4ee6a4SAndroid Build Coastguard Worker
231*bb4ee6a4SAndroid Build Coastguard Worker let input: Option<Box<dyn SerialInput>> = if let Some(input_path) = &self.input {
232*bb4ee6a4SAndroid Build Coastguard Worker let input_path = input_path.as_path();
233*bb4ee6a4SAndroid Build Coastguard Worker
234*bb4ee6a4SAndroid Build Coastguard Worker let input_file = open_file_or_duplicate(input_path, OpenOptions::new().read(true))
235*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|e| Error::FileOpen(e.into(), input_path.into()))?;
236*bb4ee6a4SAndroid Build Coastguard Worker
237*bb4ee6a4SAndroid Build Coastguard Worker keep_rds.push(input_file.as_raw_descriptor());
238*bb4ee6a4SAndroid Build Coastguard Worker Some(Box::new(input_file))
239*bb4ee6a4SAndroid Build Coastguard Worker } else if self.stdin {
240*bb4ee6a4SAndroid Build Coastguard Worker keep_rds.push(stdin().as_raw_descriptor());
241*bb4ee6a4SAndroid Build Coastguard Worker Some(Box::new(ConsoleInput::new()))
242*bb4ee6a4SAndroid Build Coastguard Worker } else {
243*bb4ee6a4SAndroid Build Coastguard Worker None
244*bb4ee6a4SAndroid Build Coastguard Worker };
245*bb4ee6a4SAndroid Build Coastguard Worker let (output, sync): (
246*bb4ee6a4SAndroid Build Coastguard Worker Option<Box<dyn io::Write + Send>>,
247*bb4ee6a4SAndroid Build Coastguard Worker Option<Box<dyn FileSync + Send>>,
248*bb4ee6a4SAndroid Build Coastguard Worker ) = match self.type_ {
249*bb4ee6a4SAndroid Build Coastguard Worker SerialType::Stdout => {
250*bb4ee6a4SAndroid Build Coastguard Worker keep_rds.push(stdout().as_raw_descriptor());
251*bb4ee6a4SAndroid Build Coastguard Worker (Some(Box::new(stdout())), None)
252*bb4ee6a4SAndroid Build Coastguard Worker }
253*bb4ee6a4SAndroid Build Coastguard Worker SerialType::Sink => (None, None),
254*bb4ee6a4SAndroid Build Coastguard Worker SerialType::Syslog => {
255*bb4ee6a4SAndroid Build Coastguard Worker syslog::push_descriptors(keep_rds);
256*bb4ee6a4SAndroid Build Coastguard Worker (
257*bb4ee6a4SAndroid Build Coastguard Worker Some(Box::new(syslog::Syslogger::new(base::syslog::Level::Info))),
258*bb4ee6a4SAndroid Build Coastguard Worker None,
259*bb4ee6a4SAndroid Build Coastguard Worker )
260*bb4ee6a4SAndroid Build Coastguard Worker }
261*bb4ee6a4SAndroid Build Coastguard Worker SerialType::File => match &self.path {
262*bb4ee6a4SAndroid Build Coastguard Worker Some(path) => {
263*bb4ee6a4SAndroid Build Coastguard Worker let file =
264*bb4ee6a4SAndroid Build Coastguard Worker open_file_or_duplicate(path, OpenOptions::new().append(true).create(true))
265*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|e| Error::FileCreate(e.into(), path.clone()))?;
266*bb4ee6a4SAndroid Build Coastguard Worker let sync = file.try_clone().map_err(Error::FileClone)?;
267*bb4ee6a4SAndroid Build Coastguard Worker
268*bb4ee6a4SAndroid Build Coastguard Worker keep_rds.push(file.as_raw_descriptor());
269*bb4ee6a4SAndroid Build Coastguard Worker keep_rds.push(sync.as_raw_descriptor());
270*bb4ee6a4SAndroid Build Coastguard Worker
271*bb4ee6a4SAndroid Build Coastguard Worker (Some(Box::new(file)), Some(Box::new(sync)))
272*bb4ee6a4SAndroid Build Coastguard Worker }
273*bb4ee6a4SAndroid Build Coastguard Worker None => return Err(Error::PathRequired),
274*bb4ee6a4SAndroid Build Coastguard Worker },
275*bb4ee6a4SAndroid Build Coastguard Worker SerialType::SystemSerialType => {
276*bb4ee6a4SAndroid Build Coastguard Worker return create_system_type_serial_device(
277*bb4ee6a4SAndroid Build Coastguard Worker self,
278*bb4ee6a4SAndroid Build Coastguard Worker protection_type,
279*bb4ee6a4SAndroid Build Coastguard Worker evt,
280*bb4ee6a4SAndroid Build Coastguard Worker input,
281*bb4ee6a4SAndroid Build Coastguard Worker keep_rds,
282*bb4ee6a4SAndroid Build Coastguard Worker );
283*bb4ee6a4SAndroid Build Coastguard Worker }
284*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(unix)]
285*bb4ee6a4SAndroid Build Coastguard Worker SerialType::UnixStream => {
286*bb4ee6a4SAndroid Build Coastguard Worker let path = self.path.as_ref().ok_or(Error::PathRequired)?;
287*bb4ee6a4SAndroid Build Coastguard Worker let output = UnixStream::connect(path).map_err(Error::SocketConnect)?;
288*bb4ee6a4SAndroid Build Coastguard Worker keep_rds.push(output.as_raw_descriptor());
289*bb4ee6a4SAndroid Build Coastguard Worker (Some(Box::new(output)), None)
290*bb4ee6a4SAndroid Build Coastguard Worker }
291*bb4ee6a4SAndroid Build Coastguard Worker };
292*bb4ee6a4SAndroid Build Coastguard Worker Ok(T::new(
293*bb4ee6a4SAndroid Build Coastguard Worker protection_type,
294*bb4ee6a4SAndroid Build Coastguard Worker evt,
295*bb4ee6a4SAndroid Build Coastguard Worker input,
296*bb4ee6a4SAndroid Build Coastguard Worker output,
297*bb4ee6a4SAndroid Build Coastguard Worker sync,
298*bb4ee6a4SAndroid Build Coastguard Worker SerialOptions {
299*bb4ee6a4SAndroid Build Coastguard Worker name: self.name.clone(),
300*bb4ee6a4SAndroid Build Coastguard Worker out_timestamp: self.out_timestamp,
301*bb4ee6a4SAndroid Build Coastguard Worker console: self.console,
302*bb4ee6a4SAndroid Build Coastguard Worker pci_address: self.pci_address,
303*bb4ee6a4SAndroid Build Coastguard Worker },
304*bb4ee6a4SAndroid Build Coastguard Worker keep_rds.to_vec(),
305*bb4ee6a4SAndroid Build Coastguard Worker ))
306*bb4ee6a4SAndroid Build Coastguard Worker }
307*bb4ee6a4SAndroid Build Coastguard Worker }
308*bb4ee6a4SAndroid Build Coastguard Worker
309*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
310*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
311*bb4ee6a4SAndroid Build Coastguard Worker use serde_keyvalue::*;
312*bb4ee6a4SAndroid Build Coastguard Worker
313*bb4ee6a4SAndroid Build Coastguard Worker use super::*;
314*bb4ee6a4SAndroid Build Coastguard Worker
from_serial_arg(options: &str) -> Result<SerialParameters, ParseError>315*bb4ee6a4SAndroid Build Coastguard Worker fn from_serial_arg(options: &str) -> Result<SerialParameters, ParseError> {
316*bb4ee6a4SAndroid Build Coastguard Worker from_key_values(options)
317*bb4ee6a4SAndroid Build Coastguard Worker }
318*bb4ee6a4SAndroid Build Coastguard Worker
319*bb4ee6a4SAndroid Build Coastguard Worker #[test]
params_from_key_values()320*bb4ee6a4SAndroid Build Coastguard Worker fn params_from_key_values() {
321*bb4ee6a4SAndroid Build Coastguard Worker // Defaults
322*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("").unwrap();
323*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
324*bb4ee6a4SAndroid Build Coastguard Worker params,
325*bb4ee6a4SAndroid Build Coastguard Worker SerialParameters {
326*bb4ee6a4SAndroid Build Coastguard Worker type_: SerialType::Sink,
327*bb4ee6a4SAndroid Build Coastguard Worker hardware: SerialHardware::Serial,
328*bb4ee6a4SAndroid Build Coastguard Worker name: None,
329*bb4ee6a4SAndroid Build Coastguard Worker path: None,
330*bb4ee6a4SAndroid Build Coastguard Worker input: None,
331*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(unix)]
332*bb4ee6a4SAndroid Build Coastguard Worker input_unix_stream: false,
333*bb4ee6a4SAndroid Build Coastguard Worker num: 1,
334*bb4ee6a4SAndroid Build Coastguard Worker console: false,
335*bb4ee6a4SAndroid Build Coastguard Worker earlycon: false,
336*bb4ee6a4SAndroid Build Coastguard Worker stdin: false,
337*bb4ee6a4SAndroid Build Coastguard Worker out_timestamp: false,
338*bb4ee6a4SAndroid Build Coastguard Worker debugcon_port: 0x402,
339*bb4ee6a4SAndroid Build Coastguard Worker pci_address: None,
340*bb4ee6a4SAndroid Build Coastguard Worker }
341*bb4ee6a4SAndroid Build Coastguard Worker );
342*bb4ee6a4SAndroid Build Coastguard Worker
343*bb4ee6a4SAndroid Build Coastguard Worker // type parameter
344*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("type=file").unwrap();
345*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(params.type_, SerialType::File);
346*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("type=stdout").unwrap();
347*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(params.type_, SerialType::Stdout);
348*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("type=sink").unwrap();
349*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(params.type_, SerialType::Sink);
350*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("type=syslog").unwrap();
351*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(params.type_, SerialType::Syslog);
352*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(target_os = "android", target_os = "linux"))]
353*bb4ee6a4SAndroid Build Coastguard Worker let opt = "type=unix";
354*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(windows)]
355*bb4ee6a4SAndroid Build Coastguard Worker let opt = "type=namedpipe";
356*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg(opt).unwrap();
357*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(params.type_, SerialType::SystemSerialType);
358*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(unix)]
359*bb4ee6a4SAndroid Build Coastguard Worker {
360*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("type=unix-stream").unwrap();
361*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(params.type_, SerialType::UnixStream);
362*bb4ee6a4SAndroid Build Coastguard Worker }
363*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("type=foobar");
364*bb4ee6a4SAndroid Build Coastguard Worker assert!(params.is_err());
365*bb4ee6a4SAndroid Build Coastguard Worker
366*bb4ee6a4SAndroid Build Coastguard Worker // hardware parameter
367*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("hardware=serial").unwrap();
368*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(params.hardware, SerialHardware::Serial);
369*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("hardware=virtio-console").unwrap();
370*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(params.hardware, SerialHardware::VirtioConsole);
371*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("hardware=debugcon").unwrap();
372*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(params.hardware, SerialHardware::Debugcon);
373*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("hardware=foobar");
374*bb4ee6a4SAndroid Build Coastguard Worker assert!(params.is_err());
375*bb4ee6a4SAndroid Build Coastguard Worker
376*bb4ee6a4SAndroid Build Coastguard Worker // path parameter
377*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("path=/test/path").unwrap();
378*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(params.path, Some("/test/path".into()));
379*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("path");
380*bb4ee6a4SAndroid Build Coastguard Worker assert!(params.is_err());
381*bb4ee6a4SAndroid Build Coastguard Worker
382*bb4ee6a4SAndroid Build Coastguard Worker // input parameter
383*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("input=/path/to/input").unwrap();
384*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(params.input, Some("/path/to/input".into()));
385*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("input");
386*bb4ee6a4SAndroid Build Coastguard Worker assert!(params.is_err());
387*bb4ee6a4SAndroid Build Coastguard Worker
388*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(unix)]
389*bb4ee6a4SAndroid Build Coastguard Worker {
390*bb4ee6a4SAndroid Build Coastguard Worker // input-unix-stream parameter
391*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("input-unix-stream").unwrap();
392*bb4ee6a4SAndroid Build Coastguard Worker assert!(params.input_unix_stream);
393*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("input-unix-stream=true").unwrap();
394*bb4ee6a4SAndroid Build Coastguard Worker assert!(params.input_unix_stream);
395*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("input-unix-stream=false").unwrap();
396*bb4ee6a4SAndroid Build Coastguard Worker assert!(!params.input_unix_stream);
397*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("input-unix-stream=foobar");
398*bb4ee6a4SAndroid Build Coastguard Worker assert!(params.is_err());
399*bb4ee6a4SAndroid Build Coastguard Worker }
400*bb4ee6a4SAndroid Build Coastguard Worker
401*bb4ee6a4SAndroid Build Coastguard Worker // console parameter
402*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("console").unwrap();
403*bb4ee6a4SAndroid Build Coastguard Worker assert!(params.console);
404*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("console=true").unwrap();
405*bb4ee6a4SAndroid Build Coastguard Worker assert!(params.console);
406*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("console=false").unwrap();
407*bb4ee6a4SAndroid Build Coastguard Worker assert!(!params.console);
408*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("console=foobar");
409*bb4ee6a4SAndroid Build Coastguard Worker assert!(params.is_err());
410*bb4ee6a4SAndroid Build Coastguard Worker
411*bb4ee6a4SAndroid Build Coastguard Worker // earlycon parameter
412*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("earlycon").unwrap();
413*bb4ee6a4SAndroid Build Coastguard Worker assert!(params.earlycon);
414*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("earlycon=true").unwrap();
415*bb4ee6a4SAndroid Build Coastguard Worker assert!(params.earlycon);
416*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("earlycon=false").unwrap();
417*bb4ee6a4SAndroid Build Coastguard Worker assert!(!params.earlycon);
418*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("earlycon=foobar");
419*bb4ee6a4SAndroid Build Coastguard Worker assert!(params.is_err());
420*bb4ee6a4SAndroid Build Coastguard Worker
421*bb4ee6a4SAndroid Build Coastguard Worker // stdin parameter
422*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("stdin").unwrap();
423*bb4ee6a4SAndroid Build Coastguard Worker assert!(params.stdin);
424*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("stdin=true").unwrap();
425*bb4ee6a4SAndroid Build Coastguard Worker assert!(params.stdin);
426*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("stdin=false").unwrap();
427*bb4ee6a4SAndroid Build Coastguard Worker assert!(!params.stdin);
428*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("stdin=foobar");
429*bb4ee6a4SAndroid Build Coastguard Worker assert!(params.is_err());
430*bb4ee6a4SAndroid Build Coastguard Worker
431*bb4ee6a4SAndroid Build Coastguard Worker // out-timestamp parameter
432*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("out-timestamp").unwrap();
433*bb4ee6a4SAndroid Build Coastguard Worker assert!(params.out_timestamp);
434*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("out-timestamp=true").unwrap();
435*bb4ee6a4SAndroid Build Coastguard Worker assert!(params.out_timestamp);
436*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("out-timestamp=false").unwrap();
437*bb4ee6a4SAndroid Build Coastguard Worker assert!(!params.out_timestamp);
438*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("out-timestamp=foobar");
439*bb4ee6a4SAndroid Build Coastguard Worker assert!(params.is_err());
440*bb4ee6a4SAndroid Build Coastguard Worker // backward compatibility
441*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("out_timestamp=true").unwrap();
442*bb4ee6a4SAndroid Build Coastguard Worker assert!(params.out_timestamp);
443*bb4ee6a4SAndroid Build Coastguard Worker
444*bb4ee6a4SAndroid Build Coastguard Worker // debugcon-port parameter
445*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("debugcon-port=1026").unwrap();
446*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(params.debugcon_port, 1026);
447*bb4ee6a4SAndroid Build Coastguard Worker // backward compatibility
448*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("debugcon_port=1026").unwrap();
449*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(params.debugcon_port, 1026);
450*bb4ee6a4SAndroid Build Coastguard Worker
451*bb4ee6a4SAndroid Build Coastguard Worker // all together
452*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("type=stdout,path=/some/path,hardware=virtio-console,num=5,earlycon,console,stdin,input=/some/input,out_timestamp,debugcon_port=12,pci-address=00:0e.0").unwrap();
453*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
454*bb4ee6a4SAndroid Build Coastguard Worker params,
455*bb4ee6a4SAndroid Build Coastguard Worker SerialParameters {
456*bb4ee6a4SAndroid Build Coastguard Worker type_: SerialType::Stdout,
457*bb4ee6a4SAndroid Build Coastguard Worker hardware: SerialHardware::VirtioConsole,
458*bb4ee6a4SAndroid Build Coastguard Worker name: None,
459*bb4ee6a4SAndroid Build Coastguard Worker path: Some("/some/path".into()),
460*bb4ee6a4SAndroid Build Coastguard Worker input: Some("/some/input".into()),
461*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(unix)]
462*bb4ee6a4SAndroid Build Coastguard Worker input_unix_stream: false,
463*bb4ee6a4SAndroid Build Coastguard Worker num: 5,
464*bb4ee6a4SAndroid Build Coastguard Worker console: true,
465*bb4ee6a4SAndroid Build Coastguard Worker earlycon: true,
466*bb4ee6a4SAndroid Build Coastguard Worker stdin: true,
467*bb4ee6a4SAndroid Build Coastguard Worker out_timestamp: true,
468*bb4ee6a4SAndroid Build Coastguard Worker debugcon_port: 12,
469*bb4ee6a4SAndroid Build Coastguard Worker pci_address: Some(PciAddress {
470*bb4ee6a4SAndroid Build Coastguard Worker bus: 0,
471*bb4ee6a4SAndroid Build Coastguard Worker dev: 14,
472*bb4ee6a4SAndroid Build Coastguard Worker func: 0
473*bb4ee6a4SAndroid Build Coastguard Worker }),
474*bb4ee6a4SAndroid Build Coastguard Worker }
475*bb4ee6a4SAndroid Build Coastguard Worker );
476*bb4ee6a4SAndroid Build Coastguard Worker
477*bb4ee6a4SAndroid Build Coastguard Worker // invalid field
478*bb4ee6a4SAndroid Build Coastguard Worker let params = from_serial_arg("type=stdout,foo=bar");
479*bb4ee6a4SAndroid Build Coastguard Worker assert!(params.is_err());
480*bb4ee6a4SAndroid Build Coastguard Worker }
481*bb4ee6a4SAndroid Build Coastguard Worker }
482