dbus_addr/transport/
unixexec.rs

1use std::{borrow::Cow, ffi::OsStr, fmt};
2
3use super::{
4    percent::{decode_percents_os_str, decode_percents_str, EncOsStr},
5    DBusAddr, Error, KeyValFmt, Result, TransportImpl,
6};
7
8/// `unixexec:` D-Bus transport.
9///
10/// <https://dbus.freedesktop.org/doc/dbus-specification.html#transports-exec>
11#[derive(Clone, Debug, PartialEq, Eq)]
12pub struct Unixexec<'a> {
13    path: Cow<'a, OsStr>,
14    argv: Vec<(usize, Cow<'a, str>)>,
15}
16
17impl<'a> Unixexec<'a> {
18    /// Binary to execute.
19    ///
20    /// Path of the binary to execute, either an absolute path or a binary name that is searched for
21    /// in the default search path of the OS. This corresponds to the first argument of execlp().
22    /// This key is mandatory.
23    pub fn path(&self) -> &OsStr {
24        self.path.as_ref()
25    }
26
27    /// Arguments.
28    ///
29    /// Arguments to pass to the binary as `[(nth, arg),...]`.
30    pub fn argv(&self) -> &[(usize, Cow<'a, str>)] {
31        self.argv.as_ref()
32    }
33
34    /// Convert into owned version, with 'static lifetime.
35    pub fn into_owned(self) -> Unixexec<'static> {
36        let argv = self
37            .argv
38            .into_iter()
39            .map(|(index, cow)| (index, cow.into_owned().into()))
40            .collect();
41        Unixexec {
42            path: self.path.into_owned().into(),
43            argv,
44        }
45    }
46}
47
48impl<'a> TransportImpl<'a> for Unixexec<'a> {
49    fn for_address(s: &'a DBusAddr<'a>) -> Result<Self> {
50        let mut path = None;
51        let mut argv = Vec::new();
52
53        for (k, v) in s.key_val_iter() {
54            match (k, v) {
55                ("path", Some(v)) => {
56                    path = Some(decode_percents_os_str(v)?);
57                }
58                (k, Some(v)) if k.starts_with("argv") => {
59                    let n: usize = k[4..].parse().map_err(|_| Error::InvalidValue(k.into()))?;
60                    let arg = decode_percents_str(v)?;
61                    argv.push((n, arg));
62                }
63                _ => continue,
64            }
65        }
66
67        let Some(path) = path else {
68            return Err(Error::MissingKey("path".into()));
69        };
70
71        argv.sort_by_key(|(num, _)| *num);
72
73        Ok(Self { path, argv })
74    }
75
76    fn fmt_key_val<'s: 'b, 'b>(&'s self, mut kv: KeyValFmt<'b>) -> KeyValFmt<'b> {
77        kv = kv.add("path", Some(EncOsStr(self.path())));
78        for (n, arg) in self.argv() {
79            kv = kv.add(Argv(*n), Some(arg));
80        }
81
82        kv
83    }
84}
85
86#[derive(Debug, PartialEq, Eq)]
87struct Argv(usize);
88
89impl fmt::Display for Argv {
90    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91        let n = self.0;
92
93        write!(f, "argv{n}")
94    }
95}