1 use static_assertions::assert_impl_all;
2 use std::{convert::Infallible, error, fmt, io, sync::Arc};
3 use zbus_names::{Error as NamesError, OwnedErrorName};
4 use zvariant::Error as VariantError;
5 
6 use crate::{fdo, Message, MessageType};
7 
8 /// The error type for `zbus`.
9 ///
10 /// The various errors that can be reported by this crate.
11 #[derive(Debug)]
12 #[non_exhaustive]
13 #[allow(clippy::upper_case_acronyms)]
14 pub enum Error {
15     /// Interface not found
16     InterfaceNotFound,
17     /// Invalid D-Bus address.
18     Address(String),
19     /// An I/O error.
20     Io(io::Error),
21     /// Invalid message field.
22     InvalidField,
23     /// Data too large.
24     ExcessData,
25     /// A [zvariant](../zvariant/index.html) error.
26     Variant(VariantError),
27     /// A [zbus_names](../zbus_names/index.html) error.
28     Names(NamesError),
29     /// Endian signature invalid or doesn't match expectation.
30     IncorrectEndian,
31     /// Initial handshake error.
32     Handshake(String),
33     /// Unexpected or incorrect reply.
34     InvalidReply,
35     /// A D-Bus method error reply.
36     // According to the spec, there can be all kinds of details in D-Bus errors but nobody adds anything more than a
37     // string description.
38     MethodError(OwnedErrorName, Option<String>, Arc<Message>),
39     /// A required field is missing in the message headers.
40     MissingField,
41     /// Invalid D-Bus GUID.
42     InvalidGUID,
43     /// Unsupported function, or support currently lacking.
44     Unsupported,
45     /// A [`fdo::Error`] transformed into [`Error`].
46     FDO(Box<fdo::Error>),
47     #[cfg(feature = "xml")]
48     /// An XML error
49     SerdeXml(serde_xml_rs::Error),
50     NoBodySignature,
51     /// The requested name was already claimed by another peer.
52     NameTaken,
53 }
54 
55 assert_impl_all!(Error: Send, Sync, Unpin);
56 
57 impl PartialEq for Error {
eq(&self, other: &Self) -> bool58     fn eq(&self, other: &Self) -> bool {
59         match (self, other) {
60             (Self::Address(_), Self::Address(_)) => true,
61             (Self::InterfaceNotFound, Self::InterfaceNotFound) => true,
62             (Self::Handshake(_), Self::Handshake(_)) => true,
63             (Self::InvalidReply, Self::InvalidReply) => true,
64             (Self::ExcessData, Self::ExcessData) => true,
65             (Self::IncorrectEndian, Self::IncorrectEndian) => true,
66             (Self::MethodError(_, _, _), Self::MethodError(_, _, _)) => true,
67             (Self::MissingField, Self::MissingField) => true,
68             (Self::InvalidGUID, Self::InvalidGUID) => true,
69             (Self::Unsupported, Self::Unsupported) => true,
70             (Self::FDO(s), Self::FDO(o)) => s == o,
71             (Self::NoBodySignature, Self::NoBodySignature) => true,
72             (Self::InvalidField, Self::InvalidField) => true,
73             (Self::Variant(s), Self::Variant(o)) => s == o,
74             (Self::Names(s), Self::Names(o)) => s == o,
75             (Self::NameTaken, Self::NameTaken) => true,
76             (Error::Io(_), Self::Io(_)) => false,
77             #[cfg(feature = "xml")]
78             (Self::SerdeXml(_), Self::SerdeXml(_)) => false,
79             (_, _) => false,
80         }
81     }
82 }
83 
84 impl error::Error for Error {
source(&self) -> Option<&(dyn error::Error + 'static)>85     fn source(&self) -> Option<&(dyn error::Error + 'static)> {
86         match self {
87             Error::InterfaceNotFound => None,
88             Error::Address(_) => None,
89             Error::Io(e) => Some(e),
90             Error::ExcessData => None,
91             Error::Handshake(_) => None,
92             Error::IncorrectEndian => None,
93             Error::Variant(e) => Some(e),
94             Error::Names(e) => Some(e),
95             Error::InvalidReply => None,
96             Error::MethodError(_, _, _) => None,
97             Error::InvalidGUID => None,
98             Error::Unsupported => None,
99             Error::FDO(e) => Some(e),
100             #[cfg(feature = "xml")]
101             Error::SerdeXml(e) => Some(e),
102             Error::NoBodySignature => None,
103             Error::InvalidField => None,
104             Error::MissingField => None,
105             Error::NameTaken => None,
106         }
107     }
108 }
109 
110 impl fmt::Display for Error {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result111     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112         match self {
113             Error::InterfaceNotFound => write!(f, "Interface not found"),
114             Error::Address(e) => write!(f, "address error: {}", e),
115             Error::ExcessData => write!(f, "excess data"),
116             Error::Io(e) => write!(f, "I/O error: {}", e),
117             Error::Handshake(e) => write!(f, "D-Bus handshake failed: {}", e),
118             Error::IncorrectEndian => write!(f, "incorrect endian"),
119             Error::InvalidField => write!(f, "invalid message field"),
120             Error::Variant(e) => write!(f, "{}", e),
121             Error::Names(e) => write!(f, "{}", e),
122             Error::InvalidReply => write!(f, "Invalid D-Bus method reply"),
123             Error::MissingField => write!(f, "A required field is missing from message headers"),
124             Error::MethodError(name, detail, _reply) => write!(
125                 f,
126                 "{}: {}",
127                 **name,
128                 detail.as_ref().map(|s| s.as_str()).unwrap_or("no details")
129             ),
130             Error::InvalidGUID => write!(f, "Invalid GUID"),
131             Error::Unsupported => write!(f, "Connection support is lacking"),
132             Error::FDO(e) => write!(f, "{}", e),
133             #[cfg(feature = "xml")]
134             Error::SerdeXml(e) => write!(f, "XML error: {}", e),
135             Error::NoBodySignature => write!(f, "missing body signature in the message"),
136             Error::NameTaken => write!(f, "name already taken on the bus"),
137         }
138     }
139 }
140 
141 impl From<io::Error> for Error {
from(val: io::Error) -> Self142     fn from(val: io::Error) -> Self {
143         Error::Io(val)
144     }
145 }
146 
147 #[cfg(unix)]
148 impl From<nix::Error> for Error {
from(val: nix::Error) -> Self149     fn from(val: nix::Error) -> Self {
150         io::Error::from_raw_os_error(val as i32).into()
151     }
152 }
153 
154 impl From<VariantError> for Error {
from(val: VariantError) -> Self155     fn from(val: VariantError) -> Self {
156         Error::Variant(val)
157     }
158 }
159 
160 impl From<NamesError> for Error {
from(val: NamesError) -> Self161     fn from(val: NamesError) -> Self {
162         match val {
163             NamesError::Variant(e) => Error::Variant(e),
164             e => Error::Names(e),
165         }
166     }
167 }
168 
169 impl From<fdo::Error> for Error {
from(val: fdo::Error) -> Self170     fn from(val: fdo::Error) -> Self {
171         match val {
172             fdo::Error::ZBus(e) => e,
173             e => Error::FDO(Box::new(e)),
174         }
175     }
176 }
177 
178 #[cfg(feature = "xml")]
179 impl From<serde_xml_rs::Error> for Error {
from(val: serde_xml_rs::Error) -> Self180     fn from(val: serde_xml_rs::Error) -> Self {
181         Error::SerdeXml(val)
182     }
183 }
184 
185 impl From<Infallible> for Error {
from(i: Infallible) -> Self186     fn from(i: Infallible) -> Self {
187         match i {}
188     }
189 }
190 
191 // For messages that are D-Bus error returns
192 impl From<Message> for Error {
from(message: Message) -> Error193     fn from(message: Message) -> Error {
194         Self::from(Arc::new(message))
195     }
196 }
197 
198 impl From<Arc<Message>> for Error {
from(message: Arc<Message>) -> Error199     fn from(message: Arc<Message>) -> Error {
200         // FIXME: Instead of checking this, we should have Method as trait and specific types for
201         // each message type.
202         let header = match message.header() {
203             Ok(header) => header,
204             Err(e) => {
205                 return e;
206             }
207         };
208         if header.primary().msg_type() != MessageType::Error {
209             return Error::InvalidReply;
210         }
211 
212         if let Ok(Some(name)) = header.error_name() {
213             let name = name.to_owned().into();
214             match message.body_unchecked::<&str>() {
215                 Ok(detail) => Error::MethodError(name, Some(String::from(detail)), message),
216                 Err(_) => Error::MethodError(name, None, message),
217             }
218         } else {
219             Error::InvalidReply
220         }
221     }
222 }
223 
224 /// Alias for a `Result` with the error type `zbus::Error`.
225 pub type Result<T> = std::result::Result<T, Error>;
226