blob: c88fc8d5c4ad17638290055c54ee83c6943c87f6 [file] [log] [blame]
Ed Tanous40e9b922024-09-10 13:50:16 -07001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright OpenBMC Authors
3// SPDX-FileCopyrightText: Copyright 2018 Intel Corporation
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07004
James Feist5b4aa862018-08-16 14:07:01 -07005#pragma once
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08006#include "app.hpp"
7#include "async_resp.hpp"
Ed Tanous95c63072024-03-26 13:19:52 -07008#include "boost_formatters.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08009#include "dbus_singleton.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +080010#include "dbus_utility.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000011#include "http_request.hpp"
12#include "http_response.hpp"
Ed Tanous95c63072024-03-26 13:19:52 -070013#include "json_formatters.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000014#include "logging.hpp"
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010015#include "parsing.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000016#include "routing.hpp"
Ed Tanous50ebd4a2023-01-19 19:03:17 -080017#include "str_utility.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000018
19#include <systemd/sd-bus-protocol.h>
20#include <systemd/sd-bus.h>
Ed Tanous911ac312017-08-15 09:37:42 -070021#include <tinyxml2.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -070022
Nan Zhoud5c80ad2022-07-11 01:16:31 +000023#include <boost/beast/http/status.hpp>
24#include <boost/beast/http/verb.hpp>
25#include <boost/container/flat_map.hpp>
26#include <boost/container/vector.hpp>
George Liue99073f2022-12-09 11:06:16 +080027#include <boost/system/error_code.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000028#include <nlohmann/json.hpp>
29#include <sdbusplus/asio/connection.hpp>
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +020030#include <sdbusplus/asio/property.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000031#include <sdbusplus/exception.hpp>
32#include <sdbusplus/message.hpp>
33#include <sdbusplus/message/native_types.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050034
Nan Zhoud5c80ad2022-07-11 01:16:31 +000035#include <algorithm>
36#include <array>
37#include <cerrno>
38#include <cstdint>
39#include <cstring>
James Feist4418c7f2019-04-15 11:09:15 -070040#include <filesystem>
Ed Tanousd4bb9bb2018-05-16 13:36:42 -070041#include <fstream>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000042#include <functional>
43#include <initializer_list>
44#include <iterator>
45#include <limits>
46#include <map>
47#include <memory>
Ed Tanous3544d2a2023-08-06 18:12:20 -070048#include <ranges>
Ramesh Iyyard9207042019-07-05 08:04:42 -050049#include <regex>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000050#include <string>
51#include <string_view>
52#include <type_traits>
Ed Tanousb5a76932020-09-29 16:16:58 -070053#include <utility>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000054#include <variant>
55#include <vector>
56
Ed Tanous1abe55e2018-09-05 08:30:59 -070057namespace crow
58{
59namespace openbmc_mapper
60{
Ed Tanous23a21a12020-07-25 04:45:05 +000061const constexpr char* notFoundMsg = "404 Not Found";
62const constexpr char* badReqMsg = "400 Bad Request";
63const constexpr char* methodNotAllowedMsg = "405 Method Not Allowed";
64const constexpr char* forbiddenMsg = "403 Forbidden";
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010065const constexpr char* unsupportedMediaMsg = "415 Unsupported Media Type";
Ed Tanous23a21a12020-07-25 04:45:05 +000066const constexpr char* methodFailedMsg = "500 Method Call Failed";
67const constexpr char* methodOutputFailedMsg = "500 Method Output Error";
68const constexpr char* notFoundDesc =
Matt Spinler2ae60092018-12-06 10:35:36 -060069 "org.freedesktop.DBus.Error.FileNotFound: path or object not found";
Ed Tanous23a21a12020-07-25 04:45:05 +000070const constexpr char* propNotFoundDesc =
71 "The specified property cannot be found";
72const constexpr char* noJsonDesc = "No JSON object could be decoded";
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010073const constexpr char* invalidContentType =
74 "Content-type header is missing or invalid";
Ed Tanous23a21a12020-07-25 04:45:05 +000075const constexpr char* methodNotFoundDesc =
76 "The specified method cannot be found";
77const constexpr char* methodNotAllowedDesc = "Method not allowed";
78const constexpr char* forbiddenPropDesc =
79 "The specified property cannot be created";
80const constexpr char* forbiddenResDesc =
81 "The specified resource cannot be created";
Matt Spinler2ae60092018-12-06 10:35:36 -060082
Josh Lehan482c45a2022-03-29 17:10:44 -070083inline bool validateFilename(const std::string& filename)
84{
Ed Tanous4b242742023-05-11 09:51:51 -070085 static std::regex validFilename(R"(^[\w\- ]+(\.?[\w\- ]*)$)");
Josh Lehan482c45a2022-03-29 17:10:44 -070086
87 return std::regex_match(filename, validFilename);
88}
89
Ed Tanous23a21a12020-07-25 04:45:05 +000090inline void setErrorResponse(crow::Response& res,
91 boost::beast::http::status result,
Ed Tanous26ccae32023-02-16 10:28:44 -080092 const std::string& desc, std::string_view msg)
Matt Spinler2ae60092018-12-06 10:35:36 -060093{
94 res.result(result);
Ed Tanous14766872022-03-15 10:44:42 -070095 res.jsonValue["data"]["description"] = desc;
96 res.jsonValue["message"] = msg;
97 res.jsonValue["status"] = "error";
Matt Spinler2ae60092018-12-06 10:35:36 -060098}
99
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400100inline void introspectObjects(
101 const std::string& processName, const std::string& objectPath,
102 const std::shared_ptr<bmcweb::AsyncResp>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700103{
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700104 if (transaction->res.jsonValue.is_null())
105 {
Ed Tanous14766872022-03-15 10:44:42 -0700106 transaction->res.jsonValue["status"] = "ok";
107 transaction->res.jsonValue["bus_name"] = processName;
108 transaction->res.jsonValue["objects"] = nlohmann::json::array();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700109 }
110
Ed Tanous1abe55e2018-09-05 08:30:59 -0700111 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700112 [transaction, processName{std::string(processName)},
113 objectPath{std::string(objectPath)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800114 const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +0000115 const std::string& introspectXml) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400116 if (ec)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700117 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400118 BMCWEB_LOG_ERROR(
119 "Introspect call failed with error: {} on process: {} path: {}",
120 ec.message(), processName, objectPath);
121 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700122 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400123 nlohmann::json::object_t object;
124 object["path"] = objectPath;
125
126 transaction->res.jsonValue["objects"].emplace_back(
127 std::move(object));
128
129 tinyxml2::XMLDocument doc;
130
131 doc.Parse(introspectXml.c_str());
132 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
133 if (pRoot == nullptr)
134 {
135 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
136 processName, objectPath);
137 }
138 else
139 {
140 tinyxml2::XMLElement* node = pRoot->FirstChildElement("node");
141 while (node != nullptr)
142 {
143 const char* childPath = node->Attribute("name");
144 if (childPath != nullptr)
145 {
146 std::string newpath;
147 if (objectPath != "/")
148 {
149 newpath += objectPath;
150 }
151 newpath += std::string("/") + childPath;
152 // introspect the subobjects as well
153 introspectObjects(processName, newpath, transaction);
154 }
155
156 node = node->NextSiblingElement("node");
157 }
158 }
159 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700160 processName, objectPath, "org.freedesktop.DBus.Introspectable",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700161 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -0700162}
Ed Tanous64530012018-02-06 17:08:16 -0800163
Ed Tanous23a21a12020-07-25 04:45:05 +0000164inline void getPropertiesForEnumerate(
165 const std::string& objectPath, const std::string& service,
Ed Tanousb5a76932020-09-29 16:16:58 -0700166 const std::string& interface,
167 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600168{
Ed Tanous62598e32023-07-17 17:06:25 -0700169 BMCWEB_LOG_DEBUG("getPropertiesForEnumerate {} {} {}", objectPath, service,
170 interface);
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600171
Ed Tanousdeae6a72024-11-11 21:58:57 -0800172 dbus::utility::getAllProperties(
173 service, objectPath, interface,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800174 [asyncResp, objectPath, service,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800175 interface](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800176 const dbus::utility::DBusPropertiesMap& propertiesList) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400177 if (ec)
178 {
179 BMCWEB_LOG_ERROR(
180 "GetAll on path {} iface {} service {} failed with code {}",
181 objectPath, interface, service, ec);
182 return;
183 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600184
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400185 nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
186 nlohmann::json& objectJson = dataJson[objectPath];
187 if (objectJson.is_null())
188 {
189 objectJson = nlohmann::json::object();
190 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600191
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400192 for (const auto& [name, value] : propertiesList)
193 {
194 nlohmann::json& propertyJson = objectJson[name];
Ed Tanouse3648032024-10-16 18:06:39 -0700195 std::visit([&propertyJson](auto&& val) { propertyJson = val; },
196 value);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400197 }
198 });
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600199}
200
201// Find any results that weren't picked up by ObjectManagers, to be
202// called after all ObjectManagers are searched for and called.
Ed Tanous23a21a12020-07-25 04:45:05 +0000203inline void findRemainingObjectsForEnumerate(
Ed Tanousb5a76932020-09-29 16:16:58 -0700204 const std::string& objectPath,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800205 const std::shared_ptr<dbus::utility::MapperGetSubTreeResponse>& subtree,
Ed Tanousb5a76932020-09-29 16:16:58 -0700206 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600207{
Ed Tanous62598e32023-07-17 17:06:25 -0700208 BMCWEB_LOG_DEBUG("findRemainingObjectsForEnumerate");
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500209 const nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600210
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500211 for (const auto& [path, interface_map] : *subtree)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600212 {
213 if (path == objectPath)
214 {
215 // An enumerate does not return the target path's properties
216 continue;
217 }
218 if (dataJson.find(path) == dataJson.end())
219 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500220 for (const auto& [service, interfaces] : interface_map)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600221 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500222 for (const auto& interface : interfaces)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600223 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700224 if (!interface.starts_with("org.freedesktop.DBus"))
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600225 {
226 getPropertiesForEnumerate(path, service, interface,
227 asyncResp);
228 }
229 }
230 }
231 }
232 }
233}
234
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600235struct InProgressEnumerateData
236{
zhanghch058d1b46d2021-04-01 11:18:24 +0800237 InProgressEnumerateData(
238 const std::string& objectPathIn,
239 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400240 objectPath(objectPathIn), asyncResp(asyncRespIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500241 {}
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600242
243 ~InProgressEnumerateData()
244 {
Ed Tanous24b2fe82022-01-06 12:45:54 -0800245 try
246 {
247 findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
248 }
249 catch (...)
250 {
Ed Tanous62598e32023-07-17 17:06:25 -0700251 BMCWEB_LOG_CRITICAL(
252 "findRemainingObjectsForEnumerate threw exception");
Ed Tanous24b2fe82022-01-06 12:45:54 -0800253 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600254 }
255
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800256 InProgressEnumerateData(const InProgressEnumerateData&) = delete;
257 InProgressEnumerateData(InProgressEnumerateData&&) = delete;
258 InProgressEnumerateData& operator=(const InProgressEnumerateData&) = delete;
259 InProgressEnumerateData& operator=(InProgressEnumerateData&&) = delete;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600260 const std::string objectPath;
Ed Tanousb9d36b42022-02-26 21:42:46 -0800261 std::shared_ptr<dbus::utility::MapperGetSubTreeResponse> subtree;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600262 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
263};
264
Ed Tanous23a21a12020-07-25 04:45:05 +0000265inline void getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000266 const std::string& objectName, const std::string& objectManagerPath,
267 const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700268 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700269{
Ed Tanous62598e32023-07-17 17:06:25 -0700270 BMCWEB_LOG_DEBUG(
271 "getManagedObjectsForEnumerate {} object_manager_path {} connection_name {}",
272 objectName, objectManagerPath, connectionName);
George Liu5eb468d2023-06-20 17:03:24 +0800273 sdbusplus::message::object_path path(objectManagerPath);
274 dbus::utility::getManagedObjects(
275 connectionName, path,
Ed Tanous81ce6092020-12-17 16:54:55 +0000276 [transaction, objectName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800277 connectionName](const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +0000278 const dbus::utility::ManagedObjectType& objects) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400279 if (ec)
Ed Tanous049a0512018-11-01 13:58:42 -0700280 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400281 BMCWEB_LOG_ERROR(
282 "GetManagedObjects on path {} on connection {} failed with code {}",
283 objectName, connectionName, ec);
284 return;
285 }
286
287 nlohmann::json& dataJson =
288 transaction->asyncResp->res.jsonValue["data"];
289
290 for (const auto& objectPath : objects)
291 {
292 if (objectPath.first.str.starts_with(objectName))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700293 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400294 BMCWEB_LOG_DEBUG("Reading object {}", objectPath.first.str);
295 nlohmann::json& objectJson = dataJson[objectPath.first.str];
296 if (objectJson.is_null())
297 {
298 objectJson = nlohmann::json::object();
299 }
300 for (const auto& interface : objectPath.second)
301 {
302 for (const auto& property : interface.second)
303 {
304 nlohmann::json& propertyJson =
305 objectJson[property.first];
306 std::visit(
307 [&propertyJson](auto&& val) {
308 if constexpr (
309 std::is_same_v<
310 std::decay_t<decltype(val)>,
311 sdbusplus::message::unix_fd>)
312 {
313 propertyJson = val.fd;
314 }
315 else
316 {
317 propertyJson = val;
318 }
319 },
320 property.second);
321 }
322 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700323 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500324 for (const auto& interface : objectPath.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700325 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400326 if (interface.first == "org.freedesktop.DBus.ObjectManager")
Ed Tanous049a0512018-11-01 13:58:42 -0700327 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400328 getManagedObjectsForEnumerate(
329 objectPath.first.str, objectPath.first.str,
330 connectionName, transaction);
Ed Tanous049a0512018-11-01 13:58:42 -0700331 }
332 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700333 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400334 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700335}
336
Ed Tanous23a21a12020-07-25 04:45:05 +0000337inline void findObjectManagerPathForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000338 const std::string& objectName, const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700339 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700340{
Ed Tanous62598e32023-07-17 17:06:25 -0700341 BMCWEB_LOG_DEBUG("Finding objectmanager for path {} on connection:{}",
342 objectName, connectionName);
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700343 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000344 [transaction, objectName, connectionName](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800345 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800346 const dbus::utility::MapperGetAncestorsResponse& objects) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400347 if (ec)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700348 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400349 BMCWEB_LOG_ERROR("GetAncestors on path {} failed with code {}",
350 objectName, ec);
351 return;
352 }
353
354 for (const auto& pathGroup : objects)
355 {
356 for (const auto& connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700357 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400358 if (connectionGroup.first == connectionName)
359 {
360 // Found the object manager path for this resource.
361 getManagedObjectsForEnumerate(
362 objectName, pathGroup.first, connectionName,
363 transaction);
364 return;
365 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700366 }
367 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400368 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700369 "xyz.openbmc_project.ObjectMapper",
370 "/xyz/openbmc_project/object_mapper",
Ed Tanous81ce6092020-12-17 16:54:55 +0000371 "xyz.openbmc_project.ObjectMapper", "GetAncestors", objectName,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500372 std::array<const char*, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700373}
Ed Tanous64530012018-02-06 17:08:16 -0800374
Ed Tanous7c091622019-05-23 11:42:36 -0700375// Uses GetObject to add the object info about the target /enumerate path to
376// the results of GetSubTree, as GetSubTree will not return info for the
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600377// target path, and then continues on enumerating the rest of the tree.
Ed Tanousb5a76932020-09-29 16:16:58 -0700378inline void getObjectAndEnumerate(
379 const std::shared_ptr<InProgressEnumerateData>& transaction)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600380{
George Liu2b731192023-01-11 16:27:13 +0800381 dbus::utility::getDbusObject(
382 transaction->objectPath, {},
383 [transaction](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800384 const dbus::utility::MapperGetObject& objects) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400385 if (ec)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600386 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400387 BMCWEB_LOG_ERROR("GetObject for path {} failed with code {}",
388 transaction->objectPath, ec);
389 return;
390 }
391
392 BMCWEB_LOG_DEBUG("GetObject for {} has {} entries",
393 transaction->objectPath, objects.size());
394 if (!objects.empty())
395 {
396 transaction->subtree->emplace_back(transaction->objectPath,
397 objects);
398 }
399
400 // Map indicating connection name, and the path where the object
401 // manager exists
402 boost::container::flat_map<
403 std::string, std::string, std::less<>,
404 std::vector<std::pair<std::string, std::string>>>
405 connections;
406
407 for (const auto& object : *(transaction->subtree))
408 {
409 for (const auto& connection : object.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600410 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400411 for (const auto& interface : connection.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600412 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400413 BMCWEB_LOG_DEBUG("{} has interface {}",
414 connection.first, interface);
415 if (interface == "org.freedesktop.DBus.ObjectManager")
416 {
417 BMCWEB_LOG_DEBUG("found object manager path {}",
418 object.first);
419 connections[connection.first] = object.first;
420 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600421 }
422 }
423 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400424 BMCWEB_LOG_DEBUG("Got {} connections", connections.size());
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600425
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400426 for (const auto& connection : connections)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600427 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400428 // If we already know where the object manager is, we don't
429 // need to search for it, we can call directly in to
430 // getManagedObjects
431 if (!connection.second.empty())
432 {
433 getManagedObjectsForEnumerate(
434 transaction->objectPath, connection.second,
435 connection.first, transaction);
436 }
437 else
438 {
439 // otherwise we need to find the object manager path
440 // before we can continue
441 findObjectManagerPathForEnumerate(
442 transaction->objectPath, connection.first, transaction);
443 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600444 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400445 });
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600446}
Ed Tanous64530012018-02-06 17:08:16 -0800447
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700448// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700449struct InProgressActionData
450{
Lei YU28dd5ca2023-03-17 13:17:05 +0800451 explicit InProgressActionData(
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400452 const std::shared_ptr<bmcweb::AsyncResp>& res) : asyncResp(res)
Ed Tanous23a21a12020-07-25 04:45:05 +0000453 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700454 ~InProgressActionData()
455 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600456 // Methods could have been called across different owners
457 // and interfaces, where some calls failed and some passed.
458 //
459 // The rules for this are:
460 // * if no method was called - error
461 // * if a method failed and none passed - error
462 // (converse: if at least one method passed - OK)
463 // * for the method output:
464 // * if output processing didn't fail, return the data
465
466 // Only deal with method returns if nothing failed earlier
Lei YU28dd5ca2023-03-17 13:17:05 +0800467 if (asyncResp->res.result() == boost::beast::http::status::ok)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700468 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600469 if (!methodPassed)
470 {
Matt Spinler06b1b632019-06-18 16:09:25 -0500471 if (!methodFailed)
Matt Spinler16caaee2019-01-15 11:40:34 -0600472 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800473 setErrorResponse(asyncResp->res,
474 boost::beast::http::status::not_found,
Matt Spinler16caaee2019-01-15 11:40:34 -0600475 methodNotFoundDesc, notFoundMsg);
476 }
477 }
478 else
479 {
480 if (outputFailed)
481 {
482 setErrorResponse(
Lei YU28dd5ca2023-03-17 13:17:05 +0800483 asyncResp->res,
484 boost::beast::http::status::internal_server_error,
Matt Spinler16caaee2019-01-15 11:40:34 -0600485 "Method output failure", methodOutputFailedMsg);
486 }
487 else
488 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800489 asyncResp->res.jsonValue["status"] = "ok";
490 asyncResp->res.jsonValue["message"] = "200 OK";
491 asyncResp->res.jsonValue["data"] = methodResponse;
Matt Spinler16caaee2019-01-15 11:40:34 -0600492 }
493 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700494 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700495 }
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800496 InProgressActionData(const InProgressActionData&) = delete;
497 InProgressActionData(InProgressActionData&&) = delete;
498 InProgressActionData& operator=(const InProgressActionData&) = delete;
499 InProgressActionData& operator=(InProgressActionData&&) = delete;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700500
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500501 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700502 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800503 setErrorResponse(asyncResp->res,
504 boost::beast::http::status::bad_request, desc,
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600505 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700506 }
Lei YU28dd5ca2023-03-17 13:17:05 +0800507 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700508 std::string path;
509 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600510 std::string interfaceName;
Matt Spinler16caaee2019-01-15 11:40:34 -0600511 bool methodPassed = false;
512 bool methodFailed = false;
513 bool outputFailed = false;
Matt Spinler39a4e392019-01-15 11:53:13 -0600514 bool convertedToArray = false;
Matt Spinler16caaee2019-01-15 11:40:34 -0600515 nlohmann::json methodResponse;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700516 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700517};
518
Ed Tanous23a21a12020-07-25 04:45:05 +0000519inline std::vector<std::string> dbusArgSplit(const std::string& string)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700520{
521 std::vector<std::string> ret;
522 if (string.empty())
523 {
524 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700525 }
Ed Tanous0f0353b2019-10-24 11:37:51 -0700526 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700527 int containerDepth = 0;
528
529 for (std::string::const_iterator character = string.begin();
530 character != string.end(); character++)
531 {
532 ret.back() += *character;
533 switch (*character)
534 {
535 case ('a'):
536 break;
537 case ('('):
538 case ('{'):
539 containerDepth++;
540 break;
541 case ('}'):
542 case (')'):
543 containerDepth--;
544 if (containerDepth == 0)
545 {
546 if (character + 1 != string.end())
547 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700548 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700549 }
550 }
551 break;
552 default:
553 if (containerDepth == 0)
554 {
555 if (character + 1 != string.end())
556 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700557 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700558 }
559 }
560 break;
561 }
562 }
Matt Spinler4ae611d2019-01-11 15:37:06 -0600563
564 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700565}
566
Ed Tanous81ce6092020-12-17 16:54:55 +0000567inline int convertJsonToDbus(sd_bus_message* m, const std::string& argType,
568 const nlohmann::json& inputJson)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700569{
570 int r = 0;
Ed Tanous296579b2024-03-11 16:58:24 -0700571 BMCWEB_LOG_DEBUG("Converting {} to type: {}", inputJson, argType);
Ed Tanous81ce6092020-12-17 16:54:55 +0000572 const std::vector<std::string> argTypes = dbusArgSplit(argType);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700573
Ed Tanous1abe55e2018-09-05 08:30:59 -0700574 // Assume a single object for now.
Ed Tanous81ce6092020-12-17 16:54:55 +0000575 const nlohmann::json* j = &inputJson;
576 nlohmann::json::const_iterator jIt = inputJson.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700577
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500578 for (const std::string& argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700579 {
580 // If we are decoding multiple objects, grab the pointer to the
581 // iterator, and increment it for the next loop
582 if (argTypes.size() > 1)
583 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000584 if (jIt == inputJson.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700585 {
586 return -2;
587 }
588 j = &*jIt;
589 jIt++;
590 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500591 const int64_t* intValue = j->get_ptr<const int64_t*>();
592 const std::string* stringValue = j->get_ptr<const std::string*>();
593 const double* doubleValue = j->get_ptr<const double*>();
594 const bool* b = j->get_ptr<const bool*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700595 int64_t v = 0;
596 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700597
Ed Tanous1abe55e2018-09-05 08:30:59 -0700598 // Do some basic type conversions that make sense. uint can be
599 // converted to int. int and uint can be converted to double
Ed Tanous66664f22019-10-11 13:05:49 -0700600 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700601 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500602 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700603 if (uintValue != nullptr)
604 {
605 v = static_cast<int64_t>(*uintValue);
606 intValue = &v;
607 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700608 }
Ed Tanous66664f22019-10-11 13:05:49 -0700609 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700610 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500611 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700612 if (uintValue != nullptr)
613 {
614 d = static_cast<double>(*uintValue);
615 doubleValue = &d;
616 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700617 }
Ed Tanous66664f22019-10-11 13:05:49 -0700618 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700619 {
Ed Tanous66664f22019-10-11 13:05:49 -0700620 if (intValue != nullptr)
621 {
622 d = static_cast<double>(*intValue);
623 doubleValue = &d;
624 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700625 }
626
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700627 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700628 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700629 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700630 {
631 return -1;
632 }
Ed Tanous271584a2019-07-09 16:24:22 -0700633 r = sd_bus_message_append_basic(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500634 m, argCode[0], static_cast<const void*>(stringValue->data()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700635 if (r < 0)
636 {
637 return r;
638 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700639 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700640 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700641 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700642 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700643 {
644 return -1;
645 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500646 if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
647 (*intValue > std::numeric_limits<int32_t>::max()))
648 {
649 return -ERANGE;
650 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700651 int32_t i = static_cast<int32_t>(*intValue);
652 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700653 if (r < 0)
654 {
655 return r;
656 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700657 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700658 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700659 {
660 // lots of ways bool could be represented here. Try them all
Ed Tanouse662eae2022-01-25 10:39:19 -0800661 int boolInt = 0;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700662 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700663 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500664 if (*intValue == 1)
665 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800666 boolInt = 1;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500667 }
668 else if (*intValue == 0)
669 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800670 boolInt = 0;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500671 }
672 else
673 {
674 return -ERANGE;
675 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700676 }
677 else if (b != nullptr)
678 {
Matt Spinlera2f02632019-01-18 10:15:35 -0600679 boolInt = *b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700680 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700681 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700682 {
Ed Tanous18f8f602023-07-18 10:07:23 -0700683 if (!stringValue->empty())
684 {
685 if (stringValue->front() == 't' ||
686 stringValue->front() == 'T')
687 {
688 boolInt = 1;
689 }
690 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700691 }
692 else
693 {
694 return -1;
695 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700696 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700697 if (r < 0)
698 {
699 return r;
700 }
701 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700702 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700703 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700704 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700705 {
706 return -1;
707 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500708 if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
709 (*intValue > std::numeric_limits<int16_t>::max()))
710 {
711 return -ERANGE;
712 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700713 int16_t n = static_cast<int16_t>(*intValue);
714 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700715 if (r < 0)
716 {
717 return r;
718 }
719 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700720 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700721 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700722 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700723 {
724 return -1;
725 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700726 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700727 if (r < 0)
728 {
729 return r;
730 }
731 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700732 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700733 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500734 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700735 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700736 {
737 return -1;
738 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000739 if (*uintValue > std::numeric_limits<uint8_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500740 {
741 return -ERANGE;
742 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700743 uint8_t y = static_cast<uint8_t>(*uintValue);
744 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700745 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700746 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700747 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500748 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700749 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700750 {
751 return -1;
752 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000753 if (*uintValue > std::numeric_limits<uint16_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500754 {
755 return -ERANGE;
756 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700757 uint16_t q = static_cast<uint16_t>(*uintValue);
758 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700759 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700760 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700761 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500762 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700763 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700764 {
765 return -1;
766 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000767 if (*uintValue > std::numeric_limits<uint32_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500768 {
769 return -ERANGE;
770 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700771 uint32_t u = static_cast<uint32_t>(*uintValue);
772 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700773 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700774 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700775 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500776 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700777 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700778 {
779 return -1;
780 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700781 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700782 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700783 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700784 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500785 if (doubleValue == nullptr)
786 {
787 return -1;
788 }
789 if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
790 (*doubleValue > std::numeric_limits<double>::max()))
791 {
792 return -ERANGE;
793 }
Ed Tanous07900812024-05-06 15:41:30 -0700794 r = sd_bus_message_append_basic(m, argCode[0], doubleValue);
795 if (r < 0)
796 {
797 return r;
798 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700799 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700800 else if (argCode.starts_with("a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700801 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700802 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700803 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700804 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700805 if (r < 0)
806 {
807 return r;
808 }
809
Ed Tanous0dfeda62019-10-24 11:21:38 -0700810 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700811 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700812 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700813 if (r < 0)
814 {
815 return r;
816 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700817 }
818 sd_bus_message_close_container(m);
819 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700820 else if (argCode.starts_with("v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700821 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700822 std::string containedType = argCode.substr(1);
Ed Tanous62598e32023-07-17 17:06:25 -0700823 BMCWEB_LOG_DEBUG("variant type: {} appending variant of type: {}",
824 argCode, containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700825 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700826 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700827 if (r < 0)
828 {
829 return r;
830 }
831
Ed Tanous81ce6092020-12-17 16:54:55 +0000832 r = convertJsonToDbus(m, containedType, inputJson);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700833 if (r < 0)
834 {
835 return r;
836 }
837
838 r = sd_bus_message_close_container(m);
839 if (r < 0)
840 {
841 return r;
842 }
843 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700844 else if (argCode.starts_with("(") && argCode.ends_with(")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700845 {
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300846 std::string containedType = argCode.substr(1, argCode.size() - 2);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700847 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700848 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800849 if (r < 0)
850 {
851 return r;
852 }
853
Ed Tanous1abe55e2018-09-05 08:30:59 -0700854 nlohmann::json::const_iterator it = j->begin();
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300855 for (const std::string& argCode2 : dbusArgSplit(containedType))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700856 {
857 if (it == j->end())
858 {
859 return -1;
860 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000861 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700862 if (r < 0)
863 {
864 return r;
865 }
866 it++;
867 }
868 r = sd_bus_message_close_container(m);
869 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700870 else if (argCode.starts_with("{") && argCode.ends_with("}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700871 {
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300872 std::string containedType = argCode.substr(1, argCode.size() - 2);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700873 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700874 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800875 if (r < 0)
876 {
877 return r;
878 }
879
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700880 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700881 if (codes.size() != 2)
882 {
883 return -1;
884 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700885 const std::string& keyType = codes[0];
886 const std::string& valueType = codes[1];
Ed Tanous0bdda662023-08-03 17:27:34 -0700887 const nlohmann::json::object_t* arr =
888 j->get_ptr<const nlohmann::json::object_t*>();
889 if (arr == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700890 {
Ed Tanous0bdda662023-08-03 17:27:34 -0700891 return -1;
892 }
893 for (const auto& it : *arr)
894 {
895 r = convertJsonToDbus(m, keyType, it.first);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700896 if (r < 0)
897 {
898 return r;
899 }
900
Ed Tanous0bdda662023-08-03 17:27:34 -0700901 r = convertJsonToDbus(m, valueType, it.second);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700902 if (r < 0)
903 {
904 return r;
905 }
906 }
907 r = sd_bus_message_close_container(m);
908 }
909 else
910 {
911 return -2;
912 }
913 if (r < 0)
914 {
915 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700916 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700917
Ed Tanous1abe55e2018-09-05 08:30:59 -0700918 if (argTypes.size() > 1)
919 {
920 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700921 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700922 }
Matt Spinler127ea542019-01-14 11:04:28 -0600923
924 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700925}
926
Matt Spinlerd22a7132019-01-14 12:14:30 -0600927template <typename T>
Patrick Williams59d494e2022-07-22 19:26:55 -0500928int readMessageItem(const std::string& typeCode, sdbusplus::message_t& m,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500929 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600930{
931 T value;
Ed Tanousf79ce6a2024-03-20 12:27:06 -0700932 // When T == char*, this warning fires. Unclear how to resolve
933 // Given that sd-bus takes a void pointer to a char*, and that's
934 // Not something we can fix.
935 // NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600936 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
937 if (r < 0)
938 {
Ed Tanous62598e32023-07-17 17:06:25 -0700939 BMCWEB_LOG_ERROR("sd_bus_message_read_basic on type {} failed!",
940 typeCode);
Matt Spinlerd22a7132019-01-14 12:14:30 -0600941 return r;
942 }
943
944 data = value;
945 return 0;
946}
947
Patrick Williams59d494e2022-07-22 19:26:55 -0500948int convertDBusToJSON(const std::string& returnType, sdbusplus::message_t& m,
949 nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600950
Ed Tanous23a21a12020-07-25 04:45:05 +0000951inline int readDictEntryFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -0500952 sdbusplus::message_t& m,
Ed Tanous23a21a12020-07-25 04:45:05 +0000953 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600954{
955 std::vector<std::string> types = dbusArgSplit(typeCode);
956 if (types.size() != 2)
957 {
Ed Tanous62598e32023-07-17 17:06:25 -0700958 BMCWEB_LOG_ERROR("wrong number contained types in dictionary: {}",
959 types.size());
Matt Spinler6df8f992019-01-14 12:47:47 -0600960 return -1;
961 }
962
963 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
964 typeCode.c_str());
965 if (r < 0)
966 {
Ed Tanous62598e32023-07-17 17:06:25 -0700967 BMCWEB_LOG_ERROR("sd_bus_message_enter_container with rc {}", r);
Matt Spinler6df8f992019-01-14 12:47:47 -0600968 return r;
969 }
970
971 nlohmann::json key;
972 r = convertDBusToJSON(types[0], m, key);
973 if (r < 0)
974 {
975 return r;
976 }
977
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500978 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -0600979 if (keyPtr == nullptr)
980 {
981 // json doesn't support non-string keys. If we hit this condition,
982 // convert the result to a string so we can proceed
Ed Tanous71f52d92021-02-19 08:51:17 -0800983 key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500984 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -0700985 // in theory this can't fail now, but lets be paranoid about it
986 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -0600987 if (keyPtr == nullptr)
988 {
989 return -1;
990 }
991 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500992 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -0600993
994 r = convertDBusToJSON(types[1], m, value);
995 if (r < 0)
996 {
997 return r;
998 }
999
1000 r = sd_bus_message_exit_container(m.get());
1001 if (r < 0)
1002 {
Ed Tanous62598e32023-07-17 17:06:25 -07001003 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001004 return r;
1005 }
1006
1007 return 0;
1008}
1009
Ed Tanous23a21a12020-07-25 04:45:05 +00001010inline int readArrayFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001011 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -06001012{
1013 if (typeCode.size() < 2)
1014 {
Ed Tanous62598e32023-07-17 17:06:25 -07001015 BMCWEB_LOG_ERROR("Type code {} too small for an array", typeCode);
Matt Spinler6df8f992019-01-14 12:47:47 -06001016 return -1;
1017 }
1018
1019 std::string containedType = typeCode.substr(1);
1020
1021 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
1022 containedType.c_str());
1023 if (r < 0)
1024 {
Ed Tanous62598e32023-07-17 17:06:25 -07001025 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler6df8f992019-01-14 12:47:47 -06001026 return r;
1027 }
1028
Ed Tanous11ba3972022-07-11 09:50:41 -07001029 bool dict = containedType.starts_with("{") && containedType.ends_with("}");
Matt Spinler6df8f992019-01-14 12:47:47 -06001030
1031 if (dict)
1032 {
1033 // Remove the { }
1034 containedType = containedType.substr(1, containedType.size() - 2);
1035 data = nlohmann::json::object();
1036 }
1037 else
1038 {
1039 data = nlohmann::json::array();
1040 }
1041
1042 while (true)
1043 {
Ed Tanouse662eae2022-01-25 10:39:19 -08001044 r = sd_bus_message_at_end(m.get(), 0);
Matt Spinler6df8f992019-01-14 12:47:47 -06001045 if (r < 0)
1046 {
Ed Tanous62598e32023-07-17 17:06:25 -07001047 BMCWEB_LOG_ERROR("sd_bus_message_at_end failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001048 return r;
1049 }
1050
1051 if (r > 0)
1052 {
1053 break;
1054 }
1055
1056 // Dictionaries are only ever seen in an array
1057 if (dict)
1058 {
1059 r = readDictEntryFromMessage(containedType, m, data);
1060 if (r < 0)
1061 {
1062 return r;
1063 }
1064 }
1065 else
1066 {
1067 data.push_back(nlohmann::json());
1068
1069 r = convertDBusToJSON(containedType, m, data.back());
1070 if (r < 0)
1071 {
1072 return r;
1073 }
1074 }
1075 }
1076
1077 r = sd_bus_message_exit_container(m.get());
1078 if (r < 0)
1079 {
Ed Tanous62598e32023-07-17 17:06:25 -07001080 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001081 return r;
1082 }
1083
1084 return 0;
1085}
1086
Ed Tanous23a21a12020-07-25 04:45:05 +00001087inline int readStructFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001088 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001089{
1090 if (typeCode.size() < 3)
1091 {
Ed Tanous62598e32023-07-17 17:06:25 -07001092 BMCWEB_LOG_ERROR("Type code {} too small for a struct", typeCode);
Matt Spinler75c6c672019-01-14 13:01:46 -06001093 return -1;
1094 }
1095
1096 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1097 std::vector<std::string> types = dbusArgSplit(containedTypes);
1098
1099 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1100 containedTypes.c_str());
1101 if (r < 0)
1102 {
Ed Tanous62598e32023-07-17 17:06:25 -07001103 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler75c6c672019-01-14 13:01:46 -06001104 return r;
1105 }
1106
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001107 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001108 {
1109 data.push_back(nlohmann::json());
1110 r = convertDBusToJSON(type, m, data.back());
1111 if (r < 0)
1112 {
1113 return r;
1114 }
1115 }
1116
1117 r = sd_bus_message_exit_container(m.get());
1118 if (r < 0)
1119 {
Ed Tanous62598e32023-07-17 17:06:25 -07001120 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler75c6c672019-01-14 13:01:46 -06001121 return r;
1122 }
1123 return 0;
1124}
1125
Patrick Williams59d494e2022-07-22 19:26:55 -05001126inline int readVariantFromMessage(sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001127{
Ed Tanous543f4402022-01-06 13:12:53 -08001128 const char* containerType = nullptr;
Ed Tanous99131cd2019-10-24 11:12:47 -07001129 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001130 if (r < 0)
1131 {
Ed Tanous62598e32023-07-17 17:06:25 -07001132 BMCWEB_LOG_ERROR("sd_bus_message_peek_type failed");
Matt Spinler89c19702019-01-14 13:13:00 -06001133 return r;
1134 }
1135
1136 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1137 containerType);
1138 if (r < 0)
1139 {
Ed Tanous62598e32023-07-17 17:06:25 -07001140 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler89c19702019-01-14 13:13:00 -06001141 return r;
1142 }
1143
1144 r = convertDBusToJSON(containerType, m, data);
1145 if (r < 0)
1146 {
1147 return r;
1148 }
1149
1150 r = sd_bus_message_exit_container(m.get());
1151 if (r < 0)
1152 {
Ed Tanous62598e32023-07-17 17:06:25 -07001153 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed");
Matt Spinler89c19702019-01-14 13:13:00 -06001154 return r;
1155 }
1156
1157 return 0;
1158}
1159
Ed Tanous23a21a12020-07-25 04:45:05 +00001160inline int convertDBusToJSON(const std::string& returnType,
Patrick Williams59d494e2022-07-22 19:26:55 -05001161 sdbusplus::message_t& m, nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001162{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001163 int r = 0;
1164 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1165
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001166 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001167 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001168 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001169 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001170 {
1171 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001172 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001173 }
1174
Ed Tanousd4d25792020-09-29 15:15:03 -07001175 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001176 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001177 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001178 if (r < 0)
1179 {
1180 return r;
1181 }
1182 }
1183 else if (typeCode == "b")
1184 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001185 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001186 if (r < 0)
1187 {
1188 return r;
1189 }
1190
Matt Spinlerf39420c2019-01-30 12:57:18 -06001191 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001192 }
1193 else if (typeCode == "u")
1194 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001195 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001196 if (r < 0)
1197 {
1198 return r;
1199 }
1200 }
1201 else if (typeCode == "i")
1202 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001203 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001204 if (r < 0)
1205 {
1206 return r;
1207 }
1208 }
1209 else if (typeCode == "x")
1210 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001211 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001212 if (r < 0)
1213 {
1214 return r;
1215 }
1216 }
1217 else if (typeCode == "t")
1218 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001219 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001220 if (r < 0)
1221 {
1222 return r;
1223 }
1224 }
1225 else if (typeCode == "n")
1226 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001227 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001228 if (r < 0)
1229 {
1230 return r;
1231 }
1232 }
1233 else if (typeCode == "q")
1234 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001235 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001236 if (r < 0)
1237 {
1238 return r;
1239 }
1240 }
1241 else if (typeCode == "y")
1242 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001243 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001244 if (r < 0)
1245 {
1246 return r;
1247 }
1248 }
1249 else if (typeCode == "d")
1250 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001251 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001252 if (r < 0)
1253 {
1254 return r;
1255 }
1256 }
1257 else if (typeCode == "h")
1258 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001259 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001260 if (r < 0)
1261 {
1262 return r;
1263 }
1264 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001265 else if (typeCode.starts_with("a"))
Matt Spinler6df8f992019-01-14 12:47:47 -06001266 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001267 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001268 if (r < 0)
1269 {
1270 return r;
1271 }
1272 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001273 else if (typeCode.starts_with("(") && typeCode.ends_with(")"))
Matt Spinler75c6c672019-01-14 13:01:46 -06001274 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001275 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001276 if (r < 0)
1277 {
1278 return r;
1279 }
1280 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001281 else if (typeCode.starts_with("v"))
Matt Spinler89c19702019-01-14 13:13:00 -06001282 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001283 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001284 if (r < 0)
1285 {
1286 return r;
1287 }
1288 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001289 else
1290 {
Ed Tanous62598e32023-07-17 17:06:25 -07001291 BMCWEB_LOG_ERROR("Invalid D-Bus signature type {}", typeCode);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001292 return -2;
1293 }
1294 }
1295
Matt Spinler16caaee2019-01-15 11:40:34 -06001296 return 0;
1297}
1298
Ed Tanousb5a76932020-09-29 16:16:58 -07001299inline void handleMethodResponse(
1300 const std::shared_ptr<InProgressActionData>& transaction,
Patrick Williams59d494e2022-07-22 19:26:55 -05001301 sdbusplus::message_t& m, const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001302{
Matt Spinler39a4e392019-01-15 11:53:13 -06001303 nlohmann::json data;
1304
1305 int r = convertDBusToJSON(returnType, m, data);
1306 if (r < 0)
1307 {
1308 transaction->outputFailed = true;
1309 return;
1310 }
1311
1312 if (data.is_null())
1313 {
1314 return;
1315 }
1316
1317 if (transaction->methodResponse.is_null())
1318 {
1319 transaction->methodResponse = std::move(data);
1320 return;
1321 }
1322
1323 // If they're both dictionaries or arrays, merge into one.
1324 // Otherwise, make the results an array with every result
1325 // an entry. Could also just fail in that case, but it
1326 // seems better to get the data back somehow.
Ed Tanous0bdda662023-08-03 17:27:34 -07001327 nlohmann::json::object_t* dataobj =
1328 data.get_ptr<nlohmann::json::object_t*>();
1329 if (transaction->methodResponse.is_object() && dataobj != nullptr)
Matt Spinler39a4e392019-01-15 11:53:13 -06001330 {
Ed Tanous0bdda662023-08-03 17:27:34 -07001331 for (auto& obj : *dataobj)
Matt Spinler39a4e392019-01-15 11:53:13 -06001332 {
1333 // Note: Will overwrite the data for a duplicate key
Ed Tanous0bdda662023-08-03 17:27:34 -07001334 transaction->methodResponse.emplace(obj.first,
1335 std::move(obj.second));
Matt Spinler39a4e392019-01-15 11:53:13 -06001336 }
1337 return;
1338 }
1339
Ed Tanous0bdda662023-08-03 17:27:34 -07001340 nlohmann::json::array_t* dataarr = data.get_ptr<nlohmann::json::array_t*>();
1341 if (transaction->methodResponse.is_array() && dataarr != nullptr)
Matt Spinler39a4e392019-01-15 11:53:13 -06001342 {
Ed Tanous0bdda662023-08-03 17:27:34 -07001343 for (auto& obj : *dataarr)
Matt Spinler39a4e392019-01-15 11:53:13 -06001344 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001345 transaction->methodResponse.emplace_back(std::move(obj));
Matt Spinler39a4e392019-01-15 11:53:13 -06001346 }
1347 return;
1348 }
1349
1350 if (!transaction->convertedToArray)
1351 {
1352 // They are different types. May as well turn them into an array
1353 nlohmann::json j = std::move(transaction->methodResponse);
1354 transaction->methodResponse = nlohmann::json::array();
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001355 transaction->methodResponse.emplace_back(std::move(j));
1356 transaction->methodResponse.emplace_back(std::move(data));
Matt Spinler39a4e392019-01-15 11:53:13 -06001357 transaction->convertedToArray = true;
1358 }
1359 else
1360 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001361 transaction->methodResponse.emplace_back(std::move(data));
Matt Spinler39a4e392019-01-15 11:53:13 -06001362 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001363}
1364
Ed Tanousb5a76932020-09-29 16:16:58 -07001365inline void findActionOnInterface(
1366 const std::shared_ptr<InProgressActionData>& transaction,
1367 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001368{
Ed Tanous62598e32023-07-17 17:06:25 -07001369 BMCWEB_LOG_DEBUG("findActionOnInterface for connection {}", connectionName);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001370 crow::connections::systemBus->async_method_call(
1371 [transaction, connectionName{std::string(connectionName)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001372 const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001373 const std::string& introspectXml) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001374 BMCWEB_LOG_DEBUG("got xml:\n {}", introspectXml);
1375 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001376 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001377 BMCWEB_LOG_ERROR(
1378 "Introspect call failed with error: {} on process: {}",
1379 ec.message(), connectionName);
1380 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001381 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001382 tinyxml2::XMLDocument doc;
1383
1384 doc.Parse(introspectXml.data(), introspectXml.size());
1385 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1386 if (pRoot == nullptr)
1387 {
1388 BMCWEB_LOG_ERROR("XML document failed to parse {}",
1389 connectionName);
1390 return;
1391 }
1392 tinyxml2::XMLElement* interfaceNode =
1393 pRoot->FirstChildElement("interface");
1394 while (interfaceNode != nullptr)
1395 {
1396 const char* thisInterfaceName =
1397 interfaceNode->Attribute("name");
1398 if (thisInterfaceName != nullptr)
1399 {
1400 if (!transaction->interfaceName.empty() &&
1401 (transaction->interfaceName != thisInterfaceName))
1402 {
1403 interfaceNode =
1404 interfaceNode->NextSiblingElement("interface");
1405 continue;
1406 }
1407
1408 tinyxml2::XMLElement* methodNode =
1409 interfaceNode->FirstChildElement("method");
1410 while (methodNode != nullptr)
1411 {
1412 const char* thisMethodName =
1413 methodNode->Attribute("name");
1414 BMCWEB_LOG_DEBUG("Found method: {}", thisMethodName);
1415 if (thisMethodName != nullptr &&
1416 thisMethodName == transaction->methodName)
1417 {
1418 BMCWEB_LOG_DEBUG(
1419 "Found method named {} on interface {}",
1420 thisMethodName, thisInterfaceName);
1421 sdbusplus::message_t m =
1422 crow::connections::systemBus->new_method_call(
1423 connectionName.c_str(),
1424 transaction->path.c_str(),
1425 thisInterfaceName,
1426 transaction->methodName.c_str());
1427
1428 tinyxml2::XMLElement* argumentNode =
1429 methodNode->FirstChildElement("arg");
1430
1431 std::string returnType;
1432
1433 // Find the output type
1434 while (argumentNode != nullptr)
1435 {
1436 const char* argDirection =
1437 argumentNode->Attribute("direction");
1438 const char* argType =
1439 argumentNode->Attribute("type");
1440 if (argDirection != nullptr &&
1441 argType != nullptr &&
1442 std::string(argDirection) == "out")
1443 {
1444 returnType = argType;
1445 break;
1446 }
1447 argumentNode =
1448 argumentNode->NextSiblingElement("arg");
1449 }
1450
1451 auto argIt = transaction->arguments.begin();
1452
1453 argumentNode = methodNode->FirstChildElement("arg");
1454
1455 while (argumentNode != nullptr)
1456 {
1457 const char* argDirection =
1458 argumentNode->Attribute("direction");
1459 const char* argType =
1460 argumentNode->Attribute("type");
1461 if (argDirection != nullptr &&
1462 argType != nullptr &&
1463 std::string(argDirection) == "in")
1464 {
1465 if (argIt == transaction->arguments.end())
1466 {
1467 transaction->setErrorStatus(
1468 "Invalid method args");
1469 return;
1470 }
1471 if (convertJsonToDbus(m.get(),
1472 std::string(argType),
1473 *argIt) < 0)
1474 {
1475 transaction->setErrorStatus(
1476 "Invalid method arg type");
1477 return;
1478 }
1479
1480 argIt++;
1481 }
1482 argumentNode =
1483 argumentNode->NextSiblingElement("arg");
1484 }
1485
1486 crow::connections::systemBus->async_send(
1487 m, [transaction, returnType](
1488 const boost::system::error_code& ec2,
1489 sdbusplus::message_t& m2) {
1490 if (ec2)
1491 {
1492 transaction->methodFailed = true;
1493 const sd_bus_error* e = m2.get_error();
1494
1495 if (e != nullptr)
1496 {
1497 setErrorResponse(
1498 transaction->asyncResp->res,
1499 boost::beast::http::status::
1500 bad_request,
1501 e->name, e->message);
1502 }
1503 else
1504 {
1505 setErrorResponse(
1506 transaction->asyncResp->res,
1507 boost::beast::http::status::
1508 bad_request,
1509 "Method call failed",
1510 methodFailedMsg);
1511 }
1512 return;
1513 }
1514 transaction->methodPassed = true;
1515
1516 handleMethodResponse(transaction, m2,
1517 returnType);
1518 });
1519 break;
1520 }
1521 methodNode = methodNode->NextSiblingElement("method");
1522 }
1523 }
1524 interfaceNode = interfaceNode->NextSiblingElement("interface");
1525 }
1526 },
Ed Tanous1abe55e2018-09-05 08:30:59 -07001527 connectionName, transaction->path,
1528 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001529}
1530
zhanghch058d1b46d2021-04-01 11:18:24 +08001531inline void handleAction(const crow::Request& req,
1532 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001533 const std::string& objectPath,
1534 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001535{
Ed Tanous62598e32023-07-17 17:06:25 -07001536 BMCWEB_LOG_DEBUG("handleAction on path: {} and method {}", objectPath,
1537 methodName);
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001538 nlohmann::json requestDbusData;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001539
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001540 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
1541 if (ret == JsonParseResult::BadContentType)
1542 {
1543 setErrorResponse(asyncResp->res,
1544 boost::beast::http::status::unsupported_media_type,
1545 invalidContentType, unsupportedMediaMsg);
1546 return;
1547 }
1548 if (ret != JsonParseResult::Success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001549 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001550 setErrorResponse(asyncResp->res,
1551 boost::beast::http::status::bad_request, noJsonDesc,
1552 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001553 return;
1554 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001555 nlohmann::json::iterator data = requestDbusData.find("data");
1556 if (data == requestDbusData.end())
1557 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001558 setErrorResponse(asyncResp->res,
1559 boost::beast::http::status::bad_request, noJsonDesc,
1560 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001561 return;
1562 }
1563
1564 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001565 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001566 setErrorResponse(asyncResp->res,
1567 boost::beast::http::status::bad_request, noJsonDesc,
1568 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001569 return;
1570 }
Lei YU28dd5ca2023-03-17 13:17:05 +08001571 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001572
1573 transaction->path = objectPath;
1574 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001575 transaction->arguments = std::move(*data);
George Liu2b731192023-01-11 16:27:13 +08001576 dbus::utility::getDbusObject(
1577 objectPath, {},
Ed Tanous1abe55e2018-09-05 08:30:59 -07001578 [transaction](
George Liu2b731192023-01-11 16:27:13 +08001579 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001580 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1581 interfaceNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001582 if (ec || interfaceNames.empty())
1583 {
1584 BMCWEB_LOG_ERROR("Can't find object");
1585 setErrorResponse(transaction->asyncResp->res,
1586 boost::beast::http::status::not_found,
1587 notFoundDesc, notFoundMsg);
1588 return;
1589 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001590
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001591 BMCWEB_LOG_DEBUG("GetObject returned {} object(s)",
1592 interfaceNames.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001593
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001594 for (const std::pair<std::string, std::vector<std::string>>&
1595 object : interfaceNames)
1596 {
1597 findActionOnInterface(transaction, object.first);
1598 }
1599 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001600}
1601
zhanghch058d1b46d2021-04-01 11:18:24 +08001602inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1603 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001604{
Ed Tanous62598e32023-07-17 17:06:25 -07001605 BMCWEB_LOG_DEBUG("handleDelete on path: {}", objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06001606
George Liu2b731192023-01-11 16:27:13 +08001607 dbus::utility::getDbusObject(
1608 objectPath, {},
zhanghch058d1b46d2021-04-01 11:18:24 +08001609 [asyncResp, objectPath](
George Liu2b731192023-01-11 16:27:13 +08001610 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001611 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1612 interfaceNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001613 if (ec || interfaceNames.empty())
1614 {
1615 BMCWEB_LOG_ERROR("Can't find object");
1616 setErrorResponse(asyncResp->res,
1617 boost::beast::http::status::method_not_allowed,
1618 methodNotAllowedDesc, methodNotAllowedMsg);
1619 return;
1620 }
Matt Spinlerde818812018-12-11 16:39:20 -06001621
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001622 auto transaction =
1623 std::make_shared<InProgressActionData>(asyncResp);
1624 transaction->path = objectPath;
1625 transaction->methodName = "Delete";
1626 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
Matt Spinlerde818812018-12-11 16:39:20 -06001627
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001628 for (const std::pair<std::string, std::vector<std::string>>&
1629 object : interfaceNames)
1630 {
1631 findActionOnInterface(transaction, object.first);
1632 }
1633 });
Matt Spinlerde818812018-12-11 16:39:20 -06001634}
1635
zhanghch058d1b46d2021-04-01 11:18:24 +08001636inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1637 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001638{
George Liu7a1dbc42022-12-07 16:03:22 +08001639 dbus::utility::getSubTreePaths(
1640 objectPath, depth, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001641 [asyncResp](
George Liu7a1dbc42022-12-07 16:03:22 +08001642 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001643 const dbus::utility::MapperGetSubTreePathsResponse& objectPaths) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001644 if (ec)
1645 {
1646 setErrorResponse(asyncResp->res,
1647 boost::beast::http::status::not_found,
1648 notFoundDesc, notFoundMsg);
1649 }
1650 else
1651 {
1652 asyncResp->res.jsonValue["status"] = "ok";
1653 asyncResp->res.jsonValue["message"] = "200 OK";
1654 asyncResp->res.jsonValue["data"] = objectPaths;
1655 }
1656 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001657}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001658
zhanghch058d1b46d2021-04-01 11:18:24 +08001659inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1660 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001661{
Ed Tanous62598e32023-07-17 17:06:25 -07001662 BMCWEB_LOG_DEBUG("Doing enumerate on {}", objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07001663
Ed Tanous14766872022-03-15 10:44:42 -07001664 asyncResp->res.jsonValue["message"] = "200 OK";
1665 asyncResp->res.jsonValue["status"] = "ok";
1666 asyncResp->res.jsonValue["data"] = nlohmann::json::object();
Ed Tanous049a0512018-11-01 13:58:42 -07001667
George Liue99073f2022-12-09 11:06:16 +08001668 dbus::utility::getSubTree(
1669 objectPath, 0, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001670 [objectPath, asyncResp](
George Liue99073f2022-12-09 11:06:16 +08001671 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001672 const dbus::utility::MapperGetSubTreeResponse& objectNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001673 auto transaction = std::make_shared<InProgressEnumerateData>(
1674 objectPath, asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001675
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001676 transaction->subtree =
1677 std::make_shared<dbus::utility::MapperGetSubTreeResponse>(
1678 objectNames);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001679
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001680 if (ec)
1681 {
1682 BMCWEB_LOG_ERROR("GetSubTree failed on {}",
1683 transaction->objectPath);
1684 setErrorResponse(transaction->asyncResp->res,
1685 boost::beast::http::status::not_found,
1686 notFoundDesc, notFoundMsg);
1687 return;
1688 }
Ed Tanous64530012018-02-06 17:08:16 -08001689
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001690 // Add the data for the path passed in to the results
1691 // as if GetSubTree returned it, and continue on enumerating
1692 getObjectAndEnumerate(transaction);
1693 });
Ed Tanous64530012018-02-06 17:08:16 -08001694}
Ed Tanous911ac312017-08-15 09:37:42 -07001695
zhanghch058d1b46d2021-04-01 11:18:24 +08001696inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1697 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001698{
Ed Tanous62598e32023-07-17 17:06:25 -07001699 BMCWEB_LOG_DEBUG("handleGet: {} prop:{}", objectPath, destProperty);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001700 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001701 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001702
Ed Tanous1abe55e2018-09-05 08:30:59 -07001703 std::shared_ptr<std::string> path =
1704 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001705
George Liu2b731192023-01-11 16:27:13 +08001706 dbus::utility::getDbusObject(
1707 *path, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001708 [asyncResp, path,
George Liu2b731192023-01-11 16:27:13 +08001709 propertyName](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001710 const dbus::utility::MapperGetObject& objectNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001711 if (ec || objectNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001712 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001713 setErrorResponse(asyncResp->res,
1714 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001715 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001716 return;
1717 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001718 std::shared_ptr<nlohmann::json> response =
1719 std::make_shared<nlohmann::json>(nlohmann::json::object());
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001720 for (const std::pair<std::string, std::vector<std::string>>&
1721 connection : objectNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001722 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001723 const std::vector<std::string>& interfaceNames =
1724 connection.second;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001725
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001726 if (interfaceNames.empty())
1727 {
Lei YU65622a52025-01-20 09:45:50 +00001728 // mapper allows empty interfaces in case an
1729 // object does not implement any interface.
1730 continue;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001731 }
1732
1733 for (const std::string& interface : interfaceNames)
1734 {
1735 sdbusplus::message_t m =
1736 crow::connections::systemBus->new_method_call(
1737 connection.first.c_str(), path->c_str(),
1738 "org.freedesktop.DBus.Properties", "GetAll");
1739 m.append(interface);
1740 crow::connections::systemBus->async_send(
1741 m, [asyncResp, response,
1742 propertyName](const boost::system::error_code& ec2,
1743 sdbusplus::message_t& msg) {
1744 if (ec2)
1745 {
1746 BMCWEB_LOG_ERROR("Bad dbus request error: {}",
1747 ec2);
1748 }
1749 else
1750 {
1751 nlohmann::json properties;
1752 int r =
1753 convertDBusToJSON("a{sv}", msg, properties);
1754 if (r < 0)
Patrick Williams5a39f772023-10-20 11:20:21 -05001755 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001756 BMCWEB_LOG_ERROR(
1757 "convertDBusToJSON failed");
Patrick Williams5a39f772023-10-20 11:20:21 -05001758 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001759 else
Patrick Williams5a39f772023-10-20 11:20:21 -05001760 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001761 nlohmann::json::object_t* obj =
1762 properties.get_ptr<
1763 nlohmann::json::object_t*>();
1764 if (obj == nullptr)
1765 {
1766 return;
1767 }
1768 for (auto& prop : *obj)
1769 {
1770 // if property name is empty, or
1771 // matches our search query, add it
1772 // to the response json
1773
1774 if (propertyName->empty())
1775 {
1776 (*response)[prop.first] =
1777 std::move(prop.second);
1778 }
1779 else if (prop.first == *propertyName)
1780 {
1781 *response = std::move(prop.second);
1782 }
1783 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001784 }
1785 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001786 if (response.use_count() == 1)
1787 {
1788 if (!propertyName->empty() && response->empty())
1789 {
1790 setErrorResponse(
1791 asyncResp->res,
1792 boost::beast::http::status::not_found,
1793 propNotFoundDesc, notFoundMsg);
1794 }
1795 else
1796 {
1797 asyncResp->res.jsonValue["status"] = "ok";
1798 asyncResp->res.jsonValue["message"] =
1799 "200 OK";
1800 asyncResp->res.jsonValue["data"] =
1801 *response;
1802 }
1803 }
1804 });
1805 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001806 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001807 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001808}
1809
Ed Tanous1abe55e2018-09-05 08:30:59 -07001810struct AsyncPutRequest
1811{
Ed Tanous4e23a442022-06-06 09:57:26 -07001812 explicit AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
zhanghch058d1b46d2021-04-01 11:18:24 +08001813 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001814 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001815 ~AsyncPutRequest()
1816 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001817 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001818 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001819 setErrorResponse(asyncResp->res,
1820 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001821 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001822 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001823 }
1824
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001825 AsyncPutRequest(const AsyncPutRequest&) = delete;
1826 AsyncPutRequest(AsyncPutRequest&&) = delete;
1827 AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1828 AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1829
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001830 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001831 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001832 setErrorResponse(asyncResp->res,
1833 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001834 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001835 }
1836
zhanghch058d1b46d2021-04-01 11:18:24 +08001837 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001838 std::string objectPath;
1839 std::string propertyName;
1840 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001841};
1842
zhanghch058d1b46d2021-04-01 11:18:24 +08001843inline void handlePut(const crow::Request& req,
1844 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001845 const std::string& objectPath,
1846 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001847{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001848 if (destProperty.empty())
1849 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001850 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001851 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001852 return;
1853 }
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001854 nlohmann::json requestDbusData;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001855
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001856 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
1857 if (ret == JsonParseResult::BadContentType)
1858 {
1859 setErrorResponse(asyncResp->res,
1860 boost::beast::http::status::unsupported_media_type,
1861 invalidContentType, unsupportedMediaMsg);
1862 return;
1863 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001864
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001865 if (ret != JsonParseResult::Success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001866 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001867 setErrorResponse(asyncResp->res,
1868 boost::beast::http::status::bad_request, noJsonDesc,
1869 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001870 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001871 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001872
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001873 auto propertyIt = requestDbusData.find("data");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001874 if (propertyIt == requestDbusData.end())
1875 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001876 setErrorResponse(asyncResp->res,
1877 boost::beast::http::status::bad_request, noJsonDesc,
1878 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001879 return;
1880 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001881 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001882 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001883 transaction->objectPath = objectPath;
1884 transaction->propertyName = destProperty;
1885 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001886
George Liu2b731192023-01-11 16:27:13 +08001887 dbus::utility::getDbusObject(
1888 transaction->objectPath, {},
1889 [transaction](const boost::system::error_code& ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001890 const dbus::utility::MapperGetObject& objectNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001891 if (!ec2 && objectNames.empty())
1892 {
1893 setErrorResponse(transaction->asyncResp->res,
1894 boost::beast::http::status::not_found,
1895 propNotFoundDesc, notFoundMsg);
1896 return;
1897 }
Ed Tanous911ac312017-08-15 09:37:42 -07001898
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001899 for (const std::pair<std::string, std::vector<std::string>>&
1900 connection : objectNames)
1901 {
1902 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001903
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001904 crow::connections::systemBus->async_method_call(
1905 [connectionName{std::string(connectionName)},
1906 transaction](const boost::system::error_code& ec3,
1907 const std::string& introspectXml) {
1908 if (ec3)
Ed Tanousb0b61522024-08-06 10:20:49 -07001909 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001910 BMCWEB_LOG_ERROR(
1911 "Introspect call failed with error: {} on process: {}",
1912 ec3.message(), connectionName);
1913 transaction->setErrorStatus("Unexpected Error");
1914 return;
Ed Tanousb0b61522024-08-06 10:20:49 -07001915 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001916 tinyxml2::XMLDocument doc;
1917
1918 doc.Parse(introspectXml.c_str());
1919 tinyxml2::XMLNode* pRoot =
1920 doc.FirstChildElement("node");
1921 if (pRoot == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001922 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001923 BMCWEB_LOG_ERROR("XML document failed to parse: {}",
1924 introspectXml);
1925 transaction->setErrorStatus("Unexpected Error");
1926 return;
1927 }
1928 tinyxml2::XMLElement* ifaceNode =
1929 pRoot->FirstChildElement("interface");
1930 while (ifaceNode != nullptr)
1931 {
1932 const char* interfaceName =
1933 ifaceNode->Attribute("name");
1934 BMCWEB_LOG_DEBUG("found interface {}",
1935 interfaceName);
1936 tinyxml2::XMLElement* propNode =
1937 ifaceNode->FirstChildElement("property");
1938 while (propNode != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001939 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001940 const char* propertyName =
1941 propNode->Attribute("name");
1942 if (propertyName == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001943 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001944 BMCWEB_LOG_DEBUG(
1945 "Couldn't find name property");
1946 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001947 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001948 BMCWEB_LOG_DEBUG("Found property {}",
1949 propertyName);
1950 if (propertyName == transaction->propertyName)
Ed Tanous002d39b2022-05-31 08:59:27 -07001951 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001952 const char* argType =
1953 propNode->Attribute("type");
1954 if (argType != nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07001955 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001956 sdbusplus::message_t m =
1957 crow::connections::systemBus
1958 ->new_method_call(
1959 connectionName.c_str(),
1960 transaction->objectPath
1961 .c_str(),
1962 "org.freedesktop.DBus."
1963 "Properties",
1964 "Set");
1965 m.append(interfaceName,
1966 transaction->propertyName);
1967 int r = sd_bus_message_open_container(
1968 m.get(), SD_BUS_TYPE_VARIANT,
1969 argType);
1970 if (r < 0)
1971 {
1972 transaction->setErrorStatus(
1973 "Unexpected Error");
1974 return;
1975 }
1976 r = convertJsonToDbus(
1977 m.get(), argType,
1978 transaction->propertyValue);
1979 if (r < 0)
1980 {
1981 if (r == -ERANGE)
1982 {
1983 transaction->setErrorStatus(
1984 "Provided property value "
1985 "is out of range for the "
1986 "property type");
1987 }
1988 else
1989 {
1990 transaction->setErrorStatus(
1991 "Invalid arg type");
1992 }
1993 return;
1994 }
1995 r = sd_bus_message_close_container(
1996 m.get());
1997 if (r < 0)
1998 {
1999 transaction->setErrorStatus(
2000 "Unexpected Error");
2001 return;
2002 }
2003 crow::connections::systemBus
2004 ->async_send(
2005 m,
2006 [transaction](
2007 const boost::system::
2008 error_code& ec,
2009 sdbusplus::message_t& m2) {
2010 BMCWEB_LOG_DEBUG("sent");
2011 if (ec)
2012 {
2013 const sd_bus_error* e =
2014 m2.get_error();
2015 setErrorResponse(
2016 transaction
2017 ->asyncResp
2018 ->res,
2019 boost::beast::http::
2020 status::
2021 forbidden,
2022 (e) != nullptr
2023 ? e->name
2024 : ec.category()
2025 .name(),
2026 (e) != nullptr
2027 ? e->message
2028 : ec.message());
2029 }
2030 else
2031 {
2032 transaction->asyncResp
2033 ->res.jsonValue
2034 ["status"] =
2035 "ok";
2036 transaction->asyncResp
2037 ->res.jsonValue
2038 ["message"] =
2039 "200 OK";
2040 transaction->asyncResp
2041 ->res
2042 .jsonValue["data"] =
2043 nullptr;
2044 }
2045 });
Ed Tanous002d39b2022-05-31 08:59:27 -07002046 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002047 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002048 propNode =
2049 propNode->NextSiblingElement("property");
Ed Tanous1abe55e2018-09-05 08:30:59 -07002050 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002051 ifaceNode =
2052 ifaceNode->NextSiblingElement("interface");
Ed Tanous1abe55e2018-09-05 08:30:59 -07002053 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002054 },
2055 connectionName, transaction->objectPath,
2056 "org.freedesktop.DBus.Introspectable", "Introspect");
2057 }
2058 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07002059}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002060
zhanghch058d1b46d2021-04-01 11:18:24 +08002061inline void handleDBusUrl(const crow::Request& req,
2062 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002063 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002064{
Ed Tanous049a0512018-11-01 13:58:42 -07002065 // If accessing a single attribute, fill in and update objectPath,
2066 // otherwise leave destProperty blank
Ed Tanouse05aec52022-01-25 10:28:56 -08002067 std::string destProperty;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002068 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002069 size_t attrPosition = objectPath.find(attrSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002070 if (attrPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002071 {
2072 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2073 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002074 objectPath.resize(attrPosition);
Ed Tanous049a0512018-11-01 13:58:42 -07002075 }
2076
Ed Tanousb41187f2019-10-24 16:30:02 -07002077 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002078 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002079 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002080 size_t actionPosition = objectPath.find(actionSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002081 if (actionPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002082 {
2083 std::string postProperty =
2084 objectPath.substr((actionPosition + strlen(actionSeperator)),
2085 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002086 objectPath.resize(actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002087 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002088 return;
2089 }
2090 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002091 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002092 {
Ed Tanous11ba3972022-07-11 09:50:41 -07002093 if (objectPath.ends_with("/enumerate"))
Ed Tanous049a0512018-11-01 13:58:42 -07002094 {
2095 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2096 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002097 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002098 }
Ed Tanous11ba3972022-07-11 09:50:41 -07002099 else if (objectPath.ends_with("/list"))
Ed Tanous049a0512018-11-01 13:58:42 -07002100 {
2101 objectPath.erase(objectPath.end() - sizeof("list"),
2102 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002103 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002104 }
2105 else
2106 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002107 // Trim any trailing "/" at the end
Ed Tanous11ba3972022-07-11 09:50:41 -07002108 if (objectPath.ends_with("/"))
Ed Tanousf839dfe2018-11-12 11:11:15 -08002109 {
2110 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002111 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002112 }
2113 else
2114 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002115 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002116 }
Ed Tanous049a0512018-11-01 13:58:42 -07002117 }
2118 return;
2119 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002120 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002121 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002122 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002123 return;
2124 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002125 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002126 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002127 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002128 return;
2129 }
Ed Tanous049a0512018-11-01 13:58:42 -07002130
zhanghch058d1b46d2021-04-01 11:18:24 +08002131 setErrorResponse(asyncResp->res,
2132 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002133 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002134}
2135
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002136inline void handleBusSystemPost(
2137 const crow::Request& req,
2138 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2139 const std::string& processName, const std::string& requestedPath)
Ed Tanous1656b292022-05-04 11:33:42 -07002140{
2141 std::vector<std::string> strs;
Ed Tanous50ebd4a2023-01-19 19:03:17 -08002142
2143 bmcweb::split(strs, requestedPath, '/');
Ed Tanous1656b292022-05-04 11:33:42 -07002144 std::string objectPath;
2145 std::string interfaceName;
2146 std::string methodName;
2147 auto it = strs.begin();
2148 if (it == strs.end())
2149 {
2150 objectPath = "/";
2151 }
2152 while (it != strs.end())
2153 {
2154 // Check if segment contains ".". If it does, it must be an
2155 // interface
2156 if (it->find(".") != std::string::npos)
2157 {
2158 break;
2159 // This check is necessary as the trailing slash gets
2160 // parsed as part of our <path> specifier above, which
2161 // causes the normal trailing backslash redirector to
2162 // fail.
2163 }
2164 if (!it->empty())
2165 {
2166 objectPath += "/" + *it;
2167 }
2168 it++;
2169 }
2170 if (it != strs.end())
2171 {
2172 interfaceName = *it;
2173 it++;
2174
2175 // after interface, we might have a method name
2176 if (it != strs.end())
2177 {
2178 methodName = *it;
2179 it++;
2180 }
2181 }
2182 if (it != strs.end())
2183 {
2184 // if there is more levels past the method name, something
2185 // went wrong, return not found
2186 asyncResp->res.result(boost::beast::http::status::not_found);
2187 return;
2188 }
2189 if (interfaceName.empty())
2190 {
2191 crow::connections::systemBus->async_method_call(
2192 [asyncResp, processName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002193 objectPath](const boost::system::error_code& ec,
Ed Tanous1656b292022-05-04 11:33:42 -07002194 const std::string& introspectXml) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002195 if (ec)
Ed Tanous1656b292022-05-04 11:33:42 -07002196 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002197 BMCWEB_LOG_ERROR(
2198 "Introspect call failed with error: {} on process: {} path: {}",
2199 ec.message(), processName, objectPath);
2200 return;
2201 }
2202 tinyxml2::XMLDocument doc;
2203
2204 doc.Parse(introspectXml.c_str());
2205 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2206 if (pRoot == nullptr)
2207 {
2208 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
2209 processName, objectPath);
2210 asyncResp->res.jsonValue["status"] = "XML parse error";
2211 asyncResp->res.result(
2212 boost::beast::http::status::internal_server_error);
2213 return;
Ed Tanous1656b292022-05-04 11:33:42 -07002214 }
2215
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002216 BMCWEB_LOG_DEBUG("{}", introspectXml);
2217 asyncResp->res.jsonValue["status"] = "ok";
2218 asyncResp->res.jsonValue["bus_name"] = processName;
2219 asyncResp->res.jsonValue["object_path"] = objectPath;
2220
2221 nlohmann::json& interfacesArray =
2222 asyncResp->res.jsonValue["interfaces"];
2223 interfacesArray = nlohmann::json::array();
2224 tinyxml2::XMLElement* interface =
2225 pRoot->FirstChildElement("interface");
2226
2227 while (interface != nullptr)
2228 {
2229 const char* ifaceName = interface->Attribute("name");
2230 if (ifaceName != nullptr)
2231 {
2232 nlohmann::json::object_t interfaceObj;
2233 interfaceObj["name"] = ifaceName;
2234 interfacesArray.emplace_back(std::move(interfaceObj));
2235 }
2236
2237 interface = interface->NextSiblingElement("interface");
2238 }
2239 },
Ed Tanous1656b292022-05-04 11:33:42 -07002240 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2241 "Introspect");
2242 }
2243 else if (methodName.empty())
2244 {
2245 crow::connections::systemBus->async_method_call(
2246 [asyncResp, processName, objectPath,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002247 interfaceName](const boost::system::error_code& ec,
Ed Tanous1656b292022-05-04 11:33:42 -07002248 const std::string& introspectXml) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002249 if (ec)
Ed Tanous1656b292022-05-04 11:33:42 -07002250 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002251 BMCWEB_LOG_ERROR(
2252 "Introspect call failed with error: {} on process: {} path: {}",
2253 ec.message(), processName, objectPath);
2254 return;
2255 }
2256 tinyxml2::XMLDocument doc;
2257
2258 doc.Parse(introspectXml.data(), introspectXml.size());
2259 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2260 if (pRoot == nullptr)
2261 {
2262 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
2263 processName, objectPath);
2264 asyncResp->res.result(
2265 boost::beast::http::status::internal_server_error);
2266 return;
Ed Tanous1656b292022-05-04 11:33:42 -07002267 }
Ed Tanous14766872022-03-15 10:44:42 -07002268
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002269 asyncResp->res.jsonValue["status"] = "ok";
2270 asyncResp->res.jsonValue["bus_name"] = processName;
2271 asyncResp->res.jsonValue["interface"] = interfaceName;
2272 asyncResp->res.jsonValue["object_path"] = objectPath;
Ed Tanous1656b292022-05-04 11:33:42 -07002273
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002274 nlohmann::json& methodsArray =
2275 asyncResp->res.jsonValue["methods"];
2276 methodsArray = nlohmann::json::array();
2277
2278 nlohmann::json& signalsArray =
2279 asyncResp->res.jsonValue["signals"];
2280 signalsArray = nlohmann::json::array();
2281
2282 nlohmann::json& propertiesObj =
2283 asyncResp->res.jsonValue["properties"];
2284 propertiesObj = nlohmann::json::object();
2285
2286 // if we know we're the only call, build the
2287 // json directly
2288 tinyxml2::XMLElement* interface =
2289 pRoot->FirstChildElement("interface");
2290 while (interface != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002291 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002292 const char* ifaceName = interface->Attribute("name");
2293
2294 if (ifaceName != nullptr && ifaceName == interfaceName)
Ed Tanous1656b292022-05-04 11:33:42 -07002295 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002296 break;
Ed Tanous002d39b2022-05-31 08:59:27 -07002297 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002298
2299 interface = interface->NextSiblingElement("interface");
2300 }
2301 if (interface == nullptr)
2302 {
2303 // if we got to the end of the list and
2304 // never found a match, throw 404
2305 asyncResp->res.result(
2306 boost::beast::http::status::not_found);
2307 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07002308 }
2309
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002310 tinyxml2::XMLElement* methods =
2311 interface->FirstChildElement("method");
2312 while (methods != nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07002313 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002314 nlohmann::json argsArray = nlohmann::json::array();
2315 tinyxml2::XMLElement* arg =
2316 methods->FirstChildElement("arg");
2317 while (arg != nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07002318 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002319 nlohmann::json thisArg;
2320 for (const char* fieldName : std::array<const char*, 3>{
2321 "name", "direction", "type"})
2322 {
2323 const char* fieldValue = arg->Attribute(fieldName);
2324 if (fieldValue != nullptr)
2325 {
2326 thisArg[fieldName] = fieldValue;
2327 }
2328 }
2329 argsArray.emplace_back(std::move(thisArg));
2330 arg = arg->NextSiblingElement("arg");
Ed Tanous002d39b2022-05-31 08:59:27 -07002331 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002332
2333 const char* name = methods->Attribute("name");
2334 if (name != nullptr)
2335 {
2336 std::string uri;
2337 uri.reserve(14 + processName.size() +
2338 objectPath.size() + interfaceName.size() +
2339 strlen(name));
2340 uri += "/bus/system/";
2341 uri += processName;
2342 uri += objectPath;
2343 uri += "/";
2344 uri += interfaceName;
2345 uri += "/";
2346 uri += name;
2347
2348 nlohmann::json::object_t object;
2349 object["name"] = name;
2350 object["uri"] = std::move(uri);
2351 object["args"] = argsArray;
2352
2353 methodsArray.emplace_back(std::move(object));
2354 }
2355 methods = methods->NextSiblingElement("method");
Ed Tanous002d39b2022-05-31 08:59:27 -07002356 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002357 tinyxml2::XMLElement* signals =
2358 interface->FirstChildElement("signal");
2359 while (signals != nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07002360 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002361 nlohmann::json argsArray = nlohmann::json::array();
2362
2363 tinyxml2::XMLElement* arg =
2364 signals->FirstChildElement("arg");
2365 while (arg != nullptr)
2366 {
2367 const char* name = arg->Attribute("name");
2368 const char* type = arg->Attribute("type");
2369 if (name != nullptr && type != nullptr)
2370 {
2371 nlohmann::json::object_t params;
2372 params["name"] = name;
2373 params["type"] = type;
2374 argsArray.push_back(std::move(params));
2375 }
2376 arg = arg->NextSiblingElement("arg");
2377 }
2378 const char* name = signals->Attribute("name");
2379 if (name != nullptr)
2380 {
2381 nlohmann::json::object_t object;
2382 object["name"] = name;
2383 object["args"] = argsArray;
2384 signalsArray.emplace_back(std::move(object));
2385 }
2386
2387 signals = signals->NextSiblingElement("signal");
Ed Tanous002d39b2022-05-31 08:59:27 -07002388 }
2389
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002390 tinyxml2::XMLElement* property =
2391 interface->FirstChildElement("property");
2392 while (property != nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07002393 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002394 const char* name = property->Attribute("name");
2395 const char* type = property->Attribute("type");
2396 if (type != nullptr && name != nullptr)
2397 {
2398 sdbusplus::message_t m =
2399 crow::connections::systemBus->new_method_call(
2400 processName.c_str(), objectPath.c_str(),
2401 "org.freedesktop."
2402 "DBus."
2403 "Properties",
2404 "Get");
2405 m.append(interfaceName, name);
2406 nlohmann::json& propertyItem = propertiesObj[name];
2407 crow::connections::systemBus->async_send(
2408 m, [&propertyItem,
2409 asyncResp](const boost::system::error_code& ec2,
2410 sdbusplus::message_t& msg) {
2411 if (ec2)
2412 {
2413 return;
2414 }
Ed Tanous1656b292022-05-04 11:33:42 -07002415
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002416 int r =
2417 convertDBusToJSON("v", msg, propertyItem);
2418 if (r < 0)
2419 {
2420 BMCWEB_LOG_ERROR(
2421 "Couldn't convert vector to json");
2422 }
2423 });
2424 }
2425 property = property->NextSiblingElement("property");
Ed Tanous1656b292022-05-04 11:33:42 -07002426 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002427 },
Ed Tanous1656b292022-05-04 11:33:42 -07002428 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2429 "Introspect");
2430 }
2431 else
2432 {
2433 if (req.method() != boost::beast::http::verb::post)
2434 {
2435 asyncResp->res.result(boost::beast::http::status::not_found);
2436 return;
2437 }
2438
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002439 nlohmann::json requestDbusData;
2440 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
2441 if (ret == JsonParseResult::BadContentType)
Ed Tanous1656b292022-05-04 11:33:42 -07002442 {
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002443 setErrorResponse(asyncResp->res,
2444 boost::beast::http::status::unsupported_media_type,
2445 invalidContentType, unsupportedMediaMsg);
Ed Tanous1656b292022-05-04 11:33:42 -07002446 return;
2447 }
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002448 if (ret != JsonParseResult::Success)
2449 {
2450 setErrorResponse(asyncResp->res,
2451 boost::beast::http::status::bad_request,
2452 noJsonDesc, badReqMsg);
2453 return;
2454 }
2455
Ed Tanous1656b292022-05-04 11:33:42 -07002456 if (!requestDbusData.is_array())
2457 {
2458 asyncResp->res.result(boost::beast::http::status::bad_request);
2459 return;
2460 }
Lei YU28dd5ca2023-03-17 13:17:05 +08002461 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous1656b292022-05-04 11:33:42 -07002462
2463 transaction->path = objectPath;
2464 transaction->methodName = methodName;
2465 transaction->arguments = std::move(requestDbusData);
2466
2467 findActionOnInterface(transaction, processName);
2468 }
2469}
2470
Ed Tanous23a21a12020-07-25 04:45:05 +00002471inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002472{
2473 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002474 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002475 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002476 [](const crow::Request&,
2477 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002478 nlohmann::json::array_t buses;
2479 nlohmann::json& bus = buses.emplace_back();
2480 bus["name"] = "system";
2481 asyncResp->res.jsonValue["busses"] = std::move(buses);
2482 asyncResp->res.jsonValue["status"] = "ok";
2483 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002484
2485 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002486 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002487 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002488 [](const crow::Request&,
2489 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002490 auto myCallback = [asyncResp](
2491 const boost::system::error_code& ec,
zhanghch058d1b46d2021-04-01 11:18:24 +08002492 std::vector<std::string>& names) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002493 if (ec)
2494 {
2495 BMCWEB_LOG_ERROR("Dbus call failed with code {}", ec);
2496 asyncResp->res.result(
2497 boost::beast::http::status::internal_server_error);
2498 }
2499 else
2500 {
2501 std::ranges::sort(names);
2502 asyncResp->res.jsonValue["status"] = "ok";
2503 auto& objectsSub = asyncResp->res.jsonValue["objects"];
2504 for (const auto& name : names)
2505 {
2506 nlohmann::json::object_t object;
2507 object["name"] = name;
2508 objectsSub.emplace_back(std::move(object));
2509 }
2510 }
2511 };
2512 crow::connections::systemBus->async_method_call(
2513 std::move(myCallback), "org.freedesktop.DBus", "/",
2514 "org.freedesktop.DBus", "ListNames");
2515 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002516
2517 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002518 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002519 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002520 [](const crow::Request&,
2521 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002522 handleList(asyncResp, "/");
2523 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002524
2525 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002526 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002527 .methods(boost::beast::http::verb::get)(
2528 [](const crow::Request& req,
2529 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002530 const std::string& path) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002531 std::string objectPath = "/xyz/" + path;
2532 handleDBusUrl(req, asyncResp, objectPath);
2533 });
zhanghch058d1b46d2021-04-01 11:18:24 +08002534
2535 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002536 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002537 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2538 boost::beast::http::verb::delete_)(
2539 [](const crow::Request& req,
2540 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2541 const std::string& path) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002542 std::string objectPath = "/xyz/" + path;
2543 handleDBusUrl(req, asyncResp, objectPath);
2544 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002545
Ed Tanous049a0512018-11-01 13:58:42 -07002546 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002547 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002548 .methods(boost::beast::http::verb::get)(
2549 [](const crow::Request& req,
2550 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2551 const std::string& path) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002552 std::string objectPath = "/org/" + path;
2553 handleDBusUrl(req, asyncResp, objectPath);
2554 });
Tanousf00032d2018-11-05 01:18:10 -03002555
2556 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002557 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002558 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2559 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002560 [](const crow::Request& req,
2561 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002562 const std::string& path) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002563 std::string objectPath = "/org/" + path;
2564 handleDBusUrl(req, asyncResp, objectPath);
2565 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002566
Ed Tanous1abe55e2018-09-05 08:30:59 -07002567 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002568 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002569 .methods(boost::beast::http::verb::get)(
2570 [](const crow::Request&,
2571 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2572 const std::string& dumpId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002573 if (!validateFilename(dumpId))
2574 {
2575 asyncResp->res.result(
2576 boost::beast::http::status::bad_request);
2577 return;
2578 }
2579 std::filesystem::path loc(
2580 "/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002581
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002582 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002583
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002584 if (!std::filesystem::exists(loc) ||
2585 !std::filesystem::is_directory(loc))
2586 {
2587 BMCWEB_LOG_ERROR("{}Not found", loc.string());
2588 asyncResp->res.result(
2589 boost::beast::http::status::not_found);
2590 return;
2591 }
2592 std::filesystem::directory_iterator files(loc);
zhanghch058d1b46d2021-04-01 11:18:24 +08002593
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002594 for (const auto& file : files)
2595 {
Myung Baed51c61b2024-09-13 10:35:34 -05002596 if (asyncResp->res.openFile(file) !=
2597 crow::OpenCode::Success)
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002598 {
2599 continue;
2600 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002601
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002602 asyncResp->res.addHeader(
2603 boost::beast::http::field::content_type,
2604 "application/octet-stream");
zhanghch058d1b46d2021-04-01 11:18:24 +08002605
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002606 // Assuming only one dump file will be present in the dump
2607 // id directory
2608 std::string dumpFileName = file.path().filename().string();
zhanghch058d1b46d2021-04-01 11:18:24 +08002609
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002610 // Filename should be in alphanumeric, dot and underscore
2611 // Its based on phosphor-debug-collector application
2612 // dumpfile format
2613 static std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
2614 if (!std::regex_match(dumpFileName, dumpFileRegex))
2615 {
2616 BMCWEB_LOG_ERROR("Invalid dump filename {}",
2617 dumpFileName);
2618 asyncResp->res.result(
2619 boost::beast::http::status::not_found);
2620 return;
2621 }
2622 std::string contentDispositionParam =
2623 "attachment; filename=\"" + dumpFileName + "\"";
2624
2625 asyncResp->res.addHeader(
2626 boost::beast::http::field::content_disposition,
2627 contentDispositionParam);
2628
2629 return;
2630 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002631 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002632 return;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002633 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002634
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002635 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002636 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002637
2638 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002639 [](const crow::Request&,
2640 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002641 const std::string& connection) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002642 introspectObjects(connection, "/", asyncResp);
2643 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002644
2645 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002646 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous1656b292022-05-04 11:33:42 -07002647 .methods(boost::beast::http::verb::get,
2648 boost::beast::http::verb::post)(handleBusSystemPost);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002649}
2650} // namespace openbmc_mapper
2651} // namespace crow