xref: /openbmc/bmcweb/include/dbus_utility.hpp (revision 40e9b92ec19acffb46f83a6e55b18974da5d708e)
1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3 // SPDX-FileCopyrightText: Copyright 2018 Intel Corporation
4 #pragma once
5 
6 #include "boost_formatters.hpp"
7 #include "dbus_singleton.hpp"
8 #include "logging.hpp"
9 
10 #include <boost/system/error_code.hpp>
11 #include <sdbusplus/asio/property.hpp>
12 #include <sdbusplus/message/native_types.hpp>
13 
14 #include <array>
15 #include <cstddef>
16 #include <cstdint>
17 #include <filesystem>
18 #include <functional>
19 #include <regex>
20 #include <span>
21 #include <sstream>
22 #include <string>
23 #include <string_view>
24 #include <tuple>
25 #include <utility>
26 #include <variant>
27 #include <vector>
28 
29 namespace dbus
30 {
31 
32 namespace utility
33 {
34 
35 // clang-format off
36 using DbusVariantType = std::variant<
37     std::vector<std::tuple<std::string, std::string, std::string>>,
38     std::vector<std::string>,
39     std::vector<double>,
40     std::string,
41     int64_t,
42     uint64_t,
43     double,
44     int32_t,
45     uint32_t,
46     int16_t,
47     uint16_t,
48     uint8_t,
49     bool,
50     std::vector<uint32_t>,
51     std::vector<uint16_t>,
52     sdbusplus::message::object_path,
53     std::tuple<uint64_t, std::vector<std::tuple<std::string, double, uint64_t>>>,
54     std::vector<sdbusplus::message::object_path>,
55     std::vector<std::tuple<std::string, std::string>>,
56     std::vector<std::tuple<uint32_t, std::vector<uint32_t>>>,
57     std::vector<std::tuple<uint32_t, size_t>>,
58     std::vector<std::tuple<
59       std::vector<std::tuple<sdbusplus::message::object_path, std::string>>,
60       std::string, std::string, uint64_t>>,
61     std::vector<std::pair<sdbusplus::message::object_path, std::string>>,
62     std::vector<std::tuple<std::string, uint64_t, std::string, double>>,
63     std::vector<std::tuple<std::string, std::string, uint64_t, std::string>>
64  >;
65 
66 // clang-format on
67 using DBusPropertiesMap = std::vector<std::pair<std::string, DbusVariantType>>;
68 using DBusInterfacesMap =
69     std::vector<std::pair<std::string, DBusPropertiesMap>>;
70 using ManagedObjectType =
71     std::vector<std::pair<sdbusplus::message::object_path, DBusInterfacesMap>>;
72 
73 // Map of service name to list of interfaces
74 using MapperServiceMap =
75     std::vector<std::pair<std::string, std::vector<std::string>>>;
76 
77 // Map of object paths to MapperServiceMaps
78 using MapperGetSubTreeResponse =
79     std::vector<std::pair<std::string, MapperServiceMap>>;
80 
81 using MapperGetObject =
82     std::vector<std::pair<std::string, std::vector<std::string>>>;
83 
84 using MapperGetAncestorsResponse = std::vector<
85     std::pair<std::string,
86               std::vector<std::pair<std::string, std::vector<std::string>>>>>;
87 
88 using MapperGetSubTreePathsResponse = std::vector<std::string>;
89 
90 using MapperEndPoints = std::vector<std::string>;
91 
escapePathForDbus(std::string & path)92 inline void escapePathForDbus(std::string& path)
93 {
94     const static std::regex reg("[^A-Za-z0-9_/]");
95     std::regex_replace(path.begin(), path.begin(), path.end(), reg, "_");
96 }
97 
logError(const boost::system::error_code & ec)98 inline void logError(const boost::system::error_code& ec)
99 {
100     if (ec)
101     {
102         BMCWEB_LOG_ERROR("DBus error: {}, cannot call method", ec);
103     }
104 }
105 
106 // gets the string N strings deep into a path
107 // i.e.  /0th/1st/2nd/3rd
getNthStringFromPath(const std::string & path,int index,std::string & result)108 inline bool getNthStringFromPath(const std::string& path, int index,
109                                  std::string& result)
110 {
111     if (index < 0)
112     {
113         return false;
114     }
115 
116     std::filesystem::path p1(path);
117     int count = -1;
118     for (const auto& element : p1)
119     {
120         if (element.has_filename())
121         {
122             ++count;
123             if (count == index)
124             {
125                 result = element.stem().string();
126                 break;
127             }
128         }
129     }
130     return count >= index;
131 }
132 
133 inline void
getAllProperties(const std::string & service,const std::string & objectPath,const std::string & interface,std::function<void (const boost::system::error_code &,const DBusPropertiesMap &)> && callback)134     getAllProperties(const std::string& service, const std::string& objectPath,
135                      const std::string& interface,
136                      std::function<void(const boost::system::error_code&,
137                                         const DBusPropertiesMap&)>&& callback)
138 {
139     sdbusplus::asio::getAllProperties(*crow::connections::systemBus, service,
140                                       objectPath, interface,
141                                       std::move(callback));
142 }
143 
144 template <typename PropertyType>
getProperty(const std::string & service,const std::string & objectPath,const std::string & interface,const std::string & propertyName,std::function<void (const boost::system::error_code &,const PropertyType &)> && callback)145 inline void getProperty(
146     const std::string& service, const std::string& objectPath,
147     const std::string& interface, const std::string& propertyName,
148     std::function<void(const boost::system::error_code&, const PropertyType&)>&&
149         callback)
150 {
151     sdbusplus::asio::getProperty<PropertyType>(
152         *crow::connections::systemBus, service, objectPath, interface,
153         propertyName, std::move(callback));
154 }
155 
156 template <typename PropertyType>
getProperty(sdbusplus::asio::connection &,const std::string & service,const std::string & objectPath,const std::string & interface,const std::string & propertyName,std::function<void (const boost::system::error_code &,const PropertyType &)> && callback)157 inline void getProperty(
158     sdbusplus::asio::connection& /*conn*/, const std::string& service,
159     const std::string& objectPath, const std::string& interface,
160     const std::string& propertyName,
161     std::function<void(const boost::system::error_code&, const PropertyType&)>&&
162         callback)
163 {
164     getProperty(service, objectPath, interface, propertyName,
165                 std::move(callback));
166 }
167 
getAllProperties(sdbusplus::asio::connection &,const std::string & service,const std::string & objectPath,const std::string & interface,std::function<void (const boost::system::error_code &,const DBusPropertiesMap &)> && callback)168 inline void getAllProperties(
169     sdbusplus::asio::connection& /*conn*/, const std::string& service,
170     const std::string& objectPath, const std::string& interface,
171     std::function<void(const boost::system::error_code&,
172                        const DBusPropertiesMap&)>&& callback)
173 {
174     getAllProperties(service, objectPath, interface, std::move(callback));
175 }
176 
checkDbusPathExists(const std::string & path,std::function<void (bool)> && callback)177 inline void checkDbusPathExists(const std::string& path,
178                                 std::function<void(bool)>&& callback)
179 {
180     crow::connections::systemBus->async_method_call(
181         [callback = std::move(callback)](const boost::system::error_code& ec,
182                                          const MapperGetObject& objectNames) {
183             callback(!ec && !objectNames.empty());
184         },
185         "xyz.openbmc_project.ObjectMapper",
186         "/xyz/openbmc_project/object_mapper",
187         "xyz.openbmc_project.ObjectMapper", "GetObject", path,
188         std::array<std::string, 0>());
189 }
190 
191 inline void
getSubTree(const std::string & path,int32_t depth,std::span<const std::string_view> interfaces,std::function<void (const boost::system::error_code &,const MapperGetSubTreeResponse &)> && callback)192     getSubTree(const std::string& path, int32_t depth,
193                std::span<const std::string_view> interfaces,
194                std::function<void(const boost::system::error_code&,
195                                   const MapperGetSubTreeResponse&)>&& callback)
196 {
197     crow::connections::systemBus->async_method_call(
198         [callback{std::move(callback)}](
199             const boost::system::error_code& ec,
200             const MapperGetSubTreeResponse& subtree) { callback(ec, subtree); },
201         "xyz.openbmc_project.ObjectMapper",
202         "/xyz/openbmc_project/object_mapper",
203         "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, depth,
204         interfaces);
205 }
206 
getSubTreePaths(const std::string & path,int32_t depth,std::span<const std::string_view> interfaces,std::function<void (const boost::system::error_code &,const MapperGetSubTreePathsResponse &)> && callback)207 inline void getSubTreePaths(
208     const std::string& path, int32_t depth,
209     std::span<const std::string_view> interfaces,
210     std::function<void(const boost::system::error_code&,
211                        const MapperGetSubTreePathsResponse&)>&& callback)
212 {
213     crow::connections::systemBus->async_method_call(
214         [callback{std::move(callback)}](
215             const boost::system::error_code& ec,
216             const MapperGetSubTreePathsResponse& subtreePaths) {
217             callback(ec, subtreePaths);
218         },
219         "xyz.openbmc_project.ObjectMapper",
220         "/xyz/openbmc_project/object_mapper",
221         "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", path, depth,
222         interfaces);
223 }
224 
getAssociatedSubTree(const sdbusplus::message::object_path & associatedPath,const sdbusplus::message::object_path & path,int32_t depth,std::span<const std::string_view> interfaces,std::function<void (const boost::system::error_code &,const MapperGetSubTreeResponse &)> && callback)225 inline void getAssociatedSubTree(
226     const sdbusplus::message::object_path& associatedPath,
227     const sdbusplus::message::object_path& path, int32_t depth,
228     std::span<const std::string_view> interfaces,
229     std::function<void(const boost::system::error_code&,
230                        const MapperGetSubTreeResponse&)>&& callback)
231 {
232     crow::connections::systemBus->async_method_call(
233         [callback{std::move(callback)}](
234             const boost::system::error_code& ec,
235             const MapperGetSubTreeResponse& subtree) { callback(ec, subtree); },
236         "xyz.openbmc_project.ObjectMapper",
237         "/xyz/openbmc_project/object_mapper",
238         "xyz.openbmc_project.ObjectMapper", "GetAssociatedSubTree",
239         associatedPath, path, depth, interfaces);
240 }
241 
getAssociatedSubTreePaths(const sdbusplus::message::object_path & associatedPath,const sdbusplus::message::object_path & path,int32_t depth,std::span<const std::string_view> interfaces,std::function<void (const boost::system::error_code &,const MapperGetSubTreePathsResponse &)> && callback)242 inline void getAssociatedSubTreePaths(
243     const sdbusplus::message::object_path& associatedPath,
244     const sdbusplus::message::object_path& path, int32_t depth,
245     std::span<const std::string_view> interfaces,
246     std::function<void(const boost::system::error_code&,
247                        const MapperGetSubTreePathsResponse&)>&& callback)
248 {
249     crow::connections::systemBus->async_method_call(
250         [callback{std::move(callback)}](
251             const boost::system::error_code& ec,
252             const MapperGetSubTreePathsResponse& subtreePaths) {
253             callback(ec, subtreePaths);
254         },
255         "xyz.openbmc_project.ObjectMapper",
256         "/xyz/openbmc_project/object_mapper",
257         "xyz.openbmc_project.ObjectMapper", "GetAssociatedSubTreePaths",
258         associatedPath, path, depth, interfaces);
259 }
260 
getAssociatedSubTreeById(const std::string & id,const std::string & path,std::span<const std::string_view> subtreeInterfaces,std::string_view association,std::span<const std::string_view> endpointInterfaces,std::function<void (const boost::system::error_code &,const MapperGetSubTreeResponse &)> && callback)261 inline void getAssociatedSubTreeById(
262     const std::string& id, const std::string& path,
263     std::span<const std::string_view> subtreeInterfaces,
264     std::string_view association,
265     std::span<const std::string_view> endpointInterfaces,
266     std::function<void(const boost::system::error_code&,
267                        const MapperGetSubTreeResponse&)>&& callback)
268 {
269     crow::connections::systemBus->async_method_call(
270         [callback{std::move(callback)}](
271             const boost::system::error_code& ec,
272             const MapperGetSubTreeResponse& subtree) { callback(ec, subtree); },
273         "xyz.openbmc_project.ObjectMapper",
274         "/xyz/openbmc_project/object_mapper",
275         "xyz.openbmc_project.ObjectMapper", "GetAssociatedSubTreeById", id,
276         path, subtreeInterfaces, association, endpointInterfaces);
277 }
278 
getAssociatedSubTreePathsById(const std::string & id,const std::string & path,std::span<const std::string_view> subtreeInterfaces,std::string_view association,std::span<const std::string_view> endpointInterfaces,std::function<void (const boost::system::error_code &,const MapperGetSubTreePathsResponse &)> && callback)279 inline void getAssociatedSubTreePathsById(
280     const std::string& id, const std::string& path,
281     std::span<const std::string_view> subtreeInterfaces,
282     std::string_view association,
283     std::span<const std::string_view> endpointInterfaces,
284     std::function<void(const boost::system::error_code&,
285                        const MapperGetSubTreePathsResponse&)>&& callback)
286 {
287     crow::connections::systemBus->async_method_call(
288         [callback{std::move(callback)}](
289             const boost::system::error_code& ec,
290             const MapperGetSubTreePathsResponse& subtreePaths) {
291             callback(ec, subtreePaths);
292         },
293         "xyz.openbmc_project.ObjectMapper",
294         "/xyz/openbmc_project/object_mapper",
295         "xyz.openbmc_project.ObjectMapper", "GetAssociatedSubTreePathsById", id,
296         path, subtreeInterfaces, association, endpointInterfaces);
297 }
298 
getDbusObject(const std::string & path,std::span<const std::string_view> interfaces,std::function<void (const boost::system::error_code &,const MapperGetObject &)> && callback)299 inline void getDbusObject(
300     const std::string& path, std::span<const std::string_view> interfaces,
301     std::function<void(const boost::system::error_code&,
302                        const MapperGetObject&)>&& callback)
303 {
304     crow::connections::systemBus->async_method_call(
305         [callback{std::move(callback)}](const boost::system::error_code& ec,
306                                         const MapperGetObject& object) {
307             callback(ec, object);
308         },
309         "xyz.openbmc_project.ObjectMapper",
310         "/xyz/openbmc_project/object_mapper",
311         "xyz.openbmc_project.ObjectMapper", "GetObject", path, interfaces);
312 }
313 
getAssociationEndPoints(const std::string & path,std::function<void (const boost::system::error_code &,const MapperEndPoints &)> && callback)314 inline void getAssociationEndPoints(
315     const std::string& path,
316     std::function<void(const boost::system::error_code&,
317                        const MapperEndPoints&)>&& callback)
318 {
319     getProperty<MapperEndPoints>("xyz.openbmc_project.ObjectMapper", path,
320                                  "xyz.openbmc_project.Association", "endpoints",
321                                  std::move(callback));
322 }
323 
getManagedObjects(const std::string & service,const sdbusplus::message::object_path & path,std::function<void (const boost::system::error_code &,const ManagedObjectType &)> && callback)324 inline void getManagedObjects(
325     const std::string& service, const sdbusplus::message::object_path& path,
326     std::function<void(const boost::system::error_code&,
327                        const ManagedObjectType&)>&& callback)
328 {
329     crow::connections::systemBus->async_method_call(
330         [callback{std::move(callback)}](const boost::system::error_code& ec,
331                                         const ManagedObjectType& objects) {
332             callback(ec, objects);
333         },
334         service, path, "org.freedesktop.DBus.ObjectManager",
335         "GetManagedObjects");
336 }
337 
338 } // namespace utility
339 } // namespace dbus
340