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