system_configuration: Fix new hostname updates

This allows changes outside of phosphor-networkd to be processed and
handled correctly.

Change-Id: I0bb8e90fe502a6d69f451a45cfecbee1bc89eb66
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/system_configuration.cpp b/src/system_configuration.cpp
index 0ba4d82..bccdb02 100644
--- a/src/system_configuration.cpp
+++ b/src/system_configuration.cpp
@@ -9,26 +9,61 @@
 namespace network
 {
 
-// systemd service to kick start a target.
-constexpr auto HOSTNAMED_SERVICE = "org.freedesktop.hostname1";
-constexpr auto HOSTNAMED_SERVICE_PATH = "/org/freedesktop/hostname1";
-constexpr auto HOSTNAMED_INTERFACE = "org.freedesktop.hostname1";
-constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
-constexpr auto METHOD_GET = "Get";
-constexpr auto METHOD_SET = "SetStaticHostname";
+static constexpr char HOSTNAMED_SVC[] = "org.freedesktop.hostname1";
+static constexpr char HOSTNAMED_OBJ[] = "/org/freedesktop/hostname1";
+static constexpr char HOSTNAMED_INTF[] = "org.freedesktop.hostname1";
 
 using namespace phosphor::logging;
 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
 
-using SystemConfigIntf =
-    sdbusplus::xyz::openbmc_project::Network::server::SystemConfiguration;
+static constexpr char propMatch[] =
+    "type='signal',sender='org.freedesktop.hostname1',"
+    "path='/org/freedesktop/hostname1',"
+    "interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',"
+    "arg0='org.freedesktop.hostname1'";
 
 SystemConfiguration::SystemConfiguration(sdbusplus::bus_t& bus,
                                          stdplus::const_zstring objPath) :
     Iface(bus, objPath.c_str(), Iface::action::defer_emit),
-    bus(bus)
+    bus(bus), hostnamePropMatch(bus, propMatch, [&](sdbusplus::message_t& m) {
+        std::string intf;
+        std::unordered_map<std::string, std::variant<std::string>> values;
+        try
+        {
+            m.read(intf, values);
+            auto it = values.find("Hostname");
+            if (it == values.end())
+            {
+                return;
+            }
+            Iface::hostName(std::get<std::string>(it->second));
+        }
+        catch (const std::exception& e)
+        {
+            log<level::ERR>(
+                fmt::format("Hostname match parsing failed: {}", e.what())
+                    .c_str(),
+                entry("ERROR=%s", e.what()));
+        }
+    })
 {
-    SystemConfigIntf::hostName(getHostNameFromSystem(), true);
+    try
+    {
+        std::variant<std::string> name;
+        auto req =
+            bus.new_method_call(HOSTNAMED_SVC, HOSTNAMED_OBJ,
+                                "org.freedesktop.DBus.Properties", "Get");
+
+        req.append(HOSTNAMED_INTF, "Hostname");
+        auto reply = bus.call(req);
+        reply.read(name);
+        SystemConfigIntf::hostName(std::get<std::string>(name), true);
+    }
+    catch (const std::exception& e)
+    {
+        auto msg = fmt::format("Failed to get hostname: {}", e.what());
+        log<level::ERR>(msg.c_str(), entry("ERROR=%s", e.what()));
+    }
 
     emit_object_added();
 }
@@ -39,44 +74,20 @@
     {
         return name;
     }
-    auto method = bus.new_method_call(HOSTNAMED_SERVICE, HOSTNAMED_SERVICE_PATH,
-                                      HOSTNAMED_INTERFACE, METHOD_SET);
-
-    method.append(name, true);
-
-    if (!bus.call(method))
-    {
-        log<level::ERR>("Failed to set the hostname");
-        report<InternalFailure>();
-        return SystemConfigIntf::hostName();
-    }
-
-    return SystemConfigIntf::hostName(name);
-}
-
-std::string SystemConfiguration::getHostNameFromSystem() const
-{
     try
     {
-        std::variant<std::string> name;
-        auto method =
-            bus.new_method_call(HOSTNAMED_SERVICE, HOSTNAMED_SERVICE_PATH,
-                                PROPERTY_INTERFACE, METHOD_GET);
-
-        method.append(HOSTNAMED_INTERFACE, "Hostname");
-
-        auto reply = bus.call(method);
-
-        reply.read(name);
-        return std::get<std::string>(name);
+        auto method = bus.new_method_call(HOSTNAMED_SVC, HOSTNAMED_OBJ,
+                                          HOSTNAMED_INTF, "SetStaticHostname");
+        method.append(name, /*interactive=*/false);
+        bus.call_noreply(method);
+        return SystemConfigIntf::hostName(std::move(name));
     }
-    catch (const sdbusplus::exception_t& ex)
+    catch (const std::exception& e)
     {
-        log<level::ERR>(
-            "Failed to get the hostname from systemd-hostnamed service",
-            entry("ERR=%s", ex.what()));
+        auto msg = fmt::format("Failed to set hostname: {}", e.what());
+        log<level::ERR>(msg.c_str(), entry("ERROR=%s", e.what()));
     }
-    return "";
+    return SystemConfigIntf::hostName();
 }
 
 } // namespace network