blob: f651c38f37fc3a507c047fa606e35fe40a726e5f [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"
Ed Tanous50ebd4a2023-01-19 19:03:17 -080016#include "str_utility.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000017
18#include <systemd/sd-bus-protocol.h>
19#include <systemd/sd-bus.h>
Ed Tanous911ac312017-08-15 09:37:42 -070020#include <tinyxml2.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -070021
Ed Tanousd7857202025-01-28 15:32:26 -080022#include <boost/beast/http/field.hpp>
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>
George Liue99073f2022-12-09 11:06:16 +080026#include <boost/system/error_code.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000027#include <nlohmann/json.hpp>
28#include <sdbusplus/asio/connection.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000029#include <sdbusplus/message.hpp>
30#include <sdbusplus/message/native_types.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050031
Nan Zhoud5c80ad2022-07-11 01:16:31 +000032#include <algorithm>
33#include <array>
34#include <cerrno>
35#include <cstdint>
36#include <cstring>
James Feist4418c7f2019-04-15 11:09:15 -070037#include <filesystem>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000038#include <functional>
39#include <initializer_list>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000040#include <limits>
41#include <map>
42#include <memory>
Ed Tanous3544d2a2023-08-06 18:12:20 -070043#include <ranges>
Ramesh Iyyard9207042019-07-05 08:04:42 -050044#include <regex>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000045#include <string>
46#include <string_view>
47#include <type_traits>
Ed Tanousb5a76932020-09-29 16:16:58 -070048#include <utility>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000049#include <variant>
50#include <vector>
51
Ed Tanous1abe55e2018-09-05 08:30:59 -070052namespace crow
53{
54namespace openbmc_mapper
55{
Ed Tanous23a21a12020-07-25 04:45:05 +000056const constexpr char* notFoundMsg = "404 Not Found";
57const constexpr char* badReqMsg = "400 Bad Request";
58const constexpr char* methodNotAllowedMsg = "405 Method Not Allowed";
59const constexpr char* forbiddenMsg = "403 Forbidden";
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010060const constexpr char* unsupportedMediaMsg = "415 Unsupported Media Type";
Ed Tanous23a21a12020-07-25 04:45:05 +000061const constexpr char* methodFailedMsg = "500 Method Call Failed";
62const constexpr char* methodOutputFailedMsg = "500 Method Output Error";
63const constexpr char* notFoundDesc =
Matt Spinler2ae60092018-12-06 10:35:36 -060064 "org.freedesktop.DBus.Error.FileNotFound: path or object not found";
Ed Tanous23a21a12020-07-25 04:45:05 +000065const constexpr char* propNotFoundDesc =
66 "The specified property cannot be found";
67const constexpr char* noJsonDesc = "No JSON object could be decoded";
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010068const constexpr char* invalidContentType =
69 "Content-type header is missing or invalid";
Ed Tanous23a21a12020-07-25 04:45:05 +000070const constexpr char* methodNotFoundDesc =
71 "The specified method cannot be found";
72const constexpr char* methodNotAllowedDesc = "Method not allowed";
73const constexpr char* forbiddenPropDesc =
74 "The specified property cannot be created";
75const constexpr char* forbiddenResDesc =
76 "The specified resource cannot be created";
Matt Spinler2ae60092018-12-06 10:35:36 -060077
Josh Lehan482c45a2022-03-29 17:10:44 -070078inline bool validateFilename(const std::string& filename)
79{
Ed Tanous4b242742023-05-11 09:51:51 -070080 static std::regex validFilename(R"(^[\w\- ]+(\.?[\w\- ]*)$)");
Josh Lehan482c45a2022-03-29 17:10:44 -070081
82 return std::regex_match(filename, validFilename);
83}
84
Ed Tanous23a21a12020-07-25 04:45:05 +000085inline void setErrorResponse(crow::Response& res,
86 boost::beast::http::status result,
Ed Tanous26ccae32023-02-16 10:28:44 -080087 const std::string& desc, std::string_view msg)
Matt Spinler2ae60092018-12-06 10:35:36 -060088{
89 res.result(result);
Ed Tanous14766872022-03-15 10:44:42 -070090 res.jsonValue["data"]["description"] = desc;
91 res.jsonValue["message"] = msg;
92 res.jsonValue["status"] = "error";
Matt Spinler2ae60092018-12-06 10:35:36 -060093}
94
Patrick Williamsbd79bce2024-08-16 15:22:20 -040095inline void introspectObjects(
96 const std::string& processName, const std::string& objectPath,
97 const std::shared_ptr<bmcweb::AsyncResp>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -070098{
Ed Tanouse3cb5a32018-08-08 14:16:49 -070099 if (transaction->res.jsonValue.is_null())
100 {
Ed Tanous14766872022-03-15 10:44:42 -0700101 transaction->res.jsonValue["status"] = "ok";
102 transaction->res.jsonValue["bus_name"] = processName;
103 transaction->res.jsonValue["objects"] = nlohmann::json::array();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700104 }
105
Ed Tanous177612a2025-02-14 15:16:09 -0800106 dbus::utility::async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700107 [transaction, processName{std::string(processName)},
108 objectPath{std::string(objectPath)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800109 const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +0000110 const std::string& introspectXml) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400111 if (ec)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700112 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400113 BMCWEB_LOG_ERROR(
114 "Introspect call failed with error: {} on process: {} path: {}",
115 ec.message(), processName, objectPath);
116 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700117 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400118 nlohmann::json::object_t object;
119 object["path"] = objectPath;
120
121 transaction->res.jsonValue["objects"].emplace_back(
122 std::move(object));
123
124 tinyxml2::XMLDocument doc;
125
126 doc.Parse(introspectXml.c_str());
127 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
128 if (pRoot == nullptr)
129 {
130 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
131 processName, objectPath);
132 }
133 else
134 {
135 tinyxml2::XMLElement* node = pRoot->FirstChildElement("node");
136 while (node != nullptr)
137 {
138 const char* childPath = node->Attribute("name");
139 if (childPath != nullptr)
140 {
141 std::string newpath;
142 if (objectPath != "/")
143 {
144 newpath += objectPath;
145 }
146 newpath += std::string("/") + childPath;
147 // introspect the subobjects as well
148 introspectObjects(processName, newpath, transaction);
149 }
150
151 node = node->NextSiblingElement("node");
152 }
153 }
154 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700155 processName, objectPath, "org.freedesktop.DBus.Introspectable",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700156 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -0700157}
Ed Tanous64530012018-02-06 17:08:16 -0800158
Ed Tanous23a21a12020-07-25 04:45:05 +0000159inline void getPropertiesForEnumerate(
160 const std::string& objectPath, const std::string& service,
Ed Tanousb5a76932020-09-29 16:16:58 -0700161 const std::string& interface,
162 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600163{
Ed Tanous62598e32023-07-17 17:06:25 -0700164 BMCWEB_LOG_DEBUG("getPropertiesForEnumerate {} {} {}", objectPath, service,
165 interface);
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600166
Ed Tanousdeae6a72024-11-11 21:58:57 -0800167 dbus::utility::getAllProperties(
168 service, objectPath, interface,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800169 [asyncResp, objectPath, service,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800170 interface](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800171 const dbus::utility::DBusPropertiesMap& propertiesList) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400172 if (ec)
173 {
174 BMCWEB_LOG_ERROR(
175 "GetAll on path {} iface {} service {} failed with code {}",
176 objectPath, interface, service, ec);
177 return;
178 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600179
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400180 nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
181 nlohmann::json& objectJson = dataJson[objectPath];
182 if (objectJson.is_null())
183 {
184 objectJson = nlohmann::json::object();
185 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600186
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400187 for (const auto& [name, value] : propertiesList)
188 {
189 nlohmann::json& propertyJson = objectJson[name];
Ed Tanouse3648032024-10-16 18:06:39 -0700190 std::visit([&propertyJson](auto&& val) { propertyJson = val; },
191 value);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400192 }
193 });
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600194}
195
196// Find any results that weren't picked up by ObjectManagers, to be
197// called after all ObjectManagers are searched for and called.
Ed Tanous23a21a12020-07-25 04:45:05 +0000198inline void findRemainingObjectsForEnumerate(
Ed Tanousb5a76932020-09-29 16:16:58 -0700199 const std::string& objectPath,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800200 const std::shared_ptr<dbus::utility::MapperGetSubTreeResponse>& subtree,
Ed Tanousb5a76932020-09-29 16:16:58 -0700201 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600202{
Ed Tanous62598e32023-07-17 17:06:25 -0700203 BMCWEB_LOG_DEBUG("findRemainingObjectsForEnumerate");
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500204 const nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600205
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500206 for (const auto& [path, interface_map] : *subtree)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600207 {
208 if (path == objectPath)
209 {
210 // An enumerate does not return the target path's properties
211 continue;
212 }
213 if (dataJson.find(path) == dataJson.end())
214 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500215 for (const auto& [service, interfaces] : interface_map)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600216 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500217 for (const auto& interface : interfaces)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600218 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700219 if (!interface.starts_with("org.freedesktop.DBus"))
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600220 {
221 getPropertiesForEnumerate(path, service, interface,
222 asyncResp);
223 }
224 }
225 }
226 }
227 }
228}
229
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600230struct InProgressEnumerateData
231{
zhanghch058d1b46d2021-04-01 11:18:24 +0800232 InProgressEnumerateData(
233 const std::string& objectPathIn,
234 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400235 objectPath(objectPathIn), asyncResp(asyncRespIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500236 {}
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600237
238 ~InProgressEnumerateData()
239 {
Ed Tanous24b2fe82022-01-06 12:45:54 -0800240 try
241 {
242 findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
243 }
244 catch (...)
245 {
Ed Tanous62598e32023-07-17 17:06:25 -0700246 BMCWEB_LOG_CRITICAL(
247 "findRemainingObjectsForEnumerate threw exception");
Ed Tanous24b2fe82022-01-06 12:45:54 -0800248 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600249 }
250
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800251 InProgressEnumerateData(const InProgressEnumerateData&) = delete;
252 InProgressEnumerateData(InProgressEnumerateData&&) = delete;
253 InProgressEnumerateData& operator=(const InProgressEnumerateData&) = delete;
254 InProgressEnumerateData& operator=(InProgressEnumerateData&&) = delete;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600255 const std::string objectPath;
Ed Tanousb9d36b42022-02-26 21:42:46 -0800256 std::shared_ptr<dbus::utility::MapperGetSubTreeResponse> subtree;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600257 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
258};
259
Ed Tanous23a21a12020-07-25 04:45:05 +0000260inline void getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000261 const std::string& objectName, const std::string& objectManagerPath,
262 const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700263 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700264{
Ed Tanous62598e32023-07-17 17:06:25 -0700265 BMCWEB_LOG_DEBUG(
266 "getManagedObjectsForEnumerate {} object_manager_path {} connection_name {}",
267 objectName, objectManagerPath, connectionName);
George Liu5eb468d2023-06-20 17:03:24 +0800268 sdbusplus::message::object_path path(objectManagerPath);
269 dbus::utility::getManagedObjects(
270 connectionName, path,
Ed Tanous81ce6092020-12-17 16:54:55 +0000271 [transaction, objectName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800272 connectionName](const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +0000273 const dbus::utility::ManagedObjectType& objects) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400274 if (ec)
Ed Tanous049a0512018-11-01 13:58:42 -0700275 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400276 BMCWEB_LOG_ERROR(
277 "GetManagedObjects on path {} on connection {} failed with code {}",
278 objectName, connectionName, ec);
279 return;
280 }
281
282 nlohmann::json& dataJson =
283 transaction->asyncResp->res.jsonValue["data"];
284
285 for (const auto& objectPath : objects)
286 {
287 if (objectPath.first.str.starts_with(objectName))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700288 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400289 BMCWEB_LOG_DEBUG("Reading object {}", objectPath.first.str);
290 nlohmann::json& objectJson = dataJson[objectPath.first.str];
291 if (objectJson.is_null())
292 {
293 objectJson = nlohmann::json::object();
294 }
295 for (const auto& interface : objectPath.second)
296 {
297 for (const auto& property : interface.second)
298 {
299 nlohmann::json& propertyJson =
300 objectJson[property.first];
301 std::visit(
302 [&propertyJson](auto&& val) {
303 if constexpr (
304 std::is_same_v<
305 std::decay_t<decltype(val)>,
306 sdbusplus::message::unix_fd>)
307 {
308 propertyJson = val.fd;
309 }
310 else
311 {
312 propertyJson = val;
313 }
314 },
315 property.second);
316 }
317 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700318 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500319 for (const auto& interface : objectPath.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700320 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400321 if (interface.first == "org.freedesktop.DBus.ObjectManager")
Ed Tanous049a0512018-11-01 13:58:42 -0700322 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400323 getManagedObjectsForEnumerate(
324 objectPath.first.str, objectPath.first.str,
325 connectionName, transaction);
Ed Tanous049a0512018-11-01 13:58:42 -0700326 }
327 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700328 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400329 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700330}
331
Ed Tanous23a21a12020-07-25 04:45:05 +0000332inline void findObjectManagerPathForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000333 const std::string& objectName, const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700334 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700335{
Ed Tanous62598e32023-07-17 17:06:25 -0700336 BMCWEB_LOG_DEBUG("Finding objectmanager for path {} on connection:{}",
337 objectName, connectionName);
Ed Tanous177612a2025-02-14 15:16:09 -0800338 dbus::utility::async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000339 [transaction, objectName, connectionName](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800340 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800341 const dbus::utility::MapperGetAncestorsResponse& objects) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400342 if (ec)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700343 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400344 BMCWEB_LOG_ERROR("GetAncestors on path {} failed with code {}",
345 objectName, ec);
346 return;
347 }
348
349 for (const auto& pathGroup : objects)
350 {
351 for (const auto& connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700352 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400353 if (connectionGroup.first == connectionName)
354 {
355 // Found the object manager path for this resource.
356 getManagedObjectsForEnumerate(
357 objectName, pathGroup.first, connectionName,
358 transaction);
359 return;
360 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700361 }
362 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400363 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700364 "xyz.openbmc_project.ObjectMapper",
365 "/xyz/openbmc_project/object_mapper",
Ed Tanous81ce6092020-12-17 16:54:55 +0000366 "xyz.openbmc_project.ObjectMapper", "GetAncestors", objectName,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500367 std::array<const char*, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700368}
Ed Tanous64530012018-02-06 17:08:16 -0800369
Ed Tanous7c091622019-05-23 11:42:36 -0700370// Uses GetObject to add the object info about the target /enumerate path to
371// the results of GetSubTree, as GetSubTree will not return info for the
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600372// target path, and then continues on enumerating the rest of the tree.
Ed Tanousb5a76932020-09-29 16:16:58 -0700373inline void getObjectAndEnumerate(
374 const std::shared_ptr<InProgressEnumerateData>& transaction)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600375{
George Liu2b731192023-01-11 16:27:13 +0800376 dbus::utility::getDbusObject(
377 transaction->objectPath, {},
378 [transaction](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800379 const dbus::utility::MapperGetObject& objects) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400380 if (ec)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600381 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400382 BMCWEB_LOG_ERROR("GetObject for path {} failed with code {}",
383 transaction->objectPath, ec);
384 return;
385 }
386
387 BMCWEB_LOG_DEBUG("GetObject for {} has {} entries",
388 transaction->objectPath, objects.size());
389 if (!objects.empty())
390 {
391 transaction->subtree->emplace_back(transaction->objectPath,
392 objects);
393 }
394
395 // Map indicating connection name, and the path where the object
396 // manager exists
397 boost::container::flat_map<
398 std::string, std::string, std::less<>,
399 std::vector<std::pair<std::string, std::string>>>
400 connections;
401
402 for (const auto& object : *(transaction->subtree))
403 {
404 for (const auto& connection : object.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600405 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400406 for (const auto& interface : connection.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600407 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400408 BMCWEB_LOG_DEBUG("{} has interface {}",
409 connection.first, interface);
410 if (interface == "org.freedesktop.DBus.ObjectManager")
411 {
412 BMCWEB_LOG_DEBUG("found object manager path {}",
413 object.first);
414 connections[connection.first] = object.first;
415 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600416 }
417 }
418 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400419 BMCWEB_LOG_DEBUG("Got {} connections", connections.size());
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600420
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400421 for (const auto& connection : connections)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600422 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400423 // If we already know where the object manager is, we don't
424 // need to search for it, we can call directly in to
425 // getManagedObjects
426 if (!connection.second.empty())
427 {
428 getManagedObjectsForEnumerate(
429 transaction->objectPath, connection.second,
430 connection.first, transaction);
431 }
432 else
433 {
434 // otherwise we need to find the object manager path
435 // before we can continue
436 findObjectManagerPathForEnumerate(
437 transaction->objectPath, connection.first, transaction);
438 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600439 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400440 });
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600441}
Ed Tanous64530012018-02-06 17:08:16 -0800442
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700443// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700444struct InProgressActionData
445{
Lei YU28dd5ca2023-03-17 13:17:05 +0800446 explicit InProgressActionData(
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400447 const std::shared_ptr<bmcweb::AsyncResp>& res) : asyncResp(res)
Ed Tanous23a21a12020-07-25 04:45:05 +0000448 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700449 ~InProgressActionData()
450 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600451 // Methods could have been called across different owners
452 // and interfaces, where some calls failed and some passed.
453 //
454 // The rules for this are:
455 // * if no method was called - error
456 // * if a method failed and none passed - error
457 // (converse: if at least one method passed - OK)
458 // * for the method output:
459 // * if output processing didn't fail, return the data
460
461 // Only deal with method returns if nothing failed earlier
Lei YU28dd5ca2023-03-17 13:17:05 +0800462 if (asyncResp->res.result() == boost::beast::http::status::ok)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700463 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600464 if (!methodPassed)
465 {
Matt Spinler06b1b632019-06-18 16:09:25 -0500466 if (!methodFailed)
Matt Spinler16caaee2019-01-15 11:40:34 -0600467 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800468 setErrorResponse(asyncResp->res,
469 boost::beast::http::status::not_found,
Matt Spinler16caaee2019-01-15 11:40:34 -0600470 methodNotFoundDesc, notFoundMsg);
471 }
472 }
473 else
474 {
475 if (outputFailed)
476 {
477 setErrorResponse(
Lei YU28dd5ca2023-03-17 13:17:05 +0800478 asyncResp->res,
479 boost::beast::http::status::internal_server_error,
Matt Spinler16caaee2019-01-15 11:40:34 -0600480 "Method output failure", methodOutputFailedMsg);
481 }
482 else
483 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800484 asyncResp->res.jsonValue["status"] = "ok";
485 asyncResp->res.jsonValue["message"] = "200 OK";
486 asyncResp->res.jsonValue["data"] = methodResponse;
Matt Spinler16caaee2019-01-15 11:40:34 -0600487 }
488 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700489 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700490 }
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800491 InProgressActionData(const InProgressActionData&) = delete;
492 InProgressActionData(InProgressActionData&&) = delete;
493 InProgressActionData& operator=(const InProgressActionData&) = delete;
494 InProgressActionData& operator=(InProgressActionData&&) = delete;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700495
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500496 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700497 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800498 setErrorResponse(asyncResp->res,
499 boost::beast::http::status::bad_request, desc,
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600500 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700501 }
Lei YU28dd5ca2023-03-17 13:17:05 +0800502 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700503 std::string path;
504 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600505 std::string interfaceName;
Matt Spinler16caaee2019-01-15 11:40:34 -0600506 bool methodPassed = false;
507 bool methodFailed = false;
508 bool outputFailed = false;
Matt Spinler39a4e392019-01-15 11:53:13 -0600509 bool convertedToArray = false;
Matt Spinler16caaee2019-01-15 11:40:34 -0600510 nlohmann::json methodResponse;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700511 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700512};
513
Ed Tanous23a21a12020-07-25 04:45:05 +0000514inline std::vector<std::string> dbusArgSplit(const std::string& string)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700515{
516 std::vector<std::string> ret;
517 if (string.empty())
518 {
519 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700520 }
Ed Tanous0f0353b2019-10-24 11:37:51 -0700521 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700522 int containerDepth = 0;
523
524 for (std::string::const_iterator character = string.begin();
525 character != string.end(); character++)
526 {
527 ret.back() += *character;
528 switch (*character)
529 {
530 case ('a'):
531 break;
532 case ('('):
533 case ('{'):
534 containerDepth++;
535 break;
536 case ('}'):
537 case (')'):
538 containerDepth--;
539 if (containerDepth == 0)
540 {
541 if (character + 1 != string.end())
542 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700543 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700544 }
545 }
546 break;
547 default:
548 if (containerDepth == 0)
549 {
550 if (character + 1 != string.end())
551 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700552 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700553 }
554 }
555 break;
556 }
557 }
Matt Spinler4ae611d2019-01-11 15:37:06 -0600558
559 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700560}
561
Ed Tanous81ce6092020-12-17 16:54:55 +0000562inline int convertJsonToDbus(sd_bus_message* m, const std::string& argType,
563 const nlohmann::json& inputJson)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700564{
565 int r = 0;
Ed Tanous296579b2024-03-11 16:58:24 -0700566 BMCWEB_LOG_DEBUG("Converting {} to type: {}", inputJson, argType);
Ed Tanous81ce6092020-12-17 16:54:55 +0000567 const std::vector<std::string> argTypes = dbusArgSplit(argType);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700568
Ed Tanous1abe55e2018-09-05 08:30:59 -0700569 // Assume a single object for now.
Ed Tanous81ce6092020-12-17 16:54:55 +0000570 const nlohmann::json* j = &inputJson;
571 nlohmann::json::const_iterator jIt = inputJson.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700572
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500573 for (const std::string& argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700574 {
575 // If we are decoding multiple objects, grab the pointer to the
576 // iterator, and increment it for the next loop
577 if (argTypes.size() > 1)
578 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000579 if (jIt == inputJson.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700580 {
581 return -2;
582 }
583 j = &*jIt;
584 jIt++;
585 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500586 const int64_t* intValue = j->get_ptr<const int64_t*>();
587 const std::string* stringValue = j->get_ptr<const std::string*>();
588 const double* doubleValue = j->get_ptr<const double*>();
589 const bool* b = j->get_ptr<const bool*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700590 int64_t v = 0;
591 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700592
Ed Tanous1abe55e2018-09-05 08:30:59 -0700593 // Do some basic type conversions that make sense. uint can be
594 // converted to int. int and uint can be converted to double
Ed Tanous66664f22019-10-11 13:05:49 -0700595 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700596 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500597 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700598 if (uintValue != nullptr)
599 {
600 v = static_cast<int64_t>(*uintValue);
601 intValue = &v;
602 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700603 }
Ed Tanous66664f22019-10-11 13:05:49 -0700604 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700605 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500606 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700607 if (uintValue != nullptr)
608 {
609 d = static_cast<double>(*uintValue);
610 doubleValue = &d;
611 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700612 }
Ed Tanous66664f22019-10-11 13:05:49 -0700613 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700614 {
Ed Tanous66664f22019-10-11 13:05:49 -0700615 if (intValue != nullptr)
616 {
617 d = static_cast<double>(*intValue);
618 doubleValue = &d;
619 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700620 }
621
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700622 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700623 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700624 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700625 {
626 return -1;
627 }
Ed Tanous271584a2019-07-09 16:24:22 -0700628 r = sd_bus_message_append_basic(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500629 m, argCode[0], static_cast<const void*>(stringValue->data()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700630 if (r < 0)
631 {
632 return r;
633 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700634 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700635 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700636 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700637 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700638 {
639 return -1;
640 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500641 if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
642 (*intValue > std::numeric_limits<int32_t>::max()))
643 {
644 return -ERANGE;
645 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700646 int32_t i = static_cast<int32_t>(*intValue);
647 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700648 if (r < 0)
649 {
650 return r;
651 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700652 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700653 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700654 {
655 // lots of ways bool could be represented here. Try them all
Ed Tanouse662eae2022-01-25 10:39:19 -0800656 int boolInt = 0;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700657 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700658 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500659 if (*intValue == 1)
660 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800661 boolInt = 1;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500662 }
663 else if (*intValue == 0)
664 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800665 boolInt = 0;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500666 }
667 else
668 {
669 return -ERANGE;
670 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700671 }
672 else if (b != nullptr)
673 {
Matt Spinlera2f02632019-01-18 10:15:35 -0600674 boolInt = *b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700675 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700676 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700677 {
Ed Tanous18f8f602023-07-18 10:07:23 -0700678 if (!stringValue->empty())
679 {
680 if (stringValue->front() == 't' ||
681 stringValue->front() == 'T')
682 {
683 boolInt = 1;
684 }
685 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700686 }
687 else
688 {
689 return -1;
690 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700691 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700692 if (r < 0)
693 {
694 return r;
695 }
696 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700697 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700698 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700699 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700700 {
701 return -1;
702 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500703 if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
704 (*intValue > std::numeric_limits<int16_t>::max()))
705 {
706 return -ERANGE;
707 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700708 int16_t n = static_cast<int16_t>(*intValue);
709 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700710 if (r < 0)
711 {
712 return r;
713 }
714 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700715 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700716 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700717 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700718 {
719 return -1;
720 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700721 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700722 if (r < 0)
723 {
724 return r;
725 }
726 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700727 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700728 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500729 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700730 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700731 {
732 return -1;
733 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000734 if (*uintValue > std::numeric_limits<uint8_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500735 {
736 return -ERANGE;
737 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700738 uint8_t y = static_cast<uint8_t>(*uintValue);
739 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700740 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700741 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700742 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500743 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700744 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700745 {
746 return -1;
747 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000748 if (*uintValue > std::numeric_limits<uint16_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500749 {
750 return -ERANGE;
751 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700752 uint16_t q = static_cast<uint16_t>(*uintValue);
753 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700754 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700755 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700756 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500757 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700758 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700759 {
760 return -1;
761 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000762 if (*uintValue > std::numeric_limits<uint32_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500763 {
764 return -ERANGE;
765 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700766 uint32_t u = static_cast<uint32_t>(*uintValue);
767 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700768 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700769 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700770 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500771 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700772 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700773 {
774 return -1;
775 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700776 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700777 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700778 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700779 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500780 if (doubleValue == nullptr)
781 {
782 return -1;
783 }
784 if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
785 (*doubleValue > std::numeric_limits<double>::max()))
786 {
787 return -ERANGE;
788 }
Ed Tanous07900812024-05-06 15:41:30 -0700789 r = sd_bus_message_append_basic(m, argCode[0], doubleValue);
790 if (r < 0)
791 {
792 return r;
793 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700794 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700795 else if (argCode.starts_with("a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700796 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700797 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700798 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700799 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700800 if (r < 0)
801 {
802 return r;
803 }
804
Ed Tanous0dfeda62019-10-24 11:21:38 -0700805 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700806 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700807 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700808 if (r < 0)
809 {
810 return r;
811 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700812 }
813 sd_bus_message_close_container(m);
814 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700815 else if (argCode.starts_with("v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700816 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700817 std::string containedType = argCode.substr(1);
Ed Tanous62598e32023-07-17 17:06:25 -0700818 BMCWEB_LOG_DEBUG("variant type: {} appending variant of type: {}",
819 argCode, containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700820 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700821 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700822 if (r < 0)
823 {
824 return r;
825 }
826
Ed Tanous81ce6092020-12-17 16:54:55 +0000827 r = convertJsonToDbus(m, containedType, inputJson);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700828 if (r < 0)
829 {
830 return r;
831 }
832
833 r = sd_bus_message_close_container(m);
834 if (r < 0)
835 {
836 return r;
837 }
838 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700839 else if (argCode.starts_with("(") && argCode.ends_with(")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700840 {
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300841 std::string containedType = argCode.substr(1, argCode.size() - 2);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700842 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700843 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800844 if (r < 0)
845 {
846 return r;
847 }
848
Ed Tanous1abe55e2018-09-05 08:30:59 -0700849 nlohmann::json::const_iterator it = j->begin();
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300850 for (const std::string& argCode2 : dbusArgSplit(containedType))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700851 {
852 if (it == j->end())
853 {
854 return -1;
855 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000856 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700857 if (r < 0)
858 {
859 return r;
860 }
861 it++;
862 }
863 r = sd_bus_message_close_container(m);
864 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700865 else if (argCode.starts_with("{") && argCode.ends_with("}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700866 {
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300867 std::string containedType = argCode.substr(1, argCode.size() - 2);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700868 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700869 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800870 if (r < 0)
871 {
872 return r;
873 }
874
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700875 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700876 if (codes.size() != 2)
877 {
878 return -1;
879 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700880 const std::string& keyType = codes[0];
881 const std::string& valueType = codes[1];
Ed Tanous0bdda662023-08-03 17:27:34 -0700882 const nlohmann::json::object_t* arr =
883 j->get_ptr<const nlohmann::json::object_t*>();
884 if (arr == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700885 {
Ed Tanous0bdda662023-08-03 17:27:34 -0700886 return -1;
887 }
888 for (const auto& it : *arr)
889 {
890 r = convertJsonToDbus(m, keyType, it.first);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700891 if (r < 0)
892 {
893 return r;
894 }
895
Ed Tanous0bdda662023-08-03 17:27:34 -0700896 r = convertJsonToDbus(m, valueType, it.second);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700897 if (r < 0)
898 {
899 return r;
900 }
901 }
902 r = sd_bus_message_close_container(m);
903 }
904 else
905 {
906 return -2;
907 }
908 if (r < 0)
909 {
910 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700911 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700912
Ed Tanous1abe55e2018-09-05 08:30:59 -0700913 if (argTypes.size() > 1)
914 {
915 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700916 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700917 }
Matt Spinler127ea542019-01-14 11:04:28 -0600918
919 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700920}
921
Matt Spinlerd22a7132019-01-14 12:14:30 -0600922template <typename T>
Patrick Williams59d494e2022-07-22 19:26:55 -0500923int readMessageItem(const std::string& typeCode, sdbusplus::message_t& m,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500924 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600925{
926 T value;
Ed Tanousf79ce6a2024-03-20 12:27:06 -0700927 // When T == char*, this warning fires. Unclear how to resolve
928 // Given that sd-bus takes a void pointer to a char*, and that's
929 // Not something we can fix.
930 // NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600931 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
932 if (r < 0)
933 {
Ed Tanous62598e32023-07-17 17:06:25 -0700934 BMCWEB_LOG_ERROR("sd_bus_message_read_basic on type {} failed!",
935 typeCode);
Matt Spinlerd22a7132019-01-14 12:14:30 -0600936 return r;
937 }
938
939 data = value;
940 return 0;
941}
942
Patrick Williams59d494e2022-07-22 19:26:55 -0500943int convertDBusToJSON(const std::string& returnType, sdbusplus::message_t& m,
944 nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600945
Ed Tanous23a21a12020-07-25 04:45:05 +0000946inline int readDictEntryFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -0500947 sdbusplus::message_t& m,
Ed Tanous23a21a12020-07-25 04:45:05 +0000948 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600949{
950 std::vector<std::string> types = dbusArgSplit(typeCode);
951 if (types.size() != 2)
952 {
Ed Tanous62598e32023-07-17 17:06:25 -0700953 BMCWEB_LOG_ERROR("wrong number contained types in dictionary: {}",
954 types.size());
Matt Spinler6df8f992019-01-14 12:47:47 -0600955 return -1;
956 }
957
958 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
959 typeCode.c_str());
960 if (r < 0)
961 {
Ed Tanous62598e32023-07-17 17:06:25 -0700962 BMCWEB_LOG_ERROR("sd_bus_message_enter_container with rc {}", r);
Matt Spinler6df8f992019-01-14 12:47:47 -0600963 return r;
964 }
965
966 nlohmann::json key;
967 r = convertDBusToJSON(types[0], m, key);
968 if (r < 0)
969 {
970 return r;
971 }
972
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500973 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -0600974 if (keyPtr == nullptr)
975 {
976 // json doesn't support non-string keys. If we hit this condition,
977 // convert the result to a string so we can proceed
Ed Tanous71f52d92021-02-19 08:51:17 -0800978 key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500979 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -0700980 // in theory this can't fail now, but lets be paranoid about it
981 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -0600982 if (keyPtr == nullptr)
983 {
984 return -1;
985 }
986 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500987 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -0600988
989 r = convertDBusToJSON(types[1], m, value);
990 if (r < 0)
991 {
992 return r;
993 }
994
995 r = sd_bus_message_exit_container(m.get());
996 if (r < 0)
997 {
Ed Tanous62598e32023-07-17 17:06:25 -0700998 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler6df8f992019-01-14 12:47:47 -0600999 return r;
1000 }
1001
1002 return 0;
1003}
1004
Ed Tanous23a21a12020-07-25 04:45:05 +00001005inline int readArrayFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001006 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -06001007{
1008 if (typeCode.size() < 2)
1009 {
Ed Tanous62598e32023-07-17 17:06:25 -07001010 BMCWEB_LOG_ERROR("Type code {} too small for an array", typeCode);
Matt Spinler6df8f992019-01-14 12:47:47 -06001011 return -1;
1012 }
1013
1014 std::string containedType = typeCode.substr(1);
1015
1016 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
1017 containedType.c_str());
1018 if (r < 0)
1019 {
Ed Tanous62598e32023-07-17 17:06:25 -07001020 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler6df8f992019-01-14 12:47:47 -06001021 return r;
1022 }
1023
Ed Tanous11ba3972022-07-11 09:50:41 -07001024 bool dict = containedType.starts_with("{") && containedType.ends_with("}");
Matt Spinler6df8f992019-01-14 12:47:47 -06001025
1026 if (dict)
1027 {
1028 // Remove the { }
1029 containedType = containedType.substr(1, containedType.size() - 2);
1030 data = nlohmann::json::object();
1031 }
1032 else
1033 {
1034 data = nlohmann::json::array();
1035 }
1036
1037 while (true)
1038 {
Ed Tanouse662eae2022-01-25 10:39:19 -08001039 r = sd_bus_message_at_end(m.get(), 0);
Matt Spinler6df8f992019-01-14 12:47:47 -06001040 if (r < 0)
1041 {
Ed Tanous62598e32023-07-17 17:06:25 -07001042 BMCWEB_LOG_ERROR("sd_bus_message_at_end failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001043 return r;
1044 }
1045
1046 if (r > 0)
1047 {
1048 break;
1049 }
1050
1051 // Dictionaries are only ever seen in an array
1052 if (dict)
1053 {
1054 r = readDictEntryFromMessage(containedType, m, data);
1055 if (r < 0)
1056 {
1057 return r;
1058 }
1059 }
1060 else
1061 {
1062 data.push_back(nlohmann::json());
1063
1064 r = convertDBusToJSON(containedType, m, data.back());
1065 if (r < 0)
1066 {
1067 return r;
1068 }
1069 }
1070 }
1071
1072 r = sd_bus_message_exit_container(m.get());
1073 if (r < 0)
1074 {
Ed Tanous62598e32023-07-17 17:06:25 -07001075 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001076 return r;
1077 }
1078
1079 return 0;
1080}
1081
Ed Tanous23a21a12020-07-25 04:45:05 +00001082inline int readStructFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001083 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001084{
1085 if (typeCode.size() < 3)
1086 {
Ed Tanous62598e32023-07-17 17:06:25 -07001087 BMCWEB_LOG_ERROR("Type code {} too small for a struct", typeCode);
Matt Spinler75c6c672019-01-14 13:01:46 -06001088 return -1;
1089 }
1090
1091 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1092 std::vector<std::string> types = dbusArgSplit(containedTypes);
1093
1094 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1095 containedTypes.c_str());
1096 if (r < 0)
1097 {
Ed Tanous62598e32023-07-17 17:06:25 -07001098 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler75c6c672019-01-14 13:01:46 -06001099 return r;
1100 }
1101
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001102 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001103 {
1104 data.push_back(nlohmann::json());
1105 r = convertDBusToJSON(type, m, data.back());
1106 if (r < 0)
1107 {
1108 return r;
1109 }
1110 }
1111
1112 r = sd_bus_message_exit_container(m.get());
1113 if (r < 0)
1114 {
Ed Tanous62598e32023-07-17 17:06:25 -07001115 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler75c6c672019-01-14 13:01:46 -06001116 return r;
1117 }
1118 return 0;
1119}
1120
Patrick Williams59d494e2022-07-22 19:26:55 -05001121inline int readVariantFromMessage(sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001122{
Ed Tanous543f4402022-01-06 13:12:53 -08001123 const char* containerType = nullptr;
Ed Tanous99131cd2019-10-24 11:12:47 -07001124 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001125 if (r < 0)
1126 {
Ed Tanous62598e32023-07-17 17:06:25 -07001127 BMCWEB_LOG_ERROR("sd_bus_message_peek_type failed");
Matt Spinler89c19702019-01-14 13:13:00 -06001128 return r;
1129 }
1130
1131 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1132 containerType);
1133 if (r < 0)
1134 {
Ed Tanous62598e32023-07-17 17:06:25 -07001135 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler89c19702019-01-14 13:13:00 -06001136 return r;
1137 }
1138
1139 r = convertDBusToJSON(containerType, m, data);
1140 if (r < 0)
1141 {
1142 return r;
1143 }
1144
1145 r = sd_bus_message_exit_container(m.get());
1146 if (r < 0)
1147 {
Ed Tanous62598e32023-07-17 17:06:25 -07001148 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed");
Matt Spinler89c19702019-01-14 13:13:00 -06001149 return r;
1150 }
1151
1152 return 0;
1153}
1154
Ed Tanous23a21a12020-07-25 04:45:05 +00001155inline int convertDBusToJSON(const std::string& returnType,
Patrick Williams59d494e2022-07-22 19:26:55 -05001156 sdbusplus::message_t& m, nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001157{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001158 int r = 0;
1159 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1160
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001161 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001162 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001163 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001164 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001165 {
1166 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001167 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001168 }
1169
Ed Tanousd4d25792020-09-29 15:15:03 -07001170 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001171 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001172 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001173 if (r < 0)
1174 {
1175 return r;
1176 }
1177 }
1178 else if (typeCode == "b")
1179 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001180 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001181 if (r < 0)
1182 {
1183 return r;
1184 }
1185
Matt Spinlerf39420c2019-01-30 12:57:18 -06001186 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001187 }
1188 else if (typeCode == "u")
1189 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001190 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001191 if (r < 0)
1192 {
1193 return r;
1194 }
1195 }
1196 else if (typeCode == "i")
1197 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001198 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001199 if (r < 0)
1200 {
1201 return r;
1202 }
1203 }
1204 else if (typeCode == "x")
1205 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001206 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001207 if (r < 0)
1208 {
1209 return r;
1210 }
1211 }
1212 else if (typeCode == "t")
1213 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001214 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001215 if (r < 0)
1216 {
1217 return r;
1218 }
1219 }
1220 else if (typeCode == "n")
1221 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001222 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001223 if (r < 0)
1224 {
1225 return r;
1226 }
1227 }
1228 else if (typeCode == "q")
1229 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001230 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001231 if (r < 0)
1232 {
1233 return r;
1234 }
1235 }
1236 else if (typeCode == "y")
1237 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001238 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001239 if (r < 0)
1240 {
1241 return r;
1242 }
1243 }
1244 else if (typeCode == "d")
1245 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001246 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001247 if (r < 0)
1248 {
1249 return r;
1250 }
1251 }
1252 else if (typeCode == "h")
1253 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001254 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001255 if (r < 0)
1256 {
1257 return r;
1258 }
1259 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001260 else if (typeCode.starts_with("a"))
Matt Spinler6df8f992019-01-14 12:47:47 -06001261 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001262 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001263 if (r < 0)
1264 {
1265 return r;
1266 }
1267 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001268 else if (typeCode.starts_with("(") && typeCode.ends_with(")"))
Matt Spinler75c6c672019-01-14 13:01:46 -06001269 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001270 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001271 if (r < 0)
1272 {
1273 return r;
1274 }
1275 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001276 else if (typeCode.starts_with("v"))
Matt Spinler89c19702019-01-14 13:13:00 -06001277 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001278 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001279 if (r < 0)
1280 {
1281 return r;
1282 }
1283 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001284 else
1285 {
Ed Tanous62598e32023-07-17 17:06:25 -07001286 BMCWEB_LOG_ERROR("Invalid D-Bus signature type {}", typeCode);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001287 return -2;
1288 }
1289 }
1290
Matt Spinler16caaee2019-01-15 11:40:34 -06001291 return 0;
1292}
1293
Ed Tanousb5a76932020-09-29 16:16:58 -07001294inline void handleMethodResponse(
1295 const std::shared_ptr<InProgressActionData>& transaction,
Patrick Williams59d494e2022-07-22 19:26:55 -05001296 sdbusplus::message_t& m, const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001297{
Matt Spinler39a4e392019-01-15 11:53:13 -06001298 nlohmann::json data;
1299
1300 int r = convertDBusToJSON(returnType, m, data);
1301 if (r < 0)
1302 {
1303 transaction->outputFailed = true;
1304 return;
1305 }
1306
1307 if (data.is_null())
1308 {
1309 return;
1310 }
1311
1312 if (transaction->methodResponse.is_null())
1313 {
1314 transaction->methodResponse = std::move(data);
1315 return;
1316 }
1317
1318 // If they're both dictionaries or arrays, merge into one.
1319 // Otherwise, make the results an array with every result
1320 // an entry. Could also just fail in that case, but it
1321 // seems better to get the data back somehow.
Ed Tanous0bdda662023-08-03 17:27:34 -07001322 nlohmann::json::object_t* dataobj =
1323 data.get_ptr<nlohmann::json::object_t*>();
1324 if (transaction->methodResponse.is_object() && dataobj != nullptr)
Matt Spinler39a4e392019-01-15 11:53:13 -06001325 {
Ed Tanous0bdda662023-08-03 17:27:34 -07001326 for (auto& obj : *dataobj)
Matt Spinler39a4e392019-01-15 11:53:13 -06001327 {
1328 // Note: Will overwrite the data for a duplicate key
Ed Tanous0bdda662023-08-03 17:27:34 -07001329 transaction->methodResponse.emplace(obj.first,
1330 std::move(obj.second));
Matt Spinler39a4e392019-01-15 11:53:13 -06001331 }
1332 return;
1333 }
1334
Ed Tanous0bdda662023-08-03 17:27:34 -07001335 nlohmann::json::array_t* dataarr = data.get_ptr<nlohmann::json::array_t*>();
1336 if (transaction->methodResponse.is_array() && dataarr != nullptr)
Matt Spinler39a4e392019-01-15 11:53:13 -06001337 {
Ed Tanous0bdda662023-08-03 17:27:34 -07001338 for (auto& obj : *dataarr)
Matt Spinler39a4e392019-01-15 11:53:13 -06001339 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001340 transaction->methodResponse.emplace_back(std::move(obj));
Matt Spinler39a4e392019-01-15 11:53:13 -06001341 }
1342 return;
1343 }
1344
1345 if (!transaction->convertedToArray)
1346 {
1347 // They are different types. May as well turn them into an array
1348 nlohmann::json j = std::move(transaction->methodResponse);
1349 transaction->methodResponse = nlohmann::json::array();
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001350 transaction->methodResponse.emplace_back(std::move(j));
1351 transaction->methodResponse.emplace_back(std::move(data));
Matt Spinler39a4e392019-01-15 11:53:13 -06001352 transaction->convertedToArray = true;
1353 }
1354 else
1355 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001356 transaction->methodResponse.emplace_back(std::move(data));
Matt Spinler39a4e392019-01-15 11:53:13 -06001357 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001358}
1359
Ed Tanousb5a76932020-09-29 16:16:58 -07001360inline void findActionOnInterface(
1361 const std::shared_ptr<InProgressActionData>& transaction,
1362 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001363{
Ed Tanous62598e32023-07-17 17:06:25 -07001364 BMCWEB_LOG_DEBUG("findActionOnInterface for connection {}", connectionName);
Ed Tanous177612a2025-02-14 15:16:09 -08001365 dbus::utility::async_method_call(
Ed Tanous1abe55e2018-09-05 08:30:59 -07001366 [transaction, connectionName{std::string(connectionName)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001367 const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001368 const std::string& introspectXml) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001369 BMCWEB_LOG_DEBUG("got xml:\n {}", introspectXml);
1370 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001371 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001372 BMCWEB_LOG_ERROR(
1373 "Introspect call failed with error: {} on process: {}",
1374 ec.message(), connectionName);
1375 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001376 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001377 tinyxml2::XMLDocument doc;
1378
1379 doc.Parse(introspectXml.data(), introspectXml.size());
1380 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1381 if (pRoot == nullptr)
1382 {
1383 BMCWEB_LOG_ERROR("XML document failed to parse {}",
1384 connectionName);
1385 return;
1386 }
1387 tinyxml2::XMLElement* interfaceNode =
1388 pRoot->FirstChildElement("interface");
1389 while (interfaceNode != nullptr)
1390 {
1391 const char* thisInterfaceName =
1392 interfaceNode->Attribute("name");
1393 if (thisInterfaceName != nullptr)
1394 {
1395 if (!transaction->interfaceName.empty() &&
1396 (transaction->interfaceName != thisInterfaceName))
1397 {
1398 interfaceNode =
1399 interfaceNode->NextSiblingElement("interface");
1400 continue;
1401 }
1402
1403 tinyxml2::XMLElement* methodNode =
1404 interfaceNode->FirstChildElement("method");
1405 while (methodNode != nullptr)
1406 {
1407 const char* thisMethodName =
1408 methodNode->Attribute("name");
1409 BMCWEB_LOG_DEBUG("Found method: {}", thisMethodName);
1410 if (thisMethodName != nullptr &&
1411 thisMethodName == transaction->methodName)
1412 {
1413 BMCWEB_LOG_DEBUG(
1414 "Found method named {} on interface {}",
1415 thisMethodName, thisInterfaceName);
1416 sdbusplus::message_t m =
1417 crow::connections::systemBus->new_method_call(
1418 connectionName.c_str(),
1419 transaction->path.c_str(),
1420 thisInterfaceName,
1421 transaction->methodName.c_str());
1422
1423 tinyxml2::XMLElement* argumentNode =
1424 methodNode->FirstChildElement("arg");
1425
1426 std::string returnType;
1427
1428 // Find the output type
1429 while (argumentNode != nullptr)
1430 {
1431 const char* argDirection =
1432 argumentNode->Attribute("direction");
1433 const char* argType =
1434 argumentNode->Attribute("type");
1435 if (argDirection != nullptr &&
1436 argType != nullptr &&
1437 std::string(argDirection) == "out")
1438 {
1439 returnType = argType;
1440 break;
1441 }
1442 argumentNode =
1443 argumentNode->NextSiblingElement("arg");
1444 }
1445
1446 auto argIt = transaction->arguments.begin();
1447
1448 argumentNode = methodNode->FirstChildElement("arg");
1449
1450 while (argumentNode != nullptr)
1451 {
1452 const char* argDirection =
1453 argumentNode->Attribute("direction");
1454 const char* argType =
1455 argumentNode->Attribute("type");
1456 if (argDirection != nullptr &&
1457 argType != nullptr &&
1458 std::string(argDirection) == "in")
1459 {
1460 if (argIt == transaction->arguments.end())
1461 {
1462 transaction->setErrorStatus(
1463 "Invalid method args");
1464 return;
1465 }
1466 if (convertJsonToDbus(m.get(),
1467 std::string(argType),
1468 *argIt) < 0)
1469 {
1470 transaction->setErrorStatus(
1471 "Invalid method arg type");
1472 return;
1473 }
1474
1475 argIt++;
1476 }
1477 argumentNode =
1478 argumentNode->NextSiblingElement("arg");
1479 }
1480
1481 crow::connections::systemBus->async_send(
1482 m, [transaction, returnType](
1483 const boost::system::error_code& ec2,
1484 sdbusplus::message_t& m2) {
1485 if (ec2)
1486 {
1487 transaction->methodFailed = true;
1488 const sd_bus_error* e = m2.get_error();
1489
1490 if (e != nullptr)
1491 {
1492 setErrorResponse(
1493 transaction->asyncResp->res,
1494 boost::beast::http::status::
1495 bad_request,
1496 e->name, e->message);
1497 }
1498 else
1499 {
1500 setErrorResponse(
1501 transaction->asyncResp->res,
1502 boost::beast::http::status::
1503 bad_request,
1504 "Method call failed",
1505 methodFailedMsg);
1506 }
1507 return;
1508 }
1509 transaction->methodPassed = true;
1510
1511 handleMethodResponse(transaction, m2,
1512 returnType);
1513 });
1514 break;
1515 }
1516 methodNode = methodNode->NextSiblingElement("method");
1517 }
1518 }
1519 interfaceNode = interfaceNode->NextSiblingElement("interface");
1520 }
1521 },
Ed Tanous1abe55e2018-09-05 08:30:59 -07001522 connectionName, transaction->path,
1523 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001524}
1525
zhanghch058d1b46d2021-04-01 11:18:24 +08001526inline void handleAction(const crow::Request& req,
1527 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001528 const std::string& objectPath,
1529 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001530{
Ed Tanous62598e32023-07-17 17:06:25 -07001531 BMCWEB_LOG_DEBUG("handleAction on path: {} and method {}", objectPath,
1532 methodName);
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001533 nlohmann::json requestDbusData;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001534
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001535 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
1536 if (ret == JsonParseResult::BadContentType)
1537 {
1538 setErrorResponse(asyncResp->res,
1539 boost::beast::http::status::unsupported_media_type,
1540 invalidContentType, unsupportedMediaMsg);
1541 return;
1542 }
1543 if (ret != JsonParseResult::Success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001544 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001545 setErrorResponse(asyncResp->res,
1546 boost::beast::http::status::bad_request, noJsonDesc,
1547 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001548 return;
1549 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001550 nlohmann::json::iterator data = requestDbusData.find("data");
1551 if (data == requestDbusData.end())
1552 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001553 setErrorResponse(asyncResp->res,
1554 boost::beast::http::status::bad_request, noJsonDesc,
1555 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001556 return;
1557 }
1558
1559 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001560 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001561 setErrorResponse(asyncResp->res,
1562 boost::beast::http::status::bad_request, noJsonDesc,
1563 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001564 return;
1565 }
Lei YU28dd5ca2023-03-17 13:17:05 +08001566 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001567
1568 transaction->path = objectPath;
1569 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001570 transaction->arguments = std::move(*data);
George Liu2b731192023-01-11 16:27:13 +08001571 dbus::utility::getDbusObject(
1572 objectPath, {},
Ed Tanous1abe55e2018-09-05 08:30:59 -07001573 [transaction](
George Liu2b731192023-01-11 16:27:13 +08001574 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001575 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1576 interfaceNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001577 if (ec || interfaceNames.empty())
1578 {
1579 BMCWEB_LOG_ERROR("Can't find object");
1580 setErrorResponse(transaction->asyncResp->res,
1581 boost::beast::http::status::not_found,
1582 notFoundDesc, notFoundMsg);
1583 return;
1584 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001585
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001586 BMCWEB_LOG_DEBUG("GetObject returned {} object(s)",
1587 interfaceNames.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001588
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001589 for (const std::pair<std::string, std::vector<std::string>>&
1590 object : interfaceNames)
1591 {
1592 findActionOnInterface(transaction, object.first);
1593 }
1594 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001595}
1596
zhanghch058d1b46d2021-04-01 11:18:24 +08001597inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1598 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001599{
Ed Tanous62598e32023-07-17 17:06:25 -07001600 BMCWEB_LOG_DEBUG("handleDelete on path: {}", objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06001601
George Liu2b731192023-01-11 16:27:13 +08001602 dbus::utility::getDbusObject(
1603 objectPath, {},
zhanghch058d1b46d2021-04-01 11:18:24 +08001604 [asyncResp, objectPath](
George Liu2b731192023-01-11 16:27:13 +08001605 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001606 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1607 interfaceNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001608 if (ec || interfaceNames.empty())
1609 {
1610 BMCWEB_LOG_ERROR("Can't find object");
1611 setErrorResponse(asyncResp->res,
1612 boost::beast::http::status::method_not_allowed,
1613 methodNotAllowedDesc, methodNotAllowedMsg);
1614 return;
1615 }
Matt Spinlerde818812018-12-11 16:39:20 -06001616
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001617 auto transaction =
1618 std::make_shared<InProgressActionData>(asyncResp);
1619 transaction->path = objectPath;
1620 transaction->methodName = "Delete";
1621 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
Matt Spinlerde818812018-12-11 16:39:20 -06001622
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001623 for (const std::pair<std::string, std::vector<std::string>>&
1624 object : interfaceNames)
1625 {
1626 findActionOnInterface(transaction, object.first);
1627 }
1628 });
Matt Spinlerde818812018-12-11 16:39:20 -06001629}
1630
zhanghch058d1b46d2021-04-01 11:18:24 +08001631inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1632 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001633{
George Liu7a1dbc42022-12-07 16:03:22 +08001634 dbus::utility::getSubTreePaths(
1635 objectPath, depth, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001636 [asyncResp](
George Liu7a1dbc42022-12-07 16:03:22 +08001637 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001638 const dbus::utility::MapperGetSubTreePathsResponse& objectPaths) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001639 if (ec)
1640 {
1641 setErrorResponse(asyncResp->res,
1642 boost::beast::http::status::not_found,
1643 notFoundDesc, notFoundMsg);
1644 }
1645 else
1646 {
1647 asyncResp->res.jsonValue["status"] = "ok";
1648 asyncResp->res.jsonValue["message"] = "200 OK";
1649 asyncResp->res.jsonValue["data"] = objectPaths;
1650 }
1651 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001652}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001653
zhanghch058d1b46d2021-04-01 11:18:24 +08001654inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1655 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001656{
Ed Tanous62598e32023-07-17 17:06:25 -07001657 BMCWEB_LOG_DEBUG("Doing enumerate on {}", objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07001658
Ed Tanous14766872022-03-15 10:44:42 -07001659 asyncResp->res.jsonValue["message"] = "200 OK";
1660 asyncResp->res.jsonValue["status"] = "ok";
1661 asyncResp->res.jsonValue["data"] = nlohmann::json::object();
Ed Tanous049a0512018-11-01 13:58:42 -07001662
George Liue99073f2022-12-09 11:06:16 +08001663 dbus::utility::getSubTree(
1664 objectPath, 0, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001665 [objectPath, asyncResp](
George Liue99073f2022-12-09 11:06:16 +08001666 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001667 const dbus::utility::MapperGetSubTreeResponse& objectNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001668 auto transaction = std::make_shared<InProgressEnumerateData>(
1669 objectPath, asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001670
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001671 transaction->subtree =
1672 std::make_shared<dbus::utility::MapperGetSubTreeResponse>(
1673 objectNames);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001674
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001675 if (ec)
1676 {
1677 BMCWEB_LOG_ERROR("GetSubTree failed on {}",
1678 transaction->objectPath);
1679 setErrorResponse(transaction->asyncResp->res,
1680 boost::beast::http::status::not_found,
1681 notFoundDesc, notFoundMsg);
1682 return;
1683 }
Ed Tanous64530012018-02-06 17:08:16 -08001684
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001685 // Add the data for the path passed in to the results
1686 // as if GetSubTree returned it, and continue on enumerating
1687 getObjectAndEnumerate(transaction);
1688 });
Ed Tanous64530012018-02-06 17:08:16 -08001689}
Ed Tanous911ac312017-08-15 09:37:42 -07001690
zhanghch058d1b46d2021-04-01 11:18:24 +08001691inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1692 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001693{
Ed Tanous62598e32023-07-17 17:06:25 -07001694 BMCWEB_LOG_DEBUG("handleGet: {} prop:{}", objectPath, destProperty);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001695 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001696 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001697
Ed Tanous1abe55e2018-09-05 08:30:59 -07001698 std::shared_ptr<std::string> path =
1699 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001700
George Liu2b731192023-01-11 16:27:13 +08001701 dbus::utility::getDbusObject(
1702 *path, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001703 [asyncResp, path,
George Liu2b731192023-01-11 16:27:13 +08001704 propertyName](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001705 const dbus::utility::MapperGetObject& objectNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001706 if (ec || objectNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001707 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001708 setErrorResponse(asyncResp->res,
1709 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001710 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001711 return;
1712 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001713 std::shared_ptr<nlohmann::json> response =
1714 std::make_shared<nlohmann::json>(nlohmann::json::object());
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001715 for (const std::pair<std::string, std::vector<std::string>>&
1716 connection : objectNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001717 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001718 const std::vector<std::string>& interfaceNames =
1719 connection.second;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001720
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001721 if (interfaceNames.empty())
1722 {
Lei YU65622a52025-01-20 09:45:50 +00001723 // mapper allows empty interfaces in case an
1724 // object does not implement any interface.
1725 continue;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001726 }
1727
1728 for (const std::string& interface : interfaceNames)
1729 {
1730 sdbusplus::message_t m =
1731 crow::connections::systemBus->new_method_call(
1732 connection.first.c_str(), path->c_str(),
1733 "org.freedesktop.DBus.Properties", "GetAll");
1734 m.append(interface);
1735 crow::connections::systemBus->async_send(
1736 m, [asyncResp, response,
1737 propertyName](const boost::system::error_code& ec2,
1738 sdbusplus::message_t& msg) {
1739 if (ec2)
1740 {
1741 BMCWEB_LOG_ERROR("Bad dbus request error: {}",
1742 ec2);
1743 }
1744 else
1745 {
1746 nlohmann::json properties;
1747 int r =
1748 convertDBusToJSON("a{sv}", msg, properties);
1749 if (r < 0)
Patrick Williams5a39f772023-10-20 11:20:21 -05001750 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001751 BMCWEB_LOG_ERROR(
1752 "convertDBusToJSON failed");
Patrick Williams5a39f772023-10-20 11:20:21 -05001753 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001754 else
Patrick Williams5a39f772023-10-20 11:20:21 -05001755 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001756 nlohmann::json::object_t* obj =
1757 properties.get_ptr<
1758 nlohmann::json::object_t*>();
1759 if (obj == nullptr)
1760 {
1761 return;
1762 }
1763 for (auto& prop : *obj)
1764 {
1765 // if property name is empty, or
1766 // matches our search query, add it
1767 // to the response json
1768
1769 if (propertyName->empty())
1770 {
1771 (*response)[prop.first] =
1772 std::move(prop.second);
1773 }
1774 else if (prop.first == *propertyName)
1775 {
1776 *response = std::move(prop.second);
1777 }
1778 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001779 }
1780 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001781 if (response.use_count() == 1)
1782 {
1783 if (!propertyName->empty() && response->empty())
1784 {
1785 setErrorResponse(
1786 asyncResp->res,
1787 boost::beast::http::status::not_found,
1788 propNotFoundDesc, notFoundMsg);
1789 }
1790 else
1791 {
1792 asyncResp->res.jsonValue["status"] = "ok";
1793 asyncResp->res.jsonValue["message"] =
1794 "200 OK";
1795 asyncResp->res.jsonValue["data"] =
1796 *response;
1797 }
1798 }
1799 });
1800 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001801 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001802 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001803}
1804
Ed Tanous1abe55e2018-09-05 08:30:59 -07001805struct AsyncPutRequest
1806{
Ed Tanous4e23a442022-06-06 09:57:26 -07001807 explicit AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
zhanghch058d1b46d2021-04-01 11:18:24 +08001808 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001809 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001810 ~AsyncPutRequest()
1811 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001812 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001813 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001814 setErrorResponse(asyncResp->res,
1815 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001816 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001817 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001818 }
1819
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001820 AsyncPutRequest(const AsyncPutRequest&) = delete;
1821 AsyncPutRequest(AsyncPutRequest&&) = delete;
1822 AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1823 AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1824
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001825 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001826 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001827 setErrorResponse(asyncResp->res,
1828 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001829 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001830 }
1831
zhanghch058d1b46d2021-04-01 11:18:24 +08001832 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001833 std::string objectPath;
1834 std::string propertyName;
1835 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001836};
1837
zhanghch058d1b46d2021-04-01 11:18:24 +08001838inline void handlePut(const crow::Request& req,
1839 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001840 const std::string& objectPath,
1841 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001842{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001843 if (destProperty.empty())
1844 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001845 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001846 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001847 return;
1848 }
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001849 nlohmann::json requestDbusData;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001850
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001851 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
1852 if (ret == JsonParseResult::BadContentType)
1853 {
1854 setErrorResponse(asyncResp->res,
1855 boost::beast::http::status::unsupported_media_type,
1856 invalidContentType, unsupportedMediaMsg);
1857 return;
1858 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001859
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001860 if (ret != JsonParseResult::Success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001861 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001862 setErrorResponse(asyncResp->res,
1863 boost::beast::http::status::bad_request, noJsonDesc,
1864 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001865 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001866 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001867
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001868 auto propertyIt = requestDbusData.find("data");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001869 if (propertyIt == requestDbusData.end())
1870 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001871 setErrorResponse(asyncResp->res,
1872 boost::beast::http::status::bad_request, noJsonDesc,
1873 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001874 return;
1875 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001876 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001877 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001878 transaction->objectPath = objectPath;
1879 transaction->propertyName = destProperty;
1880 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001881
George Liu2b731192023-01-11 16:27:13 +08001882 dbus::utility::getDbusObject(
1883 transaction->objectPath, {},
1884 [transaction](const boost::system::error_code& ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001885 const dbus::utility::MapperGetObject& objectNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001886 if (!ec2 && objectNames.empty())
1887 {
1888 setErrorResponse(transaction->asyncResp->res,
1889 boost::beast::http::status::not_found,
1890 propNotFoundDesc, notFoundMsg);
1891 return;
1892 }
Ed Tanous911ac312017-08-15 09:37:42 -07001893
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001894 for (const std::pair<std::string, std::vector<std::string>>&
1895 connection : objectNames)
1896 {
1897 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001898
Ed Tanous177612a2025-02-14 15:16:09 -08001899 dbus::utility::async_method_call(
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001900 [connectionName{std::string(connectionName)},
1901 transaction](const boost::system::error_code& ec3,
1902 const std::string& introspectXml) {
1903 if (ec3)
Ed Tanousb0b61522024-08-06 10:20:49 -07001904 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001905 BMCWEB_LOG_ERROR(
1906 "Introspect call failed with error: {} on process: {}",
1907 ec3.message(), connectionName);
1908 transaction->setErrorStatus("Unexpected Error");
1909 return;
Ed Tanousb0b61522024-08-06 10:20:49 -07001910 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001911 tinyxml2::XMLDocument doc;
1912
1913 doc.Parse(introspectXml.c_str());
1914 tinyxml2::XMLNode* pRoot =
1915 doc.FirstChildElement("node");
1916 if (pRoot == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001917 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001918 BMCWEB_LOG_ERROR("XML document failed to parse: {}",
1919 introspectXml);
1920 transaction->setErrorStatus("Unexpected Error");
1921 return;
1922 }
1923 tinyxml2::XMLElement* ifaceNode =
1924 pRoot->FirstChildElement("interface");
1925 while (ifaceNode != nullptr)
1926 {
1927 const char* interfaceName =
1928 ifaceNode->Attribute("name");
1929 BMCWEB_LOG_DEBUG("found interface {}",
1930 interfaceName);
1931 tinyxml2::XMLElement* propNode =
1932 ifaceNode->FirstChildElement("property");
1933 while (propNode != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001934 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001935 const char* propertyName =
1936 propNode->Attribute("name");
1937 if (propertyName == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001938 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001939 BMCWEB_LOG_DEBUG(
1940 "Couldn't find name property");
1941 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001942 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001943 BMCWEB_LOG_DEBUG("Found property {}",
1944 propertyName);
1945 if (propertyName == transaction->propertyName)
Ed Tanous002d39b2022-05-31 08:59:27 -07001946 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001947 const char* argType =
1948 propNode->Attribute("type");
1949 if (argType != nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07001950 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001951 sdbusplus::message_t m =
1952 crow::connections::systemBus
1953 ->new_method_call(
1954 connectionName.c_str(),
1955 transaction->objectPath
1956 .c_str(),
1957 "org.freedesktop.DBus."
1958 "Properties",
1959 "Set");
1960 m.append(interfaceName,
1961 transaction->propertyName);
1962 int r = sd_bus_message_open_container(
1963 m.get(), SD_BUS_TYPE_VARIANT,
1964 argType);
1965 if (r < 0)
1966 {
1967 transaction->setErrorStatus(
1968 "Unexpected Error");
1969 return;
1970 }
1971 r = convertJsonToDbus(
1972 m.get(), argType,
1973 transaction->propertyValue);
1974 if (r < 0)
1975 {
1976 if (r == -ERANGE)
1977 {
1978 transaction->setErrorStatus(
1979 "Provided property value "
1980 "is out of range for the "
1981 "property type");
1982 }
1983 else
1984 {
1985 transaction->setErrorStatus(
1986 "Invalid arg type");
1987 }
1988 return;
1989 }
1990 r = sd_bus_message_close_container(
1991 m.get());
1992 if (r < 0)
1993 {
1994 transaction->setErrorStatus(
1995 "Unexpected Error");
1996 return;
1997 }
1998 crow::connections::systemBus
1999 ->async_send(
2000 m,
2001 [transaction](
2002 const boost::system::
2003 error_code& ec,
2004 sdbusplus::message_t& m2) {
2005 BMCWEB_LOG_DEBUG("sent");
2006 if (ec)
2007 {
2008 const sd_bus_error* e =
2009 m2.get_error();
2010 setErrorResponse(
2011 transaction
2012 ->asyncResp
2013 ->res,
2014 boost::beast::http::
2015 status::
2016 forbidden,
2017 (e) != nullptr
2018 ? e->name
2019 : ec.category()
2020 .name(),
2021 (e) != nullptr
2022 ? e->message
2023 : ec.message());
2024 }
2025 else
2026 {
2027 transaction->asyncResp
2028 ->res.jsonValue
2029 ["status"] =
2030 "ok";
2031 transaction->asyncResp
2032 ->res.jsonValue
2033 ["message"] =
2034 "200 OK";
2035 transaction->asyncResp
2036 ->res
2037 .jsonValue["data"] =
2038 nullptr;
2039 }
2040 });
Ed Tanous002d39b2022-05-31 08:59:27 -07002041 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002042 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002043 propNode =
2044 propNode->NextSiblingElement("property");
Ed Tanous1abe55e2018-09-05 08:30:59 -07002045 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002046 ifaceNode =
2047 ifaceNode->NextSiblingElement("interface");
Ed Tanous1abe55e2018-09-05 08:30:59 -07002048 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002049 },
2050 connectionName, transaction->objectPath,
2051 "org.freedesktop.DBus.Introspectable", "Introspect");
2052 }
2053 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07002054}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002055
zhanghch058d1b46d2021-04-01 11:18:24 +08002056inline void handleDBusUrl(const crow::Request& req,
2057 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002058 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002059{
Ed Tanous049a0512018-11-01 13:58:42 -07002060 // If accessing a single attribute, fill in and update objectPath,
2061 // otherwise leave destProperty blank
Ed Tanouse05aec52022-01-25 10:28:56 -08002062 std::string destProperty;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002063 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002064 size_t attrPosition = objectPath.find(attrSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002065 if (attrPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002066 {
2067 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2068 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002069 objectPath.resize(attrPosition);
Ed Tanous049a0512018-11-01 13:58:42 -07002070 }
2071
Ed Tanousb41187f2019-10-24 16:30:02 -07002072 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002073 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002074 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002075 size_t actionPosition = objectPath.find(actionSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002076 if (actionPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002077 {
2078 std::string postProperty =
2079 objectPath.substr((actionPosition + strlen(actionSeperator)),
2080 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002081 objectPath.resize(actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002082 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002083 return;
2084 }
2085 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002086 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002087 {
Ed Tanous11ba3972022-07-11 09:50:41 -07002088 if (objectPath.ends_with("/enumerate"))
Ed Tanous049a0512018-11-01 13:58:42 -07002089 {
2090 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2091 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002092 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002093 }
Ed Tanous11ba3972022-07-11 09:50:41 -07002094 else if (objectPath.ends_with("/list"))
Ed Tanous049a0512018-11-01 13:58:42 -07002095 {
2096 objectPath.erase(objectPath.end() - sizeof("list"),
2097 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002098 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002099 }
2100 else
2101 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002102 // Trim any trailing "/" at the end
Ed Tanous11ba3972022-07-11 09:50:41 -07002103 if (objectPath.ends_with("/"))
Ed Tanousf839dfe2018-11-12 11:11:15 -08002104 {
2105 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002106 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002107 }
2108 else
2109 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002110 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002111 }
Ed Tanous049a0512018-11-01 13:58:42 -07002112 }
2113 return;
2114 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002115 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002116 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002117 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002118 return;
2119 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002120 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002121 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002122 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002123 return;
2124 }
Ed Tanous049a0512018-11-01 13:58:42 -07002125
zhanghch058d1b46d2021-04-01 11:18:24 +08002126 setErrorResponse(asyncResp->res,
2127 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002128 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002129}
2130
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002131inline void handleBusSystemPost(
2132 const crow::Request& req,
2133 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2134 const std::string& processName, const std::string& requestedPath)
Ed Tanous1656b292022-05-04 11:33:42 -07002135{
2136 std::vector<std::string> strs;
Ed Tanous50ebd4a2023-01-19 19:03:17 -08002137
2138 bmcweb::split(strs, requestedPath, '/');
Ed Tanous1656b292022-05-04 11:33:42 -07002139 std::string objectPath;
2140 std::string interfaceName;
2141 std::string methodName;
2142 auto it = strs.begin();
2143 if (it == strs.end())
2144 {
2145 objectPath = "/";
2146 }
2147 while (it != strs.end())
2148 {
2149 // Check if segment contains ".". If it does, it must be an
2150 // interface
2151 if (it->find(".") != std::string::npos)
2152 {
2153 break;
2154 // This check is necessary as the trailing slash gets
2155 // parsed as part of our <path> specifier above, which
2156 // causes the normal trailing backslash redirector to
2157 // fail.
2158 }
2159 if (!it->empty())
2160 {
2161 objectPath += "/" + *it;
2162 }
2163 it++;
2164 }
2165 if (it != strs.end())
2166 {
2167 interfaceName = *it;
2168 it++;
2169
2170 // after interface, we might have a method name
2171 if (it != strs.end())
2172 {
2173 methodName = *it;
2174 it++;
2175 }
2176 }
2177 if (it != strs.end())
2178 {
2179 // if there is more levels past the method name, something
2180 // went wrong, return not found
2181 asyncResp->res.result(boost::beast::http::status::not_found);
2182 return;
2183 }
2184 if (interfaceName.empty())
2185 {
Ed Tanous177612a2025-02-14 15:16:09 -08002186 dbus::utility::async_method_call(
Ed Tanous1656b292022-05-04 11:33:42 -07002187 [asyncResp, processName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002188 objectPath](const boost::system::error_code& ec,
Ed Tanous1656b292022-05-04 11:33:42 -07002189 const std::string& introspectXml) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002190 if (ec)
Ed Tanous1656b292022-05-04 11:33:42 -07002191 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002192 BMCWEB_LOG_ERROR(
2193 "Introspect call failed with error: {} on process: {} path: {}",
2194 ec.message(), processName, objectPath);
2195 return;
2196 }
2197 tinyxml2::XMLDocument doc;
2198
2199 doc.Parse(introspectXml.c_str());
2200 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2201 if (pRoot == nullptr)
2202 {
2203 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
2204 processName, objectPath);
2205 asyncResp->res.jsonValue["status"] = "XML parse error";
2206 asyncResp->res.result(
2207 boost::beast::http::status::internal_server_error);
2208 return;
Ed Tanous1656b292022-05-04 11:33:42 -07002209 }
2210
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002211 BMCWEB_LOG_DEBUG("{}", introspectXml);
2212 asyncResp->res.jsonValue["status"] = "ok";
2213 asyncResp->res.jsonValue["bus_name"] = processName;
2214 asyncResp->res.jsonValue["object_path"] = objectPath;
2215
2216 nlohmann::json& interfacesArray =
2217 asyncResp->res.jsonValue["interfaces"];
2218 interfacesArray = nlohmann::json::array();
2219 tinyxml2::XMLElement* interface =
2220 pRoot->FirstChildElement("interface");
2221
2222 while (interface != nullptr)
2223 {
2224 const char* ifaceName = interface->Attribute("name");
2225 if (ifaceName != nullptr)
2226 {
2227 nlohmann::json::object_t interfaceObj;
2228 interfaceObj["name"] = ifaceName;
2229 interfacesArray.emplace_back(std::move(interfaceObj));
2230 }
2231
2232 interface = interface->NextSiblingElement("interface");
2233 }
2234 },
Ed Tanous1656b292022-05-04 11:33:42 -07002235 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2236 "Introspect");
2237 }
2238 else if (methodName.empty())
2239 {
Ed Tanous177612a2025-02-14 15:16:09 -08002240 dbus::utility::async_method_call(
Ed Tanous1656b292022-05-04 11:33:42 -07002241 [asyncResp, processName, objectPath,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002242 interfaceName](const boost::system::error_code& ec,
Ed Tanous1656b292022-05-04 11:33:42 -07002243 const std::string& introspectXml) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002244 if (ec)
Ed Tanous1656b292022-05-04 11:33:42 -07002245 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002246 BMCWEB_LOG_ERROR(
2247 "Introspect call failed with error: {} on process: {} path: {}",
2248 ec.message(), processName, objectPath);
2249 return;
2250 }
2251 tinyxml2::XMLDocument doc;
2252
2253 doc.Parse(introspectXml.data(), introspectXml.size());
2254 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2255 if (pRoot == nullptr)
2256 {
2257 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
2258 processName, objectPath);
2259 asyncResp->res.result(
2260 boost::beast::http::status::internal_server_error);
2261 return;
Ed Tanous1656b292022-05-04 11:33:42 -07002262 }
Ed Tanous14766872022-03-15 10:44:42 -07002263
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002264 asyncResp->res.jsonValue["status"] = "ok";
2265 asyncResp->res.jsonValue["bus_name"] = processName;
2266 asyncResp->res.jsonValue["interface"] = interfaceName;
2267 asyncResp->res.jsonValue["object_path"] = objectPath;
Ed Tanous1656b292022-05-04 11:33:42 -07002268
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002269 nlohmann::json& methodsArray =
2270 asyncResp->res.jsonValue["methods"];
2271 methodsArray = nlohmann::json::array();
2272
2273 nlohmann::json& signalsArray =
2274 asyncResp->res.jsonValue["signals"];
2275 signalsArray = nlohmann::json::array();
2276
2277 nlohmann::json& propertiesObj =
2278 asyncResp->res.jsonValue["properties"];
2279 propertiesObj = nlohmann::json::object();
2280
2281 // if we know we're the only call, build the
2282 // json directly
2283 tinyxml2::XMLElement* interface =
2284 pRoot->FirstChildElement("interface");
2285 while (interface != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002286 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002287 const char* ifaceName = interface->Attribute("name");
2288
2289 if (ifaceName != nullptr && ifaceName == interfaceName)
Ed Tanous1656b292022-05-04 11:33:42 -07002290 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002291 break;
Ed Tanous002d39b2022-05-31 08:59:27 -07002292 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002293
2294 interface = interface->NextSiblingElement("interface");
2295 }
2296 if (interface == nullptr)
2297 {
2298 // if we got to the end of the list and
2299 // never found a match, throw 404
2300 asyncResp->res.result(
2301 boost::beast::http::status::not_found);
2302 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07002303 }
2304
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002305 tinyxml2::XMLElement* methods =
2306 interface->FirstChildElement("method");
2307 while (methods != nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07002308 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002309 nlohmann::json argsArray = nlohmann::json::array();
2310 tinyxml2::XMLElement* arg =
2311 methods->FirstChildElement("arg");
2312 while (arg != nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07002313 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002314 nlohmann::json thisArg;
2315 for (const char* fieldName : std::array<const char*, 3>{
2316 "name", "direction", "type"})
2317 {
2318 const char* fieldValue = arg->Attribute(fieldName);
2319 if (fieldValue != nullptr)
2320 {
2321 thisArg[fieldName] = fieldValue;
2322 }
2323 }
2324 argsArray.emplace_back(std::move(thisArg));
2325 arg = arg->NextSiblingElement("arg");
Ed Tanous002d39b2022-05-31 08:59:27 -07002326 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002327
2328 const char* name = methods->Attribute("name");
2329 if (name != nullptr)
2330 {
2331 std::string uri;
2332 uri.reserve(14 + processName.size() +
2333 objectPath.size() + interfaceName.size() +
2334 strlen(name));
2335 uri += "/bus/system/";
2336 uri += processName;
2337 uri += objectPath;
2338 uri += "/";
2339 uri += interfaceName;
2340 uri += "/";
2341 uri += name;
2342
2343 nlohmann::json::object_t object;
2344 object["name"] = name;
2345 object["uri"] = std::move(uri);
2346 object["args"] = argsArray;
2347
2348 methodsArray.emplace_back(std::move(object));
2349 }
2350 methods = methods->NextSiblingElement("method");
Ed Tanous002d39b2022-05-31 08:59:27 -07002351 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002352 tinyxml2::XMLElement* signals =
2353 interface->FirstChildElement("signal");
2354 while (signals != nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07002355 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002356 nlohmann::json argsArray = nlohmann::json::array();
2357
2358 tinyxml2::XMLElement* arg =
2359 signals->FirstChildElement("arg");
2360 while (arg != nullptr)
2361 {
2362 const char* name = arg->Attribute("name");
2363 const char* type = arg->Attribute("type");
2364 if (name != nullptr && type != nullptr)
2365 {
2366 nlohmann::json::object_t params;
2367 params["name"] = name;
2368 params["type"] = type;
2369 argsArray.push_back(std::move(params));
2370 }
2371 arg = arg->NextSiblingElement("arg");
2372 }
2373 const char* name = signals->Attribute("name");
2374 if (name != nullptr)
2375 {
2376 nlohmann::json::object_t object;
2377 object["name"] = name;
2378 object["args"] = argsArray;
2379 signalsArray.emplace_back(std::move(object));
2380 }
2381
2382 signals = signals->NextSiblingElement("signal");
Ed Tanous002d39b2022-05-31 08:59:27 -07002383 }
2384
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002385 tinyxml2::XMLElement* property =
2386 interface->FirstChildElement("property");
2387 while (property != nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07002388 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002389 const char* name = property->Attribute("name");
2390 const char* type = property->Attribute("type");
2391 if (type != nullptr && name != nullptr)
2392 {
2393 sdbusplus::message_t m =
2394 crow::connections::systemBus->new_method_call(
2395 processName.c_str(), objectPath.c_str(),
2396 "org.freedesktop."
2397 "DBus."
2398 "Properties",
2399 "Get");
2400 m.append(interfaceName, name);
2401 nlohmann::json& propertyItem = propertiesObj[name];
2402 crow::connections::systemBus->async_send(
2403 m, [&propertyItem,
2404 asyncResp](const boost::system::error_code& ec2,
2405 sdbusplus::message_t& msg) {
2406 if (ec2)
2407 {
2408 return;
2409 }
Ed Tanous1656b292022-05-04 11:33:42 -07002410
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002411 int r =
2412 convertDBusToJSON("v", msg, propertyItem);
2413 if (r < 0)
2414 {
2415 BMCWEB_LOG_ERROR(
2416 "Couldn't convert vector to json");
2417 }
2418 });
2419 }
2420 property = property->NextSiblingElement("property");
Ed Tanous1656b292022-05-04 11:33:42 -07002421 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002422 },
Ed Tanous1656b292022-05-04 11:33:42 -07002423 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2424 "Introspect");
2425 }
2426 else
2427 {
2428 if (req.method() != boost::beast::http::verb::post)
2429 {
2430 asyncResp->res.result(boost::beast::http::status::not_found);
2431 return;
2432 }
2433
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002434 nlohmann::json requestDbusData;
2435 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
2436 if (ret == JsonParseResult::BadContentType)
Ed Tanous1656b292022-05-04 11:33:42 -07002437 {
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002438 setErrorResponse(asyncResp->res,
2439 boost::beast::http::status::unsupported_media_type,
2440 invalidContentType, unsupportedMediaMsg);
Ed Tanous1656b292022-05-04 11:33:42 -07002441 return;
2442 }
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002443 if (ret != JsonParseResult::Success)
2444 {
2445 setErrorResponse(asyncResp->res,
2446 boost::beast::http::status::bad_request,
2447 noJsonDesc, badReqMsg);
2448 return;
2449 }
2450
Ed Tanous1656b292022-05-04 11:33:42 -07002451 if (!requestDbusData.is_array())
2452 {
2453 asyncResp->res.result(boost::beast::http::status::bad_request);
2454 return;
2455 }
Lei YU28dd5ca2023-03-17 13:17:05 +08002456 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous1656b292022-05-04 11:33:42 -07002457
2458 transaction->path = objectPath;
2459 transaction->methodName = methodName;
2460 transaction->arguments = std::move(requestDbusData);
2461
2462 findActionOnInterface(transaction, processName);
2463 }
2464}
2465
Ed Tanous23a21a12020-07-25 04:45:05 +00002466inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002467{
2468 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002469 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002470 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002471 [](const crow::Request&,
2472 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002473 nlohmann::json::array_t buses;
2474 nlohmann::json& bus = buses.emplace_back();
2475 bus["name"] = "system";
2476 asyncResp->res.jsonValue["busses"] = std::move(buses);
2477 asyncResp->res.jsonValue["status"] = "ok";
2478 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002479
2480 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002481 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002482 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002483 [](const crow::Request&,
2484 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002485 auto myCallback = [asyncResp](
2486 const boost::system::error_code& ec,
zhanghch058d1b46d2021-04-01 11:18:24 +08002487 std::vector<std::string>& names) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002488 if (ec)
2489 {
2490 BMCWEB_LOG_ERROR("Dbus call failed with code {}", ec);
2491 asyncResp->res.result(
2492 boost::beast::http::status::internal_server_error);
2493 }
2494 else
2495 {
2496 std::ranges::sort(names);
2497 asyncResp->res.jsonValue["status"] = "ok";
2498 auto& objectsSub = asyncResp->res.jsonValue["objects"];
2499 for (const auto& name : names)
2500 {
2501 nlohmann::json::object_t object;
2502 object["name"] = name;
2503 objectsSub.emplace_back(std::move(object));
2504 }
2505 }
2506 };
Ed Tanous177612a2025-02-14 15:16:09 -08002507 dbus::utility::async_method_call(
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002508 std::move(myCallback), "org.freedesktop.DBus", "/",
2509 "org.freedesktop.DBus", "ListNames");
2510 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002511
2512 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002513 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002514 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002515 [](const crow::Request&,
2516 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002517 handleList(asyncResp, "/");
2518 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002519
2520 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002521 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002522 .methods(boost::beast::http::verb::get)(
2523 [](const crow::Request& req,
2524 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002525 const std::string& path) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002526 std::string objectPath = "/xyz/" + path;
2527 handleDBusUrl(req, asyncResp, objectPath);
2528 });
zhanghch058d1b46d2021-04-01 11:18:24 +08002529
2530 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002531 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002532 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2533 boost::beast::http::verb::delete_)(
2534 [](const crow::Request& req,
2535 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2536 const std::string& path) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002537 std::string objectPath = "/xyz/" + path;
2538 handleDBusUrl(req, asyncResp, objectPath);
2539 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002540
Ed Tanous049a0512018-11-01 13:58:42 -07002541 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002542 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002543 .methods(boost::beast::http::verb::get)(
2544 [](const crow::Request& req,
2545 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2546 const std::string& path) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002547 std::string objectPath = "/org/" + path;
2548 handleDBusUrl(req, asyncResp, objectPath);
2549 });
Tanousf00032d2018-11-05 01:18:10 -03002550
2551 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002552 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002553 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2554 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002555 [](const crow::Request& req,
2556 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002557 const std::string& path) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002558 std::string objectPath = "/org/" + path;
2559 handleDBusUrl(req, asyncResp, objectPath);
2560 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002561
Ed Tanous1abe55e2018-09-05 08:30:59 -07002562 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002563 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002564 .methods(boost::beast::http::verb::get)(
2565 [](const crow::Request&,
2566 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2567 const std::string& dumpId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002568 if (!validateFilename(dumpId))
2569 {
2570 asyncResp->res.result(
2571 boost::beast::http::status::bad_request);
2572 return;
2573 }
2574 std::filesystem::path loc(
2575 "/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002576
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002577 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002578
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002579 if (!std::filesystem::exists(loc) ||
2580 !std::filesystem::is_directory(loc))
2581 {
2582 BMCWEB_LOG_ERROR("{}Not found", loc.string());
2583 asyncResp->res.result(
2584 boost::beast::http::status::not_found);
2585 return;
2586 }
2587 std::filesystem::directory_iterator files(loc);
zhanghch058d1b46d2021-04-01 11:18:24 +08002588
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002589 for (const auto& file : files)
2590 {
Myung Baed51c61b2024-09-13 10:35:34 -05002591 if (asyncResp->res.openFile(file) !=
2592 crow::OpenCode::Success)
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002593 {
2594 continue;
2595 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002596
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002597 asyncResp->res.addHeader(
2598 boost::beast::http::field::content_type,
2599 "application/octet-stream");
zhanghch058d1b46d2021-04-01 11:18:24 +08002600
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002601 // Assuming only one dump file will be present in the dump
2602 // id directory
2603 std::string dumpFileName = file.path().filename().string();
zhanghch058d1b46d2021-04-01 11:18:24 +08002604
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002605 // Filename should be in alphanumeric, dot and underscore
2606 // Its based on phosphor-debug-collector application
2607 // dumpfile format
2608 static std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
2609 if (!std::regex_match(dumpFileName, dumpFileRegex))
2610 {
2611 BMCWEB_LOG_ERROR("Invalid dump filename {}",
2612 dumpFileName);
2613 asyncResp->res.result(
2614 boost::beast::http::status::not_found);
2615 return;
2616 }
2617 std::string contentDispositionParam =
2618 "attachment; filename=\"" + dumpFileName + "\"";
2619
2620 asyncResp->res.addHeader(
2621 boost::beast::http::field::content_disposition,
2622 contentDispositionParam);
2623
2624 return;
2625 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002626 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002627 return;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002628 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002629
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002630 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002631 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002632
2633 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002634 [](const crow::Request&,
2635 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002636 const std::string& connection) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002637 introspectObjects(connection, "/", asyncResp);
2638 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002639
2640 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002641 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous1656b292022-05-04 11:33:42 -07002642 .methods(boost::beast::http::verb::get,
2643 boost::beast::http::verb::post)(handleBusSystemPost);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002644}
2645} // namespace openbmc_mapper
2646} // namespace crow