fru: remove assumption on object owner

The fru read yaml configuration allows specifying a dbus path and a dbus
interface.  Dynamically look up what service provides that interface
with that dbus path.  Continue supporting partial paths for devices
owned by the Inventory Manager.

Tested: Verified the module now reads the FRU properties over dbus if
the object is owned by another service (exported via entity-manager).

Signed-off-by: Patrick Venture <venture@google.com>
Change-Id: I5c0aeb11d0b33fab437a55dea3351a47feab0783
diff --git a/read_fru_data.cpp b/read_fru_data.cpp
index 327f552..270accf 100644
--- a/read_fru_data.cpp
+++ b/read_fru_data.cpp
@@ -23,6 +23,7 @@
 std::unique_ptr<sdbusplus::bus::match_t> matchPtr
     __attribute__((init_priority(101)));
 
+static constexpr auto XYZ_PREFIX = "/xyz/openbmc_project/";
 static constexpr auto INV_INTF = "xyz.openbmc_project.Inventory.Manager";
 static constexpr auto OBJ_PATH = "/xyz/openbmc_project/inventory";
 static constexpr auto PROP_INTF = "org.freedesktop.DBus.Properties";
@@ -49,21 +50,38 @@
 {
     ipmi::PropertyMap properties;
     sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
-    auto service = ipmi::getService(bus, INV_INTF, OBJ_PATH);
-    std::string objPath = OBJ_PATH + path;
+    std::string service;
+    std::string objPath;
+
+    // Is the path the full dbus path?
+    if (path.find(XYZ_PREFIX) != std::string::npos)
+    {
+        service = ipmi::getService(bus, intf, path);
+        objPath = path;
+    }
+    else
+    {
+        service = ipmi::getService(bus, INV_INTF, OBJ_PATH);
+        objPath = OBJ_PATH + path;
+    }
+
     auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
                                       PROP_INTF, "GetAll");
     method.append(intf);
-    auto reply = bus.call(method);
-    if (reply.is_method_error())
+    try
+    {
+        auto reply = bus.call(method);
+        reply.read(properties);
+    }
+    catch (const sdbusplus::exception::SdBusError& e)
     {
         // If property is not found simply return empty value
-        log<level::ERR>("Error in reading property values from inventory",
+        log<level::ERR>("Error in reading property values",
+                        entry("EXCEPTION=%s", e.what()),
                         entry("INTERFACE=%s", intf.c_str()),
                         entry("PATH=%s", objPath.c_str()));
-        return properties;
     }
-    reply.read(properties);
+
     return properties;
 }