Static layout: Implement gard reset

Use pflash to clear GUARD partition.

Tested: Verify GUARD partition is cleared on gard reset.

Change-Id: I54f77a30d728dc80aa40dfd58a17152b936a6a6d
Signed-off-by: Lei YU <mine260309@gmail.com>
diff --git a/static/item_updater_static.cpp b/static/item_updater_static.cpp
index 8eaf21d..6ab1f91 100644
--- a/static/item_updater_static.cpp
+++ b/static/item_updater_static.cpp
@@ -12,9 +12,12 @@
 #include <phosphor-logging/log.hpp>
 #include <sstream>
 #include <string>
+#include <tuple>
+#include <xyz/openbmc_project/Common/error.hpp>
 
 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
 using namespace phosphor::logging;
+using sdbusplus::exception::SdBusError;
 
 // When you see server:: you know we're referencing our base class
 namespace server = sdbusplus::xyz::openbmc_project::Software::server;
@@ -32,23 +35,25 @@
 }
 
 // Helper function to run pflash command
+// Returns return code and the stdout
 template <typename... Ts>
-std::string pflash(Ts const&... ts)
+std::pair<int, std::string> pflash(Ts const&... ts)
 {
     std::array<char, 512> buffer;
     std::string cmd = concat_string("pflash", ts...);
     std::stringstream result;
-    std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"),
-                                                  pclose);
+    int rc;
+    FILE* pipe = popen(cmd.c_str(), "r");
     if (!pipe)
     {
         throw std::runtime_error("popen() failed!");
     }
-    while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr)
+    while (fgets(buffer.data(), buffer.size(), pipe) != nullptr)
     {
         result << buffer.data();
     }
-    return result.str();
+    rc = pclose(pipe);
+    return {rc, result.str()};
 }
 
 std::string getPNORVersion()
@@ -72,7 +77,14 @@
     fs::path versionFile = tmpDir;
     versionFile /= "version";
 
-    pflash("-P VERSION -r", versionFile.string(), "2>&1 > /dev/null");
+    auto [rc, r] =
+        pflash("-P VERSION -r", versionFile.string(), "2>&1 > /dev/null");
+    if (rc != 0)
+    {
+        log<level::ERR>("Failed to read VERSION", entry("RETURNCODE=%d", rc));
+        return {};
+    }
+
     std::ifstream f(versionFile.c_str(), std::ios::in | std::ios::binary);
     uint8_t magic[MAGIC_SIZE];
     std::string version;
@@ -109,6 +121,10 @@
 {
 namespace updater
 {
+// TODO: Change paths once openbmc/openbmc#1663 is completed.
+constexpr auto MBOXD_INTERFACE = "org.openbmc.mboxd";
+constexpr auto MBOXD_PATH = "/org/openbmc/mboxd";
+
 std::unique_ptr<Activation> ItemUpdaterStatic::createActivationObject(
     const std::string& path, const std::string& versionId,
     const std::string& extVersion,
@@ -249,6 +265,53 @@
 
 void GardReset::reset()
 {
+    // Clear gard partition
+    std::vector<uint8_t> mboxdArgs;
+    int rc;
+
+    auto dbusCall = bus.new_method_call(MBOXD_INTERFACE, MBOXD_PATH,
+                                        MBOXD_INTERFACE, "cmd");
+    // Suspend mboxd - no args required.
+    dbusCall.append(static_cast<uint8_t>(3), mboxdArgs);
+
+    try
+    {
+        bus.call_noreply(dbusCall);
+    }
+    catch (const SdBusError& e)
+    {
+        log<level::ERR>("Error in mboxd suspend call",
+                        entry("ERROR=%s", e.what()));
+        elog<InternalFailure>();
+    }
+
+    // Clear guard partition
+    std::tie(rc, std::ignore) = utils::pflash("-P GUARD -c -f >/dev/null");
+    if (rc != 0)
+    {
+        log<level::ERR>("Failed to clear GUARD", entry("RETURNCODE=%d", rc));
+    }
+    else
+    {
+        log<level::INFO>("Clear GUARD successfully");
+    }
+
+    dbusCall = bus.new_method_call(MBOXD_INTERFACE, MBOXD_PATH, MBOXD_INTERFACE,
+                                   "cmd");
+    // Resume mboxd with arg 1, indicating that the flash is modified.
+    mboxdArgs.push_back(1);
+    dbusCall.append(static_cast<uint8_t>(4), mboxdArgs);
+
+    try
+    {
+        bus.call_noreply(dbusCall);
+    }
+    catch (const SdBusError& e)
+    {
+        log<level::ERR>("Error in mboxd resume call",
+                        entry("ERROR=%s", e.what()));
+        elog<InternalFailure>();
+    }
 }
 
 } // namespace updater