srvcfg: Updated for dynamic service/socket mgmt

Fixed srvcfg crash manager issue, by doing the service &
socket unit file queries dynamically and exposing the objects
to be controlled. This takes care of instanced service &
socket files like phosphor-ipmi-net@eth0 or
phosphor-ipmi-net@eth1 dynamically.

Tested:
1. Verified as per the base service name, all the instanced
service & socket names are dynamically queried and exposed
2. Made sure to list the disabled services thorugh this method
3. Made sure new services listed after fw-update are also
exposed as objects
4. Verfied phosphor-ipmi-net@eth0 port change using ipmitool
-p <newport> option
5. Verified permanent disable of the unit.
6. Verified run time enable / disable of the service.
7. Verified phosphor-ipmi-kcs service permanent & run time
enable / disable

Change-Id: Ib933a2fbff73eae4348a5940d350ae7972db03fb
Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com>
diff --git a/src/utils.cpp b/src/utils.cpp
index 32ac69d..cf15dee 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -15,133 +15,120 @@
 */

 #include "utils.hpp"

 

-void systemdDaemonReload(

-    const std::shared_ptr<sdbusplus::asio::connection> &conn)

+static inline void checkAndThrowInternalFailure(boost::system::error_code &ec,

+                                                const std::string &msg)

 {

-    try

+    if (ec)

     {

-        conn->async_method_call(

-            [](boost::system::error_code ec) {

-                if (ec)

-                {

-                    phosphor::logging::log<phosphor::logging::level::ERR>(

-                        "async error: Failed to do systemd reload.");

-                    return;

-                }

-                return;

-            },

-            "org.freedesktop.systemd1", "/org/freedesktop/systemd1",

-            "org.freedesktop.systemd1.Manager", "Reload");

-    }

-    catch (const sdbusplus::exception::SdBusError &e)

-    {

-        phosphor::logging::log<phosphor::logging::level::ERR>(

-            "daemon-reload operation failed.");

+        std::string msgToLog = ec.message() + (msg.empty() ? "" : " - " + msg);

+        phosphor::logging::log<phosphor::logging::level::ERR>(msgToLog.c_str());

         phosphor::logging::elog<

             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>();

     }

-

     return;

 }

 

-void systemdUnitAction(const std::shared_ptr<sdbusplus::asio::connection> &conn,

-                       const std::string &unitName,

-                       const std::string &actionMethod)

+void systemdDaemonReload(

+    const std::shared_ptr<sdbusplus::asio::connection> &conn,

+    boost::asio::yield_context yield)

 {

-    try

-    {

-        conn->async_method_call(

-            [](boost::system::error_code ec,

-               const sdbusplus::message::object_path &objPath) {

-                if (ec)

-                {

-                    phosphor::logging::log<phosphor::logging::level::ERR>(

-                        "async error: Failed to do systemd action");

-                    return;

-                }

-                phosphor::logging::log<phosphor::logging::level::ERR>(

-                    "Created unit action job.",

-                    phosphor::logging::entry("JobID=%s", objPath.str.c_str()));

-                return;

-            },

-            "org.freedesktop.systemd1", "/org/freedesktop/systemd1",

-            "org.freedesktop.systemd1.Manager", actionMethod, unitName,

-            "replace");

-    }

-    catch (const sdbusplus::exception::SdBusError &e)

+    boost::system::error_code ec;

+    conn->yield_method_call<>(yield, ec, sysdService, sysdObjPath, sysdMgrIntf,

+                              sysdReloadMethod);

+    checkAndThrowInternalFailure(ec, "daemon-reload operation failed");

+    return;

+}

+

+static inline uint32_t getJobId(const std::string &path)

+{

+    auto pos = path.rfind("/");

+    if (pos == std::string::npos)

     {

         phosphor::logging::log<phosphor::logging::level::ERR>(

-            "Systemd operation failed.",

-            phosphor::logging::entry("ACTION=%s", actionMethod.c_str()));

+            "Unable to get job id from job path");

         phosphor::logging::elog<

             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>();

     }

+    return static_cast<uint32_t>(std::stoul(path.substr(pos + 1)));

+}

 

+void systemdUnitAction(const std::shared_ptr<sdbusplus::asio::connection> &conn,

+                       boost::asio::yield_context yield,

+                       const std::string &unitName,

+                       const std::string &actionMethod)

