regulators: Handle expected D-Bus exceptions
When hardware is not present, it can appear multiple ways on D-Bus:
* Object path does not exist
* Object path exists, but Inventory.Item interface not implemented
* Inventory.Item interface implemented with Present value of false
The first two cases result in a D-Bus exception being thrown when trying
to obtain the value of the Present property.
Enhance the DBusPresenceService class to catch these exceptions and
treat them as a false Presence value.
Tested:
* Tested where hardware present
* Tested where hardware not present
* Object path and interface/property exist
* Object path exists
* Object path does not exist
* For full test plan, see
https://gist.github.com/smccarney/d3d7384700abcc5abf436e2b859d98e5
Signed-off-by: Shawn McCarney <shawnmm@us.ibm.com>
Change-Id: I543a4c16984dea3657b8024dedd1060dda4319e2
diff --git a/phosphor-regulators/src/presence_service.cpp b/phosphor-regulators/src/presence_service.cpp
index 7233d28..9e15b03 100644
--- a/phosphor-regulators/src/presence_service.cpp
+++ b/phosphor-regulators/src/presence_service.cpp
@@ -24,6 +24,7 @@
bool DBusPresenceService::isPresent(const std::string& inventoryPath)
{
+ // Initially assume hardware is not present
bool present{false};
// Try to find cached presence value
@@ -35,8 +36,24 @@
else
{
// Get presence from D-Bus interface/property
- util::getProperty(INVENTORY_IFACE, PRESENT_PROP, inventoryPath,
- INVENTORY_MGR_IFACE, bus, present);
+ try
+ {
+ util::getProperty(INVENTORY_IFACE, PRESENT_PROP, inventoryPath,
+ INVENTORY_MGR_IFACE, bus, present);
+ }
+ catch (const sdbusplus::exception::SdBusError& e)
+ {
+ // If exception type is expected and indicates hardware not present
+ if (isExpectedException(e))
+ {
+ present = false;
+ }
+ else
+ {
+ // Re-throw unexpected exception
+ throw;
+ }
+ }
// Cache presence value
cache[inventoryPath] = present;
@@ -45,4 +62,36 @@
return present;
}
+bool DBusPresenceService::isExpectedException(
+ const sdbusplus::exception::SdBusError& e)
+{
+ // Initially assume exception is not one of the expected types
+ bool isExpected{false};
+
+ // If the D-Bus error name is set within the exception
+ if (e.name() != nullptr)
+ {
+ // Check if the error name is one of the expected values when hardware
+ // is not present.
+ //
+ // Sometimes the object path does not exist. Sometimes the object path
+ // exists, but it does not implement the D-Bus interface that contains
+ // the present property. Both of these cases result in exceptions.
+ //
+ // In the case where the interface is not implemented, the systemd
+ // documentation seems to indicate that the error name should be
+ // SD_BUS_ERROR_UNKNOWN_INTERFACE. However, in OpenBMC the
+ // SD_BUS_ERROR_UNKNOWN_PROPERTY error name can occur.
+ std::string name = e.name();
+ if ((name == SD_BUS_ERROR_UNKNOWN_OBJECT) ||
+ (name == SD_BUS_ERROR_UNKNOWN_INTERFACE) ||
+ (name == SD_BUS_ERROR_UNKNOWN_PROPERTY))
+ {
+ isExpected = true;
+ }
+ }
+
+ return isExpected;
+}
+
} // namespace phosphor::power::regulators
diff --git a/phosphor-regulators/src/presence_service.hpp b/phosphor-regulators/src/presence_service.hpp
index 142e132..c81a671 100644
--- a/phosphor-regulators/src/presence_service.hpp
+++ b/phosphor-regulators/src/presence_service.hpp
@@ -16,6 +16,7 @@
#pragma once
#include <sdbusplus/bus.hpp>
+#include <sdbusplus/exception.hpp>
#include <map>
#include <string>
@@ -97,6 +98,14 @@
private:
/**
+ * Returns whether the specified D-Bus exception is one of the expected
+ * types that can be thrown if hardware is not present.
+ *
+ * @return true if exception type is expected, false otherwise
+ */
+ bool isExpectedException(const sdbusplus::exception::SdBusError& e);
+
+ /**
* D-Bus bus object.
*/
sdbusplus::bus::bus& bus;