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