exception: Add an exception for holding sd_bus_errors
This enables us to return more error information about the underlying
sd_bus api call that failed. This will make error output more verbose
and enable us to apply more granular filters to specific dbus related
errors.
Change-Id: I3811139011753d7bd596b46cb69da68f7826ed7b
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/sdbusplus/exception.cpp b/sdbusplus/exception.cpp
index e3a5ac9..5e99abb 100644
--- a/sdbusplus/exception.cpp
+++ b/sdbusplus/exception.cpp
@@ -5,6 +5,83 @@
namespace exception
{
+SdBusError::SdBusError(int error, const char* prefix) :
+ std::system_error(error, std::generic_category()), error(SD_BUS_ERROR_NULL)
+{
+ if (error == ENOMEM ||
+ sd_bus_error_set_errno(&this->error, error) == -ENOMEM)
+ {
+ throw std::bad_alloc();
+ }
+
+ populateMessage(prefix);
+}
+
+SdBusError::SdBusError(sd_bus_error error, const char* prefix) :
+ std::system_error(sd_bus_error_get_errno(&error), std::generic_category()),
+ error(error)
+{
+ populateMessage(prefix);
+}
+
+SdBusError::SdBusError(SdBusError&& other)
+{
+ move(std::move(other));
+}
+
+SdBusError& SdBusError::operator=(SdBusError&& other)
+{
+ if (this != &other)
+ {
+ move(std::move(other));
+ }
+ return *this;
+}
+
+SdBusError::~SdBusError()
+{
+ sd_bus_error_free(&error);
+}
+
+const char* SdBusError::name() const noexcept
+{
+ return error.name;
+}
+
+const char* SdBusError::description() const noexcept
+{
+ return error.message;
+}
+
+const char* SdBusError::what() const noexcept
+{
+ return full_message.c_str();
+}
+
+void SdBusError::populateMessage(const char* prefix)
+{
+ full_message = prefix;
+ if (error.name)
+ {
+ full_message += ": ";
+ full_message += error.name;
+ }
+ if (error.message)
+ {
+ full_message += ": ";
+ full_message += error.message;
+ }
+}
+
+void SdBusError::move(SdBusError&& other)
+{
+ sd_bus_error_free(&error);
+ error = other.error;
+ other.error = SD_BUS_ERROR_NULL;
+
+ full_message = std::move(other.full_message);
+}
+
const char* InvalidEnumString::name() const noexcept
{
return errName;
diff --git a/sdbusplus/exception.hpp b/sdbusplus/exception.hpp
index 37dbac9..06f488e 100644
--- a/sdbusplus/exception.hpp
+++ b/sdbusplus/exception.hpp
@@ -1,6 +1,9 @@
#pragma once
#include <exception>
+#include <string>
+#include <system_error>
+#include <systemd/sd-bus.h>
namespace sdbusplus
{
@@ -21,6 +24,37 @@
{
};
+/** Exception for when an underlying sd_bus method call fails. */
+class SdBusError final : public internal_exception, public std::system_error
+{
+ public:
+ /** Errno must be positive */
+ SdBusError(int error, const char* prefix);
+ /** Becomes the owner of the error */
+ SdBusError(sd_bus_error error, const char* prefix);
+
+ SdBusError(const SdBusError&) = delete;
+ SdBusError& operator=(const SdBusError&) = delete;
+ SdBusError(SdBusError&& other);
+ SdBusError& operator=(SdBusError&& other);
+ virtual ~SdBusError();
+
+ const char* name() const noexcept override;
+ const char* description() const noexcept override;
+ const char* what() const noexcept override;
+
+ private:
+ sd_bus_error error;
+ std::string full_message;
+
+ /** Populates the full_message from the stored
+ * error and the passed in prefix. */
+ void populateMessage(const char* 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