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 auto reply = bus.call(method);
106 if (reply.is_method_error())
107 {
108 lg2::error("util::setProperty: Failed to set property {PROP}",
109 "PROP", propertyName);
110 }
111 }
112 catch (const std::exception& e)
113 {
114 auto error = errno;
115 lg2::error("setProperty: failed to Set {PROP}, errno={ERR}, what={MSG}",
116 "PROP", propertyName, "ERR", error, "PROP", e.what());
117 }
118 }
119
getSubtreePaths(const std::vector<std::string> & interfaces,const std::string & path)120 std::vector<std::string> getSubtreePaths(
121 const std::vector<std::string>& interfaces, const std::string& path)
122 {
123 std::vector<std::string> paths;
124
125 auto& bus = getBus();
126 auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
127 MAPPER_IFACE, "GetSubTreePaths");
128 method.append(path, 0, interfaces);
129
130 auto reply = bus.call(method);
131 reply.read(paths);
132
133 return paths;
134 }
135
136 // Get the service and object path for an interface
getServiceUsingSubTree(const std::string & interface,std::string & path)137 std::string getServiceUsingSubTree(const std::string& interface,
138 std::string& path)
139 {
140 using Path = std::string;
141 using Intf = std::string;
142 using Serv = std::string;
143 using Intfs = std::vector<Intf>;
144 using Objects = std::map<Path, std::map<Serv, Intfs>>;
145 Serv service;
146 Objects rspObjects;
147
148 auto& bus = getBus();
149 auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
150 MAPPER_IFACE, "GetSubTree");
151 method.append(path, 0, std::vector{interface});
152
153 auto mapperResponseMsg = bus.call(method);
154 mapperResponseMsg.read(rspObjects);
155 if (rspObjects.empty())
156 {
157 lg2::error(
158 "util::getServiceUsingSubTree: Failed getSubTree({PATH},0,{INTF})",
159 "PATH", path, "INTF", interface);
160 }
161 else
162 {
163 path = rspObjects.begin()->first;
164 if (!rspObjects.begin()->second.empty())
165 {
166 service = rspObjects.begin()->second.begin()->first;
167 }
168 else
169 {
170 lg2::error(
171 "getServiceUsingSubTree: service not found for interface {INTF} (path={PATH})",
172 "INTF", interface, "PATH", path);
173 }
174 }
175
176 return service;
177 }
178
getStateValue(const std::string & intf,const std::string & objPath,const std::string & state)179 std::string getStateValue(const std::string& intf, const std::string& objPath,
180 const std::string& state)
181 {
182 std::string stateVal;
183 try
184 {
185 auto& bus = getBus();
186 auto service = getService(objPath, intf);
187 if (service.empty())
188 {
189 throw std::runtime_error("getStateValue: Failed to get service");
190 }
191
192 auto method =
193 bus.new_method_call(service.c_str(), objPath.c_str(),
194 "org.freedesktop.DBus.Properties", "Get");
195
196 method.append(intf, state);
197
198 auto reply = bus.call(method);
199
200 std::variant<std::string> propertyVal;
201
202 reply.read(propertyVal);
203
204 stateVal = std::get<std::string>(propertyVal);
205 }
206 catch (const sdbusplus::exception_t& e)
207 {
208 lg2::error("D-Bus call exception, OBJPATH({PATH}), "
209 "INTERFACE({INTF}), PROPERTY({PROP}) EXCEPTION({ERR})",
210 "PATH", objPath, "INTF", intf, "PROP", state, "ERR",
211 e.what());
212 throw std::runtime_error("Failed to get host state property");
213 }
214 catch (const std::bad_variant_access& e)
215 {
216 lg2::error(
217 "Exception raised while read host state({STATE}) property "
218 "value, OBJPATH({PATH}), INTERFACE({INTF}), EXCEPTION({ERR})",
219 "STATE", state, "PATH", objPath, "INTF", intf, "ERR", e.what());
220 throw std::runtime_error("Failed to get host state property");
221 }
222
223 return stateVal;
224 }
225
getBootProgress()226 BootProgress getBootProgress()
227 {
228 BootProgress bootProgessStage;
229 constexpr auto bootProgressInterface =
230 "xyz.openbmc_project.State.Boot.Progress";
231 std::string value = getStateValue(bootProgressInterface,
232 HOST_STATE_OBJ_PATH, "BootProgress");
233 bootProgessStage = sdbusplus::xyz::openbmc_project::State::Boot::server::
234 Progress::convertProgressStagesFromString(value);
235 return bootProgessStage;
236 }
237
isHostRunning()238 bool isHostRunning()
239 {
240 BootProgress bootProgressStatus = getBootProgress();
241 if ((bootProgressStatus == BootProgress::SystemInitComplete) ||
242 (bootProgressStatus == BootProgress::SystemSetup) ||
243 (bootProgressStatus == BootProgress::OSRunning))
244 {
245 return true;
246 }
247 return false;
248 }
249
250 } // namespace utils
251 } // namespace occ
252 } // namespace open_power
253