xref: /openbmc/sdbusplus/src/exception.cpp (revision b08d14dd)
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