1#[cfg(feature = "quick-xml")]
2use quick_xml::de::DeError;
3use static_assertions::assert_impl_all;
4use std::{convert::Infallible, error, fmt, io, sync::Arc};
5use zbus_names::{Error as NamesError, OwnedErrorName};
6use zvariant::Error as VariantError;
7
8use crate::{fdo, Message, MessageType};
9
10/// The error type for `zbus`.
11///
12/// The various errors that can be reported by this crate.
13#[derive(Debug)]
14#[non_exhaustive]
15#[allow(clippy::upper_case_acronyms)]
16pub enum Error {
17 /// Interface not found
18 InterfaceNotFound,
19 /// Invalid D-Bus address.
20 Address(String),
21 /// An I/O error.
22 #[deprecated(note = "Use `Error::InputOutput` instead")]
23 Io(io::Error),
24 /// An I/O error.
25 InputOutput(Arc<io::Error>),
26 /// Invalid message field.
27 InvalidField,
28 /// Data too large.
29 ExcessData,
30 /// A [zvariant](../zvariant/index.html) error.
31 Variant(VariantError),
32 /// A [zbus_names](../zbus_names/index.html) error.
33 Names(NamesError),
34 /// Endian signature invalid or doesn't match expectation.
35 IncorrectEndian,
36 /// Initial handshake error.
37 Handshake(String),
38 /// Unexpected or incorrect reply.
39 InvalidReply,
40 /// A D-Bus method error reply.
41 // According to the spec, there can be all kinds of details in D-Bus errors but nobody adds
42 // anything more than a string description.
43 MethodError(OwnedErrorName, Option<String>, Arc<Message>),
44 /// A required field is missing in the message headers.
45 MissingField,
46 /// Invalid D-Bus GUID.
47 InvalidGUID,
48 /// Unsupported function, or support currently lacking.
49 Unsupported,
50 /// A [`fdo::Error`] transformed into [`Error`].
51 FDO(Box<fdo::Error>),
52 #[cfg(feature = "xml")]
53 /// An XML error
54 SerdeXml(serde_xml_rs::Error),
55 #[cfg(feature = "quick-xml")]
56 /// An XML error from quick_xml
57 QuickXml(DeError),
58 NoBodySignature,
59 /// The requested name was already claimed by another peer.
60 NameTaken,
61 /// Invalid [match rule][MR] string.
62 ///
63 /// [MR]: https://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-routing-match-rules
64 InvalidMatchRule,
65 /// Generic error.
66 Failure(String),
67 /// A required parameter was missing.
68 MissingParameter(&'static str),
69}
70
71assert_impl_all!(Error: Send, Sync, Unpin);
72
73impl PartialEq for Error {
74 fn eq(&self, other: &Self) -> bool {
75 match (self, other) {
76 (Self::Address(_), Self::Address(_)) => true,
77 (Self::InterfaceNotFound, Self::InterfaceNotFound) => true,
78 (Self::Handshake(_), Self::Handshake(_)) => true,
79 (Self::InvalidReply, Self::InvalidReply) => true,
80 (Self::ExcessData, Self::ExcessData) => true,
81 (Self::IncorrectEndian, Self::IncorrectEndian) => true,
82 (Self::MethodError(_, _, _), Self::MethodError(_, _, _)) => true,
83 (Self::MissingField, Self::MissingField) => true,
84 (Self::InvalidGUID, Self::InvalidGUID) => true,
85 (Self::Unsupported, Self::Unsupported) => true,
86 (Self::FDO(s), Self::FDO(o)) => s == o,
87 (Self::NoBodySignature, Self::NoBodySignature) => true,
88 (Self::InvalidField, Self::InvalidField) => true,
89 (Self::InvalidMatchRule, Self::InvalidMatchRule) => true,
90 (Self::Variant(s), Self::Variant(o)) => s == o,
91 (Self::Names(s), Self::Names(o)) => s == o,
92 (Self::NameTaken, Self::NameTaken) => true,
93 #[allow(deprecated)]
94 (Error::Io(_), Self::Io(_)) => false,
95 (Error::InputOutput(_), Self::InputOutput(_)) => false,
96 #[cfg(feature = "xml")]
97 (Self::SerdeXml(_), Self::SerdeXml(_)) => false,
98 #[cfg(feature = "quick-xml")]
99 (Self::QuickXml(_), Self::QuickXml(_)) => false,
100 (Self::Failure(s1), Self::Failure(s2)) => s1 == s2,
101 (_, _) => false,
102 }
103 }
104}
105
106impl error::Error for Error {
107 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
108 match self {
109 Error::InterfaceNotFound => None,
110 Error::Address(_) => None,
111 #[allow(deprecated)]
112 Error::Io(e) => Some(e),
113 Error::InputOutput(e) => Some(e),
114 Error::ExcessData => None,
115 Error::Handshake(_) => None,
116 Error::IncorrectEndian => None,
117 Error::Variant(e) => Some(e),
118 Error::Names(e) => Some(e),
119 Error::InvalidReply => None,
120 Error::MethodError(_, _, _) => None,
121 Error::InvalidGUID => None,
122 Error::Unsupported => None,
123 Error::FDO(e) => Some(e),
124 #[cfg(feature = "xml")]
125 Error::SerdeXml(e) => Some(e),
126 #[cfg(feature = "quick-xml")]
127 Error::QuickXml(e) => Some(e),
128 Error::NoBodySignature => None,
129 Error::InvalidField => None,
130 Error::MissingField => None,
131 Error::NameTaken => None,
132 Error::InvalidMatchRule => None,
133 Error::Failure(_) => None,
134 Error::MissingParameter(_) => None,
135 }
136 }
137}
138
139impl fmt::Display for Error {
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 match self {
142 Error::InterfaceNotFound => write!(f, "Interface not found"),
143 Error::Address(e) => write!(f, "address error: {e}"),
144 Error::ExcessData => write!(f, "excess data"),
145 #[allow(deprecated)]
146 Error::Io(e) => write!(f, "I/O error: {e}"),
147 Error::InputOutput(e) => write!(f, "I/O error: {e}"),
148 Error::Handshake(e) => write!(f, "D-Bus handshake failed: {e}"),
149 Error::IncorrectEndian => write!(f, "incorrect endian"),
150 Error::InvalidField => write!(f, "invalid message field"),
151 Error::Variant(e) => write!(f, "{e}"),
152 Error::Names(e) => write!(f, "{e}"),
153 Error::InvalidReply => write!(f, "Invalid D-Bus method reply"),
154 Error::MissingField => write!(f, "A required field is missing from message headers"),
155 Error::MethodError(name, detail, _reply) => write!(
156 f,
157 "{}: {}",
158 **name,
159 detail.as_ref().map(|s| s.as_str()).unwrap_or("no details")
160 ),
161 Error::InvalidGUID => write!(f, "Invalid GUID"),
162 Error::Unsupported => write!(f, "Connection support is lacking"),
163 Error::FDO(e) => write!(f, "{e}"),
164 #[cfg(feature = "xml")]
165 Error::SerdeXml(e) => write!(f, "XML error: {}", e),
166 #[cfg(feature = "quick-xml")]
167 Error::QuickXml(e) => write!(f, "XML error: {e}"),
168 Error::NoBodySignature => write!(f, "missing body signature in the message"),
169 Error::NameTaken => write!(f, "name already taken on the bus"),
170 Error::InvalidMatchRule => write!(f, "Invalid match rule string"),
171 Error::Failure(e) => write!(f, "{e}"),
172 Error::MissingParameter(p) => {
173 write!(f, "Parameter `{}` was not specified but it is required", p)
174 }
175 }
176 }
177}
178
179impl Clone for Error {
180 fn clone(&self) -> Self {
181 match self {
182 Error::InterfaceNotFound => Error::InterfaceNotFound,
183 Error::Address(e) => Error::Address(e.clone()),
184 Error::ExcessData => Error::ExcessData,
185 #[allow(deprecated)]
186 Error::Io(e) => Error::Io(io::Error::new(e.kind(), e.to_string())),
187 Error::InputOutput(e) => Error::InputOutput(e.clone()),
188 Error::Handshake(e) => Error::Handshake(e.clone()),
189 Error::IncorrectEndian => Error::IncorrectEndian,
190 Error::InvalidField => Error::InvalidField,
191 Error::Variant(e) => Error::Variant(e.clone()),
192 Error::Names(e) => Error::Names(e.clone()),
193 Error::InvalidReply => Error::InvalidReply,
194 Error::MissingField => Error::MissingField,
195 Error::MethodError(name, detail, reply) => {
196 Error::MethodError(name.clone(), detail.clone(), reply.clone())
197 }
198 Error::InvalidGUID => Error::InvalidGUID,
199 Error::Unsupported => Error::Unsupported,
200 Error::FDO(e) => Error::FDO(e.clone()),
201 #[cfg(feature = "xml")]
202 Error::SerdeXml(e) => Error::Failure(e.to_string()),
203 #[cfg(feature = "quick-xml")]
204 // Until https://github.com/tafia/quick-xml/pull/521 is merged and released.
205 Error::QuickXml(e) => Error::QuickXml(e.clone()),
206 Error::NoBodySignature => Error::NoBodySignature,
207 Error::NameTaken => Error::NameTaken,
208 Error::InvalidMatchRule => Error::InvalidMatchRule,
209 Error::Failure(e) => Error::Failure(e.clone()),
210 Error::MissingParameter(p) => Error::MissingParameter(p),
211 }
212 }
213}
214
215impl From<io::Error> for Error {
216 fn from(val: io::Error) -> Self {
217 Error::InputOutput(Arc::new(data:val))
218 }
219}
220
221#[cfg(unix)]
222impl From<nix::Error> for Error {
223 fn from(val: nix::Error) -> Self {
224 io::Error::from_raw_os_error(code:val as i32).into()
225 }
226}
227
228impl From<VariantError> for Error {
229 fn from(val: VariantError) -> Self {
230 Error::Variant(val)
231 }
232}
233
234impl From<NamesError> for Error {
235 fn from(val: NamesError) -> Self {
236 match val {
237 NamesError::Variant(e: Error) => Error::Variant(e),
238 e: Error => Error::Names(e),
239 }
240 }
241}
242
243impl From<fdo::Error> for Error {
244 fn from(val: fdo::Error) -> Self {
245 match val {
246 fdo::Error::ZBus(e: Error) => e,
247 e: Error => Error::FDO(Box::new(e)),
248 }
249 }
250}
251
252#[cfg(feature = "xml")]
253impl From<serde_xml_rs::Error> for Error {
254 fn from(val: serde_xml_rs::Error) -> Self {
255 Error::SerdeXml(val)
256 }
257}
258
259#[cfg(feature = "quick-xml")]
260impl From<DeError> for Error {
261 fn from(val: DeError) -> Self {
262 Error::QuickXml(val)
263 }
264}
265
266impl From<Infallible> for Error {
267 fn from(i: Infallible) -> Self {
268 match i {}
269 }
270}
271
272// For messages that are D-Bus error returns
273impl From<Message> for Error {
274 fn from(message: Message) -> Error {
275 Self::from(Arc::new(data:message))
276 }
277}
278
279impl From<Arc<Message>> for Error {
280 fn from(message: Arc<Message>) -> Error {
281 // FIXME: Instead of checking this, we should have Method as trait and specific types for
282 // each message type.
283 let header = match message.header() {
284 Ok(header) => header,
285 Err(e) => {
286 return e;
287 }
288 };
289 if header.primary().msg_type() != MessageType::Error {
290 return Error::InvalidReply;
291 }
292
293 if let Ok(Some(name)) = header.error_name() {
294 let name = name.to_owned().into();
295 match message.body_unchecked::<&str>() {
296 Ok(detail) => Error::MethodError(name, Some(String::from(detail)), message),
297 Err(_) => Error::MethodError(name, None, message),
298 }
299 } else {
300 Error::InvalidReply
301 }
302 }
303}
304
305/// Alias for a `Result` with the error type `zbus::Error`.
306pub type Result<T> = std::result::Result<T, Error>;
307