xref: /openbmc/openpower-hw-diags/util/dbus.cpp (revision fe2c50d7)
1 #include <util/dbus.hpp>
2 #include <util/trace.hpp>
3 #include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
4 
5 namespace util
6 {
7 
8 namespace dbus
9 {
10 
11 //------------------------------------------------------------------------------
12 
13 constexpr auto objectMapperService   = "xyz.openbmc_project.ObjectMapper";
14 constexpr auto objectMapperPath      = "/xyz/openbmc_project/object_mapper";
15 constexpr auto objectMapperInterface = "xyz.openbmc_project.ObjectMapper";
16 
17 /** @brief Find the path and service that implements the given interface */
18 int find(const std::string& i_interface, std::string& o_path,
19          std::string& o_service)
20 {
21     int rc = 1; // assume not success
22 
23     auto bus = sdbusplus::bus::new_default();
24 
25     try
26     {
27         constexpr auto function = "GetSubTree";
28 
29         auto method = bus.new_method_call(objectMapperService, objectMapperPath,
30                                           objectMapperInterface, function);
31 
32         // Search the entire dbus tree for the specified interface
33         method.append(std::string{"/"}, 0,
34                       std::vector<std::string>{i_interface});
35 
36         auto reply = bus.call(method);
37 
38         DBusSubTree response;
39         reply.read(response);
40 
41         if (!response.empty())
42         {
43             // Response is a map of object paths to a map of service, interfaces
44             auto object = *(response.begin());
45             o_path      = object.first;                 // return path
46             o_service   = object.second.begin()->first; // return service
47 
48             rc = 0; // success
49         }
50     }
51     catch (const sdbusplus::exception::SdBusError& e)
52     {
53         trace::err("util::dbus::find exception");
54         std::string traceMsg = std::string(e.what());
55         trace::err(traceMsg.c_str());
56     }
57 
58     return rc;
59 }
60 
61 /** @brief Find the service that implements the given object and interface */
62 int findService(const std::string& i_interface, const std::string& i_path,
63                 std::string& o_service)
64 {
65     int rc = 1; // assume not success
66 
67     auto bus = sdbusplus::bus::new_default();
68 
69     try
70     {
71         constexpr auto function = "GetObject";
72 
73         auto method = bus.new_method_call(objectMapperService, objectMapperPath,
74                                           objectMapperInterface, function);
75 
76         // Find services that implement the object path, constrain the search
77         // to the given interface.
78         method.append(i_path, std::vector<std::string>{i_interface});
79 
80         auto reply = bus.call(method);
81 
82         // response is a map of service names to their interfaces
83         std::map<DBusService, DBusInterfaceList> response;
84         reply.read(response);
85 
86         if (!response.empty())
87         {
88             // return the service
89             o_service = response.begin()->first;
90 
91             rc = 0; // success
92         }
93     }
94     catch (const sdbusplus::exception::SdBusError& e)
95     {
96         trace::err("util::dbus::map exception");
97         std::string traceMsg = std::string(e.what());
98         trace::err(traceMsg.c_str());
99     }
100 
101     return rc;
102 }
103 
104 /** @brief Read a property from a dbus object interface */
105 int getProperty(const std::string& i_interface, const std::string& i_path,
106                 const std::string& i_service, const std::string& i_property,
107                 DBusValue& o_response)
108 {
109     int rc = 1; // assume not success
110 
111     auto bus = sdbusplus::bus::new_default();
112 
113     try
114     {
115         constexpr auto interface = "org.freedesktop.DBus.Properties";
116         constexpr auto function  = "Get";
117 
118         // calling the get property method
119         auto method = bus.new_method_call(i_service.c_str(), i_path.c_str(),
120                                           interface, function);
121 
122         method.append(i_interface, i_property);
123         auto reply = bus.call(method);
124 
125         // returning the property value
126         reply.read(o_response);
127 
128         rc = 0; // success
129     }
130     catch (const sdbusplus::exception::SdBusError& e)
131     {
132         trace::err("util::dbus::getProperty exception");
133         std::string traceMsg = std::string(e.what());
134         trace::err(traceMsg.c_str());
135     }
136 
137     return rc;
138 }
139 
140 /** @brief Get the IBM compatible names defined for this system */
141 std::vector<std::string> systemNames()
142 {
143     std::vector<std::string> names;
144 
145     constexpr auto interface =
146         "xyz.openbmc_project.Configuration.IBMCompatibleSystem";
147 
148     DBusService service;
149     DBusPath path;
150 
151     // find a dbus object and path that implements the interface
152     if (0 == find(interface, path, service))
153     {
154         DBusValue value;
155 
156         // compatible system names are implemented as a property
157         constexpr auto property = "Names";
158 
159         if (0 == getProperty(interface, path, service, property, value))
160         {
161             // return value is a variant, names are in the vector
162             names = std::get<std::vector<std::string>>(value);
163         }
164     }
165 
166     return names;
167 }
168 
169 /** @brief Transition the host state */
170 void transitionHost(const HostState i_hostState)
171 {
172     try
173     {
174         // We will be transitioning host by starting appropriate dbus target
175         std::string target = "obmc-host-quiesce@0.target"; // quiesce is default
176 
177         // crash (mpipl) mode state requested
178         if (HostState::Crash == i_hostState)
179         {
180             target = "obmc-host-crash@0.target";
181         }
182 
183         auto bus    = sdbusplus::bus::new_system();
184         auto method = bus.new_method_call(
185             "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
186             "org.freedesktop.systemd1.Manager", "StartUnit");
187 
188         method.append(target);    // target unit to start
189         method.append("replace"); // mode = replace conflicting queued jobs
190 
191         bus.call_noreply(method); // start the service
192     }
193     catch (const sdbusplus::exception::SdBusError& e)
194     {
195         trace::err("util::dbus::transitionHost exception");
196         std::string traceMsg = std::string(e.what());
197         trace::err(traceMsg.c_str());
198     }
199 }
200 
201 /** @brief Read state of autoreboot propertyi via dbus */
202 bool autoRebootEnabled()
203 {
204     bool autoReboot = false; // assume autoreboot attribute not available
205 
206     constexpr auto interface = "xyz.openbmc_project.Control.Boot.RebootPolicy";
207 
208     DBusService service;
209     DBusPath path;
210 
211     // find a dbus object and path that implements the interface
212     if (0 == find(interface, path, service))
213     {
214         DBusValue value;
215 
216         // autoreboot policy is implemented as a property
217         constexpr auto property = "AutoReboot";
218 
219         if (0 == getProperty(interface, path, service, property, value))
220         {
221             // return value is a variant, autoreboot policy is boolean
222             autoReboot = std::get<bool>(value);
223         }
224     }
225 
226     return autoReboot;
227 }
228 
229 /** @brief Get the running state of the host */
230 HostRunningState hostRunningState()
231 {
232     // assume not able to get host running state
233     HostRunningState host = HostRunningState::Unknown;
234 
235     constexpr auto interface = "xyz.openbmc_project.State.Boot.Progress";
236 
237     DBusService service;
238     DBusPath path;
239 
240     // find a dbus object and path that implements the interface
241     if (0 == find(interface, path, service))
242     {
243         DBusValue value;
244 
245         // boot progress is implemented as a property
246         constexpr auto property = "BootProgress";
247 
248         if (0 == getProperty(interface, path, service, property, value))
249         {
250             // return value is a variant, progress is in the vector of strings
251             std::string bootProgress(std::get<std::string>(value));
252 
253             // convert boot progress to host state
254             using BootProgress = sdbusplus::xyz::openbmc_project::State::Boot::
255                 server::Progress::ProgressStages;
256 
257             BootProgress stage = sdbusplus::xyz::openbmc_project::State::Boot::
258                 server::Progress::convertProgressStagesFromString(bootProgress);
259 
260             if ((stage == BootProgress::SystemInitComplete) ||
261                 (stage == BootProgress::OSStart) ||
262                 (stage == BootProgress::OSRunning))
263             {
264                 host = HostRunningState::Started;
265             }
266             else
267             {
268                 host = HostRunningState::NotStarted;
269             }
270         }
271     }
272 
273     return host;
274 }
275 
276 } // namespace dbus
277 
278 } // namespace util
279