Add getSubtree and getAllProperties functions

These will be used to get callout information from
the inventory.

Also added a helper function getService to find a service
name in the GetSubtree data based on an object
path and interface name.

Tested:  The functions work when called in future commit.

Change-Id: Ib9af94263506041c353fa813167051559c30bcac
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
diff --git a/dbus.cpp b/dbus.cpp
index 17ad210..06b0078 100644
--- a/dbus.cpp
+++ b/dbus.cpp
@@ -21,6 +21,13 @@
 namespace logging
 {
 
+constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
+constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
+constexpr auto MAPPER_IFACE = "xyz.openbmc_project.ObjectMapper";
+constexpr auto PROPERTY_IFACE = "org.freedesktop.DBus.Properties";
+
+using namespace phosphor::logging;
+
 ObjectValueTree getManagedObjects(sdbusplus::bus::bus& bus,
                                   const std::string& service,
                                   const std::string& objPath)
@@ -35,8 +42,8 @@
 
     if (reply.is_method_error())
     {
-        using namespace phosphor::logging;
         log<level::ERR>("Failed to get managed objects",
+                        entry("SERVICE=%s", service.c_str()),
                         entry("PATH=%s", objPath.c_str()));
     }
     else
@@ -46,5 +53,81 @@
 
     return interfaces;
 }
+
+DbusPropertyMap getAllProperties(sdbusplus::bus::bus& bus,
+                                 const std::string& service,
+                                 const std::string& objPath,
+                                 const std::string& interface)
+{
+    DbusPropertyMap properties;
+
+    auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
+                                      PROPERTY_IFACE, "GetAll");
+    method.append(interface);
+    auto reply = bus.call(method);
+
+    if (reply.is_method_error())
+    {
+        log<level::ERR>("Failed to get all properties",
+                        entry("SERVICE=%s", service.c_str()),
+                        entry("PATH=%s", objPath.c_str()),
+                        entry("INTERFACE=%s", interface.c_str()));
+    }
+    else
+    {
+        reply.read(properties);
+    }
+
+    return properties;
+}
+
+DbusSubtree getSubtree(sdbusplus::bus::bus& bus, const std::string& root,
+                       size_t depth, const std::string& interface)
+{
+    DbusSubtree tree;
+
+    auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH, MAPPER_IFACE,
+                                      "GetSubTree");
+    method.append(root);
+    method.append(depth);
+    method.append(std::vector<std::string>({interface}));
+    auto reply = bus.call(method);
+
+    if (reply.is_method_error())
+    {
+        log<level::ERR>("Failed to get subtree", entry("ROOT=%s", root.c_str()),
+                        entry("INTERFACE=%s", interface.c_str()));
+    }
+    else
+    {
+        reply.read(tree);
+    }
+
+    return tree;
+}
+
+DbusService getService(const std::string& objPath, const std::string& interface,
+                       const DbusSubtree& tree)
+{
+    DbusService service;
+
+    auto services = tree.find(objPath);
+    if (services != tree.end())
+    {
+        auto s = std::find_if(services->second.begin(), services->second.end(),
+                              [&interface](const auto& entry) {
+                                  auto i =
+                                      std::find(entry.second.begin(),
+                                                entry.second.end(), interface);
+                                  return i != entry.second.end();
+                              });
+        if (s != services->second.end())
+        {
+            service = s->first;
+        }
+    }
+
+    return service;
+}
 }
 }
diff --git a/dbus.hpp b/dbus.hpp
index d3c6152..392dd8a 100644
--- a/dbus.hpp
+++ b/dbus.hpp
@@ -12,6 +12,8 @@
 
 using DbusInterface = std::string;
 using DbusProperty = std::string;
+using DbusService = std::string;
+using DbusPath = std::string;
 using Value = sdbusplus::message::variant<bool, uint32_t, uint64_t, std::string,
                                           std::vector<std::string>>;
 
@@ -22,6 +24,9 @@
 using ObjectValueTree =
     std::map<sdbusplus::message::object_path, DbusInterfaceMap>;
 
+using DbusSubtree =
+    std::map<DbusPath, std::map<DbusService, DbusInterfaceList>>;
+
 /**
  * Returns the managed objects for an object path and service
  *
@@ -37,5 +42,53 @@
 ObjectValueTree getManagedObjects(sdbusplus::bus::bus& bus,
                                   const std::string& service,
                                   const std::string& objPath);
+
+/**
+ * Returns the subtree for a root, depth, and interface.
+ *
+ * Returns an empty map if there are any failures.
+ *
+ * @param[in] bus - the D-Bus object
+ * @param[in] root - the point from which to provide results
+ * @param[in] depth - the number of path elements to descend
+ *
+ * @return DbusSubtree - A map of object paths to their
+ *                       services and interfaces.
+ */
+DbusSubtree getSubtree(sdbusplus::bus::bus& bus, const std::string& root,
+                       size_t depth, const std::string& interface);
+
+/**
+ * Get the D-Bus service name for the object path and interface from
+ * the data returned from a GetSubTree call.
+ *
+ * Returns an empty string if the service can't be found.
+ *
+ * @param[in] objPath - the D-Bus object path
+ * @param[in] interface - the D-Bus interface name
+ * @param[in] tree - the D-Bus GetSubTree response
+ *
+ * @return string - the service name
+ */
+DbusService getService(const std::string& objPath, const std::string& interface,
+                       const DbusSubtree& tree);
+
+/**
+ * Returns all properties on a particular interface on a
+ * particular D-Bus object.
+ *
+ * Returns an empty map if there are any failures.
+ *
+ * @param[in] bus - the D-Bus object
+ * @param[in] service - the D-Bus service name
+ * @param[in] objPath - the D-Bus object path
+ * @param[in] interface - the D-Bus interface name
+ *
+ * @return DbusPropertyMap - The map of property names to values
+ */
+DbusPropertyMap getAllProperties(sdbusplus::bus::bus& bus,
+                                 const std::string& service,
+                                 const std::string& objPath,
+                                 const std::string& interface);
 }
 }