blob: 78b42342c07fef3a9ac225ed4b67f90d04ca3b7a [file] [log] [blame]
George Liuf3b75142021-06-10 11:22:50 +08001#include "utils.hpp"
2
Chris Cain36f9cde2021-11-22 11:18:21 -06003#include <fmt/core.h>
Chris Cainbae4d072022-02-28 09:46:50 -06004#include <systemd/sd-event.h>
5#include <unistd.h>
Chris Cain36f9cde2021-11-22 11:18:21 -06006
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +05307#include <phosphor-logging/elog-errors.hpp>
Gunnar Mills94df8c92018-09-14 14:50:03 -05008#include <sdbusplus/bus.hpp>
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +05309#include <xyz/openbmc_project/Common/error.hpp>
Chris Cainbae4d072022-02-28 09:46:50 -060010#include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
11#include <xyz/openbmc_project/State/Host/server.hpp>
George Liub5ca1012021-09-10 12:53:11 +080012
13#include <string>
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +053014namespace open_power
15{
16namespace occ
17{
George Liuf3b75142021-06-10 11:22:50 +080018namespace utils
19{
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +053020// For throwing exceptions
21using namespace phosphor::logging;
Gunnar Mills94df8c92018-09-14 14:50:03 -050022using InternalFailure =
23 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +053024
Chris Cainbae4d072022-02-28 09:46:50 -060025using BootProgress = sdbusplus::xyz::openbmc_project::State::Boot::server::
26 Progress::ProgressStages;
27constexpr auto HOST_STATE_OBJ_PATH = "/xyz/openbmc_project/state/host0";
28
George Liuf3b75142021-06-10 11:22:50 +080029const std::string getService(const std::string& path,
30 const std::string& interface)
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +053031{
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +053032
George Liuf3b75142021-06-10 11:22:50 +080033 using InterfaceList = std::vector<std::string>;
34 std::map<std::string, std::vector<std::string>> mapperResponse;
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +053035
George Liuf3b75142021-06-10 11:22:50 +080036 auto& bus = getBus();
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +053037
George Liuf3b75142021-06-10 11:22:50 +080038 auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
39 MAPPER_IFACE, "GetObject");
40 mapper.append(path, InterfaceList({interface}));
41
42 auto mapperResponseMsg = bus.call(mapper);
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +053043 mapperResponseMsg.read(mapperResponse);
George Liuf3b75142021-06-10 11:22:50 +080044 if (mapperResponse.empty())
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +053045 {
46 log<level::ERR>("ERROR reading mapper response",
Gunnar Mills94df8c92018-09-14 14:50:03 -050047 entry("PATH=%s", path.c_str()),
George Liuf3b75142021-06-10 11:22:50 +080048 entry("INTERFACE=%s", interface.c_str()));
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +053049
50 elog<InternalFailure>();
51 }
George Liuf3b75142021-06-10 11:22:50 +080052
53 // the value here will be the service name
54 return mapperResponse.cbegin()->first;
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +053055}
56
George Liuf3b75142021-06-10 11:22:50 +080057const PropertyValue getProperty(const std::string& objectPath,
58 const std::string& interface,
59 const std::string& propertyName)
60{
61 PropertyValue value{};
62
63 auto& bus = getBus();
64 auto service = getService(objectPath, interface);
65 if (service.empty())
66 {
67 return value;
68 }
69
70 auto method = bus.new_method_call(service.c_str(), objectPath.c_str(),
71 DBUS_PROPERTY_IFACE, "Get");
72 method.append(interface, propertyName);
73
74 auto reply = bus.call(method);
75 reply.read(value);
76
77 return value;
78}
79
Chris Cain36f9cde2021-11-22 11:18:21 -060080/**
81 * @brief Sets a given object's property value
82 *
Chris Cain1be43372021-12-09 19:29:37 -060083 * @param[in] objectPath - Name of the object containing the property
Chris Cain36f9cde2021-11-22 11:18:21 -060084 * @param[in] interface - Interface name containing the property
Chris Cain1be43372021-12-09 19:29:37 -060085 * @param[in] propertyName - Property name
Chris Cain36f9cde2021-11-22 11:18:21 -060086 * @param[in] value - Property value
87 */
88void setProperty(const std::string& objectPath, const std::string& interface,
Chris Cain5d66a0a2022-02-09 08:52:10 -060089 const std::string& propertyName, PropertyValue&& value)
Chris Cain36f9cde2021-11-22 11:18:21 -060090{
91 using namespace std::literals::string_literals;
Chris Cain5d66a0a2022-02-09 08:52:10 -060092 PropertyValue varValue(std::forward<PropertyValue>(value));
Chris Cain36f9cde2021-11-22 11:18:21 -060093
Chris Cain1be43372021-12-09 19:29:37 -060094 try
Chris Cain36f9cde2021-11-22 11:18:21 -060095 {
Chris Cain1be43372021-12-09 19:29:37 -060096 auto& bus = getBus();
97 auto service = getService(objectPath, interface);
98 if (service.empty())
99 {
100 return;
101 }
102
103 auto method = bus.new_method_call(service.c_str(), objectPath.c_str(),
104 DBUS_PROPERTY_IFACE, "Set");
105 method.append(interface, propertyName, varValue);
106
107 auto reply = bus.call(method);
108 if (reply.is_method_error())
109 {
110 log<level::ERR>(
111 fmt::format("util::setProperty: Failed to set property {}",
112 propertyName)
113 .c_str());
114 }
Chris Cain36f9cde2021-11-22 11:18:21 -0600115 }
Chris Cain1be43372021-12-09 19:29:37 -0600116 catch (const std::exception& e)
Chris Cain36f9cde2021-11-22 11:18:21 -0600117 {
Chris Cain1be43372021-12-09 19:29:37 -0600118 auto error = errno;
Chris Cain36f9cde2021-11-22 11:18:21 -0600119 log<level::ERR>(
Chris Cain1be43372021-12-09 19:29:37 -0600120 fmt::format("setProperty: failed to Set {}, errno={}, what={}",
121 propertyName.c_str(), error, e.what())
Chris Cain36f9cde2021-11-22 11:18:21 -0600122 .c_str());
123 }
124}
125
Matt Spinler5901abd2021-09-23 13:50:03 -0500126std::vector<std::string>
127 getSubtreePaths(const std::vector<std::string>& interfaces,
128 const std::string& path)
129{
130 std::vector<std::string> paths;
131
132 auto& bus = getBus();
133 auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
134 MAPPER_IFACE, "GetSubTreePaths");
135 method.append(path, 0, interfaces);
136
137 auto reply = bus.call(method);
138 reply.read(paths);
139
140 return paths;
141}
Chris Cain1be43372021-12-09 19:29:37 -0600142
143// Get the service and object path for an interface
144std::string getServiceUsingSubTree(const std::string& interface,
145 std::string& path)
146{
147 using Path = std::string;
148 using Intf = std::string;
149 using Serv = std::string;
150 using Intfs = std::vector<Intf>;
151 using Objects = std::map<Path, std::map<Serv, Intfs>>;
152 Serv service;
153 Objects rspObjects;
154
155 auto& bus = getBus();
156 auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
157 MAPPER_IFACE, "GetSubTree");
158 method.append(path, 0, std::vector{interface});
159
160 auto mapperResponseMsg = bus.call(method);
161 mapperResponseMsg.read(rspObjects);
162 if (rspObjects.empty())
163 {
164 log<level::ERR>(
165 fmt::format(
166 "util::getServiceUsingSubTree: Failed getSubTree({},0,{})",
167 path.c_str(), interface)
168 .c_str());
169 }
170 else
171 {
172 path = rspObjects.begin()->first;
173 if (!rspObjects.begin()->second.empty())
174 {
175 service = rspObjects.begin()->second.begin()->first;
176 }
177 else
178 {
179 log<level::ERR>(
180 fmt::format(
181 "getServiceUsingSubTree: service not found for interface {} (path={})",
182 interface, path.c_str())
183 .c_str());
184 }
185 }
186
187 return service;
188}
189
Chris Cainbae4d072022-02-28 09:46:50 -0600190std::string getStateValue(const std::string& intf, const std::string& objPath,
191 const std::string& state)
192{
193 std::string stateVal;
194 try
195 {
196 auto& bus = getBus();
197 auto service = getService(objPath, intf);
198 if (service.empty())
199 {
200 throw std::runtime_error("getStateValue: Failed to get service");
201 }
202
203 auto method =
204 bus.new_method_call(service.c_str(), objPath.c_str(),
205 "org.freedesktop.DBus.Properties", "Get");
206
207 method.append(intf, state);
208
209 auto reply = bus.call(method);
210
211 std::variant<std::string> propertyVal;
212
213 reply.read(propertyVal);
214
215 stateVal = std::get<std::string>(propertyVal);
216 }
217 catch (const sdbusplus::exception::exception& e)
218 {
219 log<level::ERR>(fmt::format("D-Bus call exception, OBJPATH({}), "
220 "INTERFACE({}), PROPERTY({}) EXCEPTION({})",
221 objPath, intf, state, e.what())
222 .c_str());
223 throw std::runtime_error("Failed to get host state property");
224 }
225 catch (const std::bad_variant_access& e)
226 {
227 log<level::ERR>(
228 fmt::format("Exception raised while read host state({}) property "
229 "value, OBJPATH({}), INTERFACE({}), EXCEPTION({})",
230 state, objPath, intf, e.what())
231 .c_str());
232 throw std::runtime_error("Failed to get host state property");
233 }
234
235 return stateVal;
236}
237
238BootProgress getBootProgress()
239{
240 BootProgress bootProgessStage;
241 constexpr auto bootProgressInterface =
242 "xyz.openbmc_project.State.Boot.Progress";
243 std::string value = getStateValue(bootProgressInterface,
244 HOST_STATE_OBJ_PATH, "BootProgress");
245 bootProgessStage = sdbusplus::xyz::openbmc_project::State::Boot::server::
246 Progress::convertProgressStagesFromString(value);
247 return bootProgessStage;
248}
249
250bool isHostRunning()
251{
252 BootProgress bootProgressStatus = getBootProgress();
253 if ((bootProgressStatus == BootProgress::SystemInitComplete) ||
254 (bootProgressStatus == BootProgress::SystemSetup) ||
255 (bootProgressStatus == BootProgress::OSStart) ||
256 (bootProgressStatus == BootProgress::OSRunning))
257 {
258 return true;
259 }
260 return false;
261}
262
George Liuf3b75142021-06-10 11:22:50 +0800263} // namespace utils
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530264} // namespace occ
265} // namespace open_power