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