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 <sdbusplus/bus.hpp>
8 #include <xyz/openbmc_project/Common/error.hpp>
9 #include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
10 #include <xyz/openbmc_project/State/Host/server.hpp>
11
12 #include <format>
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 log<level::ERR>("ERROR reading mapper response",
46 entry("PATH=%s", path.c_str()),
47 entry("INTERFACE=%s", interface.c_str()));
48
49 elog<InternalFailure>();
50 }
51
52 // the value here will be the service name
53 return mapperResponse.cbegin()->first;
54 }
55
getProperty(const std::string & objectPath,const std::string & interface,const std::string & propertyName)56 const 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
79 /**
80 * @brief Sets a given object's property value
81 *
82 * @param[in] objectPath - Name of the object containing the property
83 * @param[in] interface - Interface name containing the property
84 * @param[in] propertyName - Property name
85 * @param[in] value - Property value
86 */
setProperty(const std::string & objectPath,const std::string & interface,const std::string & propertyName,PropertyValue && value)87 void setProperty(const std::string& objectPath, const std::string& interface,
88 const std::string& propertyName, PropertyValue&& value)
89 {
90 using namespace std::literals::string_literals;
91 PropertyValue varValue(std::forward<PropertyValue>(value));
92
93 try
94 {
95 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>(
110 std::format("util::setProperty: Failed to set property {}",
111 propertyName)
112 .c_str());
113 }
114 }
115 catch (const std::exception& e)
116 {
117 auto error = errno;
118 log<level::ERR>(
119 std::format("setProperty: failed to Set {}, errno={}, what={}",
120 propertyName.c_str(), error, e.what())
121 .c_str());
122 }
123 }
124
125 std::vector<std::string>
getSubtreePaths(const std::vector<std::string> & interfaces,const std::string & path)126 getSubtreePaths(const std::vector<std::string>& interfaces,
127 const std::string& path)
128 {
129 std::vector<std::string> paths;
130
131 auto& bus = getBus();
132 auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
133 MAPPER_IFACE, "GetSubTreePaths");
134 method.append(path, 0, interfaces);
135
136 auto reply = bus.call(method);
137 reply.read(paths);
138
139 return paths;
140 }
141
142 // Get the service and object path for an interface
getServiceUsingSubTree(const std::string & interface,std::string & path)143 std::string getServiceUsingSubTree(const std::string& interface,
144 std::string& path)
145 {
146 using Path = std::string;
147 using Intf = std::string;
148 using Serv = std::string;
149 using Intfs = std::vector<Intf>;
150 using Objects = std::map<Path, std::map<Serv, Intfs>>;
151 Serv service;
152 Objects rspObjects;
153
154 auto& bus = getBus();
155 auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
156 MAPPER_IFACE, "GetSubTree");
157 method.append(path, 0, std::vector{interface});
158
159 auto mapperResponseMsg = bus.call(method);
160 mapperResponseMsg.read(rspObjects);
161 if (rspObjects.empty())
162 {
163 log<level::ERR>(
164 std::format(
165 "util::getServiceUsingSubTree: Failed getSubTree({},0,{})",
166 path.c_str(), interface)
167 .c_str());
168 }
169 else
170 {
171 path = rspObjects.begin()->first;
172 if (!rspObjects.begin()->second.empty())
173 {
174 service = rspObjects.begin()->second.begin()->first;
175 }
176 else
177 {
178 log<level::ERR>(
179 std::format(
180 "getServiceUsingSubTree: service not found for interface {} (path={})",
181 interface, path.c_str())
182 .c_str());
183 }
184 }
185
186 return service;
187 }
188
getStateValue(const std::string & intf,const std::string & objPath,const std::string & state)189 std::string getStateValue(const std::string& intf, const std::string& objPath,
190 const std::string& state)
191 {
192 std::string stateVal;
193 try
194 {
195 auto& bus = getBus();
196 auto service = getService(objPath, intf);
197 if (service.empty())
198 {
199 throw std::runtime_error("getStateValue: Failed to get service");
200 }
201
202 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
203 "org.freedesktop.DBus.Properties",
204 "Get");
205
206 method.append(intf, state);
207
208 auto reply = bus.call(method);
209
210 std::variant<std::string> propertyVal;
211
212 reply.read(propertyVal);
213
214 stateVal = std::get<std::string>(propertyVal);
215 }
216 catch (const sdbusplus::exception_t& e)
217 {
218 log<level::ERR>(std::format("D-Bus call exception, OBJPATH({}), "
219 "INTERFACE({}), PROPERTY({}) EXCEPTION({})",
220 objPath, intf, state, e.what())
221 .c_str());
222 throw std::runtime_error("Failed to get host state property");
223 }
224 catch (const std::bad_variant_access& e)
225 {
226 log<level::ERR>(
227 std::format("Exception raised while read host state({}) property "
228 "value, OBJPATH({}), INTERFACE({}), EXCEPTION({})",
229 state, objPath, intf, e.what())
230 .c_str());
231 throw std::runtime_error("Failed to get host state property");
232 }
233
234 return stateVal;
235 }
236
getBootProgress()237 BootProgress getBootProgress()
238 {
239 BootProgress bootProgessStage;
240 constexpr auto bootProgressInterface =
241 "xyz.openbmc_project.State.Boot.Progress";
242 std::string value = getStateValue(bootProgressInterface,
243 HOST_STATE_OBJ_PATH, "BootProgress");
244 bootProgessStage = sdbusplus::xyz::openbmc_project::State::Boot::server::
245 Progress::convertProgressStagesFromString(value);
246 return bootProgessStage;
247 }
248
isHostRunning()249 bool isHostRunning()
250 {
251 BootProgress bootProgressStatus = getBootProgress();
252 if ((bootProgressStatus == BootProgress::SystemInitComplete) ||
253 (bootProgressStatus == BootProgress::SystemSetup) ||
254 (bootProgressStatus == BootProgress::OSStart) ||
255 (bootProgressStatus == BootProgress::OSRunning))
256 {
257 return true;
258 }
259 return false;
260 }
261
262 } // namespace utils
263 } // namespace occ
264 } // namespace open_power
265