blob: 5963486243efd1ea84faacfe18193ff0854203fc [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*>();
Ed Tanousd0a341b2024-10-18 14:20:33 -07001324
1325 nlohmann::json::object_t* methodResponseObj =
1326 transaction->methodResponse.get_ptr<nlohmann::json::object_t*>();
1327 if (methodResponseObj != nullptr && dataobj != nullptr)
Matt Spinler39a4e392019-01-15 11:53:13 -06001328 {
Ed Tanous0bdda662023-08-03 17:27:34 -07001329 for (auto& obj : *dataobj)
Matt Spinler39a4e392019-01-15 11:53:13 -06001330 {
1331 // Note: Will overwrite the data for a duplicate key
Ed Tanousd0a341b2024-10-18 14:20:33 -07001332 methodResponseObj->emplace(obj.first, std::move(obj.second));
Matt Spinler39a4e392019-01-15 11:53:13 -06001333 }
1334 return;
1335 }
1336
Ed Tanous0bdda662023-08-03 17:27:34 -07001337 nlohmann::json::array_t* dataarr = data.get_ptr<nlohmann::json::array_t*>();
Ed Tanousd0a341b2024-10-18 14:20:33 -07001338 nlohmann::json::array_t* methodResponseArr =
1339 transaction->methodResponse.get_ptr<nlohmann::json::array_t*>();
1340 if (methodResponseArr != nullptr && dataarr != nullptr)
Matt Spinler39a4e392019-01-15 11:53:13 -06001341 {
Ed Tanous0bdda662023-08-03 17:27:34 -07001342 for (auto& obj : *dataarr)
Matt Spinler39a4e392019-01-15 11:53:13 -06001343 {
Ed Tanousd0a341b2024-10-18 14:20:33 -07001344 methodResponseArr->emplace_back(std::move(obj));
Matt Spinler39a4e392019-01-15 11:53:13 -06001345 }
1346 return;
1347 }
1348
1349 if (!transaction->convertedToArray)
1350 {
1351 // They are different types. May as well turn them into an array
1352 nlohmann::json j = std::move(transaction->methodResponse);
1353 transaction->methodResponse = nlohmann::json::array();
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001354 transaction->methodResponse.emplace_back(std::move(j));
1355 transaction->methodResponse.emplace_back(std::move(data));
Matt Spinler39a4e392019-01-15 11:53:13 -06001356 transaction->convertedToArray = true;
1357 }
1358 else
1359 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001360 transaction->methodResponse.emplace_back(std::move(data));
Matt Spinler39a4e392019-01-15 11:53:13 -06001361 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001362}
1363
Ed Tanousb5a76932020-09-29 16:16:58 -07001364inline void findActionOnInterface(
1365 const std::shared_ptr<InProgressActionData>& transaction,
1366 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001367{
Ed Tanous62598e32023-07-17 17:06:25 -07001368 BMCWEB_LOG_DEBUG("findActionOnInterface for connection {}", connectionName);
Ed Tanous177612a2025-02-14 15:16:09 -08001369 dbus::utility::async_method_call(
Ed Tanous1abe55e2018-09-05 08:30:59 -07001370 [transaction, connectionName{std::string(connectionName)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001371 const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001372 const std::string& introspectXml) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001373 BMCWEB_LOG_DEBUG("got xml:\n {}", introspectXml);
1374 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001375 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001376 BMCWEB_LOG_ERROR(
1377 "Introspect call failed with error: {} on process: {}",
1378 ec.message(), connectionName);
1379 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001380 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001381 tinyxml2::XMLDocument doc;
1382
1383 doc.Parse(introspectXml.data(), introspectXml.size());
1384 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1385 if (pRoot == nullptr)
1386 {
1387 BMCWEB_LOG_ERROR("XML document failed to parse {}",
1388 connectionName);
1389 return;
1390 }
1391 tinyxml2::XMLElement* interfaceNode =
1392 pRoot->FirstChildElement("interface");
1393 while (interfaceNode != nullptr)
1394 {
1395 const char* thisInterfaceName =
1396 interfaceNode->Attribute("name");
1397 if (thisInterfaceName != nullptr)
1398 {
1399 if (!transaction->interfaceName.empty() &&
1400 (transaction->interfaceName != thisInterfaceName))
1401 {
1402 interfaceNode =
1403 interfaceNode->NextSiblingElement("interface");
1404 continue;
1405 }
1406
1407 tinyxml2::XMLElement* methodNode =
1408 interfaceNode->FirstChildElement("method");
1409 while (methodNode != nullptr)
1410 {
1411 const char* thisMethodName =
1412 methodNode->Attribute("name");
1413 BMCWEB_LOG_DEBUG("Found method: {}", thisMethodName);
1414 if (thisMethodName != nullptr &&
1415 thisMethodName == transaction->methodName)
1416 {
1417 BMCWEB_LOG_DEBUG(
1418 "Found method named {} on interface {}",
1419 thisMethodName, thisInterfaceName);
1420 sdbusplus::message_t m =
1421 crow::connections::systemBus->new_method_call(
1422 connectionName.c_str(),
1423 transaction->path.c_str(),
1424 thisInterfaceName,
1425 transaction->methodName.c_str());
1426
1427 tinyxml2::XMLElement* argumentNode =
1428 methodNode->FirstChildElement("arg");
1429
1430 std::string returnType;
1431
1432 // Find the output type
1433 while (argumentNode != nullptr)
1434 {
1435 const char* argDirection =
1436 argumentNode->Attribute("direction");
1437 const char* argType =
1438 argumentNode->Attribute("type");
1439 if (argDirection != nullptr &&
1440 argType != nullptr &&
1441 std::string(argDirection) == "out")
1442 {
1443 returnType = argType;
1444 break;
1445 }
1446 argumentNode =
1447 argumentNode->NextSiblingElement("arg");
1448 }
1449
1450 auto argIt = transaction->arguments.begin();
1451
1452 argumentNode = methodNode->FirstChildElement("arg");
1453
1454 while (argumentNode != nullptr)
1455 {
1456 const char* argDirection =
1457 argumentNode->Attribute("direction");
1458 const char* argType =
1459 argumentNode->Attribute("type");
1460 if (argDirection != nullptr &&
1461 argType != nullptr &&
1462 std::string(argDirection) == "in")
1463 {
1464 if (argIt == transaction->arguments.end())
1465 {
1466 transaction->setErrorStatus(
1467 "Invalid method args");
1468 return;
1469 }
1470 if (convertJsonToDbus(m.get(),
1471 std::string(argType),
1472 *argIt) < 0)
1473 {
1474 transaction->setErrorStatus(
1475 "Invalid method arg type");
1476 return;
1477 }
1478
1479 argIt++;
1480 }
1481 argumentNode =
1482 argumentNode->NextSiblingElement("arg");
1483 }
1484
1485 crow::connections::systemBus->async_send(
1486 m, [transaction, returnType](
1487 const boost::system::error_code& ec2,
1488 sdbusplus::message_t& m2) {
1489 if (ec2)
1490 {
1491 transaction->methodFailed = true;
1492 const sd_bus_error* e = m2.get_error();
1493
1494 if (e != nullptr)
1495 {
1496 setErrorResponse(
1497 transaction->asyncResp->res,
1498 boost::beast::http::status::
1499 bad_request,
1500 e->name, e->message);
1501 }
1502 else
1503 {
1504 setErrorResponse(
1505 transaction->asyncResp->res,
1506 boost::beast::http::status::
1507 bad_request,
1508 "Method call failed",
1509 methodFailedMsg);
1510 }
1511 return;
1512 }
1513 transaction->methodPassed = true;
1514
1515 handleMethodResponse(transaction, m2,
1516 returnType);
1517 });
1518 break;
1519 }
1520 methodNode = methodNode->NextSiblingElement("method");
1521 }
1522 }
1523 interfaceNode = interfaceNode->NextSiblingElement("interface");
1524 }
1525 },
Ed Tanous1abe55e2018-09-05 08:30:59 -07001526 connectionName, transaction->path,
1527 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001528}
1529
zhanghch058d1b46d2021-04-01 11:18:24 +08001530inline void handleAction(const crow::Request& req,
1531 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001532 const std::string& objectPath,
1533 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001534{
Ed Tanous62598e32023-07-17 17:06:25 -07001535 BMCWEB_LOG_DEBUG("handleAction on path: {} and method {}", objectPath,
1536 methodName);
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001537 nlohmann::json requestDbusData;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001538
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001539 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
1540 if (ret == JsonParseResult::BadContentType)
1541 {
1542 setErrorResponse(asyncResp->res,
1543 boost::beast::http::status::unsupported_media_type,
1544 invalidContentType, unsupportedMediaMsg);
1545 return;
1546 }
1547 if (ret != JsonParseResult::Success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001548 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001549 setErrorResponse(asyncResp->res,
1550 boost::beast::http::status::bad_request, noJsonDesc,
1551 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001552 return;
1553 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001554 nlohmann::json::iterator data = requestDbusData.find("data");
1555 if (data == requestDbusData.end())
1556 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001557 setErrorResponse(asyncResp->res,
1558 boost::beast::http::status::bad_request, noJsonDesc,
1559 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001560 return;
1561 }
1562
1563 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001564 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001565 setErrorResponse(asyncResp->res,
1566 boost::beast::http::status::bad_request, noJsonDesc,
1567 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001568 return;
1569 }
Lei YU28dd5ca2023-03-17 13:17:05 +08001570 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001571
1572 transaction->path = objectPath;
1573 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001574 transaction->arguments = std::move(*data);
George Liu2b731192023-01-11 16:27:13 +08001575 dbus::utility::getDbusObject(
1576 objectPath, {},
Ed Tanous1abe55e2018-09-05 08:30:59 -07001577 [transaction](
George Liu2b731192023-01-11 16:27:13 +08001578 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001579 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1580 interfaceNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001581 if (ec || interfaceNames.empty())
1582 {
1583 BMCWEB_LOG_ERROR("Can't find object");
1584 setErrorResponse(transaction->asyncResp->res,
1585 boost::beast::http::status::not_found,
1586 notFoundDesc, notFoundMsg);
1587 return;
1588 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001589
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001590 BMCWEB_LOG_DEBUG("GetObject returned {} object(s)",
1591 interfaceNames.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001592
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001593 for (const std::pair<std::string, std::vector<std::string>>&
1594 object : interfaceNames)
1595 {
1596 findActionOnInterface(transaction, object.first);
1597 }
1598 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001599}
1600
zhanghch058d1b46d2021-04-01 11:18:24 +08001601inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1602 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001603{
Ed Tanous62598e32023-07-17 17:06:25 -07001604 BMCWEB_LOG_DEBUG("handleDelete on path: {}", objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06001605
George Liu2b731192023-01-11 16:27:13 +08001606 dbus::utility::getDbusObject(
1607 objectPath, {},
zhanghch058d1b46d2021-04-01 11:18:24 +08001608 [asyncResp, objectPath](
George Liu2b731192023-01-11 16:27:13 +08001609 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001610 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1611 interfaceNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001612 if (ec || interfaceNames.empty())
1613 {
1614 BMCWEB_LOG_ERROR("Can't find object");
1615 setErrorResponse(asyncResp->res,
1616 boost::beast::http::status::method_not_allowed,
1617 methodNotAllowedDesc, methodNotAllowedMsg);
1618 return;
1619 }
Matt Spinlerde818812018-12-11 16:39:20 -06001620
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001621 auto transaction =
1622 std::make_shared<InProgressActionData>(asyncResp);
1623 transaction->path = objectPath;
1624 transaction->methodName = "Delete";
1625 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
Matt Spinlerde818812018-12-11 16:39:20 -06001626
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001627 for (const std::pair<std::string, std::vector<std::string>>&
1628 object : interfaceNames)
1629 {
1630 findActionOnInterface(transaction, object.first);
1631 }
1632 });
Matt Spinlerde818812018-12-11 16:39:20 -06001633}
1634
zhanghch058d1b46d2021-04-01 11:18:24 +08001635inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1636 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001637{
George Liu7a1dbc42022-12-07 16:03:22 +08001638 dbus::utility::getSubTreePaths(
1639 objectPath, depth, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001640 [asyncResp](
George Liu7a1dbc42022-12-07 16:03:22 +08001641 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001642 const dbus::utility::MapperGetSubTreePathsResponse& objectPaths) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001643 if (ec)
1644 {
1645 setErrorResponse(asyncResp->res,
1646 boost::beast::http::status::not_found,
1647 notFoundDesc, notFoundMsg);
1648 }
1649 else
1650 {
1651 asyncResp->res.jsonValue["status"] = "ok";
1652 asyncResp->res.jsonValue["message"] = "200 OK";
1653 asyncResp->res.jsonValue["data"] = objectPaths;
1654 }
1655 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001656}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001657
zhanghch058d1b46d2021-04-01 11:18:24 +08001658inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1659 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001660{
Ed Tanous62598e32023-07-17 17:06:25 -07001661 BMCWEB_LOG_DEBUG("Doing enumerate on {}", objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07001662
Ed Tanous14766872022-03-15 10:44:42 -07001663 asyncResp->res.jsonValue["message"] = "200 OK";
1664 asyncResp->res.jsonValue["status"] = "ok";
1665 asyncResp->res.jsonValue["data"] = nlohmann::json::object();
Ed Tanous049a0512018-11-01 13:58:42 -07001666
George Liue99073f2022-12-09 11:06:16 +08001667 dbus::utility::getSubTree(
1668 objectPath, 0, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001669 [objectPath, asyncResp](
George Liue99073f2022-12-09 11:06:16 +08001670 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001671 const dbus::utility::MapperGetSubTreeResponse& objectNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001672 auto transaction = std::make_shared<InProgressEnumerateData>(
1673 objectPath, asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001674
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001675 transaction->subtree =
1676 std::make_shared<dbus::utility::MapperGetSubTreeResponse>(
1677 objectNames);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001678
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001679 if (ec)
1680 {
1681 BMCWEB_LOG_ERROR("GetSubTree failed on {}",
1682 transaction->objectPath);
1683 setErrorResponse(transaction->asyncResp->res,
1684 boost::beast::http::status::not_found,
1685 notFoundDesc, notFoundMsg);
1686 return;
1687 }
Ed Tanous64530012018-02-06 17:08:16 -08001688
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001689 // Add the data for the path passed in to the results
1690 // as if GetSubTree returned it, and continue on enumerating
1691 getObjectAndEnumerate(transaction);
1692 });
Ed Tanous64530012018-02-06 17:08:16 -08001693}
Ed Tanous911ac312017-08-15 09:37:42 -07001694
zhanghch058d1b46d2021-04-01 11:18:24 +08001695inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1696 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001697{
Ed Tanous62598e32023-07-17 17:06:25 -07001698 BMCWEB_LOG_DEBUG("handleGet: {} prop:{}", objectPath, destProperty);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001699 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001700 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001701
Ed Tanous1abe55e2018-09-05 08:30:59 -07001702 std::shared_ptr<std::string> path =
1703 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001704
George Liu2b731192023-01-11 16:27:13 +08001705 dbus::utility::getDbusObject(
1706 *path, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001707 [asyncResp, path,
George Liu2b731192023-01-11 16:27:13 +08001708 propertyName](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001709 const dbus::utility::MapperGetObject& objectNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001710 if (ec || objectNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001711 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001712 setErrorResponse(asyncResp->res,
1713 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001714 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001715 return;
1716 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001717 std::shared_ptr<nlohmann::json> response =
1718 std::make_shared<nlohmann::json>(nlohmann::json::object());
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001719 for (const std::pair<std::string, std::vector<std::string>>&
1720 connection : objectNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001721 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001722 const std::vector<std::string>& interfaceNames =
1723 connection.second;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001724
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001725 if (interfaceNames.empty())
1726 {
Lei YU65622a52025-01-20 09:45:50 +00001727 // mapper allows empty interfaces in case an
1728 // object does not implement any interface.
1729 continue;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001730 }
1731
1732 for (const std::string& interface : interfaceNames)
1733 {
1734 sdbusplus::message_t m =
1735 crow::connections::systemBus->new_method_call(
1736 connection.first.c_str(), path->c_str(),
1737 "org.freedesktop.DBus.Properties", "GetAll");
1738 m.append(interface);
1739 crow::connections::systemBus->async_send(
1740 m, [asyncResp, response,
1741 propertyName](const boost::system::error_code& ec2,
1742 sdbusplus::message_t& msg) {
1743 if (ec2)
1744 {
1745 BMCWEB_LOG_ERROR("Bad dbus request error: {}",
1746 ec2);
1747 }
1748 else
1749 {
1750 nlohmann::json properties;
1751 int r =
1752 convertDBusToJSON("a{sv}", msg, properties);
1753 if (r < 0)
Patrick Williams5a39f772023-10-20 11:20:21 -05001754 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001755 BMCWEB_LOG_ERROR(
1756 "convertDBusToJSON failed");
Patrick Williams5a39f772023-10-20 11:20:21 -05001757 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001758 else
Patrick Williams5a39f772023-10-20 11:20:21 -05001759 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001760 nlohmann::json::object_t* obj =
1761 properties.get_ptr<
1762 nlohmann::json::object_t*>();
1763 if (obj == nullptr)
1764 {
1765 return;
1766 }
1767 for (auto& prop : *obj)
1768 {
1769 // if property name is empty, or
1770 // matches our search query, add it
1771 // to the response json
1772
1773 if (propertyName->empty())
1774 {
1775 (*response)[prop.first] =
1776 std::move(prop.second);
1777 }
1778 else if (prop.first == *propertyName)
1779 {
1780 *response = std::move(prop.second);
1781 }
1782 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001783 }
1784 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001785 if (response.use_count() == 1)
1786 {
1787 if (!propertyName->empty() && response->empty())
1788 {
1789 setErrorResponse(
1790 asyncResp->res,
1791 boost::beast::http::status::not_found,
1792 propNotFoundDesc, notFoundMsg);
1793 }
1794 else
1795 {
1796 asyncResp->res.jsonValue["status"] = "ok";
1797 asyncResp->res.jsonValue["message"] =
1798 "200 OK";
1799 asyncResp->res.jsonValue["data"] =
1800 *response;
1801 }
1802 }
1803 });
1804 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001805 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001806 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001807}
1808
Ed Tanous1abe55e2018-09-05 08:30:59 -07001809struct AsyncPutRequest
1810{
Ed Tanous4e23a442022-06-06 09:57:26 -07001811 explicit AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
zhanghch058d1b46d2021-04-01 11:18:24 +08001812 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001813 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001814 ~AsyncPutRequest()
1815 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001816 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001817 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001818 setErrorResponse(asyncResp->res,
1819 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001820 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001821 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001822 }
1823
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001824 AsyncPutRequest(const AsyncPutRequest&) = delete;
1825 AsyncPutRequest(AsyncPutRequest&&) = delete;
1826 AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1827 AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1828
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001829 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001830 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001831 setErrorResponse(asyncResp->res,
1832 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001833 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001834 }
1835
zhanghch058d1b46d2021-04-01 11:18:24 +08001836 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001837 std::string objectPath;
1838 std::string propertyName;
1839 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001840};
1841
zhanghch058d1b46d2021-04-01 11:18:24 +08001842inline void handlePut(const crow::Request& req,
1843 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001844 const std::string& objectPath,
1845 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001846{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001847 if (destProperty.empty())
1848 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001849 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001850 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001851 return;
1852 }
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001853 nlohmann::json requestDbusData;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001854
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001855 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
1856 if (ret == JsonParseResult::BadContentType)
1857 {
1858 setErrorResponse(asyncResp->res,
1859 boost::beast::http::status::unsupported_media_type,
1860 invalidContentType, unsupportedMediaMsg);
1861 return;
1862 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001863
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001864 if (ret != JsonParseResult::Success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001865 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001866 setErrorResponse(asyncResp->res,
1867 boost::beast::http::status::bad_request, noJsonDesc,
1868 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001869 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001870 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001871
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001872 auto propertyIt = requestDbusData.find("data");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001873 if (propertyIt == requestDbusData.end())
1874 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001875 setErrorResponse(asyncResp->res,
1876 boost::beast::http::status::bad_request, noJsonDesc,
1877 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001878 return;
1879 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001880 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001881 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001882 transaction->objectPath = objectPath;
1883 transaction->propertyName = destProperty;
1884 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001885
George Liu2b731192023-01-11 16:27:13 +08001886 dbus::utility::getDbusObject(
1887 transaction->objectPath, {},
1888 [transaction](const boost::system::error_code& ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001889 const dbus::utility::MapperGetObject& objectNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001890 if (!ec2 && objectNames.empty())
1891 {
1892 setErrorResponse(transaction->asyncResp->res,
1893 boost::beast::http::status::not_found,
1894 propNotFoundDesc, notFoundMsg);
1895 return;
1896 }
Ed Tanous911ac312017-08-15 09:37:42 -07001897
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001898 for (const std::pair<std::string, std::vector<std::string>>&
1899 connection : objectNames)
1900 {
1901 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001902
Ed Tanous177612a2025-02-14 15:16:09 -08001903 dbus::utility::async_method_call(
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001904 [connectionName{std::string(connectionName)},
1905 transaction](const boost::system::error_code& ec3,
1906 const std::string& introspectXml) {
1907 if (ec3)
Ed Tanousb0b61522024-08-06 10:20:49 -07001908 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001909 BMCWEB_LOG_ERROR(
1910 "Introspect call failed with error: {} on process: {}",
1911 ec3.message(), connectionName);
1912 transaction->setErrorStatus("Unexpected Error");
1913 return;
Ed Tanousb0b61522024-08-06 10:20:49 -07001914 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001915 tinyxml2::XMLDocument doc;
1916
1917 doc.Parse(introspectXml.c_str());
1918 tinyxml2::XMLNode* pRoot =
1919 doc.FirstChildElement("node");
1920 if (pRoot == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001921 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001922 BMCWEB_LOG_ERROR("XML document failed to parse: {}",
1923 introspectXml);
1924 transaction->setErrorStatus("Unexpected Error");
1925 return;
1926 }
1927 tinyxml2::XMLElement* ifaceNode =
1928 pRoot->FirstChildElement("interface");
1929 while (ifaceNode != nullptr)
1930 {
1931 const char* interfaceName =
1932 ifaceNode->Attribute("name");
1933 BMCWEB_LOG_DEBUG("found interface {}",
1934 interfaceName);
1935 tinyxml2::XMLElement* propNode =
1936 ifaceNode->FirstChildElement("property");
1937 while (propNode != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001938 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001939 const char* propertyName =
1940 propNode->Attribute("name");
1941 if (propertyName == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001942 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001943 BMCWEB_LOG_DEBUG(
1944 "Couldn't find name property");
1945 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001946 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001947 BMCWEB_LOG_DEBUG("Found property {}",
1948 propertyName);
1949 if (propertyName == transaction->propertyName)
Ed Tanous002d39b2022-05-31 08:59:27 -07001950 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001951 const char* argType =
1952 propNode->Attribute("type");
1953 if (argType != nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07001954 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001955 sdbusplus::message_t m =
1956 crow::connections::systemBus
1957 ->new_method_call(
1958 connectionName.c_str(),
1959 transaction->objectPath
1960 .c_str(),
1961 "org.freedesktop.DBus."
1962 "Properties",
1963 "Set");
1964 m.append(interfaceName,
1965 transaction->propertyName);
1966 int r = sd_bus_message_open_container(
1967 m.get(), SD_BUS_TYPE_VARIANT,
1968 argType);
1969 if (r < 0)
1970 {
1971 transaction->setErrorStatus(
1972 "Unexpected Error");
1973 return;
1974 }
1975 r = convertJsonToDbus(
1976 m.get(), argType,
1977 transaction->propertyValue);
1978 if (r < 0)
1979 {
1980 if (r == -ERANGE)
1981 {
1982 transaction->setErrorStatus(
1983 "Provided property value "
1984 "is out of range for the "
1985 "property type");
1986 }
1987 else
1988 {
1989 transaction->setErrorStatus(
1990 "Invalid arg type");
1991 }
1992 return;
1993 }
1994 r = sd_bus_message_close_container(
1995 m.get());
1996 if (r < 0)
1997 {
1998 transaction->setErrorStatus(
1999 "Unexpected Error");
2000 return;
2001 }
2002 crow::connections::systemBus
2003 ->async_send(
2004 m,
2005 [transaction](
2006 const boost::system::
2007 error_code& ec,
2008 sdbusplus::message_t& m2) {
2009 BMCWEB_LOG_DEBUG("sent");
2010 if (ec)
2011 {
2012 const sd_bus_error* e =
2013 m2.get_error();
2014 setErrorResponse(
2015 transaction
2016 ->asyncResp
2017 ->res,
2018 boost::beast::http::
2019 status::
2020 forbidden,
2021 (e) != nullptr
2022 ? e->name
2023 : ec.category()
2024 .name(),
2025 (e) != nullptr
2026 ? e->message
2027 : ec.message());
2028 }
2029 else
2030 {
2031 transaction->asyncResp
2032 ->res.jsonValue
2033 ["status"] =
2034 "ok";
2035 transaction->asyncResp
2036 ->res.jsonValue
2037 ["message"] =
2038 "200 OK";
2039 transaction->asyncResp
2040 ->res
2041 .jsonValue["data"] =
2042 nullptr;
2043 }
2044 });
Ed Tanous002d39b2022-05-31 08:59:27 -07002045 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002046 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002047 propNode =
2048 propNode->NextSiblingElement("property");
Ed Tanous1abe55e2018-09-05 08:30:59 -07002049 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002050 ifaceNode =
2051 ifaceNode->NextSiblingElement("interface");
Ed Tanous1abe55e2018-09-05 08:30:59 -07002052 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002053 },
2054 connectionName, transaction->objectPath,
2055 "org.freedesktop.DBus.Introspectable", "Introspect");
2056 }
2057 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07002058}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002059
zhanghch058d1b46d2021-04-01 11:18:24 +08002060inline void handleDBusUrl(const crow::Request& req,
2061 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002062 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002063{
Ed Tanous049a0512018-11-01 13:58:42 -07002064 // If accessing a single attribute, fill in and update objectPath,
2065 // otherwise leave destProperty blank
Ed Tanouse05aec52022-01-25 10:28:56 -08002066 std::string destProperty;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002067 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002068 size_t attrPosition = objectPath.find(attrSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002069 if (attrPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002070 {
2071 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2072 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002073 objectPath.resize(attrPosition);
Ed Tanous049a0512018-11-01 13:58:42 -07002074 }
2075
Ed Tanousb41187f2019-10-24 16:30:02 -07002076 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002077 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002078 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002079 size_t actionPosition = objectPath.find(actionSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002080 if (actionPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002081 {
2082 std::string postProperty =
2083 objectPath.substr((actionPosition + strlen(actionSeperator)),
2084 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002085 objectPath.resize(actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002086 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002087 return;
2088 }
2089 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002090 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002091 {
Ed Tanous11ba3972022-07-11 09:50:41 -07002092 if (objectPath.ends_with("/enumerate"))
Ed Tanous049a0512018-11-01 13:58:42 -07002093 {
2094 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2095 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002096 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002097 }
Ed Tanous11ba3972022-07-11 09:50:41 -07002098 else if (objectPath.ends_with("/list"))
Ed Tanous049a0512018-11-01 13:58:42 -07002099 {
2100 objectPath.erase(objectPath.end() - sizeof("list"),
2101 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002102 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002103 }
2104 else
2105 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002106 // Trim any trailing "/" at the end
Ed Tanous11ba3972022-07-11 09:50:41 -07002107 if (objectPath.ends_with("/"))
Ed Tanousf839dfe2018-11-12 11:11:15 -08002108 {
2109 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002110 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002111 }
2112 else
2113 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002114 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002115 }
Ed Tanous049a0512018-11-01 13:58:42 -07002116 }
2117 return;
2118 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002119 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002120 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002121 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002122 return;
2123 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002124 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002125 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002126 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002127 return;
2128 }
Ed Tanous049a0512018-11-01 13:58:42 -07002129
zhanghch058d1b46d2021-04-01 11:18:24 +08002130 setErrorResponse(asyncResp->res,
2131 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002132 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002133}
2134
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002135inline void handleBusSystemPost(
2136 const crow::Request& req,
2137 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2138 const std::string& processName, const std::string& requestedPath)
Ed Tanous1656b292022-05-04 11:33:42 -07002139{
2140 std::vector<std::string> strs;
Ed Tanous50ebd4a2023-01-19 19:03:17 -08002141
2142 bmcweb::split(strs, requestedPath, '/');
Ed Tanous1656b292022-05-04 11:33:42 -07002143 std::string objectPath;
2144 std::string interfaceName;
2145 std::string methodName;
2146 auto it = strs.begin();
2147 if (it == strs.end())
2148 {
2149 objectPath = "/";
2150 }
2151 while (it != strs.end())
2152 {
2153 // Check if segment contains ".". If it does, it must be an
2154 // interface
2155 if (it->find(".") != std::string::npos)
2156 {
2157 break;
2158 // This check is necessary as the trailing slash gets
2159 // parsed as part of our <path> specifier above, which
2160 // causes the normal trailing backslash redirector to
2161 // fail.
2162 }
2163 if (!it->empty())
2164 {
2165 objectPath += "/" + *it;
2166 }
2167 it++;
2168 }
2169 if (it != strs.end())
2170 {
2171 interfaceName = *it;
2172 it++;
2173
2174 // after interface, we might have a method name
2175 if (it != strs.end())
2176 {
2177 methodName = *it;
2178 it++;
2179 }
2180 }
2181 if (it != strs.end())
2182 {
2183 // if there is more levels past the method name, something
2184 // went wrong, return not found
2185 asyncResp->res.result(boost::beast::http::status::not_found);
2186 return;
2187 }
2188 if (interfaceName.empty())
2189 {
Ed Tanous177612a2025-02-14 15:16:09 -08002190 dbus::utility::async_method_call(
Ed Tanous1656b292022-05-04 11:33:42 -07002191 [asyncResp, processName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002192 objectPath](const boost::system::error_code& ec,
Ed Tanous1656b292022-05-04 11:33:42 -07002193 const std::string& introspectXml) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002194 if (ec)
Ed Tanous1656b292022-05-04 11:33:42 -07002195 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002196 BMCWEB_LOG_ERROR(
2197 "Introspect call failed with error: {} on process: {} path: {}",
2198 ec.message(), processName, objectPath);
2199 return;
2200 }
2201 tinyxml2::XMLDocument doc;
2202
2203 doc.Parse(introspectXml.c_str());
2204 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2205 if (pRoot == nullptr)
2206 {
2207 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
2208 processName, objectPath);
2209 asyncResp->res.jsonValue["status"] = "XML parse error";
2210 asyncResp->res.result(
2211 boost::beast::http::status::internal_server_error);
2212 return;
Ed Tanous1656b292022-05-04 11:33:42 -07002213 }
2214
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002215 BMCWEB_LOG_DEBUG("{}", introspectXml);
2216 asyncResp->res.jsonValue["status"] = "ok";
2217 asyncResp->res.jsonValue["bus_name"] = processName;
2218 asyncResp->res.jsonValue["object_path"] = objectPath;
2219
2220 nlohmann::json& interfacesArray =
2221 asyncResp->res.jsonValue["interfaces"];
2222 interfacesArray = nlohmann::json::array();
2223 tinyxml2::XMLElement* interface =
2224 pRoot->FirstChildElement("interface");
2225
2226 while (interface != nullptr)
2227 {
2228 const char* ifaceName = interface->Attribute("name");
2229 if (ifaceName != nullptr)
2230 {
2231 nlohmann::json::object_t interfaceObj;
2232 interfaceObj["name"] = ifaceName;
2233 interfacesArray.emplace_back(std::move(interfaceObj));
2234 }
2235
2236 interface = interface->NextSiblingElement("interface");
2237 }
2238 },
Ed Tanous1656b292022-05-04 11:33:42 -07002239 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2240 "Introspect");
2241 }
2242 else if (methodName.empty())
2243 {
Ed Tanous177612a2025-02-14 15:16:09 -08002244 dbus::utility::async_method_call(
Ed Tanous1656b292022-05-04 11:33:42 -07002245 [asyncResp, processName, objectPath,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002246 interfaceName](const boost::system::error_code& ec,
Ed Tanous1656b292022-05-04 11:33:42 -07002247 const std::string& introspectXml) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002248 if (ec)
Ed Tanous1656b292022-05-04 11:33:42 -07002249 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002250 BMCWEB_LOG_ERROR(
2251 "Introspect call failed with error: {} on process: {} path: {}",
2252 ec.message(), processName, objectPath);
2253 return;
2254 }
2255 tinyxml2::XMLDocument doc;
2256
2257 doc.Parse(introspectXml.data(), introspectXml.size());
2258 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2259 if (pRoot == nullptr)
2260 {
2261 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
2262 processName, objectPath);
2263 asyncResp->res.result(
2264 boost::beast::http::status::internal_server_error);
2265 return;
Ed Tanous1656b292022-05-04 11:33:42 -07002266 }
Ed Tanous14766872022-03-15 10:44:42 -07002267
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002268 asyncResp->res.jsonValue["status"] = "ok";
2269 asyncResp->res.jsonValue["bus_name"] = processName;
2270 asyncResp->res.jsonValue["interface"] = interfaceName;
2271 asyncResp->res.jsonValue["object_path"] = objectPath;
Ed Tanous1656b292022-05-04 11:33:42 -07002272
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002273 nlohmann::json& methodsArray =
2274 asyncResp->res.jsonValue["methods"];
2275 methodsArray = nlohmann::json::array();
2276
2277 nlohmann::json& signalsArray =
2278 asyncResp->res.jsonValue["signals"];
2279 signalsArray = nlohmann::json::array();
2280
2281 nlohmann::json& propertiesObj =
2282 asyncResp->res.jsonValue["properties"];
2283 propertiesObj = nlohmann::json::object();
2284
2285 // if we know we're the only call, build the
2286 // json directly
2287 tinyxml2::XMLElement* interface =
2288 pRoot->FirstChildElement("interface");
2289 while (interface != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002290 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002291 const char* ifaceName = interface->Attribute("name");
2292
2293 if (ifaceName != nullptr && ifaceName == interfaceName)
Ed Tanous1656b292022-05-04 11:33:42 -07002294 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002295 break;
Ed Tanous002d39b2022-05-31 08:59:27 -07002296 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002297
2298 interface = interface->NextSiblingElement("interface");
2299 }
2300 if (interface == nullptr)
2301 {
2302 // if we got to the end of the list and
2303 // never found a match, throw 404
2304 asyncResp->res.result(
2305 boost::beast::http::status::not_found);
2306 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07002307 }
2308
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002309 tinyxml2::XMLElement* methods =
2310 interface->FirstChildElement("method");
2311 while (methods != nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07002312 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002313 nlohmann::json argsArray = nlohmann::json::array();
2314 tinyxml2::XMLElement* arg =
2315 methods->FirstChildElement("arg");
2316 while (arg != nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07002317 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002318 nlohmann::json thisArg;
2319 for (const char* fieldName : std::array<const char*, 3>{
2320 "name", "direction", "type"})
2321 {
2322 const char* fieldValue = arg->Attribute(fieldName);
2323 if (fieldValue != nullptr)
2324 {
2325 thisArg[fieldName] = fieldValue;
2326 }
2327 }
2328 argsArray.emplace_back(std::move(thisArg));
2329 arg = arg->NextSiblingElement("arg");
Ed Tanous002d39b2022-05-31 08:59:27 -07002330 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002331
2332 const char* name = methods->Attribute("name");
2333 if (name != nullptr)
2334 {
2335 std::string uri;
2336 uri.reserve(14 + processName.size() +
2337 objectPath.size() + interfaceName.size() +
2338 strlen(name));
2339 uri += "/bus/system/";
2340 uri += processName;
2341 uri += objectPath;
2342 uri += "/";
2343 uri += interfaceName;
2344 uri += "/";
2345 uri += name;
2346
2347 nlohmann::json::object_t object;
2348 object["name"] = name;
2349 object["uri"] = std::move(uri);
2350 object["args"] = argsArray;
2351
2352 methodsArray.emplace_back(std::move(object));
2353 }
2354 methods = methods->NextSiblingElement("method");
Ed Tanous002d39b2022-05-31 08:59:27 -07002355 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002356 tinyxml2::XMLElement* signals =
2357 interface->FirstChildElement("signal");
2358 while (signals != nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07002359 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002360 nlohmann::json argsArray = nlohmann::json::array();
2361
2362 tinyxml2::XMLElement* arg =
2363 signals->FirstChildElement("arg");
2364 while (arg != nullptr)
2365 {
2366 const char* name = arg->Attribute("name");
2367 const char* type = arg->Attribute("type");
2368 if (name != nullptr && type != nullptr)
2369 {
2370 nlohmann::json::object_t params;
2371 params["name"] = name;
2372 params["type"] = type;
2373 argsArray.push_back(std::move(params));
2374 }
2375 arg = arg->NextSiblingElement("arg");
2376 }
2377 const char* name = signals->Attribute("name");
2378 if (name != nullptr)
2379 {
2380 nlohmann::json::object_t object;
2381 object["name"] = name;
2382 object["args"] = argsArray;
2383 signalsArray.emplace_back(std::move(object));
2384 }
2385
2386 signals = signals->NextSiblingElement("signal");
Ed Tanous002d39b2022-05-31 08:59:27 -07002387 }
2388
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002389 tinyxml2::XMLElement* property =
2390 interface->FirstChildElement("property");
2391 while (property != nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07002392 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002393 const char* name = property->Attribute("name");
2394 const char* type = property->Attribute("type");
2395 if (type != nullptr && name != nullptr)
2396 {
2397 sdbusplus::message_t m =
2398 crow::connections::systemBus->new_method_call(
2399 processName.c_str(), objectPath.c_str(),
2400 "org.freedesktop."
2401 "DBus."
2402 "Properties",
2403 "Get");
2404 m.append(interfaceName, name);
2405 nlohmann::json& propertyItem = propertiesObj[name];
2406 crow::connections::systemBus->async_send(
2407 m, [&propertyItem,
2408 asyncResp](const boost::system::error_code& ec2,
2409 sdbusplus::message_t& msg) {
2410 if (ec2)
2411 {
2412 return;
2413 }
Ed Tanous1656b292022-05-04 11:33:42 -07002414
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002415 int r =
2416 convertDBusToJSON("v", msg, propertyItem);
2417 if (r < 0)
2418 {
2419 BMCWEB_LOG_ERROR(
2420 "Couldn't convert vector to json");
2421 }
2422 });
2423 }
2424 property = property->NextSiblingElement("property");
Ed Tanous1656b292022-05-04 11:33:42 -07002425 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002426 },
Ed Tanous1656b292022-05-04 11:33:42 -07002427 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2428 "Introspect");
2429 }
2430 else
2431 {
2432 if (req.method() != boost::beast::http::verb::post)
2433 {
2434 asyncResp->res.result(boost::beast::http::status::not_found);
2435 return;
2436 }
2437
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002438 nlohmann::json requestDbusData;
2439 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
2440 if (ret == JsonParseResult::BadContentType)
Ed Tanous1656b292022-05-04 11:33:42 -07002441 {
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002442 setErrorResponse(asyncResp->res,
2443 boost::beast::http::status::unsupported_media_type,
2444 invalidContentType, unsupportedMediaMsg);
Ed Tanous1656b292022-05-04 11:33:42 -07002445 return;
2446 }
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002447 if (ret != JsonParseResult::Success)
2448 {
2449 setErrorResponse(asyncResp->res,
2450 boost::beast::http::status::bad_request,
2451 noJsonDesc, badReqMsg);
2452 return;
2453 }
2454
Ed Tanous1656b292022-05-04 11:33:42 -07002455 if (!requestDbusData.is_array())
2456 {
2457 asyncResp->res.result(boost::beast::http::status::bad_request);
2458 return;
2459 }
Lei YU28dd5ca2023-03-17 13:17:05 +08002460 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous1656b292022-05-04 11:33:42 -07002461
2462 transaction->path = objectPath;
2463 transaction->methodName = methodName;
2464 transaction->arguments = std::move(requestDbusData);
2465
2466 findActionOnInterface(transaction, processName);
2467 }
2468}
2469
Ed Tanous23a21a12020-07-25 04:45:05 +00002470inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002471{
2472 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002473 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002474 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002475 [](const crow::Request&,
2476 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002477 nlohmann::json::array_t buses;
2478 nlohmann::json& bus = buses.emplace_back();
2479 bus["name"] = "system";
2480 asyncResp->res.jsonValue["busses"] = std::move(buses);
2481 asyncResp->res.jsonValue["status"] = "ok";
2482 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002483
2484 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002485 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002486 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002487 [](const crow::Request&,
2488 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002489 auto myCallback = [asyncResp](
2490 const boost::system::error_code& ec,
zhanghch058d1b46d2021-04-01 11:18:24 +08002491 std::vector<std::string>& names) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002492 if (ec)
2493 {
2494 BMCWEB_LOG_ERROR("Dbus call failed with code {}", ec);
2495 asyncResp->res.result(
2496 boost::beast::http::status::internal_server_error);
2497 }
2498 else
2499 {
2500 std::ranges::sort(names);
2501 asyncResp->res.jsonValue["status"] = "ok";
2502 auto& objectsSub = asyncResp->res.jsonValue["objects"];
2503 for (const auto& name : names)
2504 {
2505 nlohmann::json::object_t object;
2506 object["name"] = name;
2507 objectsSub.emplace_back(std::move(object));
2508 }
2509 }
2510 };
Ed Tanous177612a2025-02-14 15:16:09 -08002511 dbus::utility::async_method_call(
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002512 std::move(myCallback), "org.freedesktop.DBus", "/",
2513 "org.freedesktop.DBus", "ListNames");
2514 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002515
2516 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002517 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002518 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002519 [](const crow::Request&,
2520 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002521 handleList(asyncResp, "/");
2522 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002523
2524 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002525 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002526 .methods(boost::beast::http::verb::get)(
2527 [](const crow::Request& req,
2528 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002529 const std::string& path) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002530 std::string objectPath = "/xyz/" + path;
2531 handleDBusUrl(req, asyncResp, objectPath);
2532 });
zhanghch058d1b46d2021-04-01 11:18:24 +08002533
2534 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002535 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002536 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2537 boost::beast::http::verb::delete_)(
2538 [](const crow::Request& req,
2539 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2540 const std::string& path) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002541 std::string objectPath = "/xyz/" + path;
2542 handleDBusUrl(req, asyncResp, objectPath);
2543 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002544
Ed Tanous049a0512018-11-01 13:58:42 -07002545 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002546 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002547 .methods(boost::beast::http::verb::get)(
2548 [](const crow::Request& req,
2549 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2550 const std::string& path) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002551 std::string objectPath = "/org/" + path;
2552 handleDBusUrl(req, asyncResp, objectPath);
2553 });
Tanousf00032d2018-11-05 01:18:10 -03002554
2555 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002556 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002557 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2558 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002559 [](const crow::Request& req,
2560 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002561 const std::string& path) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002562 std::string objectPath = "/org/" + path;
2563 handleDBusUrl(req, asyncResp, objectPath);
2564 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002565
Ed Tanous1abe55e2018-09-05 08:30:59 -07002566 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002567 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002568 .methods(boost::beast::http::verb::get)(
2569 [](const crow::Request&,
2570 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2571 const std::string& dumpId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002572 if (!validateFilename(dumpId))
2573 {
2574 asyncResp->res.result(
2575 boost::beast::http::status::bad_request);
2576 return;
2577 }
2578 std::filesystem::path loc(
2579 "/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002580
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002581 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002582
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002583 if (!std::filesystem::exists(loc) ||
2584 !std::filesystem::is_directory(loc))
2585 {
2586 BMCWEB_LOG_ERROR("{}Not found", loc.string());
2587 asyncResp->res.result(
2588 boost::beast::http::status::not_found);
2589 return;
2590 }
2591 std::filesystem::directory_iterator files(loc);
zhanghch058d1b46d2021-04-01 11:18:24 +08002592
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002593 for (const auto& file : files)
2594 {
Myung Baed51c61b2024-09-13 10:35:34 -05002595 if (asyncResp->res.openFile(file) !=
2596 crow::OpenCode::Success)
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002597 {
2598 continue;
2599 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002600
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002601 asyncResp->res.addHeader(
2602 boost::beast::http::field::content_type,
2603 "application/octet-stream");
zhanghch058d1b46d2021-04-01 11:18:24 +08002604
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002605 // Assuming only one dump file will be present in the dump
2606 // id directory
2607 std::string dumpFileName = file.path().filename().string();
zhanghch058d1b46d2021-04-01 11:18:24 +08002608
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002609 // Filename should be in alphanumeric, dot and underscore
2610 // Its based on phosphor-debug-collector application
2611 // dumpfile format
2612 static std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
2613 if (!std::regex_match(dumpFileName, dumpFileRegex))
2614 {
2615 BMCWEB_LOG_ERROR("Invalid dump filename {}",
2616 dumpFileName);
2617 asyncResp->res.result(
2618 boost::beast::http::status::not_found);
2619 return;
2620 }
2621 std::string contentDispositionParam =
2622 "attachment; filename=\"" + dumpFileName + "\"";
2623
2624 asyncResp->res.addHeader(
2625 boost::beast::http::field::content_disposition,
2626 contentDispositionParam);
2627
2628 return;
2629 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002630 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002631 return;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002632 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002633
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002634 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002635 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002636
2637 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002638 [](const crow::Request&,
2639 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002640 const std::string& connection) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002641 introspectObjects(connection, "/", asyncResp);
2642 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002643
2644 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002645 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous1656b292022-05-04 11:33:42 -07002646 .methods(boost::beast::http::verb::get,
2647 boost::beast::http::verb::post)(handleBusSystemPost);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002648}
2649} // namespace openbmc_mapper
2650} // namespace crow