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