xref: /openbmc/bmcweb/include/dbus_utility.hpp (revision 95c6307a)
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> // IWYU pragma: keep
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 // IWYU pragma: no_include <stddef.h>
42 // IWYU pragma: no_include <stdint.h>
43 // IWYU pragma: no_include <boost/system/detail/error_code.hpp>
44 
45 namespace dbus
46 {
47 
48 namespace utility
49 {
50 
51 // clang-format off
52 using DbusVariantType = std::variant<
53     std::vector<std::tuple<std::string, std::string, std::string>>,
54     std::vector<std::string>,
55     std::vector<double>,
56     std::string,
57     int64_t,
58     uint64_t,
59     double,
60     int32_t,
61     uint32_t,
62     int16_t,
63     uint16_t,
64     uint8_t,
65     bool,
66     sdbusplus::message::unix_fd,
67     std::vector<uint32_t>,
68     std::vector<uint16_t>,
69     sdbusplus::message::object_path,
70     std::tuple<uint64_t, std::vector<std::tuple<std::string, double, uint64_t>>>,
71     std::vector<sdbusplus::message::object_path>,
72     std::vector<std::tuple<std::string, std::string>>,
73     std::vector<std::tuple<uint32_t, std::vector<uint32_t>>>,
74     std::vector<std::tuple<uint32_t, size_t>>,
75     std::vector<std::tuple<
76       std::vector<std::tuple<sdbusplus::message::object_path, std::string>>,
77       std::string, std::string, uint64_t>>
78  >;
79 
80 // clang-format on
81 using DBusPropertiesMap = std::vector<std::pair<std::string, DbusVariantType>>;
82 using DBusInterfacesMap =
83     std::vector<std::pair<std::string, DBusPropertiesMap>>;
84 using ManagedObjectType =
85     std::vector<std::pair<sdbusplus::message::object_path, DBusInterfacesMap>>;
86 
87 // Map of service name to list of interfaces
88 using MapperServiceMap =
89     std::vector<std::pair<std::string, std::vector<std::string>>>;
90 
91 // Map of object paths to MapperServiceMaps
92 using MapperGetSubTreeResponse =
93     std::vector<std::pair<std::string, MapperServiceMap>>;
94 
95 using MapperGetObject =
96     std::vector<std::pair<std::string, std::vector<std::string>>>;
97 
98 using MapperGetAncestorsResponse = std::vector<
99     std::pair<std::string,
100               std::vector<std::pair<std::string, std::vector<std::string>>>>>;
101 
102 using MapperGetSubTreePathsResponse = std::vector<std::string>;
103 
104 using MapperEndPoints = std::vector<std::string>;
105 
escapePathForDbus(std::string & path)106 inline void escapePathForDbus(std::string& path)
107 {
108     const static std::regex reg("[^A-Za-z0-9_/]");
109     std::regex_replace(path.begin(), path.begin(), path.end(), reg, "_");
110 }
111 
logError(const boost::system::error_code & ec)112 inline void logError(const boost::system::error_code& ec)
113 {
114     if (ec)
115     {
116         BMCWEB_LOG_ERROR("DBus error: {}, cannot call method", ec);
117     }
118 }
119 
120 // gets the string N strings deep into a path
121 // i.e.  /0th/1st/2nd/3rd
getNthStringFromPath(const std::string & path,int index,std::string & result)122 inline bool getNthStringFromPath(const std::string& path, int index,
123                                  std::string& result)
124 {
125     if (index < 0)
126     {
127         return false;
128     }
129 
130     std::filesystem::path p1(path);
131     int count = -1;
132     for (const auto& element : p1)
133     {
134         if (element.has_filename())
135         {
136             ++count;
137             if (count == index)
138             {
139                 result = element.stem().string();
140                 break;
141             }
142         }
143     }
144     return count >= index;
145 }
146 
147 template <typename Callback>
checkDbusPathExists(const std::string & path,Callback && callback)148 inline void checkDbusPathExists(const std::string& path, Callback&& callback)
149 {
150     crow::connections::systemBus->async_method_call(
151         [callback = std::forward<Callback>(callback)](
152             const boost::system::error_code& ec,
153             const dbus::utility::MapperGetObject& objectNames) {
154         callback(!ec && !objectNames.empty());
155     },
156         "xyz.openbmc_project.ObjectMapper",
157         "/xyz/openbmc_project/object_mapper",
158         "xyz.openbmc_project.ObjectMapper", "GetObject", path,
159         std::array<std::string, 0>());
160 }
161 
162 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)163     getSubTree(const std::string& path, int32_t depth,
164                std::span<const std::string_view> interfaces,
165                std::function<void(const boost::system::error_code&,
166                                   const MapperGetSubTreeResponse&)>&& callback)
167 {
168     crow::connections::systemBus->async_method_call(
169         [callback{std::move(callback)}](
170             const boost::system::error_code& ec,
171             const MapperGetSubTreeResponse& subtree) { callback(ec, subtree); },
172         "xyz.openbmc_project.ObjectMapper",
173         "/xyz/openbmc_project/object_mapper",
174         "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, depth,
175         interfaces);
176 }
177 
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)178 inline void getSubTreePaths(
179     const std::string& path, int32_t depth,
180     std::span<const std::string_view> interfaces,
181     std::function<void(const boost::system::error_code&,
182                        const MapperGetSubTreePathsResponse&)>&& callback)
183 {
184     crow::connections::systemBus->async_method_call(
185         [callback{std::move(callback)}](
186             const boost::system::error_code& ec,
187             const MapperGetSubTreePathsResponse& subtreePaths) {
188         callback(ec, subtreePaths);
189     },
190         "xyz.openbmc_project.ObjectMapper",
191         "/xyz/openbmc_project/object_mapper",
192         "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", path, depth,
193         interfaces);
194 }
195 
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)196 inline void getAssociatedSubTree(
197     const sdbusplus::message::object_path& associatedPath,
198     const sdbusplus::message::object_path& path, int32_t depth,
199     std::span<const std::string_view> interfaces,
200     std::function<void(const boost::system::error_code&,
201                        const MapperGetSubTreeResponse&)>&& callback)
202 {
203     crow::connections::systemBus->async_method_call(
204         [callback{std::move(callback)}](
205             const boost::system::error_code& ec,
206             const MapperGetSubTreeResponse& subtree) { callback(ec, subtree); },
207         "xyz.openbmc_project.ObjectMapper",
208         "/xyz/openbmc_project/object_mapper",
209         "xyz.openbmc_project.ObjectMapper", "GetAssociatedSubTree",
210         associatedPath, path, depth, interfaces);
211 }
212 
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)213 inline void getAssociatedSubTreePaths(
214     const sdbusplus::message::object_path& associatedPath,
215     const sdbusplus::message::object_path& path, int32_t depth,
216     std::span<const std::string_view> interfaces,
217     std::function<void(const boost::system::error_code&,
218                        const MapperGetSubTreePathsResponse&)>&& callback)
219 {
220     crow::connections::systemBus->async_method_call(
221         [callback{std::move(callback)}](
222             const boost::system::error_code& ec,
223             const MapperGetSubTreePathsResponse& subtreePaths) {
224         callback(ec, subtreePaths);
225     },
226         "xyz.openbmc_project.ObjectMapper",
227         "/xyz/openbmc_project/object_mapper",
228         "xyz.openbmc_project.ObjectMapper", "GetAssociatedSubTreePaths",
229         associatedPath, path, depth, interfaces);
230 }
231 
232 inline void
getDbusObject(const std::string & path,std::span<const std::string_view> interfaces,std::function<void (const boost::system::error_code &,const MapperGetObject &)> && callback)233     getDbusObject(const std::string& path,
234                   std::span<const std::string_view> interfaces,
235                   std::function<void(const boost::system::error_code&,
236                                      const MapperGetObject&)>&& callback)
237 {
238     crow::connections::systemBus->async_method_call(
239         [callback{std::move(callback)}](const boost::system::error_code& ec,
240                                         const MapperGetObject& object) {
241         callback(ec, object);
242     },
243         "xyz.openbmc_project.ObjectMapper",
244         "/xyz/openbmc_project/object_mapper",
245         "xyz.openbmc_project.ObjectMapper", "GetObject", path, interfaces);
246 }
247 
getAssociationEndPoints(const std::string & path,std::function<void (const boost::system::error_code &,const MapperEndPoints &)> && callback)248 inline void getAssociationEndPoints(
249     const std::string& path,
250     std::function<void(const boost::system::error_code&,
251                        const MapperEndPoints&)>&& callback)
252 {
253     sdbusplus::asio::getProperty<MapperEndPoints>(
254         *crow::connections::systemBus, "xyz.openbmc_project.ObjectMapper", path,
255         "xyz.openbmc_project.Association", "endpoints", std::move(callback));
256 }
257 
258 inline void
getManagedObjects(const std::string & service,const sdbusplus::message::object_path & path,std::function<void (const boost::system::error_code &,const ManagedObjectType &)> && callback)259     getManagedObjects(const std::string& service,
260                       const sdbusplus::message::object_path& path,
261                       std::function<void(const boost::system::error_code&,
262                                          const ManagedObjectType&)>&& callback)
263 {
264     crow::connections::systemBus->async_method_call(
265         [callback{std::move(callback)}](const boost::system::error_code& ec,
266                                         const ManagedObjectType& objects) {
267         callback(ec, objects);
268     },
269         service, path, "org.freedesktop.DBus.ObjectManager",
270         "GetManagedObjects");
271 }
272 
273 } // namespace utility
274 } // namespace dbus
275