blob: 4025f94ad79062c13caa1eeb89f7c6439c025b7a [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>
Chris Cain37abe9b2024-10-31 17:20:31 -05007#include <phosphor-logging/lg2.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{
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 {
Chris Cain37abe9b2024-10-31 17:20:31 -050045 lg2::error("ERROR reading mapper response: path={PATH}, I/F={INTF}",
46 "PATH", path, "INTF", interface);
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +053047
48 elog<InternalFailure>();
49 }
George Liuf3b75142021-06-10 11:22:50 +080050
51 // the value here will be the service name
52 return mapperResponse.cbegin()->first;
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +053053}
54
George Liuf3b75142021-06-10 11:22:50 +080055const PropertyValue getProperty(const std::string& objectPath,
56 const std::string& interface,
57 const std::string& propertyName)
58{
59 PropertyValue value{};
60
61 auto& bus = getBus();
62 auto service = getService(objectPath, interface);
63 if (service.empty())
64 {
65 return value;
66 }
67
68 auto method = bus.new_method_call(service.c_str(), objectPath.c_str(),
69 DBUS_PROPERTY_IFACE, "Get");
70 method.append(interface, propertyName);
71
72 auto reply = bus.call(method);
73 reply.read(value);
74
75 return value;
76}
77
Chris Cain36f9cde2021-11-22 11:18:21 -060078/**
79 * @brief Sets a given object's property value
80 *
Chris Cain1be43372021-12-09 19:29:37 -060081 * @param[in] objectPath - Name of the object containing the property
Chris Cain36f9cde2021-11-22 11:18:21 -060082 * @param[in] interface - Interface name containing the property
Chris Cain1be43372021-12-09 19:29:37 -060083 * @param[in] propertyName - Property name
Chris Cain36f9cde2021-11-22 11:18:21 -060084 * @param[in] value - Property value
85 */
86void setProperty(const std::string& objectPath, const std::string& interface,
Chris Cain5d66a0a2022-02-09 08:52:10 -060087 const std::string& propertyName, PropertyValue&& value)
Chris Cain36f9cde2021-11-22 11:18:21 -060088{
89 using namespace std::literals::string_literals;
Chris Cain5d66a0a2022-02-09 08:52:10 -060090 PropertyValue varValue(std::forward<PropertyValue>(value));
Chris Cain36f9cde2021-11-22 11:18:21 -060091
Chris Cain1be43372021-12-09 19:29:37 -060092 try
Chris Cain36f9cde2021-11-22 11:18:21 -060093 {
Chris Cain1be43372021-12-09 19:29:37 -060094 auto& bus = getBus();
95 auto service = getService(objectPath, interface);
96 if (service.empty())
97 {
98 return;
99 }
100
101 auto method = bus.new_method_call(service.c_str(), objectPath.c_str(),
102 DBUS_PROPERTY_IFACE, "Set");
103 method.append(interface, propertyName, varValue);
104
Patrick Williamscbeaa782025-11-04 22:20:51 -0500105 bus.call(method);
Chris Cain36f9cde2021-11-22 11:18:21 -0600106 }
Chris Cain1be43372021-12-09 19:29:37 -0600107 catch (const std::exception& e)
Chris Cain36f9cde2021-11-22 11:18:21 -0600108 {
Chris Cain1be43372021-12-09 19:29:37 -0600109 auto error = errno;
Chris Cain37abe9b2024-10-31 17:20:31 -0500110 lg2::error("setProperty: failed to Set {PROP}, errno={ERR}, what={MSG}",
Patrick Williamscbeaa782025-11-04 22:20:51 -0500111 "PROP", propertyName, "ERR", error, "MSG", e);
Chris Cain36f9cde2021-11-22 11:18:21 -0600112 }
113}
114
Patrick Williamsd7542c82024-08-16 15:20:28 -0400115std::vector<std::string> getSubtreePaths(
116 const std::vector<std::string>& interfaces, const std::string& path)
Matt Spinler5901abd2021-09-23 13:50:03 -0500117{
118 std::vector<std::string> paths;
119
120 auto& bus = getBus();
121 auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
122 MAPPER_IFACE, "GetSubTreePaths");
123 method.append(path, 0, interfaces);
124
125 auto reply = bus.call(method);
126 reply.read(paths);
127
128 return paths;
129}
Chris Cain1be43372021-12-09 19:29:37 -0600130
131// Get the service and object path for an interface
132std::string getServiceUsingSubTree(const std::string& interface,
133 std::string& path)
134{
135 using Path = std::string;
136 using Intf = std::string;
137 using Serv = std::string;
138 using Intfs = std::vector<Intf>;
139 using Objects = std::map<Path, std::map<Serv, Intfs>>;
140 Serv service;
141 Objects rspObjects;
142
143 auto& bus = getBus();
144 auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
145 MAPPER_IFACE, "GetSubTree");
146 method.append(path, 0, std::vector{interface});
147
148 auto mapperResponseMsg = bus.call(method);
149 mapperResponseMsg.read(rspObjects);
150 if (rspObjects.empty())
151 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500152 lg2::error(
153 "util::getServiceUsingSubTree: Failed getSubTree({PATH},0,{INTF})",
154 "PATH", path, "INTF", interface);
Chris Cain1be43372021-12-09 19:29:37 -0600155 }
156 else
157 {
158 path = rspObjects.begin()->first;
159 if (!rspObjects.begin()->second.empty())
160 {
161 service = rspObjects.begin()->second.begin()->first;
162 }
163 else
164 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500165 lg2::error(
166 "getServiceUsingSubTree: service not found for interface {INTF} (path={PATH})",
167 "INTF", interface, "PATH", path);
Chris Cain1be43372021-12-09 19:29:37 -0600168 }
169 }
170
171 return service;
172}
173
Chris Cainbae4d072022-02-28 09:46:50 -0600174std::string getStateValue(const std::string& intf, const std::string& objPath,
175 const std::string& state)
176{
177 std::string stateVal;
178 try
179 {
180 auto& bus = getBus();
181 auto service = getService(objPath, intf);
182 if (service.empty())
183 {
184 throw std::runtime_error("getStateValue: Failed to get service");
185 }
186
Patrick Williamsd7542c82024-08-16 15:20:28 -0400187 auto method =
188 bus.new_method_call(service.c_str(), objPath.c_str(),
189 "org.freedesktop.DBus.Properties", "Get");
Chris Cainbae4d072022-02-28 09:46:50 -0600190
191 method.append(intf, state);
192
193 auto reply = bus.call(method);
194
195 std::variant<std::string> propertyVal;
196
197 reply.read(propertyVal);
198
199 stateVal = std::get<std::string>(propertyVal);
200 }
Patrick Williamsaf408082022-07-22 19:26:54 -0500201 catch (const sdbusplus::exception_t& e)
Chris Cainbae4d072022-02-28 09:46:50 -0600202 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500203 lg2::error("D-Bus call exception, OBJPATH({PATH}), "
204 "INTERFACE({INTF}), PROPERTY({PROP}) EXCEPTION({ERR})",
205 "PATH", objPath, "INTF", intf, "PROP", state, "ERR",
206 e.what());
Chris Cainbae4d072022-02-28 09:46:50 -0600207 throw std::runtime_error("Failed to get host state property");
208 }
209 catch (const std::bad_variant_access& e)
210 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500211 lg2::error(
212 "Exception raised while read host state({STATE}) property "
213 "value, OBJPATH({PATH}), INTERFACE({INTF}), EXCEPTION({ERR})",
214 "STATE", state, "PATH", objPath, "INTF", intf, "ERR", e.what());
Chris Cainbae4d072022-02-28 09:46:50 -0600215 throw std::runtime_error("Failed to get host state property");
216 }
217
218 return stateVal;
219}
220
221BootProgress getBootProgress()
222{
223 BootProgress bootProgessStage;
224 constexpr auto bootProgressInterface =
225 "xyz.openbmc_project.State.Boot.Progress";
226 std::string value = getStateValue(bootProgressInterface,
227 HOST_STATE_OBJ_PATH, "BootProgress");
228 bootProgessStage = sdbusplus::xyz::openbmc_project::State::Boot::server::
229 Progress::convertProgressStagesFromString(value);
230 return bootProgessStage;
231}
232
233bool isHostRunning()
234{
235 BootProgress bootProgressStatus = getBootProgress();
236 if ((bootProgressStatus == BootProgress::SystemInitComplete) ||
237 (bootProgressStatus == BootProgress::SystemSetup) ||
Chris Cainbae4d072022-02-28 09:46:50 -0600238 (bootProgressStatus == BootProgress::OSRunning))
239 {
240 return true;
241 }
242 return false;
243}
244
Chris Cainffb63212025-08-01 14:39:38 -0500245// Convert vector to hex dump string
246std::vector<std::string> hex_dump(const std::vector<std::uint8_t>& data,
247 const unsigned int data_len)
248{
249 unsigned int dump_length = data.size();
250 if ((data_len > 0) && (data_len < dump_length))
251 {
252 dump_length = data_len;
253 }
254 std::vector<std::string> dumpString;
255 std::string s;
256 for (uint32_t i = 0; i < dump_length; i++)
257 {
258 if (i % 16 == 0)
259 {
260 s += std::format("{:04X}: ", i);
261 }
262 else if (i % 4 == 0)
263 {
264 s += " ";
265 }
266
267 s += std::format("{:02X}", data.at(i));
268
269 if ((i % 16 == 15) || (i == (dump_length - 1)))
270 {
271 dumpString.push_back(s);
272 s.clear();
273 }
274 }
275 return dumpString;
276}
277
George Liuf3b75142021-06-10 11:22:50 +0800278} // namespace utils
Vishwanatha Subbanna30e329a2017-07-24 23:13:14 +0530279} // namespace occ
280} // namespace open_power