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
checkAndThrowInternalFailure(boost::system::error_code & ec,const std::string & msg)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
systemdDaemonReload(const std::shared_ptr<sdbusplus::asio::connection> & conn,boost::asio::yield_context yield)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
getJobId(const std::string & path)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
systemdUnitAction(const std::shared_ptr<sdbusplus::asio::connection> & conn,boost::asio::yield_context yield,const std::string & unitName,const std::string & actionMethod)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
systemdUnitFilesStateChange(const std::shared_ptr<sdbusplus::asio::connection> & conn,boost::asio::yield_context yield,const std::vector<std::string> & unitFiles,const std::string & unitState,bool maskedState,bool enabledState)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