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 { 68*f27f431fSJiaqing Zhao lg2::info("Enable usb code update"); 6925a0f634SChicago Duan std::filesystem::remove(emptyUsbCodeUpdateRulesFile); 7025a0f634SChicago Duan } 7125a0f634SChicago Duan return; 7225a0f634SChicago Duan } 7325a0f634SChicago Duan 7425a0f634SChicago Duan // Disable usb code update 7525a0f634SChicago Duan if (std::filesystem::exists(emptyUsbCodeUpdateRulesFile)) 7625a0f634SChicago Duan { 7725a0f634SChicago Duan std::filesystem::remove(emptyUsbCodeUpdateRulesFile); 7825a0f634SChicago Duan } 7925a0f634SChicago Duan std::error_code ec; 8025a0f634SChicago Duan std::filesystem::create_symlink("/dev/null", emptyUsbCodeUpdateRulesFile, 8125a0f634SChicago Duan ec); 8225a0f634SChicago Duan if (ec) 8325a0f634SChicago Duan { 84*f27f431fSJiaqing Zhao lg2::error("Disable usb code update failed"); 8525a0f634SChicago Duan return; 8625a0f634SChicago Duan } 87*f27f431fSJiaqing Zhao lg2::info("Disable usb code update"); 8825a0f634SChicago Duan } 8925a0f634SChicago Duan 9025a0f634SChicago Duan void ServiceConfig::saveUSBCodeUpdateStateToFile(const bool& maskedState, 9125a0f634SChicago Duan const bool& enabledState) 9225a0f634SChicago Duan { 9325a0f634SChicago Duan if (!std::filesystem::exists(usbCodeUpdateStateFilePath)) 9425a0f634SChicago Duan { 9525a0f634SChicago Duan std::filesystem::create_directories(usbCodeUpdateStateFilePath); 9625a0f634SChicago Duan } 9725a0f634SChicago Duan 9825a0f634SChicago Duan UsbCodeUpdateStateMap usbCodeUpdateState; 9925a0f634SChicago Duan usbCodeUpdateState[srvCfgPropMasked] = maskedState; 10025a0f634SChicago Duan usbCodeUpdateState[srvCfgPropEnabled] = enabledState; 10125a0f634SChicago Duan 10225a0f634SChicago Duan std::ofstream file(usbCodeUpdateStateFile, std::ios::out); 10325a0f634SChicago Duan cereal::JSONOutputArchive archive(file); 10425a0f634SChicago Duan archive(CEREAL_NVP(usbCodeUpdateState)); 10525a0f634SChicago Duan } 10625a0f634SChicago Duan 10725a0f634SChicago Duan void ServiceConfig::getUSBCodeUpdateStateFromFile() 10825a0f634SChicago Duan { 10925a0f634SChicago Duan if (!std::filesystem::exists(usbCodeUpdateStateFile)) 11025a0f634SChicago Duan { 111*f27f431fSJiaqing Zhao lg2::info("usb-code-update-state file does not exist"); 11225a0f634SChicago Duan 11325a0f634SChicago Duan unitMaskedState = false; 11425a0f634SChicago Duan unitEnabledState = true; 11525a0f634SChicago Duan unitRunningState = true; 11625a0f634SChicago Duan setUSBCodeUpdateState(unitEnabledState); 11725a0f634SChicago Duan return; 11825a0f634SChicago Duan } 11925a0f634SChicago Duan 12025a0f634SChicago Duan std::ifstream file(usbCodeUpdateStateFile); 12125a0f634SChicago Duan cereal::JSONInputArchive archive(file); 12225a0f634SChicago Duan UsbCodeUpdateStateMap usbCodeUpdateState; 12325a0f634SChicago Duan archive(usbCodeUpdateState); 12425a0f634SChicago Duan 12525a0f634SChicago Duan auto iterMask = usbCodeUpdateState.find(srvCfgPropMasked); 12625a0f634SChicago Duan if (iterMask != usbCodeUpdateState.end()) 12725a0f634SChicago Duan { 12825a0f634SChicago Duan unitMaskedState = iterMask->second; 12925a0f634SChicago Duan if (unitMaskedState) 13025a0f634SChicago Duan { 13125a0f634SChicago Duan unitEnabledState = !unitMaskedState; 13225a0f634SChicago Duan unitRunningState = !unitMaskedState; 13325a0f634SChicago Duan setUSBCodeUpdateState(unitEnabledState); 13425a0f634SChicago Duan return; 13525a0f634SChicago Duan } 13625a0f634SChicago Duan 13725a0f634SChicago Duan auto iterEnable = usbCodeUpdateState.find(srvCfgPropEnabled); 13825a0f634SChicago Duan if (iterEnable != usbCodeUpdateState.end()) 13925a0f634SChicago Duan { 14025a0f634SChicago Duan unitEnabledState = iterEnable->second; 14125a0f634SChicago Duan unitRunningState = iterEnable->second; 14225a0f634SChicago Duan setUSBCodeUpdateState(unitEnabledState); 14325a0f634SChicago Duan } 14425a0f634SChicago Duan } 14525a0f634SChicago Duan } 14625a0f634SChicago Duan #endif 14725a0f634SChicago Duan 14890f2da3fSRichard Marian Thomaiyar void ServiceConfig::updateSocketProperties( 14990f2da3fSRichard Marian Thomaiyar const boost::container::flat_map<std::string, VariantType>& propertyMap) 1500084047dSAppaRao Puli { 15190f2da3fSRichard Marian Thomaiyar auto listenIt = propertyMap.find("Listen"); 15290f2da3fSRichard Marian Thomaiyar if (listenIt != propertyMap.end()) 1530084047dSAppaRao Puli { 15490f2da3fSRichard Marian Thomaiyar auto listenVal = 15590f2da3fSRichard Marian Thomaiyar std::get<std::vector<std::tuple<std::string, std::string>>>( 15690f2da3fSRichard Marian Thomaiyar listenIt->second); 15790f2da3fSRichard Marian Thomaiyar if (listenVal.size()) 1580084047dSAppaRao Puli { 1590084047dSAppaRao Puli protocol = std::get<0>(listenVal[0]); 1600084047dSAppaRao Puli std::string port = std::get<1>(listenVal[0]); 1610084047dSAppaRao Puli auto tmp = std::stoul(port.substr(port.find_last_of(":") + 1), 1620084047dSAppaRao Puli nullptr, 10); 1630084047dSAppaRao Puli if (tmp > std::numeric_limits<uint16_t>::max()) 1640084047dSAppaRao Puli { 1650084047dSAppaRao Puli throw std::out_of_range("Out of range"); 1660084047dSAppaRao Puli } 1670084047dSAppaRao Puli portNum = tmp; 16883241c09STom Joseph if (sockAttrIface && sockAttrIface->is_initialized()) 16990f2da3fSRichard Marian Thomaiyar { 17090f2da3fSRichard Marian Thomaiyar internalSet = true; 17183241c09STom Joseph sockAttrIface->set_property(sockAttrPropPort, portNum); 17290f2da3fSRichard Marian Thomaiyar internalSet = false; 17390f2da3fSRichard Marian Thomaiyar } 17490f2da3fSRichard Marian Thomaiyar } 17590f2da3fSRichard Marian Thomaiyar } 17690f2da3fSRichard Marian Thomaiyar } 17790f2da3fSRichard Marian Thomaiyar 17890f2da3fSRichard Marian Thomaiyar void ServiceConfig::updateServiceProperties( 17990f2da3fSRichard Marian Thomaiyar const boost::container::flat_map<std::string, VariantType>& propertyMap) 18090f2da3fSRichard Marian Thomaiyar { 18190f2da3fSRichard Marian Thomaiyar auto stateIt = propertyMap.find("UnitFileState"); 18290f2da3fSRichard Marian Thomaiyar if (stateIt != propertyMap.end()) 18390f2da3fSRichard Marian Thomaiyar { 18490f2da3fSRichard Marian Thomaiyar stateValue = std::get<std::string>(stateIt->second); 18590f2da3fSRichard Marian Thomaiyar unitEnabledState = unitMaskedState = false; 18690f2da3fSRichard Marian Thomaiyar if (stateValue == stateMasked) 18790f2da3fSRichard Marian Thomaiyar { 18890f2da3fSRichard Marian Thomaiyar unitMaskedState = true; 18990f2da3fSRichard Marian Thomaiyar } 19090f2da3fSRichard Marian Thomaiyar else if (stateValue == stateEnabled) 19190f2da3fSRichard Marian Thomaiyar { 19290f2da3fSRichard Marian Thomaiyar unitEnabledState = true; 19390f2da3fSRichard Marian Thomaiyar } 19483241c09STom Joseph if (srvCfgIface && srvCfgIface->is_initialized()) 19590f2da3fSRichard Marian Thomaiyar { 19690f2da3fSRichard Marian Thomaiyar internalSet = true; 19783241c09STom Joseph srvCfgIface->set_property(srvCfgPropMasked, unitMaskedState); 19883241c09STom Joseph srvCfgIface->set_property(srvCfgPropEnabled, unitEnabledState); 19990f2da3fSRichard Marian Thomaiyar internalSet = false; 20090f2da3fSRichard Marian Thomaiyar } 20190f2da3fSRichard Marian Thomaiyar } 20290f2da3fSRichard Marian Thomaiyar auto subStateIt = propertyMap.find("SubState"); 20390f2da3fSRichard Marian Thomaiyar if (subStateIt != propertyMap.end()) 20490f2da3fSRichard Marian Thomaiyar { 20590f2da3fSRichard Marian Thomaiyar subStateValue = std::get<std::string>(subStateIt->second); 206a19b5093SGeorge Liu if (subStateValue == subStateRunning || 207a19b5093SGeorge Liu subStateValue == subStateListening) 20890f2da3fSRichard Marian Thomaiyar { 20990f2da3fSRichard Marian Thomaiyar unitRunningState = true; 21090f2da3fSRichard Marian Thomaiyar } 21183241c09STom Joseph if (srvCfgIface && srvCfgIface->is_initialized()) 21290f2da3fSRichard Marian Thomaiyar { 21390f2da3fSRichard Marian Thomaiyar internalSet = true; 21483241c09STom Joseph srvCfgIface->set_property(srvCfgPropRunning, unitRunningState); 21590f2da3fSRichard Marian Thomaiyar internalSet = false; 21690f2da3fSRichard Marian Thomaiyar } 21790f2da3fSRichard Marian Thomaiyar } 21825a0f634SChicago Duan 21925a0f634SChicago Duan #ifdef USB_CODE_UPDATE 22025a0f634SChicago Duan if (objPath == usbCodeUpdateObjectPath) 22125a0f634SChicago Duan { 22225a0f634SChicago Duan getUSBCodeUpdateStateFromFile(); 22325a0f634SChicago Duan } 22425a0f634SChicago Duan #endif 22590f2da3fSRichard Marian Thomaiyar } 22690f2da3fSRichard Marian Thomaiyar 22790f2da3fSRichard Marian Thomaiyar void ServiceConfig::queryAndUpdateProperties() 22890f2da3fSRichard Marian Thomaiyar { 229a19b5093SGeorge Liu std::string objectPath = 230f476683cSJiaqing Zhao isSocketActivatedService ? socketObjectPath : serviceObjectPath; 231a19b5093SGeorge Liu if (objectPath.empty()) 232a19b5093SGeorge Liu { 233a19b5093SGeorge Liu return; 234a19b5093SGeorge Liu } 235a19b5093SGeorge Liu 23690f2da3fSRichard Marian Thomaiyar conn->async_method_call( 23790f2da3fSRichard Marian Thomaiyar [this](boost::system::error_code ec, 238ee853eb2SAppaRao Puli const boost::container::flat_map<std::string, VariantType>& 239ee853eb2SAppaRao Puli propertyMap) { 24090f2da3fSRichard Marian Thomaiyar if (ec) 24190f2da3fSRichard Marian Thomaiyar { 242cb267c8fSGeorge Liu lg2::error( 243cb267c8fSGeorge Liu "async_method_call error: Failed to service unit properties: {EC}", 244cb267c8fSGeorge Liu "EC", ec.value()); 24590f2da3fSRichard Marian Thomaiyar return; 24690f2da3fSRichard Marian Thomaiyar } 24790f2da3fSRichard Marian Thomaiyar try 24890f2da3fSRichard Marian Thomaiyar { 24990f2da3fSRichard Marian Thomaiyar updateServiceProperties(propertyMap); 25090f2da3fSRichard Marian Thomaiyar if (!socketObjectPath.empty()) 25190f2da3fSRichard Marian Thomaiyar { 25290f2da3fSRichard Marian Thomaiyar conn->async_method_call( 25390f2da3fSRichard Marian Thomaiyar [this](boost::system::error_code ec, 25490f2da3fSRichard Marian Thomaiyar const boost::container::flat_map< 25590f2da3fSRichard Marian Thomaiyar std::string, VariantType>& propertyMap) { 25690f2da3fSRichard Marian Thomaiyar if (ec) 25790f2da3fSRichard Marian Thomaiyar { 258cb267c8fSGeorge Liu lg2::error( 259cb267c8fSGeorge Liu "async_method_call error: Failed to get all property: {EC}", 260cb267c8fSGeorge Liu "EC", ec.value()); 26190f2da3fSRichard Marian Thomaiyar return; 26290f2da3fSRichard Marian Thomaiyar } 26390f2da3fSRichard Marian Thomaiyar try 26490f2da3fSRichard Marian Thomaiyar { 26590f2da3fSRichard Marian Thomaiyar updateSocketProperties(propertyMap); 26683241c09STom Joseph if (!srvCfgIface) 26790f2da3fSRichard Marian Thomaiyar { 26890f2da3fSRichard Marian Thomaiyar registerProperties(); 26990f2da3fSRichard Marian Thomaiyar } 27090f2da3fSRichard Marian Thomaiyar } 27190f2da3fSRichard Marian Thomaiyar catch (const std::exception& e) 27290f2da3fSRichard Marian Thomaiyar { 273cb267c8fSGeorge Liu lg2::error( 274cb267c8fSGeorge Liu "Exception in getting socket properties: {ERROR}", 275cb267c8fSGeorge Liu "ERROR", e); 27690f2da3fSRichard Marian Thomaiyar return; 27790f2da3fSRichard Marian Thomaiyar } 27890f2da3fSRichard Marian Thomaiyar }, 27990f2da3fSRichard Marian Thomaiyar sysdService, socketObjectPath, dBusPropIntf, 28090f2da3fSRichard Marian Thomaiyar dBusGetAllMethod, sysdSocketIntf); 28190f2da3fSRichard Marian Thomaiyar } 28283241c09STom Joseph else if (!srvCfgIface) 28390f2da3fSRichard Marian Thomaiyar { 28490f2da3fSRichard Marian Thomaiyar registerProperties(); 28590f2da3fSRichard Marian Thomaiyar } 2860084047dSAppaRao Puli } 2870084047dSAppaRao Puli catch (const std::exception& e) 2880084047dSAppaRao Puli { 289cb267c8fSGeorge Liu lg2::error("Exception in getting socket properties: {ERROR}", 290cb267c8fSGeorge Liu "ERROR", e); 2910084047dSAppaRao Puli return; 2920084047dSAppaRao Puli } 2930084047dSAppaRao Puli }, 294a19b5093SGeorge Liu sysdService, objectPath, dBusPropIntf, dBusGetAllMethod, sysdUnitIntf); 2950084047dSAppaRao Puli return; 2960084047dSAppaRao Puli } 2970084047dSAppaRao Puli 29890f2da3fSRichard Marian Thomaiyar void ServiceConfig::createSocketOverrideConf() 2990084047dSAppaRao Puli { 30090f2da3fSRichard Marian Thomaiyar if (!socketObjectPath.empty()) 3010084047dSAppaRao Puli { 30290f2da3fSRichard Marian Thomaiyar std::string socketUnitName(instantiatedUnitName + ".socket"); 3030084047dSAppaRao Puli /// Check override socket directory exist, if not create it. 30482e9557eSTom Joseph std::filesystem::path ovrUnitFileDir(systemdOverrideUnitBasePath); 3050084047dSAppaRao Puli ovrUnitFileDir += socketUnitName; 3060084047dSAppaRao Puli ovrUnitFileDir += ".d"; 30782e9557eSTom Joseph if (!std::filesystem::exists(ovrUnitFileDir)) 3080084047dSAppaRao Puli { 30982e9557eSTom Joseph if (!std::filesystem::create_directories(ovrUnitFileDir)) 3100084047dSAppaRao Puli { 311cb267c8fSGeorge Liu lg2::error("Unable to create the {DIR} directory.", "DIR", 312cb267c8fSGeorge Liu ovrUnitFileDir); 31390f2da3fSRichard Marian Thomaiyar phosphor::logging::elog<sdbusplus::xyz::openbmc_project:: 31490f2da3fSRichard Marian Thomaiyar Common::Error::InternalFailure>(); 31590f2da3fSRichard Marian Thomaiyar } 31690f2da3fSRichard Marian Thomaiyar } 31790f2da3fSRichard Marian Thomaiyar overrideConfDir = std::string(ovrUnitFileDir); 3180084047dSAppaRao Puli } 3190084047dSAppaRao Puli } 3200084047dSAppaRao Puli 32190f2da3fSRichard Marian Thomaiyar ServiceConfig::ServiceConfig( 32290f2da3fSRichard Marian Thomaiyar sdbusplus::asio::object_server& srv_, 32390f2da3fSRichard Marian Thomaiyar std::shared_ptr<sdbusplus::asio::connection>& conn_, 32490f2da3fSRichard Marian Thomaiyar const std::string& objPath_, const std::string& baseUnitName_, 32590f2da3fSRichard Marian Thomaiyar const std::string& instanceName_, const std::string& serviceObjPath_, 32690f2da3fSRichard Marian Thomaiyar const std::string& socketObjPath_) : 32782e9557eSTom Joseph conn(conn_), 32882e9557eSTom Joseph server(srv_), objPath(objPath_), baseUnitName(baseUnitName_), 32990f2da3fSRichard Marian Thomaiyar instanceName(instanceName_), serviceObjectPath(serviceObjPath_), 33090f2da3fSRichard Marian Thomaiyar socketObjectPath(socketObjPath_) 33190f2da3fSRichard Marian Thomaiyar { 332f476683cSJiaqing Zhao isSocketActivatedService = serviceObjectPath.empty(); 33390f2da3fSRichard Marian Thomaiyar instantiatedUnitName = baseUnitName + addInstanceName(instanceName, "@"); 3340084047dSAppaRao Puli updatedFlag = 0; 33590f2da3fSRichard Marian Thomaiyar queryAndUpdateProperties(); 3360084047dSAppaRao Puli return; 3370084047dSAppaRao Puli } 3380084047dSAppaRao Puli 33990f2da3fSRichard Marian Thomaiyar std::string ServiceConfig::getSocketUnitName() 3400084047dSAppaRao Puli { 34190f2da3fSRichard Marian Thomaiyar return instantiatedUnitName + ".socket"; 342e55cfd6eSAppaRao Puli } 343e55cfd6eSAppaRao Puli 34490f2da3fSRichard Marian Thomaiyar std::string ServiceConfig::getServiceUnitName() 34590f2da3fSRichard Marian Thomaiyar { 34690f2da3fSRichard Marian Thomaiyar return instantiatedUnitName + ".service"; 34790f2da3fSRichard Marian Thomaiyar } 34890f2da3fSRichard Marian Thomaiyar 34990f2da3fSRichard Marian Thomaiyar bool ServiceConfig::isMaskedOut() 35090f2da3fSRichard Marian Thomaiyar { 35190f2da3fSRichard Marian Thomaiyar // return true if state is masked & no request to update the maskedState 35290f2da3fSRichard Marian Thomaiyar return ( 35390f2da3fSRichard Marian Thomaiyar stateValue == "masked" && 35490f2da3fSRichard Marian Thomaiyar !(updatedFlag & (1 << static_cast<uint8_t>(UpdatedProp::maskedState)))); 35590f2da3fSRichard Marian Thomaiyar } 35690f2da3fSRichard Marian Thomaiyar 35790f2da3fSRichard Marian Thomaiyar void ServiceConfig::stopAndApplyUnitConfig(boost::asio::yield_context yield) 35890f2da3fSRichard Marian Thomaiyar { 35990f2da3fSRichard Marian Thomaiyar if (!updatedFlag || isMaskedOut()) 36090f2da3fSRichard Marian Thomaiyar { 36190f2da3fSRichard Marian Thomaiyar // No updates / masked - Just return. 36290f2da3fSRichard Marian Thomaiyar return; 36390f2da3fSRichard Marian Thomaiyar } 364cb267c8fSGeorge Liu lg2::info("Applying new settings: {OBJPATH}", "OBJPATH", objPath); 365a19b5093SGeorge Liu if (subStateValue == subStateRunning || subStateValue == subStateListening) 3660084047dSAppaRao Puli { 36790f2da3fSRichard Marian Thomaiyar if (!socketObjectPath.empty()) 36890f2da3fSRichard Marian Thomaiyar { 36990f2da3fSRichard Marian Thomaiyar systemdUnitAction(conn, yield, getSocketUnitName(), sysdStopUnit); 37090f2da3fSRichard Marian Thomaiyar } 371f476683cSJiaqing Zhao if (!isSocketActivatedService) 372a19b5093SGeorge Liu { 37390f2da3fSRichard Marian Thomaiyar systemdUnitAction(conn, yield, getServiceUnitName(), sysdStopUnit); 37490f2da3fSRichard Marian Thomaiyar } 375a19b5093SGeorge Liu else 376a19b5093SGeorge Liu { 377f476683cSJiaqing Zhao // For socket-activated service, each connection will spawn a 378f476683cSJiaqing Zhao // service instance from template. Need to find all spawned service 379f476683cSJiaqing Zhao // `<unitName>@<attribute>.service` and stop them through the 380f476683cSJiaqing Zhao // systemdUnitAction method 381a19b5093SGeorge Liu boost::system::error_code ec; 382a19b5093SGeorge Liu auto listUnits = 383a19b5093SGeorge Liu conn->yield_method_call<std::vector<ListUnitsType>>( 384a19b5093SGeorge Liu yield, ec, sysdService, sysdObjPath, sysdMgrIntf, 385a19b5093SGeorge Liu "ListUnits"); 386a19b5093SGeorge Liu 387a19b5093SGeorge Liu checkAndThrowInternalFailure( 388a19b5093SGeorge Liu ec, "yield_method_call error: ListUnits failed"); 389a19b5093SGeorge Liu 390a19b5093SGeorge Liu for (const auto& unit : listUnits) 391a19b5093SGeorge Liu { 392a19b5093SGeorge Liu const auto& service = 393a19b5093SGeorge Liu std::get<static_cast<int>(ListUnitElements::name)>(unit); 394a19b5093SGeorge Liu const auto& status = 395a19b5093SGeorge Liu std::get<static_cast<int>(ListUnitElements::subState)>( 396a19b5093SGeorge Liu unit); 397f476683cSJiaqing Zhao if (service.find(baseUnitName + "@") != std::string::npos && 398a19b5093SGeorge Liu service.find(".service") != std::string::npos && 399a19b5093SGeorge Liu status == subStateRunning) 400a19b5093SGeorge Liu { 401a19b5093SGeorge Liu systemdUnitAction(conn, yield, service, sysdStopUnit); 402a19b5093SGeorge Liu } 403a19b5093SGeorge Liu } 404a19b5093SGeorge Liu } 405a19b5093SGeorge Liu } 40690f2da3fSRichard Marian Thomaiyar 40790f2da3fSRichard Marian Thomaiyar if (updatedFlag & (1 << static_cast<uint8_t>(UpdatedProp::port))) 40890f2da3fSRichard Marian Thomaiyar { 40990f2da3fSRichard Marian Thomaiyar createSocketOverrideConf(); 4100084047dSAppaRao Puli // Create override config file and write data. 41190f2da3fSRichard Marian Thomaiyar std::string ovrCfgFile{overrideConfDir + "/" + overrideConfFileName}; 4120084047dSAppaRao Puli std::string tmpFile{ovrCfgFile + "_tmp"}; 4130084047dSAppaRao Puli std::ofstream cfgFile(tmpFile, std::ios::out); 4140084047dSAppaRao Puli if (!cfgFile.good()) 4150084047dSAppaRao Puli { 416cb267c8fSGeorge Liu lg2::error("Failed to open the {TMPFILE} file.", "TMPFILE", 417cb267c8fSGeorge Liu tmpFile); 4180084047dSAppaRao Puli phosphor::logging::elog<sdbusplus::xyz::openbmc_project::Common:: 4190084047dSAppaRao Puli Error::InternalFailure>(); 4200084047dSAppaRao Puli } 4210084047dSAppaRao Puli 4220084047dSAppaRao Puli // Write the socket header 4230084047dSAppaRao Puli cfgFile << "[Socket]\n"; 4240084047dSAppaRao Puli // Listen 4250084047dSAppaRao Puli cfgFile << "Listen" << protocol << "=" 4260084047dSAppaRao Puli << "\n"; 4270084047dSAppaRao Puli cfgFile << "Listen" << protocol << "=" << portNum << "\n"; 4280084047dSAppaRao Puli cfgFile.close(); 4290084047dSAppaRao Puli 4300084047dSAppaRao Puli if (std::rename(tmpFile.c_str(), ovrCfgFile.c_str()) != 0) 4310084047dSAppaRao Puli { 432cb267c8fSGeorge Liu lg2::error("Failed to rename {TMPFILE} file as {OVERCFGFILE} file.", 433cb267c8fSGeorge Liu "TMPFILE", tmpFile, "OVERCFGFILE", ovrCfgFile); 4340084047dSAppaRao Puli std::remove(tmpFile.c_str()); 4350084047dSAppaRao Puli phosphor::logging::elog<sdbusplus::xyz::openbmc_project::Common:: 4360084047dSAppaRao Puli Error::InternalFailure>(); 4370084047dSAppaRao Puli } 438e55cfd6eSAppaRao Puli } 4390084047dSAppaRao Puli 44090f2da3fSRichard Marian Thomaiyar if (updatedFlag & ((1 << static_cast<uint8_t>(UpdatedProp::maskedState)) | 44190f2da3fSRichard Marian Thomaiyar (1 << static_cast<uint8_t>(UpdatedProp::enabledState)))) 442e55cfd6eSAppaRao Puli { 44390f2da3fSRichard Marian Thomaiyar std::vector<std::string> unitFiles; 44490f2da3fSRichard Marian Thomaiyar if (socketObjectPath.empty()) 44590f2da3fSRichard Marian Thomaiyar { 44690f2da3fSRichard Marian Thomaiyar unitFiles = {getServiceUnitName()}; 447e55cfd6eSAppaRao Puli } 448f476683cSJiaqing Zhao else if (serviceObjectPath.empty()) 449a19b5093SGeorge Liu { 450a19b5093SGeorge Liu unitFiles = {getSocketUnitName()}; 451a19b5093SGeorge Liu } 45290f2da3fSRichard Marian Thomaiyar else 453e55cfd6eSAppaRao Puli { 45490f2da3fSRichard Marian Thomaiyar unitFiles = {getSocketUnitName(), getServiceUnitName()}; 45590f2da3fSRichard Marian Thomaiyar } 45690f2da3fSRichard Marian Thomaiyar systemdUnitFilesStateChange(conn, yield, unitFiles, stateValue, 45790f2da3fSRichard Marian Thomaiyar unitMaskedState, unitEnabledState); 45890f2da3fSRichard Marian Thomaiyar } 45990f2da3fSRichard Marian Thomaiyar return; 46090f2da3fSRichard Marian Thomaiyar } 46190f2da3fSRichard Marian Thomaiyar void ServiceConfig::restartUnitConfig(boost::asio::yield_context yield) 46290f2da3fSRichard Marian Thomaiyar { 46390f2da3fSRichard Marian Thomaiyar if (!updatedFlag || isMaskedOut()) 46490f2da3fSRichard Marian Thomaiyar { 46590f2da3fSRichard Marian Thomaiyar // No updates. Just return. 46690f2da3fSRichard Marian Thomaiyar return; 4670084047dSAppaRao Puli } 4680084047dSAppaRao Puli 46990f2da3fSRichard Marian Thomaiyar if (unitRunningState) 4700084047dSAppaRao Puli { 47190f2da3fSRichard Marian Thomaiyar if (!socketObjectPath.empty()) 47290f2da3fSRichard Marian Thomaiyar { 47390f2da3fSRichard Marian Thomaiyar systemdUnitAction(conn, yield, getSocketUnitName(), 47490f2da3fSRichard Marian Thomaiyar sysdRestartUnit); 4750084047dSAppaRao Puli } 476f476683cSJiaqing Zhao if (!serviceObjectPath.empty()) 477a19b5093SGeorge Liu { 478a19b5093SGeorge Liu systemdUnitAction(conn, yield, getServiceUnitName(), 479a19b5093SGeorge Liu sysdRestartUnit); 480a19b5093SGeorge Liu } 4810084047dSAppaRao Puli } 4820084047dSAppaRao Puli 4830084047dSAppaRao Puli // Reset the flag 4840084047dSAppaRao Puli updatedFlag = 0; 4850084047dSAppaRao Puli 486cb267c8fSGeorge Liu lg2::info("Applied new settings: {OBJPATH}", "OBJPATH", objPath); 4870084047dSAppaRao Puli 48890f2da3fSRichard Marian Thomaiyar queryAndUpdateProperties(); 4890084047dSAppaRao Puli return; 4900084047dSAppaRao Puli } 4910084047dSAppaRao Puli 4920084047dSAppaRao Puli void ServiceConfig::startServiceRestartTimer() 4930084047dSAppaRao Puli { 49433816cf9SRichard Marian Thomaiyar timer->expires_after(std::chrono::seconds(restartTimeout)); 4950084047dSAppaRao Puli timer->async_wait([this](const boost::system::error_code& ec) { 4960084047dSAppaRao Puli if (ec == boost::asio::error::operation_aborted) 4970084047dSAppaRao Puli { 4980084047dSAppaRao Puli // Timer reset. 4990084047dSAppaRao Puli return; 5000084047dSAppaRao Puli } 5010084047dSAppaRao Puli else if (ec) 5020084047dSAppaRao Puli { 503cb267c8fSGeorge Liu lg2::error("async wait error: {EC}", "EC", ec.value()); 5040084047dSAppaRao Puli return; 5050084047dSAppaRao Puli } 50690f2da3fSRichard Marian Thomaiyar updateInProgress = true; 50790f2da3fSRichard Marian Thomaiyar boost::asio::spawn(conn->get_io_context(), 50890f2da3fSRichard Marian Thomaiyar [this](boost::asio::yield_context yield) { 50990f2da3fSRichard Marian Thomaiyar // Stop and apply configuration for all objects 5100084047dSAppaRao Puli for (auto& srvMgrObj : srvMgrObjects) 5110084047dSAppaRao Puli { 5120084047dSAppaRao Puli auto& srvObj = srvMgrObj.second; 5130084047dSAppaRao Puli if (srvObj->updatedFlag) 5140084047dSAppaRao Puli { 51590f2da3fSRichard Marian Thomaiyar srvObj->stopAndApplyUnitConfig(yield); 5160084047dSAppaRao Puli } 5170084047dSAppaRao Puli } 51890f2da3fSRichard Marian Thomaiyar // Do system reload 51990f2da3fSRichard Marian Thomaiyar systemdDaemonReload(conn, yield); 52090f2da3fSRichard Marian Thomaiyar // restart unit config. 52190f2da3fSRichard Marian Thomaiyar for (auto& srvMgrObj : srvMgrObjects) 52290f2da3fSRichard Marian Thomaiyar { 52390f2da3fSRichard Marian Thomaiyar auto& srvObj = srvMgrObj.second; 52490f2da3fSRichard Marian Thomaiyar if (srvObj->updatedFlag) 52590f2da3fSRichard Marian Thomaiyar { 52690f2da3fSRichard Marian Thomaiyar srvObj->restartUnitConfig(yield); 52790f2da3fSRichard Marian Thomaiyar } 52890f2da3fSRichard Marian Thomaiyar } 52990f2da3fSRichard Marian Thomaiyar updateInProgress = false; 53090f2da3fSRichard Marian Thomaiyar }); 5310084047dSAppaRao Puli }); 5320084047dSAppaRao Puli } 5330084047dSAppaRao Puli 5340084047dSAppaRao Puli void ServiceConfig::registerProperties() 5350084047dSAppaRao Puli { 53683241c09STom Joseph srvCfgIface = server.add_interface(objPath, serviceConfigIntfName); 5370084047dSAppaRao Puli 53890f2da3fSRichard Marian Thomaiyar if (!socketObjectPath.empty()) 53990f2da3fSRichard Marian Thomaiyar { 54083241c09STom Joseph sockAttrIface = server.add_interface(objPath, sockAttrIntfName); 54183241c09STom Joseph sockAttrIface->register_property( 54283241c09STom Joseph sockAttrPropPort, portNum, 54390f2da3fSRichard Marian Thomaiyar [this](const uint16_t& req, uint16_t& res) { 54490f2da3fSRichard Marian Thomaiyar if (!internalSet) 54590f2da3fSRichard Marian Thomaiyar { 5460084047dSAppaRao Puli if (req == res) 5470084047dSAppaRao Puli { 5480084047dSAppaRao Puli return 1; 5490084047dSAppaRao Puli } 55090f2da3fSRichard Marian Thomaiyar if (updateInProgress) 55190f2da3fSRichard Marian Thomaiyar { 55290f2da3fSRichard Marian Thomaiyar return 0; 55390f2da3fSRichard Marian Thomaiyar } 5540084047dSAppaRao Puli portNum = req; 55590f2da3fSRichard Marian Thomaiyar updatedFlag |= 55690f2da3fSRichard Marian Thomaiyar (1 << static_cast<uint8_t>(UpdatedProp::port)); 5570084047dSAppaRao Puli startServiceRestartTimer(); 55890f2da3fSRichard Marian Thomaiyar } 55990f2da3fSRichard Marian Thomaiyar res = req; 56090f2da3fSRichard Marian Thomaiyar return 1; 56190f2da3fSRichard Marian Thomaiyar }); 56290f2da3fSRichard Marian Thomaiyar } 56390f2da3fSRichard Marian Thomaiyar 56483241c09STom Joseph srvCfgIface->register_property( 56590f2da3fSRichard Marian Thomaiyar srvCfgPropMasked, unitMaskedState, [this](const bool& req, bool& res) { 56690f2da3fSRichard Marian Thomaiyar if (!internalSet) 56790f2da3fSRichard Marian Thomaiyar { 56825a0f634SChicago Duan #ifdef USB_CODE_UPDATE 56925a0f634SChicago Duan if (objPath == usbCodeUpdateObjectPath) 57025a0f634SChicago Duan { 57125a0f634SChicago Duan unitMaskedState = req; 57225a0f634SChicago Duan unitEnabledState = !unitMaskedState; 57325a0f634SChicago Duan unitRunningState = !unitMaskedState; 57425a0f634SChicago Duan internalSet = true; 57525a0f634SChicago Duan srvCfgIface->set_property(srvCfgPropEnabled, 57625a0f634SChicago Duan unitEnabledState); 57725a0f634SChicago Duan srvCfgIface->set_property(srvCfgPropRunning, 57825a0f634SChicago Duan unitRunningState); 57925a0f634SChicago Duan srvCfgIface->set_property(srvCfgPropMasked, 58025a0f634SChicago Duan unitMaskedState); 58125a0f634SChicago Duan internalSet = false; 58225a0f634SChicago Duan setUSBCodeUpdateState(unitEnabledState); 58325a0f634SChicago Duan saveUSBCodeUpdateStateToFile(unitMaskedState, 58425a0f634SChicago Duan unitEnabledState); 58525a0f634SChicago Duan return 1; 58625a0f634SChicago Duan } 58725a0f634SChicago Duan #endif 58890f2da3fSRichard Marian Thomaiyar if (req == res) 58990f2da3fSRichard Marian Thomaiyar { 59090f2da3fSRichard Marian Thomaiyar return 1; 59190f2da3fSRichard Marian Thomaiyar } 59290f2da3fSRichard Marian Thomaiyar if (updateInProgress) 59390f2da3fSRichard Marian Thomaiyar { 59490f2da3fSRichard Marian Thomaiyar return 0; 59590f2da3fSRichard Marian Thomaiyar } 59690f2da3fSRichard Marian Thomaiyar unitMaskedState = req; 59790f2da3fSRichard Marian Thomaiyar unitEnabledState = !unitMaskedState; 59890f2da3fSRichard Marian Thomaiyar unitRunningState = !unitMaskedState; 59990f2da3fSRichard Marian Thomaiyar updatedFlag |= 60090f2da3fSRichard Marian Thomaiyar (1 << static_cast<uint8_t>(UpdatedProp::maskedState)) | 60190f2da3fSRichard Marian Thomaiyar (1 << static_cast<uint8_t>(UpdatedProp::enabledState)) | 60290f2da3fSRichard Marian Thomaiyar (1 << static_cast<uint8_t>(UpdatedProp::runningState)); 60390f2da3fSRichard Marian Thomaiyar internalSet = true; 60483241c09STom Joseph srvCfgIface->set_property(srvCfgPropEnabled, unitEnabledState); 60583241c09STom Joseph srvCfgIface->set_property(srvCfgPropRunning, unitRunningState); 60690f2da3fSRichard Marian Thomaiyar internalSet = false; 60790f2da3fSRichard Marian Thomaiyar startServiceRestartTimer(); 60890f2da3fSRichard Marian Thomaiyar } 6090084047dSAppaRao Puli res = req; 6100084047dSAppaRao Puli return 1; 6110084047dSAppaRao Puli }); 6120084047dSAppaRao Puli 61383241c09STom Joseph srvCfgIface->register_property( 61490f2da3fSRichard Marian Thomaiyar srvCfgPropEnabled, unitEnabledState, 61590f2da3fSRichard Marian Thomaiyar [this](const bool& req, bool& res) { 61690f2da3fSRichard Marian Thomaiyar if (!internalSet) 61790f2da3fSRichard Marian Thomaiyar { 61825a0f634SChicago Duan #ifdef USB_CODE_UPDATE 61925a0f634SChicago Duan if (objPath == usbCodeUpdateObjectPath) 62025a0f634SChicago Duan { 62125a0f634SChicago Duan if (unitMaskedState) 62225a0f634SChicago Duan { // block updating if masked 623*f27f431fSJiaqing Zhao lg2::error("Invalid value specified"); 62425a0f634SChicago Duan return -EINVAL; 62525a0f634SChicago Duan } 62625a0f634SChicago Duan unitEnabledState = req; 62725a0f634SChicago Duan unitRunningState = req; 62825a0f634SChicago Duan internalSet = true; 62925a0f634SChicago Duan srvCfgIface->set_property(srvCfgPropEnabled, 63025a0f634SChicago Duan unitEnabledState); 63125a0f634SChicago Duan srvCfgIface->set_property(srvCfgPropRunning, 63225a0f634SChicago Duan unitRunningState); 63325a0f634SChicago Duan internalSet = false; 63425a0f634SChicago Duan setUSBCodeUpdateState(unitEnabledState); 63525a0f634SChicago Duan saveUSBCodeUpdateStateToFile(unitMaskedState, 63625a0f634SChicago Duan unitEnabledState); 63725a0f634SChicago Duan res = req; 63825a0f634SChicago Duan return 1; 63925a0f634SChicago Duan } 64025a0f634SChicago Duan #endif 6410084047dSAppaRao Puli if (req == res) 6420084047dSAppaRao Puli { 6430084047dSAppaRao Puli return 1; 6440084047dSAppaRao Puli } 64590f2da3fSRichard Marian Thomaiyar if (updateInProgress) 6460084047dSAppaRao Puli { 64790f2da3fSRichard Marian Thomaiyar return 0; 6480084047dSAppaRao Puli } 64990f2da3fSRichard Marian Thomaiyar if (unitMaskedState) 65090f2da3fSRichard Marian Thomaiyar { // block updating if masked 651cb267c8fSGeorge Liu lg2::error("Invalid value specified"); 6520084047dSAppaRao Puli return -EINVAL; 6530084047dSAppaRao Puli } 65490f2da3fSRichard Marian Thomaiyar unitEnabledState = req; 65590f2da3fSRichard Marian Thomaiyar updatedFlag |= 65690f2da3fSRichard Marian Thomaiyar (1 << static_cast<uint8_t>(UpdatedProp::enabledState)); 6570084047dSAppaRao Puli startServiceRestartTimer(); 65890f2da3fSRichard Marian Thomaiyar } 65990f2da3fSRichard Marian Thomaiyar res = req; 66090f2da3fSRichard Marian Thomaiyar return 1; 66190f2da3fSRichard Marian Thomaiyar }); 66290f2da3fSRichard Marian Thomaiyar 66383241c09STom Joseph srvCfgIface->register_property( 66490f2da3fSRichard Marian Thomaiyar srvCfgPropRunning, unitRunningState, 66590f2da3fSRichard Marian Thomaiyar [this](const bool& req, bool& res) { 66690f2da3fSRichard Marian Thomaiyar if (!internalSet) 66790f2da3fSRichard Marian Thomaiyar { 66825a0f634SChicago Duan #ifdef USB_CODE_UPDATE 66925a0f634SChicago Duan if (objPath == usbCodeUpdateObjectPath) 67025a0f634SChicago Duan { 67125a0f634SChicago Duan if (unitMaskedState) 67225a0f634SChicago Duan { // block updating if masked 673*f27f431fSJiaqing Zhao lg2::error("Invalid value specified"); 67425a0f634SChicago Duan return -EINVAL; 67525a0f634SChicago Duan } 67625a0f634SChicago Duan unitEnabledState = req; 67725a0f634SChicago Duan unitRunningState = req; 67825a0f634SChicago Duan internalSet = true; 67925a0f634SChicago Duan srvCfgIface->set_property(srvCfgPropEnabled, 68025a0f634SChicago Duan unitEnabledState); 68125a0f634SChicago Duan srvCfgIface->set_property(srvCfgPropRunning, 68225a0f634SChicago Duan unitRunningState); 68325a0f634SChicago Duan internalSet = false; 68425a0f634SChicago Duan setUSBCodeUpdateState(unitEnabledState); 68525a0f634SChicago Duan saveUSBCodeUpdateStateToFile(unitMaskedState, 68625a0f634SChicago Duan unitEnabledState); 68725a0f634SChicago Duan res = req; 68825a0f634SChicago Duan return 1; 68925a0f634SChicago Duan } 69025a0f634SChicago Duan #endif 69190f2da3fSRichard Marian Thomaiyar if (req == res) 69290f2da3fSRichard Marian Thomaiyar { 69390f2da3fSRichard Marian Thomaiyar return 1; 69490f2da3fSRichard Marian Thomaiyar } 69590f2da3fSRichard Marian Thomaiyar if (updateInProgress) 69690f2da3fSRichard Marian Thomaiyar { 69790f2da3fSRichard Marian Thomaiyar return 0; 69890f2da3fSRichard Marian Thomaiyar } 69990f2da3fSRichard Marian Thomaiyar if (unitMaskedState) 70090f2da3fSRichard Marian Thomaiyar { // block updating if masked 701cb267c8fSGeorge Liu lg2::error("Invalid value specified"); 70290f2da3fSRichard Marian Thomaiyar return -EINVAL; 70390f2da3fSRichard Marian Thomaiyar } 70490f2da3fSRichard Marian Thomaiyar unitRunningState = req; 70590f2da3fSRichard Marian Thomaiyar updatedFlag |= 70690f2da3fSRichard Marian Thomaiyar (1 << static_cast<uint8_t>(UpdatedProp::runningState)); 70790f2da3fSRichard Marian Thomaiyar startServiceRestartTimer(); 70890f2da3fSRichard Marian Thomaiyar } 7090084047dSAppaRao Puli res = req; 7100084047dSAppaRao Puli return 1; 7110084047dSAppaRao Puli }); 7120084047dSAppaRao Puli 71383241c09STom Joseph srvCfgIface->initialize(); 71483241c09STom Joseph if (!socketObjectPath.empty()) 71583241c09STom Joseph { 71683241c09STom Joseph sockAttrIface->initialize(); 71783241c09STom Joseph } 7180084047dSAppaRao Puli return; 7190084047dSAppaRao Puli } 7200084047dSAppaRao Puli 7210084047dSAppaRao Puli } // namespace service 7220084047dSAppaRao Puli } // namespace phosphor 723