xref: /aosp_15_r20/external/crosvm/devices/src/serial_device.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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