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