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