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 16 void exception::unused() const noexcept {} 17 18 int exception::set_error(sd_bus_error* e) const 19 { 20 return sd_bus_error_set(e, name(), description()); 21 } 22 23 int exception::set_error(SdBusInterface* i, sd_bus_error* e) const 24 { 25 return i->sd_bus_error_set(e, name(), description()); 26 } 27 28 int generated_exception::get_errno() const noexcept 29 { 30 return EIO; 31 } 32 33 SdBusError::SdBusError(int error_in, const char* prefix, 34 SdBusInterface* intf_in) : 35 SdBusError(error_in, std::string(prefix), intf_in) 36 {} 37 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 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 65 SdBusError::SdBusError(SdBusError&& other) : error(SD_BUS_ERROR_NULL) 66 { 67 move(std::move(other)); 68 } 69 70 SdBusError& SdBusError::operator=(SdBusError&& other) 71 { 72 if (this != &other) 73 { 74 move(std::move(other)); 75 } 76 return *this; 77 } 78 79 SdBusError::~SdBusError() 80 { 81 intf->sd_bus_error_free(&error); 82 } 83 84 const char* SdBusError::name() const noexcept 85 { 86 return error.name; 87 } 88 89 const char* SdBusError::description() const noexcept 90 { 91 return error.message; 92 } 93 94 const char* SdBusError::what() const noexcept 95 { 96 return full_message.c_str(); 97 } 98 99 int SdBusError::get_errno() const noexcept 100 { 101 return intf->sd_bus_error_get_errno(&this->error); 102 } 103 104 const sd_bus_error* SdBusError::get_error() const noexcept 105 { 106 return &error; 107 } 108 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 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 135 const char* InvalidEnumString::name() const noexcept 136 { 137 return errName; 138 } 139 140 const char* InvalidEnumString::description() const noexcept 141 { 142 return errDesc; 143 } 144 145 const char* InvalidEnumString::what() const noexcept 146 { 147 return errWhat; 148 } 149 150 int InvalidEnumString::get_errno() const noexcept 151 { 152 return EINVAL; 153 } 154 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 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 174 const char* UnpackPropertyError::name() const noexcept 175 { 176 return errName; 177 } 178 179 const char* UnpackPropertyError::description() const noexcept 180 { 181 return errDesc; 182 } 183 184 const char* UnpackPropertyError::what() const noexcept 185 { 186 return errWhatDetailed.c_str(); 187 } 188 189 int UnpackPropertyError::get_errno() const noexcept 190 { 191 return EINVAL; 192 } 193 194 const char* UnhandledStop::name() const noexcept 195 { 196 return errName; 197 } 198 199 const char* UnhandledStop::description() const noexcept 200 { 201 return errDesc; 202 } 203 204 const char* UnhandledStop::what() const noexcept 205 { 206 return errWhat; 207 } 208 209 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 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 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 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