vpd-tool sync BIOS attributes implementation stub

This commit implements stub for vpd-tool manufacturing clean sync
BIOS attributes feature. This changes in this commit allows user to
select --syncBiosAttribute option in --mfgClean. This commit does not
include complete implementation of --syncBiosAttribute option.

Change-Id: I0a8232588edb28b220a0fcf04070a26e2bb2c6f6
Signed-off-by: Souvik Roy <souvikroyofficial10@gmail.com>
diff --git a/vpd-tool/include/tool_constants.hpp b/vpd-tool/include/tool_constants.hpp
index 26c8e75..84b7025 100644
--- a/vpd-tool/include/tool_constants.hpp
+++ b/vpd-tool/include/tool_constants.hpp
@@ -34,5 +34,9 @@
 constexpr auto chassisStateManagerObjectPath =
     "/xyz/openbmc_project/state/chassis0";
 constexpr auto chassisStateManagerInfName = "xyz.openbmc_project.State.Chassis";
+constexpr auto dbusService = "org.freedesktop.DBus";
+constexpr auto dbusObjectPath = "/org/freedesktop/DBus";
+constexpr auto dbusInterface = "org.freedesktop.DBus";
+constexpr auto biosConfigMgrService = "xyz.openbmc_project.BIOSConfigManager";
 } // namespace constants
 } // namespace vpd
diff --git a/vpd-tool/include/tool_utils.hpp b/vpd-tool/include/tool_utils.hpp
index 97359c9..d4bde8a 100644
--- a/vpd-tool/include/tool_utils.hpp
+++ b/vpd-tool/include/tool_utils.hpp
@@ -868,5 +868,40 @@
     return false;
 }
 
+/**
+ * @brief API to check if a D-Bus service is running or not.
+ *
+ * Any failure in calling the method "NameHasOwner" implies that the service
+ * is not in a running state. Hence the API returns false in case of any
+ * exception as well.
+ *
+ * @param[in] i_serviceName - D-Bus service name whose status is to be
+ * checked.
+ * @return bool - True if the service is running, false otherwise.
+ */
+inline bool isServiceRunning(const std::string& i_serviceName) noexcept
+{
+    bool l_retVal = false;
+
+    try
+    {
+        auto l_bus = sdbusplus::bus::new_default();
+        auto l_method = l_bus.new_method_call(
+            constants::dbusService, constants::dbusObjectPath,
+            constants::dbusInterface, "NameHasOwner");
+        l_method.append(i_serviceName);
+
+        l_bus.call(l_method).read(l_retVal);
+    }
+    catch (const sdbusplus::exception::SdBusError& l_ex)
+    {
+        std::cout << "Call to check service status failed with exception: " +
+                         std::string(l_ex.what())
+                  << std::endl;
+    }
+
+    return l_retVal;
+}
+
 } // namespace utils
 } // namespace vpd
diff --git a/vpd-tool/include/vpd_tool.hpp b/vpd-tool/include/vpd_tool.hpp
index d1248da..67a52fc 100644
--- a/vpd-tool/include/vpd_tool.hpp
+++ b/vpd-tool/include/vpd_tool.hpp
@@ -168,6 +168,26 @@
      */
     int handleMoreOption(const nlohmann::json& i_parsedJsonObj) const noexcept;
 
+    /**
+     * @brief API to get VPD value of keyword in BIOS Config Manager.
+     *
+     * For a given record and keyword, this API gets the associated BIOS
+     * attribute current value from BIOS Config Manager, by reading the
+     * attribute value from BIOS Config Manager, converts the BIOS attribute
+     * value to VPD format, and returns it.
+     *
+     * @param[in] i_recordName - Record name.
+     * @param[in] i_keywordName - Keyword name.
+     *
+     * @return On success returns the resultant keyword value in binary
+     * format, else returns empty value.
+     *
+     * @throw std::terminate, std::bad_alloc
+     */
+    types::BinaryVector getVpdValueInBiosConfigManager(
+        [[maybe_unused]] const std::string& i_recordName,
+        [[maybe_unused]] const std::string& i_keywordName) const;
+
   public:
     /**
      * @brief Read keyword value.
@@ -259,13 +279,14 @@
      * 3. D-Bus cache.
      * 4. Backup path.
      *
-     * @param[in] i_syncBiosAttributes - Flag which specifies whether BIOS
-     * attribute related keywords need to be synced from BIOS Config Manager
-     * instead of being reset to default value.
+     * @param[in] i_syncBiosAttributesRequired - Flag which specifies whether
+     * BIOS attribute related keywords need to be synced from BIOS Config
+     * Manager instead of being reset to default value.
      *
      * @return On success returns 0, otherwise returns -1.
      */
