xref: /openbmc/bmcweb/include/dbus_utility.hpp (revision d35c241d30bba30a1d42ebc85ef8072f283cb820)
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 
escapePathForDbus(std::string & path)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 
logError(const boost::system::error_code & ec)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
getNthStringFromPath(const std::string & path,int index,std::string & result)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
getAllProperties(const std::string & service,const std::string & objectPath,const std::string & interface,std::function<void (const boost::system::error_code &,const DBusPropertiesMap &)> && callback)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>
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)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>
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)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 
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)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 
checkDbusPathExists(const std::string & path,std::function<void (bool)> && callback)189 inline void checkDbusPathExists(const std::string& path,
190                                 std::function<void(bool)>&& callback)
191 {
192     crow::connections::systemBus->async_method_call(
193         [callback = std::move(callback)](const boost::system::error_code& ec,
194                                          const MapperGetObject& objectNames) {
195             callback(!ec && !objectNames.empty());
196         },
197         "xyz.openbmc_project.ObjectMapper",
198         "/xyz/openbmc_project/object_mapper",
199         "xyz.openbmc_project.ObjectMapper", "GetObject", path,
200         std::array<std::string, 0>());
201 }
202 
203 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)204     getSubTree(const std::string& path, int32_t depth,
205                std::span<const std::string_view> interfaces,
206                std::function<void(const boost::system::error_code&,
207                                   const MapperGetSubTreeResponse&)>&& callback)
208 {
209     crow::connections::systemBus->async_method_call(
210         [callback{std::move(callback)}](
211             const boost::system::error_code& ec,
212             const MapperGetSubTreeResponse& subtree) { callback(ec, subtree); },
213         "xyz.openbmc_project.ObjectMapper",
214         "/xyz/openbmc_project/object_mapper",
215         "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, depth,
216         interfaces);
217 }
218 
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)219 inline void getSubTreePaths(
220     const std::string& path, int32_t depth,
221     std::span<const std::string_view> interfaces,
222     std::function<void(const boost::system::error_code&,
223                        const MapperGetSubTreePathsResponse&)>&& callback)
224 {
225     crow::connections::systemBus->async_method_call(
226         [callback{std::move(callback)}](
227             const boost::system::error_code& ec,
228             const MapperGetSubTreePathsResponse& subtreePaths) {
229             callback(ec, subtreePaths);
230         },
231         "xyz.openbmc_project.ObjectMapper",
232         "/xyz/openbmc_project/object_mapper",
233         "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", path, depth,
234         interfaces);
235 }
236 
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)237 inline void getAssociatedSubTree(
238     const sdbusplus::message::object_path& associatedPath,
239     const sdbusplus::message::object_path& path, int32_t depth,
240     std::span<const std::string_view> interfaces,
241     std::function<void(const boost::system::error_code&,
242                        const MapperGetSubTreeResponse&)>&& callback)
243 {
244     crow::connections::systemBus->async_method_call(
245         [callback{std::move(callback)}](
246             const boost::system::error_code& ec,
247             const MapperGetSubTreeResponse& subtree) { callback(ec, subtree); },
248         "xyz.openbmc_project.ObjectMapper",
249         "/xyz/openbmc_project/object_mapper",
250         "xyz.openbmc_project.ObjectMapper", "GetAssociatedSubTree",
251         associatedPath, path, depth, interfaces);
252 }
253 
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)254 inline void getAssociatedSubTreePaths(
255     const sdbusplus::message::object_path& associatedPath,
256     const sdbusplus::message::object_path& path, int32_t depth,
257     std::span<const std::string_view> interfaces,
258     std::function<void(const boost::system::error_code&,
259                        const MapperGetSubTreePathsResponse&)>&& callback)
260 {
261     crow::connections::systemBus->async_method_call(
262         [callback{std::move(callback)}](
263             const boost::system::error_code& ec,
264             const MapperGetSubTreePathsResponse& subtreePaths) {
265             callback(ec, subtreePaths);
266         },
267         "xyz.openbmc_project.ObjectMapper",
268         "/xyz/openbmc_project/object_mapper",
269         "xyz.openbmc_project.ObjectMapper", "GetAssociatedSubTreePaths",
270         associatedPath, path, depth, interfaces);
271 }
272 
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)273 inline void getAssociatedSubTreeById(
274     const std::string& id, const std::string& path,
275     std::span<const std::string_view> subtreeInterfaces,
276     std::string_view association,
277     std::span<const std::string_view> endpointInterfaces,
278     std::function<void(const boost::system::error_code&,
279                        const MapperGetSubTreeResponse&)>&& callback)
280 {
281     crow::connections::systemBus->async_method_call(
282         [callback{std::move(callback)}](
283             const boost::system::error_code& ec,
284             const MapperGetSubTreeResponse& subtree) { callback(ec, subtree); },
285         "xyz.openbmc_project.ObjectMapper",
286         "/xyz/openbmc_project/object_mapper",
287         "xyz.openbmc_project.ObjectMapper", "GetAssociatedSubTreeById", id,
288         path, subtreeInterfaces, association, endpointInterfaces);
289 }
290 
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)291 inline void getAssociatedSubTreePathsById(
292     const std::string& id, const std::string& path,
293     std::span<const std::string_view> subtreeInterfaces,
294     std::string_view association,
295     std::span<const std::string_view> endpointInterfaces,
296     std::function<void(const boost::system::error_code&,
297                        const MapperGetSubTreePathsResponse&)>&& callback)
298 {
299     crow::connections::systemBus->async_method_call(
300         [callback{std::move(callback)}](
301             const boost::system::error_code& ec,
302             const MapperGetSubTreePathsResponse& subtreePaths) {
303             callback(ec, subtreePaths);
304         },
305         "xyz.openbmc_project.ObjectMapper",
306         "/xyz/openbmc_project/object_mapper",
307         "xyz.openbmc_project.ObjectMapper", "GetAssociatedSubTreePathsById", id,
308         path, subtreeInterfaces, association, endpointInterfaces);
309 }
310 
getDbusObject(const std::string & path,std::span<const std::string_view> interfaces,std::function<void (const boost::system::error_code &,const MapperGetObject &)> && callback)311 inline void getDbusObject(
312     const std::string& path, std::span<const std::string_view> interfaces,
313     std::function<void(const boost::system::error_code&,
314                        const MapperGetObject&)>&& callback)
315 {
316     crow::connections::systemBus->async_method_call(
317         [callback{std::move(callback)}](const boost::system::error_code& ec,
318                                         const MapperGetObject& object) {
319             callback(ec, object);
320         },
321         "xyz.openbmc_project.ObjectMapper",
322         "/xyz/openbmc_project/object_mapper",
323         "xyz.openbmc_project.ObjectMapper", "GetObject", path, interfaces);
324 }
325 
getAssociationEndPoints(const std::string & path,std::function<void (const boost::system::error_code &,const MapperEndPoints &)> && callback)326 inline void getAssociationEndPoints(
327     const std::string& path,
328     std::function<void(const boost::system::error_code&,
329                        const MapperEndPoints&)>&& callback)
330 {
331     getProperty<MapperEndPoints>("xyz.openbmc_project.ObjectMapper", path,
332                                  "xyz.openbmc_project.Association", "endpoints",
333                                  std::move(callback));
334 }
335 
getManagedObjects(const std::string & service,const sdbusplus::message::object_path & path,std::function<void (const boost::system::error_code &,const ManagedObjectType &)> && callback)336 inline void getManagedObjects(
337     const std::string& service, const sdbusplus::message::object_path& path,
338     std::function<void(const boost::system::error_code&,
339                        const ManagedObjectType&)>&& callback)
340 {
341     crow::connections::systemBus->async_method_call(
342         [callback{std::move(callback)}](const boost::system::error_code& ec,
343                                         const ManagedObjectType& objects) {
344             callback(ec, objects);
345         },
346         service, path, "org.freedesktop.DBus.ObjectManager",
347         "GetManagedObjects");
348 }
349 
350 } // namespace utility
351 } // namespace dbus
352