1 /* 2 // Copyright (c) 2018 Intel Corporation 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 */ 16 #include "utils.hpp" 17 18 void checkAndThrowInternalFailure(boost::system::error_code& ec, 19 const std::string& msg) 20 { 21 if (ec) 22 { 23 std::string msgToLog = ec.message() + (msg.empty() ? "" : " - " + msg); 24 lg2::error("Check and throw internal failure: {MSG}", "MSG", msgToLog); 25 phosphor::logging::elog< 26 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>(); 27 } 28 return; 29 } 30 31 void systemdDaemonReload( 32 const std::shared_ptr<sdbusplus::asio::connection>& conn, 33 boost::asio::yield_context yield) 34 { 35 boost::system::error_code ec; 36 conn->yield_method_call<>(yield, ec, sysdService, sysdObjPath, sysdMgrIntf, 37 sysdReloadMethod); 38 checkAndThrowInternalFailure(ec, "daemon-reload operation failed"); 39 return; 40 } 41 42 static inline uint32_t getJobId(const std::string& path) 43 { 44 auto pos = path.rfind("/"); 45 if (pos == std::string::npos) 46 { 47 lg2::error("Unable to get job id from {PATH}.", "PATH", path); 48 phosphor::logging::elog< 49 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>(); 50 } 51 return static_cast<uint32_t>(std::stoul(path.substr(pos + 1))); 52 } 53 54 void systemdUnitAction(const std::shared_ptr<sdbusplus::asio::connection>& conn, 55 boost::asio::yield_context yield, 56 const std::string& unitName, 57 const std::string& actionMethod) 58 { 59 boost::system::error_code ec; 60 auto jobPath = conn->yield_method_call<sdbusplus::message::object_path>( 61 yield, ec, sysdService, sysdObjPath, sysdMgrIntf, actionMethod, 62 unitName, sysdReplaceMode); 63 checkAndThrowInternalFailure(ec, 64 "Systemd operation failed, " + actionMethod); 65 // Query the job till it doesn't exist anymore. 66 // this way we guarantee that queued job id is done. 67 // this is needed to make sure dependency list on units are 68 // properly handled. 69 while (true) 70 { 71 ec.clear(); 72 conn->yield_method_call<>(yield, ec, sysdService, sysdObjPath, 73 sysdMgrIntf, sysdGetJobMethod, 74 getJobId(jobPath.str)); 75 if (ec) 76 { 77 if (ec.value() == boost::system::errc::no_such_file_or_directory) 78 { 79 // Queued job is done, return now 80 return; 81 } 82 lg2::error("Systemd operation failed for job query: {EC}", "EC", 83 ec.value()); 84 phosphor::logging::elog<sdbusplus::xyz::openbmc_project::Common:: 85 Error::InternalFailure>(); 86 } 87 boost::asio::steady_timer sleepTimer(conn->get_io_context()); 88 sleepTimer.expires_after(std::chrono::milliseconds(20)); 89 ec.clear(); 90 sleepTimer.async_wait(yield[ec]); 91 checkAndThrowInternalFailure(ec, "Systemd operation timer error"); 92 } 93 return; 94 } 95 96 void systemdUnitFilesStateChange( 97 const std::shared_ptr<sdbusplus::asio::connection>& conn, 98 boost::asio::yield_context yield, const std::vector<std::string>& unitFiles, 99 const std::string& unitState, bool maskedState, bool enabledState) 100 { 101 boost::system::error_code ec; 102 103 if (unitState == stateMasked && !maskedState) 104 { 105 conn->yield_method_call<>(yield, ec, sysdService, sysdObjPath, 106 sysdMgrIntf, "UnmaskUnitFiles", unitFiles, 107 false); 108 checkAndThrowInternalFailure(ec, "Systemd UnmaskUnitFiles() failed."); 109 } 110 else if (unitState != stateMasked && maskedState) 111 { 112 conn->yield_method_call<>(yield, ec, sysdService, sysdObjPath, 113 sysdMgrIntf, "MaskUnitFiles", unitFiles, 114 false, false); 115 checkAndThrowInternalFailure(ec, "Systemd MaskUnitFiles() failed."); 116 } 117 ec.clear(); 118 if (unitState != stateEnabled && enabledState) 119 { 120 conn->yield_method_call<>(yield, ec, sysdService, sysdObjPath, 121 sysdMgrIntf, "EnableUnitFiles", unitFiles, 122 false, false); 123 checkAndThrowInternalFailure(ec, "Systemd EnableUnitFiles() failed."); 124 } 125 else if (unitState != stateDisabled && !enabledState) 126 { 127 conn->yield_method_call<>(yield, ec, sysdService, sysdObjPath, 128 sysdMgrIntf, "DisableUnitFiles", unitFiles, 129 false); 130 checkAndThrowInternalFailure(ec, "Systemd DisableUnitFiles() failed."); 131 } 132 return; 133 } 134