dbus_addr/transport/
unix.rs

1use std::{borrow::Cow, ffi::OsStr};
2
3use super::{
4    percent::{decode_percents, decode_percents_os_str, decode_percents_str, EncData, EncOsStr},
5    DBusAddr, Error, KeyValFmt, Result, TransportImpl,
6};
7
8/// `unix:` D-Bus transport.
9///
10/// <https://dbus.freedesktop.org/doc/dbus-specification.html#transports-unix-domain-sockets-addresses>
11#[derive(Clone, Debug, PartialEq, Eq)]
12pub struct Unix<'a> {
13    kind: UnixAddrKind<'a>,
14}
15
16impl<'a> Unix<'a> {
17    /// One of the various `unix:` addresses.
18    pub fn kind(&self) -> &UnixAddrKind<'a> {
19        &self.kind
20    }
21
22    /// Convert into owned version, with 'static lifetime.
23    pub fn into_owned(self) -> Unix<'static> {
24        Unix {
25            kind: self.kind.into_owned(),
26        }
27    }
28}
29
30impl<'a> TransportImpl<'a> for Unix<'a> {
31    fn for_address(s: &'a DBusAddr<'a>) -> Result<Self> {
32        let mut kind = None;
33        let mut iter = s.key_val_iter();
34        for (k, v) in &mut iter {
35            match k {
36                "path" | "dir" | "tmpdir" => {
37                    let v = v.ok_or_else(|| Error::MissingValue(k.into()))?;
38                    let v = decode_percents_os_str(v)?;
39                    kind = Some(match k {
40                        "path" => UnixAddrKind::Path(v),
41                        "dir" => UnixAddrKind::Dir(v),
42                        "tmpdir" => UnixAddrKind::Tmpdir(v),
43                        // can't happen, we matched those earlier
44                        _ => panic!(),
45                    });
46
47                    break;
48                }
49                "abstract" => {
50                    let v = v.ok_or_else(|| Error::MissingValue(k.into()))?;
51                    let v = decode_percents(v)?;
52                    kind = Some(UnixAddrKind::Abstract(v));
53
54                    break;
55                }
56                "runtime" => {
57                    let v = v.ok_or_else(|| Error::MissingValue(k.into()))?;
58                    let v = decode_percents_str(v)?;
59                    if v != "yes" {
60                        return Err(Error::InvalidValue(k.into()));
61                    }
62                    kind = Some(UnixAddrKind::Runtime);
63
64                    break;
65                }
66                _ => continue,
67            }
68        }
69        let Some(kind) = kind else {
70            return Err(Error::Other(
71                "invalid `unix:` address, missing required key".into(),
72            ));
73        };
74        for (k, _) in iter {
75            match k {
76                "path" | "dir" | "tmpdir" | "abstract" | "runtime" => {
77                    return Err(Error::Other("invalid address, only one of `path` `dir` `tmpdir` `abstract` or `runtime` expected".into()));
78                }
79                _ => (),
80            }
81        }
82
83        Ok(Unix { kind })
84    }
85
86    fn fmt_key_val<'s: 'b, 'b>(&'s self, kv: KeyValFmt<'b>) -> KeyValFmt<'b> {
87        self.kind().fmt_key_val(kv)
88    }
89}
90
91/// A sub-type of `unix:` transport.
92#[derive(Clone, Debug, PartialEq, Eq)]
93#[non_exhaustive]
94pub enum UnixAddrKind<'a> {
95    /// Path of the unix domain socket.
96    Path(Cow<'a, OsStr>),
97    /// Directory in which a socket file with a random file name starting with 'dbus-' should be
98    /// created by a server.
99    Dir(Cow<'a, OsStr>),
100    /// The same as "dir", except that on platforms with abstract sockets, a server may attempt to
101    /// create an abstract socket whose name starts with this directory instead of a path-based
102    /// socket.
103    Tmpdir(Cow<'a, OsStr>),
104    /// Unique string in the abstract namespace, often syntactically resembling a path but
105    /// unconnected to the filesystem namespace
106    Abstract(Cow<'a, [u8]>),
107    /// Listen on $XDG_RUNTIME_DIR/bus.
108    Runtime,
109}
110
111impl UnixAddrKind<'_> {
112    fn fmt_key_val<'s: 'b, 'b>(&'s self, kv: KeyValFmt<'b>) -> KeyValFmt<'b> {
113        match self {
114            UnixAddrKind::Path(p) => kv.add("path", Some(EncOsStr(p))),
115            UnixAddrKind::Dir(p) => kv.add("dir", Some(EncOsStr(p))),
116            UnixAddrKind::Tmpdir(p) => kv.add("tmpdir", Some(EncOsStr(p))),
117            UnixAddrKind::Abstract(p) => kv.add("abstract", Some(EncData(p))),
118            UnixAddrKind::Runtime => kv.add("runtime", Some("yes")),
119        }
120    }
121
122    fn into_owned(self) -> UnixAddrKind<'static> {
123        match self {
124            UnixAddrKind::Path(cow) => UnixAddrKind::Path(cow.into_owned().into()),
125            UnixAddrKind::Dir(cow) => UnixAddrKind::Dir(cow.into_owned().into()),
126            UnixAddrKind::Tmpdir(cow) => UnixAddrKind::Tmpdir(cow.into_owned().into()),
127            UnixAddrKind::Abstract(cow) => UnixAddrKind::Abstract(cow.into_owned().into()),
128            UnixAddrKind::Runtime => UnixAddrKind::Runtime,
129        }
130    }
131}