VPD Tool: Update Hardware

Vpd tool has --Hardware/-H flag which should be given along
with writeKeyword flags, if the user wants to write directly to "Hardware".

In general the user should give only the object path in
--path/-P value.

Only if --Hardware/-H flag is given, the user has an
option to give either eeprom path or the object path in
--path/-P value.

Test:
Tested on simics.

./vpd-tool --writeKeyword -H --path < hardware path/object path > -R < record name > -K < keyword > -V < value in hex/ascii >

CASE 1: <updating eeprom path> < update directly on hardware using -H.>
./vpd-tool -u -H -P /sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a480.i2c-bus/i2c-8/8-0051/8-00510/nvmem -R VINI -K PN -V 0x717273
updation successful on both dbus and hardware.

CASE 2:
./vpd-tool -u -H -P /sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a480.i2c-bus/i2c-8/8-0051/8-00510/nvmem -R DINF -K FL -V 0x717273
updation successful on hardware. <this wont get updated in dbus as the given record-keyword pair is not required to update in dbus(only those record keywords
present in dbus_properties.json are required to be updated in dbus).

CASE 3: <failure case - invalid eeprom path>
root@rainier:/tmp# ./vpd-tool -u -H -P /sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a490.i2c-bus/i2c-8/8-0051/8-00510/nvmem -R VINI -K PN -V 0x717273
Invalid object path : /sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a490.i2c-bus/i2c-8/8-0051/8-00510/nvmem. Unable to find the corresponding EEPROM path for the given object path : /sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e7$

Signed-off-by: PriyangaRamasamy <priyanga24@in.ibm.com>
Change-Id: I6b893e699fe343c90c3a3fd2b07fd8b9a4711687
diff --git a/utils.cpp b/utils.cpp
index b9d07e4..69fbe6e 100644
--- a/utils.cpp
+++ b/utils.cpp
@@ -3,12 +3,19 @@
 #include "utils.hpp"
 
 #include "defines.hpp"
+#include "vpd_exceptions.hpp"
 
+#include <fstream>
+#include <iomanip>
 #include <phosphor-logging/elog-errors.hpp>
 #include <phosphor-logging/log.hpp>
 #include <sdbusplus/server.hpp>
+#include <sstream>
+#include <vector>
 #include <xyz/openbmc_project/Common/error.hpp>
 
+using json = nlohmann::json;
+
 namespace openpower
 {
 namespace vpd
@@ -17,7 +24,8 @@
 using namespace inventory;
 using namespace phosphor::logging;
 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
-
+using namespace record;
+using namespace openpower::vpd::exceptions;
 namespace inventory
 {
 
@@ -230,5 +238,113 @@
             "Error in invoking D-Bus logging create interface to register PEL");
     }
 }
+
+inventory::VPDfilepath getVpdFilePath(const string& jsonFile,
+                                      const std::string& ObjPath)
+{
+    ifstream inventoryJson(jsonFile);
+    const auto& jsonObject = json::parse(inventoryJson);
+    inventory::VPDfilepath filePath{};
+
+    if (jsonObject.find("frus") == jsonObject.end())
+    {
+        throw(VpdJsonException(
+            "Invalid JSON structure - frus{} object not found in ", jsonFile));
+    }
+
+    const nlohmann::json& groupFRUS =
+        jsonObject["frus"].get_ref<const nlohmann::json::object_t&>();
+    for (const auto& itemFRUS : groupFRUS.items())
+    {
+        const std::vector<nlohmann::json>& groupEEPROM =
+            itemFRUS.value().get_ref<const nlohmann::json::array_t&>();
+        for (const auto& itemEEPROM : groupEEPROM)
+        {
+            if (itemEEPROM["inventoryPath"]
+                    .get_ref<const nlohmann::json::string_t&>() == ObjPath)
+            {
+                filePath = itemFRUS.key();
+                return filePath;
+            }
+        }
+    }
+
+    return filePath;
+}
+
+bool isPathInJson(const std::string& eepromPath)
+{
+    bool present = false;
+    ifstream inventoryJson(INVENTORY_JSON_SYM_LINK);
+
+    try
+    {
+        auto js = json::parse(inventoryJson);
+        if (js.find("frus") == js.end())
+        {
+            throw(VpdJsonException(
+                "Invalid JSON structure - frus{} object not found in ",
+                INVENTORY_JSON_SYM_LINK));
+        }
+        json fruJson = js["frus"];
+
+        if (fruJson.find(eepromPath) != fruJson.end())
+        {
+            present = true;
+        }
+    }
+    catch (json::parse_error& ex)
+    {
+        throw(VpdJsonException("Json Parsing failed", INVENTORY_JSON_SYM_LINK));
+    }
+    return present;
+}
+
+bool isRecKwInDbusJson(const std::string& recordName,
+                       const std::string& keyword)
+{
+    ifstream propertyJson(DBUS_PROP_JSON);
+    json dbusProperty;
+    bool present = false;
+
+    if (propertyJson.is_open())
+    {
+        try
+        {
+            auto dbusPropertyJson = json::parse(propertyJson);
+            if (dbusPropertyJson.find("dbusProperties") ==
+                dbusPropertyJson.end())
+            {
+                throw(VpdJsonException("dbusProperties{} object not found in "
+                                       "DbusProperties json : ",
+                                       DBUS_PROP_JSON));
+            }
+
+            dbusProperty = dbusPropertyJson["dbusProperties"];
+            if (dbusProperty.contains(recordName))
+            {
+                const vector<string>& kwdsToPublish = dbusProperty[recordName];
+                if (find(kwdsToPublish.begin(), kwdsToPublish.end(), keyword) !=
+                    kwdsToPublish.end()) // present
+                {
+                    present = true;
+                }
+            }
+        }
+        catch (json::parse_error& ex)
+        {
+            throw(VpdJsonException("Json Parsing failed", DBUS_PROP_JSON));
+        }
+    }
+    else
+    {
+        // If dbus properties json is not available, we assume the given
+        // record-keyword is part of dbus-properties json. So setting the bool
+        // variable to true.
+        present = true;
+    }
+    return present;
+}
+
 } // namespace vpd
 } // namespace openpower