blob: c35a2beb05d617eedad8c8afd68ff2f4f5c9dce5 [file] [log] [blame]
Ed Tanous6be832e2024-09-10 11:44:48 -07001/*
2Copyright (c) 2018 Intel Corporation
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
Ed Tanousb9b2e0b2018-09-13 13:47:50 -070016
James Feist5b4aa862018-08-16 14:07:01 -070017#pragma once
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080018#include "app.hpp"
19#include "async_resp.hpp"
Ed Tanous95c63072024-03-26 13:19:52 -070020#include "boost_formatters.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080021#include "dbus_singleton.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +080022#include "dbus_utility.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000023#include "http_request.hpp"
24#include "http_response.hpp"
Ed Tanous95c63072024-03-26 13:19:52 -070025#include "json_formatters.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000026#include "logging.hpp"
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010027#include "parsing.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000028#include "routing.hpp"
Ed Tanous50ebd4a2023-01-19 19:03:17 -080029#include "str_utility.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000030
31#include <systemd/sd-bus-protocol.h>
32#include <systemd/sd-bus.h>
Ed Tanous911ac312017-08-15 09:37:42 -070033#include <tinyxml2.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -070034
Nan Zhoud5c80ad2022-07-11 01:16:31 +000035#include <boost/beast/http/status.hpp>
36#include <boost/beast/http/verb.hpp>
37#include <boost/container/flat_map.hpp>
38#include <boost/container/vector.hpp>
George Liue99073f2022-12-09 11:06:16 +080039#include <boost/system/error_code.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000040#include <nlohmann/json.hpp>
41#include <sdbusplus/asio/connection.hpp>
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +020042#include <sdbusplus/asio/property.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000043#include <sdbusplus/exception.hpp>
44#include <sdbusplus/message.hpp>
45#include <sdbusplus/message/native_types.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050046
Nan Zhoud5c80ad2022-07-11 01:16:31 +000047#include <algorithm>
48#include <array>
49#include <cerrno>
50#include <cstdint>
51#include <cstring>
James Feist4418c7f2019-04-15 11:09:15 -070052#include <filesystem>
Ed Tanousd4bb9bb2018-05-16 13:36:42 -070053#include <fstream>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000054#include <functional>
55#include <initializer_list>
56#include <iterator>
57#include <limits>
58#include <map>
59#include <memory>
Ed Tanous3544d2a2023-08-06 18:12:20 -070060#include <ranges>
Ramesh Iyyard9207042019-07-05 08:04:42 -050061#include <regex>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000062#include <string>
63#include <string_view>
64#include <type_traits>
Ed Tanousb5a76932020-09-29 16:16:58 -070065#include <utility>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000066#include <variant>
67#include <vector>
68
Ed Tanouse3648032024-10-16 18:06:39 -070069namespace nlohmann
70{
71template <typename... Args>
72struct adl_serializer<std::variant<Args...>>
73{
74 // NOLINTNEXTLINE(readability-identifier-naming)
75 static void to_json(json& j, const std::variant<Args...>& args)
76 {
77 std::visit([&j](auto&& val) { j = val; }, args);
78 }
79};
80} // namespace nlohmann
81
Ed Tanous1abe55e2018-09-05 08:30:59 -070082namespace crow
83{
84namespace openbmc_mapper
85{
Ed Tanous23a21a12020-07-25 04:45:05 +000086const constexpr char* notFoundMsg = "404 Not Found";
87const constexpr char* badReqMsg = "400 Bad Request";
88const constexpr char* methodNotAllowedMsg = "405 Method Not Allowed";
89const constexpr char* forbiddenMsg = "403 Forbidden";
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010090const constexpr char* unsupportedMediaMsg = "415 Unsupported Media Type";
Ed Tanous23a21a12020-07-25 04:45:05 +000091const constexpr char* methodFailedMsg = "500 Method Call Failed";
92const constexpr char* methodOutputFailedMsg = "500 Method Output Error";
93const constexpr char* notFoundDesc =
Matt Spinler2ae60092018-12-06 10:35:36 -060094 "org.freedesktop.DBus.Error.FileNotFound: path or object not found";
Ed Tanous23a21a12020-07-25 04:45:05 +000095const constexpr char* propNotFoundDesc =
96 "The specified property cannot be found";
97const constexpr char* noJsonDesc = "No JSON object could be decoded";
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010098const constexpr char* invalidContentType =
99 "Content-type header is missing or invalid";
Ed Tanous23a21a12020-07-25 04:45:05 +0000100const constexpr char* methodNotFoundDesc =
101 "The specified method cannot be found";
102const constexpr char* methodNotAllowedDesc = "Method not allowed";
103const constexpr char* forbiddenPropDesc =
104 "The specified property cannot be created";
105const constexpr char* forbiddenResDesc =
106 "The specified resource cannot be created";
Matt Spinler2ae60092018-12-06 10:35:36 -0600107
Josh Lehan482c45a2022-03-29 17:10:44 -0700108inline bool validateFilename(const std::string& filename)
109{
Ed Tanous4b242742023-05-11 09:51:51 -0700110 static std::regex validFilename(R"(^[\w\- ]+(\.?[\w\- ]*)$)");
Josh Lehan482c45a2022-03-29 17:10:44 -0700111
112 return std::regex_match(filename, validFilename);
113}
114
Ed Tanous23a21a12020-07-25 04:45:05 +0000115inline void setErrorResponse(crow::Response& res,
116 boost::beast::http::status result,
Ed Tanous26ccae32023-02-16 10:28:44 -0800117 const std::string& desc, std::string_view msg)
Matt Spinler2ae60092018-12-06 10:35:36 -0600118{
119 res.result(result);
Ed Tanous14766872022-03-15 10:44:42 -0700120 res.jsonValue["data"]["description"] = desc;
121 res.jsonValue["message"] = msg;
122 res.jsonValue["status"] = "error";
Matt Spinler2ae60092018-12-06 10:35:36 -0600123}
124
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400125inline void introspectObjects(
126 const std::string& processName, const std::string& objectPath,
127 const std::shared_ptr<bmcweb::AsyncResp>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700128{
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700129 if (transaction->res.jsonValue.is_null())
130 {
Ed Tanous14766872022-03-15 10:44:42 -0700131 transaction->res.jsonValue["status"] = "ok";
132 transaction->res.jsonValue["bus_name"] = processName;
133 transaction->res.jsonValue["objects"] = nlohmann::json::array();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700134 }
135
Ed Tanous1abe55e2018-09-05 08:30:59 -0700136 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700137 [transaction, processName{std::string(processName)},
138 objectPath{std::string(objectPath)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800139 const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +0000140 const std::string& introspectXml) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400141 if (ec)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700142 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400143 BMCWEB_LOG_ERROR(
144 "Introspect call failed with error: {} on process: {} path: {}",
145 ec.message(), processName, objectPath);
146 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700147 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400148 nlohmann::json::object_t object;
149 object["path"] = objectPath;
150
151 transaction->res.jsonValue["objects"].emplace_back(
152 std::move(object));
153
154 tinyxml2::XMLDocument doc;
155
156 doc.Parse(introspectXml.c_str());
157 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
158 if (pRoot == nullptr)
159 {
160 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
161 processName, objectPath);
162 }
163 else
164 {
165 tinyxml2::XMLElement* node = pRoot->FirstChildElement("node");
166 while (node != nullptr)
167 {
168 const char* childPath = node->Attribute("name");
169 if (childPath != nullptr)
170 {
171 std::string newpath;
172 if (objectPath != "/")
173 {
174 newpath += objectPath;
175 }
176 newpath += std::string("/") + childPath;
177 // introspect the subobjects as well
178 introspectObjects(processName, newpath, transaction);
179 }
180
181 node = node->NextSiblingElement("node");
182 }
183 }
184 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700185 processName, objectPath, "org.freedesktop.DBus.Introspectable",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700186 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -0700187}
Ed Tanous64530012018-02-06 17:08:16 -0800188
Ed Tanous23a21a12020-07-25 04:45:05 +0000189inline void getPropertiesForEnumerate(
190 const std::string& objectPath, const std::string& service,
Ed Tanousb5a76932020-09-29 16:16:58 -0700191 const std::string& interface,
192 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600193{
Ed Tanous62598e32023-07-17 17:06:25 -0700194 BMCWEB_LOG_DEBUG("getPropertiesForEnumerate {} {} {}", objectPath, service,
195 interface);
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600196
Ed Tanousdeae6a72024-11-11 21:58:57 -0800197 dbus::utility::getAllProperties(
198 service, objectPath, interface,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800199 [asyncResp, objectPath, service,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800200 interface](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800201 const dbus::utility::DBusPropertiesMap& propertiesList) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400202 if (ec)
203 {
204 BMCWEB_LOG_ERROR(
205 "GetAll on path {} iface {} service {} failed with code {}",
206 objectPath, interface, service, ec);
207 return;
208 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600209
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400210 nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
211 nlohmann::json& objectJson = dataJson[objectPath];
212 if (objectJson.is_null())
213 {
214 objectJson = nlohmann::json::object();
215 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600216
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400217 for (const auto& [name, value] : propertiesList)
218 {
219 nlohmann::json& propertyJson = objectJson[name];
Ed Tanouse3648032024-10-16 18:06:39 -0700220 std::visit([&propertyJson](auto&& val) { propertyJson = val; },
221 value);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400222 }
223 });
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600224}
225
226// Find any results that weren't picked up by ObjectManagers, to be
227// called after all ObjectManagers are searched for and called.
Ed Tanous23a21a12020-07-25 04:45:05 +0000228inline void findRemainingObjectsForEnumerate(
Ed Tanousb5a76932020-09-29 16:16:58 -0700229 const std::string& objectPath,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800230 const std::shared_ptr<dbus::utility::MapperGetSubTreeResponse>& subtree,
Ed Tanousb5a76932020-09-29 16:16:58 -0700231 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600232{
Ed Tanous62598e32023-07-17 17:06:25 -0700233 BMCWEB_LOG_DEBUG("findRemainingObjectsForEnumerate");
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500234 const nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600235
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500236 for (const auto& [path, interface_map] : *subtree)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600237 {
238 if (path == objectPath)
239 {
240 // An enumerate does not return the target path's properties
241 continue;
242 }
243 if (dataJson.find(path) == dataJson.end())
244 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500245 for (const auto& [service, interfaces] : interface_map)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600246 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500247 for (const auto& interface : interfaces)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600248 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700249 if (!interface.starts_with("org.freedesktop.DBus"))
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600250 {
251 getPropertiesForEnumerate(path, service, interface,
252 asyncResp);
253 }
254 }
255 }
256 }
257 }
258}
259
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600260struct InProgressEnumerateData
261{
zhanghch058d1b46d2021-04-01 11:18:24 +0800262 InProgressEnumerateData(
263 const std::string& objectPathIn,
264 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400265 objectPath(objectPathIn), asyncResp(asyncRespIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500266 {}
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600267
268 ~InProgressEnumerateData()
269 {
Ed Tanous24b2fe82022-01-06 12:45:54 -0800270 try
271 {
272 findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
273 }
274 catch (...)
275 {
Ed Tanous62598e32023-07-17 17:06:25 -0700276 BMCWEB_LOG_CRITICAL(
277 "findRemainingObjectsForEnumerate threw exception");
Ed Tanous24b2fe82022-01-06 12:45:54 -0800278 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600279 }
280
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800281 InProgressEnumerateData(const InProgressEnumerateData&) = delete;
282 InProgressEnumerateData(InProgressEnumerateData&&) = delete;
283 InProgressEnumerateData& operator=(const InProgressEnumerateData&) = delete;
284 InProgressEnumerateData& operator=(InProgressEnumerateData&&) = delete;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600285 const std::string objectPath;
Ed Tanousb9d36b42022-02-26 21:42:46 -0800286 std::shared_ptr<dbus::utility::MapperGetSubTreeResponse> subtree;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600287 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
288};
289
Ed Tanous23a21a12020-07-25 04:45:05 +0000290inline void getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000291 const std::string& objectName, const std::string& objectManagerPath,
292 const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700293 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700294{
Ed Tanous62598e32023-07-17 17:06:25 -0700295 BMCWEB_LOG_DEBUG(
296 "getManagedObjectsForEnumerate {} object_manager_path {} connection_name {}",
297 objectName, objectManagerPath, connectionName);
George Liu5eb468d2023-06-20 17:03:24 +0800298 sdbusplus::message::object_path path(objectManagerPath);
299 dbus::utility::getManagedObjects(
300 connectionName, path,
Ed Tanous81ce6092020-12-17 16:54:55 +0000301 [transaction, objectName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800302 connectionName](const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +0000303 const dbus::utility::ManagedObjectType& objects) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400304 if (ec)
Ed Tanous049a0512018-11-01 13:58:42 -0700305 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400306 BMCWEB_LOG_ERROR(
307 "GetManagedObjects on path {} on connection {} failed with code {}",
308 objectName, connectionName, ec);
309 return;
310 }
311
312 nlohmann::json& dataJson =
313 transaction->asyncResp->res.jsonValue["data"];
314
315 for (const auto& objectPath : objects)
316 {
317 if (objectPath.first.str.starts_with(objectName))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700318 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400319 BMCWEB_LOG_DEBUG("Reading object {}", objectPath.first.str);
320 nlohmann::json& objectJson = dataJson[objectPath.first.str];
321 if (objectJson.is_null())
322 {
323 objectJson = nlohmann::json::object();
324 }
325 for (const auto& interface : objectPath.second)
326 {
327 for (const auto& property : interface.second)
328 {
329 nlohmann::json& propertyJson =
330 objectJson[property.first];
331 std::visit(
332 [&propertyJson](auto&& val) {
333 if constexpr (
334 std::is_same_v<
335 std::decay_t<decltype(val)>,
336 sdbusplus::message::unix_fd>)
337 {
338 propertyJson = val.fd;
339 }
340 else
341 {
342 propertyJson = val;
343 }
344 },
345 property.second);
346 }
347 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700348 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500349 for (const auto& interface : objectPath.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700350 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400351 if (interface.first == "org.freedesktop.DBus.ObjectManager")
Ed Tanous049a0512018-11-01 13:58:42 -0700352 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400353 getManagedObjectsForEnumerate(
354 objectPath.first.str, objectPath.first.str,
355 connectionName, transaction);
Ed Tanous049a0512018-11-01 13:58:42 -0700356 }
357 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700358 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400359 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700360}
361
Ed Tanous23a21a12020-07-25 04:45:05 +0000362inline void findObjectManagerPathForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000363 const std::string& objectName, const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700364 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700365{
Ed Tanous62598e32023-07-17 17:06:25 -0700366 BMCWEB_LOG_DEBUG("Finding objectmanager for path {} on connection:{}",
367 objectName, connectionName);
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700368 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000369 [transaction, objectName, connectionName](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800370 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800371 const dbus::utility::MapperGetAncestorsResponse& objects) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400372 if (ec)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700373 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400374 BMCWEB_LOG_ERROR("GetAncestors on path {} failed with code {}",
375 objectName, ec);
376 return;
377 }
378
379 for (const auto& pathGroup : objects)
380 {
381 for (const auto& connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700382 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400383 if (connectionGroup.first == connectionName)
384 {
385 // Found the object manager path for this resource.
386 getManagedObjectsForEnumerate(
387 objectName, pathGroup.first, connectionName,
388 transaction);
389 return;
390 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700391 }
392 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400393 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700394 "xyz.openbmc_project.ObjectMapper",
395 "/xyz/openbmc_project/object_mapper",
Ed Tanous81ce6092020-12-17 16:54:55 +0000396 "xyz.openbmc_project.ObjectMapper", "GetAncestors", objectName,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500397 std::array<const char*, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700398}
Ed Tanous64530012018-02-06 17:08:16 -0800399
Ed Tanous7c091622019-05-23 11:42:36 -0700400// Uses GetObject to add the object info about the target /enumerate path to
401// the results of GetSubTree, as GetSubTree will not return info for the
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600402// target path, and then continues on enumerating the rest of the tree.
Ed Tanousb5a76932020-09-29 16:16:58 -0700403inline void getObjectAndEnumerate(
404 const std::shared_ptr<InProgressEnumerateData>& transaction)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600405{
George Liu2b731192023-01-11 16:27:13 +0800406 dbus::utility::getDbusObject(
407 transaction->objectPath, {},
408 [transaction](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800409 const dbus::utility::MapperGetObject& objects) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400410 if (ec)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600411 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400412 BMCWEB_LOG_ERROR("GetObject for path {} failed with code {}",
413 transaction->objectPath, ec);
414 return;
415 }
416
417 BMCWEB_LOG_DEBUG("GetObject for {} has {} entries",
418 transaction->objectPath, objects.size());
419 if (!objects.empty())
420 {
421 transaction->subtree->emplace_back(transaction->objectPath,
422 objects);
423 }
424
425 // Map indicating connection name, and the path where the object
426 // manager exists
427 boost::container::flat_map<
428 std::string, std::string, std::less<>,
429 std::vector<std::pair<std::string, std::string>>>
430 connections;
431
432 for (const auto& object : *(transaction->subtree))
433 {
434 for (const auto& connection : object.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600435 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400436 for (const auto& interface : connection.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600437 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400438 BMCWEB_LOG_DEBUG("{} has interface {}",
439 connection.first, interface);
440 if (interface == "org.freedesktop.DBus.ObjectManager")
441 {
442 BMCWEB_LOG_DEBUG("found object manager path {}",
443 object.first);
444 connections[connection.first] = object.first;
445 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600446 }
447 }
448 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400449 BMCWEB_LOG_DEBUG("Got {} connections", connections.size());
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600450
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400451 for (const auto& connection : connections)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600452 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400453 // If we already know where the object manager is, we don't
454 // need to search for it, we can call directly in to
455 // getManagedObjects
456 if (!connection.second.empty())
457 {
458 getManagedObjectsForEnumerate(
459 transaction->objectPath, connection.second,
460 connection.first, transaction);
461 }
462 else
463 {
464 // otherwise we need to find the object manager path
465 // before we can continue
466 findObjectManagerPathForEnumerate(
467 transaction->objectPath, connection.first, transaction);
468 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600469 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400470 });
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600471}
Ed Tanous64530012018-02-06 17:08:16 -0800472
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700473// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700474struct InProgressActionData
475{
Lei YU28dd5ca2023-03-17 13:17:05 +0800476 explicit InProgressActionData(
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400477 const std::shared_ptr<bmcweb::AsyncResp>& res) : asyncResp(res)
Ed Tanous23a21a12020-07-25 04:45:05 +0000478 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700479 ~InProgressActionData()
480 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600481 // Methods could have been called across different owners
482 // and interfaces, where some calls failed and some passed.
483 //
484 // The rules for this are:
485 // * if no method was called - error
486 // * if a method failed and none passed - error
487 // (converse: if at least one method passed - OK)
488 // * for the method output:
489 // * if output processing didn't fail, return the data
490
491 // Only deal with method returns if nothing failed earlier
Lei YU28dd5ca2023-03-17 13:17:05 +0800492 if (asyncResp->res.result() == boost::beast::http::status::ok)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700493 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600494 if (!methodPassed)
495 {
Matt Spinler06b1b632019-06-18 16:09:25 -0500496 if (!methodFailed)
Matt Spinler16caaee2019-01-15 11:40:34 -0600497 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800498 setErrorResponse(asyncResp->res,
499 boost::beast::http::status::not_found,
Matt Spinler16caaee2019-01-15 11:40:34 -0600500 methodNotFoundDesc, notFoundMsg);
501 }
502 }
503 else
504 {
505 if (outputFailed)
506 {
507 setErrorResponse(
Lei YU28dd5ca2023-03-17 13:17:05 +0800508 asyncResp->res,
509 boost::beast::http::status::internal_server_error,
Matt Spinler16caaee2019-01-15 11:40:34 -0600510 "Method output failure", methodOutputFailedMsg);
511 }
512 else
513 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800514 asyncResp->res.jsonValue["status"] = "ok";
515 asyncResp->res.jsonValue["message"] = "200 OK";
516 asyncResp->res.jsonValue["data"] = methodResponse;
Matt Spinler16caaee2019-01-15 11:40:34 -0600517 }
518 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700519 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700520 }
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800521 InProgressActionData(const InProgressActionData&) = delete;
522 InProgressActionData(InProgressActionData&&) = delete;
523 InProgressActionData& operator=(const InProgressActionData&) = delete;
524 InProgressActionData& operator=(InProgressActionData&&) = delete;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700525
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500526 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700527 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800528 setErrorResponse(asyncResp->res,
529 boost::beast::http::status::bad_request, desc,
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600530 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700531 }
Lei YU28dd5ca2023-03-17 13:17:05 +0800532 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700533 std::string path;
534 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600535 std::string interfaceName;
Matt Spinler16caaee2019-01-15 11:40:34 -0600536 bool methodPassed = false;
537 bool methodFailed = false;
538 bool outputFailed = false;
Matt Spinler39a4e392019-01-15 11:53:13 -0600539 bool convertedToArray = false;
Matt Spinler16caaee2019-01-15 11:40:34 -0600540 nlohmann::json methodResponse;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700541 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700542};
543
Ed Tanous23a21a12020-07-25 04:45:05 +0000544inline std::vector<std::string> dbusArgSplit(const std::string& string)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700545{
546 std::vector<std::string> ret;
547 if (string.empty())
548 {
549 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700550 }
Ed Tanous0f0353b2019-10-24 11:37:51 -0700551 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700552 int containerDepth = 0;
553
554 for (std::string::const_iterator character = string.begin();
555 character != string.end(); character++)
556 {
557 ret.back() += *character;
558 switch (*character)
559 {
560 case ('a'):
561 break;
562 case ('('):
563 case ('{'):
564 containerDepth++;
565 break;
566 case ('}'):
567 case (')'):
568 containerDepth--;
569 if (containerDepth == 0)
570 {
571 if (character + 1 != string.end())
572 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700573 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700574 }
575 }
576 break;
577 default:
578 if (containerDepth == 0)
579 {
580 if (character + 1 != string.end())
581 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700582 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700583 }
584 }
585 break;
586 }
587 }
Matt Spinler4ae611d2019-01-11 15:37:06 -0600588
589 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700590}
591
Ed Tanous81ce6092020-12-17 16:54:55 +0000592inline int convertJsonToDbus(sd_bus_message* m, const std::string& argType,
593 const nlohmann::json& inputJson)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700594{
595 int r = 0;
Ed Tanous296579b2024-03-11 16:58:24 -0700596 BMCWEB_LOG_DEBUG("Converting {} to type: {}", inputJson, argType);
Ed Tanous81ce6092020-12-17 16:54:55 +0000597 const std::vector<std::string> argTypes = dbusArgSplit(argType);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700598
Ed Tanous1abe55e2018-09-05 08:30:59 -0700599 // Assume a single object for now.
Ed Tanous81ce6092020-12-17 16:54:55 +0000600 const nlohmann::json* j = &inputJson;
601 nlohmann::json::const_iterator jIt = inputJson.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700602
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500603 for (const std::string& argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700604 {
605 // If we are decoding multiple objects, grab the pointer to the
606 // iterator, and increment it for the next loop
607 if (argTypes.size() > 1)
608 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000609 if (jIt == inputJson.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700610 {
611 return -2;
612 }
613 j = &*jIt;
614 jIt++;
615 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500616 const int64_t* intValue = j->get_ptr<const int64_t*>();
617 const std::string* stringValue = j->get_ptr<const std::string*>();
618 const double* doubleValue = j->get_ptr<const double*>();
619 const bool* b = j->get_ptr<const bool*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700620 int64_t v = 0;
621 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700622
Ed Tanous1abe55e2018-09-05 08:30:59 -0700623 // Do some basic type conversions that make sense. uint can be
624 // converted to int. int and uint can be converted to double
Ed Tanous66664f22019-10-11 13:05:49 -0700625 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700626 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500627 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700628 if (uintValue != nullptr)
629 {
630 v = static_cast<int64_t>(*uintValue);
631 intValue = &v;
632 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700633 }
Ed Tanous66664f22019-10-11 13:05:49 -0700634 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700635 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500636 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700637 if (uintValue != nullptr)
638 {
639 d = static_cast<double>(*uintValue);
640 doubleValue = &d;
641 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700642 }
Ed Tanous66664f22019-10-11 13:05:49 -0700643 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700644 {
Ed Tanous66664f22019-10-11 13:05:49 -0700645 if (intValue != nullptr)
646 {
647 d = static_cast<double>(*intValue);
648 doubleValue = &d;
649 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700650 }
651
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700652 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700653 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700654 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700655 {
656 return -1;
657 }
Ed Tanous271584a2019-07-09 16:24:22 -0700658 r = sd_bus_message_append_basic(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500659 m, argCode[0], static_cast<const void*>(stringValue->data()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700660 if (r < 0)
661 {
662 return r;
663 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700664 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700665 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700666 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700667 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700668 {
669 return -1;
670 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500671 if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
672 (*intValue > std::numeric_limits<int32_t>::max()))
673 {
674 return -ERANGE;
675 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700676 int32_t i = static_cast<int32_t>(*intValue);
677 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700678 if (r < 0)
679 {
680 return r;
681 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700682 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700683 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700684 {
685 // lots of ways bool could be represented here. Try them all
Ed Tanouse662eae2022-01-25 10:39:19 -0800686 int boolInt = 0;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700687 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700688 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500689 if (*intValue == 1)
690 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800691 boolInt = 1;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500692 }
693 else if (*intValue == 0)
694 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800695 boolInt = 0;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500696 }
697 else
698 {
699 return -ERANGE;
700 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700701 }
702 else if (b != nullptr)
703 {
Matt Spinlera2f02632019-01-18 10:15:35 -0600704 boolInt = *b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700705 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700706 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700707 {
Ed Tanous18f8f602023-07-18 10:07:23 -0700708 if (!stringValue->empty())
709 {
710 if (stringValue->front() == 't' ||
711 stringValue->front() == 'T')
712 {
713 boolInt = 1;
714 }
715 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700716 }
717 else
718 {
719 return -1;
720 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700721 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
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 == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700728 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700729 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700730 {
731 return -1;
732 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500733 if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
734 (*intValue > std::numeric_limits<int16_t>::max()))
735 {
736 return -ERANGE;
737 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700738 int16_t n = static_cast<int16_t>(*intValue);
739 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700740 if (r < 0)
741 {
742 return r;
743 }
744 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700745 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700746 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700747 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700748 {
749 return -1;
750 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700751 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700752 if (r < 0)
753 {
754 return r;
755 }
756 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700757 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700758 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500759 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700760 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700761 {
762 return -1;
763 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000764 if (*uintValue > std::numeric_limits<uint8_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500765 {
766 return -ERANGE;
767 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700768 uint8_t y = static_cast<uint8_t>(*uintValue);
769 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700770 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700771 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700772 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500773 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700774 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700775 {
776 return -1;
777 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000778 if (*uintValue > std::numeric_limits<uint16_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500779 {
780 return -ERANGE;
781 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700782 uint16_t q = static_cast<uint16_t>(*uintValue);
783 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700784 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700785 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700786 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500787 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700788 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700789 {
790 return -1;
791 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000792 if (*uintValue > std::numeric_limits<uint32_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500793 {
794 return -ERANGE;
795 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700796 uint32_t u = static_cast<uint32_t>(*uintValue);
797 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700798 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700799 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700800 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500801 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700802 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700803 {
804 return -1;
805 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700806 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700807 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700808 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700809 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500810 if (doubleValue == nullptr)
811 {
812 return -1;
813 }
814 if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
815 (*doubleValue > std::numeric_limits<double>::max()))
816 {
817 return -ERANGE;
818 }
Ed Tanous07900812024-05-06 15:41:30 -0700819 r = sd_bus_message_append_basic(m, argCode[0], doubleValue);
820 if (r < 0)
821 {
822 return r;
823 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700824 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700825 else if (argCode.starts_with("a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700826 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700827 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700828 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700829 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700830 if (r < 0)
831 {
832 return r;
833 }
834
Ed Tanous0dfeda62019-10-24 11:21:38 -0700835 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700836 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700837 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700838 if (r < 0)
839 {
840 return r;
841 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700842 }
843 sd_bus_message_close_container(m);
844 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700845 else if (argCode.starts_with("v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700846 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700847 std::string containedType = argCode.substr(1);
Ed Tanous62598e32023-07-17 17:06:25 -0700848 BMCWEB_LOG_DEBUG("variant type: {} appending variant of type: {}",
849 argCode, containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700850 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700851 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700852 if (r < 0)
853 {
854 return r;
855 }
856
Ed Tanous81ce6092020-12-17 16:54:55 +0000857 r = convertJsonToDbus(m, containedType, inputJson);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700858 if (r < 0)
859 {
860 return r;
861 }
862
863 r = sd_bus_message_close_container(m);
864 if (r < 0)
865 {
866 return r;
867 }
868 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700869 else if (argCode.starts_with("(") && argCode.ends_with(")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700870 {
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300871 std::string containedType = argCode.substr(1, argCode.size() - 2);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700872 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700873 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800874 if (r < 0)
875 {
876 return r;
877 }
878
Ed Tanous1abe55e2018-09-05 08:30:59 -0700879 nlohmann::json::const_iterator it = j->begin();
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300880 for (const std::string& argCode2 : dbusArgSplit(containedType))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700881 {
882 if (it == j->end())
883 {
884 return -1;
885 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000886 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700887 if (r < 0)
888 {
889 return r;
890 }
891 it++;
892 }
893 r = sd_bus_message_close_container(m);
894 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700895 else if (argCode.starts_with("{") && argCode.ends_with("}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700896 {
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300897 std::string containedType = argCode.substr(1, argCode.size() - 2);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700898 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700899 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800900 if (r < 0)
901 {
902 return r;
903 }
904
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700905 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700906 if (codes.size() != 2)
907 {
908 return -1;
909 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700910 const std::string& keyType = codes[0];
911 const std::string& valueType = codes[1];
Ed Tanous0bdda662023-08-03 17:27:34 -0700912 const nlohmann::json::object_t* arr =
913 j->get_ptr<const nlohmann::json::object_t*>();
914 if (arr == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700915 {
Ed Tanous0bdda662023-08-03 17:27:34 -0700916 return -1;
917 }
918 for (const auto& it : *arr)
919 {
920 r = convertJsonToDbus(m, keyType, it.first);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700921 if (r < 0)
922 {
923 return r;
924 }
925
Ed Tanous0bdda662023-08-03 17:27:34 -0700926 r = convertJsonToDbus(m, valueType, it.second);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700927 if (r < 0)
928 {
929 return r;
930 }
931 }
932 r = sd_bus_message_close_container(m);
933 }
934 else
935 {
936 return -2;
937 }
938 if (r < 0)
939 {
940 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700941 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700942
Ed Tanous1abe55e2018-09-05 08:30:59 -0700943 if (argTypes.size() > 1)
944 {
945 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700946 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700947 }
Matt Spinler127ea542019-01-14 11:04:28 -0600948
949 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700950}
951
Matt Spinlerd22a7132019-01-14 12:14:30 -0600952template <typename T>
Patrick Williams59d494e2022-07-22 19:26:55 -0500953int readMessageItem(const std::string& typeCode, sdbusplus::message_t& m,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500954 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600955{
956 T value;
Ed Tanousf79ce6a2024-03-20 12:27:06 -0700957 // When T == char*, this warning fires. Unclear how to resolve
958 // Given that sd-bus takes a void pointer to a char*, and that's
959 // Not something we can fix.
960 // NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600961 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
962 if (r < 0)
963 {
Ed Tanous62598e32023-07-17 17:06:25 -0700964 BMCWEB_LOG_ERROR("sd_bus_message_read_basic on type {} failed!",
965 typeCode);
Matt Spinlerd22a7132019-01-14 12:14:30 -0600966 return r;
967 }
968
969 data = value;
970 return 0;
971}
972
Patrick Williams59d494e2022-07-22 19:26:55 -0500973int convertDBusToJSON(const std::string& returnType, sdbusplus::message_t& m,
974 nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600975
Ed Tanous23a21a12020-07-25 04:45:05 +0000976inline int readDictEntryFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -0500977 sdbusplus::message_t& m,
Ed Tanous23a21a12020-07-25 04:45:05 +0000978 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600979{
980 std::vector<std::string> types = dbusArgSplit(typeCode);
981 if (types.size() != 2)
982 {
Ed Tanous62598e32023-07-17 17:06:25 -0700983 BMCWEB_LOG_ERROR("wrong number contained types in dictionary: {}",
984 types.size());
Matt Spinler6df8f992019-01-14 12:47:47 -0600985 return -1;
986 }
987
988 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
989 typeCode.c_str());
990 if (r < 0)
991 {
Ed Tanous62598e32023-07-17 17:06:25 -0700992 BMCWEB_LOG_ERROR("sd_bus_message_enter_container with rc {}", r);
Matt Spinler6df8f992019-01-14 12:47:47 -0600993 return r;
994 }
995
996 nlohmann::json key;
997 r = convertDBusToJSON(types[0], m, key);
998 if (r < 0)
999 {
1000 return r;
1001 }
1002
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001003 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -06001004 if (keyPtr == nullptr)
1005 {
1006 // json doesn't support non-string keys. If we hit this condition,
1007 // convert the result to a string so we can proceed
Ed Tanous71f52d92021-02-19 08:51:17 -08001008 key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001009 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -07001010 // in theory this can't fail now, but lets be paranoid about it
1011 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -06001012 if (keyPtr == nullptr)
1013 {
1014 return -1;
1015 }
1016 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001017 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -06001018
1019 r = convertDBusToJSON(types[1], m, value);
1020 if (r < 0)
1021 {
1022 return r;
1023 }
1024
1025 r = sd_bus_message_exit_container(m.get());
1026 if (r < 0)
1027 {
Ed Tanous62598e32023-07-17 17:06:25 -07001028 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001029 return r;
1030 }
1031
1032 return 0;
1033}
1034
Ed Tanous23a21a12020-07-25 04:45:05 +00001035inline int readArrayFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001036 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -06001037{
1038 if (typeCode.size() < 2)
1039 {
Ed Tanous62598e32023-07-17 17:06:25 -07001040 BMCWEB_LOG_ERROR("Type code {} too small for an array", typeCode);
Matt Spinler6df8f992019-01-14 12:47:47 -06001041 return -1;
1042 }
1043
1044 std::string containedType = typeCode.substr(1);
1045
1046 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
1047 containedType.c_str());
1048 if (r < 0)
1049 {
Ed Tanous62598e32023-07-17 17:06:25 -07001050 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler6df8f992019-01-14 12:47:47 -06001051 return r;
1052 }
1053
Ed Tanous11ba3972022-07-11 09:50:41 -07001054 bool dict = containedType.starts_with("{") && containedType.ends_with("}");
Matt Spinler6df8f992019-01-14 12:47:47 -06001055
1056 if (dict)
1057 {
1058 // Remove the { }
1059 containedType = containedType.substr(1, containedType.size() - 2);
1060 data = nlohmann::json::object();
1061 }
1062 else
1063 {
1064 data = nlohmann::json::array();
1065 }
1066
1067 while (true)
1068 {
Ed Tanouse662eae2022-01-25 10:39:19 -08001069 r = sd_bus_message_at_end(m.get(), 0);
Matt Spinler6df8f992019-01-14 12:47:47 -06001070 if (r < 0)
1071 {
Ed Tanous62598e32023-07-17 17:06:25 -07001072 BMCWEB_LOG_ERROR("sd_bus_message_at_end failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001073 return r;
1074 }
1075
1076 if (r > 0)
1077 {
1078 break;
1079 }
1080
1081 // Dictionaries are only ever seen in an array
1082 if (dict)
1083 {
1084 r = readDictEntryFromMessage(containedType, m, data);
1085 if (r < 0)
1086 {
1087 return r;
1088 }
1089 }
1090 else
1091 {
1092 data.push_back(nlohmann::json());
1093
1094 r = convertDBusToJSON(containedType, m, data.back());
1095 if (r < 0)
1096 {
1097 return r;
1098 }
1099 }
1100 }
1101
1102 r = sd_bus_message_exit_container(m.get());
1103 if (r < 0)
1104 {
Ed Tanous62598e32023-07-17 17:06:25 -07001105 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001106 return r;
1107 }
1108
1109 return 0;
1110}
1111
Ed Tanous23a21a12020-07-25 04:45:05 +00001112inline int readStructFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001113 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001114{
1115 if (typeCode.size() < 3)
1116 {
Ed Tanous62598e32023-07-17 17:06:25 -07001117 BMCWEB_LOG_ERROR("Type code {} too small for a struct", typeCode);
Matt Spinler75c6c672019-01-14 13:01:46 -06001118 return -1;
1119 }
1120
1121 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1122 std::vector<std::string> types = dbusArgSplit(containedTypes);
1123
1124 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1125 containedTypes.c_str());
1126 if (r < 0)
1127 {
Ed Tanous62598e32023-07-17 17:06:25 -07001128 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler75c6c672019-01-14 13:01:46 -06001129 return r;
1130 }
1131
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001132 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001133 {
1134 data.push_back(nlohmann::json());
1135 r = convertDBusToJSON(type, m, data.back());
1136 if (r < 0)
1137 {
1138 return r;
1139 }
1140 }
1141
1142 r = sd_bus_message_exit_container(m.get());
1143 if (r < 0)
1144 {
Ed Tanous62598e32023-07-17 17:06:25 -07001145 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler75c6c672019-01-14 13:01:46 -06001146 return r;
1147 }
1148 return 0;
1149}
1150
Patrick Williams59d494e2022-07-22 19:26:55 -05001151inline int readVariantFromMessage(sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001152{
Ed Tanous543f4402022-01-06 13:12:53 -08001153 const char* containerType = nullptr;
Ed Tanous99131cd2019-10-24 11:12:47 -07001154 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001155 if (r < 0)
1156 {
Ed Tanous62598e32023-07-17 17:06:25 -07001157 BMCWEB_LOG_ERROR("sd_bus_message_peek_type failed");
Matt Spinler89c19702019-01-14 13:13:00 -06001158 return r;
1159 }
1160
1161 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1162 containerType);
1163 if (r < 0)
1164 {
Ed Tanous62598e32023-07-17 17:06:25 -07001165 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler89c19702019-01-14 13:13:00 -06001166 return r;
1167 }
1168
1169 r = convertDBusToJSON(containerType, m, data);
1170 if (r < 0)
1171 {
1172 return r;
1173 }
1174
1175 r = sd_bus_message_exit_container(m.get());
1176 if (r < 0)
1177 {
Ed Tanous62598e32023-07-17 17:06:25 -07001178 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed");
Matt Spinler89c19702019-01-14 13:13:00 -06001179 return r;
1180 }
1181
1182 return 0;
1183}
1184
Ed Tanous23a21a12020-07-25 04:45:05 +00001185inline int convertDBusToJSON(const std::string& returnType,
Patrick Williams59d494e2022-07-22 19:26:55 -05001186 sdbusplus::message_t& m, nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001187{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001188 int r = 0;
1189 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1190
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001191 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001192 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001193 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001194 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001195 {
1196 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001197 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001198 }
1199
Ed Tanousd4d25792020-09-29 15:15:03 -07001200 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001201 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001202 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001203 if (r < 0)
1204 {
1205 return r;
1206 }
1207 }
1208 else if (typeCode == "b")
1209 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001210 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001211 if (r < 0)
1212 {
1213 return r;
1214 }
1215
Matt Spinlerf39420c2019-01-30 12:57:18 -06001216 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001217 }
1218 else if (typeCode == "u")
1219 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001220 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001221 if (r < 0)
1222 {
1223 return r;
1224 }
1225 }
1226 else if (typeCode == "i")
1227 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001228 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001229 if (r < 0)
1230 {
1231 return r;
1232 }
1233 }
1234 else if (typeCode == "x")
1235 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001236 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001237 if (r < 0)
1238 {
1239 return r;
1240 }
1241 }
1242 else if (typeCode == "t")
1243 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001244 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001245 if (r < 0)
1246 {
1247 return r;
1248 }
1249 }
1250 else if (typeCode == "n")
1251 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001252 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001253 if (r < 0)
1254 {
1255 return r;
1256 }
1257 }
1258 else if (typeCode == "q")
1259 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001260 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001261 if (r < 0)
1262 {
1263 return r;
1264 }
1265 }
1266 else if (typeCode == "y")
1267 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001268 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001269 if (r < 0)
1270 {
1271 return r;
1272 }
1273 }
1274 else if (typeCode == "d")
1275 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001276 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001277 if (r < 0)
1278 {
1279 return r;
1280 }
1281 }
1282 else if (typeCode == "h")
1283 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001284 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001285 if (r < 0)
1286 {
1287 return r;
1288 }
1289 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001290 else if (typeCode.starts_with("a"))
Matt Spinler6df8f992019-01-14 12:47:47 -06001291 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001292 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001293 if (r < 0)
1294 {
1295 return r;
1296 }
1297 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001298 else if (typeCode.starts_with("(") && typeCode.ends_with(")"))
Matt Spinler75c6c672019-01-14 13:01:46 -06001299 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001300 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001301 if (r < 0)
1302 {
1303 return r;
1304 }
1305 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001306 else if (typeCode.starts_with("v"))
Matt Spinler89c19702019-01-14 13:13:00 -06001307 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001308 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001309 if (r < 0)
1310 {
1311 return r;
1312 }
1313 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001314 else
1315 {
Ed Tanous62598e32023-07-17 17:06:25 -07001316 BMCWEB_LOG_ERROR("Invalid D-Bus signature type {}", typeCode);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001317 return -2;
1318 }
1319 }
1320
Matt Spinler16caaee2019-01-15 11:40:34 -06001321 return 0;
1322}
1323
Ed Tanousb5a76932020-09-29 16:16:58 -07001324inline void handleMethodResponse(
1325 const std::shared_ptr<InProgressActionData>& transaction,
Patrick Williams59d494e2022-07-22 19:26:55 -05001326 sdbusplus::message_t& m, const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001327{
Matt Spinler39a4e392019-01-15 11:53:13 -06001328 nlohmann::json data;
1329
1330 int r = convertDBusToJSON(returnType, m, data);
1331 if (r < 0)
1332 {
1333 transaction->outputFailed = true;
1334 return;
1335 }
1336
1337 if (data.is_null())
1338 {
1339 return;
1340 }
1341
1342 if (transaction->methodResponse.is_null())
1343 {
1344 transaction->methodResponse = std::move(data);
1345 return;
1346 }
1347
1348 // If they're both dictionaries or arrays, merge into one.
1349 // Otherwise, make the results an array with every result
1350 // an entry. Could also just fail in that case, but it
1351 // seems better to get the data back somehow.
Ed Tanous0bdda662023-08-03 17:27:34 -07001352 nlohmann::json::object_t* dataobj =
1353 data.get_ptr<nlohmann::json::object_t*>();
1354 if (transaction->methodResponse.is_object() && dataobj != nullptr)
Matt Spinler39a4e392019-01-15 11:53:13 -06001355 {
Ed Tanous0bdda662023-08-03 17:27:34 -07001356 for (auto& obj : *dataobj)
Matt Spinler39a4e392019-01-15 11:53:13 -06001357 {
1358 // Note: Will overwrite the data for a duplicate key
Ed Tanous0bdda662023-08-03 17:27:34 -07001359 transaction->methodResponse.emplace(obj.first,
1360 std::move(obj.second));
Matt Spinler39a4e392019-01-15 11:53:13 -06001361 }
1362 return;
1363 }
1364
Ed Tanous0bdda662023-08-03 17:27:34 -07001365 nlohmann::json::array_t* dataarr = data.get_ptr<nlohmann::json::array_t*>();
1366 if (transaction->methodResponse.is_array() && dataarr != nullptr)
Matt Spinler39a4e392019-01-15 11:53:13 -06001367 {
Ed Tanous0bdda662023-08-03 17:27:34 -07001368 for (auto& obj : *dataarr)
Matt Spinler39a4e392019-01-15 11:53:13 -06001369 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001370 transaction->methodResponse.emplace_back(std::move(obj));
Matt Spinler39a4e392019-01-15 11:53:13 -06001371 }
1372 return;
1373 }
1374
1375 if (!transaction->convertedToArray)
1376 {
1377 // They are different types. May as well turn them into an array
1378 nlohmann::json j = std::move(transaction->methodResponse);
1379 transaction->methodResponse = nlohmann::json::array();
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001380 transaction->methodResponse.emplace_back(std::move(j));
1381 transaction->methodResponse.emplace_back(std::move(data));
Matt Spinler39a4e392019-01-15 11:53:13 -06001382 transaction->convertedToArray = true;
1383 }
1384 else
1385 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001386 transaction->methodResponse.emplace_back(std::move(data));
Matt Spinler39a4e392019-01-15 11:53:13 -06001387 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001388}
1389
Ed Tanousb5a76932020-09-29 16:16:58 -07001390inline void findActionOnInterface(
1391 const std::shared_ptr<InProgressActionData>& transaction,
1392 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001393{
Ed Tanous62598e32023-07-17 17:06:25 -07001394 BMCWEB_LOG_DEBUG("findActionOnInterface for connection {}", connectionName);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001395 crow::connections::systemBus->async_method_call(
1396 [transaction, connectionName{std::string(connectionName)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001397 const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001398 const std::string& introspectXml) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001399 BMCWEB_LOG_DEBUG("got xml:\n {}", introspectXml);
1400 if (ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001401 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001402 BMCWEB_LOG_ERROR(
1403 "Introspect call failed with error: {} on process: {}",
1404 ec.message(), connectionName);
1405 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001406 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001407 tinyxml2::XMLDocument doc;
1408
1409 doc.Parse(introspectXml.data(), introspectXml.size());
1410 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1411 if (pRoot == nullptr)
1412 {
1413 BMCWEB_LOG_ERROR("XML document failed to parse {}",
1414 connectionName);
1415 return;
1416 }
1417 tinyxml2::XMLElement* interfaceNode =
1418 pRoot->FirstChildElement("interface");
1419 while (interfaceNode != nullptr)
1420 {
1421 const char* thisInterfaceName =
1422 interfaceNode->Attribute("name");
1423 if (thisInterfaceName != nullptr)
1424 {
1425 if (!transaction->interfaceName.empty() &&
1426 (transaction->interfaceName != thisInterfaceName))
1427 {
1428 interfaceNode =
1429 interfaceNode->NextSiblingElement("interface");
1430 continue;
1431 }
1432
1433 tinyxml2::XMLElement* methodNode =
1434 interfaceNode->FirstChildElement("method");
1435 while (methodNode != nullptr)
1436 {
1437 const char* thisMethodName =
1438 methodNode->Attribute("name");
1439 BMCWEB_LOG_DEBUG("Found method: {}", thisMethodName);
1440 if (thisMethodName != nullptr &&
1441 thisMethodName == transaction->methodName)
1442 {
1443 BMCWEB_LOG_DEBUG(
1444 "Found method named {} on interface {}",
1445 thisMethodName, thisInterfaceName);
1446 sdbusplus::message_t m =
1447 crow::connections::systemBus->new_method_call(
1448 connectionName.c_str(),
1449 transaction->path.c_str(),
1450 thisInterfaceName,
1451 transaction->methodName.c_str());
1452
1453 tinyxml2::XMLElement* argumentNode =
1454 methodNode->FirstChildElement("arg");
1455
1456 std::string returnType;
1457
1458 // Find the output type
1459 while (argumentNode != nullptr)
1460 {
1461 const char* argDirection =
1462 argumentNode->Attribute("direction");
1463 const char* argType =
1464 argumentNode->Attribute("type");
1465 if (argDirection != nullptr &&
1466 argType != nullptr &&
1467 std::string(argDirection) == "out")
1468 {
1469 returnType = argType;
1470 break;
1471 }
1472 argumentNode =
1473 argumentNode->NextSiblingElement("arg");
1474 }
1475
1476 auto argIt = transaction->arguments.begin();
1477
1478 argumentNode = methodNode->FirstChildElement("arg");
1479
1480 while (argumentNode != nullptr)
1481 {
1482 const char* argDirection =
1483 argumentNode->Attribute("direction");
1484 const char* argType =
1485 argumentNode->Attribute("type");
1486 if (argDirection != nullptr &&
1487 argType != nullptr &&
1488 std::string(argDirection) == "in")
1489 {
1490 if (argIt == transaction->arguments.end())
1491 {
1492 transaction->setErrorStatus(
1493 "Invalid method args");
1494 return;
1495 }
1496 if (convertJsonToDbus(m.get(),
1497 std::string(argType),
1498 *argIt) < 0)
1499 {
1500 transaction->setErrorStatus(
1501 "Invalid method arg type");
1502 return;
1503 }
1504
1505 argIt++;
1506 }
1507 argumentNode =
1508 argumentNode->NextSiblingElement("arg");
1509 }
1510
1511 crow::connections::systemBus->async_send(
1512 m, [transaction, returnType](
1513 const boost::system::error_code& ec2,
1514 sdbusplus::message_t& m2) {
1515 if (ec2)
1516 {
1517 transaction->methodFailed = true;
1518 const sd_bus_error* e = m2.get_error();
1519
1520 if (e != nullptr)
1521 {
1522 setErrorResponse(
1523 transaction->asyncResp->res,
1524 boost::beast::http::status::
1525 bad_request,
1526 e->name, e->message);
1527 }
1528 else
1529 {
1530 setErrorResponse(
1531 transaction->asyncResp->res,
1532 boost::beast::http::status::
1533 bad_request,
1534 "Method call failed",
1535 methodFailedMsg);
1536 }
1537 return;
1538 }
1539 transaction->methodPassed = true;
1540
1541 handleMethodResponse(transaction, m2,
1542 returnType);
1543 });
1544 break;
1545 }
1546 methodNode = methodNode->NextSiblingElement("method");
1547 }
1548 }
1549 interfaceNode = interfaceNode->NextSiblingElement("interface");
1550 }
1551 },
Ed Tanous1abe55e2018-09-05 08:30:59 -07001552 connectionName, transaction->path,
1553 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001554}
1555
zhanghch058d1b46d2021-04-01 11:18:24 +08001556inline void handleAction(const crow::Request& req,
1557 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001558 const std::string& objectPath,
1559 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001560{
Ed Tanous62598e32023-07-17 17:06:25 -07001561 BMCWEB_LOG_DEBUG("handleAction on path: {} and method {}", objectPath,
1562 methodName);
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001563 nlohmann::json requestDbusData;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001564
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001565 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
1566 if (ret == JsonParseResult::BadContentType)
1567 {
1568 setErrorResponse(asyncResp->res,
1569 boost::beast::http::status::unsupported_media_type,
1570 invalidContentType, unsupportedMediaMsg);
1571 return;
1572 }
1573 if (ret != JsonParseResult::Success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001574 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001575 setErrorResponse(asyncResp->res,
1576 boost::beast::http::status::bad_request, noJsonDesc,
1577 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001578 return;
1579 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001580 nlohmann::json::iterator data = requestDbusData.find("data");
1581 if (data == requestDbusData.end())
1582 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001583 setErrorResponse(asyncResp->res,
1584 boost::beast::http::status::bad_request, noJsonDesc,
1585 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001586 return;
1587 }
1588
1589 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001590 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001591 setErrorResponse(asyncResp->res,
1592 boost::beast::http::status::bad_request, noJsonDesc,
1593 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001594 return;
1595 }
Lei YU28dd5ca2023-03-17 13:17:05 +08001596 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001597
1598 transaction->path = objectPath;
1599 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001600 transaction->arguments = std::move(*data);
George Liu2b731192023-01-11 16:27:13 +08001601 dbus::utility::getDbusObject(
1602 objectPath, {},
Ed Tanous1abe55e2018-09-05 08:30:59 -07001603 [transaction](
George Liu2b731192023-01-11 16:27:13 +08001604 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001605 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1606 interfaceNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001607 if (ec || interfaceNames.empty())
1608 {
1609 BMCWEB_LOG_ERROR("Can't find object");
1610 setErrorResponse(transaction->asyncResp->res,
1611 boost::beast::http::status::not_found,
1612 notFoundDesc, notFoundMsg);
1613 return;
1614 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001615
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001616 BMCWEB_LOG_DEBUG("GetObject returned {} object(s)",
1617 interfaceNames.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001618
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001619 for (const std::pair<std::string, std::vector<std::string>>&
1620 object : interfaceNames)
1621 {
1622 findActionOnInterface(transaction, object.first);
1623 }
1624 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001625}
1626
zhanghch058d1b46d2021-04-01 11:18:24 +08001627inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1628 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001629{
Ed Tanous62598e32023-07-17 17:06:25 -07001630 BMCWEB_LOG_DEBUG("handleDelete on path: {}", objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06001631
George Liu2b731192023-01-11 16:27:13 +08001632 dbus::utility::getDbusObject(
1633 objectPath, {},
zhanghch058d1b46d2021-04-01 11:18:24 +08001634 [asyncResp, objectPath](
George Liu2b731192023-01-11 16:27:13 +08001635 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001636 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1637 interfaceNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001638 if (ec || interfaceNames.empty())
1639 {
1640 BMCWEB_LOG_ERROR("Can't find object");
1641 setErrorResponse(asyncResp->res,
1642 boost::beast::http::status::method_not_allowed,
1643 methodNotAllowedDesc, methodNotAllowedMsg);
1644 return;
1645 }
Matt Spinlerde818812018-12-11 16:39:20 -06001646
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001647 auto transaction =
1648 std::make_shared<InProgressActionData>(asyncResp);
1649 transaction->path = objectPath;
1650 transaction->methodName = "Delete";
1651 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
Matt Spinlerde818812018-12-11 16:39:20 -06001652
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001653 for (const std::pair<std::string, std::vector<std::string>>&
1654 object : interfaceNames)
1655 {
1656 findActionOnInterface(transaction, object.first);
1657 }
1658 });
Matt Spinlerde818812018-12-11 16:39:20 -06001659}
1660
zhanghch058d1b46d2021-04-01 11:18:24 +08001661inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1662 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001663{
George Liu7a1dbc42022-12-07 16:03:22 +08001664 dbus::utility::getSubTreePaths(
1665 objectPath, depth, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001666 [asyncResp](
George Liu7a1dbc42022-12-07 16:03:22 +08001667 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001668 const dbus::utility::MapperGetSubTreePathsResponse& objectPaths) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001669 if (ec)
1670 {
1671 setErrorResponse(asyncResp->res,
1672 boost::beast::http::status::not_found,
1673 notFoundDesc, notFoundMsg);
1674 }
1675 else
1676 {
1677 asyncResp->res.jsonValue["status"] = "ok";
1678 asyncResp->res.jsonValue["message"] = "200 OK";
1679 asyncResp->res.jsonValue["data"] = objectPaths;
1680 }
1681 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001682}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001683
zhanghch058d1b46d2021-04-01 11:18:24 +08001684inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1685 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001686{
Ed Tanous62598e32023-07-17 17:06:25 -07001687 BMCWEB_LOG_DEBUG("Doing enumerate on {}", objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07001688
Ed Tanous14766872022-03-15 10:44:42 -07001689 asyncResp->res.jsonValue["message"] = "200 OK";
1690 asyncResp->res.jsonValue["status"] = "ok";
1691 asyncResp->res.jsonValue["data"] = nlohmann::json::object();
Ed Tanous049a0512018-11-01 13:58:42 -07001692
George Liue99073f2022-12-09 11:06:16 +08001693 dbus::utility::getSubTree(
1694 objectPath, 0, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001695 [objectPath, asyncResp](
George Liue99073f2022-12-09 11:06:16 +08001696 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001697 const dbus::utility::MapperGetSubTreeResponse& objectNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001698 auto transaction = std::make_shared<InProgressEnumerateData>(
1699 objectPath, asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001700
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001701 transaction->subtree =
1702 std::make_shared<dbus::utility::MapperGetSubTreeResponse>(
1703 objectNames);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001704
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001705 if (ec)
1706 {
1707 BMCWEB_LOG_ERROR("GetSubTree failed on {}",
1708 transaction->objectPath);
1709 setErrorResponse(transaction->asyncResp->res,
1710 boost::beast::http::status::not_found,
1711 notFoundDesc, notFoundMsg);
1712 return;
1713 }
Ed Tanous64530012018-02-06 17:08:16 -08001714
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001715 // Add the data for the path passed in to the results
1716 // as if GetSubTree returned it, and continue on enumerating
1717 getObjectAndEnumerate(transaction);
1718 });
Ed Tanous64530012018-02-06 17:08:16 -08001719}
Ed Tanous911ac312017-08-15 09:37:42 -07001720
zhanghch058d1b46d2021-04-01 11:18:24 +08001721inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1722 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001723{
Ed Tanous62598e32023-07-17 17:06:25 -07001724 BMCWEB_LOG_DEBUG("handleGet: {} prop:{}", objectPath, destProperty);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001725 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001726 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001727
Ed Tanous1abe55e2018-09-05 08:30:59 -07001728 std::shared_ptr<std::string> path =
1729 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001730
George Liu2b731192023-01-11 16:27:13 +08001731 dbus::utility::getDbusObject(
1732 *path, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001733 [asyncResp, path,
George Liu2b731192023-01-11 16:27:13 +08001734 propertyName](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001735 const dbus::utility::MapperGetObject& objectNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001736 if (ec || objectNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001737 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001738 setErrorResponse(asyncResp->res,
1739 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001740 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001741 return;
1742 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001743 std::shared_ptr<nlohmann::json> response =
1744 std::make_shared<nlohmann::json>(nlohmann::json::object());
1745 // The mapper should never give us an empty interface names
1746 // list, but check anyway
1747 for (const std::pair<std::string, std::vector<std::string>>&
1748 connection : objectNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001749 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001750 const std::vector<std::string>& interfaceNames =
1751 connection.second;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001752
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001753 if (interfaceNames.empty())
1754 {
1755 setErrorResponse(asyncResp->res,
1756 boost::beast::http::status::not_found,
1757 notFoundDesc, notFoundMsg);
1758 return;
1759 }
1760
1761 for (const std::string& interface : interfaceNames)
1762 {
1763 sdbusplus::message_t m =
1764 crow::connections::systemBus->new_method_call(
1765 connection.first.c_str(), path->c_str(),
1766 "org.freedesktop.DBus.Properties", "GetAll");
1767 m.append(interface);
1768 crow::connections::systemBus->async_send(
1769 m, [asyncResp, response,
1770 propertyName](const boost::system::error_code& ec2,
1771 sdbusplus::message_t& msg) {
1772 if (ec2)
1773 {
1774 BMCWEB_LOG_ERROR("Bad dbus request error: {}",
1775 ec2);
1776 }
1777 else
1778 {
1779 nlohmann::json properties;
1780 int r =
1781 convertDBusToJSON("a{sv}", msg, properties);
1782 if (r < 0)
Patrick Williams5a39f772023-10-20 11:20:21 -05001783 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001784 BMCWEB_LOG_ERROR(
1785 "convertDBusToJSON failed");
Patrick Williams5a39f772023-10-20 11:20:21 -05001786 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001787 else
Patrick Williams5a39f772023-10-20 11:20:21 -05001788 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001789 nlohmann::json::object_t* obj =
1790 properties.get_ptr<
1791 nlohmann::json::object_t*>();
1792 if (obj == nullptr)
1793 {
1794 return;
1795 }
1796 for (auto& prop : *obj)
1797 {
1798 // if property name is empty, or
1799 // matches our search query, add it
1800 // to the response json
1801
1802 if (propertyName->empty())
1803 {
1804 (*response)[prop.first] =
1805 std::move(prop.second);
1806 }
1807 else if (prop.first == *propertyName)
1808 {
1809 *response = std::move(prop.second);
1810 }
1811 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001812 }
1813 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001814 if (response.use_count() == 1)
1815 {
1816 if (!propertyName->empty() && response->empty())
1817 {
1818 setErrorResponse(
1819 asyncResp->res,
1820 boost::beast::http::status::not_found,
1821 propNotFoundDesc, notFoundMsg);
1822 }
1823 else
1824 {
1825 asyncResp->res.jsonValue["status"] = "ok";
1826 asyncResp->res.jsonValue["message"] =
1827 "200 OK";
1828 asyncResp->res.jsonValue["data"] =
1829 *response;
1830 }
1831 }
1832 });
1833 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001834 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001835 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001836}
1837
Ed Tanous1abe55e2018-09-05 08:30:59 -07001838struct AsyncPutRequest
1839{
Ed Tanous4e23a442022-06-06 09:57:26 -07001840 explicit AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
zhanghch058d1b46d2021-04-01 11:18:24 +08001841 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001842 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001843 ~AsyncPutRequest()
1844 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001845 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001846 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001847 setErrorResponse(asyncResp->res,
1848 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001849 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001850 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001851 }
1852
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001853 AsyncPutRequest(const AsyncPutRequest&) = delete;
1854 AsyncPutRequest(AsyncPutRequest&&) = delete;
1855 AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1856 AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1857
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001858 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001859 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001860 setErrorResponse(asyncResp->res,
1861 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001862 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001863 }
1864
zhanghch058d1b46d2021-04-01 11:18:24 +08001865 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001866 std::string objectPath;
1867 std::string propertyName;
1868 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001869};
1870
zhanghch058d1b46d2021-04-01 11:18:24 +08001871inline void handlePut(const crow::Request& req,
1872 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001873 const std::string& objectPath,
1874 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001875{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001876 if (destProperty.empty())
1877 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001878 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001879 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001880 return;
1881 }
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001882 nlohmann::json requestDbusData;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001883
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001884 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
1885 if (ret == JsonParseResult::BadContentType)
1886 {
1887 setErrorResponse(asyncResp->res,
1888 boost::beast::http::status::unsupported_media_type,
1889 invalidContentType, unsupportedMediaMsg);
1890 return;
1891 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001892
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001893 if (ret != JsonParseResult::Success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001894 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001895 setErrorResponse(asyncResp->res,
1896 boost::beast::http::status::bad_request, noJsonDesc,
1897 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001898 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001899 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001900
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001901 auto propertyIt = requestDbusData.find("data");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001902 if (propertyIt == requestDbusData.end())
1903 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001904 setErrorResponse(asyncResp->res,
1905 boost::beast::http::status::bad_request, noJsonDesc,
1906 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001907 return;
1908 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001909 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001910 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001911 transaction->objectPath = objectPath;
1912 transaction->propertyName = destProperty;
1913 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001914
George Liu2b731192023-01-11 16:27:13 +08001915 dbus::utility::getDbusObject(
1916 transaction->objectPath, {},
1917 [transaction](const boost::system::error_code& ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001918 const dbus::utility::MapperGetObject& objectNames) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001919 if (!ec2 && objectNames.empty())
1920 {
1921 setErrorResponse(transaction->asyncResp->res,
1922 boost::beast::http::status::not_found,
1923 propNotFoundDesc, notFoundMsg);
1924 return;
1925 }
Ed Tanous911ac312017-08-15 09:37:42 -07001926
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001927 for (const std::pair<std::string, std::vector<std::string>>&
1928 connection : objectNames)
1929 {
1930 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001931
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001932 crow::connections::systemBus->async_method_call(
1933 [connectionName{std::string(connectionName)},
1934 transaction](const boost::system::error_code& ec3,
1935 const std::string& introspectXml) {
1936 if (ec3)
Ed Tanousb0b61522024-08-06 10:20:49 -07001937 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001938 BMCWEB_LOG_ERROR(
1939 "Introspect call failed with error: {} on process: {}",
1940 ec3.message(), connectionName);
1941 transaction->setErrorStatus("Unexpected Error");
1942 return;
Ed Tanousb0b61522024-08-06 10:20:49 -07001943 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001944 tinyxml2::XMLDocument doc;
1945
1946 doc.Parse(introspectXml.c_str());
1947 tinyxml2::XMLNode* pRoot =
1948 doc.FirstChildElement("node");
1949 if (pRoot == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001950 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001951 BMCWEB_LOG_ERROR("XML document failed to parse: {}",
1952 introspectXml);
1953 transaction->setErrorStatus("Unexpected Error");
1954 return;
1955 }
1956 tinyxml2::XMLElement* ifaceNode =
1957 pRoot->FirstChildElement("interface");
1958 while (ifaceNode != nullptr)
1959 {
1960 const char* interfaceName =
1961 ifaceNode->Attribute("name");
1962 BMCWEB_LOG_DEBUG("found interface {}",
1963 interfaceName);
1964 tinyxml2::XMLElement* propNode =
1965 ifaceNode->FirstChildElement("property");
1966 while (propNode != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001967 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001968 const char* propertyName =
1969 propNode->Attribute("name");
1970 if (propertyName == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001971 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001972 BMCWEB_LOG_DEBUG(
1973 "Couldn't find name property");
1974 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001975 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001976 BMCWEB_LOG_DEBUG("Found property {}",
1977 propertyName);
1978 if (propertyName == transaction->propertyName)
Ed Tanous002d39b2022-05-31 08:59:27 -07001979 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001980 const char* argType =
1981 propNode->Attribute("type");
1982 if (argType != nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07001983 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001984 sdbusplus::message_t m =
1985 crow::connections::systemBus
1986 ->new_method_call(
1987 connectionName.c_str(),
1988 transaction->objectPath
1989 .c_str(),
1990 "org.freedesktop.DBus."
1991 "Properties",
1992 "Set");
1993 m.append(interfaceName,
1994 transaction->propertyName);
1995 int r = sd_bus_message_open_container(
1996 m.get(), SD_BUS_TYPE_VARIANT,
1997 argType);
1998 if (r < 0)
1999 {
2000 transaction->setErrorStatus(
2001 "Unexpected Error");
2002 return;
2003 }
2004 r = convertJsonToDbus(
2005 m.get(), argType,
2006 transaction->propertyValue);
2007 if (r < 0)
2008 {
2009 if (r == -ERANGE)
2010 {
2011 transaction->setErrorStatus(
2012 "Provided property value "
2013 "is out of range for the "
2014 "property type");
2015 }
2016 else
2017 {
2018 transaction->setErrorStatus(
2019 "Invalid arg type");
2020 }
2021 return;
2022 }
2023 r = sd_bus_message_close_container(
2024 m.get());
2025 if (r < 0)
2026 {
2027 transaction->setErrorStatus(
2028 "Unexpected Error");
2029 return;
2030 }
2031 crow::connections::systemBus
2032 ->async_send(
2033 m,
2034 [transaction](
2035 const boost::system::
2036 error_code& ec,
2037 sdbusplus::message_t& m2) {
2038 BMCWEB_LOG_DEBUG("sent");
2039 if (ec)
2040 {
2041 const sd_bus_error* e =
2042 m2.get_error();
2043 setErrorResponse(
2044 transaction
2045 ->asyncResp
2046 ->res,
2047 boost::beast::http::
2048 status::
2049 forbidden,
2050 (e) != nullptr
2051 ? e->name
2052 : ec.category()
2053 .name(),
2054 (e) != nullptr
2055 ? e->message
2056 : ec.message());
2057 }
2058 else
2059 {
2060 transaction->asyncResp
2061 ->res.jsonValue
2062 ["status"] =
2063 "ok";
2064 transaction->asyncResp
2065 ->res.jsonValue
2066 ["message"] =
2067 "200 OK";
2068 transaction->asyncResp
2069 ->res
2070 .jsonValue["data"] =
2071 nullptr;
2072 }
2073 });
Ed Tanous002d39b2022-05-31 08:59:27 -07002074 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002075 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002076 propNode =
2077 propNode->NextSiblingElement("property");
Ed Tanous1abe55e2018-09-05 08:30:59 -07002078 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002079 ifaceNode =
2080 ifaceNode->NextSiblingElement("interface");
Ed Tanous1abe55e2018-09-05 08:30:59 -07002081 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002082 },
2083 connectionName, transaction->objectPath,
2084 "org.freedesktop.DBus.Introspectable", "Introspect");
2085 }
2086 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07002087}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002088
zhanghch058d1b46d2021-04-01 11:18:24 +08002089inline void handleDBusUrl(const crow::Request& req,
2090 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002091 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002092{
Ed Tanous049a0512018-11-01 13:58:42 -07002093 // If accessing a single attribute, fill in and update objectPath,
2094 // otherwise leave destProperty blank
Ed Tanouse05aec52022-01-25 10:28:56 -08002095 std::string destProperty;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002096 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002097 size_t attrPosition = objectPath.find(attrSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002098 if (attrPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002099 {
2100 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2101 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002102 objectPath.resize(attrPosition);
Ed Tanous049a0512018-11-01 13:58:42 -07002103 }
2104
Ed Tanousb41187f2019-10-24 16:30:02 -07002105 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002106 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002107 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002108 size_t actionPosition = objectPath.find(actionSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002109 if (actionPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002110 {
2111 std::string postProperty =
2112 objectPath.substr((actionPosition + strlen(actionSeperator)),
2113 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002114 objectPath.resize(actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002115 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002116 return;
2117 }
2118 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002119 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002120 {
Ed Tanous11ba3972022-07-11 09:50:41 -07002121 if (objectPath.ends_with("/enumerate"))
Ed Tanous049a0512018-11-01 13:58:42 -07002122 {
2123 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2124 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002125 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002126 }
Ed Tanous11ba3972022-07-11 09:50:41 -07002127 else if (objectPath.ends_with("/list"))
Ed Tanous049a0512018-11-01 13:58:42 -07002128 {
2129 objectPath.erase(objectPath.end() - sizeof("list"),
2130 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002131 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002132 }
2133 else
2134 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002135 // Trim any trailing "/" at the end
Ed Tanous11ba3972022-07-11 09:50:41 -07002136 if (objectPath.ends_with("/"))
Ed Tanousf839dfe2018-11-12 11:11:15 -08002137 {
2138 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002139 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002140 }
2141 else
2142 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002143 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002144 }
Ed Tanous049a0512018-11-01 13:58:42 -07002145 }
2146 return;
2147 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002148 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002149 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002150 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002151 return;
2152 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002153 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002154 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002155 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002156 return;
2157 }
Ed Tanous049a0512018-11-01 13:58:42 -07002158
zhanghch058d1b46d2021-04-01 11:18:24 +08002159 setErrorResponse(asyncResp->res,
2160 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002161 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002162}
2163
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002164inline void handleBusSystemPost(
2165 const crow::Request& req,
2166 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2167 const std::string& processName, const std::string& requestedPath)
Ed Tanous1656b292022-05-04 11:33:42 -07002168{
2169 std::vector<std::string> strs;
Ed Tanous50ebd4a2023-01-19 19:03:17 -08002170
2171 bmcweb::split(strs, requestedPath, '/');
Ed Tanous1656b292022-05-04 11:33:42 -07002172 std::string objectPath;
2173 std::string interfaceName;
2174 std::string methodName;
2175 auto it = strs.begin();
2176 if (it == strs.end())
2177 {
2178 objectPath = "/";
2179 }
2180 while (it != strs.end())
2181 {
2182 // Check if segment contains ".". If it does, it must be an
2183 // interface
2184 if (it->find(".") != std::string::npos)
2185 {
2186 break;
2187 // This check is necessary as the trailing slash gets
2188 // parsed as part of our <path> specifier above, which
2189 // causes the normal trailing backslash redirector to
2190 // fail.
2191 }
2192 if (!it->empty())
2193 {
2194 objectPath += "/" + *it;
2195 }
2196 it++;
2197 }
2198 if (it != strs.end())
2199 {
2200 interfaceName = *it;
2201 it++;
2202
2203 // after interface, we might have a method name
2204 if (it != strs.end())
2205 {
2206 methodName = *it;
2207 it++;
2208 }
2209 }
2210 if (it != strs.end())
2211 {
2212 // if there is more levels past the method name, something
2213 // went wrong, return not found
2214 asyncResp->res.result(boost::beast::http::status::not_found);
2215 return;
2216 }
2217 if (interfaceName.empty())
2218 {
2219 crow::connections::systemBus->async_method_call(
2220 [asyncResp, processName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002221 objectPath](const boost::system::error_code& ec,
Ed Tanous1656b292022-05-04 11:33:42 -07002222 const std::string& introspectXml) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002223 if (ec)
Ed Tanous1656b292022-05-04 11:33:42 -07002224 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002225 BMCWEB_LOG_ERROR(
2226 "Introspect call failed with error: {} on process: {} path: {}",
2227 ec.message(), processName, objectPath);
2228 return;
2229 }
2230 tinyxml2::XMLDocument doc;
2231
2232 doc.Parse(introspectXml.c_str());
2233 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2234 if (pRoot == nullptr)
2235 {
2236 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
2237 processName, objectPath);
2238 asyncResp->res.jsonValue["status"] = "XML parse error";
2239 asyncResp->res.result(
2240 boost::beast::http::status::internal_server_error);
2241 return;
Ed Tanous1656b292022-05-04 11:33:42 -07002242 }
2243
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002244 BMCWEB_LOG_DEBUG("{}", introspectXml);
2245 asyncResp->res.jsonValue["status"] = "ok";
2246 asyncResp->res.jsonValue["bus_name"] = processName;
2247 asyncResp->res.jsonValue["object_path"] = objectPath;
2248
2249 nlohmann::json& interfacesArray =
2250 asyncResp->res.jsonValue["interfaces"];
2251 interfacesArray = nlohmann::json::array();
2252 tinyxml2::XMLElement* interface =
2253 pRoot->FirstChildElement("interface");
2254
2255 while (interface != nullptr)
2256 {
2257 const char* ifaceName = interface->Attribute("name");
2258 if (ifaceName != nullptr)
2259 {
2260 nlohmann::json::object_t interfaceObj;
2261 interfaceObj["name"] = ifaceName;
2262 interfacesArray.emplace_back(std::move(interfaceObj));
2263 }
2264
2265 interface = interface->NextSiblingElement("interface");
2266 }
2267 },
Ed Tanous1656b292022-05-04 11:33:42 -07002268 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2269 "Introspect");
2270 }
2271 else if (methodName.empty())
2272 {
2273 crow::connections::systemBus->async_method_call(
2274 [asyncResp, processName, objectPath,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002275 interfaceName](const boost::system::error_code& ec,
Ed Tanous1656b292022-05-04 11:33:42 -07002276 const std::string& introspectXml) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002277 if (ec)
Ed Tanous1656b292022-05-04 11:33:42 -07002278 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002279 BMCWEB_LOG_ERROR(
2280 "Introspect call failed with error: {} on process: {} path: {}",
2281 ec.message(), processName, objectPath);
2282 return;
2283 }
2284 tinyxml2::XMLDocument doc;
2285
2286 doc.Parse(introspectXml.data(), introspectXml.size());
2287 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2288 if (pRoot == nullptr)
2289 {
2290 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
2291 processName, objectPath);
2292 asyncResp->res.result(
2293 boost::beast::http::status::internal_server_error);
2294 return;
Ed Tanous1656b292022-05-04 11:33:42 -07002295 }
Ed Tanous14766872022-03-15 10:44:42 -07002296
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002297 asyncResp->res.jsonValue["status"] = "ok";
2298 asyncResp->res.jsonValue["bus_name"] = processName;
2299 asyncResp->res.jsonValue["interface"] = interfaceName;
2300 asyncResp->res.jsonValue["object_path"] = objectPath;
Ed Tanous1656b292022-05-04 11:33:42 -07002301
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002302 nlohmann::json& methodsArray =
2303 asyncResp->res.jsonValue["methods"];
2304 methodsArray = nlohmann::json::array();
2305
2306 nlohmann::json& signalsArray =
2307 asyncResp->res.jsonValue["signals"];
2308 signalsArray = nlohmann::json::array();
2309
2310 nlohmann::json& propertiesObj =
2311 asyncResp->res.jsonValue["properties"];
2312 propertiesObj = nlohmann::json::object();
2313
2314 // if we know we're the only call, build the
2315 // json directly
2316 tinyxml2::XMLElement* interface =
2317 pRoot->FirstChildElement("interface");
2318 while (interface != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002319 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002320 const char* ifaceName = interface->Attribute("name");
2321
2322 if (ifaceName != nullptr && ifaceName == interfaceName)
Ed Tanous1656b292022-05-04 11:33:42 -07002323 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002324 break;
Ed Tanous002d39b2022-05-31 08:59:27 -07002325 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002326
2327 interface = interface->NextSiblingElement("interface");
2328 }
2329 if (interface == nullptr)
2330 {
2331 // if we got to the end of the list and
2332 // never found a match, throw 404
2333 asyncResp->res.result(
2334 boost::beast::http::status::not_found);
2335 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07002336 }
2337
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002338 tinyxml2::XMLElement* methods =
2339 interface->FirstChildElement("method");
2340 while (methods != nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07002341 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002342 nlohmann::json argsArray = nlohmann::json::array();
2343 tinyxml2::XMLElement* arg =
2344 methods->FirstChildElement("arg");
2345 while (arg != nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07002346 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002347 nlohmann::json thisArg;
2348 for (const char* fieldName : std::array<const char*, 3>{
2349 "name", "direction", "type"})
2350 {
2351 const char* fieldValue = arg->Attribute(fieldName);
2352 if (fieldValue != nullptr)
2353 {
2354 thisArg[fieldName] = fieldValue;
2355 }
2356 }
2357 argsArray.emplace_back(std::move(thisArg));
2358 arg = arg->NextSiblingElement("arg");
Ed Tanous002d39b2022-05-31 08:59:27 -07002359 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002360
2361 const char* name = methods->Attribute("name");
2362 if (name != nullptr)
2363 {
2364 std::string uri;
2365 uri.reserve(14 + processName.size() +
2366 objectPath.size() + interfaceName.size() +
2367 strlen(name));
2368 uri += "/bus/system/";
2369 uri += processName;
2370 uri += objectPath;
2371 uri += "/";
2372 uri += interfaceName;
2373 uri += "/";
2374 uri += name;
2375
2376 nlohmann::json::object_t object;
2377 object["name"] = name;
2378 object["uri"] = std::move(uri);
2379 object["args"] = argsArray;
2380
2381 methodsArray.emplace_back(std::move(object));
2382 }
2383 methods = methods->NextSiblingElement("method");
Ed Tanous002d39b2022-05-31 08:59:27 -07002384 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002385 tinyxml2::XMLElement* signals =
2386 interface->FirstChildElement("signal");
2387 while (signals != nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07002388 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002389 nlohmann::json argsArray = nlohmann::json::array();
2390
2391 tinyxml2::XMLElement* arg =
2392 signals->FirstChildElement("arg");
2393 while (arg != nullptr)
2394 {
2395 const char* name = arg->Attribute("name");
2396 const char* type = arg->Attribute("type");
2397 if (name != nullptr && type != nullptr)
2398 {
2399 nlohmann::json::object_t params;
2400 params["name"] = name;
2401 params["type"] = type;
2402 argsArray.push_back(std::move(params));
2403 }
2404 arg = arg->NextSiblingElement("arg");
2405 }
2406 const char* name = signals->Attribute("name");
2407 if (name != nullptr)
2408 {
2409 nlohmann::json::object_t object;
2410 object["name"] = name;
2411 object["args"] = argsArray;
2412 signalsArray.emplace_back(std::move(object));
2413 }
2414
2415 signals = signals->NextSiblingElement("signal");
Ed Tanous002d39b2022-05-31 08:59:27 -07002416 }
2417
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002418 tinyxml2::XMLElement* property =
2419 interface->FirstChildElement("property");
2420 while (property != nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07002421 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002422 const char* name = property->Attribute("name");
2423 const char* type = property->Attribute("type");
2424 if (type != nullptr && name != nullptr)
2425 {
2426 sdbusplus::message_t m =
2427 crow::connections::systemBus->new_method_call(
2428 processName.c_str(), objectPath.c_str(),
2429 "org.freedesktop."
2430 "DBus."
2431 "Properties",
2432 "Get");
2433 m.append(interfaceName, name);
2434 nlohmann::json& propertyItem = propertiesObj[name];
2435 crow::connections::systemBus->async_send(
2436 m, [&propertyItem,
2437 asyncResp](const boost::system::error_code& ec2,
2438 sdbusplus::message_t& msg) {
2439 if (ec2)
2440 {
2441 return;
2442 }
Ed Tanous1656b292022-05-04 11:33:42 -07002443
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002444 int r =
2445 convertDBusToJSON("v", msg, propertyItem);
2446 if (r < 0)
2447 {
2448 BMCWEB_LOG_ERROR(
2449 "Couldn't convert vector to json");
2450 }
2451 });
2452 }
2453 property = property->NextSiblingElement("property");
Ed Tanous1656b292022-05-04 11:33:42 -07002454 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002455 },
Ed Tanous1656b292022-05-04 11:33:42 -07002456 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2457 "Introspect");
2458 }
2459 else
2460 {
2461 if (req.method() != boost::beast::http::verb::post)
2462 {
2463 asyncResp->res.result(boost::beast::http::status::not_found);
2464 return;
2465 }
2466
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002467 nlohmann::json requestDbusData;
2468 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
2469 if (ret == JsonParseResult::BadContentType)
Ed Tanous1656b292022-05-04 11:33:42 -07002470 {
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002471 setErrorResponse(asyncResp->res,
2472 boost::beast::http::status::unsupported_media_type,
2473 invalidContentType, unsupportedMediaMsg);
Ed Tanous1656b292022-05-04 11:33:42 -07002474 return;
2475 }
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002476 if (ret != JsonParseResult::Success)
2477 {
2478 setErrorResponse(asyncResp->res,
2479 boost::beast::http::status::bad_request,
2480 noJsonDesc, badReqMsg);
2481 return;
2482 }
2483
Ed Tanous1656b292022-05-04 11:33:42 -07002484 if (!requestDbusData.is_array())
2485 {
2486 asyncResp->res.result(boost::beast::http::status::bad_request);
2487 return;
2488 }
Lei YU28dd5ca2023-03-17 13:17:05 +08002489 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous1656b292022-05-04 11:33:42 -07002490
2491 transaction->path = objectPath;
2492 transaction->methodName = methodName;
2493 transaction->arguments = std::move(requestDbusData);
2494
2495 findActionOnInterface(transaction, processName);
2496 }
2497}
2498
Ed Tanous23a21a12020-07-25 04:45:05 +00002499inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002500{
2501 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002502 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002503 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002504 [](const crow::Request&,
2505 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002506 nlohmann::json::array_t buses;
2507 nlohmann::json& bus = buses.emplace_back();
2508 bus["name"] = "system";
2509 asyncResp->res.jsonValue["busses"] = std::move(buses);
2510 asyncResp->res.jsonValue["status"] = "ok";
2511 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002512
2513 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002514 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002515 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002516 [](const crow::Request&,
2517 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002518 auto myCallback = [asyncResp](
2519 const boost::system::error_code& ec,
zhanghch058d1b46d2021-04-01 11:18:24 +08002520 std::vector<std::string>& names) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002521 if (ec)
2522 {
2523 BMCWEB_LOG_ERROR("Dbus call failed with code {}", ec);
2524 asyncResp->res.result(
2525 boost::beast::http::status::internal_server_error);
2526 }
2527 else
2528 {
2529 std::ranges::sort(names);
2530 asyncResp->res.jsonValue["status"] = "ok";
2531 auto& objectsSub = asyncResp->res.jsonValue["objects"];
2532 for (const auto& name : names)
2533 {
2534 nlohmann::json::object_t object;
2535 object["name"] = name;
2536 objectsSub.emplace_back(std::move(object));
2537 }
2538 }
2539 };
2540 crow::connections::systemBus->async_method_call(
2541 std::move(myCallback), "org.freedesktop.DBus", "/",
2542 "org.freedesktop.DBus", "ListNames");
2543 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002544
2545 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002546 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002547 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002548 [](const crow::Request&,
2549 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002550 handleList(asyncResp, "/");
2551 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002552
2553 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002554 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002555 .methods(boost::beast::http::verb::get)(
2556 [](const crow::Request& req,
2557 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002558 const std::string& path) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002559 std::string objectPath = "/xyz/" + path;
2560 handleDBusUrl(req, asyncResp, objectPath);
2561 });
zhanghch058d1b46d2021-04-01 11:18:24 +08002562
2563 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002564 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002565 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2566 boost::beast::http::verb::delete_)(
2567 [](const crow::Request& req,
2568 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2569 const std::string& path) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002570 std::string objectPath = "/xyz/" + path;
2571 handleDBusUrl(req, asyncResp, objectPath);
2572 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002573
Ed Tanous049a0512018-11-01 13:58:42 -07002574 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002575 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002576 .methods(boost::beast::http::verb::get)(
2577 [](const crow::Request& req,
2578 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2579 const std::string& path) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002580 std::string objectPath = "/org/" + path;
2581 handleDBusUrl(req, asyncResp, objectPath);
2582 });
Tanousf00032d2018-11-05 01:18:10 -03002583
2584 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002585 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002586 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2587 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002588 [](const crow::Request& req,
2589 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002590 const std::string& path) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002591 std::string objectPath = "/org/" + path;
2592 handleDBusUrl(req, asyncResp, objectPath);
2593 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002594
Ed Tanous1abe55e2018-09-05 08:30:59 -07002595 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002596 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002597 .methods(boost::beast::http::verb::get)(
2598 [](const crow::Request&,
2599 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2600 const std::string& dumpId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002601 if (!validateFilename(dumpId))
2602 {
2603 asyncResp->res.result(
2604 boost::beast::http::status::bad_request);
2605 return;
2606 }
2607 std::filesystem::path loc(
2608 "/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002609
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002610 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002611
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002612 if (!std::filesystem::exists(loc) ||
2613 !std::filesystem::is_directory(loc))
2614 {
2615 BMCWEB_LOG_ERROR("{}Not found", loc.string());
2616 asyncResp->res.result(
2617 boost::beast::http::status::not_found);
2618 return;
2619 }
2620 std::filesystem::directory_iterator files(loc);
zhanghch058d1b46d2021-04-01 11:18:24 +08002621
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002622 for (const auto& file : files)
2623 {
Myung Baed51c61b2024-09-13 10:35:34 -05002624 if (asyncResp->res.openFile(file) !=
2625 crow::OpenCode::Success)
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002626 {
2627 continue;
2628 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002629
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002630 asyncResp->res.addHeader(
2631 boost::beast::http::field::content_type,
2632 "application/octet-stream");
zhanghch058d1b46d2021-04-01 11:18:24 +08002633
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002634 // Assuming only one dump file will be present in the dump
2635 // id directory
2636 std::string dumpFileName = file.path().filename().string();
zhanghch058d1b46d2021-04-01 11:18:24 +08002637
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002638 // Filename should be in alphanumeric, dot and underscore
2639 // Its based on phosphor-debug-collector application
2640 // dumpfile format
2641 static std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
2642 if (!std::regex_match(dumpFileName, dumpFileRegex))
2643 {
2644 BMCWEB_LOG_ERROR("Invalid dump filename {}",
2645 dumpFileName);
2646 asyncResp->res.result(
2647 boost::beast::http::status::not_found);
2648 return;
2649 }
2650 std::string contentDispositionParam =
2651 "attachment; filename=\"" + dumpFileName + "\"";
2652
2653 asyncResp->res.addHeader(
2654 boost::beast::http::field::content_disposition,
2655 contentDispositionParam);
2656
2657 return;
2658 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002659 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002660 return;
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002661 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002662
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002663 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002664 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002665
2666 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002667 [](const crow::Request&,
2668 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002669 const std::string& connection) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002670 introspectObjects(connection, "/", asyncResp);
2671 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002672
2673 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002674 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous1656b292022-05-04 11:33:42 -07002675 .methods(boost::beast::http::verb::get,
2676 boost::beast::http::verb::post)(handleBusSystemPost);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002677}
2678} // namespace openbmc_mapper
2679} // namespace crow