1 #include <sdbusplus/exception.hpp>
2 #include <sdbusplus/sdbuspp_support/event.hpp>
3
4 #include <cerrno>
5 #include <stdexcept>
6 #include <utility>
7
8 #ifdef __clang__
9 #pragma clang diagnostic push
10 #pragma clang diagnostic ignored "-Wc99-extensions"
11 #endif
12
13 namespace sdbusplus::exception
14 {
15
unused() const16 void exception::unused() const noexcept {}
17
set_error(sd_bus_error * e) const18 int exception::set_error(sd_bus_error* e) const
19 {
20 return sd_bus_error_set(e, name(), description());
21 }
22
set_error(SdBusInterface * i,sd_bus_error * e) const23 int exception::set_error(SdBusInterface* i, sd_bus_error* e) const
24 {
25 return i->sd_bus_error_set(e, name(), description());
26 }
27
get_errno() const28 int generated_exception::get_errno() const noexcept
29 {
30 return EIO;
31 }
32
SdBusError(int error_in,const char * prefix,SdBusInterface * intf_in)33 SdBusError::SdBusError(int error_in, const char* prefix,
34 SdBusInterface* intf_in) :
35 SdBusError(error_in, std::string(prefix), intf_in)
36 {}
37
SdBusError(int error_in,std::string && prefix,SdBusInterface * intf_in)38 SdBusError::SdBusError(int error_in, std::string&& prefix,
39 SdBusInterface* intf_in) :
40 error(SD_BUS_ERROR_NULL), intf(intf_in)
41 {
42 // We can't check the output of intf->sd_bus_error_set_errno() because
43 // it returns the input errorcode. We don't want to try and guess
44 // possible error statuses. Instead, check to see if the error was
45 // constructed to determine success.
46 intf->sd_bus_error_set_errno(&this->error, error_in);
47 if (!intf->sd_bus_error_is_set(&this->error))
48 {
49 throw std::runtime_error("Failed to create SdBusError");
50 }
51
52 populateMessage(std::move(prefix));
53 }
54
SdBusError(sd_bus_error * error_in,const char * prefix,SdBusInterface * intf_in)55 SdBusError::SdBusError(sd_bus_error* error_in, const char* prefix,
56 SdBusInterface* intf_in) :
57 error(*error_in), intf(intf_in)
58 {
59 // We own the error so remove the caller's reference
60 *error_in = SD_BUS_ERROR_NULL;
61
62 populateMessage(std::string(prefix));
63 }
64
SdBusError(SdBusError && other)65 SdBusError::SdBusError(SdBusError&& other) : error(SD_BUS_ERROR_NULL)
66 {
67 move(std::move(other));
68 }
69
operator =(SdBusError && other)70 SdBusError& SdBusError::operator=(SdBusError&& other)
71 {
72 if (this != &other)
73 {
74 move(std::move(other));
75 }
76 return *this;
77 }
78
~SdBusError()79 SdBusError::~SdBusError()
80 {
81 intf->sd_bus_error_free(&error);
82 }
83
name() const84 const char* SdBusError::name() const noexcept
85 {
86 return error.name;
87 }
88
description() const89 const char* SdBusError::description() const noexcept
90 {
91 return error.message;
92 }
93
what() const94 const char* SdBusError::what() const noexcept
95 {
96 return full_message.c_str();
97 }
98
get_errno() const99 int SdBusError::get_errno() const noexcept
100 {
101 return intf->sd_bus_error_get_errno(&this->error);
102 }
103
get_error() const104 const sd_bus_error* SdBusError::get_error() const noexcept
105 {
106 return &error;
107 }
108
populateMessage(std::string && prefix)109 void SdBusError::populateMessage(std::string&& prefix)
110 {
111 full_message = std::move(prefix);
112 if (error.name)
113 {
114 full_message += ": ";
115 full_message += error.name;
116 }
117 if (error.message)
118 {
119 full_message += ": ";
120 full_message += error.message;
121 }
122 }
123
move(SdBusError && other)124 void SdBusError::move(SdBusError&& other)
125 {
126 intf = std::move(other.intf);
127
128 intf->sd_bus_error_free(&error);
129 error = other.error;
130 other.error = SD_BUS_ERROR_NULL;
131
132 full_message = std::move(other.full_message);
133 }
134
name() const135 const char* InvalidEnumString::name() const noexcept
136 {
137 return errName;
138 }
139
description() const140 const char* InvalidEnumString::description() const noexcept
141 {
142 return errDesc;
143 }
144
what() const145 const char* InvalidEnumString::what() const noexcept
146 {
147 return errWhat;
148 }
149
get_errno() const150 int InvalidEnumString::get_errno() const noexcept
151 {
152 return EINVAL;
153 }
154
unpackErrorReasonToString(const UnpackErrorReason reason)155 static std::string unpackErrorReasonToString(const UnpackErrorReason reason)
156 {
157 switch (reason)
158 {
159 case UnpackErrorReason::missingProperty:
160 return "Missing property";
161 case UnpackErrorReason::wrongType:
162 return "Type not matched";
163 }
164 return "Unknown";
165 }
166
UnpackPropertyError(std::string_view propertyNameIn,const UnpackErrorReason reasonIn)167 UnpackPropertyError::UnpackPropertyError(std::string_view propertyNameIn,
168 const UnpackErrorReason reasonIn) :
169 propertyName(propertyNameIn), reason(reasonIn),
170 errWhatDetailed(std::string(errWhat) + " PropertyName: '" + propertyName +
171 "', Reason: '" + unpackErrorReasonToString(reason) + "'.")
172 {}
173
name() const174 const char* UnpackPropertyError::name() const noexcept
175 {
176 return errName;
177 }
178
description() const179 const char* UnpackPropertyError::description() const noexcept
180 {
181 return errDesc;
182 }
183
what() const184 const char* UnpackPropertyError::what() const noexcept
185 {
186 return errWhatDetailed.c_str();
187 }
188
get_errno() const189 int UnpackPropertyError::get_errno() const noexcept
190 {
191 return EINVAL;
192 }
193
name() const194 const char* UnhandledStop::name() const noexcept
195 {
196 return errName;
197 }
198
description() const199 const char* UnhandledStop::description() const noexcept
200 {
201 return errDesc;
202 }
203
what() const204 const char* UnhandledStop::what() const noexcept
205 {
206 return errWhat;
207 }
208
get_errno() const209 int UnhandledStop::get_errno() const noexcept
210 {
211 return ECANCELED;
212 }
213
214 static std::unordered_map<std::string, sdbusplus::sdbuspp::register_hook>
215 event_hooks = {};
216
throw_via_json(const nlohmann::json & j,const std::source_location & source)217 void throw_via_json(const nlohmann::json& j, const std::source_location& source)
218 {
219 for (const auto& i : j.items())
220 {
221 if (auto it = event_hooks.find(i.key()); it != event_hooks.end())
222 {
223 it->second(j, source);
224 }
225 }
226 }
227
known_events()228 auto known_events() -> std::vector<std::string>
229 {
230 std::vector<std::string> result{};
231
232 for (const auto& [key, _] : event_hooks)
233 {
234 result.emplace_back(key);
235 }
236
237 std::ranges::sort(result);
238
239 return result;
240 }
241
242 } // namespace sdbusplus::exception
243
244 namespace sdbusplus::sdbuspp
245 {
246
register_event(const std::string & event,register_hook throw_hook)247 void register_event(const std::string& event, register_hook throw_hook)
248 {
249 sdbusplus::exception::event_hooks.emplace(event, throw_hook);
250 }
251
252 } // namespace sdbusplus::sdbuspp
253
254 #ifdef __clang__
255 #pragma clang diagnostic pop
256 #endif
257