Change files to use standard unix file endings
CRLF line endings are non-standard for this project. Change them to use
the standard unix LF ending.
Tested: `git show -w` shows no difference
Change-Id: I353adcd2054c48a040b4e3a09bc46913cb6422fa
Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
diff --git a/inc/srvcfg_manager.hpp b/inc/srvcfg_manager.hpp
index ea84c53..d0a3ae1 100644
--- a/inc/srvcfg_manager.hpp
+++ b/inc/srvcfg_manager.hpp
@@ -1,113 +1,113 @@
-/*
-// Copyright (c) 2018 Intel Corporation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-*/
-#pragma once
-#include "utils.hpp"
-
-#include <sdbusplus/timer.hpp>
-
-namespace phosphor
-{
-namespace service
-{
-
-static constexpr const char* serviceConfigSrvName =
- "xyz.openbmc_project.Control.Service.Manager";
-static constexpr const char* serviceConfigIntfName =
- "xyz.openbmc_project.Control.Service.Attributes";
-static constexpr const char* sockAttrIntfName =
- "xyz.openbmc_project.Control.Service.SocketAttributes";
-static constexpr const char* srcCfgMgrBasePath =
- "/xyz/openbmc_project/control/service";
-static constexpr const char* srcCfgMgrIntf =
- "/xyz/openbmc_project.Control.Service.Manager";
-static constexpr const char* sockAttrPropPort = "Port";
-static constexpr const char* srvCfgPropMasked = "Masked";
-static constexpr const char* srvCfgPropEnabled = "Enabled";
-static constexpr const char* srvCfgPropRunning = "Running";
-
-enum class UpdatedProp
-{
- port = 1,
- maskedState,
- enabledState,
- runningState
-};
-
-using VariantType =
- std::variant<std::string, int64_t, uint64_t, double, int32_t, uint32_t,
- int16_t, uint16_t, uint8_t, bool,
- std::vector<std::tuple<std::string, std::string>>>;
-
-class ServiceConfig
-{
- public:
- ServiceConfig(sdbusplus::asio::object_server& srv_,
- std::shared_ptr<sdbusplus::asio::connection>& conn_,
- const std::string& objPath_, const std::string& baseUnitName,
- const std::string& instanceName,
- const std::string& serviceObjPath,
- const std::string& socketObjPath);
- ~ServiceConfig() = default;
-
- std::shared_ptr<sdbusplus::asio::connection> conn;
- uint8_t updatedFlag;
-
- void stopAndApplyUnitConfig(boost::asio::yield_context yield);
- void restartUnitConfig(boost::asio::yield_context yield);
- void startServiceRestartTimer();
-
- private:
- sdbusplus::asio::object_server& server;
- std::shared_ptr<sdbusplus::asio::dbus_interface> srvCfgIface;
- std::shared_ptr<sdbusplus::asio::dbus_interface> sockAttrIface;
-
- bool internalSet = false;
- std::string objPath;
- std::string baseUnitName;
- std::string instanceName;
- std::string instantiatedUnitName;
- std::string serviceObjectPath;
- std::string socketObjectPath;
- std::string overrideConfDir;
-
- // Properties
- std::string activeState;
- std::string subState;
- uint16_t portNum;
- std::vector<std::string> channelList;
- std::string protocol;
- std::string stateValue;
- bool unitMaskedState = false;
- bool unitEnabledState = false;
- bool unitRunningState = false;
- std::string subStateValue;
-
- bool isMaskedOut();
- void registerProperties();
- void queryAndUpdateProperties();
- void createSocketOverrideConf();
- void updateServiceProperties(
- const boost::container::flat_map<std::string, VariantType>&
- propertyMap);
- void updateSocketProperties(
- const boost::container::flat_map<std::string, VariantType>&
- propertyMap);
- std::string getSocketUnitName();
- std::string getServiceUnitName();
-};
-
-} // namespace service
-} // namespace phosphor
+/*
+// Copyright (c) 2018 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#pragma once
+#include "utils.hpp"
+
+#include <sdbusplus/timer.hpp>
+
+namespace phosphor
+{
+namespace service
+{
+
+static constexpr const char* serviceConfigSrvName =
+ "xyz.openbmc_project.Control.Service.Manager";
+static constexpr const char* serviceConfigIntfName =
+ "xyz.openbmc_project.Control.Service.Attributes";
+static constexpr const char* sockAttrIntfName =
+ "xyz.openbmc_project.Control.Service.SocketAttributes";
+static constexpr const char* srcCfgMgrBasePath =
+ "/xyz/openbmc_project/control/service";
+static constexpr const char* srcCfgMgrIntf =
+ "/xyz/openbmc_project.Control.Service.Manager";
+static constexpr const char* sockAttrPropPort = "Port";
+static constexpr const char* srvCfgPropMasked = "Masked";
+static constexpr const char* srvCfgPropEnabled = "Enabled";
+static constexpr const char* srvCfgPropRunning = "Running";
+
+enum class UpdatedProp
+{
+ port = 1,
+ maskedState,
+ enabledState,
+ runningState
+};
+
+using VariantType =
+ std::variant<std::string, int64_t, uint64_t, double, int32_t, uint32_t,
+ int16_t, uint16_t, uint8_t, bool,
+ std::vector<std::tuple<std::string, std::string>>>;
+
+class ServiceConfig
+{
+ public:
+ ServiceConfig(sdbusplus::asio::object_server& srv_,
+ std::shared_ptr<sdbusplus::asio::connection>& conn_,
+ const std::string& objPath_, const std::string& baseUnitName,
+ const std::string& instanceName,
+ const std::string& serviceObjPath,
+ const std::string& socketObjPath);
+ ~ServiceConfig() = default;
+
+ std::shared_ptr<sdbusplus::asio::connection> conn;
+ uint8_t updatedFlag;
+
+ void stopAndApplyUnitConfig(boost::asio::yield_context yield);
+ void restartUnitConfig(boost::asio::yield_context yield);
+ void startServiceRestartTimer();
+
+ private:
+ sdbusplus::asio::object_server& server;
+ std::shared_ptr<sdbusplus::asio::dbus_interface> srvCfgIface;
+ std::shared_ptr<sdbusplus::asio::dbus_interface> sockAttrIface;
+
+ bool internalSet = false;
+ std::string objPath;
+ std::string baseUnitName;
+ std::string instanceName;
+ std::string instantiatedUnitName;
+ std::string serviceObjectPath;
+ std::string socketObjectPath;
+ std::string overrideConfDir;
+
+ // Properties
+ std::string activeState;
+ std::string subState;
+ uint16_t portNum;
+ std::vector<std::string> channelList;
+ std::string protocol;
+ std::string stateValue;
+ bool unitMaskedState = false;
+ bool unitEnabledState = false;
+ bool unitRunningState = false;
+ std::string subStateValue;
+
+ bool isMaskedOut();
+ void registerProperties();
+ void queryAndUpdateProperties();
+ void createSocketOverrideConf();
+ void updateServiceProperties(
+ const boost::container::flat_map<std::string, VariantType>&
+ propertyMap);
+ void updateSocketProperties(
+ const boost::container::flat_map<std::string, VariantType>&
+ propertyMap);
+ std::string getSocketUnitName();
+ std::string getServiceUnitName();
+};
+
+} // namespace service
+} // namespace phosphor
diff --git a/inc/utils.hpp b/inc/utils.hpp
index e4a31bb..c9df6ae 100644
--- a/inc/utils.hpp
+++ b/inc/utils.hpp
@@ -1,64 +1,64 @@
-/*
-// Copyright (c) 2018 Intel Corporation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-*/
-#pragma once
-#include <boost/asio.hpp>
-#include <phosphor-logging/elog-errors.hpp>
-#include <sdbusplus/asio/object_server.hpp>
-#include <xyz/openbmc_project/Common/error.hpp>
-
-#include <chrono>
-#include <ctime>
-#include <filesystem>
-#include <string>
-
-static constexpr const char* sysdStartUnit = "StartUnit";
-static constexpr const char* sysdStopUnit = "StopUnit";
-static constexpr const char* sysdRestartUnit = "RestartUnit";
-static constexpr const char* sysdReloadMethod = "Reload";
-static constexpr const char* sysdGetJobMethod = "GetJob";
-static constexpr const char* sysdReplaceMode = "replace";
-static constexpr const char* dBusGetAllMethod = "GetAll";
-static constexpr const char* dBusGetMethod = "Get";
-static constexpr const char* sysdService = "org.freedesktop.systemd1";
-static constexpr const char* sysdObjPath = "/org/freedesktop/systemd1";
-static constexpr const char* sysdMgrIntf = "org.freedesktop.systemd1.Manager";
-static constexpr const char* sysdUnitIntf = "org.freedesktop.systemd1.Unit";
-static constexpr const char* sysdSocketIntf = "org.freedesktop.systemd1.Socket";
-static constexpr const char* dBusPropIntf = "org.freedesktop.DBus.Properties";
-static constexpr const char* stateMasked = "masked";
-static constexpr const char* stateEnabled = "enabled";
-static constexpr const char* stateDisabled = "disabled";
-static constexpr const char* subStateRunning = "running";
-
-static inline std::string addInstanceName(const std::string& instanceName,
- const std::string& suffix)
-{
- return (instanceName.empty() ? "" : suffix + instanceName);
-}
-
-void systemdDaemonReload(
- const std::shared_ptr<sdbusplus::asio::connection>& conn,
- boost::asio::yield_context yield);
-
-void systemdUnitAction(const std::shared_ptr<sdbusplus::asio::connection>& conn,
- boost::asio::yield_context yield,
- const std::string& unitName,
- const std::string& actionMethod);
-
-void systemdUnitFilesStateChange(
- const std::shared_ptr<sdbusplus::asio::connection>& conn,
- boost::asio::yield_context yield, const std::vector<std::string>& unitFiles,
- const std::string& unitState, bool maskedState, bool enabledState);
+/*
+// Copyright (c) 2018 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#pragma once
+#include <boost/asio.hpp>
+#include <phosphor-logging/elog-errors.hpp>
+#include <sdbusplus/asio/object_server.hpp>
+#include <xyz/openbmc_project/Common/error.hpp>
+
+#include <chrono>
+#include <ctime>
+#include <filesystem>
+#include <string>
+
+static constexpr const char* sysdStartUnit = "StartUnit";
+static constexpr const char* sysdStopUnit = "StopUnit";
+static constexpr const char* sysdRestartUnit = "RestartUnit";
+static constexpr const char* sysdReloadMethod = "Reload";
+static constexpr const char* sysdGetJobMethod = "GetJob";
+static constexpr const char* sysdReplaceMode = "replace";
+static constexpr const char* dBusGetAllMethod = "GetAll";
+static constexpr const char* dBusGetMethod = "Get";
+static constexpr const char* sysdService = "org.freedesktop.systemd1";
+static constexpr const char* sysdObjPath = "/org/freedesktop/systemd1";
+static constexpr const char* sysdMgrIntf = "org.freedesktop.systemd1.Manager";
+static constexpr const char* sysdUnitIntf = "org.freedesktop.systemd1.Unit";
+static constexpr const char* sysdSocketIntf = "org.freedesktop.systemd1.Socket";
+static constexpr const char* dBusPropIntf = "org.freedesktop.DBus.Properties";
+static constexpr const char* stateMasked = "masked";
+static constexpr const char* stateEnabled = "enabled";
+static constexpr const char* stateDisabled = "disabled";
+static constexpr const char* subStateRunning = "running";
+
+static inline std::string addInstanceName(const std::string& instanceName,
+ const std::string& suffix)
+{
+ return (instanceName.empty() ? "" : suffix + instanceName);
+}
+
+void systemdDaemonReload(
+ const std::shared_ptr<sdbusplus::asio::connection>& conn,
+ boost::asio::yield_context yield);
+
+void systemdUnitAction(const std::shared_ptr<sdbusplus::asio::connection>& conn,
+ boost::asio::yield_context yield,
+ const std::string& unitName,
+ const std::string& actionMethod);
+
+void systemdUnitFilesStateChange(
+ const std::shared_ptr<sdbusplus::asio::connection>& conn,
+ boost::asio::yield_context yield, const std::vector<std::string>& unitFiles,
+ const std::string& unitState, bool maskedState, bool enabledState);
diff --git a/src/main.cpp b/src/main.cpp
index d15a4b9..b45cf63 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,333 +1,333 @@
-/*
-// Copyright (c) 2018 Intel Corporation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-*/
-#include "srvcfg_manager.hpp"
-
-#include <boost/algorithm/string/replace.hpp>
-#include <cereal/archives/json.hpp>
-#include <cereal/types/tuple.hpp>
-#include <cereal/types/unordered_map.hpp>
-#include <sdbusplus/bus/match.hpp>
-
-#include <filesystem>
-#include <fstream>
-
-std::unique_ptr<boost::asio::steady_timer> timer = nullptr;
-std::unique_ptr<boost::asio::steady_timer> initTimer = nullptr;
-std::map<std::string, std::shared_ptr<phosphor::service::ServiceConfig>>
- srvMgrObjects;
-static bool unitQueryStarted = false;
-
-static constexpr const char* srvCfgMgrFile = "/etc/srvcfg-mgr.json";
-
-// Base service name list. All instance of these services and
-// units(service/socket) will be managed by this daemon.
-static std::array<std::string, 5> serviceNames = {
- "phosphor-ipmi-net", "bmcweb", "phosphor-ipmi-kcs", "start-ipkvm",
- "obmc-console"};
-
-using ListUnitsType =
- std::tuple<std::string, std::string, std::string, std::string, std::string,
- std::string, sdbusplus::message::object_path, uint32_t,
- std::string, sdbusplus::message::object_path>;
-
-enum class ListUnitElements
-{
- name,
- descriptionString,
- loadState,
- activeState,
- subState,
- followedUnit,
- objectPath,
- queuedJobType,
- jobType,
- jobObject
-};
-
-enum class UnitType
-{
- service,
- socket,
- target,
- device,
- invalid
-};
-
-using MonitorListMap =
- std::unordered_map<std::string, std::tuple<std::string, std::string,
- std::string, std::string>>;
-MonitorListMap unitsToMonitor;
-
-enum class monitorElement
-{
- unitName,
- instanceName,
- serviceObjPath,
- socketObjPath
-};
-
-std::tuple<std::string, UnitType, std::string>
- getUnitNameTypeAndInstance(const std::string& fullUnitName)
-{
- UnitType type = UnitType::invalid;
- std::string instanceName;
- std::string unitName;
- // get service type
- auto typePos = fullUnitName.rfind(".");
- if (typePos != std::string::npos)
- {
- const auto& typeStr = fullUnitName.substr(typePos + 1);
- // Ignore types other than service and socket
- if (typeStr == "service")
- {
- type = UnitType::service;
- }
- else if (typeStr == "socket")
- {
- type = UnitType::socket;
- }
- // get instance name if available
- auto instancePos = fullUnitName.rfind("@");
- if (instancePos != std::string::npos)
- {
- instanceName =
- fullUnitName.substr(instancePos + 1, typePos - instancePos - 1);
- unitName = fullUnitName.substr(0, instancePos);
- }
- else
- {
- unitName = fullUnitName.substr(0, typePos);
- }
- }
- return std::make_tuple(unitName, type, instanceName);
-}
-
-static inline void
- handleListUnitsResponse(sdbusplus::asio::object_server& server,
- std::shared_ptr<sdbusplus::asio::connection>& conn,
- boost::system::error_code /*ec*/,
- const std::vector<ListUnitsType>& listUnits)
-{
- // Loop through all units, and mark all units, which has to be
- // managed, irrespective of instance name.
- for (const auto& unit : listUnits)
- {
- const auto& fullUnitName =
- std::get<static_cast<int>(ListUnitElements::name)>(unit);
- auto [unitName, type, instanceName] =
- getUnitNameTypeAndInstance(fullUnitName);
- if (std::find(serviceNames.begin(), serviceNames.end(), unitName) !=
- serviceNames.end())
- {
- std::string instantiatedUnitName =
- unitName + addInstanceName(instanceName, "_40");
- boost::replace_all(instantiatedUnitName, "-", "_2d");
- const sdbusplus::message::object_path& objectPath =
- std::get<static_cast<int>(ListUnitElements::objectPath)>(unit);
- // Group the service & socket units togther.. Same services
- // are managed together.
- auto it = unitsToMonitor.find(instantiatedUnitName);
- if (it != unitsToMonitor.end())
- {
- auto& value = it->second;
- if (type == UnitType::service)
- {
- std::get<static_cast<int>(monitorElement::unitName)>(
- value) = unitName;
- std::get<static_cast<int>(monitorElement::instanceName)>(
- value) = instanceName;
- std::get<static_cast<int>(monitorElement::serviceObjPath)>(
- value) = objectPath;
- }
- else if (type == UnitType::socket)
- {
- std::get<static_cast<int>(monitorElement::socketObjPath)>(
- value) = objectPath;
- }
- }
- if (type == UnitType::service)
- {
- unitsToMonitor.emplace(instantiatedUnitName,
- std::make_tuple(unitName, instanceName,
- objectPath.str, ""));
- }
- else if (type == UnitType::socket)
- {
- unitsToMonitor.emplace(
- instantiatedUnitName,
- std::make_tuple("", "", "", objectPath.str));
- }
- }
- }
-
- bool updateRequired = false;
- bool jsonExist = std::filesystem::exists(srvCfgMgrFile);
- if (jsonExist)
- {
- std::ifstream file(srvCfgMgrFile);
- cereal::JSONInputArchive archive(file);
- MonitorListMap savedMonitorList;
- archive(savedMonitorList);
-
- // compare the unit list read from systemd1 and the save list.
- MonitorListMap diffMap;
- std::set_difference(begin(unitsToMonitor), end(unitsToMonitor),
- begin(savedMonitorList), end(savedMonitorList),
- std::inserter(diffMap, begin(diffMap)));
- for (auto& unitIt : diffMap)
- {
- auto it = savedMonitorList.find(unitIt.first);
- if (it == savedMonitorList.end())
- {
- savedMonitorList.insert(unitIt);
- updateRequired = true;
- }
- }
- unitsToMonitor = savedMonitorList;
- }
- if (!jsonExist || updateRequired)
- {
- std::ofstream file(srvCfgMgrFile);
- cereal::JSONOutputArchive archive(file);
- archive(CEREAL_NVP(unitsToMonitor));
- }
-
- // create objects for needed services
- for (auto& it : unitsToMonitor)
- {
- std::string objPath(std::string(phosphor::service::srcCfgMgrBasePath) +
- "/" + it.first);
- std::string instanciatedUnitName =
- std::get<static_cast<int>(monitorElement::unitName)>(it.second) +
- addInstanceName(
- std::get<static_cast<int>(monitorElement::instanceName)>(
- it.second),
- "@");
- auto srvCfgObj = std::make_unique<phosphor::service::ServiceConfig>(
- server, conn, objPath,
- std::get<static_cast<int>(monitorElement::unitName)>(it.second),
- std::get<static_cast<int>(monitorElement::instanceName)>(it.second),
- std::get<static_cast<int>(monitorElement::serviceObjPath)>(
- it.second),
- std::get<static_cast<int>(monitorElement::socketObjPath)>(
- it.second));
- srvMgrObjects.emplace(
- std::make_pair(std::move(objPath), std::move(srvCfgObj)));
- }
-}
-
-void init(sdbusplus::asio::object_server& server,
- std::shared_ptr<sdbusplus::asio::connection>& conn)
-{
- // Go through all systemd units, and dynamically detect and manage
- // the service daemons
- conn->async_method_call(
- [&server, &conn](boost::system::error_code ec,
- const std::vector<ListUnitsType>& listUnits) {
- if (ec)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "async_method_call error: ListUnits failed");
- return;
- }
- handleListUnitsResponse(server, conn, ec, listUnits);
- },
- sysdService, sysdObjPath, sysdMgrIntf, "ListUnits");
-}
-
-void checkAndInit(sdbusplus::asio::object_server& server,
- std::shared_ptr<sdbusplus::asio::connection>& conn)
-{
- // Check whether systemd completed all the loading before initializing
- conn->async_method_call(
- [&server, &conn](boost::system::error_code ec,
- const std::variant<uint64_t>& value) {
- if (ec)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "async_method_call error: ListUnits failed");
- return;
- }
- if (std::get<uint64_t>(value))
- {
- if (!unitQueryStarted)
- {
- unitQueryStarted = true;
- init(server, conn);
- }
- }
- else
- {
- // FIX-ME: Latest up-stream sync caused issue in receiving
- // StartupFinished signal. Unable to get StartupFinished signal
- // from systemd1 hence using poll method too, to trigger it
- // properly.
- constexpr size_t pollTimeout = 10; // seconds
- initTimer->expires_after(std::chrono::seconds(pollTimeout));
- initTimer->async_wait([&server, &conn](
- const boost::system::error_code& ec) {
- if (ec == boost::asio::error::operation_aborted)
- {
- // Timer reset.
- return;
- }
- if (ec)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "service config mgr - init - async wait error.");
- return;
- }
- checkAndInit(server, conn);
- });
- }
- },
- sysdService, sysdObjPath, dBusPropIntf, dBusGetMethod, sysdMgrIntf,
- "FinishTimestamp");
-}
-
-int main()
-{
- boost::asio::io_service io;
- auto conn = std::make_shared<sdbusplus::asio::connection>(io);
- timer = std::make_unique<boost::asio::steady_timer>(io);
- initTimer = std::make_unique<boost::asio::steady_timer>(io);
- conn->request_name(phosphor::service::serviceConfigSrvName);
- auto server = sdbusplus::asio::object_server(conn, true);
- auto mgrIntf = server.add_interface(phosphor::service::srcCfgMgrBasePath,
- phosphor::service::srcCfgMgrIntf);
- mgrIntf->initialize();
- server.add_manager(phosphor::service::srcCfgMgrBasePath);
- // Initialize the objects after systemd indicated startup finished.
- auto userUpdatedSignal = std::make_unique<sdbusplus::bus::match::match>(
- static_cast<sdbusplus::bus::bus&>(*conn),
- "type='signal',"
- "member='StartupFinished',path='/org/freedesktop/systemd1',"
- "interface='org.freedesktop.systemd1.Manager'",
- [&server, &conn](sdbusplus::message::message& /*msg*/) {
- if (!unitQueryStarted)
- {
- unitQueryStarted = true;
- init(server, conn);
- }
- });
- // this will make sure to initialize the objects, when daemon is
- // restarted.
- checkAndInit(server, conn);
-
- io.run();
-
- return 0;
-}
+/*
+// Copyright (c) 2018 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include "srvcfg_manager.hpp"
+
+#include <boost/algorithm/string/replace.hpp>
+#include <cereal/archives/json.hpp>
+#include <cereal/types/tuple.hpp>
+#include <cereal/types/unordered_map.hpp>
+#include <sdbusplus/bus/match.hpp>
+
+#include <filesystem>
+#include <fstream>
+
+std::unique_ptr<boost::asio::steady_timer> timer = nullptr;
+std::unique_ptr<boost::asio::steady_timer> initTimer = nullptr;
+std::map<std::string, std::shared_ptr<phosphor::service::ServiceConfig>>
+ srvMgrObjects;
+static bool unitQueryStarted = false;
+
+static constexpr const char* srvCfgMgrFile = "/etc/srvcfg-mgr.json";
+
+// Base service name list. All instance of these services and
+// units(service/socket) will be managed by this daemon.
+static std::array<std::string, 5> serviceNames = {
+ "phosphor-ipmi-net", "bmcweb", "phosphor-ipmi-kcs", "start-ipkvm",
+ "obmc-console"};
+
+using ListUnitsType =
+ std::tuple<std::string, std::string, std::string, std::string, std::string,
+ std::string, sdbusplus::message::object_path, uint32_t,
+ std::string, sdbusplus::message::object_path>;
+
+enum class ListUnitElements
+{
+ name,
+ descriptionString,
+ loadState,
+ activeState,
+ subState,
+ followedUnit,
+ objectPath,
+ queuedJobType,
+ jobType,
+ jobObject
+};
+
+enum class UnitType
+{
+ service,
+ socket,
+ target,
+ device,
+ invalid
+};
+
+using MonitorListMap =
+ std::unordered_map<std::string, std::tuple<std::string, std::string,
+ std::string, std::string>>;
+MonitorListMap unitsToMonitor;
+
+enum class monitorElement
+{
+ unitName,
+ instanceName,
+ serviceObjPath,
+ socketObjPath
+};
+
+std::tuple<std::string, UnitType, std::string>
+ getUnitNameTypeAndInstance(const std::string& fullUnitName)
+{
+ UnitType type = UnitType::invalid;
+ std::string instanceName;
+ std::string unitName;
+ // get service type
+ auto typePos = fullUnitName.rfind(".");
+ if (typePos != std::string::npos)
+ {
+ const auto& typeStr = fullUnitName.substr(typePos + 1);
+ // Ignore types other than service and socket
+ if (typeStr == "service")
+ {
+ type = UnitType::service;
+ }
+ else if (typeStr == "socket")
+ {
+ type = UnitType::socket;
+ }
+ // get instance name if available
+ auto instancePos = fullUnitName.rfind("@");
+ if (instancePos != std::string::npos)
+ {
+ instanceName =
+ fullUnitName.substr(instancePos + 1, typePos - instancePos - 1);
+ unitName = fullUnitName.substr(0, instancePos);
+ }
+ else
+ {
+ unitName = fullUnitName.substr(0, typePos);
+ }
+ }
+ return std::make_tuple(unitName, type, instanceName);
+}
+
+static inline void
+ handleListUnitsResponse(sdbusplus::asio::object_server& server,
+ std::shared_ptr<sdbusplus::asio::connection>& conn,
+ boost::system::error_code /*ec*/,
+ const std::vector<ListUnitsType>& listUnits)
+{
+ // Loop through all units, and mark all units, which has to be
+ // managed, irrespective of instance name.
+ for (const auto& unit : listUnits)
+ {
+ const auto& fullUnitName =
+ std::get<static_cast<int>(ListUnitElements::name)>(unit);
+ auto [unitName, type, instanceName] =
+ getUnitNameTypeAndInstance(fullUnitName);
+ if (std::find(serviceNames.begin(), serviceNames.end(), unitName) !=
+ serviceNames.end())
+ {
+ std::string instantiatedUnitName =
+ unitName + addInstanceName(instanceName, "_40");
+ boost::replace_all(instantiatedUnitName, "-", "_2d");
+ const sdbusplus::message::object_path& objectPath =
+ std::get<static_cast<int>(ListUnitElements::objectPath)>(unit);
+ // Group the service & socket units togther.. Same services
+ // are managed together.
+ auto it = unitsToMonitor.find(instantiatedUnitName);
+ if (it != unitsToMonitor.end())
+ {
+ auto& value = it->second;
+ if (type == UnitType::service)
+ {
+ std::get<static_cast<int>(monitorElement::unitName)>(
+ value) = unitName;
+ std::get<static_cast<int>(monitorElement::instanceName)>(
+ value) = instanceName;
+ std::get<static_cast<int>(monitorElement::serviceObjPath)>(
+ value) = objectPath;
+ }
+ else if (type == UnitType::socket)
+ {
+ std::get<static_cast<int>(monitorElement::socketObjPath)>(
+ value) = objectPath;
+ }
+ }
+ if (type == UnitType::service)
+ {
+ unitsToMonitor.emplace(instantiatedUnitName,
+ std::make_tuple(unitName, instanceName,
+ objectPath.str, ""));
+ }
+ else if (type == UnitType::socket)
+ {
+ unitsToMonitor.emplace(
+ instantiatedUnitName,
+ std::make_tuple("", "", "", objectPath.str));
+ }
+ }
+ }
+
+ bool updateRequired = false;
+ bool jsonExist = std::filesystem::exists(srvCfgMgrFile);
+ if (jsonExist)
+ {
+ std::ifstream file(srvCfgMgrFile);
+ cereal::JSONInputArchive archive(file);
+ MonitorListMap savedMonitorList;
+ archive(savedMonitorList);
+
+ // compare the unit list read from systemd1 and the save list.
+ MonitorListMap diffMap;
+ std::set_difference(begin(unitsToMonitor), end(unitsToMonitor),
+ begin(savedMonitorList), end(savedMonitorList),
+ std::inserter(diffMap, begin(diffMap)));
+ for (auto& unitIt : diffMap)
+ {
+ auto it = savedMonitorList.find(unitIt.first);
+ if (it == savedMonitorList.end())
+ {
+ savedMonitorList.insert(unitIt);
+ updateRequired = true;
+ }
+ }
+ unitsToMonitor = savedMonitorList;
+ }
+ if (!jsonExist || updateRequired)
+ {
+ std::ofstream file(srvCfgMgrFile);
+ cereal::JSONOutputArchive archive(file);
+ archive(CEREAL_NVP(unitsToMonitor));
+ }
+
+ // create objects for needed services
+ for (auto& it : unitsToMonitor)
+ {
+ std::string objPath(std::string(phosphor::service::srcCfgMgrBasePath) +
+ "/" + it.first);
+ std::string instanciatedUnitName =
+ std::get<static_cast<int>(monitorElement::unitName)>(it.second) +
+ addInstanceName(
+ std::get<static_cast<int>(monitorElement::instanceName)>(
+ it.second),
+ "@");
+ auto srvCfgObj = std::make_unique<phosphor::service::ServiceConfig>(
+ server, conn, objPath,
+ std::get<static_cast<int>(monitorElement::unitName)>(it.second),
+ std::get<static_cast<int>(monitorElement::instanceName)>(it.second),
+ std::get<static_cast<int>(monitorElement::serviceObjPath)>(
+ it.second),
+ std::get<static_cast<int>(monitorElement::socketObjPath)>(
+ it.second));
+ srvMgrObjects.emplace(
+ std::make_pair(std::move(objPath), std::move(srvCfgObj)));
+ }
+}
+
+void init(sdbusplus::asio::object_server& server,
+ std::shared_ptr<sdbusplus::asio::connection>& conn)
+{
+ // Go through all systemd units, and dynamically detect and manage
+ // the service daemons
+ conn->async_method_call(
+ [&server, &conn](boost::system::error_code ec,
+ const std::vector<ListUnitsType>& listUnits) {
+ if (ec)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "async_method_call error: ListUnits failed");
+ return;
+ }
+ handleListUnitsResponse(server, conn, ec, listUnits);
+ },
+ sysdService, sysdObjPath, sysdMgrIntf, "ListUnits");
+}
+
+void checkAndInit(sdbusplus::asio::object_server& server,
+ std::shared_ptr<sdbusplus::asio::connection>& conn)
+{
+ // Check whether systemd completed all the loading before initializing
+ conn->async_method_call(
+ [&server, &conn](boost::system::error_code ec,
+ const std::variant<uint64_t>& value) {
+ if (ec)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "async_method_call error: ListUnits failed");
+ return;
+ }
+ if (std::get<uint64_t>(value))
+ {
+ if (!unitQueryStarted)
+ {
+ unitQueryStarted = true;
+ init(server, conn);
+ }
+ }
+ else
+ {
+ // FIX-ME: Latest up-stream sync caused issue in receiving
+ // StartupFinished signal. Unable to get StartupFinished signal
+ // from systemd1 hence using poll method too, to trigger it
+ // properly.
+ constexpr size_t pollTimeout = 10; // seconds
+ initTimer->expires_after(std::chrono::seconds(pollTimeout));
+ initTimer->async_wait([&server, &conn](
+ const boost::system::error_code& ec) {
+ if (ec == boost::asio::error::operation_aborted)
+ {
+ // Timer reset.
+ return;
+ }
+ if (ec)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "service config mgr - init - async wait error.");
+ return;
+ }
+ checkAndInit(server, conn);
+ });
+ }
+ },
+ sysdService, sysdObjPath, dBusPropIntf, dBusGetMethod, sysdMgrIntf,
+ "FinishTimestamp");
+}
+
+int main()
+{
+ boost::asio::io_service io;
+ auto conn = std::make_shared<sdbusplus::asio::connection>(io);
+ timer = std::make_unique<boost::asio::steady_timer>(io);
+ initTimer = std::make_unique<boost::asio::steady_timer>(io);
+ conn->request_name(phosphor::service::serviceConfigSrvName);
+ auto server = sdbusplus::asio::object_server(conn, true);
+ auto mgrIntf = server.add_interface(phosphor::service::srcCfgMgrBasePath,
+ phosphor::service::srcCfgMgrIntf);
+ mgrIntf->initialize();
+ server.add_manager(phosphor::service::srcCfgMgrBasePath);
+ // Initialize the objects after systemd indicated startup finished.
+ auto userUpdatedSignal = std::make_unique<sdbusplus::bus::match::match>(
+ static_cast<sdbusplus::bus::bus&>(*conn),
+ "type='signal',"
+ "member='StartupFinished',path='/org/freedesktop/systemd1',"
+ "interface='org.freedesktop.systemd1.Manager'",
+ [&server, &conn](sdbusplus::message::message& /*msg*/) {
+ if (!unitQueryStarted)
+ {
+ unitQueryStarted = true;
+ init(server, conn);
+ }
+ });
+ // this will make sure to initialize the objects, when daemon is
+ // restarted.
+ checkAndInit(server, conn);
+
+ io.run();
+
+ return 0;
+}
diff --git a/src/srvcfg_manager.cpp b/src/srvcfg_manager.cpp
index 2d346c2..038d11a 100644
--- a/src/srvcfg_manager.cpp
+++ b/src/srvcfg_manager.cpp
@@ -1,505 +1,505 @@
-/*
-// Copyright (c) 2018 Intel Corporation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-*/
-#include "srvcfg_manager.hpp"
-
-#include <boost/asio/spawn.hpp>
-
-#include <fstream>
-#include <regex>
-
-extern std::unique_ptr<boost::asio::steady_timer> timer;
-extern std::map<std::string, std::shared_ptr<phosphor::service::ServiceConfig>>
- srvMgrObjects;
-static bool updateInProgress = false;
-
-namespace phosphor
-{
-namespace service
-{
-
-static constexpr const char* overrideConfFileName = "override.conf";
-static constexpr const size_t restartTimeout = 15; // seconds
-
-static constexpr const char* systemd1UnitBasePath =
- "/org/freedesktop/systemd1/unit/";
-static constexpr const char* systemdOverrideUnitBasePath =
- "/etc/systemd/system/";
-
-void ServiceConfig::updateSocketProperties(
- const boost::container::flat_map<std::string, VariantType>& propertyMap)
-{
- auto listenIt = propertyMap.find("Listen");
- if (listenIt != propertyMap.end())
- {
- auto listenVal =
- std::get<std::vector<std::tuple<std::string, std::string>>>(
- listenIt->second);
- if (listenVal.size())
- {
- protocol = std::get<0>(listenVal[0]);
- std::string port = std::get<1>(listenVal[0]);
- auto tmp = std::stoul(port.substr(port.find_last_of(":") + 1),
- nullptr, 10);
- if (tmp > std::numeric_limits<uint16_t>::max())
- {
- throw std::out_of_range("Out of range");
- }
- portNum = tmp;
- if (sockAttrIface && sockAttrIface->is_initialized())
- {
- internalSet = true;
- sockAttrIface->set_property(sockAttrPropPort, portNum);
- internalSet = false;
- }
- }
- }
-}
-
-void ServiceConfig::updateServiceProperties(
- const boost::container::flat_map<std::string, VariantType>& propertyMap)
-{
- auto stateIt = propertyMap.find("UnitFileState");
- if (stateIt != propertyMap.end())
- {
- stateValue = std::get<std::string>(stateIt->second);
- unitEnabledState = unitMaskedState = false;
- if (stateValue == stateMasked)
- {
- unitMaskedState = true;
- }
- else if (stateValue == stateEnabled)
- {
- unitEnabledState = true;
- }
- if (srvCfgIface && srvCfgIface->is_initialized())
- {
- internalSet = true;
- srvCfgIface->set_property(srvCfgPropMasked, unitMaskedState);
- srvCfgIface->set_property(srvCfgPropEnabled, unitEnabledState);
- internalSet = false;
- }
- }
- auto subStateIt = propertyMap.find("SubState");
- if (subStateIt != propertyMap.end())
- {
- subStateValue = std::get<std::string>(subStateIt->second);
- if (subStateValue == subStateRunning)
- {
- unitRunningState = true;
- }
- if (srvCfgIface && srvCfgIface->is_initialized())
- {
- internalSet = true;
- srvCfgIface->set_property(srvCfgPropRunning, unitRunningState);
- internalSet = false;
- }
- }
-}
-
-void ServiceConfig::queryAndUpdateProperties()
-{
- conn->async_method_call(
- [this](boost::system::error_code ec,
- const boost::container::flat_map<std::string, VariantType>&
- propertyMap) {
- if (ec)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "async_method_call error: Failed to service unit "
- "properties");
- return;
- }
- try
- {
- updateServiceProperties(propertyMap);
- if (!socketObjectPath.empty())
- {
- conn->async_method_call(
- [this](boost::system::error_code ec,
- const boost::container::flat_map<
- std::string, VariantType>& propertyMap) {
- if (ec)
- {
- phosphor::logging::log<
- phosphor::logging::level::ERR>(
- "async_method_call error: Failed to get "
- "all property");
- return;
- }
- try
- {
- updateSocketProperties(propertyMap);
- if (!srvCfgIface)
- {
- registerProperties();
- }
- }
- catch (const std::exception& e)
- {
- phosphor::logging::log<
- phosphor::logging::level::ERR>(
- "Exception in getting socket properties",
- phosphor::logging::entry("WHAT=%s",
- e.what()));
- return;
- }
- },
- sysdService, socketObjectPath, dBusPropIntf,
- dBusGetAllMethod, sysdSocketIntf);
- }
- else if (!srvCfgIface)
- {
- registerProperties();
- }
- }
- catch (const std::exception& e)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "Exception in getting socket properties",
- phosphor::logging::entry("WHAT=%s", e.what()));
- return;
- }
- },
- sysdService, serviceObjectPath, dBusPropIntf, dBusGetAllMethod,
- sysdUnitIntf);
- return;
-}
-
-void ServiceConfig::createSocketOverrideConf()
-{
- if (!socketObjectPath.empty())
- {
- std::string socketUnitName(instantiatedUnitName + ".socket");
- /// Check override socket directory exist, if not create it.
- std::filesystem::path ovrUnitFileDir(systemdOverrideUnitBasePath);
- ovrUnitFileDir += socketUnitName;
- ovrUnitFileDir += ".d";
- if (!std::filesystem::exists(ovrUnitFileDir))
- {
- if (!std::filesystem::create_directories(ovrUnitFileDir))
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "Unable to create the directory.",
- phosphor::logging::entry("DIR=%s", ovrUnitFileDir.c_str()));
- phosphor::logging::elog<sdbusplus::xyz::openbmc_project::
- Common::Error::InternalFailure>();
- }
- }
- overrideConfDir = std::string(ovrUnitFileDir);
- }
-}
-
-ServiceConfig::ServiceConfig(
- sdbusplus::asio::object_server& srv_,
- std::shared_ptr<sdbusplus::asio::connection>& conn_,
- const std::string& objPath_, const std::string& baseUnitName_,
- const std::string& instanceName_, const std::string& serviceObjPath_,
- const std::string& socketObjPath_) :
- conn(conn_),
- server(srv_), objPath(objPath_), baseUnitName(baseUnitName_),
- instanceName(instanceName_), serviceObjectPath(serviceObjPath_),
- socketObjectPath(socketObjPath_)
-{
- instantiatedUnitName = baseUnitName + addInstanceName(instanceName, "@");
- updatedFlag = 0;
- queryAndUpdateProperties();
- return;
-}
-
-std::string ServiceConfig::getSocketUnitName()
-{
- return instantiatedUnitName + ".socket";
-}
-
-std::string ServiceConfig::getServiceUnitName()
-{
- return instantiatedUnitName + ".service";
-}
-
-bool ServiceConfig::isMaskedOut()
-{
- // return true if state is masked & no request to update the maskedState
- return (
- stateValue == "masked" &&
- !(updatedFlag & (1 << static_cast<uint8_t>(UpdatedProp::maskedState))));
-}
-
-void ServiceConfig::stopAndApplyUnitConfig(boost::asio::yield_context yield)
-{
- if (!updatedFlag || isMaskedOut())
- {
- // No updates / masked - Just return.
- return;
- }
- phosphor::logging::log<phosphor::logging::level::INFO>(
- "Applying new settings.",
- phosphor::logging::entry("OBJPATH=%s", objPath.c_str()));
- if (subStateValue == "running")
- {
- if (!socketObjectPath.empty())
- {
- systemdUnitAction(conn, yield, getSocketUnitName(), sysdStopUnit);
- }
- systemdUnitAction(conn, yield, getServiceUnitName(), sysdStopUnit);
- }
-
- if (updatedFlag & (1 << static_cast<uint8_t>(UpdatedProp::port)))
- {
- createSocketOverrideConf();
- // Create override config file and write data.
- std::string ovrCfgFile{overrideConfDir + "/" + overrideConfFileName};
- std::string tmpFile{ovrCfgFile + "_tmp"};
- std::ofstream cfgFile(tmpFile, std::ios::out);
- if (!cfgFile.good())
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "Failed to open override.conf_tmp file");
- phosphor::logging::elog<sdbusplus::xyz::openbmc_project::Common::
- Error::InternalFailure>();
- }
-
- // Write the socket header
- cfgFile << "[Socket]\n";
- // Listen
- cfgFile << "Listen" << protocol << "="
- << "\n";
- cfgFile << "Listen" << protocol << "=" << portNum << "\n";
- cfgFile.close();
-
- if (std::rename(tmpFile.c_str(), ovrCfgFile.c_str()) != 0)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "Failed to rename tmp file as override.conf");
- std::remove(tmpFile.c_str());
- phosphor::logging::elog<sdbusplus::xyz::openbmc_project::Common::
- Error::InternalFailure>();
- }
- }
-
- if (updatedFlag & ((1 << static_cast<uint8_t>(UpdatedProp::maskedState)) |
- (1 << static_cast<uint8_t>(UpdatedProp::enabledState))))
- {
- std::vector<std::string> unitFiles;
- if (socketObjectPath.empty())
- {
- unitFiles = {getServiceUnitName()};
- }
- else
- {
- unitFiles = {getSocketUnitName(), getServiceUnitName()};
- }
- systemdUnitFilesStateChange(conn, yield, unitFiles, stateValue,
- unitMaskedState, unitEnabledState);
- }
- return;
-}
-void ServiceConfig::restartUnitConfig(boost::asio::yield_context yield)
-{
- if (!updatedFlag || isMaskedOut())
- {
- // No updates. Just return.
- return;
- }
-
- if (unitRunningState)
- {
- if (!socketObjectPath.empty())
- {
- systemdUnitAction(conn, yield, getSocketUnitName(),
- sysdRestartUnit);
- }
- systemdUnitAction(conn, yield, getServiceUnitName(), sysdRestartUnit);
- }
-
- // Reset the flag
- updatedFlag = 0;
-
- phosphor::logging::log<phosphor::logging::level::INFO>(
- "Applied new settings",
- phosphor::logging::entry("OBJPATH=%s", objPath.c_str()));
-
- queryAndUpdateProperties();
- return;
-}
-
-void ServiceConfig::startServiceRestartTimer()
-{
- timer->expires_after(std::chrono::seconds(restartTimeout));
- timer->async_wait([this](const boost::system::error_code& ec) {
- if (ec == boost::asio::error::operation_aborted)
- {
- // Timer reset.
- return;
- }
- else if (ec)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "async wait error.");
- return;
- }
- updateInProgress = true;
- boost::asio::spawn(conn->get_io_context(),
- [this](boost::asio::yield_context yield) {
- // Stop and apply configuration for all objects
- for (auto& srvMgrObj : srvMgrObjects)
- {
- auto& srvObj = srvMgrObj.second;
- if (srvObj->updatedFlag)
- {
- srvObj->stopAndApplyUnitConfig(yield);
- }
- }
- // Do system reload
- systemdDaemonReload(conn, yield);
- // restart unit config.
- for (auto& srvMgrObj : srvMgrObjects)
- {
- auto& srvObj = srvMgrObj.second;
- if (srvObj->updatedFlag)
- {
- srvObj->restartUnitConfig(yield);
- }
- }
- updateInProgress = false;
- });
- });
-}
-
-void ServiceConfig::registerProperties()
-{
- srvCfgIface = server.add_interface(objPath, serviceConfigIntfName);
-
- if (!socketObjectPath.empty())
- {
- sockAttrIface = server.add_interface(objPath, sockAttrIntfName);
- sockAttrIface->register_property(
- sockAttrPropPort, portNum,
- [this](const uint16_t& req, uint16_t& res) {
- if (!internalSet)
- {
- if (req == res)
- {
- return 1;
- }
- if (updateInProgress)
- {
- return 0;
- }
- portNum = req;
- updatedFlag |=
- (1 << static_cast<uint8_t>(UpdatedProp::port));
- startServiceRestartTimer();
- }
- res = req;
- return 1;
- });
- }
-
- srvCfgIface->register_property(
- srvCfgPropMasked, unitMaskedState, [this](const bool& req, bool& res) {
- if (!internalSet)
- {
- if (req == res)
- {
- return 1;
- }
- if (updateInProgress)
- {
- return 0;
- }
- unitMaskedState = req;
- unitEnabledState = !unitMaskedState;
- unitRunningState = !unitMaskedState;
- updatedFlag |=
- (1 << static_cast<uint8_t>(UpdatedProp::maskedState)) |
- (1 << static_cast<uint8_t>(UpdatedProp::enabledState)) |
- (1 << static_cast<uint8_t>(UpdatedProp::runningState));
- internalSet = true;
- srvCfgIface->set_property(srvCfgPropEnabled, unitEnabledState);
- srvCfgIface->set_property(srvCfgPropRunning, unitRunningState);
- internalSet = false;
- startServiceRestartTimer();
- }
- res = req;
- return 1;
- });
-
- srvCfgIface->register_property(
- srvCfgPropEnabled, unitEnabledState,
- [this](const bool& req, bool& res) {
- if (!internalSet)
- {
- if (req == res)
- {
- return 1;
- }
- if (updateInProgress)
- {
- return 0;
- }
- if (unitMaskedState)
- { // block updating if masked
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "Invalid value specified");
- return -EINVAL;
- }
- unitEnabledState = req;
- updatedFlag |=
- (1 << static_cast<uint8_t>(UpdatedProp::enabledState));
- startServiceRestartTimer();
- }
- res = req;
- return 1;
- });
-
- srvCfgIface->register_property(
- srvCfgPropRunning, unitRunningState,
- [this](const bool& req, bool& res) {
- if (!internalSet)
- {
- if (req == res)
- {
- return 1;
- }
- if (updateInProgress)
- {
- return 0;
- }
- if (unitMaskedState)
- { // block updating if masked
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "Invalid value specified");
- return -EINVAL;
- }
- unitRunningState = req;
- updatedFlag |=
- (1 << static_cast<uint8_t>(UpdatedProp::runningState));
- startServiceRestartTimer();
- }
- res = req;
- return 1;
- });
-
- srvCfgIface->initialize();
- if (!socketObjectPath.empty())
- {
- sockAttrIface->initialize();
- }
- return;
-}
-
-} // namespace service
-} // namespace phosphor
+/*
+// Copyright (c) 2018 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include "srvcfg_manager.hpp"
+
+#include <boost/asio/spawn.hpp>
+
+#include <fstream>
+#include <regex>
+
+extern std::unique_ptr<boost::asio::steady_timer> timer;
+extern std::map<std::string, std::shared_ptr<phosphor::service::ServiceConfig>>
+ srvMgrObjects;
+static bool updateInProgress = false;
+
+namespace phosphor
+{
+namespace service
+{
+
+static constexpr const char* overrideConfFileName = "override.conf";
+static constexpr const size_t restartTimeout = 15; // seconds
+
+static constexpr const char* systemd1UnitBasePath =
+ "/org/freedesktop/systemd1/unit/";
+static constexpr const char* systemdOverrideUnitBasePath =
+ "/etc/systemd/system/";
+
+void ServiceConfig::updateSocketProperties(
+ const boost::container::flat_map<std::string, VariantType>& propertyMap)
+{
+ auto listenIt = propertyMap.find("Listen");
+ if (listenIt != propertyMap.end())
+ {
+ auto listenVal =
+ std::get<std::vector<std::tuple<std::string, std::string>>>(
+ listenIt->second);
+ if (listenVal.size())
+ {
+ protocol = std::get<0>(listenVal[0]);
+ std::string port = std::get<1>(listenVal[0]);
+ auto tmp = std::stoul(port.substr(port.find_last_of(":") + 1),
+ nullptr, 10);
+ if (tmp > std::numeric_limits<uint16_t>::max())
+ {
+ throw std::out_of_range("Out of range");
+ }
+ portNum = tmp;
+ if (sockAttrIface && sockAttrIface->is_initialized())
+ {
+ internalSet = true;
+ sockAttrIface->set_property(sockAttrPropPort, portNum);
+ internalSet = false;
+ }
+ }
+ }
+}
+
+void ServiceConfig::updateServiceProperties(
+ const boost::container::flat_map<std::string, VariantType>& propertyMap)
+{
+ auto stateIt = propertyMap.find("UnitFileState");
+ if (stateIt != propertyMap.end())
+ {
+ stateValue = std::get<std::string>(stateIt->second);
+ unitEnabledState = unitMaskedState = false;
+ if (stateValue == stateMasked)
+ {
+ unitMaskedState = true;
+ }
+ else if (stateValue == stateEnabled)
+ {
+ unitEnabledState = true;
+ }
+ if (srvCfgIface && srvCfgIface->is_initialized())
+ {
+ internalSet = true;
+ srvCfgIface->set_property(srvCfgPropMasked, unitMaskedState);
+ srvCfgIface->set_property(srvCfgPropEnabled, unitEnabledState);
+ internalSet = false;
+ }
+ }
+ auto subStateIt = propertyMap.find("SubState");
+ if (subStateIt != propertyMap.end())
+ {
+ subStateValue = std::get<std::string>(subStateIt->second);
+ if (subStateValue == subStateRunning)
+ {
+ unitRunningState = true;
+ }
+ if (srvCfgIface && srvCfgIface->is_initialized())
+ {
+ internalSet = true;
+ srvCfgIface->set_property(srvCfgPropRunning, unitRunningState);
+ internalSet = false;
+ }
+ }
+}
+
+void ServiceConfig::queryAndUpdateProperties()
+{
+ conn->async_method_call(
+ [this](boost::system::error_code ec,
+ const boost::container::flat_map<std::string, VariantType>&
+ propertyMap) {
+ if (ec)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "async_method_call error: Failed to service unit "
+ "properties");
+ return;
+ }
+ try
+ {
+ updateServiceProperties(propertyMap);
+ if (!socketObjectPath.empty())
+ {
+ conn->async_method_call(
+ [this](boost::system::error_code ec,
+ const boost::container::flat_map<
+ std::string, VariantType>& propertyMap) {
+ if (ec)
+ {
+ phosphor::logging::log<
+ phosphor::logging::level::ERR>(
+ "async_method_call error: Failed to get "
+ "all property");
+ return;
+ }
+ try
+ {
+ updateSocketProperties(propertyMap);
+ if (!srvCfgIface)
+ {
+ registerProperties();
+ }
+ }
+ catch (const std::exception& e)
+ {
+ phosphor::logging::log<
+ phosphor::logging::level::ERR>(
+ "Exception in getting socket properties",
+ phosphor::logging::entry("WHAT=%s",
+ e.what()));
+ return;
+ }
+ },
+ sysdService, socketObjectPath, dBusPropIntf,
+ dBusGetAllMethod, sysdSocketIntf);
+ }
+ else if (!srvCfgIface)
+ {
+ registerProperties();
+ }
+ }
+ catch (const std::exception& e)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Exception in getting socket properties",
+ phosphor::logging::entry("WHAT=%s", e.what()));
+ return;
+ }
+ },
+ sysdService, serviceObjectPath, dBusPropIntf, dBusGetAllMethod,
+ sysdUnitIntf);
+ return;
+}
+
+void ServiceConfig::createSocketOverrideConf()
+{
+ if (!socketObjectPath.empty())
+ {
+ std::string socketUnitName(instantiatedUnitName + ".socket");
+ /// Check override socket directory exist, if not create it.
+ std::filesystem::path ovrUnitFileDir(systemdOverrideUnitBasePath);
+ ovrUnitFileDir += socketUnitName;
+ ovrUnitFileDir += ".d";
+ if (!std::filesystem::exists(ovrUnitFileDir))
+ {
+ if (!std::filesystem::create_directories(ovrUnitFileDir))
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Unable to create the directory.",
+ phosphor::logging::entry("DIR=%s", ovrUnitFileDir.c_str()));
+ phosphor::logging::elog<sdbusplus::xyz::openbmc_project::
+ Common::Error::InternalFailure>();
+ }
+ }
+ overrideConfDir = std::string(ovrUnitFileDir);
+ }
+}
+
+ServiceConfig::ServiceConfig(
+ sdbusplus::asio::object_server& srv_,
+ std::shared_ptr<sdbusplus::asio::connection>& conn_,
+ const std::string& objPath_, const std::string& baseUnitName_,
+ const std::string& instanceName_, const std::string& serviceObjPath_,
+ const std::string& socketObjPath_) :
+ conn(conn_),
+ server(srv_), objPath(objPath_), baseUnitName(baseUnitName_),
+ instanceName(instanceName_), serviceObjectPath(serviceObjPath_),
+ socketObjectPath(socketObjPath_)
+{
+ instantiatedUnitName = baseUnitName + addInstanceName(instanceName, "@");
+ updatedFlag = 0;
+ queryAndUpdateProperties();
+ return;
+}
+
+std::string ServiceConfig::getSocketUnitName()
+{
+ return instantiatedUnitName + ".socket";
+}
+
+std::string ServiceConfig::getServiceUnitName()
+{
+ return instantiatedUnitName + ".service";
+}
+
+bool ServiceConfig::isMaskedOut()
+{
+ // return true if state is masked & no request to update the maskedState
+ return (
+ stateValue == "masked" &&
+ !(updatedFlag & (1 << static_cast<uint8_t>(UpdatedProp::maskedState))));
+}
+
+void ServiceConfig::stopAndApplyUnitConfig(boost::asio::yield_context yield)
+{
+ if (!updatedFlag || isMaskedOut())
+ {
+ // No updates / masked - Just return.
+ return;
+ }
+ phosphor::logging::log<phosphor::logging::level::INFO>(
+ "Applying new settings.",
+ phosphor::logging::entry("OBJPATH=%s", objPath.c_str()));
+ if (subStateValue == "running")
+ {
+ if (!socketObjectPath.empty())
+ {
+ systemdUnitAction(conn, yield, getSocketUnitName(), sysdStopUnit);
+ }
+ systemdUnitAction(conn, yield, getServiceUnitName(), sysdStopUnit);
+ }
+
+ if (updatedFlag & (1 << static_cast<uint8_t>(UpdatedProp::port)))
+ {
+ createSocketOverrideConf();
+ // Create override config file and write data.
+ std::string ovrCfgFile{overrideConfDir + "/" + overrideConfFileName};
+ std::string tmpFile{ovrCfgFile + "_tmp"};
+ std::ofstream cfgFile(tmpFile, std::ios::out);
+ if (!cfgFile.good())
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Failed to open override.conf_tmp file");
+ phosphor::logging::elog<sdbusplus::xyz::openbmc_project::Common::
+ Error::InternalFailure>();
+ }
+
+ // Write the socket header
+ cfgFile << "[Socket]\n";
+ // Listen
+ cfgFile << "Listen" << protocol << "="
+ << "\n";
+ cfgFile << "Listen" << protocol << "=" << portNum << "\n";
+ cfgFile.close();
+
+ if (std::rename(tmpFile.c_str(), ovrCfgFile.c_str()) != 0)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Failed to rename tmp file as override.conf");
+ std::remove(tmpFile.c_str());
+ phosphor::logging::elog<sdbusplus::xyz::openbmc_project::Common::
+ Error::InternalFailure>();
+ }
+ }
+
+ if (updatedFlag & ((1 << static_cast<uint8_t>(UpdatedProp::maskedState)) |
+ (1 << static_cast<uint8_t>(UpdatedProp::enabledState))))
+ {
+ std::vector<std::string> unitFiles;
+ if (socketObjectPath.empty())
+ {
+ unitFiles = {getServiceUnitName()};
+ }
+ else
+ {
+ unitFiles = {getSocketUnitName(), getServiceUnitName()};
+ }
+ systemdUnitFilesStateChange(conn, yield, unitFiles, stateValue,
+ unitMaskedState, unitEnabledState);
+ }
+ return;
+}
+void ServiceConfig::restartUnitConfig(boost::asio::yield_context yield)
+{
+ if (!updatedFlag || isMaskedOut())
+ {
+ // No updates. Just return.
+ return;
+ }
+
+ if (unitRunningState)
+ {
+ if (!socketObjectPath.empty())
+ {
+ systemdUnitAction(conn, yield, getSocketUnitName(),
+ sysdRestartUnit);
+ }
+ systemdUnitAction(conn, yield, getServiceUnitName(), sysdRestartUnit);
+ }
+
+ // Reset the flag
+ updatedFlag = 0;
+
+ phosphor::logging::log<phosphor::logging::level::INFO>(
+ "Applied new settings",
+ phosphor::logging::entry("OBJPATH=%s", objPath.c_str()));
+
+ queryAndUpdateProperties();
+ return;
+}
+
+void ServiceConfig::startServiceRestartTimer()
+{
+ timer->expires_after(std::chrono::seconds(restartTimeout));
+ timer->async_wait([this](const boost::system::error_code& ec) {
+ if (ec == boost::asio::error::operation_aborted)
+ {
+ // Timer reset.
+ return;
+ }
+ else if (ec)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "async wait error.");
+ return;
+ }
+ updateInProgress = true;
+ boost::asio::spawn(conn->get_io_context(),
+ [this](boost::asio::yield_context yield) {
+ // Stop and apply configuration for all objects
+ for (auto& srvMgrObj : srvMgrObjects)
+ {
+ auto& srvObj = srvMgrObj.second;
+ if (srvObj->updatedFlag)
+ {
+ srvObj->stopAndApplyUnitConfig(yield);
+ }
+ }
+ // Do system reload
+ systemdDaemonReload(conn, yield);
+ // restart unit config.
+ for (auto& srvMgrObj : srvMgrObjects)
+ {
+ auto& srvObj = srvMgrObj.second;
+ if (srvObj->updatedFlag)
+ {
+ srvObj->restartUnitConfig(yield);
+ }
+ }
+ updateInProgress = false;
+ });
+ });
+}
+
+void ServiceConfig::registerProperties()
+{
+ srvCfgIface = server.add_interface(objPath, serviceConfigIntfName);
+
+ if (!socketObjectPath.empty())
+ {
+ sockAttrIface = server.add_interface(objPath, sockAttrIntfName);
+ sockAttrIface->register_property(
+ sockAttrPropPort, portNum,
+ [this](const uint16_t& req, uint16_t& res) {
+ if (!internalSet)
+ {
+ if (req == res)
+ {
+ return 1;
+ }
+ if (updateInProgress)
+ {
+ return 0;
+ }
+ portNum = req;
+ updatedFlag |=
+ (1 << static_cast<uint8_t>(UpdatedProp::port));
+ startServiceRestartTimer();
+ }
+ res = req;
+ return 1;
+ });
+ }
+
+ srvCfgIface->register_property(
+ srvCfgPropMasked, unitMaskedState, [this](const bool& req, bool& res) {
+ if (!internalSet)
+ {
+ if (req == res)
+ {
+ return 1;
+ }
+ if (updateInProgress)
+ {
+ return 0;
+ }
+ unitMaskedState = req;
+ unitEnabledState = !unitMaskedState;
+ unitRunningState = !unitMaskedState;
+ updatedFlag |=
+ (1 << static_cast<uint8_t>(UpdatedProp::maskedState)) |
+ (1 << static_cast<uint8_t>(UpdatedProp::enabledState)) |
+ (1 << static_cast<uint8_t>(UpdatedProp::runningState));
+ internalSet = true;
+ srvCfgIface->set_property(srvCfgPropEnabled, unitEnabledState);
+ srvCfgIface->set_property(srvCfgPropRunning, unitRunningState);
+ internalSet = false;
+ startServiceRestartTimer();
+ }
+ res = req;
+ return 1;
+ });
+
+ srvCfgIface->register_property(
+ srvCfgPropEnabled, unitEnabledState,
+ [this](const bool& req, bool& res) {
+ if (!internalSet)
+ {
+ if (req == res)
+ {
+ return 1;
+ }
+ if (updateInProgress)
+ {
+ return 0;
+ }
+ if (unitMaskedState)
+ { // block updating if masked
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Invalid value specified");
+ return -EINVAL;
+ }
+ unitEnabledState = req;
+ updatedFlag |=
+ (1 << static_cast<uint8_t>(UpdatedProp::enabledState));
+ startServiceRestartTimer();
+ }
+ res = req;
+ return 1;
+ });
+
+ srvCfgIface->register_property(
+ srvCfgPropRunning, unitRunningState,
+ [this](const bool& req, bool& res) {
+ if (!internalSet)
+ {
+ if (req == res)
+ {
+ return 1;
+ }
+ if (updateInProgress)
+ {
+ return 0;
+ }
+ if (unitMaskedState)
+ { // block updating if masked
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Invalid value specified");
+ return -EINVAL;
+ }
+ unitRunningState = req;
+ updatedFlag |=
+ (1 << static_cast<uint8_t>(UpdatedProp::runningState));
+ startServiceRestartTimer();
+ }
+ res = req;
+ return 1;
+ });
+
+ srvCfgIface->initialize();
+ if (!socketObjectPath.empty())
+ {
+ sockAttrIface->initialize();
+ }
+ return;
+}
+
+} // namespace service
+} // namespace phosphor
diff --git a/src/utils.cpp b/src/utils.cpp
index 775c39e..b4ed9f7 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -1,134 +1,134 @@
-/*
-// Copyright (c) 2018 Intel Corporation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-*/
-#include "utils.hpp"
-
-static inline void checkAndThrowInternalFailure(boost::system::error_code& ec,
- const std::string& msg)
-{
- if (ec)
- {
- 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 systemdDaemonReload(
- const std::shared_ptr<sdbusplus::asio::connection>& conn,
- boost::asio::yield_context yield)
-{
- 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>(
- "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::steady_timer sleepTimer(conn->get_io_context());
- sleepTimer.expires_after(std::chrono::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,
- boost::asio::yield_context yield, const std::vector<std::string>& unitFiles,
- const std::string& unitState, bool maskedState, bool enabledState)
-{
- 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;
-}
+/*
+// Copyright (c) 2018 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include "utils.hpp"
+
+static inline void checkAndThrowInternalFailure(boost::system::error_code& ec,
+ const std::string& msg)
+{
+ if (ec)
+ {
+ 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 systemdDaemonReload(
+ const std::shared_ptr<sdbusplus::asio::connection>& conn,
+ boost::asio::yield_context yield)
+{
+ 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>(
+ "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::steady_timer sleepTimer(conn->get_io_context());
+ sleepTimer.expires_after(std::chrono::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,
+ boost::asio::yield_context yield, const std::vector<std::string>& unitFiles,
+ const std::string& unitState, bool maskedState, bool enabledState)
+{
+ 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;
+}