Host updater: Back up version priority in environment variables

This enhancement to the host updater adds an extra location for storing
redundancy priority values for host software versions. Priority values
are stored as environment variables in the format
pnor-[versionId]=[priority]. This addresses any scenario in which the
Cereal files storing these priority values are deleted, including (but
not limited to) a BMC factory reset.

Additionally, priority files are no longer removed during a host factory
reset. Removing these files makes restoration of the priority on reboot
impossible.

Resolves openbmc/openbmc#2666

Change-Id: I6b528e75785d48bbb5c8782e879b061934ad9432
Signed-off-by: Michael Tritz <mtritz@us.ibm.com>
diff --git a/item_updater.cpp b/item_updater.cpp
index 1d4f3ce..7b7995e 100644
--- a/item_updater.cpp
+++ b/item_updater.cpp
@@ -357,8 +357,6 @@
                     entry("SERVICE_FILE=%s", serviceFile));
             elog<InternalFailure>();
         }
-
-        removeFile(it.first);
     }
     static constexpr auto serviceFile =
             "obmc-flash-bios-ubiclear@pnor-prsv.service";
diff --git a/serialize.cpp b/serialize.cpp
index ac1b8ac..595a970 100644
--- a/serialize.cpp
+++ b/serialize.cpp
@@ -3,6 +3,7 @@
 #include <cereal/archives/json.hpp>
 #include <fstream>
 #include "serialize.hpp"
+#include <sdbusplus/server.hpp>
 
 namespace openpower
 {
@@ -15,6 +16,8 @@
 
 void storeToFile(std::string versionId, uint8_t priority)
 {
+    auto bus = sdbusplus::bus::new_default();
+
     if (!fs::is_directory(PERSIST_DIR))
     {
         fs::create_directories(PERSIST_DIR);
@@ -34,6 +37,17 @@
         cereal::JSONOutputArchive rwArchive(rwOutput);
         rwArchive(cereal::make_nvp("priority", priority));
     }
+
+    // lastly, store the priority as an environment variable pnor-[versionId]
+    std::string serviceFile = "obmc-flash-bmc-setenv@pnor\\x2d" + versionId +
+            "\\x3d" + std::to_string(priority) + ".service";
+    auto method = bus.new_method_call(
+            SYSTEMD_BUSNAME,
+            SYSTEMD_PATH,
+            SYSTEMD_INTERFACE,
+            "StartUnit");
+    method.append(serviceFile, "replace");
+    bus.call_noreply(method);
 }
 
 bool restoreFromFile(std::string versionId, uint8_t& priority)
@@ -69,11 +83,54 @@
             fs::remove(rwPath);
         }
     }
+
+    try
+    {
+        std::string devicePath = "/dev/mtd/u-boot-env";
+
+        if (fs::exists(devicePath) && !devicePath.empty())
+        {
+            std::ifstream input(devicePath.c_str());
+            std::string envVars;
+            std::getline(input, envVars);
+
+            std::string versionVar = "pnor-" + versionId + "=";
+            auto varPosition = envVars.find(versionVar);
+
+            if (varPosition != std::string::npos)
+            {
+                // Grab the environment variable for this versionId. These
+                // variables follow the format "pnor-[versionId]=[priority]\0"
+                auto var = envVars.substr(varPosition);
+                priority = std::stoi(var.substr(versionVar.length()));
+                return true;
+            }
+        }
+    }
+    catch (const std::exception& e){}
+
     return false;
 }
 
 void removeFile(std::string versionId)
 {
+    auto bus = sdbusplus::bus::new_default();
+
+    // Clear the environment variable pnor-[versionId].
+    std::string serviceFile = "obmc-flash-bmc-setenv@pnor\\x2d" + versionId +
+            ".service";
+    auto method = bus.new_method_call(
+            SYSTEMD_BUSNAME,
+            SYSTEMD_PATH,
+            SYSTEMD_INTERFACE,
+            "StartUnit");
+    method.append(serviceFile, "replace");
+    bus.call_noreply(method);
+
+    // Delete the file /var/lib/obmc/openpower-pnor-code-mgmt/[versionId].
+    // Note that removeFile() is called in the case of a version being deleted,
+    // so the file /media/pnor-rw-[versionId]/[versionId] will also be deleted
+    // along with its surrounding directory.
     std::string path = PERSIST_DIR + versionId;
     if (fs::exists(path))
     {