Create Version and Activation objects for current PNOR image

On BMC boot, create the Software version and activation that
points to the current PNOR version by reading:
/var/lib/phosphor-software-manager/pnor/ro

Resolves openbmc/openbmc#1762

Change-Id: I46ddb37491a1a230699da9f3acbd3fcff23dc538
Signed-off-by: Saqib Khan <khansa@us.ibm.com>
diff --git a/Makefile.am b/Makefile.am
index cf9197d..d188b56 100755
--- a/Makefile.am
+++ b/Makefile.am
@@ -7,6 +7,7 @@
 
 openpower_update_manager_SOURCES = \
 	activation.cpp \
+	version.cpp \
 	item_updater.cpp \
 	item_updater_main.cpp
 
diff --git a/item_updater.cpp b/item_updater.cpp
index 3edfb0c..7a56775 100755
--- a/item_updater.cpp
+++ b/item_updater.cpp
@@ -3,6 +3,7 @@
 #include <fstream>
 #include <phosphor-logging/log.hpp>
 #include <xyz/openbmc_project/Software/Version/server.hpp>
+#include "version.hpp"
 #include "config.h"
 #include "item_updater.hpp"
 #include "activation.hpp"
@@ -101,7 +102,9 @@
 
         fs::path manifestPath(filePath);
         manifestPath /= MANIFEST_FILE;
-        auto extendedVersion = ItemUpdater::getExtendedVersion(manifestPath);
+        std::string extendedVersion = (Version::getValue(manifestPath.string(),
+                 std::map<std::string, std::string>
+                 {{"extended_version", ""}})).begin()->second;
         activations.insert(std::make_pair(
                 versionId,
                 std::make_unique<Activation>(
@@ -123,43 +126,44 @@
     return;
 }
 
-std::string ItemUpdater::getExtendedVersion(const std::string& manifestFilePath)
+void ItemUpdater::processPNORImage()
 {
-    constexpr auto extendedVersionKey = "extended_version=";
-    constexpr auto extendedVersionKeySize = strlen(extendedVersionKey);
 
-    if (manifestFilePath.empty())
+    fs::path pnorTOC(PNOR_RO_ACTIVE_PATH);
+    pnorTOC /= PNOR_TOC_FILE;
+    std::ifstream efile(pnorTOC.c_str());
+    if (efile.good() != 1)
     {
-        log<level::ERR>("Error MANIFESTFilePath is empty");
-        throw std::runtime_error("MANIFESTFilePath is empty");
+        log<level::INFO>("Error PNOR current version is empty");
+        return;
     }
-
-    std::string extendedVersion{};
-    std::ifstream efile;
-    std::string line;
-    efile.exceptions(std::ifstream::failbit
-                     | std::ifstream::badbit
-                     | std::ifstream::eofbit);
-
-    try
-    {
-        efile.open(manifestFilePath);
-        while (getline(efile, line))
-        {
-            if (line.compare(0, extendedVersionKeySize,
-                             extendedVersionKey) == 0)
-            {
-                extendedVersion = line.substr(extendedVersionKeySize);
-                break;
-            }
-        }
-        efile.close();
-    }
-    catch (const std::exception& e)
-    {
-        log<level::ERR>("Error in reading Host MANIFEST file");
-    }
-    return extendedVersion;
+    auto keyValues = Version::getValue(pnorTOC.string(),
+        std::map<std::string, std::string> {{"version", ""},
+        {"extended_version", ""}});
+    std::string version = keyValues.at("version");
+    std::string extendedVersion = keyValues.at("extended_version");
+    auto id = Version::getId(version);
+    auto purpose = server::Version::VersionPurpose::Host;
+    auto path =  std::string{SOFTWARE_OBJPATH} + '/' + id;
+    auto activationState = server::Activation::Activations::Active;
+    activations.insert(std::make_pair(
+                           id,
+                           std::make_unique<Activation>(
+                               bus,
+                               path,
+                               *this,
+                               id,
+                               extendedVersion,
+                               activationState)));
+    versions.insert(std::make_pair(
+                        id,
+                        std::make_unique<Version>(
+                             bus,
+                             path,
+                             version,
+                             purpose,
+                             "")));
+    return;
 }
 
 int ItemUpdater::validateSquashFSImage(const std::string& filePath)
diff --git a/item_updater.hpp b/item_updater.hpp
index 6409698..2a71905 100755
--- a/item_updater.hpp
+++ b/item_updater.hpp
@@ -39,6 +39,7 @@
                                     this,
                                     std::placeholders::_1))
         {
+            processPNORImage();
         }
 
         /** @brief Sets the given priority free by incrementing
@@ -50,6 +51,11 @@
          */
         void freePriority(uint8_t value);
 
