| 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 | |