phosphor-post-code-manager: Add post code support for multi host

Added implementation to handle post codes from multiple host to BMC with
multi process approach. Each process handles post codes for corresponding host.

TESTED : Built the openbmc image targetting Facebook YosemiteV2 hardware.
Verified all the host's postcodes stored in corresponding host directories.

Signed-off-by: Kumar Thangavel <thangavel.k@hcl.com>
Change-Id: I29d55558ed165d9e4494f017e13808dff6252b04
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 594d839..ce94929 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -16,7 +16,8 @@
 set(SRC_FILES src/post_code.cpp
     src/main.cpp )
 set ( SERVICE_FILES
-    service_files/xyz.openbmc_project.State.Boot.PostCode.service )
+    service_files/xyz.openbmc_project.State.Boot.PostCode.service
+    service_files/xyz.openbmc_project.State.Boot.PostCode@.service )
 
 # import sdbusplus
 find_package(PkgConfig REQUIRED)
@@ -42,4 +43,4 @@
 target_link_libraries(${PROJECT_NAME} "${SDBUSPLUSPLUS_LIBRARIES} -lstdc++fs -lphosphor_dbus")
 
 install (TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
-install (FILES ${SERVICE_FILES} DESTINATION /lib/systemd/system/)
\ No newline at end of file
+install (FILES ${SERVICE_FILES} DESTINATION /lib/systemd/system/)
diff --git a/inc/post_code.hpp b/inc/post_code.hpp
index 5541de4..5e2a7b9 100644
--- a/inc/post_code.hpp
+++ b/inc/post_code.hpp
@@ -34,16 +34,39 @@
 
 #define MaxPostCodeCycles 100
 
-const static constexpr char *PostCodePath =
-    "/xyz/openbmc_project/state/boot/raw";
-const static constexpr char *PropertiesIntf = "org.freedesktop.DBus.Properties";
-const static constexpr char *PostCodeListPath =
-    "/var/lib/phosphor-post-code-manager/";
 const static constexpr char *CurrentBootCycleCountName =
     "CurrentBootCycleCount";
 const static constexpr char *CurrentBootCycleIndexName =
     "CurrentBootCycleIndex";
-const static constexpr char *HostStatePath = "/xyz/openbmc_project/state/host0";
+
+// Singleton holder to store host/node and other path information
+class PostCodeDataHolder
+{
+    static PostCodeDataHolder *instance;
+
+    PostCodeDataHolder()
+    {
+    }
+
+  public:
+    static PostCodeDataHolder *getInstance()
+    {
+        if (!instance)
+            instance = new PostCodeDataHolder;
+        return instance;
+    }
+
+    int node;
+
+    const static constexpr char *PostCodePath =
+        "/xyz/openbmc_project/state/boot/raw";
+    const static constexpr char *PropertiesIntf =
+        "org.freedesktop.DBus.Properties";
+    const static constexpr char *PostCodeListPathPrefix =
+        "/var/lib/phosphor-post-code-manager/host";
+    const static constexpr char *HostStatePathPrefix =
+        "/xyz/openbmc_project/state/host";
+};
 
 struct EventDeleter
 {
@@ -63,14 +86,20 @@
 
 struct PostCode : sdbusplus::server::object_t<post_code, delete_all>
 {
+    PostCodeDataHolder *postcodeDataHolderObj =
+        postcodeDataHolderObj->getInstance();
+
     PostCode(sdbusplus::bus::bus &bus, const char *path, EventPtr &event) :
         sdbusplus::server::object_t<post_code, delete_all>(bus, path), bus(bus),
         propertiesChangedSignalRaw(
             bus,
             sdbusplus::bus::match::rules::type::signal() +
                 sdbusplus::bus::match::rules::member("PropertiesChanged") +
-                sdbusplus::bus::match::rules::path(PostCodePath) +
-                sdbusplus::bus::match::rules::interface(PropertiesIntf),
+                sdbusplus::bus::match::rules::path(
+                    postcodeDataHolderObj->PostCodePath +
+                    std::to_string(postcodeDataHolderObj->node)) +
+                sdbusplus::bus::match::rules::interface(
+                    postcodeDataHolderObj->PropertiesIntf),
             [this](sdbusplus::message::message &msg) {
                 std::string objectName;
                 std::map<std::string, std::variant<uint64_t>> msgData;
@@ -89,8 +118,11 @@
             bus,
             sdbusplus::bus::match::rules::type::signal() +
                 sdbusplus::bus::match::rules::member("PropertiesChanged") +
-                sdbusplus::bus::match::rules::path(HostStatePath) +
-                sdbusplus::bus::match::rules::interface(PropertiesIntf),
+                sdbusplus::bus::match::rules::path(
+                    postcodeDataHolderObj->HostStatePathPrefix +
+                    std::to_string(postcodeDataHolderObj->node)) +
+                sdbusplus::bus::match::rules::interface(
+                    postcodeDataHolderObj->PropertiesIntf),
             [this](sdbusplus::message::message &msg) {
                 std::string objectName;
                 std::map<std::string, std::variant<std::string>> msgData;
@@ -124,9 +156,11 @@
     {
         phosphor::logging::log<phosphor::logging::level::INFO>(
             "PostCode is created");
-        auto dir = fs::path(PostCodeListPath);
+        auto dir = fs::path(postcodeDataHolderObj->PostCodeListPathPrefix +
+                            std::to_string(postcodeDataHolderObj->node));
         fs::create_directories(dir);
-        strPostCodeListPath = PostCodeListPath;
+        strPostCodeListPath = postcodeDataHolderObj->PostCodeListPathPrefix +
+                              std::to_string(postcodeDataHolderObj->node) + "/";
         strCurrentBootCycleIndexName = CurrentBootCycleIndexName;
         uint16_t index = 0;
         deserialize(
diff --git a/service_files/xyz.openbmc_project.State.Boot.PostCode@.service b/service_files/xyz.openbmc_project.State.Boot.PostCode@.service
new file mode 100644
index 0000000..1118434
--- /dev/null
+++ b/service_files/xyz.openbmc_project.State.Boot.PostCode@.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Post code manager
+
+[Service]
+ExecStart=/usr/bin/env post-code-manager --host %i
+SyslogIdentifier=post-code-manager%i
+Type=dbus
+BusName=xyz.openbmc_project.State.Boot.PostCode%i
+
+[Install]
+WantedBy=multi-user.target
diff --git a/src/main.cpp b/src/main.cpp
index fcd09d3..016659f 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -15,10 +15,34 @@
 */
 #include "post_code.hpp"
 
+#include <getopt.h>
+
 int main(int argc, char* argv[])
 {
+    PostCodeDataHolder* postcodeDataHolderObj =
+        postcodeDataHolderObj->getInstance();
+
+    int arg;
+    int optIndex = 0;
     int ret = 0;
 
+    std::string intfName;
+
+    static struct option longOpts[] = {{"host", required_argument, 0, 'h'},
+                                       {0, 0, 0, 0}};
+
+    while ((arg = getopt_long(argc, argv, "h:", longOpts, &optIndex)) != -1)
+    {
+        switch (arg)
+        {
+            case 'h':
+                postcodeDataHolderObj->node = std::stoi(optarg);
+                break;
+            default:
+                break;
+        }
+    }
+
     phosphor::logging::log<phosphor::logging::level::INFO>(
         "Start post code manager service...");
 
@@ -36,7 +60,16 @@
     sdbusplus::bus::bus bus = sdbusplus::bus::new_default();
     sdbusplus::server::manager_t m{bus, DBUS_OBJECT_NAME};
 
-    bus.request_name(DBUS_INTF_NAME);
+    if (postcodeDataHolderObj->node == 0)
+    {
+        intfName = DBUS_INTF_NAME;
+    }
+    else
+    {
+        intfName = DBUS_INTF_NAME + std::to_string(postcodeDataHolderObj->node);
+    }
+
+    bus.request_name(intfName.c_str());
 
     PostCode postCode{bus, DBUS_OBJECT_NAME, eventP};
 
diff --git a/src/post_code.cpp b/src/post_code.cpp
index 67a9d8f..d0ba711 100644
--- a/src/post_code.cpp
+++ b/src/post_code.cpp
@@ -17,12 +17,17 @@
 
 #include "iomanip"
 
+PostCodeDataHolder* PostCodeDataHolder::instance = 0;
+
 void PostCode::deleteAll()
 {
-    auto dir = fs::path(PostCodeListPath);
+    auto dir = fs::path(postcodeDataHolderObj->PostCodeListPathPrefix +
+                        std::to_string(postcodeDataHolderObj->node));
     std::uintmax_t n = fs::remove_all(dir);
     std::cerr << "clearPostCodes deleted " << n << " files in "
-              << PostCodeListPath << std::endl;
+              << postcodeDataHolderObj->PostCodeListPathPrefix +
+                     std::to_string(postcodeDataHolderObj->node)
+              << std::endl;
     fs::create_directories(dir);
     postCodes.clear();
     currentBootCycleIndex = 1;
@@ -88,7 +93,7 @@
     }
 
     postCodes.insert(std::make_pair(tsUS, code));
-    serialize(fs::path(PostCodeListPath));
+    serialize(fs::path(strPostCodeListPath));
 
     return;
 }
@@ -207,4 +212,4 @@
         bootNum = currentBootCycleIndex - index + 1;
     }
     return bootNum;
-}
\ No newline at end of file
+}