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