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