-    int cleanSystemVpd(bool i_syncBiosAttributes = false) const noexcept;
+    int cleanSystemVpd(
+        bool i_syncBiosAttributesRequired = false) const noexcept;
 
     /**
      * @brief Dump all the inventory objects in JSON or table format to console.
diff --git a/vpd-tool/src/vpd_tool.cpp b/vpd-tool/src/vpd_tool.cpp
index 3b66f5c..f66450c 100644
--- a/vpd-tool/src/vpd_tool.cpp
+++ b/vpd-tool/src/vpd_tool.cpp
@@ -389,11 +389,20 @@
     return l_parsedBackupRestoreJson;
 }
 
-int VpdTool::cleanSystemVpd(bool i_syncBiosAttributes) const noexcept
+int VpdTool::cleanSystemVpd(bool i_syncBiosAttributesRequired) const noexcept
 {
     try
     {
-        (void)i_syncBiosAttributes;
+        // In order to do syncBiosAttributes, we need BIOS Config Manager
+        // service up and running
+        if (i_syncBiosAttributesRequired &&
+            !utils::isServiceRunning(constants::biosConfigMgrService))
+        {
+            std::cerr
+                << "Cannot sync BIOS attributes as BIOS Config Manager service is not running."
+                << std::endl;
+            return constants::FAILURE;
+        }
 
         // get the keyword map from backup_restore json
         // iterate through the keyword map get default value of
@@ -435,9 +444,27 @@
                         l_aRecordKwInfo.contains("defaultValue") &&
                         l_aRecordKwInfo["defaultValue"].is_array())
                     {
-                        const types::BinaryVector l_defaultBinaryValue =
-                            l_aRecordKwInfo["defaultValue"]
-                                .get<types::BinaryVector>();
+                        // check if this keyword is used for backing up BIOS
+                        // attribute
+                        const bool l_isUsedForBiosAttributeBackup =
+                            l_aRecordKwInfo.value("isBiosSyncRequired", false);
+
+                        const types::BinaryVector l_keywordValueToUpdate =
+                            (i_syncBiosAttributesRequired &&
+                             l_isUsedForBiosAttributeBackup)
+                                ? getVpdValueInBiosConfigManager(
+                                      l_srcRecordName, l_srcKeywordName)
+                                : l_aRecordKwInfo["defaultValue"]
+                                      .get<types::BinaryVector>();
+
+                        if (l_keywordValueToUpdate.empty())
+                        {
+                            std::cerr << "Failed to update " << l_srcRecordName
+                                      << ":" << l_srcKeywordName
+                                      << " . Keyword value to update is empty"
+                                      << std::endl;
+                            continue;
+                        }
 
                         // update the Keyword with default value, use D-Bus
                         // method UpdateKeyword exposed by vpd-manager.
@@ -450,7 +477,7 @@
                                 l_hardwarePath,
                                 std::make_tuple(l_srcRecordName,
                                                 l_srcKeywordName,
-                                                l_defaultBinaryValue)))
+                                                l_keywordValueToUpdate)))
                         {
                             // TODO: Enable logging when verbose
                             // is enabled.
@@ -1217,4 +1244,14 @@
     return constants::SUCCESS;
 }
 
+types::BinaryVector VpdTool::getVpdValueInBiosConfigManager(
+    [[maybe_unused]] const std::string& i_recordName,
+    [[maybe_unused]] const std::string& i_keywordName) const
+{
+    types::BinaryVector l_result;
+    // TODO: Use Record name, Keyword name to identify BIOS attribute.
+    //  Get BIOS attribute value from BIOS Config Manager.
+    //  Convert BIOS attribute value to VPD format value in binary.
+    return l_result;
+}
 } // namespace vpd