boot-block: quiesce host on error

If the user has requested the boot be blocked on an error with a
callout then also quiesce the host if it is running when this error
occurs.

Signed-off-by: Andrew Geissler <geissonator@yahoo.com>
Change-Id: I9f1f4fc1c704850649217770f4cfcff1cad70404
diff --git a/log_manager.cpp b/log_manager.cpp
index d636a67..1acd746 100644
--- a/log_manager.cpp
+++ b/log_manager.cpp
@@ -27,6 +27,7 @@
 #include <set>
 #include <string>
 #include <vector>
+#include <xyz/openbmc_project/State/Host/server.hpp>
 
 using namespace phosphor::logging;
 using namespace std::chrono;
@@ -314,6 +315,59 @@
     }
 }
 
+void Manager::checkAndQuiesceHost()
+{
+    // First check host state
+    std::variant<std::string> property;
+
+    auto method = this->busLog.new_method_call(
+        "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
+        "org.freedesktop.DBus.Properties", "Get");
+
+    method.append("xyz.openbmc_project.State.Host", "CurrentHostState");
+
+    try
+    {
+        auto reply = this->busLog.call(method);
+        reply.read(property);
+    }
+    catch (const SdBusError& e)
+    {
+        // Quiescing the host is a "best effort" type function. If unable to
+        // read the host state or it comes back empty, just return.
+        // The boot block object will still be created and the associations to
+        // find the log will be present. Don't want a dependency with
+        // phosphor-state-manager service
+        log<level::INFO>("Error reading QuiesceOnHwError property",
+                         entry("ERROR=%s", e.what()));
+        return;
+    }
+
+    std::string hostState = std::get<std::string>(property);
+
+    // If host state is empty, do nothing
+    if (hostState.empty())
+    {
+        return;
+    }
+
+    using Host = sdbusplus::xyz::openbmc_project::State::server::Host;
+    auto state = Host::convertHostStateFromString(hostState);
+    if (state != Host::HostState::Running)
+    {
+        return;
+    }
+
+    auto quiesce = this->busLog.new_method_call(
+        "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
+        "org.freedesktop.systemd1.Manager", "StartUnit");
+
+    quiesce.append("obmc-host-quiesce@0.target");
+    quiesce.append("replace");
+
+    this->busLog.call_noreply(quiesce);
+}
+
 void Manager::checkQuiesceOnError(const Entry& entry)
 {
 
@@ -343,8 +397,7 @@
     propChangedEntryCallback.insert(
         std::make_pair(entry.id(), std::move(callback)));
 
-    // TODO in later commit in this series
-    // Call systemd to quiesce host
+    checkAndQuiesceHost();
 }
 
 void Manager::doExtensionLogCreate(const Entry& entry, const FFDCEntries& ffdc)