Skip to main content

sysd_manager_comcontroler/
errors.rs

1use base::file::SysdBaseError;
2use gettextrs::pgettext;
3use std::{
4    ffi::OsString,
5    fmt::{self, Display, Formatter},
6    string::FromUtf8Error,
7    time::Duration,
8};
9
10#[derive(Debug)]
11#[allow(unused)]
12pub enum SystemdErrors {
13    Command(
14        OsString,
15        Vec<OsString>,
16        Vec<(OsString, Option<OsString>)>,
17        std::io::Error,
18    ),
19    Custom(String),
20    IoError(std::io::Error),
21    Utf8Error(FromUtf8Error),
22    Fmt(std::fmt::Error),
23    ZMethodError(String, String, String),
24    CmdNoFlatpakSpawn,
25    CmdNoFreedesktopFlatpakPermission(Option<String>, Option<String>),
26    JournalError(String),
27    NoFilePathforUnit(String),
28    Malformed(String, String),
29    NotAuthorized,
30    NotAuthorizedAuthentificationDismissed,
31    NoUnit,
32    SystemCtlError(String),
33    Tokio,
34    ZBusError(zbus::Error),
35    ZAccessDenied(String, String),
36    ZNoSuchUnit(String, String),
37    ZNoSuchUnitProxy(String, String),
38    ZJobTypeNotApplicable(String, String),
39    ZUnitMasked(String, String),
40    ZVariantError(zvariant::Error),
41    ZBusFdoError(zbus::fdo::Error),
42    ZFdoServiceUnknowm(String),
43    ZFdoZError(String),
44    ZXml(zbus_xml::Error),
45    Unreachable,
46    InvalidPath(String),
47    Timeout(Duration),
48    JobRemoved(String),
49    ZFileNotFound(String),
50}
51
52impl SystemdErrors {
53    pub fn gui_description(&self) -> Option<String> {
54        match self {
55            SystemdErrors::CmdNoFlatpakSpawn => {
56                //error message flatpak permission
57                Some(pgettext(
58                    "error",
59                    "The program <b>flatpack-spawn</b> is needed if you use the application from Flatpack.\nPlease install it to enable all features.",
60                ))
61            }
62            SystemdErrors::CmdNoFreedesktopFlatpakPermission(_cmdl, _file_path) => {
63                //error message flatpak permission
64                Some(pgettext(
65                    "error",
66                    "It requires permission to talk to <b>org.freedesktop.Flatpak</b> D-Bus interface when the program is a Flatpak.",
67                ))
68            }
69            _ => None,
70        }
71    }
72
73    pub fn human_error_type(&self) -> String {
74        match self {
75            SystemdErrors::ZAccessDenied(_, detail) => detail.clone(),
76            SystemdErrors::ZJobTypeNotApplicable(_, detail) => detail.clone(),
77            SystemdErrors::ZNoSuchUnit(_, detail) => detail.clone(),
78            SystemdErrors::ZNoSuchUnitProxy(_, detail) => detail.clone(),
79            SystemdErrors::ZUnitMasked(_, detail) => detail.clone(),
80            SystemdErrors::JobRemoved(reason) => uppercase_first_letter(reason),
81            _ => self.to_string(),
82        }
83    }
84
85    pub fn file_not_found(&self) -> bool {
86        if let SystemdErrors::IoError(io_error) = self
87            && io_error.kind() == std::io::ErrorKind::NotFound
88        {
89            true
90        } else {
91            false
92        }
93    }
94}
95
96fn uppercase_first_letter(s: &str) -> String {
97    let mut c = s.chars();
98    match c.next() {
99        None => String::new(),
100        Some(f) => f.to_uppercase().chain(c).collect(),
101    }
102}
103
104impl Display for SystemdErrors {
105    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
106        write!(f, "{self:?}")
107    }
108}
109
110impl From<std::io::Error> for SystemdErrors {
111    fn from(error: std::io::Error) -> Self {
112        SystemdErrors::IoError(error)
113    }
114}
115
116impl From<FromUtf8Error> for SystemdErrors {
117    fn from(error: FromUtf8Error) -> Self {
118        SystemdErrors::Utf8Error(error)
119    }
120}
121
122impl From<(zbus::Error, &str)> for SystemdErrors {
123    fn from(value: (zbus::Error, &str)) -> Self {
124        let (zb_error, method) = value;
125
126        match zb_error {
127            zbus::Error::MethodError(owned_error_name, ref msg, _message) => {
128                let err_code = zvariant::Str::from(owned_error_name);
129
130                let err_code = err_code.as_str();
131                let message = msg.clone().unwrap_or_default();
132
133                match err_code {
134                    "org.freedesktop.DBus.Error.AccessDenied" => {
135                        let method = if method.is_empty() {
136                            "AccessDenied"
137                        } else {
138                            method
139                        };
140                        SystemdErrors::ZAccessDenied(method.to_owned(), message)
141                    }
142                    "org.freedesktop.systemd1.NoSuchUnit" => {
143                        let method = if method.is_empty() {
144                            "NoSuchUnit"
145                        } else {
146                            method
147                        };
148                        SystemdErrors::ZNoSuchUnit(method.to_owned(), message)
149                    }
150                    "org.freedesktop.DBus.Error.InvalidArgs" => {
151                        let method = if method.is_empty() {
152                            "InvalidArgs"
153                        } else {
154                            method
155                        };
156                        SystemdErrors::ZNoSuchUnitProxy(method.to_owned(), message)
157                    }
158                    "org.freedesktop.systemd1.JobTypeNotApplicable" => {
159                        let method = if method.is_empty() {
160                            "JobTypeNotApplicable"
161                        } else {
162                            method
163                        };
164                        SystemdErrors::ZJobTypeNotApplicable(method.to_owned(), message)
165                    }
166                    "org.freedesktop.systemd1.UnitMasked" => {
167                        let method = if method.is_empty() {
168                            "UnitMasked"
169                        } else {
170                            method
171                        };
172                        SystemdErrors::ZUnitMasked(method.to_owned(), message)
173                    }
174                    "org.freedesktop.zbus.Error" => {
175                        SystemdErrors::ZUnitMasked(method.to_owned(), message)
176                    }
177                    "org.freedesktop.DBus.Error.FileNotFound" => {
178                        SystemdErrors::ZFileNotFound(message)
179                    }
180                    _ => {
181                        SystemdErrors::ZMethodError(method.to_owned(), err_code.to_owned(), message)
182                    }
183                }
184            }
185
186            _ => SystemdErrors::ZBusError(zb_error),
187        }
188    }
189}
190
191impl From<zbus::Error> for SystemdErrors {
192    fn from(error: zbus::Error) -> Self {
193        //log::info!("TS {:?}", error);
194        SystemdErrors::from((error, ""))
195    }
196}
197
198impl From<zbus::fdo::Error> for SystemdErrors {
199    fn from(error: zbus::fdo::Error) -> Self {
200        match error {
201            zbus::fdo::Error::ServiceUnknown(s) => SystemdErrors::ZFdoServiceUnknowm(s),
202            zbus::fdo::Error::ZBus(err) => err.into(),
203            _ => SystemdErrors::ZBusFdoError(error),
204        }
205    }
206}
207
208impl From<Box<dyn std::error::Error>> for SystemdErrors {
209    fn from(error: Box<dyn std::error::Error>) -> Self {
210        let msg = format!("{error}");
211        SystemdErrors::JournalError(msg)
212    }
213}
214
215impl From<zvariant::Error> for SystemdErrors {
216    fn from(value: zvariant::Error) -> Self {
217        SystemdErrors::ZVariantError(value)
218    }
219}
220
221impl From<tokio::task::JoinError> for SystemdErrors {
222    fn from(_value: tokio::task::JoinError) -> Self {
223        SystemdErrors::Tokio
224    }
225}
226
227impl From<zbus_xml::Error> for SystemdErrors {
228    fn from(value: zbus_xml::Error) -> Self {
229        SystemdErrors::ZXml(value)
230    }
231}
232
233impl From<std::fmt::Error> for SystemdErrors {
234    fn from(value: std::fmt::Error) -> Self {
235        SystemdErrors::Fmt(value)
236    }
237}
238
239impl From<String> for SystemdErrors {
240    fn from(value: String) -> Self {
241        SystemdErrors::Custom(value)
242    }
243}
244
245impl From<&str> for SystemdErrors {
246    fn from(value: &str) -> Self {
247        value.to_owned().into()
248    }
249}
250
251impl From<SysdBaseError> for SystemdErrors {
252    fn from(value: SysdBaseError) -> Self {
253        match value {
254            SysdBaseError::CmdNoFreedesktopFlatpakPermission => {
255                SystemdErrors::CmdNoFreedesktopFlatpakPermission(None, None)
256            }
257            SysdBaseError::CommandCallError(os_string, os_strings, items, error) => {
258                SystemdErrors::Command(os_string, os_strings, items, error)
259            }
260            SysdBaseError::Custom(s) => SystemdErrors::Custom(s),
261            SysdBaseError::IoError(error) => SystemdErrors::IoError(error),
262            SysdBaseError::NotAuthorizedAuthentificationDismissed => {
263                SystemdErrors::NotAuthorizedAuthentificationDismissed
264            }
265            SysdBaseError::NotAuthorized => SystemdErrors::NotAuthorized,
266            SysdBaseError::Tokio(_join_error) => SystemdErrors::Tokio,
267            SysdBaseError::InvalidPath(msg) => SystemdErrors::InvalidPath(msg),
268        }
269    }
270}