ItemUpdater: Implement Software.Extended Version

- Add Extended version in the MANIFEST
- Create an ExtendedVersion object
- Populate the ExtendedVersion object from MANIFEST

Resolves openbmc/openbmc#1401

Change-Id: Icb21e51a2a74c94f54ffecbd9057add4a0d3d694
Signed-off-by: Saqib Khan <khansa@us.ibm.com>
diff --git a/activation.hpp b/activation.hpp
index 08fba78..5c6c5fe 100755
--- a/activation.hpp
+++ b/activation.hpp
@@ -3,6 +3,7 @@
 #include <sdbusplus/bus.hpp>
 #include <xyz/openbmc_project/Software/Activation/server.hpp>
 #include <xyz/openbmc_project/Software/ActivationBlocksTransition/server.hpp>
+#include "xyz/openbmc_project/Software/ExtendedVersion/server.hpp"
 
 namespace openpower
 {
@@ -12,6 +13,7 @@
 {
 
 using ActivationInherit = sdbusplus::server::object::object<
+    sdbusplus::xyz::openbmc_project::Software::server::ExtendedVersion,
     sdbusplus::xyz::openbmc_project::Software::server::Activation>;
 using ActivationBlocksTransitionInherit = sdbusplus::server::object::object<
  sdbusplus::xyz::openbmc_project::Software::server::ActivationBlocksTransition>;
@@ -28,12 +30,21 @@
          *
          * @param[in] bus    - The Dbus bus object
          * @param[in] path   - The Dbus object path
-         * @param[in] versionId - The software version id
+         * @param[in] versionId  - The software version id
+         * @param[in] extVersion - The extended version
          */
         Activation(sdbusplus::bus::bus& bus, const std::string& path,
-                   std::string& versionId) :
-                   ActivationInherit(bus, path.c_str()),
-                   versionId(versionId) {}
+                   std::string& versionId,
+                   std::string& extVersion) :
+                   ActivationInherit(bus, path.c_str(), true),
+                   versionId(versionId)
+        {
+            // Set Properties.
+            extendedVersion(extVersion);
+
+            // Emit deferred signal.
+            emit_object_added();
+        }
 
         /** @brief Overloaded Activation property setter function
          *
diff --git a/generate-squashfs b/generate-squashfs
index 11f0abc..6b14618 100755
--- a/generate-squashfs
+++ b/generate-squashfs
@@ -104,7 +104,8 @@
 
 echo "Creating MANIFEST for the image"
 manifest_location="${scratch_dir}/MANIFEST"
-echo -e "purpose=host\nversion=$version" >> $manifest_location
+echo -e "purpose=host\nversion=$version\n\
+extended_version=$extended_version" >> $manifest_location
 
 echo "Generating tarball to contain the SquashFS image and its MANIFEST"
 tar -cvf $outfile $manifest_location ${scratch_dir}/pnor.xz.squashfs
diff --git a/item_updater.cpp b/item_updater.cpp
index ba153e6..42e7729 100755
--- a/item_updater.cpp
+++ b/item_updater.cpp
@@ -1,3 +1,5 @@
+#include <string>
+#include <fstream>
 #include <phosphor-logging/log.hpp>
 #include "config.h"
 #include "item_updater.hpp"
@@ -44,6 +46,7 @@
         return -1;
     }
 
+    auto extendedVersion = ItemUpdater::getExtendedVersion(MANIFEST_FILE);
     for (const auto& resp : mapperResponse)
     {
         // Version id is the last item in the path
@@ -63,12 +66,53 @@
                     std::make_unique<Activation>(
                             updater->busItem,
                             resp,
-                            versionId)));
+                            versionId,
+                            extendedVersion)));
         }
     }
     return 0;
 }
 
+std::string ItemUpdater::getExtendedVersion(const std::string& manifestFilePath)
+{
+    constexpr auto extendedVersionKey = "extended_version=";
+    constexpr auto extendedVersionKeySize = strlen(extendedVersionKey);
+
+    if (manifestFilePath.empty())
+    {
+        log<level::ERR>("Error MANIFESTFilePath is empty");
+        throw std::runtime_error("MANIFESTFilePath is empty");
+    }
+
+    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;
+}
+
 } // namespace updater
 } // namespace software
 } // namespace openpower
diff --git a/item_updater.hpp b/item_updater.hpp
index 091e31d..5afb96d 100755
--- a/item_updater.hpp
+++ b/item_updater.hpp
@@ -52,6 +52,16 @@
                                     void* userData,
                                     sd_bus_error* retError);
 
+        /**
+         * @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 Persistent sdbusplus DBus bus connection. */
         sdbusplus::bus::bus& busItem;