blob: 44abfa4a7ffa4f588622bc21e3b33e5f2d8ba8f7 [file] [log] [blame]
George Liuf3b75142021-06-10 11:22:50 +08001#include "utils.hpp"
2
Chris Cainbae4d072022-02-28 09:46:50 -06003#include <systemd/sd-event.h>
4#include <unistd.h>
Chris Cain36f9cde2021-11-22 11:18:21 -06005
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +05306#include <phosphor-logging/elog-errors.hpp>
Gunnar Mills94df8c92018-09-14 14:50:03 -05007#include <sdbusplus/bus.hpp>
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +05308#include <xyz/openbmc_project/Common/error.hpp>
Chris Cainbae4d072022-02-28 09:46:50 -06009#include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
10#include <xyz/openbmc_project/State/Host/server.hpp>
George Liub5ca1012021-09-10 12:53:11 +080011
Patrick Williams48002492024-02-13 21:43:32 -060012#include <format>
George Liub5ca1012021-09-10 12:53:11 +080013#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{
George Liuf3b75142021-06-10 11:22:50 +080032 using InterfaceList = std::vector<std::string>;
33 std::map<std::string, std::vector<std::string>> mapperResponse;
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +053034
George Liuf3b75142021-06-10 11:22:50 +080035 auto& bus = getBus();
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +053036
George Liuf3b75142021-06-10 11:22:50 +080037 auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
38 MAPPER_IFACE, "GetObject");
39 mapper.append(path, InterfaceList({interface}));
40
41 auto mapperResponseMsg = bus.call(mapper);
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +053042 mapperResponseMsg.read(mapperResponse);
George Liuf3b75142021-06-10 11:22:50 +080043 if (mapperResponse.empty())
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +053044 {
45 log<level::ERR>("ERROR reading mapper response",
Gunnar Mills94df8c92018-09-14 14:50:03 -050046 entry("PATH=%s", path.c_str()),
George Liuf3b75142021-06-10 11:22:50 +080047 entry("INTERFACE=%s", interface.c_str()));
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +053048
49 elog<InternalFailure>();
50 }
George Liuf3b75142021-06-10 11:22:50 +080051
52 // the value here will be the service name
53 return mapperResponse.cbegin()->first;
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +053054}
55
George Liuf3b75142021-06-10 11:22:50 +080056const PropertyValue getProperty(const std::string& objectPath,
57 const std::string& interface,
58 const std::string& propertyName)
59{
60 PropertyValue value{};
61
62 auto& bus = getBus();
63 auto service = getService(objectPath, interface);
64 if (service.empty())
65 {
66 return value;
67 }
68
69 auto method = bus.new_method_call(service.c_str(), objectPath.c_str(),
70 DBUS_PROPERTY_IFACE, "Get");
71 method.append(interface, propertyName);
72
73 auto reply = bus.call(method);
74 reply.read(value);
75
76 return value;
77}
78
Chris Cain36f9cde2021-11-22 11:18:21 -060079/**
80 * @brief Sets a given object's property value
81 *
Chris Cain1be43372021-12-09 19:29:37 -060082 * @param[in] objectPath - Name of the object containing the property
Chris Cain36f9cde2021-11-22 11:18:21 -060083 * @param[in] interface - Interface name containing the property
Chris Cain1be43372021-12-09 19:29:37 -060084 * @param[in] propertyName - Property name
Chris Cain36f9cde2021-11-22 11:18:21 -060085 * @param[in] value - Property value
86 */
87void setProperty(const std::string& objectPath, const std::string& interface,
Chris Cain5d66a0a2022-02-09 08:52:10 -060088 const std::string& propertyName, PropertyValue&& value)
Chris Cain36f9cde2021-11-22 11:18:21 -060089{
90 using namespace std::literals::string_literals;
Chris Cain5d66a0a2022-02-09 08:52:10 -060091 PropertyValue varValue(std::forward<PropertyValue>(value));
Chris Cain36f9cde2021-11-22 11:18:21 -060092
Chris Cain1be43372021-12-09 19:29:37 -060093 try
Chris Cain36f9cde2021-11-22 11:18:21 -060094 {
Chris Cain1be43372021-12-09 19:29:37 -060095 auto& bus = getBus();
96 auto service = getService(objectPath, interface);
97 if (service.empty())
98 {
99 return;
100 }
101
102 auto method = bus.new_method_call(service.c_str(), objectPath.c_str(),
103 DBUS_PROPERTY_IFACE, "Set");
104 method.append(interface, propertyName, varValue);
105
106 auto reply = bus.call(method);
107 if (reply.is_method_error())
108 {
109 log<level::ERR>(
Patrick Williams48002492024-02-13 21:43:32 -0600110 std::format("util::setProperty: Failed to set property {}",
Chris Cain1be43372021-12-09 19:29:37 -0600111 propertyName)
112 .c_str());
113 }
Chris Cain36f9cde2021-11-22 11:18:21 -0600114 }
Chris Cain1be43372021-12-09 19:29:37 -0600115 catch (const std::exception& e)
Chris Cain36f9cde2021-11-22 11:18:21 -0600116 {
Chris Cain1be43372021-12-09 19:29:37 -0600117 auto error = errno;
Chris Cain36f9cde2021-11-22 11:18:21 -0600118 log<level::ERR>(
Patrick Williams48002492024-02-13 21:43:32 -0600119 std::format("setProperty: failed to Set {}, errno={}, what={}",
Chris Cain1be43372021-12-09 19:29:37 -0600120 propertyName.c_str(), error, e.what())
Chris Cain36f9cde2021-11-22 11:18:21 -0600121 .c_str());
122 }
123}
124
Patrick Williamsd7542c82024-08-16 15:20:28 -0400125std::vector<std::string> getSubtreePaths(
126 const std::vector<std::string>& interfaces, const std::string& path)
Matt Spinler5901abd2021-09-23 13:50:03 -0500127{
128 std::vector<std::string> paths;
129
130 auto& bus = getBus();
131 auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
132 MAPPER_IFACE, "GetSubTreePaths");
133 method.append(path, 0, interfaces);
134
135 auto reply = bus.call(method);
136 reply.read(paths);
137
138 return paths;
139}
Chris Cain1be43372021-12-09 19:29:37 -0600140
141// Get the service and object path for an interface
142std::string getServiceUsingSubTree(const std::string& interface,
143 std::string& path)
144{
145 using Path = std::string;
146 using Intf = std::string;
147 using Serv = std::string;
148 using Intfs = std::vector<Intf>;
149 using Objects = std::map<Path, std::map<Serv, Intfs>>;
150 Serv service;
151 Objects rspObjects;
152
153 auto& bus = getBus();
154 auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
155 MAPPER_IFACE, "GetSubTree");
156 method.append(path, 0, std::vector{interface});
157
158 auto mapperResponseMsg = bus.call(method);
159 mapperResponseMsg.read(rspObjects);
160 if (rspObjects.empty())
161 {
162 log<level::ERR>(
Patrick Williams48002492024-02-13 21:43:32 -0600163 std::format(
Chris Cain1be43372021-12-09 19:29:37 -0600164 "util::getServiceUsingSubTree: Failed getSubTree({},0,{})",
165 path.c_str(), interface)
166 .c_str());
167 }
168 else
169 {
170 path = rspObjects.begin()->first;
171 if (!rspObjects.begin()->second.empty())
172 {
173 service = rspObjects.begin()->second.begin()->first;
174 }
175 else
176 {
177 log<level::ERR>(
Patrick Williams48002492024-02-13 21:43:32 -0600178 std::format(
Chris Cain1be43372021-12-09 19:29:37 -0600179 "getServiceUsingSubTree: service not found for interface {} (path={})",
180 interface, path.c_str())
181 .c_str());
182 }
183 }
184
185 return service;
186}
187
Chris Cainbae4d072022-02-28 09:46:50 -0600188std::string getStateValue(const std::string& intf, const std::string& objPath,
189 const std::string& state)
190{
191 std::string stateVal;
192 try
193 {
194 auto& bus = getBus();
195 auto service = getService(objPath, intf);
196 if (service.empty())
197 {
198 throw std::runtime_error("getStateValue: Failed to get service");
199 }
200
Patrick Williamsd7542c82024-08-16 15:20:28 -0400201 auto method =
202 bus.new_method_call(service.c_str(), objPath.c_str(),
203 "org.freedesktop.DBus.Properties", "Get");
Chris Cainbae4d072022-02-28 09:46:50 -0600204
205 method.append(intf, state);
206
207 auto reply = bus.call(method);
208
209 std::variant<std::string> propertyVal;
210
211 reply.read(propertyVal);
212
213 stateVal = std::get<std::string>(propertyVal);
214 }
Patrick Williamsaf408082022-07-22 19:26:54 -0500215 catch (const sdbusplus::exception_t& e)
Chris Cainbae4d072022-02-28 09:46:50 -0600216 {
Patrick Williams48002492024-02-13 21:43:32 -0600217 log<level::ERR>(std::format("D-Bus call exception, OBJPATH({}), "
Chris Cainbae4d072022-02-28 09:46:50 -0600218 "INTERFACE({}), PROPERTY({}) EXCEPTION({})",
219 objPath, intf, state, e.what())
220 .c_str());
221 throw std::runtime_error("Failed to get host state property");
222 }
223 catch (const std::bad_variant_access& e)
224 {
225 log<level::ERR>(
Patrick Williams48002492024-02-13 21:43:32 -0600226 std::format("Exception raised while read host state({}) property "
Chris Cainbae4d072022-02-28 09:46:50 -0600227 "value, OBJPATH({}), INTERFACE({}), EXCEPTION({})",
228 state, objPath, intf, e.what())
229 .c_str());
230 throw std::runtime_error("Failed to get host state property");
231 }
232
233 return stateVal;
234}
235
236BootProgress getBootProgress()
237{
238 BootProgress bootProgessStage;
239 constexpr auto bootProgressInterface =
240 "xyz.openbmc_project.State.Boot.Progress";
241 std::string value = getStateValue(bootProgressInterface,
242 HOST_STATE_OBJ_PATH, "BootProgress");
243 bootProgessStage = sdbusplus::xyz::openbmc_project::State::Boot::server::
244 Progress::convertProgressStagesFromString(value);
245 return bootProgessStage;
246}
247
248bool isHostRunning()
249{
250 BootProgress bootProgressStatus = getBootProgress();
251 if ((bootProgressStatus == BootProgress::SystemInitComplete) ||
252 (bootProgressStatus == BootProgress::SystemSetup) ||
253 (bootProgressStatus == BootProgress::OSStart) ||
254 (bootProgressStatus == BootProgress::OSRunning))
255 {
256 return true;
257 }
258 return false;
259}
260
George Liuf3b75142021-06-10 11:22:50 +0800261} // namespace utils
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530262} // namespace occ
263} // namespace open_power