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