+{

+    boost::system::error_code ec;

+    auto jobPath = conn->yield_method_call<sdbusplus::message::object_path>(

+        yield, ec, sysdService, sysdObjPath, sysdMgrIntf, actionMethod,

+        unitName, sysdReplaceMode);

+    checkAndThrowInternalFailure(ec,

+                                 "Systemd operation failed, " + actionMethod);

+    // Query the job till it doesn't exist anymore.

+    // this way we guarantee that queued job id is done.

+    // this is needed to make sure dependency list on units are

+    // properly handled.

+    while (1)

+    {

+        ec.clear();

+        conn->yield_method_call<>(yield, ec, sysdService, sysdObjPath,

+                                  sysdMgrIntf, sysdGetJobMethod,

+                                  getJobId(jobPath.str));

+        if (ec)

+        {

+            if (ec.value() == boost::system::errc::no_such_file_or_directory)

+            {

+                // Queued job is done, return now

+                return;

+            }

+            phosphor::logging::log<phosphor::logging::level::ERR>(

+                "Systemd operation failed for job query");

+            phosphor::logging::elog<sdbusplus::xyz::openbmc_project::Common::

+                                        Error::InternalFailure>();

+        }

+        boost::asio::deadline_timer sleepTimer(conn->get_io_context());

+        sleepTimer.expires_from_now(boost::posix_time::milliseconds(20));

+        ec.clear();

+        sleepTimer.async_wait(yield[ec]);

+        checkAndThrowInternalFailure(ec, "Systemd operation timer error");

+    }

     return;

 }

 

 void systemdUnitFilesStateChange(

     const std::shared_ptr<sdbusplus::asio::connection> &conn,

-    const std::vector<std::string> &unitFiles, const std::string &unitState)

+    boost::asio::yield_context yield, const std::vector<std::string> &unitFiles,

+    const std::string &unitState, bool maskedState, bool enabledState)

 {

-    try

-    {

-        if (unitState == "enabled")

-        {

-            conn->async_method_call(

-                [](boost::system::error_code ec) {

-                    if (ec)

-                    {

-                        phosphor::logging::log<phosphor::logging::level::ERR>(

-                            "async error: Failed to perform UnmaskUnitFiles.");

-                        return;

-                    }

-                    return;

-                },

-                "org.freedesktop.systemd1", "/org/freedesktop/systemd1",

-                "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles",

-                unitFiles, false);

-        }

-        else if (unitState == "disabled")

-        {

-            conn->async_method_call(

-                [](boost::system::error_code ec) {

-                    if (ec)

-                    {

-                        phosphor::logging::log<phosphor::logging::level::ERR>(

-                            "async error: Failed to perform MaskUnitFiles.");

-                        return;

-                    }

-                    return;

-                },

-                "org.freedesktop.systemd1", "/org/freedesktop/systemd1",

-                "org.freedesktop.systemd1.Manager", "MaskUnitFiles", unitFiles,

-                false, false);

-        }

-        else

-        {

-            // Not supported unit State

-            phosphor::logging::log<phosphor::logging::level::ERR>(

-                "invalid Unit state",

-                phosphor::logging::entry("STATE=%s", unitState.c_str()));

-            phosphor::logging::elog<sdbusplus::xyz::openbmc_project::Common::

-                                        Error::InternalFailure>();

-        }

-    }

-    catch (const sdbusplus::exception::SdBusError &e)

-    {

-        phosphor::logging::log<phosphor::logging::level::ERR>(

-            "Systemd state change operation failed.");

-        phosphor::logging::elog<

-            sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>();

-    }

+    boost::system::error_code ec;

 

+    if (unitState == stateMasked && !maskedState)

+    {

+        conn->yield_method_call<>(yield, ec, sysdService, sysdObjPath,

+                                  sysdMgrIntf, "UnmaskUnitFiles", unitFiles,

+                                  false);

+        checkAndThrowInternalFailure(ec, "Systemd UnmaskUnitFiles() failed.");

+    }

+    else if (unitState != stateMasked && maskedState)

+    {

+        conn->yield_method_call<>(yield, ec, sysdService, sysdObjPath,

+                                  sysdMgrIntf, "MaskUnitFiles", unitFiles,

+                                  false, false);

+        checkAndThrowInternalFailure(ec, "Systemd MaskUnitFiles() failed.");

+    }

+    ec.clear();

+    if (unitState != stateEnabled && enabledState)

+    {

+        conn->yield_method_call<>(yield, ec, sysdService, sysdObjPath,

+                                  sysdMgrIntf, "EnableUnitFiles", unitFiles,

+                                  false, false);

+        checkAndThrowInternalFailure(ec, "Systemd EnableUnitFiles() failed.");

+    }

+    else if (unitState != stateDisabled && !enabledState)

+    {

+        conn->yield_method_call<>(yield, ec, sysdService, sysdObjPath,

+                                  sysdMgrIntf, "DisableUnitFiles", unitFiles,

+                                  false);

+        checkAndThrowInternalFailure(ec, "Systemd DisableUnitFiles() failed.");

+    }

     return;

 }

-

-bool checkSystemdUnitExist(const std::string &unitName)

-{

-    std::experimental::filesystem::path unitFilePath(

-        std::string("/lib/systemd/system/") + unitName);

-    return std::experimental::filesystem::exists(unitFilePath);

-}