10084047dSAppaRao Puli /*
20084047dSAppaRao Puli // Copyright (c) 2018 Intel Corporation
30084047dSAppaRao Puli //
40084047dSAppaRao Puli // Licensed under the Apache License, Version 2.0 (the "License");
50084047dSAppaRao Puli // you may not use this file except in compliance with the License.
60084047dSAppaRao Puli // You may obtain a copy of the License at
70084047dSAppaRao Puli //
80084047dSAppaRao Puli // http://www.apache.org/licenses/LICENSE-2.0
90084047dSAppaRao Puli //
100084047dSAppaRao Puli // Unless required by applicable law or agreed to in writing, software
110084047dSAppaRao Puli // distributed under the License is distributed on an "AS IS" BASIS,
120084047dSAppaRao Puli // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130084047dSAppaRao Puli // See the License for the specific language governing permissions and
140084047dSAppaRao Puli // limitations under the License.
150084047dSAppaRao Puli */
16ee853eb2SAppaRao Puli #include "srvcfg_manager.hpp"
17ee853eb2SAppaRao Puli
18ee853eb2SAppaRao Puli #include <boost/asio/spawn.hpp>
19ee853eb2SAppaRao Puli
2025a0f634SChicago Duan #ifdef USB_CODE_UPDATE
2125a0f634SChicago Duan #include <cereal/archives/json.hpp>
2225a0f634SChicago Duan #include <cereal/types/tuple.hpp>
2325a0f634SChicago Duan #include <cereal/types/unordered_map.hpp>
2425a0f634SChicago Duan
2525a0f634SChicago Duan #include <cstdio>
2625a0f634SChicago Duan #endif
2725a0f634SChicago Duan
280084047dSAppaRao Puli #include <fstream>
290084047dSAppaRao Puli #include <regex>
300084047dSAppaRao Puli
3133816cf9SRichard Marian Thomaiyar extern std::unique_ptr<boost::asio::steady_timer> timer;
320084047dSAppaRao Puli extern std::map<std::string, std::shared_ptr<phosphor::service::ServiceConfig>>
330084047dSAppaRao Puli srvMgrObjects;
3490f2da3fSRichard Marian Thomaiyar static bool updateInProgress = false;
350084047dSAppaRao Puli
360084047dSAppaRao Puli namespace phosphor
370084047dSAppaRao Puli {
380084047dSAppaRao Puli namespace service
390084047dSAppaRao Puli {
400084047dSAppaRao Puli
410084047dSAppaRao Puli static constexpr const char* overrideConfFileName = "override.conf";
420084047dSAppaRao Puli static constexpr const size_t restartTimeout = 15; // seconds
430084047dSAppaRao Puli
440084047dSAppaRao Puli static constexpr const char* systemd1UnitBasePath =
450084047dSAppaRao Puli "/org/freedesktop/systemd1/unit/";
460084047dSAppaRao Puli static constexpr const char* systemdOverrideUnitBasePath =
470084047dSAppaRao Puli "/etc/systemd/system/";
480084047dSAppaRao Puli
4925a0f634SChicago Duan #ifdef USB_CODE_UPDATE
5025a0f634SChicago Duan static constexpr const char* usbCodeUpdateStateFilePath =
5125a0f634SChicago Duan "/var/lib/srvcfg_manager";
5225a0f634SChicago Duan static constexpr const char* usbCodeUpdateStateFile =
5325a0f634SChicago Duan "/var/lib/srvcfg_manager/usb-code-update-state";
5425a0f634SChicago Duan static constexpr const char* emptyUsbCodeUpdateRulesFile =
5525a0f634SChicago Duan "/etc/udev/rules.d/70-bmc-usb.rules";
5625a0f634SChicago Duan
5725a0f634SChicago Duan using UsbCodeUpdateStateMap = std::unordered_map<std::string, bool>;
5825a0f634SChicago Duan
setUSBCodeUpdateState(const bool & state)5925a0f634SChicago Duan void ServiceConfig::setUSBCodeUpdateState(const bool& state)
6025a0f634SChicago Duan {
6125a0f634SChicago Duan // Enable usb code update
6225a0f634SChicago Duan if (state)
6325a0f634SChicago Duan {
6425a0f634SChicago Duan if (std::filesystem::exists(emptyUsbCodeUpdateRulesFile))
6525a0f634SChicago Duan {
66f27f431fSJiaqing Zhao lg2::info("Enable usb code update");
6725a0f634SChicago Duan std::filesystem::remove(emptyUsbCodeUpdateRulesFile);
6825a0f634SChicago Duan }
6925a0f634SChicago Duan return;
7025a0f634SChicago Duan }
7125a0f634SChicago Duan
7225a0f634SChicago Duan // Disable usb code update
7325a0f634SChicago Duan if (std::filesystem::exists(emptyUsbCodeUpdateRulesFile))
7425a0f634SChicago Duan {
7525a0f634SChicago Duan std::filesystem::remove(emptyUsbCodeUpdateRulesFile);
7625a0f634SChicago Duan }
7725a0f634SChicago Duan std::error_code ec;
7825a0f634SChicago Duan std::filesystem::create_symlink("/dev/null", emptyUsbCodeUpdateRulesFile,
7925a0f634SChicago Duan ec);
8025a0f634SChicago Duan if (ec)
8125a0f634SChicago Duan {
82f27f431fSJiaqing Zhao lg2::error("Disable usb code update failed");
8325a0f634SChicago Duan return;
8425a0f634SChicago Duan }
85f27f431fSJiaqing Zhao lg2::info("Disable usb code update");
8625a0f634SChicago Duan }
8725a0f634SChicago Duan
saveUSBCodeUpdateStateToFile(const bool & maskedState,const bool & enabledState)8825a0f634SChicago Duan void ServiceConfig::saveUSBCodeUpdateStateToFile(const bool& maskedState,
8925a0f634SChicago Duan const bool& enabledState)
9025a0f634SChicago Duan {
9125a0f634SChicago Duan if (!std::filesystem::exists(usbCodeUpdateStateFilePath))
9225a0f634SChicago Duan {
9325a0f634SChicago Duan std::filesystem::create_directories(usbCodeUpdateStateFilePath);
9425a0f634SChicago Duan }
9525a0f634SChicago Duan
9625a0f634SChicago Duan UsbCodeUpdateStateMap usbCodeUpdateState;
9725a0f634SChicago Duan usbCodeUpdateState[srvCfgPropMasked] = maskedState;
9825a0f634SChicago Duan usbCodeUpdateState[srvCfgPropEnabled] = enabledState;
9925a0f634SChicago Duan
10025a0f634SChicago Duan std::ofstream file(usbCodeUpdateStateFile, std::ios::out);
10125a0f634SChicago Duan cereal::JSONOutputArchive archive(file);
10225a0f634SChicago Duan archive(CEREAL_NVP(usbCodeUpdateState));
10325a0f634SChicago Duan }
10425a0f634SChicago Duan
getUSBCodeUpdateStateFromFile()10525a0f634SChicago Duan void ServiceConfig::getUSBCodeUpdateStateFromFile()
10625a0f634SChicago Duan {
10725a0f634SChicago Duan if (!std::filesystem::exists(usbCodeUpdateStateFile))
10825a0f634SChicago Duan {
109f27f431fSJiaqing Zhao lg2::info("usb-code-update-state file does not exist");
11025a0f634SChicago Duan
11125a0f634SChicago Duan unitMaskedState = false;
11225a0f634SChicago Duan unitEnabledState = true;
11325a0f634SChicago Duan unitRunningState = true;
11425a0f634SChicago Duan setUSBCodeUpdateState(unitEnabledState);
11525a0f634SChicago Duan return;
11625a0f634SChicago Duan }
11725a0f634SChicago Duan
11825a0f634SChicago Duan std::ifstream file(usbCodeUpdateStateFile);
11925a0f634SChicago Duan cereal::JSONInputArchive archive(file);
12025a0f634SChicago Duan UsbCodeUpdateStateMap usbCodeUpdateState;
12125a0f634SChicago Duan archive(usbCodeUpdateState);
12225a0f634SChicago Duan
12325a0f634SChicago Duan auto iterMask = usbCodeUpdateState.find(srvCfgPropMasked);
12425a0f634SChicago Duan if (iterMask != usbCodeUpdateState.end())
12525a0f634SChicago Duan {
12625a0f634SChicago Duan unitMaskedState = iterMask->second;
12725a0f634SChicago Duan if (unitMaskedState)
12825a0f634SChicago Duan {
12925a0f634SChicago Duan unitEnabledState = !unitMaskedState;
13025a0f634SChicago Duan unitRunningState = !unitMaskedState;
13125a0f634SChicago Duan setUSBCodeUpdateState(unitEnabledState);
13225a0f634SChicago Duan return;
13325a0f634SChicago Duan }
13425a0f634SChicago Duan
13525a0f634SChicago Duan auto iterEnable = usbCodeUpdateState.find(srvCfgPropEnabled);
13625a0f634SChicago Duan if (iterEnable != usbCodeUpdateState.end())
13725a0f634SChicago Duan {
13825a0f634SChicago Duan unitEnabledState = iterEnable->second;
13925a0f634SChicago Duan unitRunningState = iterEnable->second;
14025a0f634SChicago Duan setUSBCodeUpdateState(unitEnabledState);
14125a0f634SChicago Duan }
14225a0f634SChicago Duan }
14325a0f634SChicago Duan }
14425a0f634SChicago Duan #endif
14525a0f634SChicago Duan
updateSocketProperties(const boost::container::flat_map<std::string,VariantType> & propertyMap)14690f2da3fSRichard Marian Thomaiyar void ServiceConfig::updateSocketProperties(
14790f2da3fSRichard Marian Thomaiyar const boost::container::flat_map<std::string, VariantType>& propertyMap)
1480084047dSAppaRao Puli {
14990f2da3fSRichard Marian Thomaiyar auto listenIt = propertyMap.find("Listen");
15090f2da3fSRichard Marian Thomaiyar if (listenIt != propertyMap.end())
1510084047dSAppaRao Puli {
15290f2da3fSRichard Marian Thomaiyar auto listenVal =
15390f2da3fSRichard Marian Thomaiyar std::get<std::vector<std::tuple<std::string, std::string>>>(
15490f2da3fSRichard Marian Thomaiyar listenIt->second);
15590f2da3fSRichard Marian Thomaiyar if (listenVal.size())
1560084047dSAppaRao Puli {
1570084047dSAppaRao Puli protocol = std::get<0>(listenVal[0]);
1580084047dSAppaRao Puli std::string port = std::get<1>(listenVal[0]);
1590084047dSAppaRao Puli auto tmp = std::stoul(port.substr(port.find_last_of(":") + 1),
1600084047dSAppaRao Puli nullptr, 10);
1610084047dSAppaRao Puli if (tmp > std::numeric_limits<uint16_t>::max())
1620084047dSAppaRao Puli {
1630084047dSAppaRao Puli throw std::out_of_range("Out of range");
1640084047dSAppaRao Puli }
1650084047dSAppaRao Puli portNum = tmp;
16683241c09STom Joseph if (sockAttrIface && sockAttrIface->is_initialized())
16790f2da3fSRichard Marian Thomaiyar {
16890f2da3fSRichard Marian Thomaiyar internalSet = true;
16983241c09STom Joseph sockAttrIface->set_property(sockAttrPropPort, portNum);
17090f2da3fSRichard Marian Thomaiyar internalSet = false;
17190f2da3fSRichard Marian Thomaiyar }
17290f2da3fSRichard Marian Thomaiyar }
17390f2da3fSRichard Marian Thomaiyar }
17490f2da3fSRichard Marian Thomaiyar }
17590f2da3fSRichard Marian Thomaiyar
updateServiceProperties(const boost::container::flat_map<std::string,VariantType> & propertyMap)17690f2da3fSRichard Marian Thomaiyar void ServiceConfig::updateServiceProperties(
17790f2da3fSRichard Marian Thomaiyar const boost::container::flat_map<std::string, VariantType>& propertyMap)
17890f2da3fSRichard Marian Thomaiyar {
17990f2da3fSRichard Marian Thomaiyar auto stateIt = propertyMap.find("UnitFileState");
18090f2da3fSRichard Marian Thomaiyar if (stateIt != propertyMap.end())
18190f2da3fSRichard Marian Thomaiyar {
18290f2da3fSRichard Marian Thomaiyar stateValue = std::get<std::string>(stateIt->second);
18390f2da3fSRichard Marian Thomaiyar unitEnabledState = unitMaskedState = false;
18490f2da3fSRichard Marian Thomaiyar if (stateValue == stateMasked)
18590f2da3fSRichard Marian Thomaiyar {
18690f2da3fSRichard Marian Thomaiyar unitMaskedState = true;
18790f2da3fSRichard Marian Thomaiyar }
18890f2da3fSRichard Marian Thomaiyar else if (stateValue == stateEnabled)
18990f2da3fSRichard Marian Thomaiyar {
19090f2da3fSRichard Marian Thomaiyar unitEnabledState = true;
19190f2da3fSRichard Marian Thomaiyar }
19283241c09STom Joseph if (srvCfgIface && srvCfgIface->is_initialized())
19390f2da3fSRichard Marian Thomaiyar {
19490f2da3fSRichard Marian Thomaiyar internalSet = true;
19583241c09STom Joseph srvCfgIface->set_property(srvCfgPropMasked, unitMaskedState);
19683241c09STom Joseph srvCfgIface->set_property(srvCfgPropEnabled, unitEnabledState);
19790f2da3fSRichard Marian Thomaiyar internalSet = false;
19890f2da3fSRichard Marian Thomaiyar }
19990f2da3fSRichard Marian Thomaiyar }
20090f2da3fSRichard Marian Thomaiyar auto subStateIt = propertyMap.find("SubState");
20190f2da3fSRichard Marian Thomaiyar if (subStateIt != propertyMap.end())
20290f2da3fSRichard Marian Thomaiyar {
20390f2da3fSRichard Marian Thomaiyar subStateValue = std::get<std::string>(subStateIt->second);
204a19b5093SGeorge Liu if (subStateValue == subStateRunning ||
205a19b5093SGeorge Liu subStateValue == subStateListening)
20690f2da3fSRichard Marian Thomaiyar {
20790f2da3fSRichard Marian Thomaiyar unitRunningState = true;
20890f2da3fSRichard Marian Thomaiyar }
20983241c09STom Joseph if (srvCfgIface && srvCfgIface->is_initialized())
21090f2da3fSRichard Marian Thomaiyar {
21190f2da3fSRichard Marian Thomaiyar internalSet = true;
21283241c09STom Joseph srvCfgIface->set_property(srvCfgPropRunning, unitRunningState);
21390f2da3fSRichard Marian Thomaiyar internalSet = false;
21490f2da3fSRichard Marian Thomaiyar }
21590f2da3fSRichard Marian Thomaiyar }
21625a0f634SChicago Duan
21725a0f634SChicago Duan #ifdef USB_CODE_UPDATE
218430d7ea5SJiaqing Zhao if (baseUnitName == usbCodeUpdateUnitName)
21925a0f634SChicago Duan {
22025a0f634SChicago Duan getUSBCodeUpdateStateFromFile();
22125a0f634SChicago Duan }
22225a0f634SChicago Duan #endif
22390f2da3fSRichard Marian Thomaiyar }
22490f2da3fSRichard Marian Thomaiyar
queryAndUpdateProperties()22590f2da3fSRichard Marian Thomaiyar void ServiceConfig::queryAndUpdateProperties()
22690f2da3fSRichard Marian Thomaiyar {
227de879726SPatrick Williams std::string objectPath =
228de879726SPatrick Williams isSocketActivatedService ? socketObjectPath : serviceObjectPath;
229a19b5093SGeorge Liu if (objectPath.empty())
230a19b5093SGeorge Liu {
231a19b5093SGeorge Liu return;
232a19b5093SGeorge Liu }
233a19b5093SGeorge Liu
23490f2da3fSRichard Marian Thomaiyar conn->async_method_call(
23590f2da3fSRichard Marian Thomaiyar [this](boost::system::error_code ec,
236ee853eb2SAppaRao Puli const boost::container::flat_map<std::string, VariantType>&
237ee853eb2SAppaRao Puli propertyMap) {
23890f2da3fSRichard Marian Thomaiyar if (ec)
23990f2da3fSRichard Marian Thomaiyar {
240cb267c8fSGeorge Liu lg2::error(
241cb267c8fSGeorge Liu "async_method_call error: Failed to service unit properties: {EC}",
242cb267c8fSGeorge Liu "EC", ec.value());
24390f2da3fSRichard Marian Thomaiyar return;
24490f2da3fSRichard Marian Thomaiyar }
24590f2da3fSRichard Marian Thomaiyar try
24690f2da3fSRichard Marian Thomaiyar {
24790f2da3fSRichard Marian Thomaiyar updateServiceProperties(propertyMap);
24890f2da3fSRichard Marian Thomaiyar if (!socketObjectPath.empty())
24990f2da3fSRichard Marian Thomaiyar {
25090f2da3fSRichard Marian Thomaiyar conn->async_method_call(
25190f2da3fSRichard Marian Thomaiyar [this](boost::system::error_code ec,
25290f2da3fSRichard Marian Thomaiyar const boost::container::flat_map<
25390f2da3fSRichard Marian Thomaiyar std::string, VariantType>& propertyMap) {
25490f2da3fSRichard Marian Thomaiyar if (ec)
25590f2da3fSRichard Marian Thomaiyar {
256cb267c8fSGeorge Liu lg2::error(
257cb267c8fSGeorge Liu "async_method_call error: Failed to get all property: {EC}",
258cb267c8fSGeorge Liu "EC", ec.value());
25990f2da3fSRichard Marian Thomaiyar return;
26090f2da3fSRichard Marian Thomaiyar }
26190f2da3fSRichard Marian Thomaiyar try
26290f2da3fSRichard Marian Thomaiyar {
26390f2da3fSRichard Marian Thomaiyar updateSocketProperties(propertyMap);
26483241c09STom Joseph if (!srvCfgIface)
26590f2da3fSRichard Marian Thomaiyar {
26690f2da3fSRichard Marian Thomaiyar registerProperties();
26790f2da3fSRichard Marian Thomaiyar }
26890f2da3fSRichard Marian Thomaiyar }
26990f2da3fSRichard Marian Thomaiyar catch (const std::exception& e)
27090f2da3fSRichard Marian Thomaiyar {
271cb267c8fSGeorge Liu lg2::error(
272cb267c8fSGeorge Liu "Exception in getting socket properties: {ERROR}",
273cb267c8fSGeorge Liu "ERROR", e);
27490f2da3fSRichard Marian Thomaiyar return;
27590f2da3fSRichard Marian Thomaiyar }
27690f2da3fSRichard Marian Thomaiyar },
27790f2da3fSRichard Marian Thomaiyar sysdService, socketObjectPath, dBusPropIntf,
27890f2da3fSRichard Marian Thomaiyar dBusGetAllMethod, sysdSocketIntf);
27990f2da3fSRichard Marian Thomaiyar }
28083241c09STom Joseph else if (!srvCfgIface)
28190f2da3fSRichard Marian Thomaiyar {
28290f2da3fSRichard Marian Thomaiyar registerProperties();
28390f2da3fSRichard Marian Thomaiyar }
2840084047dSAppaRao Puli }
2850084047dSAppaRao Puli catch (const std::exception& e)
2860084047dSAppaRao Puli {
287cb267c8fSGeorge Liu lg2::error("Exception in getting socket properties: {ERROR}",
288cb267c8fSGeorge Liu "ERROR", e);
2890084047dSAppaRao Puli return;
2900084047dSAppaRao Puli }
2910084047dSAppaRao Puli },
292a19b5093SGeorge Liu sysdService, objectPath, dBusPropIntf, dBusGetAllMethod, sysdUnitIntf);
2930084047dSAppaRao Puli return;
2940084047dSAppaRao Puli }
2950084047dSAppaRao Puli
createSocketOverrideConf()29690f2da3fSRichard Marian Thomaiyar void ServiceConfig::createSocketOverrideConf()
2970084047dSAppaRao Puli {
29890f2da3fSRichard Marian Thomaiyar if (!socketObjectPath.empty())
2990084047dSAppaRao Puli {
30090f2da3fSRichard Marian Thomaiyar std::string socketUnitName(instantiatedUnitName + ".socket");
3010084047dSAppaRao Puli /// Check override socket directory exist, if not create it.
30282e9557eSTom Joseph std::filesystem::path ovrUnitFileDir(systemdOverrideUnitBasePath);
3030084047dSAppaRao Puli ovrUnitFileDir += socketUnitName;
3040084047dSAppaRao Puli ovrUnitFileDir += ".d";
30582e9557eSTom Joseph if (!std::filesystem::exists(ovrUnitFileDir))
3060084047dSAppaRao Puli {
30782e9557eSTom Joseph if (!std::filesystem::create_directories(ovrUnitFileDir))
3080084047dSAppaRao Puli {
309cb267c8fSGeorge Liu lg2::error("Unable to create the {DIR} directory.", "DIR",
310cb267c8fSGeorge Liu ovrUnitFileDir);
31190f2da3fSRichard Marian Thomaiyar phosphor::logging::elog<sdbusplus::xyz::openbmc_project::
31290f2da3fSRichard Marian Thomaiyar Common::Error::InternalFailure>();
31390f2da3fSRichard Marian Thomaiyar }
31490f2da3fSRichard Marian Thomaiyar }
31590f2da3fSRichard Marian Thomaiyar overrideConfDir = std::string(ovrUnitFileDir);
3160084047dSAppaRao Puli }
3170084047dSAppaRao Puli }
3180084047dSAppaRao Puli
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_)31990f2da3fSRichard Marian Thomaiyar ServiceConfig::ServiceConfig(
32090f2da3fSRichard Marian Thomaiyar sdbusplus::asio::object_server& srv_,
32190f2da3fSRichard Marian Thomaiyar std::shared_ptr<sdbusplus::asio::connection>& conn_,
32290f2da3fSRichard Marian Thomaiyar const std::string& objPath_, const std::string& baseUnitName_,
32390f2da3fSRichard Marian Thomaiyar const std::string& instanceName_, const std::string& serviceObjPath_,
32490f2da3fSRichard Marian Thomaiyar const std::string& socketObjPath_) :
325de879726SPatrick Williams conn(conn_), server(srv_), objPath(objPath_), baseUnitName(baseUnitName_),
32690f2da3fSRichard Marian Thomaiyar instanceName(instanceName_), serviceObjectPath(serviceObjPath_),
32790f2da3fSRichard Marian Thomaiyar socketObjectPath(socketObjPath_)
32890f2da3fSRichard Marian Thomaiyar {
329f476683cSJiaqing Zhao isSocketActivatedService = serviceObjectPath.empty();
33090f2da3fSRichard Marian Thomaiyar instantiatedUnitName = baseUnitName + addInstanceName(instanceName, "@");
3310084047dSAppaRao Puli updatedFlag = 0;
33290f2da3fSRichard Marian Thomaiyar queryAndUpdateProperties();
3330084047dSAppaRao Puli return;
3340084047dSAppaRao Puli }
3350084047dSAppaRao Puli
getSocketUnitName()33690f2da3fSRichard Marian Thomaiyar std::string ServiceConfig::getSocketUnitName()
3370084047dSAppaRao Puli {
33890f2da3fSRichard Marian Thomaiyar return instantiatedUnitName + ".socket";
339e55cfd6eSAppaRao Puli }
340e55cfd6eSAppaRao Puli
getServiceUnitName()34190f2da3fSRichard Marian Thomaiyar std::string ServiceConfig::getServiceUnitName()
34290f2da3fSRichard Marian Thomaiyar {
34390f2da3fSRichard Marian Thomaiyar return instantiatedUnitName + ".service";
34490f2da3fSRichard Marian Thomaiyar }
34590f2da3fSRichard Marian Thomaiyar
isMaskedOut()34690f2da3fSRichard Marian Thomaiyar bool ServiceConfig::isMaskedOut()
34790f2da3fSRichard Marian Thomaiyar {
34890f2da3fSRichard Marian Thomaiyar // return true if state is masked & no request to update the maskedState
34990f2da3fSRichard Marian Thomaiyar return (
35090f2da3fSRichard Marian Thomaiyar stateValue == "masked" &&
35190f2da3fSRichard Marian Thomaiyar !(updatedFlag & (1 << static_cast<uint8_t>(UpdatedProp::maskedState))));
35290f2da3fSRichard Marian Thomaiyar }
35390f2da3fSRichard Marian Thomaiyar
stopAndApplyUnitConfig(boost::asio::yield_context yield)35490f2da3fSRichard Marian Thomaiyar void ServiceConfig::stopAndApplyUnitConfig(boost::asio::yield_context yield)
35590f2da3fSRichard Marian Thomaiyar {
35690f2da3fSRichard Marian Thomaiyar if (!updatedFlag || isMaskedOut())
35790f2da3fSRichard Marian Thomaiyar {
35890f2da3fSRichard Marian Thomaiyar // No updates / masked - Just return.
35990f2da3fSRichard Marian Thomaiyar return;
36090f2da3fSRichard Marian Thomaiyar }
361cb267c8fSGeorge Liu lg2::info("Applying new settings: {OBJPATH}", "OBJPATH", objPath);
362a19b5093SGeorge Liu if (subStateValue == subStateRunning || subStateValue == subStateListening)
3630084047dSAppaRao Puli {
36490f2da3fSRichard Marian Thomaiyar if (!socketObjectPath.empty())
36590f2da3fSRichard Marian Thomaiyar {
36690f2da3fSRichard Marian Thomaiyar systemdUnitAction(conn, yield, getSocketUnitName(), sysdStopUnit);
36790f2da3fSRichard Marian Thomaiyar }
368f476683cSJiaqing Zhao if (!isSocketActivatedService)
369a19b5093SGeorge Liu {
37090f2da3fSRichard Marian Thomaiyar systemdUnitAction(conn, yield, getServiceUnitName(), sysdStopUnit);
37190f2da3fSRichard Marian Thomaiyar }
372a19b5093SGeorge Liu else
373a19b5093SGeorge Liu {
374f476683cSJiaqing Zhao // For socket-activated service, each connection will spawn a
375f476683cSJiaqing Zhao // service instance from template. Need to find all spawned service
376f476683cSJiaqing Zhao // `<unitName>@<attribute>.service` and stop them through the
377f476683cSJiaqing Zhao // systemdUnitAction method
378a19b5093SGeorge Liu boost::system::error_code ec;
379a19b5093SGeorge Liu auto listUnits =
380a19b5093SGeorge Liu conn->yield_method_call<std::vector<ListUnitsType>>(
381a19b5093SGeorge Liu yield, ec, sysdService, sysdObjPath, sysdMgrIntf,
382a19b5093SGeorge Liu "ListUnits");
383a19b5093SGeorge Liu
384a19b5093SGeorge Liu checkAndThrowInternalFailure(
385a19b5093SGeorge Liu ec, "yield_method_call error: ListUnits failed");
386a19b5093SGeorge Liu
387a19b5093SGeorge Liu for (const auto& unit : listUnits)
388a19b5093SGeorge Liu {
389a19b5093SGeorge Liu const auto& service =
390a19b5093SGeorge Liu std::get<static_cast<int>(ListUnitElements::name)>(unit);
391a19b5093SGeorge Liu const auto& status =
392a19b5093SGeorge Liu std::get<static_cast<int>(ListUnitElements::subState)>(
393a19b5093SGeorge Liu unit);
394f476683cSJiaqing Zhao if (service.find(baseUnitName + "@") != std::string::npos &&
395a19b5093SGeorge Liu service.find(".service") != std::string::npos &&
396a19b5093SGeorge Liu status == subStateRunning)
397a19b5093SGeorge Liu {
398a19b5093SGeorge Liu systemdUnitAction(conn, yield, service, sysdStopUnit);
399a19b5093SGeorge Liu }
400a19b5093SGeorge Liu }
401a19b5093SGeorge Liu }
402a19b5093SGeorge Liu }
40390f2da3fSRichard Marian Thomaiyar
40490f2da3fSRichard Marian Thomaiyar if (updatedFlag & (1 << static_cast<uint8_t>(UpdatedProp::port)))
40590f2da3fSRichard Marian Thomaiyar {
40690f2da3fSRichard Marian Thomaiyar createSocketOverrideConf();
4070084047dSAppaRao Puli // Create override config file and write data.
40890f2da3fSRichard Marian Thomaiyar std::string ovrCfgFile{overrideConfDir + "/" + overrideConfFileName};
4090084047dSAppaRao Puli std::string tmpFile{ovrCfgFile + "_tmp"};
4100084047dSAppaRao Puli std::ofstream cfgFile(tmpFile, std::ios::out);
4110084047dSAppaRao Puli if (!cfgFile.good())
4120084047dSAppaRao Puli {
413cb267c8fSGeorge Liu lg2::error("Failed to open the {TMPFILE} file.", "TMPFILE",
414cb267c8fSGeorge Liu tmpFile);
4150084047dSAppaRao Puli phosphor::logging::elog<sdbusplus::xyz::openbmc_project::Common::
4160084047dSAppaRao Puli Error::InternalFailure>();
4170084047dSAppaRao Puli }
4180084047dSAppaRao Puli
4190084047dSAppaRao Puli // Write the socket header
4200084047dSAppaRao Puli cfgFile << "[Socket]\n";
4210084047dSAppaRao Puli // Listen
4220084047dSAppaRao Puli cfgFile << "Listen" << protocol << "="
4230084047dSAppaRao Puli << "\n";
4240084047dSAppaRao Puli cfgFile << "Listen" << protocol << "=" << portNum << "\n";
4250084047dSAppaRao Puli cfgFile.close();
4260084047dSAppaRao Puli
4270084047dSAppaRao Puli if (std::rename(tmpFile.c_str(), ovrCfgFile.c_str()) != 0)
4280084047dSAppaRao Puli {
429cb267c8fSGeorge Liu lg2::error("Failed to rename {TMPFILE} file as {OVERCFGFILE} file.",
430cb267c8fSGeorge Liu "TMPFILE", tmpFile, "OVERCFGFILE", ovrCfgFile);
4310084047dSAppaRao Puli std::remove(tmpFile.c_str());
4320084047dSAppaRao Puli phosphor::logging::elog<sdbusplus::xyz::openbmc_project::Common::
4330084047dSAppaRao Puli Error::InternalFailure>();
4340084047dSAppaRao Puli }
435e55cfd6eSAppaRao Puli }
4360084047dSAppaRao Puli
43790f2da3fSRichard Marian Thomaiyar if (updatedFlag & ((1 << static_cast<uint8_t>(UpdatedProp::maskedState)) |
43890f2da3fSRichard Marian Thomaiyar (1 << static_cast<uint8_t>(UpdatedProp::enabledState))))
439e55cfd6eSAppaRao Puli {
44090f2da3fSRichard Marian Thomaiyar std::vector<std::string> unitFiles;
44190f2da3fSRichard Marian Thomaiyar if (socketObjectPath.empty())
44290f2da3fSRichard Marian Thomaiyar {
44390f2da3fSRichard Marian Thomaiyar unitFiles = {getServiceUnitName()};
444e55cfd6eSAppaRao Puli }
445f476683cSJiaqing Zhao else if (serviceObjectPath.empty())
446a19b5093SGeorge Liu {
447a19b5093SGeorge Liu unitFiles = {getSocketUnitName()};
448a19b5093SGeorge Liu }
44990f2da3fSRichard Marian Thomaiyar else
450e55cfd6eSAppaRao Puli {
45190f2da3fSRichard Marian Thomaiyar unitFiles = {getSocketUnitName(), getServiceUnitName()};
45290f2da3fSRichard Marian Thomaiyar }
45390f2da3fSRichard Marian Thomaiyar systemdUnitFilesStateChange(conn, yield, unitFiles, stateValue,
45490f2da3fSRichard Marian Thomaiyar unitMaskedState, unitEnabledState);
45590f2da3fSRichard Marian Thomaiyar }
45690f2da3fSRichard Marian Thomaiyar return;
45790f2da3fSRichard Marian Thomaiyar }
restartUnitConfig(boost::asio::yield_context yield)45890f2da3fSRichard Marian Thomaiyar void ServiceConfig::restartUnitConfig(boost::asio::yield_context yield)
45990f2da3fSRichard Marian Thomaiyar {
46090f2da3fSRichard Marian Thomaiyar if (!updatedFlag || isMaskedOut())
46190f2da3fSRichard Marian Thomaiyar {
46290f2da3fSRichard Marian Thomaiyar // No updates. Just return.
46390f2da3fSRichard Marian Thomaiyar return;
4640084047dSAppaRao Puli }
4650084047dSAppaRao Puli
46690f2da3fSRichard Marian Thomaiyar if (unitRunningState)
4670084047dSAppaRao Puli {
46890f2da3fSRichard Marian Thomaiyar if (!socketObjectPath.empty())
46990f2da3fSRichard Marian Thomaiyar {
47090f2da3fSRichard Marian Thomaiyar systemdUnitAction(conn, yield, getSocketUnitName(),
47190f2da3fSRichard Marian Thomaiyar sysdRestartUnit);
4720084047dSAppaRao Puli }
473f476683cSJiaqing Zhao if (!serviceObjectPath.empty())
474a19b5093SGeorge Liu {
475a19b5093SGeorge Liu systemdUnitAction(conn, yield, getServiceUnitName(),
476a19b5093SGeorge Liu sysdRestartUnit);
477a19b5093SGeorge Liu }
4780084047dSAppaRao Puli }
4790084047dSAppaRao Puli
4800084047dSAppaRao Puli // Reset the flag
4810084047dSAppaRao Puli updatedFlag = 0;
4820084047dSAppaRao Puli
483cb267c8fSGeorge Liu lg2::info("Applied new settings: {OBJPATH}", "OBJPATH", objPath);
4840084047dSAppaRao Puli
48590f2da3fSRichard Marian Thomaiyar queryAndUpdateProperties();
4860084047dSAppaRao Puli return;
4870084047dSAppaRao Puli }
4880084047dSAppaRao Puli
startServiceRestartTimer()4890084047dSAppaRao Puli void ServiceConfig::startServiceRestartTimer()
4900084047dSAppaRao Puli {
49133816cf9SRichard Marian Thomaiyar timer->expires_after(std::chrono::seconds(restartTimeout));
4920084047dSAppaRao Puli timer->async_wait([this](const boost::system::error_code& ec) {
4930084047dSAppaRao Puli if (ec == boost::asio::error::operation_aborted)
4940084047dSAppaRao Puli {
4950084047dSAppaRao Puli // Timer reset.
4960084047dSAppaRao Puli return;
4970084047dSAppaRao Puli }
4980084047dSAppaRao Puli else if (ec)
4990084047dSAppaRao Puli {
500cb267c8fSGeorge Liu lg2::error("async wait error: {EC}", "EC", ec.value());
5010084047dSAppaRao Puli return;
5020084047dSAppaRao Puli }
50390f2da3fSRichard Marian Thomaiyar updateInProgress = true;
50490f2da3fSRichard Marian Thomaiyar boost::asio::spawn(conn->get_io_context(),
50590f2da3fSRichard Marian Thomaiyar [this](boost::asio::yield_context yield) {
50690f2da3fSRichard Marian Thomaiyar // Stop and apply configuration for all objects
5070084047dSAppaRao Puli for (auto& srvMgrObj : srvMgrObjects)
5080084047dSAppaRao Puli {
5090084047dSAppaRao Puli auto& srvObj = srvMgrObj.second;
5100084047dSAppaRao Puli if (srvObj->updatedFlag)
5110084047dSAppaRao Puli {
51290f2da3fSRichard Marian Thomaiyar srvObj->stopAndApplyUnitConfig(yield);
5130084047dSAppaRao Puli }
5140084047dSAppaRao Puli }
51590f2da3fSRichard Marian Thomaiyar // Do system reload
51690f2da3fSRichard Marian Thomaiyar systemdDaemonReload(conn, yield);
51790f2da3fSRichard Marian Thomaiyar // restart unit config.
51890f2da3fSRichard Marian Thomaiyar for (auto& srvMgrObj : srvMgrObjects)
51990f2da3fSRichard Marian Thomaiyar {
52090f2da3fSRichard Marian Thomaiyar auto& srvObj = srvMgrObj.second;
52190f2da3fSRichard Marian Thomaiyar if (srvObj->updatedFlag)
52290f2da3fSRichard Marian Thomaiyar {
52390f2da3fSRichard Marian Thomaiyar srvObj->restartUnitConfig(yield);
52490f2da3fSRichard Marian Thomaiyar }
52590f2da3fSRichard Marian Thomaiyar }
52690f2da3fSRichard Marian Thomaiyar updateInProgress = false;
527*b5aabea4SJayanth Othayoth },
528*b5aabea4SJayanth Othayoth {});
5290084047dSAppaRao Puli });
5300084047dSAppaRao Puli }
5310084047dSAppaRao Puli
registerProperties()5320084047dSAppaRao Puli void ServiceConfig::registerProperties()
5330084047dSAppaRao Puli {
53483241c09STom Joseph srvCfgIface = server.add_interface(objPath, serviceConfigIntfName);
5350084047dSAppaRao Puli
53690f2da3fSRichard Marian Thomaiyar if (!socketObjectPath.empty())
53790f2da3fSRichard Marian Thomaiyar {
53883241c09STom Joseph sockAttrIface = server.add_interface(objPath, sockAttrIntfName);
53983241c09STom Joseph sockAttrIface->register_property(
54083241c09STom Joseph sockAttrPropPort, portNum,
54190f2da3fSRichard Marian Thomaiyar [this](const uint16_t& req, uint16_t& res) {
54290f2da3fSRichard Marian Thomaiyar if (!internalSet)
54390f2da3fSRichard Marian Thomaiyar {
5440084047dSAppaRao Puli if (req == res)
5450084047dSAppaRao Puli {
5460084047dSAppaRao Puli return 1;
5470084047dSAppaRao Puli }
54890f2da3fSRichard Marian Thomaiyar if (updateInProgress)
54990f2da3fSRichard Marian Thomaiyar {
55090f2da3fSRichard Marian Thomaiyar return 0;
55190f2da3fSRichard Marian Thomaiyar }
5520084047dSAppaRao Puli portNum = req;
553de879726SPatrick Williams updatedFlag |=
554de879726SPatrick Williams (1 << static_cast<uint8_t>(UpdatedProp::port));
5550084047dSAppaRao Puli startServiceRestartTimer();
55690f2da3fSRichard Marian Thomaiyar }
55790f2da3fSRichard Marian Thomaiyar res = req;
55890f2da3fSRichard Marian Thomaiyar return 1;
55990f2da3fSRichard Marian Thomaiyar });
56090f2da3fSRichard Marian Thomaiyar }
56190f2da3fSRichard Marian Thomaiyar
562de879726SPatrick Williams srvCfgIface->register_property(
563de879726SPatrick Williams srvCfgPropMasked, unitMaskedState, [this](const bool& req, bool& res) {
56490f2da3fSRichard Marian Thomaiyar if (!internalSet)
56590f2da3fSRichard Marian Thomaiyar {
56625a0f634SChicago Duan #ifdef USB_CODE_UPDATE
567430d7ea5SJiaqing Zhao if (baseUnitName == usbCodeUpdateUnitName)
56825a0f634SChicago Duan {
56925a0f634SChicago Duan unitMaskedState = req;
57025a0f634SChicago Duan unitEnabledState = !unitMaskedState;
57125a0f634SChicago Duan unitRunningState = !unitMaskedState;
57225a0f634SChicago Duan internalSet = true;
573de879726SPatrick Williams srvCfgIface->set_property(srvCfgPropEnabled,
574de879726SPatrick Williams unitEnabledState);
575de879726SPatrick Williams srvCfgIface->set_property(srvCfgPropRunning,
576de879726SPatrick Williams unitRunningState);
577de879726SPatrick Williams srvCfgIface->set_property(srvCfgPropMasked,
578de879726SPatrick Williams unitMaskedState);
57925a0f634SChicago Duan internalSet = false;
58025a0f634SChicago Duan setUSBCodeUpdateState(unitEnabledState);
581de879726SPatrick Williams saveUSBCodeUpdateStateToFile(unitMaskedState,
582de879726SPatrick Williams unitEnabledState);
58325a0f634SChicago Duan return 1;
58425a0f634SChicago Duan }
58525a0f634SChicago Duan #endif
58690f2da3fSRichard Marian Thomaiyar if (req == res)
58790f2da3fSRichard Marian Thomaiyar {
58890f2da3fSRichard Marian Thomaiyar return 1;
58990f2da3fSRichard Marian Thomaiyar }
59090f2da3fSRichard Marian Thomaiyar if (updateInProgress)
59190f2da3fSRichard Marian Thomaiyar {
59290f2da3fSRichard Marian Thomaiyar return 0;
59390f2da3fSRichard Marian Thomaiyar }
59490f2da3fSRichard Marian Thomaiyar unitMaskedState = req;
59590f2da3fSRichard Marian Thomaiyar unitEnabledState = !unitMaskedState;
59690f2da3fSRichard Marian Thomaiyar unitRunningState = !unitMaskedState;
59790f2da3fSRichard Marian Thomaiyar updatedFlag |=
59890f2da3fSRichard Marian Thomaiyar (1 << static_cast<uint8_t>(UpdatedProp::maskedState)) |
59990f2da3fSRichard Marian Thomaiyar (1 << static_cast<uint8_t>(UpdatedProp::enabledState)) |
60090f2da3fSRichard Marian Thomaiyar (1 << static_cast<uint8_t>(UpdatedProp::runningState));
60190f2da3fSRichard Marian Thomaiyar internalSet = true;
60283241c09STom Joseph srvCfgIface->set_property(srvCfgPropEnabled, unitEnabledState);
60383241c09STom Joseph srvCfgIface->set_property(srvCfgPropRunning, unitRunningState);
60490f2da3fSRichard Marian Thomaiyar internalSet = false;
60590f2da3fSRichard Marian Thomaiyar startServiceRestartTimer();
60690f2da3fSRichard Marian Thomaiyar }
6070084047dSAppaRao Puli res = req;
6080084047dSAppaRao Puli return 1;
6090084047dSAppaRao Puli });
6100084047dSAppaRao Puli
611de879726SPatrick Williams srvCfgIface->register_property(
612de879726SPatrick Williams srvCfgPropEnabled, unitEnabledState,
61390f2da3fSRichard Marian Thomaiyar [this](const bool& req, bool& res) {
61490f2da3fSRichard Marian Thomaiyar if (!internalSet)
61590f2da3fSRichard Marian Thomaiyar {
61625a0f634SChicago Duan #ifdef USB_CODE_UPDATE
617430d7ea5SJiaqing Zhao if (baseUnitName == usbCodeUpdateUnitName)
61825a0f634SChicago Duan {
61925a0f634SChicago Duan if (unitMaskedState)
62025a0f634SChicago Duan { // block updating if masked
621f27f431fSJiaqing Zhao lg2::error("Invalid value specified");
62225a0f634SChicago Duan return -EINVAL;
62325a0f634SChicago Duan }
62425a0f634SChicago Duan unitEnabledState = req;
62525a0f634SChicago Duan unitRunningState = req;
62625a0f634SChicago Duan internalSet = true;
627de879726SPatrick Williams srvCfgIface->set_property(srvCfgPropEnabled,
628de879726SPatrick Williams unitEnabledState);
629de879726SPatrick Williams srvCfgIface->set_property(srvCfgPropRunning,
630de879726SPatrick Williams unitRunningState);
63125a0f634SChicago Duan internalSet = false;
63225a0f634SChicago Duan setUSBCodeUpdateState(unitEnabledState);
633de879726SPatrick Williams saveUSBCodeUpdateStateToFile(unitMaskedState,
634de879726SPatrick Williams unitEnabledState);
63525a0f634SChicago Duan res = req;
63625a0f634SChicago Duan return 1;
63725a0f634SChicago Duan }
63825a0f634SChicago Duan #endif
6390084047dSAppaRao Puli if (req == res)
6400084047dSAppaRao Puli {
6410084047dSAppaRao Puli return 1;
6420084047dSAppaRao Puli }
64390f2da3fSRichard Marian Thomaiyar if (updateInProgress)
6440084047dSAppaRao Puli {
64590f2da3fSRichard Marian Thomaiyar return 0;
6460084047dSAppaRao Puli }
64790f2da3fSRichard Marian Thomaiyar if (unitMaskedState)
64890f2da3fSRichard Marian Thomaiyar { // block updating if masked
649cb267c8fSGeorge Liu lg2::error("Invalid value specified");
6500084047dSAppaRao Puli return -EINVAL;
6510084047dSAppaRao Puli }
65290f2da3fSRichard Marian Thomaiyar unitEnabledState = req;
653de879726SPatrick Williams updatedFlag |=
654de879726SPatrick Williams (1 << static_cast<uint8_t>(UpdatedProp::enabledState));
6550084047dSAppaRao Puli startServiceRestartTimer();
65690f2da3fSRichard Marian Thomaiyar }
65790f2da3fSRichard Marian Thomaiyar res = req;
65890f2da3fSRichard Marian Thomaiyar return 1;
65990f2da3fSRichard Marian Thomaiyar });
66090f2da3fSRichard Marian Thomaiyar
661de879726SPatrick Williams srvCfgIface->register_property(
662de879726SPatrick Williams srvCfgPropRunning, unitRunningState,
66390f2da3fSRichard Marian Thomaiyar [this](const bool& req, bool& res) {
66490f2da3fSRichard Marian Thomaiyar if (!internalSet)
66590f2da3fSRichard Marian Thomaiyar {
66625a0f634SChicago Duan #ifdef USB_CODE_UPDATE
667430d7ea5SJiaqing Zhao if (baseUnitName == usbCodeUpdateUnitName)
66825a0f634SChicago Duan {
66925a0f634SChicago Duan if (unitMaskedState)
67025a0f634SChicago Duan { // block updating if masked
671f27f431fSJiaqing Zhao lg2::error("Invalid value specified");
67225a0f634SChicago Duan return -EINVAL;
67325a0f634SChicago Duan }
67425a0f634SChicago Duan unitEnabledState = req;
67525a0f634SChicago Duan unitRunningState = req;
67625a0f634SChicago Duan internalSet = true;
677de879726SPatrick Williams srvCfgIface->set_property(srvCfgPropEnabled,
678de879726SPatrick Williams unitEnabledState);
679de879726SPatrick Williams srvCfgIface->set_property(srvCfgPropRunning,
680de879726SPatrick Williams unitRunningState);
68125a0f634SChicago Duan internalSet = false;
68225a0f634SChicago Duan setUSBCodeUpdateState(unitEnabledState);
683de879726SPatrick Williams saveUSBCodeUpdateStateToFile(unitMaskedState,
684de879726SPatrick Williams unitEnabledState);
68525a0f634SChicago Duan res = req;
68625a0f634SChicago Duan return 1;
68725a0f634SChicago Duan }
68825a0f634SChicago Duan #endif
68990f2da3fSRichard Marian Thomaiyar if (req == res)
69090f2da3fSRichard Marian Thomaiyar {
69190f2da3fSRichard Marian Thomaiyar return 1;
69290f2da3fSRichard Marian Thomaiyar }
69390f2da3fSRichard Marian Thomaiyar if (updateInProgress)
69490f2da3fSRichard Marian Thomaiyar {
69590f2da3fSRichard Marian Thomaiyar return 0;
69690f2da3fSRichard Marian Thomaiyar }
69790f2da3fSRichard Marian Thomaiyar if (unitMaskedState)
69890f2da3fSRichard Marian Thomaiyar { // block updating if masked
699cb267c8fSGeorge Liu lg2::error("Invalid value specified");
70090f2da3fSRichard Marian Thomaiyar return -EINVAL;
70190f2da3fSRichard Marian Thomaiyar }
70290f2da3fSRichard Marian Thomaiyar unitRunningState = req;
703de879726SPatrick Williams updatedFlag |=
704de879726SPatrick Williams (1 << static_cast<uint8_t>(UpdatedProp::runningState));
70590f2da3fSRichard Marian Thomaiyar startServiceRestartTimer();
70690f2da3fSRichard Marian Thomaiyar }
7070084047dSAppaRao Puli res = req;
7080084047dSAppaRao Puli return 1;
7090084047dSAppaRao Puli });
7100084047dSAppaRao Puli
71183241c09STom Joseph srvCfgIface->initialize();
71283241c09STom Joseph if (!socketObjectPath.empty())
71383241c09STom Joseph {
71483241c09STom Joseph sockAttrIface->initialize();
71583241c09STom Joseph }
7160084047dSAppaRao Puli return;
7170084047dSAppaRao Puli }
7180084047dSAppaRao Puli
7190084047dSAppaRao Puli } // namespace service
7200084047dSAppaRao Puli } // namespace phosphor
721