Create OCC pass-through objects

Create OCC pass-through d-bus objects when corresponding CPU objects are
created in the inventory.

Resolves openbmc/openbmc#1450.

Change-Id: I8da879f51ebef8dcc3d25358def81c5e0dce0617
Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
diff --git a/occ_pass_through.hpp b/occ_pass_through.hpp
index 070e371..c9f6566 100644
--- a/occ_pass_through.hpp
+++ b/occ_pass_through.hpp
@@ -1,14 +1,20 @@
 #pragma once
 
 #include <string>
+#include <cstring>
+#include <map>
 #include <vector>
+#include <experimental/filesystem>
 #include <unistd.h>
 #include <sdbusplus/bus.hpp>
+#include <functional>
 #include <sdbusplus/server/object.hpp>
 #include <org/open_power/OCC/PassThrough/server.hpp>
 #include "config.h"
 #include "file.hpp"
 
+namespace sdbusRule = sdbusplus::bus::match::rules;
+
 namespace open_power
 {
 namespace occ
@@ -16,20 +22,86 @@
 namespace pass_through
 {
 
-/** @brief Make occ pass-through d-bus object pathname
- *  @param[in] occ - occ name
- *  @returns occ pass-through path
- */
-inline auto object(const std::string& occ)
-{
-    return std::string(OCC_PASS_THROUGH_ROOT) +
-           '/' +
-           occ;
-}
+class PassThrough;
 
-/** @brief Put occ pass through objects on the bus
+namespace manager
+{
+
+/** @class Manager
+ *  @brief Builds and manages OCC pass-through objects
  */
-void run();
+struct Manager
+{
+    public:
+        Manager() = delete;
+        Manager(const Manager&) = delete;
+        Manager& operator=(const Manager&) = delete;
+        Manager(Manager&&) = default;
+        Manager& operator=(Manager&&) = default;
+        ~Manager() = default;
+
+        /** @brief Ctor - Add OCC pass-through objects on the bus. Create
+         *         OCC objects when corresponding CPU inventory is created.
+         *  @param[in] bus - handle to the bus
+         */
+        Manager(sdbusplus::bus::bus& bus):
+            bus(bus)
+        {
+            for (auto id = 0; id < MAX_CPUS; ++id)
+            {
+                auto path = std::string(CPU_PATH) + std::to_string(id);
+                cpuMatches.emplace_back(
+                    bus,
+                    sdbusRule::interfacesAdded() +
+                    sdbusRule::argNpath(0, path),
+                    std::bind(std::mem_fn(&Manager::cpuCreated),
+                              this, std::placeholders::_1));
+            }
+        }
+
+        /** @brief Callback that responds to cpu creation in the inventory -
+         *         by creating the occ passthrough object.
+         *
+         *  @param[in] msg - bus message
+         *
+         *  @returns 0 to indicate success
+         */
+        int cpuCreated(sdbusplus::message::message& msg)
+        {
+            namespace fs = std::experimental::filesystem;
+
+            sdbusplus::message::object_path o;
+            msg.read(o);
+            fs::path cpuPath(std::string(std::move(o)));
+            auto cpu = cpuPath.filename();
+
+            auto occPath = fs::path(OCC_PASS_THROUGH_ROOT);
+            std::string name{cpu.c_str()};
+            auto index = name.find(CPU_NAME);
+            name.replace(index, std::strlen(CPU_NAME), OCC_NAME);
+            occPath /= name;
+
+            objects.emplace_back(
+                std::make_unique<PassThrough>(
+                    bus,
+                    occPath.c_str()));
+
+            return 0;
+        }
+
+    private:
+        /** @brief reference to the bus */
+        sdbusplus::bus::bus& bus;
+
+        /** @brief OCC pass-through objects */
+        std::vector<std::unique_ptr<PassThrough>> objects;
+
+        /** @brief sbdbusplus match objects */
+        std::vector<sdbusplus::bus::match_t> cpuMatches;
+};
+
+} // namespace manager
+
 
 using Iface = sdbusplus::server::object::object<
     sdbusplus::org::open_power::OCC::server::PassThrough>;