vpd-tool force reset command

This commit implements ‘force reset’ user option in vpd-tool. Command
clears the BMC persisted data and recollects the VPD for all the FRUs
mentioned in system config JSON.

Command will only be processed if chassis is powered off.

stub API is added in VpdTool class to implement this command.

Output:
```
root@p10bmc:/tmp# obmcutil state
CurrentBMCState     : xyz.openbmc_project.State.BMC.BMCState.Ready
CurrentPowerState   : xyz.openbmc_project.State.Chassis.PowerState.On
CurrentHostState    : xyz.openbmc_project.State.Host.HostState.Running
BootProgress        : xyz.openbmc_project.State.Boot.Progress.ProgressStages.MemoryInit
OperatingSystemState: xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive

When chassis is powered on, force reset command will fail:
root@p10bmc:/tmp# ./vpd-tool -f
The chassis power state is not Off. Force reset operation is not allowed.
```

Change-Id: I58ed0f11cf182d718ae957c4fbe803dc24f83d09
Signed-off-by: Anupama B R <anupama.b.r1@ibm.com>
diff --git a/vpd-tool/include/tool_constants.hpp b/vpd-tool/include/tool_constants.hpp
index 6e89957..26c8e75 100644
--- a/vpd-tool/include/tool_constants.hpp
+++ b/vpd-tool/include/tool_constants.hpp
@@ -30,5 +30,9 @@
 constexpr auto objectMapperService = "xyz.openbmc_project.ObjectMapper";
 constexpr auto objectMapperObjectPath = "/xyz/openbmc_project/object_mapper";
 constexpr auto objectMapperInfName = "xyz.openbmc_project.ObjectMapper";
+constexpr auto chassisStateManagerService = "xyz.openbmc_project.State.Chassis";
+constexpr auto chassisStateManagerObjectPath =
+    "/xyz/openbmc_project/state/chassis0";
+constexpr auto chassisStateManagerInfName = "xyz.openbmc_project.State.Chassis";
 } // namespace constants
 } // namespace vpd
diff --git a/vpd-tool/include/tool_utils.hpp b/vpd-tool/include/tool_utils.hpp
index 598cdd2..97359c9 100644
--- a/vpd-tool/include/tool_utils.hpp
+++ b/vpd-tool/include/tool_utils.hpp
@@ -834,5 +834,39 @@
     return l_valueRead;
 }
 
+/**
+ * @brief API to check if chassis is powered off.
+ *
+ * This API queries Phosphor Chassis State Manager to know whether
+ * chassis is powered off.
+ *
+ * @return true if chassis is powered off, false otherwise.
+ */
+inline bool isChassisPowerOff()
+{
+    try
+    {
+        // ToDo: Handle in case system has multiple chassis
+        auto l_powerState = readDbusProperty(
+            constants::chassisStateManagerService,
+            constants::chassisStateManagerObjectPath,
+            constants::chassisStateManagerInfName, "CurrentPowerState");
+
+        if (auto l_curPowerState = std::get_if<std::string>(&l_powerState);
+            l_curPowerState &&
+            ("xyz.openbmc_project.State.Chassis.PowerState.Off" ==
+             *l_curPowerState))
+        {
+            return true;
+        }
+    }
+    catch (const std::exception& l_ex)
+    {
+        // Todo: Enale log when verbose is enabled
+        std::cerr << l_ex.what() << std::endl;
+    }
+    return false;
+}
+
 } // namespace utils
 } // namespace vpd
diff --git a/vpd-tool/include/vpd_tool.hpp b/vpd-tool/include/vpd_tool.hpp
index 7898d00..d1248da 100644
--- a/vpd-tool/include/vpd_tool.hpp
+++ b/vpd-tool/include/vpd_tool.hpp
@@ -287,5 +287,17 @@
      * @return On success returns 0, otherwise returns -1.
      */
     int dumpInventory(bool i_dumpTable = false) const noexcept;
+
+    /**
+     * @brief Resets the VPD on DBus for all the Frus.
+     *
+     * API clears the inventory persisted data and restarts the phosphor
+     * inventory manager(PIM) DBus service and the VPD manager service. VPD
+     * manager service collects the VPD for all the FRU's listed on the system
+     * config JSON and calls PIM to publish VPD on DBus.
+     *
+     * @return On success returns 0, otherwise returns -1.
+     */
+    int resetVpdOnDbus();
 };
 } // namespace vpd
diff --git a/vpd-tool/src/vpd_tool.cpp b/vpd-tool/src/vpd_tool.cpp
index 1291129..3b66f5c 100644
--- a/vpd-tool/src/vpd_tool.cpp
+++ b/vpd-tool/src/vpd_tool.cpp
@@ -1211,4 +1211,10 @@
     return l_rc;
 }
 
+int VpdTool::resetVpdOnDbus()
+{
+    // ToDo: Implementation needs to be added
+    return constants::SUCCESS;
+}
+
 } // namespace vpd
diff --git a/vpd-tool/src/vpd_tool_main.cpp b/vpd-tool/src/vpd_tool_main.cpp
index c7a846f..4dde248 100644
--- a/vpd-tool/src/vpd_tool_main.cpp
+++ b/vpd-tool/src/vpd_tool_main.cpp
@@ -8,6 +8,32 @@
 #include <iostream>
 
 /**
+ * @brief Resets the VPD on DBus for all the Frus.
+ *
+ * API clears the inventory persisted data and restarts the phosphor inventory
+ * manager(PIM) DBus service and the VPD manager service. VPD manager service
+ * collects the VPD for all the FRU's listed on the system config JSON and calls
+ * PIM to publish VPD on DBus.
+ *
+ * Note: Force reset only happens if chassis is powered off.
+ *
+ * @return On success returns 0, otherwise returns -1.
+ */
+int forceReset()
+{
+    if (vpd::utils::isChassisPowerOff())
+    {
+        vpd::VpdTool l_vpdToolObj;
+        return l_vpdToolObj.resetVpdOnDbus();
+    }
+
+    std::cerr
+        << "The chassis power state is not Off. Force reset operation is not allowed."
+        << std::endl;
+    return vpd::constants::FAILURE;
+}
+
+/**
  * @brief API to perform manufacturing clean.
  *
  * @param[in] i_mfgCleanConfirmFlag - Confirmation flag to perform manufacturing
@@ -230,7 +256,9 @@
         "   From DBus to console in JSON format: "
         "vpd-tool -i\n"
         "   From DBus to console in Table format: "
-        "vpd-tool -i -t\n");
+        "vpd-tool -i -t\n"
+        "Force Reset:\n"
+        "   vpd-tool --forceReset\n");
 }
 
 int main(int argc, char** argv)
@@ -305,6 +333,10 @@
         "--syncBiosAttributes, -s",
         "Using this flag with --mfgClean option, Syncs the BIOS attribute related keywords from BIOS Config Manager service instead resetting keyword's value to default value");
 
+    auto l_forceResetFlag = l_app.add_flag(
+        "--forceReset, -f, -F",
+        "Force collect for hardware. CAUTION: Developer only option.");
+
     CLI11_PARSE(l_app, argc, argv);
 
     if (checkOptionValuePair(l_objectOption, l_vpdPath, l_recordOption,
@@ -373,6 +405,11 @@
         return l_vpdToolObj.dumpInventory(!l_dumpInventoryTableFlag->empty());
     }
 
+    if (!l_forceResetFlag->empty())
+    {
+        return forceReset();
+    }
+
     std::cout << l_app.help() << std::endl;
     return vpd::constants::FAILURE;
 }