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 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 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 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 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> 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> 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 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> 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 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 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 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 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 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 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 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 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 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