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