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 static constexpr const char* usbCodeUpdateObjectPath = 5725a0f634SChicago Duan "/xyz/openbmc_project/control/service/phosphor_2dusb_2dcode_2dupdate"; 5825a0f634SChicago Duan 5925a0f634SChicago Duan using UsbCodeUpdateStateMap = std::unordered_map<std::string, bool>; 6025a0f634SChicago Duan 6125a0f634SChicago Duan void ServiceConfig::setUSBCodeUpdateState(const bool& state) 6225a0f634SChicago Duan { 6325a0f634SChicago Duan // Enable usb code update 6425a0f634SChicago Duan if (state) 6525a0f634SChicago Duan { 6625a0f634SChicago Duan if (std::filesystem::exists(emptyUsbCodeUpdateRulesFile)) 6725a0f634SChicago Duan { 6825a0f634SChicago Duan phosphor::logging::log<phosphor::logging::level::INFO>( 6925a0f634SChicago Duan "Enable usb code update"); 7025a0f634SChicago Duan std::filesystem::remove(emptyUsbCodeUpdateRulesFile); 7125a0f634SChicago Duan } 7225a0f634SChicago Duan return; 7325a0f634SChicago Duan } 7425a0f634SChicago Duan 7525a0f634SChicago Duan // Disable usb code update 7625a0f634SChicago Duan if (std::filesystem::exists(emptyUsbCodeUpdateRulesFile)) 7725a0f634SChicago Duan { 7825a0f634SChicago Duan std::filesystem::remove(emptyUsbCodeUpdateRulesFile); 7925a0f634SChicago Duan } 8025a0f634SChicago Duan std::error_code ec; 8125a0f634SChicago Duan std::filesystem::create_symlink("/dev/null", emptyUsbCodeUpdateRulesFile, 8225a0f634SChicago Duan ec); 8325a0f634SChicago Duan if (ec) 8425a0f634SChicago Duan { 8525a0f634SChicago Duan phosphor::logging::log<phosphor::logging::level::ERR>( 8625a0f634SChicago Duan "Disable usb code update failed"); 8725a0f634SChicago Duan return; 8825a0f634SChicago Duan } 8925a0f634SChicago Duan phosphor::logging::log<phosphor::logging::level::INFO>( 9025a0f634SChicago Duan "Disable usb code update"); 9125a0f634SChicago Duan } 9225a0f634SChicago Duan 9325a0f634SChicago Duan void ServiceConfig::saveUSBCodeUpdateStateToFile(const bool& maskedState, 9425a0f634SChicago Duan const bool& enabledState) 9525a0f634SChicago Duan { 9625a0f634SChicago Duan if (!std::filesystem::exists(usbCodeUpdateStateFilePath)) 9725a0f634SChicago Duan { 9825a0f634SChicago Duan std::filesystem::create_directories(usbCodeUpdateStateFilePath); 9925a0f634SChicago Duan } 10025a0f634SChicago Duan 10125a0f634SChicago Duan UsbCodeUpdateStateMap usbCodeUpdateState; 10225a0f634SChicago Duan usbCodeUpdateState[srvCfgPropMasked] = maskedState; 10325a0f634SChicago Duan usbCodeUpdateState[srvCfgPropEnabled] = enabledState; 10425a0f634SChicago Duan 10525a0f634SChicago Duan std::ofstream file(usbCodeUpdateStateFile, std::ios::out); 10625a0f634SChicago Duan cereal::JSONOutputArchive archive(file); 10725a0f634SChicago Duan archive(CEREAL_NVP(usbCodeUpdateState)); 10825a0f634SChicago Duan } 10925a0f634SChicago Duan 11025a0f634SChicago Duan void ServiceConfig::getUSBCodeUpdateStateFromFile() 11125a0f634SChicago Duan { 11225a0f634SChicago Duan if (!std::filesystem::exists(usbCodeUpdateStateFile)) 11325a0f634SChicago Duan { 11425a0f634SChicago Duan phosphor::logging::log<phosphor::logging::level::INFO>( 11525a0f634SChicago Duan "usb-code-update-state file does not exist"); 11625a0f634SChicago Duan 11725a0f634SChicago Duan unitMaskedState = false; 11825a0f634SChicago Duan unitEnabledState = true; 11925a0f634SChicago Duan unitRunningState = true; 12025a0f634SChicago Duan setUSBCodeUpdateState(unitEnabledState); 12125a0f634SChicago Duan return; 12225a0f634SChicago Duan } 12325a0f634SChicago Duan 12425a0f634SChicago Duan std::ifstream file(usbCodeUpdateStateFile); 12525a0f634SChicago Duan cereal::JSONInputArchive archive(file); 12625a0f634SChicago Duan UsbCodeUpdateStateMap usbCodeUpdateState; 12725a0f634SChicago Duan archive(usbCodeUpdateState); 12825a0f634SChicago Duan 12925a0f634SChicago Duan auto iterMask = usbCodeUpdateState.find(srvCfgPropMasked); 13025a0f634SChicago Duan if (iterMask != usbCodeUpdateState.end()) 13125a0f634SChicago Duan { 13225a0f634SChicago Duan unitMaskedState = iterMask->second; 13325a0f634SChicago Duan if (unitMaskedState) 13425a0f634SChicago Duan { 13525a0f634SChicago Duan unitEnabledState = !unitMaskedState; 13625a0f634SChicago Duan unitRunningState = !unitMaskedState; 13725a0f634SChicago Duan setUSBCodeUpdateState(unitEnabledState); 13825a0f634SChicago Duan return; 13925a0f634SChicago Duan } 14025a0f634SChicago Duan 14125a0f634SChicago Duan auto iterEnable = usbCodeUpdateState.find(srvCfgPropEnabled); 14225a0f634SChicago Duan if (iterEnable != usbCodeUpdateState.end()) 14325a0f634SChicago Duan { 14425a0f634SChicago Duan unitEnabledState = iterEnable->second; 14525a0f634SChicago Duan unitRunningState = iterEnable->second; 14625a0f634SChicago Duan setUSBCodeUpdateState(unitEnabledState); 14725a0f634SChicago Duan } 14825a0f634SChicago Duan } 14925a0f634SChicago Duan } 15025a0f634SChicago Duan #endif 15125a0f634SChicago Duan 15290f2da3fSRichard Marian Thomaiyar void ServiceConfig::updateSocketProperties( 15390f2da3fSRichard Marian Thomaiyar const boost::container::flat_map<std::string, VariantType>& propertyMap) 1540084047dSAppaRao Puli { 15590f2da3fSRichard Marian Thomaiyar auto listenIt = propertyMap.find("Listen"); 15690f2da3fSRichard Marian Thomaiyar if (listenIt != propertyMap.end()) 1570084047dSAppaRao Puli { 15890f2da3fSRichard Marian Thomaiyar auto listenVal = 15990f2da3fSRichard Marian Thomaiyar std::get<std::vector<std::tuple<std::string, std::string>>>( 16090f2da3fSRichard Marian Thomaiyar listenIt->second); 16190f2da3fSRichard Marian Thomaiyar if (listenVal.size()) 1620084047dSAppaRao Puli { 1630084047dSAppaRao Puli protocol = std::get<0>(listenVal[0]); 1640084047dSAppaRao Puli std::string port = std::get<1>(listenVal[0]); 1650084047dSAppaRao Puli auto tmp = std::stoul(port.substr(port.find_last_of(":") + 1), 1660084047dSAppaRao Puli nullptr, 10); 1670084047dSAppaRao Puli if (tmp > std::numeric_limits<uint16_t>::max()) 1680084047dSAppaRao Puli { 1690084047dSAppaRao Puli throw std::out_of_range("Out of range"); 1700084047dSAppaRao Puli } 1710084047dSAppaRao Puli portNum = tmp; 17283241c09STom Joseph if (sockAttrIface && sockAttrIface->is_initialized()) 17390f2da3fSRichard Marian Thomaiyar { 17490f2da3fSRichard Marian Thomaiyar internalSet = true; 17583241c09STom Joseph sockAttrIface->set_property(sockAttrPropPort, portNum); 17690f2da3fSRichard Marian Thomaiyar internalSet = false; 17790f2da3fSRichard Marian Thomaiyar } 17890f2da3fSRichard Marian Thomaiyar } 17990f2da3fSRichard Marian Thomaiyar } 18090f2da3fSRichard Marian Thomaiyar } 18190f2da3fSRichard Marian Thomaiyar 18290f2da3fSRichard Marian Thomaiyar void ServiceConfig::updateServiceProperties( 18390f2da3fSRichard Marian Thomaiyar const boost::container::flat_map<std::string, VariantType>& propertyMap) 18490f2da3fSRichard Marian Thomaiyar { 18590f2da3fSRichard Marian Thomaiyar auto stateIt = propertyMap.find("UnitFileState"); 18690f2da3fSRichard Marian Thomaiyar if (stateIt != propertyMap.end()) 18790f2da3fSRichard Marian Thomaiyar { 18890f2da3fSRichard Marian Thomaiyar stateValue = std::get<std::string>(stateIt->second); 18990f2da3fSRichard Marian Thomaiyar unitEnabledState = unitMaskedState = false; 19090f2da3fSRichard Marian Thomaiyar if (stateValue == stateMasked) 19190f2da3fSRichard Marian Thomaiyar { 19290f2da3fSRichard Marian Thomaiyar unitMaskedState = true; 19390f2da3fSRichard Marian Thomaiyar } 19490f2da3fSRichard Marian Thomaiyar else if (stateValue == stateEnabled) 19590f2da3fSRichard Marian Thomaiyar { 19690f2da3fSRichard Marian Thomaiyar unitEnabledState = true; 19790f2da3fSRichard Marian Thomaiyar } 19883241c09STom Joseph if (srvCfgIface && srvCfgIface->is_initialized()) 19990f2da3fSRichard Marian Thomaiyar { 20090f2da3fSRichard Marian Thomaiyar internalSet = true; 20183241c09STom Joseph srvCfgIface->set_property(srvCfgPropMasked, unitMaskedState); 20283241c09STom Joseph srvCfgIface->set_property(srvCfgPropEnabled, unitEnabledState); 20390f2da3fSRichard Marian Thomaiyar internalSet = false; 20490f2da3fSRichard Marian Thomaiyar } 20590f2da3fSRichard Marian Thomaiyar } 20690f2da3fSRichard Marian Thomaiyar auto subStateIt = propertyMap.find("SubState"); 20790f2da3fSRichard Marian Thomaiyar if (subStateIt != propertyMap.end()) 20890f2da3fSRichard Marian Thomaiyar { 20990f2da3fSRichard Marian Thomaiyar subStateValue = std::get<std::string>(subStateIt->second); 210a19b5093SGeorge Liu if (subStateValue == subStateRunning || 211a19b5093SGeorge Liu subStateValue == subStateListening) 21290f2da3fSRichard Marian Thomaiyar { 21390f2da3fSRichard Marian Thomaiyar unitRunningState = true; 21490f2da3fSRichard Marian Thomaiyar } 21583241c09STom Joseph if (srvCfgIface && srvCfgIface->is_initialized()) 21690f2da3fSRichard Marian Thomaiyar { 21790f2da3fSRichard Marian Thomaiyar internalSet = true; 21883241c09STom Joseph srvCfgIface->set_property(srvCfgPropRunning, unitRunningState); 21990f2da3fSRichard Marian Thomaiyar internalSet = false; 22090f2da3fSRichard Marian Thomaiyar } 22190f2da3fSRichard Marian Thomaiyar } 22225a0f634SChicago Duan 22325a0f634SChicago Duan #ifdef USB_CODE_UPDATE 22425a0f634SChicago Duan if (objPath == usbCodeUpdateObjectPath) 22525a0f634SChicago Duan { 22625a0f634SChicago Duan getUSBCodeUpdateStateFromFile(); 22725a0f634SChicago Duan } 22825a0f634SChicago Duan #endif 22990f2da3fSRichard Marian Thomaiyar } 23090f2da3fSRichard Marian Thomaiyar 23190f2da3fSRichard Marian Thomaiyar void ServiceConfig::queryAndUpdateProperties() 23290f2da3fSRichard Marian Thomaiyar { 233a19b5093SGeorge Liu std::string objectPath = 234*f476683cSJiaqing Zhao isSocketActivatedService ? socketObjectPath : serviceObjectPath; 235a19b5093SGeorge Liu if (objectPath.empty()) 236a19b5093SGeorge Liu { 237a19b5093SGeorge Liu return; 238a19b5093SGeorge Liu } 239a19b5093SGeorge Liu 24090f2da3fSRichard Marian Thomaiyar conn->async_method_call( 24190f2da3fSRichard Marian Thomaiyar [this](boost::system::error_code ec, 242ee853eb2SAppaRao Puli const boost::container::flat_map<std::string, VariantType>& 243ee853eb2SAppaRao Puli propertyMap) { 24490f2da3fSRichard Marian Thomaiyar if (ec) 24590f2da3fSRichard Marian Thomaiyar { 246cb267c8fSGeorge Liu lg2::error( 247cb267c8fSGeorge Liu "async_method_call error: Failed to service unit properties: {EC}", 248cb267c8fSGeorge Liu "EC", ec.value()); 24990f2da3fSRichard Marian Thomaiyar return; 25090f2da3fSRichard Marian Thomaiyar } 25190f2da3fSRichard Marian Thomaiyar try 25290f2da3fSRichard Marian Thomaiyar { 25390f2da3fSRichard Marian Thomaiyar updateServiceProperties(propertyMap); 25490f2da3fSRichard Marian Thomaiyar if (!socketObjectPath.empty()) 25590f2da3fSRichard Marian Thomaiyar { 25690f2da3fSRichard Marian Thomaiyar conn->async_method_call( 25790f2da3fSRichard Marian Thomaiyar [this](boost::system::error_code ec, 25890f2da3fSRichard Marian Thomaiyar const boost::container::flat_map< 25990f2da3fSRichard Marian Thomaiyar std::string, VariantType>& propertyMap) { 26090f2da3fSRichard Marian Thomaiyar if (ec) 26190f2da3fSRichard Marian Thomaiyar { 262cb267c8fSGeorge Liu lg2::error( 263cb267c8fSGeorge Liu "async_method_call error: Failed to get all property: {EC}", 264cb267c8fSGeorge Liu "EC", ec.value()); 26590f2da3fSRichard Marian Thomaiyar return; 26690f2da3fSRichard Marian Thomaiyar } 26790f2da3fSRichard Marian Thomaiyar try 26890f2da3fSRichard Marian Thomaiyar { 26990f2da3fSRichard Marian Thomaiyar updateSocketProperties(propertyMap); 27083241c09STom Joseph if (!srvCfgIface) 27190f2da3fSRichard Marian Thomaiyar { 27290f2da3fSRichard Marian Thomaiyar registerProperties(); 27390f2da3fSRichard Marian Thomaiyar } 27490f2da3fSRichard Marian Thomaiyar } 27590f2da3fSRichard Marian Thomaiyar catch (const std::exception& e) 27690f2da3fSRichard Marian Thomaiyar { 277cb267c8fSGeorge Liu lg2::error( 278cb267c8fSGeorge Liu "Exception in getting socket properties: {ERROR}", 279cb267c8fSGeorge Liu "ERROR", e); 28090f2da3fSRichard Marian Thomaiyar return; 28190f2da3fSRichard Marian Thomaiyar } 28290f2da3fSRichard Marian Thomaiyar }, 28390f2da3fSRichard Marian Thomaiyar sysdService, socketObjectPath, dBusPropIntf, 28490f2da3fSRichard Marian Thomaiyar dBusGetAllMethod, sysdSocketIntf); 28590f2da3fSRichard Marian Thomaiyar } 28683241c09STom Joseph else if (!srvCfgIface) 28790f2da3fSRichard Marian Thomaiyar { 28890f2da3fSRichard Marian Thomaiyar registerProperties(); 28990f2da3fSRichard Marian Thomaiyar } 2900084047dSAppaRao Puli } 2910084047dSAppaRao Puli catch (const std::exception& e) 2920084047dSAppaRao Puli { 293cb267c8fSGeorge Liu lg2::error("Exception in getting socket properties: {ERROR}", 294cb267c8fSGeorge Liu "ERROR", e); 2950084047dSAppaRao Puli return; 2960084047dSAppaRao Puli } 2970084047dSAppaRao Puli }, 298a19b5093SGeorge Liu sysdService, objectPath, dBusPropIntf, dBusGetAllMethod, sysdUnitIntf); 2990084047dSAppaRao Puli return; 3000084047dSAppaRao Puli } 3010084047dSAppaRao Puli 30290f2da3fSRichard Marian Thomaiyar void ServiceConfig::createSocketOverrideConf() 3030084047dSAppaRao Puli { 30490f2da3fSRichard Marian Thomaiyar if (!socketObjectPath.empty()) 3050084047dSAppaRao Puli { 30690f2da3fSRichard Marian Thomaiyar std::string socketUnitName(instantiatedUnitName + ".socket"); 3070084047dSAppaRao Puli /// Check override socket directory exist, if not create it. 30882e9557eSTom Joseph std::filesystem::path ovrUnitFileDir(systemdOverrideUnitBasePath); 3090084047dSAppaRao Puli ovrUnitFileDir += socketUnitName; 3100084047dSAppaRao Puli ovrUnitFileDir += ".d"; 31182e9557eSTom Joseph if (!std::filesystem::exists(ovrUnitFileDir)) 3120084047dSAppaRao Puli { 31382e9557eSTom Joseph if (!std::filesystem::create_directories(ovrUnitFileDir)) 3140084047dSAppaRao Puli { 315cb267c8fSGeorge Liu lg2::error("Unable to create the {DIR} directory.", "DIR", 316cb267c8fSGeorge Liu ovrUnitFileDir); 31790f2da3fSRichard Marian Thomaiyar phosphor::logging::elog<sdbusplus::xyz::openbmc_project:: 31890f2da3fSRichard Marian Thomaiyar Common::Error::InternalFailure>(); 31990f2da3fSRichard Marian Thomaiyar } 32090f2da3fSRichard Marian Thomaiyar } 32190f2da3fSRichard Marian Thomaiyar overrideConfDir = std::string(ovrUnitFileDir); 3220084047dSAppaRao Puli } 3230084047dSAppaRao Puli } 3240084047dSAppaRao Puli 32590f2da3fSRichard Marian Thomaiyar ServiceConfig::ServiceConfig( 32690f2da3fSRichard Marian Thomaiyar sdbusplus::asio::object_server& srv_, 32790f2da3fSRichard Marian Thomaiyar std::shared_ptr<sdbusplus::asio::connection>& conn_, 32890f2da3fSRichard Marian Thomaiyar const std::string& objPath_, const std::string& baseUnitName_, 32990f2da3fSRichard Marian Thomaiyar const std::string& instanceName_, const std::string& serviceObjPath_, 33090f2da3fSRichard Marian Thomaiyar const std::string& socketObjPath_) : 33182e9557eSTom Joseph conn(conn_), 33282e9557eSTom Joseph server(srv_), objPath(objPath_), baseUnitName(baseUnitName_), 33390f2da3fSRichard Marian Thomaiyar instanceName(instanceName_), serviceObjectPath(serviceObjPath_), 33490f2da3fSRichard Marian Thomaiyar socketObjectPath(socketObjPath_) 33590f2da3fSRichard Marian Thomaiyar { 336*f476683cSJiaqing Zhao isSocketActivatedService = serviceObjectPath.empty(); 33790f2da3fSRichard Marian Thomaiyar instantiatedUnitName = baseUnitName + addInstanceName(instanceName, "@"); 3380084047dSAppaRao Puli updatedFlag = 0; 33990f2da3fSRichard Marian Thomaiyar queryAndUpdateProperties(); 3400084047dSAppaRao Puli return; 3410084047dSAppaRao Puli } 3420084047dSAppaRao Puli 34390f2da3fSRichard Marian Thomaiyar std::string ServiceConfig::getSocketUnitName() 3440084047dSAppaRao Puli { 34590f2da3fSRichard Marian Thomaiyar return instantiatedUnitName + ".socket"; 346e55cfd6eSAppaRao Puli } 347e55cfd6eSAppaRao Puli 34890f2da3fSRichard Marian Thomaiyar std::string ServiceConfig::getServiceUnitName() 34990f2da3fSRichard Marian Thomaiyar { 35090f2da3fSRichard Marian Thomaiyar return instantiatedUnitName + ".service"; 35190f2da3fSRichard Marian Thomaiyar } 35290f2da3fSRichard Marian Thomaiyar 35390f2da3fSRichard Marian Thomaiyar bool ServiceConfig::isMaskedOut() 35490f2da3fSRichard Marian Thomaiyar { 35590f2da3fSRichard Marian Thomaiyar // return true if state is masked & no request to update the maskedState 35690f2da3fSRichard Marian Thomaiyar return ( 35790f2da3fSRichard Marian Thomaiyar stateValue == "masked" && 35890f2da3fSRichard Marian Thomaiyar !(updatedFlag & (1 << static_cast<uint8_t>(UpdatedProp::maskedState)))); 35990f2da3fSRichard Marian Thomaiyar } 36090f2da3fSRichard Marian Thomaiyar 36190f2da3fSRichard Marian Thomaiyar void ServiceConfig::stopAndApplyUnitConfig(boost::asio::yield_context yield) 36290f2da3fSRichard Marian Thomaiyar { 36390f2da3fSRichard Marian Thomaiyar if (!updatedFlag || isMaskedOut()) 36490f2da3fSRichard Marian Thomaiyar { 36590f2da3fSRichard Marian Thomaiyar // No updates / masked - Just return. 36690f2da3fSRichard Marian Thomaiyar return; 36790f2da3fSRichard Marian Thomaiyar } 368cb267c8fSGeorge Liu lg2::info("Applying new settings: {OBJPATH}", "OBJPATH", objPath); 369a19b5093SGeorge Liu if (subStateValue == subStateRunning || subStateValue == subStateListening) 3700084047dSAppaRao Puli { 37190f2da3fSRichard Marian Thomaiyar if (!socketObjectPath.empty()) 37290f2da3fSRichard Marian Thomaiyar { 37390f2da3fSRichard Marian Thomaiyar systemdUnitAction(conn, yield, getSocketUnitName(), sysdStopUnit); 37490f2da3fSRichard Marian Thomaiyar } 375*f476683cSJiaqing Zhao if (!isSocketActivatedService) 376a19b5093SGeorge Liu { 37790f2da3fSRichard Marian Thomaiyar systemdUnitAction(conn, yield, getServiceUnitName(), sysdStopUnit); 37890f2da3fSRichard Marian Thomaiyar } 379a19b5093SGeorge Liu else 380a19b5093SGeorge Liu { 381*f476683cSJiaqing Zhao // For socket-activated service, each connection will spawn a 382*f476683cSJiaqing Zhao // service instance from template. Need to find all spawned service 383*f476683cSJiaqing Zhao // `<unitName>@<attribute>.service` and stop them through the 384*f476683cSJiaqing Zhao // systemdUnitAction method 385a19b5093SGeorge Liu boost::system::error_code ec; 386a19b5093SGeorge Liu auto listUnits = 387a19b5093SGeorge Liu conn->yield_method_call<std::vector<ListUnitsType>>( 388a19b5093SGeorge Liu yield, ec, sysdService, sysdObjPath, sysdMgrIntf, 389a19b5093SGeorge Liu "ListUnits"); 390a19b5093SGeorge Liu 391a19b5093SGeorge Liu checkAndThrowInternalFailure( 392a19b5093SGeorge Liu ec, "yield_method_call error: ListUnits failed"); 393a19b5093SGeorge Liu 394a19b5093SGeorge Liu for (const auto& unit : listUnits) 395a19b5093SGeorge Liu { 396a19b5093SGeorge Liu const auto& service = 397a19b5093SGeorge Liu std::get<static_cast<int>(ListUnitElements::name)>(unit); 398a19b5093SGeorge Liu const auto& status = 399a19b5093SGeorge Liu std::get<static_cast<int>(ListUnitElements::subState)>( 400a19b5093SGeorge Liu unit); 401*f476683cSJiaqing Zhao if (service.find(baseUnitName + "@") != std::string::npos && 402a19b5093SGeorge Liu service.find(".service") != std::string::npos && 403a19b5093SGeorge Liu status == subStateRunning) 404a19b5093SGeorge Liu { 405a19b5093SGeorge Liu systemdUnitAction(conn, yield, service, sysdStopUnit); 406a19b5093SGeorge Liu } 407a19b5093SGeorge Liu } 408a19b5093SGeorge Liu } 409a19b5093SGeorge Liu } 41090f2da3fSRichard Marian Thomaiyar 41190f2da3fSRichard Marian Thomaiyar if (updatedFlag & (1 << static_cast<uint8_t>(UpdatedProp::port))) 41290f2da3fSRichard Marian Thomaiyar { 41390f2da3fSRichard Marian Thomaiyar createSocketOverrideConf(); 4140084047dSAppaRao Puli // Create override config file and write data. 41590f2da3fSRichard Marian Thomaiyar std::string ovrCfgFile{overrideConfDir + "/" + overrideConfFileName}; 4160084047dSAppaRao Puli std::string tmpFile{ovrCfgFile + "_tmp"}; 4170084047dSAppaRao Puli std::ofstream cfgFile(tmpFile, std::ios::out); 4180084047dSAppaRao Puli if (!cfgFile.good()) 4190084047dSAppaRao Puli { 420cb267c8fSGeorge Liu lg2::error("Failed to open the {TMPFILE} file.", "TMPFILE", 421cb267c8fSGeorge Liu tmpFile); 4220084047dSAppaRao Puli phosphor::logging::elog<sdbusplus::xyz::openbmc_project::Common:: 4230084047dSAppaRao Puli Error::InternalFailure>(); 4240084047dSAppaRao Puli } 4250084047dSAppaRao Puli 4260084047dSAppaRao Puli // Write the socket header 4270084047dSAppaRao Puli cfgFile << "[Socket]\n"; 4280084047dSAppaRao Puli // Listen 4290084047dSAppaRao Puli cfgFile << "Listen" << protocol << "=" 4300084047dSAppaRao Puli << "\n"; 4310084047dSAppaRao Puli cfgFile << "Listen" << protocol << "=" << portNum << "\n"; 4320084047dSAppaRao Puli cfgFile.close(); 4330084047dSAppaRao Puli 4340084047dSAppaRao Puli if (std::rename(tmpFile.c_str(), ovrCfgFile.c_str()) != 0) 4350084047dSAppaRao Puli { 436cb267c8fSGeorge Liu lg2::error("Failed to rename {TMPFILE} file as {OVERCFGFILE} file.", 437cb267c8fSGeorge Liu "TMPFILE", tmpFile, "OVERCFGFILE", ovrCfgFile); 4380084047dSAppaRao Puli std::remove(tmpFile.c_str()); 4390084047dSAppaRao Puli phosphor::logging::elog<sdbusplus::xyz::openbmc_project::Common:: 4400084047dSAppaRao Puli Error::InternalFailure>(); 4410084047dSAppaRao Puli } 442e55cfd6eSAppaRao Puli } 4430084047dSAppaRao Puli 44490f2da3fSRichard Marian Thomaiyar if (updatedFlag & ((1 << static_cast<uint8_t>(UpdatedProp::maskedState)) | 44590f2da3fSRichard Marian Thomaiyar (1 << static_cast<uint8_t>(UpdatedProp::enabledState)))) 446e55cfd6eSAppaRao Puli { 44790f2da3fSRichard Marian Thomaiyar std::vector<std::string> unitFiles; 44890f2da3fSRichard Marian Thomaiyar if (socketObjectPath.empty()) 44990f2da3fSRichard Marian Thomaiyar { 45090f2da3fSRichard Marian Thomaiyar unitFiles = {getServiceUnitName()}; 451e55cfd6eSAppaRao Puli } 452*f476683cSJiaqing Zhao else if (serviceObjectPath.empty()) 453a19b5093SGeorge Liu { 454a19b5093SGeorge Liu unitFiles = {getSocketUnitName()}; 455a19b5093SGeorge Liu } 45690f2da3fSRichard Marian Thomaiyar else 457e55cfd6eSAppaRao Puli { 45890f2da3fSRichard Marian Thomaiyar unitFiles = {getSocketUnitName(), getServiceUnitName()}; 45990f2da3fSRichard Marian Thomaiyar } 46090f2da3fSRichard Marian Thomaiyar systemdUnitFilesStateChange(conn, yield, unitFiles, stateValue, 46190f2da3fSRichard Marian Thomaiyar unitMaskedState, unitEnabledState); 46290f2da3fSRichard Marian Thomaiyar } 46390f2da3fSRichard Marian Thomaiyar return; 46490f2da3fSRichard Marian Thomaiyar } 46590f2da3fSRichard Marian Thomaiyar void ServiceConfig::restartUnitConfig(boost::asio::yield_context yield) 46690f2da3fSRichard Marian Thomaiyar { 46790f2da3fSRichard Marian Thomaiyar if (!updatedFlag || isMaskedOut()) 46890f2da3fSRichard Marian Thomaiyar { 46990f2da3fSRichard Marian Thomaiyar // No updates. Just return. 47090f2da3fSRichard Marian Thomaiyar return; 4710084047dSAppaRao Puli } 4720084047dSAppaRao Puli 47390f2da3fSRichard Marian Thomaiyar if (unitRunningState) 4740084047dSAppaRao Puli { 47590f2da3fSRichard Marian Thomaiyar if (!socketObjectPath.empty()) 47690f2da3fSRichard Marian Thomaiyar { 47790f2da3fSRichard Marian Thomaiyar systemdUnitAction(conn, yield, getSocketUnitName(), 47890f2da3fSRichard Marian Thomaiyar sysdRestartUnit); 4790084047dSAppaRao Puli } 480*f476683cSJiaqing Zhao if (!serviceObjectPath.empty()) 481a19b5093SGeorge Liu { 482a19b5093SGeorge Liu systemdUnitAction(conn, yield, getServiceUnitName(), 483a19b5093SGeorge Liu sysdRestartUnit); 484a19b5093SGeorge Liu } 4850084047dSAppaRao Puli } 4860084047dSAppaRao Puli 4870084047dSAppaRao Puli // Reset the flag 4880084047dSAppaRao Puli updatedFlag = 0; 4890084047dSAppaRao Puli 490cb267c8fSGeorge Liu lg2::info("Applied new settings: {OBJPATH}", "OBJPATH", objPath); 4910084047dSAppaRao Puli 49290f2da3fSRichard Marian Thomaiyar queryAndUpdateProperties(); 4930084047dSAppaRao Puli return; 4940084047dSAppaRao Puli } 4950084047dSAppaRao Puli 4960084047dSAppaRao Puli void ServiceConfig::startServiceRestartTimer() 4970084047dSAppaRao Puli { 49833816cf9SRichard Marian Thomaiyar timer->expires_after(std::chrono::seconds(restartTimeout)); 4990084047dSAppaRao Puli timer->async_wait([this](const boost::system::error_code& ec) { 5000084047dSAppaRao Puli if (ec == boost::asio::error::operation_aborted) 5010084047dSAppaRao Puli { 5020084047dSAppaRao Puli // Timer reset. 5030084047dSAppaRao Puli return; 5040084047dSAppaRao Puli } 5050084047dSAppaRao Puli else if (ec) 5060084047dSAppaRao Puli { 507cb267c8fSGeorge Liu lg2::error("async wait error: {EC}", "EC", ec.value()); 5080084047dSAppaRao Puli return; 5090084047dSAppaRao Puli } 51090f2da3fSRichard Marian Thomaiyar updateInProgress = true; 51190f2da3fSRichard Marian Thomaiyar boost::asio::spawn(conn->get_io_context(), 51290f2da3fSRichard Marian Thomaiyar [this](boost::asio::yield_context yield) { 51390f2da3fSRichard Marian Thomaiyar // Stop and apply configuration for all objects 5140084047dSAppaRao Puli for (auto& srvMgrObj : srvMgrObjects) 5150084047dSAppaRao Puli { 5160084047dSAppaRao Puli auto& srvObj = srvMgrObj.second; 5170084047dSAppaRao Puli if (srvObj->updatedFlag) 5180084047dSAppaRao Puli { 51990f2da3fSRichard Marian Thomaiyar srvObj->stopAndApplyUnitConfig(yield); 5200084047dSAppaRao Puli } 5210084047dSAppaRao Puli } 52290f2da3fSRichard Marian Thomaiyar // Do system reload 52390f2da3fSRichard Marian Thomaiyar systemdDaemonReload(conn, yield); 52490f2da3fSRichard Marian Thomaiyar // restart unit config. 52590f2da3fSRichard Marian Thomaiyar for (auto& srvMgrObj : srvMgrObjects) 52690f2da3fSRichard Marian Thomaiyar { 52790f2da3fSRichard Marian Thomaiyar auto& srvObj = srvMgrObj.second; 52890f2da3fSRichard Marian Thomaiyar if (srvObj->updatedFlag) 52990f2da3fSRichard Marian Thomaiyar { 53090f2da3fSRichard Marian Thomaiyar srvObj->restartUnitConfig(yield); 53190f2da3fSRichard Marian Thomaiyar } 53290f2da3fSRichard Marian Thomaiyar } 53390f2da3fSRichard Marian Thomaiyar updateInProgress = false; 53490f2da3fSRichard Marian Thomaiyar }); 5350084047dSAppaRao Puli }); 5360084047dSAppaRao Puli } 5370084047dSAppaRao Puli 5380084047dSAppaRao Puli void ServiceConfig::registerProperties() 5390084047dSAppaRao Puli { 54083241c09STom Joseph srvCfgIface = server.add_interface(objPath, serviceConfigIntfName); 5410084047dSAppaRao Puli 54290f2da3fSRichard Marian Thomaiyar if (!socketObjectPath.empty()) 54390f2da3fSRichard Marian Thomaiyar { 54483241c09STom Joseph sockAttrIface = server.add_interface(objPath, sockAttrIntfName); 54583241c09STom Joseph sockAttrIface->register_property( 54683241c09STom Joseph sockAttrPropPort, portNum, 54790f2da3fSRichard Marian Thomaiyar [this](const uint16_t& req, uint16_t& res) { 54890f2da3fSRichard Marian Thomaiyar if (!internalSet) 54990f2da3fSRichard Marian Thomaiyar { 5500084047dSAppaRao Puli if (req == res) 5510084047dSAppaRao Puli { 5520084047dSAppaRao Puli return 1; 5530084047dSAppaRao Puli } 55490f2da3fSRichard Marian Thomaiyar if (updateInProgress) 55590f2da3fSRichard Marian Thomaiyar { 55690f2da3fSRichard Marian Thomaiyar return 0; 55790f2da3fSRichard Marian Thomaiyar } 5580084047dSAppaRao Puli portNum = req; 55990f2da3fSRichard Marian Thomaiyar updatedFlag |= 56090f2da3fSRichard Marian Thomaiyar (1 << static_cast<uint8_t>(UpdatedProp::port)); 5610084047dSAppaRao Puli startServiceRestartTimer(); 56290f2da3fSRichard Marian Thomaiyar } 56390f2da3fSRichard Marian Thomaiyar res = req; 56490f2da3fSRichard Marian Thomaiyar return 1; 56590f2da3fSRichard Marian Thomaiyar }); 56690f2da3fSRichard Marian Thomaiyar } 56790f2da3fSRichard Marian Thomaiyar 56883241c09STom Joseph srvCfgIface->register_property( 56990f2da3fSRichard Marian Thomaiyar srvCfgPropMasked, unitMaskedState, [this](const bool& req, bool& res) { 57090f2da3fSRichard Marian Thomaiyar if (!internalSet) 57190f2da3fSRichard Marian Thomaiyar { 57225a0f634SChicago Duan #ifdef USB_CODE_UPDATE 57325a0f634SChicago Duan if (objPath == usbCodeUpdateObjectPath) 57425a0f634SChicago Duan { 57525a0f634SChicago Duan unitMaskedState = req; 57625a0f634SChicago Duan unitEnabledState = !unitMaskedState; 57725a0f634SChicago Duan unitRunningState = !unitMaskedState; 57825a0f634SChicago Duan internalSet = true; 57925a0f634SChicago Duan srvCfgIface->set_property(srvCfgPropEnabled, 58025a0f634SChicago Duan unitEnabledState); 58125a0f634SChicago Duan srvCfgIface->set_property(srvCfgPropRunning, 58225a0f634SChicago Duan unitRunningState); 58325a0f634SChicago Duan srvCfgIface->set_property(srvCfgPropMasked, 58425a0f634SChicago Duan unitMaskedState); 58525a0f634SChicago Duan internalSet = false; 58625a0f634SChicago Duan setUSBCodeUpdateState(unitEnabledState); 58725a0f634SChicago Duan saveUSBCodeUpdateStateToFile(unitMaskedState, 58825a0f634SChicago Duan unitEnabledState); 58925a0f634SChicago Duan return 1; 59025a0f634SChicago Duan } 59125a0f634SChicago Duan #endif 59290f2da3fSRichard Marian Thomaiyar if (req == res) 59390f2da3fSRichard Marian Thomaiyar { 59490f2da3fSRichard Marian Thomaiyar return 1; 59590f2da3fSRichard Marian Thomaiyar } 59690f2da3fSRichard Marian Thomaiyar if (updateInProgress) 59790f2da3fSRichard Marian Thomaiyar { 59890f2da3fSRichard Marian Thomaiyar return 0; 59990f2da3fSRichard Marian Thomaiyar } 60090f2da3fSRichard Marian Thomaiyar unitMaskedState = req; 60190f2da3fSRichard Marian Thomaiyar unitEnabledState = !unitMaskedState; 60290f2da3fSRichard Marian Thomaiyar unitRunningState = !unitMaskedState; 60390f2da3fSRichard Marian Thomaiyar updatedFlag |= 60490f2da3fSRichard Marian Thomaiyar (1 << static_cast<uint8_t>(UpdatedProp::maskedState)) | 60590f2da3fSRichard Marian Thomaiyar (1 << static_cast<uint8_t>(UpdatedProp::enabledState)) | 60690f2da3fSRichard Marian Thomaiyar (1 << static_cast<uint8_t>(UpdatedProp::runningState)); 60790f2da3fSRichard Marian Thomaiyar internalSet = true; 60883241c09STom Joseph srvCfgIface->set_property(srvCfgPropEnabled, unitEnabledState); 60983241c09STom Joseph srvCfgIface->set_property(srvCfgPropRunning, unitRunningState); 61090f2da3fSRichard Marian Thomaiyar internalSet = false; 61190f2da3fSRichard Marian Thomaiyar startServiceRestartTimer(); 61290f2da3fSRichard Marian Thomaiyar } 6130084047dSAppaRao Puli res = req; 6140084047dSAppaRao Puli return 1; 6150084047dSAppaRao Puli }); 6160084047dSAppaRao Puli 61783241c09STom Joseph srvCfgIface->register_property( 61890f2da3fSRichard Marian Thomaiyar srvCfgPropEnabled, unitEnabledState, 61990f2da3fSRichard Marian Thomaiyar [this](const bool& req, bool& res) { 62090f2da3fSRichard Marian Thomaiyar if (!internalSet) 62190f2da3fSRichard Marian Thomaiyar { 62225a0f634SChicago Duan #ifdef USB_CODE_UPDATE 62325a0f634SChicago Duan if (objPath == usbCodeUpdateObjectPath) 62425a0f634SChicago Duan { 62525a0f634SChicago Duan if (unitMaskedState) 62625a0f634SChicago Duan { // block updating if masked 62725a0f634SChicago Duan phosphor::logging::log<phosphor::logging::level::ERR>( 62825a0f634SChicago Duan "Invalid value specified"); 62925a0f634SChicago Duan return -EINVAL; 63025a0f634SChicago Duan } 63125a0f634SChicago Duan unitEnabledState = req; 63225a0f634SChicago Duan unitRunningState = req; 63325a0f634SChicago Duan internalSet = true; 63425a0f634SChicago Duan srvCfgIface->set_property(srvCfgPropEnabled, 63525a0f634SChicago Duan unitEnabledState); 63625a0f634SChicago Duan srvCfgIface->set_property(srvCfgPropRunning, 63725a0f634SChicago Duan unitRunningState); 63825a0f634SChicago Duan internalSet = false; 63925a0f634SChicago Duan setUSBCodeUpdateState(unitEnabledState); 64025a0f634SChicago Duan saveUSBCodeUpdateStateToFile(unitMaskedState, 64125a0f634SChicago Duan unitEnabledState); 64225a0f634SChicago Duan res = req; 64325a0f634SChicago Duan return 1; 64425a0f634SChicago Duan } 64525a0f634SChicago Duan #endif 6460084047dSAppaRao Puli if (req == res) 6470084047dSAppaRao Puli { 6480084047dSAppaRao Puli return 1; 6490084047dSAppaRao Puli } 65090f2da3fSRichard Marian Thomaiyar if (updateInProgress) 6510084047dSAppaRao Puli { 65290f2da3fSRichard Marian Thomaiyar return 0; 6530084047dSAppaRao Puli } 65490f2da3fSRichard Marian Thomaiyar if (unitMaskedState) 65590f2da3fSRichard Marian Thomaiyar { // block updating if masked 656cb267c8fSGeorge Liu lg2::error("Invalid value specified"); 6570084047dSAppaRao Puli return -EINVAL; 6580084047dSAppaRao Puli } 65990f2da3fSRichard Marian Thomaiyar unitEnabledState = req; 66090f2da3fSRichard Marian Thomaiyar updatedFlag |= 66190f2da3fSRichard Marian Thomaiyar (1 << static_cast<uint8_t>(UpdatedProp::enabledState)); 6620084047dSAppaRao Puli startServiceRestartTimer(); 66390f2da3fSRichard Marian Thomaiyar } 66490f2da3fSRichard Marian Thomaiyar res = req; 66590f2da3fSRichard Marian Thomaiyar return 1; 66690f2da3fSRichard Marian Thomaiyar }); 66790f2da3fSRichard Marian Thomaiyar 66883241c09STom Joseph srvCfgIface->register_property( 66990f2da3fSRichard Marian Thomaiyar srvCfgPropRunning, unitRunningState, 67090f2da3fSRichard Marian Thomaiyar [this](const bool& req, bool& res) { 67190f2da3fSRichard Marian Thomaiyar if (!internalSet) 67290f2da3fSRichard Marian Thomaiyar { 67325a0f634SChicago Duan #ifdef USB_CODE_UPDATE 67425a0f634SChicago Duan if (objPath == usbCodeUpdateObjectPath) 67525a0f634SChicago Duan { 67625a0f634SChicago Duan if (unitMaskedState) 67725a0f634SChicago Duan { // block updating if masked 67825a0f634SChicago Duan phosphor::logging::log<phosphor::logging::level::ERR>( 67925a0f634SChicago Duan "Invalid value specified"); 68025a0f634SChicago Duan return -EINVAL; 68125a0f634SChicago Duan } 68225a0f634SChicago Duan unitEnabledState = req; 68325a0f634SChicago Duan unitRunningState = req; 68425a0f634SChicago Duan internalSet = true; 68525a0f634SChicago Duan srvCfgIface->set_property(srvCfgPropEnabled, 68625a0f634SChicago Duan unitEnabledState); 68725a0f634SChicago Duan srvCfgIface->set_property(srvCfgPropRunning, 68825a0f634SChicago Duan unitRunningState); 68925a0f634SChicago Duan internalSet = false; 69025a0f634SChicago Duan setUSBCodeUpdateState(unitEnabledState); 69125a0f634SChicago Duan saveUSBCodeUpdateStateToFile(unitMaskedState, 69225a0f634SChicago Duan unitEnabledState); 69325a0f634SChicago Duan res = req; 69425a0f634SChicago Duan return 1; 69525a0f634SChicago Duan } 69625a0f634SChicago Duan #endif 69790f2da3fSRichard Marian Thomaiyar if (req == res) 69890f2da3fSRichard Marian Thomaiyar { 69990f2da3fSRichard Marian Thomaiyar return 1; 70090f2da3fSRichard Marian Thomaiyar } 70190f2da3fSRichard Marian Thomaiyar if (updateInProgress) 70290f2da3fSRichard Marian Thomaiyar { 70390f2da3fSRichard Marian Thomaiyar return 0; 70490f2da3fSRichard Marian Thomaiyar } 70590f2da3fSRichard Marian Thomaiyar if (unitMaskedState) 70690f2da3fSRichard Marian Thomaiyar { // block updating if masked 707cb267c8fSGeorge Liu lg2::error("Invalid value specified"); 70890f2da3fSRichard Marian Thomaiyar return -EINVAL; 70990f2da3fSRichard Marian Thomaiyar } 71090f2da3fSRichard Marian Thomaiyar unitRunningState = req; 71190f2da3fSRichard Marian Thomaiyar updatedFlag |= 71290f2da3fSRichard Marian Thomaiyar (1 << static_cast<uint8_t>(UpdatedProp::runningState)); 71390f2da3fSRichard Marian Thomaiyar startServiceRestartTimer(); 71490f2da3fSRichard Marian Thomaiyar } 7150084047dSAppaRao Puli res = req; 7160084047dSAppaRao Puli return 1; 7170084047dSAppaRao Puli }); 7180084047dSAppaRao Puli 71983241c09STom Joseph srvCfgIface->initialize(); 72083241c09STom Joseph if (!socketObjectPath.empty()) 72183241c09STom Joseph { 72283241c09STom Joseph sockAttrIface->initialize(); 72383241c09STom Joseph } 7240084047dSAppaRao Puli return; 7250084047dSAppaRao Puli } 7260084047dSAppaRao Puli 7270084047dSAppaRao Puli } // namespace service 7280084047dSAppaRao Puli } // namespace phosphor 729