Add field mode to BMC updater

In this commit, a "field mode" feature is added. When field mode is
enabled, the PNOR patch path is unmounted, disabling host patches.

Resolves openbmc/openbmc#1350

Change-Id: Ia207b1fe1cdeb1b4fbf9b2fbf77052d7191ea726
Signed-off-by: Michael Tritz <mtritz@us.ibm.com>
diff --git a/item_updater.cpp b/item_updater.cpp
index 12f818b..f151412 100644
--- a/item_updater.cpp
+++ b/item_updater.cpp
@@ -17,6 +17,7 @@
 
 // When you see server:: you know we're referencing our base class
 namespace server = sdbusplus::xyz::openbmc_project::Software::server;
+namespace control = sdbusplus::xyz::openbmc_project::Control::server;
 
 using namespace phosphor::logging;
 namespace fs = std::experimental::filesystem;
@@ -247,7 +248,7 @@
             SYSTEMD_PATH,
             SYSTEMD_INTERFACE,
             "StartUnit");
-    method.append("obmc-flash-bmc-setenv@rwreset=true.service", "replace");
+    method.append("obmc-flash-bmc-setenv@rwreset\\x3dtrue.service", "replace");
     bus.call_noreply(method);
 
     log<level::INFO>("BMC factory reset will take effect upon reboot.");
@@ -284,6 +285,56 @@
     bus.call_noreply(method);
 }
 
+bool ItemUpdater::fieldModeEnabled(bool value)
+{
+    // enabling field mode is intended to be one way: false -> true
+    if (value && !control::FieldMode::fieldModeEnabled())
+    {
+        control::FieldMode::fieldModeEnabled(value);
+
+        auto method = bus.new_method_call(
+                SYSTEMD_BUSNAME,
+                SYSTEMD_PATH,
+                SYSTEMD_INTERFACE,
+                "StartUnit");
+        method.append("obmc-flash-bmc-setenv@fieldmode\\x3dtrue.service",
+                "replace");
+        bus.call_noreply(method);
+
+        method = bus.new_method_call(
+                SYSTEMD_BUSNAME,
+                SYSTEMD_PATH,
+                SYSTEMD_INTERFACE,
+                "StopUnit");
+        method.append("usr-local.mount", "replace");
+        bus.call_noreply(method);
+
+        std::vector<std::string> usrLocal = {"usr-local.mount"};
+
+        method = bus.new_method_call(
+                SYSTEMD_BUSNAME,
+                SYSTEMD_PATH,
+                SYSTEMD_INTERFACE,
+                "MaskUnitFiles");
+        method.append(usrLocal, false, true);
+        bus.call_noreply(method);
+    }
+
+    return control::FieldMode::fieldModeEnabled();
+}
+
+void ItemUpdater::restoreFieldModeStatus()
+{
+    std::ifstream input("/run/fw_env");
+    std::string envVar;
+    std::getline(input, envVar);
+
+    if(envVar.find("fieldmode=true") != std::string::npos)
+    {
+        ItemUpdater::fieldModeEnabled(true);
+    }
+}
+
 } // namespace updater
 } // namespace software
 } // namespace phosphor
diff --git a/item_updater.hpp b/item_updater.hpp
index 5b2a71b..de7b614 100644
--- a/item_updater.hpp
+++ b/item_updater.hpp
@@ -4,6 +4,7 @@
 #include "activation.hpp"
 #include "version.hpp"
 #include <xyz/openbmc_project/Common/FactoryReset/server.hpp>
+#include <xyz/openbmc_project/Control/FieldMode/server.hpp>
 
 namespace phosphor
 {
@@ -13,7 +14,8 @@
 {
 
 using ItemUpdaterInherit = sdbusplus::server::object::object<
-    sdbusplus::xyz::openbmc_project::Common::server::FactoryReset>;
+    sdbusplus::xyz::openbmc_project::Common::server::FactoryReset,
+    sdbusplus::xyz::openbmc_project::Control::server::FieldMode>;
 
 namespace MatchRules = sdbusplus::bus::match::rules;
 
@@ -38,7 +40,7 @@
          * @param[in] bus    - The Dbus bus object
          */
         ItemUpdater(sdbusplus::bus::bus& bus, const std::string& path) :
-                    ItemUpdaterInherit(bus, path.c_str()),
+                    ItemUpdaterInherit(bus, path.c_str(), false),
                     bus(bus),
                     versionMatch(
                             bus,
@@ -50,6 +52,8 @@
                                     std::placeholders::_1))
         {
             processBMCImage();
+            restoreFieldModeStatus();
+            emit_object_added();
         };
 
     /** @brief Sets the given priority free by incrementing
@@ -98,6 +102,18 @@
           * recreation upon reboot. */
         void reset() override;
 
+        /**
+         * @brief Enables field mode, if value=true.
+         *
+         * @param[in]  value  - If true, enables field mode.
+         * @param[out] result - Returns the current state of field mode.
+         *
+         */
+        bool fieldModeEnabled(bool value) override;
+
+        /** @brief Restores field mode status on reboot. */
+        void restoreFieldModeStatus();
+
         /** @brief Persistent sdbusplus DBus bus connection. */
         sdbusplus::bus::bus& bus;