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