Fix for sensor value PATCH in manufacturing mode

Issue: Not able to PATCH sensor value in manufacturing mode, as
manufacturing mode is not getting updated after BMC reboot.

Added support to cache initial value of `SpecialMode` property on
startup and register for `InterfacesAdded` signal in case
`specialmodemgr` service starts late.

Tested:
1. Verified `manufacturingMode` value is getting updated as expected.
Verified the same over different scenarios like service(specialmodemgr,
hwmontempsensor, cpusensor) restart and `SpecialMode` property update.
2. Verified PATCH operation is working as expected over BMC resets
in manufacturing mode.
PATCH - /redfish/v1/Chassis/<Board>/Thermal
   Body:
       {
           "Temperatures": [
               {
                   "MemberId": "Inlet_BRD_Temp",
                   "ReadingCelsius" : 20
               }
           ]
        }
   Response:
      {
          "@odata.id": "/redfish/v1/Chassis/<Board>/Thermal",
          "@odata.type": "#Thermal.v1_4_0.Thermal",
          "Fans": [],
          "Id": "Thermal",
          "Name": "Thermal",
          "Temperatures": []
      }

Signed-off-by: Snehalatha Venkatesh <snehalathax.v@intel.com>
Signed-off-by: Arun P. Mohanan <arun.p.m@linux.intel.com>
Change-Id: I6ae9fb7d6e9fdd508f199bcdaf629411a2c96da6
diff --git a/src/Utils.cpp b/src/Utils.cpp
index 1a14911..20f4c4e 100644
--- a/src/Utils.cpp
+++ b/src/Utils.cpp
@@ -522,50 +522,101 @@
     return std::nullopt;
 }
 
+static void handleSpecialModeChange(const std::string& manufacturingModeStatus)
+{
+    manufacturingMode = false;
+    if (manufacturingModeStatus == "xyz.openbmc_project.Control.Security."
+                                   "SpecialMode.Modes.Manufacturing")
+    {
+        manufacturingMode = true;
+    }
+    if (validateUnsecureFeature == true)
+    {
+        if (manufacturingModeStatus == "xyz.openbmc_project.Control.Security."
+                                       "SpecialMode.Modes.ValidationUnsecure")
+        {
+            manufacturingMode = true;
+        }
+    }
+}
+
 void setupManufacturingModeMatch(sdbusplus::asio::connection& conn)
 {
-    static std::unique_ptr<sdbusplus::bus::match::match>
-        setupManufacturingModeMatch =
-            std::make_unique<sdbusplus::bus::match::match>(
-                conn,
-                "type='signal',interface='org.freedesktop.DBus."
-                "Properties',member='"
-                "PropertiesChanged',arg0namespace='xyz.openbmc_project."
-                "Security.SpecialMode'",
-                [](sdbusplus::message::message& msg) {
-                    std::string interfaceName;
+    namespace rules = sdbusplus::bus::match::rules;
+    static constexpr const char* specialModeInterface =
+        "xyz.openbmc_project.Security.SpecialMode";
+
+    const std::string filterSpecialModeIntfAdd =
+        rules::interfacesAdded() +
+        rules::argNpath(0, "/xyz/openbmc_project/security/special_mode");
+    static std::unique_ptr<sdbusplus::bus::match::match> specialModeIntfMatch =
+        std::make_unique<sdbusplus::bus::match::match>(
+            conn, filterSpecialModeIntfAdd, [](sdbusplus::message::message& m) {
+                sdbusplus::message::object_path path;
+                using PropertyMap =
                     boost::container::flat_map<std::string,
-                                               std::variant<std::string>>
-                        propertiesChanged;
-                    std::string manufacturingModeStatus;
+                                               std::variant<std::string>>;
+                boost::container::flat_map<std::string, PropertyMap>
+                    interfaceAdded;
+                m.read(path, interfaceAdded);
+                auto intfItr = interfaceAdded.find(specialModeInterface);
+                if (intfItr == interfaceAdded.end())
+                {
+                    return;
+                }
+                PropertyMap& propertyList = intfItr->second;
+                auto itr = propertyList.find("SpecialMode");
+                if (itr == propertyList.end())
+                {
+                    std::cerr << "error getting  SpecialMode property "
+                              << "\n";
+                    return;
+                }
+                auto manufacturingModeStatus =
+                    std::get_if<std::string>(&itr->second);
+                handleSpecialModeChange(*manufacturingModeStatus);
+            });
 
-                    msg.read(interfaceName, propertiesChanged);
-                    if (propertiesChanged.begin() == propertiesChanged.end())
-                    {
-                        return;
-                    }
+    const std::string filterSpecialModeChange =
+        rules::type::signal() + rules::member("PropertiesChanged") +
+        rules::interface("org.freedesktop.DBus.Properties") +
+        rules::argN(0, specialModeInterface);
+    static std::unique_ptr<sdbusplus::bus::match::match>
+        specialModeChangeMatch = std::make_unique<sdbusplus::bus::match::match>(
+            conn, filterSpecialModeChange, [](sdbusplus::message::message& m) {
+                std::string interfaceName;
+                boost::container::flat_map<std::string,
+                                           std::variant<std::string>>
+                    propertiesChanged;
 
-                    manufacturingModeStatus = std::get<std::string>(
-                        propertiesChanged.begin()->second);
-                    manufacturingMode = false;
-                    if (manufacturingModeStatus ==
-                        "xyz.openbmc_project.Control.Security."
-                        "SpecialMode.Modes.Manufacturing")
-                    {
-                        manufacturingMode = true;
-                    }
-                    if (validateUnsecureFeature == true)
-                    {
-                        if (manufacturingModeStatus ==
-                            "xyz.openbmc_project.Control.Security."
-                            "SpecialMode.Modes.ValidationUnsecure")
-                        {
-                            manufacturingMode = true;
-                        }
-                    }
-                });
+                m.read(interfaceName, propertiesChanged);
+                auto itr = propertiesChanged.find("SpecialMode");
+                if (itr == propertiesChanged.end())
+                {
+                    return;
+                }
+                auto manufacturingModeStatus =
+                    std::get_if<std::string>(&itr->second);
+                handleSpecialModeChange(*manufacturingModeStatus);
+            });
 
-    return;
+    conn.async_method_call(
+        [](const boost::system::error_code ec,
+           const std::variant<std::string>& getManufactMode) {
+            if (ec)
+            {
+                std::cerr << "error getting  SpecialMode status "
+                          << ec.message() << "\n";
+                return;
+            }
+            auto manufacturingModeStatus =
+                std::get_if<std::string>(&getManufactMode);
+            handleSpecialModeChange(*manufacturingModeStatus);
+        },
+        "xyz.openbmc_project.SpecialMode",
+        "/xyz/openbmc_project/security/special_mode",
+        "org.freedesktop.DBus.Properties", "Get", specialModeInterface,
+        "SpecialMode");
 }
 
 bool getManufacturingMode()