blob: 80f0d22ad23cac94d4cf58731f43064feb96bd17 [file] [log] [blame]
#pragma once
#include <systemd/sd-bus.h>
#include <nlohmann/json_fwd.hpp>
#include <sdbusplus/sdbus.hpp>
#include <sdbusplus/utility/consteval_string.hpp>
#include <exception>
#include <string>
namespace sdbusplus
{
enum class UnpackErrorReason
{
missingProperty,
wrongType
};
namespace exception
{
/** Base exception class for all sdbusplus exceptions, including those created
* by the bindings. */
struct exception : public std::exception
{
virtual const char* name() const noexcept = 0;
virtual const char* description() const noexcept = 0;
virtual int get_errno() const noexcept = 0;
virtual int set_error(sd_bus_error*) const;
virtual int set_error(SdBusInterface*, sd_bus_error*) const;
private:
// This unused function is to ensure that the vtable for this class is
// properly emitted when `-flto=auto` is used, which is the default in
// Yocto builds. Without this, the vtable is a hidden symbol and no
// users can inherit from our exception type directly.
virtual void unused() const noexcept;
};
/** base exception class for all errors created by the sdbus++ generator */
struct generated_exception : public exception
{
int get_errno() const noexcept override;
};
/** Non-templated base for all new errors and events created by the sdbus++
* generator */
struct generated_event_base : public generated_exception
{
virtual auto to_json() const -> nlohmann::json = 0;
virtual int severity() const noexcept = 0;
};
/** base exception for all new errors and events created by the sdbus++
* generator */
template <typename Event>
struct generated_event : public generated_event_base
{
const char* name() const noexcept override
{
return Event::errName;
}
const char* description() const noexcept override
{
return Event::errDesc;
}
const char* what() const noexcept override
{
return Event::errWhat;
}
int get_errno() const noexcept override
{
return Event::errErrno;
}
int severity() const noexcept override
{
return Event::errSeverity;
}
template <utility::details::consteval_string_holder V>
using metadata_t = utility::consteval_string<V>;
protected:
mutable std::string jsonString;
};
/** base exception class for all errors generated by sdbusplus itself. */
struct internal_exception : public exception
{};
/** Exception for when an underlying sd_bus method call fails. */
class SdBusError final : public internal_exception
{
public:
/** Errno must be positive */
SdBusError(int error, const char* prefix,
SdBusInterface* intf = &sdbus_impl);
SdBusError(int error, std::string&& prefix,
SdBusInterface* intf = &sdbus_impl);
/** Becomes the owner of the error */
SdBusError(sd_bus_error* error, const char* prefix,
SdBusInterface* intf = &sdbus_impl);
SdBusError(const SdBusError&) = delete;
SdBusError& operator=(const SdBusError&) = delete;
SdBusError(SdBusError&& other);
SdBusError& operator=(SdBusError&& other);
~SdBusError() override;
const char* name() const noexcept override;
const char* description() const noexcept override;
const char* what() const noexcept override;
int get_errno() const noexcept override;
const sd_bus_error* get_error() const noexcept;
private:
sd_bus_error error;
std::string full_message;
SdBusInterface* intf;
/** Populates the full_message from the stored
* error and the passed in prefix. */
void populateMessage(std::string&& prefix);
/** Helper to reduce duplicate move logic */
void move(SdBusError&& other);
};
/** Exception for when an invalid conversion from string to enum is
* attempted. */
struct InvalidEnumString final : public internal_exception
{
static constexpr auto errName =
"xyz.openbmc_project.sdbusplus.Error.InvalidEnumString";
static constexpr auto errDesc =
"An enumeration mapping was attempted for which no valid enumeration "
"value exists.";
static constexpr auto errWhat =
"xyz.openbmc_project.sdbusplus.Error.InvalidEnumString: "
"An enumeration mapping was attempted for which no valid enumeration "
"value exists.";
const char* name() const noexcept override;
const char* description() const noexcept override;
const char* what() const noexcept override;
int get_errno() const noexcept override;
};
/** Exception for when unpackProperties cannot find given property in provided
* container */
class UnpackPropertyError final : public internal_exception
{
public:
UnpackPropertyError(std::string_view propertyName,
const UnpackErrorReason reason);
static constexpr auto errName =
"xyz.openbmc_project.sdbusplus.Error.UnpackPropertyError";
static constexpr auto errDesc =
"unpackProperties failed to unpack one of requested properties.";
static constexpr auto errWhat =
"xyz.openbmc_project.sdbusplus.Error.UnpackPropertyError: "
"unpackProperties failed to unpack one of requested properties.";
const char* name() const noexcept override;
const char* description() const noexcept override;
const char* what() const noexcept override;
int get_errno() const noexcept override;
const std::string propertyName;
const UnpackErrorReason reason;
private:
const std::string errWhatDetailed;
};
class UnhandledStop final : public internal_exception
{
public:
static constexpr auto errName =
"xyz.openbmc_project.sdbusplus.Error.UnhandledStop";
static constexpr auto errDesc =
"An async Sender failed to handle a stop condition.";
static constexpr auto errWhat =
"xyz.openbmc_project.sdbusplus.Error.UnhandledStop: "
"An async Sender failed to handle a stop condition.";
const char* name() const noexcept override;
const char* description() const noexcept override;
const char* what() const noexcept override;
int get_errno() const noexcept override;
};
} // namespace exception
using exception_t = exception::exception;
using internal_exception_t = exception::internal_exception;
} // namespace sdbusplus