sysd_manager_comcontroler/
errors.rs1use std::{
2 ffi::OsString,
3 fmt::{self, Display, Formatter},
4 process::Command,
5 string::FromUtf8Error,
6};
7
8use gettextrs::pgettext;
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}
47
48impl SystemdErrors {
49 pub fn gui_description(&self) -> Option<String> {
50 match self {
51 SystemdErrors::CmdNoFlatpakSpawn => {
52 Some(pgettext(
54 "error",
55 "The program <b>flatpack-spawn</b> is needed if you use the application from Flatpack.\nPlease install it to enable all features.",
56 ))
57 }
58 SystemdErrors::CmdNoFreedesktopFlatpakPermission(_cmdl, _file_path) => {
59 Some(pgettext(
61 "error",
62 "It requires permission to talk to <b>org.freedesktop.Flatpak</b> D-Bus interface when the program is a Flatpak.",
63 ))
64 }
65 _ => None,
66 }
67 }
68
69 pub fn human_error_type(&self) -> String {
70 match self {
71 SystemdErrors::ZAccessDenied(_, detail) => detail.clone(),
72 SystemdErrors::ZJobTypeNotApplicable(_, detail) => detail.clone(),
73 SystemdErrors::ZNoSuchUnit(_, detail) => detail.clone(),
74 SystemdErrors::ZNoSuchUnitProxy(_, detail) => detail.clone(),
75 SystemdErrors::ZUnitMasked(_, detail) => detail.clone(),
76 _ => self.to_string(),
77 }
78 }
79
80 pub(crate) fn create_command_error(command: &Command, error: std::io::Error) -> Self {
81 let program = command.get_program().to_os_string();
82 let envs: Vec<(OsString, Option<OsString>)> = command
83 .get_envs()
84 .map(|(k, v)| (k.to_os_string(), v.map(|s| s.to_os_string())))
85 .collect();
86 let arg: Vec<OsString> = command.get_args().map(|s| s.to_os_string()).collect();
87
88 SystemdErrors::Command(program, arg, envs, error)
89 }
90}
91
92impl Display for SystemdErrors {
93 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
94 write!(f, "{self:?}")
95 }
96}
97
98impl From<std::io::Error> for SystemdErrors {
99 fn from(error: std::io::Error) -> Self {
100 SystemdErrors::IoError(error)
101 }
102}
103
104impl From<FromUtf8Error> for SystemdErrors {
105 fn from(error: FromUtf8Error) -> Self {
106 SystemdErrors::Utf8Error(error)
107 }
108}
109
110impl From<(zbus::Error, &str)> for SystemdErrors {
111 fn from(value: (zbus::Error, &str)) -> Self {
112 let (zb_error, method) = value;
113
114 match zb_error {
115 zbus::Error::MethodError(owned_error_name, ref msg, _message) => {
116 let err_code = zvariant::Str::from(owned_error_name);
117
118 let err_code = err_code.as_str();
119 let message = msg.clone().unwrap_or_default();
120
121 match err_code {
122 "org.freedesktop.DBus.Error.AccessDenied" => {
123 let method = if method.is_empty() {
124 "AccessDenied"
125 } else {
126 method
127 };
128 SystemdErrors::ZAccessDenied(method.to_owned(), message)
129 }
130 "org.freedesktop.systemd1.NoSuchUnit" => {
131 let method = if method.is_empty() {
132 "NoSuchUnit"
133 } else {
134 method
135 };
136 SystemdErrors::ZNoSuchUnit(method.to_owned(), message)
137 }
138 "org.freedesktop.DBus.Error.InvalidArgs" => {
139 let method = if method.is_empty() {
140 "InvalidArgs"
141 } else {
142 method
143 };
144 SystemdErrors::ZNoSuchUnitProxy(method.to_owned(), message)
145 }
146 "org.freedesktop.systemd1.JobTypeNotApplicable" => {
147 let method = if method.is_empty() {
148 "JobTypeNotApplicable"
149 } else {
150 method
151 };
152 SystemdErrors::ZJobTypeNotApplicable(method.to_owned(), message)
153 }
154 "org.freedesktop.systemd1.UnitMasked" => {
155 let method = if method.is_empty() {
156 "UnitMasked"
157 } else {
158 method
159 };
160 SystemdErrors::ZUnitMasked(method.to_owned(), message)
161 }
162 "org.freedesktop.zbus.Error" => {
163 SystemdErrors::ZUnitMasked(method.to_owned(), message)
164 }
165 _ => {
166 SystemdErrors::ZMethodError(method.to_owned(), err_code.to_owned(), message)
167 }
168 }
169 }
170
171 _ => SystemdErrors::ZBusError(zb_error),
172 }
173 }
174}
175
176impl From<zbus::Error> for SystemdErrors {
177 fn from(error: zbus::Error) -> Self {
178 SystemdErrors::from((error, ""))
180 }
181}
182
183impl From<zbus::fdo::Error> for SystemdErrors {
184 fn from(error: zbus::fdo::Error) -> Self {
185 match error {
186 zbus::fdo::Error::ServiceUnknown(s) => SystemdErrors::ZFdoServiceUnknowm(s),
187 zbus::fdo::Error::ZBus(err) => err.into(),
188 _ => SystemdErrors::ZBusFdoError(error),
189 }
190 }
191}
192
193impl From<Box<dyn std::error::Error>> for SystemdErrors {
194 fn from(error: Box<dyn std::error::Error>) -> Self {
195 let msg = format!("{error}");
196 SystemdErrors::JournalError(msg)
197 }
198}
199
200impl From<zvariant::Error> for SystemdErrors {
201 fn from(value: zvariant::Error) -> Self {
202 SystemdErrors::ZVariantError(value)
203 }
204}
205
206impl From<tokio::task::JoinError> for SystemdErrors {
207 fn from(_value: tokio::task::JoinError) -> Self {
208 SystemdErrors::Tokio
209 }
210}
211
212impl From<zbus_xml::Error> for SystemdErrors {
213 fn from(value: zbus_xml::Error) -> Self {
214 SystemdErrors::ZXml(value)
215 }
216}
217
218impl From<std::fmt::Error> for SystemdErrors {
219 fn from(value: std::fmt::Error) -> Self {
220 SystemdErrors::Fmt(value)
221 }
222}
223
224impl From<String> for SystemdErrors {
225 fn from(value: String) -> Self {
226 SystemdErrors::Custom(value)
227 }
228}
229
230impl From<&str> for SystemdErrors {
231 fn from(value: &str) -> Self {
232 value.to_owned().into()
233 }
234}