1 #pragma once 2 3 #include <systemd/sd-bus.h> 4 5 #include <nlohmann/json_fwd.hpp> 6 #include <sdbusplus/sdbus.hpp> 7 #include <sdbusplus/utility/consteval_string.hpp> 8 9 #include <exception> 10 #include <source_location> 11 #include <string> 12 13 namespace sdbusplus 14 { 15 16 enum class UnpackErrorReason 17 { 18 missingProperty, 19 wrongType 20 }; 21 22 namespace exception 23 { 24 25 /** Base exception class for all sdbusplus exceptions, including those created 26 * by the bindings. */ 27 struct exception : public std::exception 28 { 29 virtual const char* name() const noexcept = 0; 30 virtual const char* description() const noexcept = 0; 31 virtual int get_errno() const noexcept = 0; 32 33 virtual int set_error(sd_bus_error*) const; 34 virtual int set_error(SdBusInterface*, sd_bus_error*) const; 35 36 private: 37 // This unused function is to ensure that the vtable for this class is 38 // properly emitted when `-flto=auto` is used, which is the default in 39 // Yocto builds. Without this, the vtable is a hidden symbol and no 40 // users can inherit from our exception type directly. 41 virtual void unused() const noexcept; 42 }; 43 44 /** base exception class for all errors created by the sdbus++ generator */ 45 struct generated_exception : public exception 46 { 47 int get_errno() const noexcept override; 48 }; 49 50 /** Non-templated base for all new errors and events created by the sdbus++ 51 * generator */ 52 struct generated_event_base : public generated_exception 53 { 54 virtual auto to_json() const -> nlohmann::json = 0; 55 virtual int severity() const noexcept = 0; 56 }; 57 58 /** base exception for all new errors and events created by the sdbus++ 59 * generator */ 60 template <typename Event> 61 struct generated_event : public generated_event_base 62 { namesdbusplus::exception::generated_event63 const char* name() const noexcept override 64 { 65 return Event::errName; 66 } 67 descriptionsdbusplus::exception::generated_event68 const char* description() const noexcept override 69 { 70 return Event::errDesc; 71 } 72 whatsdbusplus::exception::generated_event73 const char* what() const noexcept override 74 { 75 return Event::errWhat; 76 } 77 get_errnosdbusplus::exception::generated_event78 int get_errno() const noexcept override 79 { 80 return Event::errErrno; 81 } 82 severitysdbusplus::exception::generated_event83 int severity() const noexcept override 84 { 85 return Event::errSeverity; 86 } 87 88 template <utility::details::consteval_string_holder V> 89 using metadata_t = utility::consteval_string<V>; 90 91 protected: 92 mutable std::string jsonString; 93 }; 94 95 /** base exception class for all errors generated by sdbusplus itself. */ 96 struct internal_exception : public exception 97 {}; 98 99 /** Exception for when an underlying sd_bus method call fails. */ 100 class SdBusError final : public internal_exception 101 { 102 public: 103 /** Errno must be positive */ 104 SdBusError(int error, const char* prefix, 105 SdBusInterface* intf = &sdbus_impl); 106 SdBusError(int error, std::string&& prefix, 107 SdBusInterface* intf = &sdbus_impl); 108 /** Becomes the owner of the error */ 109 SdBusError(sd_bus_error* error, const char* prefix, 110 SdBusInterface* intf = &sdbus_impl); 111 112 SdBusError(const SdBusError&) = delete; 113 SdBusError& operator=(const SdBusError&) = delete; 114 SdBusError(SdBusError&& other); 115 SdBusError& operator=(SdBusError&& other); 116 ~SdBusError() override; 117 118 const char* name() const noexcept override; 119 const char* description() const noexcept override; 120 const char* what() const noexcept override; 121 int get_errno() const noexcept override; 122 const sd_bus_error* get_error() const noexcept; 123 124 private: 125 sd_bus_error error; 126 std::string full_message; 127 SdBusInterface* intf; 128 129 /** Populates the full_message from the stored 130 * error and the passed in prefix. */ 131 void populateMessage(std::string&& prefix); 132 133 /** Helper to reduce duplicate move logic */ 134 void move(SdBusError&& other); 135 }; 136 137 /** Exception for when an invalid conversion from string to enum is 138 * attempted. */ 139 struct InvalidEnumString final : public internal_exception 140 { 141 static constexpr auto errName = 142 "xyz.openbmc_project.sdbusplus.Error.InvalidEnumString"; 143 static constexpr auto errDesc = 144 "An enumeration mapping was attempted for which no valid enumeration " 145 "value exists."; 146 static constexpr auto errWhat = 147 "xyz.openbmc_project.sdbusplus.Error.InvalidEnumString: " 148 "An enumeration mapping was attempted for which no valid enumeration " 149 "value exists."; 150 151 const char* name() const noexcept override; 152 const char* description() const noexcept override; 153 const char* what() const noexcept override; 154 int get_errno() const noexcept override; 155 }; 156 157 /** Exception for when unpackProperties cannot find given property in provided 158 * container */ 159 class UnpackPropertyError final : public internal_exception 160 { 161 public: 162 UnpackPropertyError(std::string_view propertyName, 163 const UnpackErrorReason reason); 164 165 static constexpr auto errName = 166 "xyz.openbmc_project.sdbusplus.Error.UnpackPropertyError"; 167 static constexpr auto errDesc = 168 "unpackProperties failed to unpack one of requested properties."; 169 static constexpr auto errWhat = 170 "xyz.openbmc_project.sdbusplus.Error.UnpackPropertyError: " 171 "unpackProperties failed to unpack one of requested properties."; 172 173 const char* name() const noexcept override; 174 const char* description() const noexcept override; 175 const char* what() const noexcept override; 176 int get_errno() const noexcept override; 177 178 const std::string propertyName; 179 const UnpackErrorReason reason; 180 181 private: 182 const std::string errWhatDetailed; 183 }; 184 185 class UnhandledStop final : public internal_exception 186 { 187 public: 188 static constexpr auto errName = 189 "xyz.openbmc_project.sdbusplus.Error.UnhandledStop"; 190 static constexpr auto errDesc = 191 "An async Sender failed to handle a stop condition."; 192 static constexpr auto errWhat = 193 "xyz.openbmc_project.sdbusplus.Error.UnhandledStop: " 194 "An async Sender failed to handle a stop condition."; 195 196 const char* name() const noexcept override; 197 const char* description() const noexcept override; 198 const char* what() const noexcept override; 199 int get_errno() const noexcept override; 200 }; 201 202 /** Throw a generated_event from the JSON representation. 203 * 204 * @param[in] j - JSON representation of the event. 205 * @param[in] source - The source code location of the origin. 206 */ 207 void throw_via_json( 208 const nlohmann::json& j, 209 const std::source_location& source = std::source_location::current()); 210 211 /** Get the list of known events by name. */ 212 auto known_events() -> std::vector<std::string>; 213 214 } // namespace exception 215 216 using exception_t = exception::exception; 217 using internal_exception_t = exception::internal_exception; 218 219 } // namespace sdbusplus 220