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 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 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 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 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 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 218*430d7ea5SJiaqing Zhao if (baseUnitName == usbCodeUpdateUnitName) 21925a0f634SChicago Duan { 22025a0f634SChicago Duan getUSBCodeUpdateStateFromFile(); 22125a0f634SChicago Duan } 22225a0f634SChicago Duan #endif 22390f2da3fSRichard Marian Thomaiyar } 22490f2da3fSRichard Marian Thomaiyar 22590f2da3fSRichard Marian Thomaiyar void ServiceConfig::queryAndUpdateProperties() 22690f2da3fSRichard Marian Thomaiyar { 227a19b5093SGeorge Liu std::string objectPath = 228f476683cSJiaqing Zhao 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 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 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_) : 32582e9557eSTom Joseph conn(conn_), 32682e9557eSTom Joseph server(srv_), objPath(objPath_), baseUnitName(baseUnitName_), 32790f2da3fSRichard Marian Thomaiyar instanceName(instanceName_), serviceObjectPath(serviceObjPath_), 32890f2da3fSRichard Marian Thomaiyar socketObjectPath(socketObjPath_) 32990f2da3fSRichard Marian Thomaiyar { 330f476683cSJiaqing Zhao isSocketActivatedService = serviceObjectPath.empty(); 33190f2da3fSRichard Marian Thomaiyar instantiatedUnitName = baseUnitName + addInstanceName(instanceName, "@"); 3320084047dSAppaRao Puli updatedFlag = 0; 33390f2da3fSRichard Marian Thomaiyar queryAndUpdateProperties(); 3340084047dSAppaRao Puli return; 3350084047dSAppaRao Puli } 3360084047dSAppaRao Puli 33790f2da3fSRichard Marian Thomaiyar std::string ServiceConfig::getSocketUnitName() 3380084047dSAppaRao Puli { 33990f2da3fSRichard Marian Thomaiyar return instantiatedUnitName + ".socket"; 340e55cfd6eSAppaRao Puli } 341e55cfd6eSAppaRao Puli 34290f2da3fSRichard Marian Thomaiyar std::string ServiceConfig::getServiceUnitName() 34390f2da3fSRichard Marian Thomaiyar { 34490f2da3fSRichard Marian Thomaiyar return instantiatedUnitName + ".service"; 34590f2da3fSRichard Marian Thomaiyar } 34690f2da3fSRichard Marian Thomaiyar 34790f2da3fSRichard Marian Thomaiyar bool ServiceConfig::isMaskedOut() 34890f2da3fSRichard Marian Thomaiyar { 34990f2da3fSRichard Marian Thomaiyar // return true if state is masked & no request to update the maskedState 35090f2da3fSRichard Marian Thomaiyar return ( 35190f2da3fSRichard Marian Thomaiyar stateValue == "masked" && 35290f2da3fSRichard Marian Thomaiyar !(updatedFlag & (1 << static_cast<uint8_t>(UpdatedProp::maskedState)))); 35390f2da3fSRichard Marian Thomaiyar } 35490f2da3fSRichard Marian Thomaiyar 35590f2da3fSRichard Marian Thomaiyar void ServiceConfig::stopAndApplyUnitConfig(boost::asio::yield_context yield) 35690f2da3fSRichard Marian Thomaiyar { 35790f2da3fSRichard Marian Thomaiyar if (!updatedFlag || isMaskedOut()) 35890f2da3fSRichard Marian Thomaiyar { 35990f2da3fSRichard Marian Thomaiyar // No updates / masked - Just return. 36090f2da3fSRichard Marian Thomaiyar return; 36190f2da3fSRichard Marian Thomaiyar } 362cb267c8fSGeorge Liu lg2::info("Applying new settings: {OBJPATH}", "OBJPATH", objPath); 363a19b5093SGeorge Liu if (subStateValue == subStateRunning || subStateValue == subStateListening) 3640084047dSAppaRao Puli { 36590f2da3fSRichard Marian Thomaiyar if (!socketObjectPath.empty()) 36690f2da3fSRichard Marian Thomaiyar { 36790f2da3fSRichard Marian Thomaiyar systemdUnitAction(conn, yield, getSocketUnitName(), sysdStopUnit); 36890f2da3fSRichard Marian Thomaiyar } 369f476683cSJiaqing Zhao if (!isSocketActivatedService) 370a19b5093SGeorge Liu { 37190f2da3fSRichard Marian Thomaiyar systemdUnitAction(conn, yield, getServiceUnitName(), sysdStopUnit); 37290f2da3fSRichard Marian Thomaiyar } 373a19b5093SGeorge Liu else 374a19b5093SGeorge Liu { 375f476683cSJiaqing Zhao // For socket-activated service, each connection will spawn a 376f476683cSJiaqing Zhao // service instance from template. Need to find all spawned service 377f476683cSJiaqing Zhao // `<unitName>@<attribute>.service` and stop them through the 378f476683cSJiaqing Zhao // systemdUnitAction method 379a19b5093SGeorge Liu boost::system::error_code ec; 380a19b5093SGeorge Liu auto listUnits = 381a19b5093SGeorge Liu conn->yield_method_call<std::vector<ListUnitsType>>( 382a19b5093SGeorge Liu yield, ec, sysdService, sysdObjPath, sysdMgrIntf, 383a19b5093SGeorge Liu "ListUnits"); 384a19b5093SGeorge Liu 385a19b5093SGeorge Liu checkAndThrowInternalFailure( 386a19b5093SGeorge Liu ec, "yield_method_call error: ListUnits failed"); 387a19b5093SGeorge Liu 388a19b5093SGeorge Liu for (const auto& unit : listUnits) 389a19b5093SGeorge Liu { 390a19b5093SGeorge Liu const auto& service = 391a19b5093SGeorge Liu std::get<static_cast<int>(ListUnitElements::name)>(unit); 392a19b5093SGeorge Liu const auto& status = 393a19b5093SGeorge Liu std::get<static_cast<int>(ListUnitElements::subState)>( 394a19b5093SGeorge Liu unit); 395f476683cSJiaqing Zhao if (service.find(baseUnitName + "@") != std::string::npos && 396a19b5093SGeorge Liu service.find(".service") != std::string::npos && 397a19b5093SGeorge Liu status == subStateRunning) 398a19b5093SGeorge Liu { 399a19b5093SGeorge Liu systemdUnitAction(conn, yield, service, sysdStopUnit); 400a19b5093SGeorge Liu } 401a19b5093SGeorge Liu } 402a19b5093SGeorge Liu } 403a19b5093SGeorge Liu } 40490f2da3fSRichard Marian Thomaiyar 40590f2da3fSRichard Marian Thomaiyar if (updatedFlag & (1 << static_cast<uint8_t>(UpdatedProp::port))) 40690f2da3fSRichard Marian Thomaiyar { 40790f2da3fSRichard Marian Thomaiyar createSocketOverrideConf(); 4080084047dSAppaRao Puli // Create override config file and write data. 40990f2da3fSRichard Marian Thomaiyar std::string ovrCfgFile{overrideConfDir + "/" + overrideConfFileName}; 4100084047dSAppaRao Puli std::string tmpFile{ovrCfgFile + "_tmp"}; 4110084047dSAppaRao Puli std::ofstream cfgFile(tmpFile, std::ios::out); 4120084047dSAppaRao Puli if (!cfgFile.good()) 4130084047dSAppaRao Puli { 414cb267c8fSGeorge Liu lg2::error("Failed to open the {TMPFILE} file.", "TMPFILE", 415cb267c8fSGeorge Liu tmpFile); 4160084047dSAppaRao Puli phosphor::logging::elog<sdbusplus::xyz::openbmc_project::Common:: 4170084047dSAppaRao Puli Error::InternalFailure>(); 4180084047dSAppaRao Puli } 4190084047dSAppaRao Puli 4200084047dSAppaRao Puli // Write the socket header 4210084047dSAppaRao Puli cfgFile << "[Socket]\n"; 4220084047dSAppaRao Puli // Listen 4230084047dSAppaRao Puli cfgFile << "Listen" << protocol << "=" 4240084047dSAppaRao Puli << "\n"; 4250084047dSAppaRao Puli cfgFile << "Listen" << protocol << "=" << portNum << "\n"; 4260084047dSAppaRao Puli cfgFile.close(); 4270084047dSAppaRao Puli 4280084047dSAppaRao Puli if (std::rename(tmpFile.c_str(), ovrCfgFile.c_str()) != 0) 4290084047dSAppaRao Puli { 430cb267c8fSGeorge Liu lg2::error("Failed to rename {TMPFILE} file as {OVERCFGFILE} file.", 431cb267c8fSGeorge Liu "TMPFILE", tmpFile, "OVERCFGFILE", ovrCfgFile); 4320084047dSAppaRao Puli std::remove(tmpFile.c_str()); 4330084047dSAppaRao Puli phosphor::logging::elog<sdbusplus::xyz::openbmc_project::Common:: 4340084047dSAppaRao Puli Error::InternalFailure>(); 4350084047dSAppaRao Puli } 436e55cfd6eSAppaRao Puli } 4370084047dSAppaRao Puli 43890f2da3fSRichard Marian Thomaiyar if (updatedFlag & ((1 << static_cast<uint8_t>(UpdatedProp::maskedState)) | 43990f2da3fSRichard Marian Thomaiyar (1 << static_cast<uint8_t>(UpdatedProp::enabledState)))) 440e55cfd6eSAppaRao Puli { 44190f2da3fSRichard Marian Thomaiyar std::vector<std::string> unitFiles; 44290f2da3fSRichard Marian Thomaiyar if (socketObjectPath.empty()) 44390f2da3fSRichard Marian Thomaiyar { 44490f2da3fSRichard Marian Thomaiyar unitFiles = {getServiceUnitName()}; 445e55cfd6eSAppaRao Puli } 446f476683cSJiaqing Zhao else if (serviceObjectPath.empty()) 447a19b5093SGeorge Liu { 448a19b5093SGeorge Liu unitFiles = {getSocketUnitName()}; 449a19b5093SGeorge Liu } 45090f2da3fSRichard Marian Thomaiyar else 451e55cfd6eSAppaRao Puli { 45290f2da3fSRichard Marian Thomaiyar unitFiles = {getSocketUnitName(), getServiceUnitName()}; 45390f2da3fSRichard Marian Thomaiyar } 45490f2da3fSRichard Marian Thomaiyar systemdUnitFilesStateChange(conn, yield, unitFiles, stateValue, 45590f2da3fSRichard Marian Thomaiyar unitMaskedState, unitEnabledState); 45690f2da3fSRichard Marian Thomaiyar } 45790f2da3fSRichard Marian Thomaiyar return; 45890f2da3fSRichard Marian Thomaiyar } 45990f2da3fSRichard Marian Thomaiyar void ServiceConfig::restartUnitConfig(boost::asio::yield_context yield) 46090f2da3fSRichard Marian Thomaiyar { 46190f2da3fSRichard Marian Thomaiyar if (!updatedFlag || isMaskedOut()) 46290f2da3fSRichard Marian Thomaiyar { 46390f2da3fSRichard Marian Thomaiyar // No updates. Just return. 46490f2da3fSRichard Marian Thomaiyar return; 4650084047dSAppaRao Puli } 4660084047dSAppaRao Puli 46790f2da3fSRichard Marian Thomaiyar if (unitRunningState) 4680084047dSAppaRao Puli { 46990f2da3fSRichard Marian Thomaiyar if (!socketObjectPath.empty()) 47090f2da3fSRichard Marian Thomaiyar { 47190f2da3fSRichard Marian Thomaiyar systemdUnitAction(conn, yield, getSocketUnitName(), 47290f2da3fSRichard Marian Thomaiyar sysdRestartUnit); 4730084047dSAppaRao Puli } 474f476683cSJiaqing Zhao if (!serviceObjectPath.empty()) 475a19b5093SGeorge Liu { 476a19b5093SGeorge Liu systemdUnitAction(conn, yield, getServiceUnitName(), 477a19b5093SGeorge Liu sysdRestartUnit); 478a19b5093SGeorge Liu } 4790084047dSAppaRao Puli } 4800084047dSAppaRao Puli 4810084047dSAppaRao Puli // Reset the flag 4820084047dSAppaRao Puli updatedFlag = 0; 4830084047dSAppaRao Puli 484cb267c8fSGeorge Liu lg2::info("Applied new settings: {OBJPATH}", "OBJPATH", objPath); 4850084047dSAppaRao Puli 48690f2da3fSRichard Marian Thomaiyar queryAndUpdateProperties(); 4870084047dSAppaRao Puli return; 4880084047dSAppaRao Puli } 4890084047dSAppaRao Puli 4900084047dSAppaRao Puli void ServiceConfig::startServiceRestartTimer() 4910084047dSAppaRao Puli { 49233816cf9SRichard Marian Thomaiyar timer->expires_after(std::chrono::seconds(restartTimeout)); 4930084047dSAppaRao Puli timer->async_wait([this](const boost::system::error_code& ec) { 4940084047dSAppaRao Puli if (ec == boost::asio::error::operation_aborted) 4950084047dSAppaRao Puli { 4960084047dSAppaRao Puli // Timer reset. 4970084047dSAppaRao Puli return; 4980084047dSAppaRao Puli } 4990084047dSAppaRao Puli else if (ec) 5000084047dSAppaRao Puli { 501cb267c8fSGeorge Liu lg2::error("async wait error: {EC}", "EC", ec.value()); 5020084047dSAppaRao Puli return; 5030084047dSAppaRao Puli } 50490f2da3fSRichard Marian Thomaiyar updateInProgress = true; 50590f2da3fSRichard Marian Thomaiyar boost::asio::spawn(conn->get_io_context(), 50690f2da3fSRichard Marian Thomaiyar [this](boost::asio::yield_context yield) { 50790f2da3fSRichard Marian Thomaiyar // Stop and apply configuration for all objects 5080084047dSAppaRao Puli for (auto& srvMgrObj : srvMgrObjects) 5090084047dSAppaRao Puli { 5100084047dSAppaRao Puli auto& srvObj = srvMgrObj.second; 5110084047dSAppaRao Puli if (srvObj->updatedFlag) 5120084047dSAppaRao Puli { 51390f2da3fSRichard Marian Thomaiyar srvObj->stopAndApplyUnitConfig(yield); 5140084047dSAppaRao Puli } 5150084047dSAppaRao Puli } 51690f2da3fSRichard Marian Thomaiyar // Do system reload 51790f2da3fSRichard Marian Thomaiyar systemdDaemonReload(conn, yield); 51890f2da3fSRichard Marian Thomaiyar // restart unit config. 51990f2da3fSRichard Marian Thomaiyar for (auto& srvMgrObj : srvMgrObjects) 52090f2da3fSRichard Marian Thomaiyar { 52190f2da3fSRichard Marian Thomaiyar auto& srvObj = srvMgrObj.second; 52290f2da3fSRichard Marian Thomaiyar if (srvObj->updatedFlag) 52390f2da3fSRichard Marian Thomaiyar { 52490f2da3fSRichard Marian Thomaiyar srvObj->restartUnitConfig(yield); 52590f2da3fSRichard Marian Thomaiyar } 52690f2da3fSRichard Marian Thomaiyar } 52790f2da3fSRichard Marian Thomaiyar updateInProgress = false; 52890f2da3fSRichard Marian Thomaiyar }); 5290084047dSAppaRao Puli }); 5300084047dSAppaRao Puli } 5310084047dSAppaRao Puli 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; 55390f2da3fSRichard Marian Thomaiyar updatedFlag |= 55490f2da3fSRichard Marian Thomaiyar (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 56283241c09STom Joseph srvCfgIface->register_property( 56390f2da3fSRichard Marian Thomaiyar srvCfgPropMasked, unitMaskedState, [this](const bool& req, bool& res) { 56490f2da3fSRichard Marian Thomaiyar if (!internalSet) 56590f2da3fSRichard Marian Thomaiyar { 56625a0f634SChicago Duan #ifdef USB_CODE_UPDATE 567*430d7ea5SJiaqing Zhao if (baseUnitName == usbCodeUpdateUnitName) 56825a0f634SChicago Duan { 56925a0f634SChicago Duan unitMaskedState = req; 57025a0f634SChicago Duan unitEnabledState = !unitMaskedState; 57125a0f634SChicago Duan unitRunningState = !unitMaskedState; 57225a0f634SChicago Duan internalSet = true; 57325a0f634SChicago Duan srvCfgIface->set_property(srvCfgPropEnabled, 57425a0f634SChicago Duan unitEnabledState); 57525a0f634SChicago Duan srvCfgIface->set_property(srvCfgPropRunning, 57625a0f634SChicago Duan unitRunningState); 57725a0f634SChicago Duan srvCfgIface->set_property(srvCfgPropMasked, 57825a0f634SChicago Duan unitMaskedState); 57925a0f634SChicago Duan internalSet = false; 58025a0f634SChicago Duan setUSBCodeUpdateState(unitEnabledState); 58125a0f634SChicago Duan saveUSBCodeUpdateStateToFile(unitMaskedState, 58225a0f634SChicago Duan 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 61183241c09STom Joseph srvCfgIface->register_property( 61290f2da3fSRichard Marian Thomaiyar 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 617*430d7ea5SJiaqing 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; 62725a0f634SChicago Duan srvCfgIface->set_property(srvCfgPropEnabled, 62825a0f634SChicago Duan unitEnabledState); 62925a0f634SChicago Duan srvCfgIface->set_property(srvCfgPropRunning, 63025a0f634SChicago Duan unitRunningState); 63125a0f634SChicago Duan internalSet = false; 63225a0f634SChicago Duan setUSBCodeUpdateState(unitEnabledState); 63325a0f634SChicago Duan saveUSBCodeUpdateStateToFile(unitMaskedState, 63425a0f634SChicago Duan 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; 65390f2da3fSRichard Marian Thomaiyar updatedFlag |= 65490f2da3fSRichard Marian Thomaiyar (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 66183241c09STom Joseph srvCfgIface->register_property( 66290f2da3fSRichard Marian Thomaiyar 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 667*430d7ea5SJiaqing 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; 67725a0f634SChicago Duan srvCfgIface->set_property(srvCfgPropEnabled, 67825a0f634SChicago Duan unitEnabledState); 67925a0f634SChicago Duan srvCfgIface->set_property(srvCfgPropRunning, 68025a0f634SChicago Duan unitRunningState); 68125a0f634SChicago Duan internalSet = false; 68225a0f634SChicago Duan setUSBCodeUpdateState(unitEnabledState); 68325a0f634SChicago Duan saveUSBCodeUpdateStateToFile(unitMaskedState, 68425a0f634SChicago Duan 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; 70390f2da3fSRichard Marian Thomaiyar updatedFlag |= 70490f2da3fSRichard Marian Thomaiyar (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