xref: /openbmc/openpower-occ-control/utils.cpp (revision 764d3599a7f72177cc1e63f2685d3e1a21fcf005)
1 #include "utils.hpp"
2 
3 #include <systemd/sd-event.h>
4 #include <unistd.h>
5 
6 #include <phosphor-logging/elog-errors.hpp>
7 #include <phosphor-logging/lg2.hpp>
8 #include <sdbusplus/bus.hpp>
9 #include <xyz/openbmc_project/Common/error.hpp>
10 #include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
11 #include <xyz/openbmc_project/State/Host/server.hpp>
12 
13 #include <string>
14 namespace open_power
15 {
16 namespace occ
17 {
18 namespace utils
19 {
20 // For throwing exceptions
21 using namespace phosphor::logging;
22 using InternalFailure =
23     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
24 
25 using BootProgress = sdbusplus::xyz::openbmc_project::State::Boot::server::
26     Progress::ProgressStages;
27 constexpr auto HOST_STATE_OBJ_PATH = "/xyz/openbmc_project/state/host0";
28 
getService(const std::string & path,const std::string & interface)29 const std::string getService(const std::string& path,
30                              const std::string& interface)
31 {
32     using InterfaceList = std::vector<std::string>;
33     std::map<std::string, std::vector<std::string>> mapperResponse;
34 
35     auto& bus = getBus();
36 
37     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);
42     mapperResponseMsg.read(mapperResponse);
43     if (mapperResponse.empty())
44     {
45         lg2::error("ERROR reading mapper response: path={PATH}, I/F={INTF}",
46                    "PATH", path, "INTF", interface);
47 
48         elog<InternalFailure>();
49     }
50 
51     // the value here will be the service name
52     return mapperResponse.cbegin()->first;
53 }
54 
getProperty(const std::string & objectPath,const std::string & interface,const std::string & propertyName)55 const 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 
78 /**
79  * @brief Sets a given object's property value
80  *
81  * @param[in] objectPath - Name of the object containing the property
82  * @param[in] interface - Interface name containing the property
83  * @param[in] propertyName - Property name
84  * @param[in] value - Property value
85  */
setProperty(const std::string & objectPath,const std::string & interface,const std::string & propertyName,PropertyValue && value)86 void setProperty(const std::string& objectPath, const std::string& interface,
87                  const std::string& propertyName, PropertyValue&& value)
88 {
89     using namespace std::literals::string_literals;
90     PropertyValue varValue(std::forward<PropertyValue>(value));
91 
92     try
93     {
94         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 
105         bus.call(method);
106     }
107     catch (const std::exception& e)
108     {
109         auto error = errno;
110         lg2::error("setProperty: failed to Set {PROP}, errno={ERR}, what={MSG}",
111                    "PROP", propertyName, "ERR", error, "MSG", e);
112     }
113 }
114 
getSubtreePaths(const std::vector<std::string> & interfaces,const std::string & path)115 std::vector<std::string> getSubtreePaths(
116     const std::vector<std::string>& interfaces, const std::string& path)
117 {
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 }
130 
131 // Get the service and object path for an interface
getServiceUsingSubTree(const std::string & interface,std::string & path)132 std::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     {
152         lg2::error(
153             "util::getServiceUsingSubTree: Failed getSubTree({PATH},0,{INTF})",
154             "PATH", path, "INTF", interface);
155     }
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         {
165             lg2::error(
166                 "getServiceUsingSubTree: service not found for interface {INTF} (path={PATH})",
167                 "INTF", interface, "PATH", path);
168         }
169     }
170 
171     return service;
172 }
173 
getStateValue(const std::string & intf,const std::string & objPath,const std::string & state)174 std::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 
187         auto method =
188             bus.new_method_call(service.c_str(), objPath.c_str(),
189                                 "org.freedesktop.DBus.Properties", "Get");
190 
191         method.append(intf, state);
192 
193         auto reply = bus.call(method);
194 
195         auto propertyVal = reply.unpack<std::variant<std::string>>();
196 
197         stateVal = std::get<std::string>(propertyVal);
198     }
199     catch (const sdbusplus::exception_t& e)
200     {
201         lg2::error("D-Bus call exception, OBJPATH({PATH}), "
202                    "INTERFACE({INTF}), PROPERTY({PROP}) EXCEPTION({ERR})",
203                    "PATH", objPath, "INTF", intf, "PROP", state, "ERR",
204                    e.what());
205         throw std::runtime_error("Failed to get host state property");
206     }
207     catch (const std::bad_variant_access& e)
208     {
209         lg2::error(
210             "Exception raised while read host state({STATE}) property "
211             "value,  OBJPATH({PATH}), INTERFACE({INTF}), EXCEPTION({ERR})",
212             "STATE", state, "PATH", objPath, "INTF", intf, "ERR", e.what());
213         throw std::runtime_error("Failed to get host state property");
214     }
215 
216     return stateVal;
217 }
218 
getBootProgress()219 BootProgress getBootProgress()
220 {
221     BootProgress bootProgessStage;
222     constexpr auto bootProgressInterface =
223         "xyz.openbmc_project.State.Boot.Progress";
224     std::string value = getStateValue(bootProgressInterface,
225                                       HOST_STATE_OBJ_PATH, "BootProgress");
226     bootProgessStage = sdbusplus::xyz::openbmc_project::State::Boot::server::
227         Progress::convertProgressStagesFromString(value);
228     return bootProgessStage;
229 }
230 
isHostRunning()231 bool isHostRunning()
232 {
233     BootProgress bootProgressStatus = getBootProgress();
234     if ((bootProgressStatus == BootProgress::SystemInitComplete) ||
235         (bootProgressStatus == BootProgress::SystemSetup) ||
236         (bootProgressStatus == BootProgress::OSRunning))
237     {
238         return true;
239     }
240     return false;
241 }
242 
243 // Convert vector to hex dump string
hex_dump(const std::vector<std::uint8_t> & data,const unsigned int data_len)244 std::vector<std::string> hex_dump(const std::vector<std::uint8_t>& data,
245                                   const unsigned int data_len)
246 {
247     unsigned int dump_length = data.size();
248     if ((data_len > 0) && (data_len < dump_length))
249     {
250         dump_length = data_len;
251     }
252     std::vector<std::string> dumpString;
253     std::string s;
254     for (uint32_t i = 0; i < dump_length; i++)
255     {
256         if (i % 16 == 0)
257         {
258             s += std::format("{:04X}: ", i);
259         }
260         else if (i % 4 == 0)
261         {
262             s += " ";
263         }
264 
265         s += std::format("{:02X}", data.at(i));
266 
267         if ((i % 16 == 15) || (i == (dump_length - 1)))
268         {
269             dumpString.push_back(s);
270             s.clear();
271         }
272     }
273     return dumpString;
274 }
275 
276 } // namespace utils
277 } // namespace occ
278 } // namespace open_power
279