PNOR: Restore version and activation dbus objects on BMC reboot.

- Read the /media/ dir for active pnor versions. Each active
  version has a pnor.toc inside /media/ which is used to
  recreate the version and activation objects.
- version that matches the version inside
  "/var/lib/phosphor-software-manager/pnor/ro" is considered
  the current version and its priority is set to 0.

Resolves openbmc/openbmc#1846

Change-Id: Ic3d22cc310fdd60d708a73ddc406d3fb0620845c
Signed-off-by: Saqib Khan <khansa@us.ibm.com>
diff --git a/item_updater.cpp b/item_updater.cpp
index 1c0a6b8..fa3938e 100755
--- a/item_updater.cpp
+++ b/item_updater.cpp
@@ -129,52 +129,111 @@
 
 void ItemUpdater::processPNORImage()
 {
-
-    fs::path pnorTOC(PNOR_RO_ACTIVE_PATH);
-    pnorTOC /= PNOR_TOC_FILE;
-    std::ifstream efile(pnorTOC.c_str());
-    if (efile.good() != 1)
+    // Get the current PNOR version
+    auto pnorTOC = fs::path(PNOR_RO_ACTIVE_PATH) / PNOR_TOC_FILE;
+    if (!fs::is_regular_file(pnorTOC))
     {
         log<level::INFO>("Error PNOR current version is empty");
         return;
     }
-    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>(
+    std::string currentVersion =
+            Version::getValue(pnorTOC, {{ "version", "" }}).begin()->second;
+
+    // Read pnor.toc from folders under /media/
+    // to get Active Software Versions.
+    for(const auto& iter : fs::directory_iterator(MEDIA_DIR))
+    {
+        auto activationState = server::Activation::Activations::Active;
+
+        static const auto PNOR_RO_PREFIX_LEN = strlen(PNOR_RO_PREFIX);
+
+        // Check if the PNOR_RO_PREFIX is the prefix of the iter.path
+        if (0 == iter.path().native().compare(0, PNOR_RO_PREFIX_LEN,
+                                              PNOR_RO_PREFIX))
+        {
+            auto pnorTOC = iter.path() / PNOR_TOC_FILE;
+            if (!fs::is_regular_file(pnorTOC))
+            {
+                log<level::ERR>("Failed to read pnorTOC\n",
+                                entry("FileName=%s", pnorTOC.string()));
+                activationState = server::Activation::Activations::Invalid;
+            }
+            auto keyValues =
+                    Version::getValue(pnorTOC,
+                                      {{ "version", "" },
+                                       { "extended_version", "" } });
+            auto& version = keyValues.at("version");
+            if (version.empty())
+            {
+                log<level::ERR>("Failed to read version from pnorTOC",
+                                entry("FILENAME=%s", pnorTOC.string()));
+                activationState = server::Activation::Activations::Invalid;
+            }
+
+            auto& extendedVersion = keyValues.at("extended_version");
+            if (extendedVersion.empty())
+            {
+                log<level::ERR>("Failed to read extendedVersion from pnorTOC",
+                                entry("FILENAME=%s", pnorTOC.string()));
+                activationState = server::Activation::Activations::Invalid;
+            }
+
+            // The versionId is extracted from the path
+            // for example /media/pnor-ro-2a1022fe
+            auto id = iter.path().native().substr(PNOR_RO_PREFIX_LEN);
+            auto purpose = server::Version::VersionPurpose::Host;
+            auto path = fs::path(SOFTWARE_OBJPATH) / id;
+
+            // Create Activation instance for this version.
+            activations.insert(std::make_pair(
+                                   id,
+                                   std::make_unique<Activation>(
+                                       bus,
+                                       path,
+                                       *this,
+                                       id,
+                                       extendedVersion,
+                                       activationState)));
+
+            // If Active, create RedundancyPriority instance for this version.
+            if (activationState == server::Activation::Activations::Active)
+            {
+                // Current PNOR needs the lowest Priority, so setting to 0.
+                // TODO openbmc/openbmc#2040 Need to store Priority in the
+                // RW partition to be able to restore the priorities that
+                // were set before the BMC reboot.
+                auto priority = 1;
+                if (currentVersion == version)
+                {
+                    priority = 0;
+                }
+                activations.find(id)->second->redundancyPriority =
+                         std::make_unique<RedundancyPriority>(
                              bus,
                              path,
-                             version,
-                             purpose,
-                             "",
-                             *this)));
+                             *(activations.find(id)->second),
+                             priority);
+            }
+
+            // Create Version instance for this version.
+            versions.insert(std::make_pair(
+                                id,
+                                std::make_unique<Version>(
+                                     bus,
+                                     path,
+                                     version,
+                                     purpose,
+                                     "",
+                                     *this)));
+        }
+    }
     return;
 }
 
 int ItemUpdater::validateSquashFSImage(const std::string& filePath)
 {
-    fs::path file(filePath);
-    file /= squashFSImage;
-    std::ifstream efile(file.c_str());
-
-    if (efile.good() == 1)
+    auto file = fs::path(filePath) / squashFSImage;
+    if (fs::is_regular_file(file))
     {
         return 0;
     }