+        /**
+         * @brief Create and populate the active PNOR Version.
+         */
+        void processPNORImage();
+
     private:
         /** @brief Callback function for Software.Version match.
          *  @details Creates an Activation dbus object.
@@ -59,15 +65,6 @@
         void createActivation(sdbusplus::message::message& msg);
 
         /**
-         * @brief Get the extended version from the specified file.
-         *
-         * @param[in] manifestFilePath  - File to read.
-         *
-         * @return The extended version.
-         */
-        static std::string getExtendedVersion(const std::string&
-                                               manifestFilePath);
-        /**
          * @brief Validates the presence of SquashFS iamge in the image dir.
          *
          * @param[in]  filePath - The path to the SquashfFS image.
diff --git a/version.cpp b/version.cpp
new file mode 100644
index 0000000..6cdc723
--- /dev/null
+++ b/version.cpp
@@ -0,0 +1,87 @@
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <fstream>
+#include <stdexcept>
+#include <phosphor-logging/log.hpp>
+#include "version.hpp"
+#include <phosphor-logging/elog-errors.hpp>
+#include "xyz/openbmc_project/Common/error.hpp"
+
+namespace openpower
+{
+namespace software
+{
+namespace updater
+{
+
+using namespace sdbusplus::xyz::openbmc_project::Common::Error;
+using namespace phosphor::logging;
+
+std::string Version::getId(const std::string& version)
+{
+    std::stringstream hexId;
+
+    if (version.empty())
+    {
+        log<level::ERR>("Error version is empty");
+        elog<InvalidArgument>(xyz::openbmc_project::Common::InvalidArgument::
+                              ARGUMENT_NAME("Version"),
+                              xyz::openbmc_project::Common::InvalidArgument::
+                              ARGUMENT_VALUE(version.c_str()));
+    }
+
+    // Only want 8 hex digits.
+    hexId << std::hex << ((std::hash<std::string> {}(
+                               version)) & 0xFFFFFFFF);
+    return hexId.str();
+}
+
+std::map<std::string, std::string> Version::getValue(
+        const std::string& filePath, std::map<std::string, std::string> keys)
+{
+
+    if (filePath.empty())
+    {
+        log<level::ERR>("Error filePath is empty");
+        elog<InvalidArgument>(xyz::openbmc_project::Common::InvalidArgument::
+                              ARGUMENT_NAME("FilePath"),
+                              xyz::openbmc_project::Common::InvalidArgument::
+                              ARGUMENT_VALUE(filePath.c_str()));
+    }
+
+    std::ifstream efile;
+    std::string line;
+    efile.exceptions(std::ifstream::failbit
+                     | std::ifstream::badbit
+                     | std::ifstream::eofbit);
+
+    try
+    {
+        efile.open(filePath);
+        while (getline(efile, line))
+        {
+            for(auto& key : keys)
+            {
+                auto value = key.first + "=";
+                auto keySize = value.length();
+                if (line.compare(0, keySize, value) == 0)
+                {
+                    key.second = line.substr(keySize);
+                    break;
+                }
+            }
+        }
+        efile.close();
+    }
+    catch (const std::exception& e)
+    {
+        log<level::ERR>("Error in reading file");
+    }
+
+    return keys;
+}
+
+} // namespace updater
+} // namespace software
+} // namespace openpower
diff --git a/version.hpp b/version.hpp
index 573255c..23bf604 100644
--- a/version.hpp
+++ b/version.hpp
@@ -46,6 +46,28 @@
             // Emit deferred signal.
             emit_object_added();
         }
+
+        /**
+         * @brief Read the manifest file to get the value of the key.
+         *
+         * @param[in] filePath - The path to file which contains the value
+         *                       of keys.
+         * @param[in] keys     - A map of keys with empty values.
+         *
+         * @return The map of keys with filled values.
+         **/
+        static std::map<std::string, std::string> getValue(
+                const std::string& filePath,
+                std::map<std::string, std::string> keys);
+
+        /**
+         * @brief Get the Version id.
+         *
+         * @param[in] version     - The image version.
+         *
+         * @return The id.
+         */
+        static std::string getId(const std::string& version);
 };
 
 } // namespace updater