1 | #[cfg (target_os = "linux" )] |
2 | use std::ffi::OsString; |
3 | use std::{ |
4 | ffi::OsStr, |
5 | fmt::{Display, Formatter}, |
6 | path::PathBuf, |
7 | }; |
8 | |
9 | #[cfg (unix)] |
10 | use super::encode_percents; |
11 | |
12 | /// A Unix domain socket transport in a D-Bus address. |
13 | #[derive (Clone, Debug, PartialEq, Eq)] |
14 | pub struct Unix { |
15 | path: UnixSocket, |
16 | } |
17 | |
18 | impl Unix { |
19 | /// Create a new Unix transport with the given path. |
20 | pub fn new(path: UnixSocket) -> Self { |
21 | Self { path } |
22 | } |
23 | |
24 | /// The path. |
25 | pub fn path(&self) -> &UnixSocket { |
26 | &self.path |
27 | } |
28 | |
29 | /// Take the path, consuming `self`. |
30 | pub fn take_path(self) -> UnixSocket { |
31 | self.path |
32 | } |
33 | |
34 | pub(super) fn from_options(opts: std::collections::HashMap<&str, &str>) -> crate::Result<Self> { |
35 | let path = opts.get("path" ); |
36 | let abs = opts.get("abstract" ); |
37 | let dir = opts.get("dir" ); |
38 | let tmpdir = opts.get("tmpdir" ); |
39 | let path = match (path, abs, dir, tmpdir) { |
40 | (Some(p), None, None, None) => UnixSocket::File(PathBuf::from(p)), |
41 | #[cfg (target_os = "linux" )] |
42 | (None, Some(p), None, None) => UnixSocket::Abstract(OsString::from(p)), |
43 | #[cfg (not(target_os = "linux" ))] |
44 | (None, Some(_), None, None) => { |
45 | return Err(crate::Error::Address( |
46 | "abstract sockets currently Linux-only" .to_owned(), |
47 | )); |
48 | } |
49 | (None, None, Some(p), None) => UnixSocket::Dir(PathBuf::from(p)), |
50 | (None, None, None, Some(p)) => UnixSocket::TmpDir(PathBuf::from(p)), |
51 | _ => { |
52 | return Err(crate::Error::Address("unix: address is invalid" .to_owned())); |
53 | } |
54 | }; |
55 | |
56 | Ok(Self::new(path)) |
57 | } |
58 | } |
59 | |
60 | impl Display for Unix { |
61 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
62 | write!(f, "unix: {}" , self.path) |
63 | } |
64 | } |
65 | |
66 | /// A Unix domain socket path in a D-Bus address. |
67 | #[derive (Clone, Debug, PartialEq, Eq)] |
68 | #[non_exhaustive ] |
69 | pub enum UnixSocket { |
70 | /// A path to a unix domain socket on the filesystem. |
71 | File(PathBuf), |
72 | /// A abstract unix domain socket name. |
73 | #[cfg (target_os = "linux" )] |
74 | Abstract(OsString), |
75 | /// A listenable address using the specified path, in which a socket file with a random file |
76 | /// name starting with 'dbus-' will be created by the server. See [UNIX domain socket address] |
77 | /// reference documentation. |
78 | /// |
79 | /// This address is mostly relevant to server (typically bus broker) implementations. |
80 | /// |
81 | /// [UNIX domain socket address]: https://dbus.freedesktop.org/doc/dbus-specification.html#transports-unix-domain-sockets-addresses |
82 | Dir(PathBuf), |
83 | /// The same as UnixDir, except that on platforms with abstract sockets, the server may attempt |
84 | /// to create an abstract socket whose name starts with this directory instead of a path-based |
85 | /// socket. |
86 | /// |
87 | /// This address is mostly relevant to server (typically bus broker) implementations. |
88 | TmpDir(PathBuf), |
89 | } |
90 | |
91 | impl Display for UnixSocket { |
92 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
93 | fn fmt_unix_path(f: &mut Formatter<'_>, path: &OsStr) -> std::fmt::Result { |
94 | #[cfg (unix)] |
95 | { |
96 | use std::os::unix::ffi::OsStrExt; |
97 | |
98 | encode_percents(f, path.as_bytes())?; |
99 | } |
100 | |
101 | #[cfg (windows)] |
102 | write!(f, "{}" , path.to_str().ok_or(std::fmt::Error)?)?; |
103 | |
104 | Ok(()) |
105 | } |
106 | |
107 | match self { |
108 | UnixSocket::File(path) => { |
109 | f.write_str("path=" )?; |
110 | fmt_unix_path(f, path.as_os_str())?; |
111 | } |
112 | #[cfg (target_os = "linux" )] |
113 | UnixSocket::Abstract(name) => { |
114 | f.write_str("abstract=" )?; |
115 | fmt_unix_path(f, name)?; |
116 | } |
117 | UnixSocket::Dir(path) => { |
118 | f.write_str("dir=" )?; |
119 | fmt_unix_path(f, path.as_os_str())?; |
120 | } |
121 | UnixSocket::TmpDir(path) => { |
122 | f.write_str("tmpdir=" )?; |
123 | fmt_unix_path(f, path.as_os_str())?; |
124 | } |
125 | } |
126 | |
127 | Ok(()) |
128 | } |
129 | } |
130 | |