Skip to main content

qemu_command_builder/args/
addfs.rs

1use crate::parsers::ARG_ADD_FD;
2use std::str::FromStr;
3
4use bon::Builder;
5use proptest_derive::Arbitrary;
6
7use crate::parsers::DELIM_COMMA;
8use crate::shell_string::ShellString;
9use crate::to_command::ToCommand;
10
11const KEY_FD: &str = "fd=";
12const KEY_SET: &str = "set=";
13const KEY_OPAQUE: &str = "opaque=";
14
15/// Add a file descriptor to a fd set.
16#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Default, Builder, Arbitrary)]
17pub struct AddFd {
18    /// This option defines the file descriptor of which a duplicate is
19    /// added to fd set. The file descriptor cannot be stdin, stdout, or
20    /// stderr.
21    pub fd: usize,
22    /// This option defines the ID of the fd set to add the file
23    /// descriptor to.
24    pub set: usize,
25    /// This option defines a free-form string that can be used to
26    /// describe fd.
27    pub opaque: Option<ShellString>,
28}
29
30impl AddFd {
31    /// Creates an `-add-fd` mapping from a host file descriptor to a QEMU fd set.
32    pub fn new(fd: usize, set: usize) -> Self {
33        Self { fd, set, opaque: None }
34    }
35}
36
37impl ToCommand for AddFd {
38    fn command(&self) -> String {
39        ARG_ADD_FD.to_string()
40    }
41
42    fn to_args(&self) -> Vec<String> {
43        let mut args = vec![format!("{}{}", KEY_FD, self.fd)];
44        args.push(format!("{}{}", KEY_SET, self.set));
45        if let Some(opaque) = &self.opaque {
46            args.push(format!("{}{}", KEY_OPAQUE, opaque.as_ref()));
47        }
48
49        vec![args.join(DELIM_COMMA)]
50    }
51}
52
53impl FromStr for AddFd {
54    type Err = String;
55
56    fn from_str(s: &str) -> Result<Self, Self::Err> {
57        let mut fd = None;
58        let mut set = None;
59        let mut opaque = None;
60
61        for part in s.split(DELIM_COMMA) {
62            let (key, value) = part.split_once('=').ok_or_else(|| format!("invalid add-fd option: {part}"))?;
63            match key {
64                "fd" => fd = Some(value.parse::<usize>().map_err(|e| e.to_string())?),
65                "set" => set = Some(value.parse::<usize>().map_err(|e| e.to_string())?),
66                "opaque" => opaque = Some(ShellString::from_str(value)?),
67                other => return Err(format!("unsupported add-fd option: {other}")),
68            }
69        }
70
71        Ok(AddFd {
72            fd: fd.ok_or_else(|| "missing fd= for -add-fd".to_string())?,
73            set: set.ok_or_else(|| "missing set= for -add-fd".to_string())?,
74            opaque,
75        })
76    }
77}