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