blob: dd1dac37d9f9c678967f8d546cb4587a6c68086f [file] [log] [blame]
James Feist5b4aa862018-08-16 14:07:01 -07001// Copyright (c) 2018 Intel Corporation
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
Ed Tanousb9b2e0b2018-09-13 13:47:50 -070014
James Feist5b4aa862018-08-16 14:07:01 -070015#pragma once
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080016#include "app.hpp"
17#include "async_resp.hpp"
18#include "dbus_singleton.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +080019#include "dbus_utility.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000020#include "http_request.hpp"
21#include "http_response.hpp"
22#include "logging.hpp"
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010023#include "parsing.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000024#include "routing.hpp"
Ed Tanous50ebd4a2023-01-19 19:03:17 -080025#include "str_utility.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000026
27#include <systemd/sd-bus-protocol.h>
28#include <systemd/sd-bus.h>
Ed Tanous911ac312017-08-15 09:37:42 -070029#include <tinyxml2.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -070030
Nan Zhoud5c80ad2022-07-11 01:16:31 +000031#include <boost/beast/http/status.hpp>
32#include <boost/beast/http/verb.hpp>
33#include <boost/container/flat_map.hpp>
34#include <boost/container/vector.hpp>
35#include <boost/iterator/iterator_facade.hpp>
George Liue99073f2022-12-09 11:06:16 +080036#include <boost/system/error_code.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000037#include <nlohmann/json.hpp>
38#include <sdbusplus/asio/connection.hpp>
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +020039#include <sdbusplus/asio/property.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000040#include <sdbusplus/exception.hpp>
41#include <sdbusplus/message.hpp>
42#include <sdbusplus/message/native_types.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050043
Nan Zhoud5c80ad2022-07-11 01:16:31 +000044#include <algorithm>
45#include <array>
46#include <cerrno>
47#include <cstdint>
48#include <cstring>
James Feist4418c7f2019-04-15 11:09:15 -070049#include <filesystem>
Ed Tanousd4bb9bb2018-05-16 13:36:42 -070050#include <fstream>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000051#include <functional>
52#include <initializer_list>
53#include <iterator>
54#include <limits>
55#include <map>
56#include <memory>
Ed Tanous3544d2a2023-08-06 18:12:20 -070057#include <ranges>
Ramesh Iyyard9207042019-07-05 08:04:42 -050058#include <regex>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000059#include <string>
60#include <string_view>
61#include <type_traits>
Ed Tanousb5a76932020-09-29 16:16:58 -070062#include <utility>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000063#include <variant>
64#include <vector>
65
66// IWYU pragma: no_include <boost/algorithm/string/detail/classification.hpp>
67// IWYU pragma: no_include <boost/system/detail/error_code.hpp>
68// IWYU pragma: no_include <boost/system/detail/error_category.hpp>
69// IWYU pragma: no_include <errno.h>
70// IWYU pragma: no_include <string.h>
71// IWYU pragma: no_include <ext/alloc_traits.h>
72// IWYU pragma: no_include <exception>
73// IWYU pragma: no_include <boost/type_index/type_index_facade.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -070074
Ed Tanous1abe55e2018-09-05 08:30:59 -070075namespace crow
76{
77namespace openbmc_mapper
78{
Ed Tanous23a21a12020-07-25 04:45:05 +000079const constexpr char* notFoundMsg = "404 Not Found";
80const constexpr char* badReqMsg = "400 Bad Request";
81const constexpr char* methodNotAllowedMsg = "405 Method Not Allowed";
82const constexpr char* forbiddenMsg = "403 Forbidden";
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010083const constexpr char* unsupportedMediaMsg = "415 Unsupported Media Type";
Ed Tanous23a21a12020-07-25 04:45:05 +000084const constexpr char* methodFailedMsg = "500 Method Call Failed";
85const constexpr char* methodOutputFailedMsg = "500 Method Output Error";
86const constexpr char* notFoundDesc =
Matt Spinler2ae60092018-12-06 10:35:36 -060087 "org.freedesktop.DBus.Error.FileNotFound: path or object not found";
Ed Tanous23a21a12020-07-25 04:45:05 +000088const constexpr char* propNotFoundDesc =
89 "The specified property cannot be found";
90const constexpr char* noJsonDesc = "No JSON object could be decoded";
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010091const constexpr char* invalidContentType =
92 "Content-type header is missing or invalid";
Ed Tanous23a21a12020-07-25 04:45:05 +000093const constexpr char* methodNotFoundDesc =
94 "The specified method cannot be found";
95const constexpr char* methodNotAllowedDesc = "Method not allowed";
96const constexpr char* forbiddenPropDesc =
97 "The specified property cannot be created";
98const constexpr char* forbiddenResDesc =
99 "The specified resource cannot be created";
Matt Spinler2ae60092018-12-06 10:35:36 -0600100
Josh Lehan482c45a2022-03-29 17:10:44 -0700101inline bool validateFilename(const std::string& filename)
102{
Ed Tanous4b242742023-05-11 09:51:51 -0700103 static std::regex validFilename(R"(^[\w\- ]+(\.?[\w\- ]*)$)");
Josh Lehan482c45a2022-03-29 17:10:44 -0700104
105 return std::regex_match(filename, validFilename);
106}
107
Ed Tanous23a21a12020-07-25 04:45:05 +0000108inline void setErrorResponse(crow::Response& res,
109 boost::beast::http::status result,
Ed Tanous26ccae32023-02-16 10:28:44 -0800110 const std::string& desc, std::string_view msg)
Matt Spinler2ae60092018-12-06 10:35:36 -0600111{
112 res.result(result);
Ed Tanous14766872022-03-15 10:44:42 -0700113 res.jsonValue["data"]["description"] = desc;
114 res.jsonValue["message"] = msg;
115 res.jsonValue["status"] = "error";
Matt Spinler2ae60092018-12-06 10:35:36 -0600116}
117
Ed Tanousb5a76932020-09-29 16:16:58 -0700118inline void
119 introspectObjects(const std::string& processName,
120 const std::string& objectPath,
121 const std::shared_ptr<bmcweb::AsyncResp>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700122{
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700123 if (transaction->res.jsonValue.is_null())
124 {
Ed Tanous14766872022-03-15 10:44:42 -0700125 transaction->res.jsonValue["status"] = "ok";
126 transaction->res.jsonValue["bus_name"] = processName;
127 transaction->res.jsonValue["objects"] = nlohmann::json::array();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700128 }
129
Ed Tanous1abe55e2018-09-05 08:30:59 -0700130 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700131 [transaction, processName{std::string(processName)},
132 objectPath{std::string(objectPath)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800133 const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +0000134 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700135 if (ec)
136 {
Ed Tanous62598e32023-07-17 17:06:25 -0700137 BMCWEB_LOG_ERROR(
138 "Introspect call failed with error: {} on process: {} path: {}",
139 ec.message(), processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -0700140 return;
141 }
142 nlohmann::json::object_t object;
143 object["path"] = objectPath;
Ed Tanous14766872022-03-15 10:44:42 -0700144
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500145 transaction->res.jsonValue["objects"].emplace_back(std::move(object));
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700146
Ed Tanous002d39b2022-05-31 08:59:27 -0700147 tinyxml2::XMLDocument doc;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700148
Ed Tanous002d39b2022-05-31 08:59:27 -0700149 doc.Parse(introspectXml.c_str());
150 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
151 if (pRoot == nullptr)
152 {
Ed Tanous62598e32023-07-17 17:06:25 -0700153 BMCWEB_LOG_ERROR("XML document failed to parse {} {}", processName,
154 objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -0700155 }
156 else
157 {
158 tinyxml2::XMLElement* node = pRoot->FirstChildElement("node");
159 while (node != nullptr)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700160 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700161 const char* childPath = node->Attribute("name");
162 if (childPath != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700163 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700164 std::string newpath;
165 if (objectPath != "/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700166 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700167 newpath += objectPath;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700168 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700169 newpath += std::string("/") + childPath;
170 // introspect the subobjects as well
171 introspectObjects(processName, newpath, transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700172 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700173
174 node = node->NextSiblingElement("node");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700175 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700176 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500177 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700178 processName, objectPath, "org.freedesktop.DBus.Introspectable",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700179 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -0700180}
Ed Tanous64530012018-02-06 17:08:16 -0800181
Ed Tanous23a21a12020-07-25 04:45:05 +0000182inline void getPropertiesForEnumerate(
183 const std::string& objectPath, const std::string& service,
Ed Tanousb5a76932020-09-29 16:16:58 -0700184 const std::string& interface,
185 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600186{
Ed Tanous62598e32023-07-17 17:06:25 -0700187 BMCWEB_LOG_DEBUG("getPropertiesForEnumerate {} {} {}", objectPath, service,
188 interface);
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600189
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +0200190 sdbusplus::asio::getAllProperties(
191 *crow::connections::systemBus, service, objectPath, interface,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800192 [asyncResp, objectPath, service,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800193 interface](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800194 const dbus::utility::DBusPropertiesMap& propertiesList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700195 if (ec)
196 {
Ed Tanous62598e32023-07-17 17:06:25 -0700197 BMCWEB_LOG_ERROR(
198 "GetAll on path {} iface {} service {} failed with code {}",
199 objectPath, interface, service, ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700200 return;
201 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600202
Ed Tanous002d39b2022-05-31 08:59:27 -0700203 nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
204 nlohmann::json& objectJson = dataJson[objectPath];
205 if (objectJson.is_null())
206 {
207 objectJson = nlohmann::json::object();
208 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600209
Ed Tanous002d39b2022-05-31 08:59:27 -0700210 for (const auto& [name, value] : propertiesList)
211 {
212 nlohmann::json& propertyJson = objectJson[name];
213 std::visit(
214 [&propertyJson](auto&& val) {
215 if constexpr (std::is_same_v<std::decay_t<decltype(val)>,
216 sdbusplus::message::unix_fd>)
217 {
218 propertyJson = val.fd;
219 }
220 else
221 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700222 propertyJson = val;
223 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500224 },
Ed Tanous002d39b2022-05-31 08:59:27 -0700225 value);
226 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500227 });
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600228}
229
230// Find any results that weren't picked up by ObjectManagers, to be
231// called after all ObjectManagers are searched for and called.
Ed Tanous23a21a12020-07-25 04:45:05 +0000232inline void findRemainingObjectsForEnumerate(
Ed Tanousb5a76932020-09-29 16:16:58 -0700233 const std::string& objectPath,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800234 const std::shared_ptr<dbus::utility::MapperGetSubTreeResponse>& subtree,
Ed Tanousb5a76932020-09-29 16:16:58 -0700235 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600236{
Ed Tanous62598e32023-07-17 17:06:25 -0700237 BMCWEB_LOG_DEBUG("findRemainingObjectsForEnumerate");
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500238 const nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600239
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500240 for (const auto& [path, interface_map] : *subtree)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600241 {
242 if (path == objectPath)
243 {
244 // An enumerate does not return the target path's properties
245 continue;
246 }
247 if (dataJson.find(path) == dataJson.end())
248 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500249 for (const auto& [service, interfaces] : interface_map)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600250 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500251 for (const auto& interface : interfaces)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600252 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700253 if (!interface.starts_with("org.freedesktop.DBus"))
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600254 {
255 getPropertiesForEnumerate(path, service, interface,
256 asyncResp);
257 }
258 }
259 }
260 }
261 }
262}
263
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600264struct InProgressEnumerateData
265{
zhanghch058d1b46d2021-04-01 11:18:24 +0800266 InProgressEnumerateData(
267 const std::string& objectPathIn,
268 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
Ed Tanous23a21a12020-07-25 04:45:05 +0000269 objectPath(objectPathIn),
zhanghch058d1b46d2021-04-01 11:18:24 +0800270 asyncResp(asyncRespIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500271 {}
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600272
273 ~InProgressEnumerateData()
274 {
Ed Tanous24b2fe82022-01-06 12:45:54 -0800275 try
276 {
277 findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
278 }
279 catch (...)
280 {
Ed Tanous62598e32023-07-17 17:06:25 -0700281 BMCWEB_LOG_CRITICAL(
282 "findRemainingObjectsForEnumerate threw exception");
Ed Tanous24b2fe82022-01-06 12:45:54 -0800283 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600284 }
285
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800286 InProgressEnumerateData(const InProgressEnumerateData&) = delete;
287 InProgressEnumerateData(InProgressEnumerateData&&) = delete;
288 InProgressEnumerateData& operator=(const InProgressEnumerateData&) = delete;
289 InProgressEnumerateData& operator=(InProgressEnumerateData&&) = delete;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600290 const std::string objectPath;
Ed Tanousb9d36b42022-02-26 21:42:46 -0800291 std::shared_ptr<dbus::utility::MapperGetSubTreeResponse> subtree;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600292 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
293};
294
Ed Tanous23a21a12020-07-25 04:45:05 +0000295inline void getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000296 const std::string& objectName, const std::string& objectManagerPath,
297 const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700298 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700299{
Ed Tanous62598e32023-07-17 17:06:25 -0700300 BMCWEB_LOG_DEBUG(
301 "getManagedObjectsForEnumerate {} object_manager_path {} connection_name {}",
302 objectName, objectManagerPath, connectionName);
George Liu5eb468d2023-06-20 17:03:24 +0800303 sdbusplus::message::object_path path(objectManagerPath);
304 dbus::utility::getManagedObjects(
305 connectionName, path,
Ed Tanous81ce6092020-12-17 16:54:55 +0000306 [transaction, objectName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800307 connectionName](const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +0000308 const dbus::utility::ManagedObjectType& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700309 if (ec)
310 {
Ed Tanous62598e32023-07-17 17:06:25 -0700311 BMCWEB_LOG_ERROR(
312 "GetManagedObjects on path {} on connection {} failed with code {}",
313 objectName, connectionName, ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700314 return;
315 }
Ed Tanous64530012018-02-06 17:08:16 -0800316
Ed Tanous002d39b2022-05-31 08:59:27 -0700317 nlohmann::json& dataJson =
318 transaction->asyncResp->res.jsonValue["data"];
Ed Tanous049a0512018-11-01 13:58:42 -0700319
Ed Tanous002d39b2022-05-31 08:59:27 -0700320 for (const auto& objectPath : objects)
321 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700322 if (objectPath.first.str.starts_with(objectName))
Ed Tanous049a0512018-11-01 13:58:42 -0700323 {
Ed Tanous62598e32023-07-17 17:06:25 -0700324 BMCWEB_LOG_DEBUG("Reading object {}", objectPath.first.str);
Ed Tanous002d39b2022-05-31 08:59:27 -0700325 nlohmann::json& objectJson = dataJson[objectPath.first.str];
326 if (objectJson.is_null())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700327 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700328 objectJson = nlohmann::json::object();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700329 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500330 for (const auto& interface : objectPath.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700331 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700332 for (const auto& property : interface.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700333 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700334 nlohmann::json& propertyJson =
335 objectJson[property.first];
336 std::visit(
337 [&propertyJson](auto&& val) {
338 if constexpr (std::is_same_v<
339 std::decay_t<decltype(val)>,
340 sdbusplus::message::unix_fd>)
341 {
342 propertyJson = val.fd;
343 }
344 else
345 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700346 propertyJson = val;
347 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500348 },
Ed Tanous002d39b2022-05-31 08:59:27 -0700349 property.second);
Ed Tanous049a0512018-11-01 13:58:42 -0700350 }
351 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700352 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700353 for (const auto& interface : objectPath.second)
354 {
355 if (interface.first == "org.freedesktop.DBus.ObjectManager")
356 {
357 getManagedObjectsForEnumerate(objectPath.first.str,
358 objectPath.first.str,
359 connectionName, transaction);
360 }
361 }
362 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500363 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700364}
365
Ed Tanous23a21a12020-07-25 04:45:05 +0000366inline void findObjectManagerPathForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000367 const std::string& objectName, const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700368 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700369{
Ed Tanous62598e32023-07-17 17:06:25 -0700370 BMCWEB_LOG_DEBUG("Finding objectmanager for path {} on connection:{}",
371 objectName, connectionName);
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700372 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000373 [transaction, objectName, connectionName](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800374 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800375 const dbus::utility::MapperGetAncestorsResponse& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700376 if (ec)
377 {
Ed Tanous62598e32023-07-17 17:06:25 -0700378 BMCWEB_LOG_ERROR("GetAncestors on path {} failed with code {}",
379 objectName, ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700380 return;
381 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700382
Ed Tanous002d39b2022-05-31 08:59:27 -0700383 for (const auto& pathGroup : objects)
384 {
385 for (const auto& connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700386 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700387 if (connectionGroup.first == connectionName)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700388 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700389 // Found the object manager path for this resource.
390 getManagedObjectsForEnumerate(objectName, pathGroup.first,
391 connectionName, transaction);
392 return;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700393 }
394 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700395 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500396 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700397 "xyz.openbmc_project.ObjectMapper",
398 "/xyz/openbmc_project/object_mapper",
Ed Tanous81ce6092020-12-17 16:54:55 +0000399 "xyz.openbmc_project.ObjectMapper", "GetAncestors", objectName,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500400 std::array<const char*, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700401}
Ed Tanous64530012018-02-06 17:08:16 -0800402
Ed Tanous7c091622019-05-23 11:42:36 -0700403// Uses GetObject to add the object info about the target /enumerate path to
404// the results of GetSubTree, as GetSubTree will not return info for the
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600405// target path, and then continues on enumerating the rest of the tree.
Ed Tanousb5a76932020-09-29 16:16:58 -0700406inline void getObjectAndEnumerate(
407 const std::shared_ptr<InProgressEnumerateData>& transaction)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600408{
George Liu2b731192023-01-11 16:27:13 +0800409 dbus::utility::getDbusObject(
410 transaction->objectPath, {},
411 [transaction](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800412 const dbus::utility::MapperGetObject& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700413 if (ec)
414 {
Ed Tanous62598e32023-07-17 17:06:25 -0700415 BMCWEB_LOG_ERROR("GetObject for path {} failed with code {}",
416 transaction->objectPath, ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700417 return;
418 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600419
Ed Tanous62598e32023-07-17 17:06:25 -0700420 BMCWEB_LOG_DEBUG("GetObject for {} has {} entries",
421 transaction->objectPath, objects.size());
Ed Tanous002d39b2022-05-31 08:59:27 -0700422 if (!objects.empty())
423 {
424 transaction->subtree->emplace_back(transaction->objectPath,
425 objects);
426 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600427
Ed Tanous002d39b2022-05-31 08:59:27 -0700428 // Map indicating connection name, and the path where the object
429 // manager exists
Ed Tanous18f8f602023-07-18 10:07:23 -0700430 boost::container::flat_map<
431 std::string, std::string, std::less<>,
432 std::vector<std::pair<std::string, std::string>>>
433 connections;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600434
Ed Tanous002d39b2022-05-31 08:59:27 -0700435 for (const auto& object : *(transaction->subtree))
436 {
437 for (const auto& connection : object.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600438 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700439 for (const auto& interface : connection.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600440 {
Ed Tanous62598e32023-07-17 17:06:25 -0700441 BMCWEB_LOG_DEBUG("{} has interface {}", connection.first,
442 interface);
Ed Tanous002d39b2022-05-31 08:59:27 -0700443 if (interface == "org.freedesktop.DBus.ObjectManager")
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600444 {
Ed Tanous62598e32023-07-17 17:06:25 -0700445 BMCWEB_LOG_DEBUG("found object manager path {}",
446 object.first);
Ed Tanousf8fe53e2022-06-30 15:55:45 -0700447 connections[connection.first] = object.first;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600448 }
449 }
450 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700451 }
Ed Tanous62598e32023-07-17 17:06:25 -0700452 BMCWEB_LOG_DEBUG("Got {} connections", connections.size());
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600453
Ed Tanous002d39b2022-05-31 08:59:27 -0700454 for (const auto& connection : connections)
455 {
456 // If we already know where the object manager is, we don't
457 // need to search for it, we can call directly in to
458 // getManagedObjects
459 if (!connection.second.empty())
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600460 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700461 getManagedObjectsForEnumerate(transaction->objectPath,
462 connection.second,
463 connection.first, transaction);
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600464 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700465 else
466 {
467 // otherwise we need to find the object manager path
468 // before we can continue
469 findObjectManagerPathForEnumerate(
470 transaction->objectPath, connection.first, transaction);
471 }
472 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500473 });
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600474}
Ed Tanous64530012018-02-06 17:08:16 -0800475
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700476// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700477struct InProgressActionData
478{
Lei YU28dd5ca2023-03-17 13:17:05 +0800479 explicit InProgressActionData(
480 const std::shared_ptr<bmcweb::AsyncResp>& res) :
481 asyncResp(res)
Ed Tanous23a21a12020-07-25 04:45:05 +0000482 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700483 ~InProgressActionData()
484 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600485 // Methods could have been called across different owners
486 // and interfaces, where some calls failed and some passed.
487 //
488 // The rules for this are:
489 // * if no method was called - error
490 // * if a method failed and none passed - error
491 // (converse: if at least one method passed - OK)
492 // * for the method output:
493 // * if output processing didn't fail, return the data
494
495 // Only deal with method returns if nothing failed earlier
Lei YU28dd5ca2023-03-17 13:17:05 +0800496 if (asyncResp->res.result() == boost::beast::http::status::ok)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700497 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600498 if (!methodPassed)
499 {
Matt Spinler06b1b632019-06-18 16:09:25 -0500500 if (!methodFailed)
Matt Spinler16caaee2019-01-15 11:40:34 -0600501 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800502 setErrorResponse(asyncResp->res,
503 boost::beast::http::status::not_found,
Matt Spinler16caaee2019-01-15 11:40:34 -0600504 methodNotFoundDesc, notFoundMsg);
505 }
506 }
507 else
508 {
509 if (outputFailed)
510 {
511 setErrorResponse(
Lei YU28dd5ca2023-03-17 13:17:05 +0800512 asyncResp->res,
513 boost::beast::http::status::internal_server_error,
Matt Spinler16caaee2019-01-15 11:40:34 -0600514 "Method output failure", methodOutputFailedMsg);
515 }
516 else
517 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800518 asyncResp->res.jsonValue["status"] = "ok";
519 asyncResp->res.jsonValue["message"] = "200 OK";
520 asyncResp->res.jsonValue["data"] = methodResponse;
Matt Spinler16caaee2019-01-15 11:40:34 -0600521 }
522 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700523 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700524 }
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800525 InProgressActionData(const InProgressActionData&) = delete;
526 InProgressActionData(InProgressActionData&&) = delete;
527 InProgressActionData& operator=(const InProgressActionData&) = delete;
528 InProgressActionData& operator=(InProgressActionData&&) = delete;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700529
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500530 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700531 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800532 setErrorResponse(asyncResp->res,
533 boost::beast::http::status::bad_request, desc,
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600534 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700535 }
Lei YU28dd5ca2023-03-17 13:17:05 +0800536 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700537 std::string path;
538 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600539 std::string interfaceName;
Matt Spinler16caaee2019-01-15 11:40:34 -0600540 bool methodPassed = false;
541 bool methodFailed = false;
542 bool outputFailed = false;
Matt Spinler39a4e392019-01-15 11:53:13 -0600543 bool convertedToArray = false;
Matt Spinler16caaee2019-01-15 11:40:34 -0600544 nlohmann::json methodResponse;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700545 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700546};
547
Ed Tanous23a21a12020-07-25 04:45:05 +0000548inline std::vector<std::string> dbusArgSplit(const std::string& string)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700549{
550 std::vector<std::string> ret;
551 if (string.empty())
552 {
553 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700554 }
Ed Tanous0f0353b2019-10-24 11:37:51 -0700555 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700556 int containerDepth = 0;
557
558 for (std::string::const_iterator character = string.begin();
559 character != string.end(); character++)
560 {
561 ret.back() += *character;
562 switch (*character)
563 {
564 case ('a'):
565 break;
566 case ('('):
567 case ('{'):
568 containerDepth++;
569 break;
570 case ('}'):
571 case (')'):
572 containerDepth--;
573 if (containerDepth == 0)
574 {
575 if (character + 1 != string.end())
576 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700577 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700578 }
579 }
580 break;
581 default:
582 if (containerDepth == 0)
583 {
584 if (character + 1 != string.end())
585 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700586 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700587 }
588 }
589 break;
590 }
591 }
Matt Spinler4ae611d2019-01-11 15:37:06 -0600592
593 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700594}
595
Ed Tanous81ce6092020-12-17 16:54:55 +0000596inline int convertJsonToDbus(sd_bus_message* m, const std::string& argType,
597 const nlohmann::json& inputJson)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700598{
599 int r = 0;
Ed Tanous62598e32023-07-17 17:06:25 -0700600 BMCWEB_LOG_DEBUG(
601 "Converting {} to type: {}",
602 inputJson.dump(2, ' ', true, nlohmann::json::error_handler_t::replace),
603 argType);
Ed Tanous81ce6092020-12-17 16:54:55 +0000604 const std::vector<std::string> argTypes = dbusArgSplit(argType);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700605
Ed Tanous1abe55e2018-09-05 08:30:59 -0700606 // Assume a single object for now.
Ed Tanous81ce6092020-12-17 16:54:55 +0000607 const nlohmann::json* j = &inputJson;
608 nlohmann::json::const_iterator jIt = inputJson.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700609
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500610 for (const std::string& argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700611 {
612 // If we are decoding multiple objects, grab the pointer to the
613 // iterator, and increment it for the next loop
614 if (argTypes.size() > 1)
615 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000616 if (jIt == inputJson.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700617 {
618 return -2;
619 }
620 j = &*jIt;
621 jIt++;
622 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500623 const int64_t* intValue = j->get_ptr<const int64_t*>();
624 const std::string* stringValue = j->get_ptr<const std::string*>();
625 const double* doubleValue = j->get_ptr<const double*>();
626 const bool* b = j->get_ptr<const bool*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700627 int64_t v = 0;
628 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700629
Ed Tanous1abe55e2018-09-05 08:30:59 -0700630 // Do some basic type conversions that make sense. uint can be
631 // converted to int. int and uint can be converted to double
Ed Tanous66664f22019-10-11 13:05:49 -0700632 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700633 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500634 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700635 if (uintValue != nullptr)
636 {
637 v = static_cast<int64_t>(*uintValue);
638 intValue = &v;
639 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700640 }
Ed Tanous66664f22019-10-11 13:05:49 -0700641 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700642 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500643 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700644 if (uintValue != nullptr)
645 {
646 d = static_cast<double>(*uintValue);
647 doubleValue = &d;
648 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700649 }
Ed Tanous66664f22019-10-11 13:05:49 -0700650 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700651 {
Ed Tanous66664f22019-10-11 13:05:49 -0700652 if (intValue != nullptr)
653 {
654 d = static_cast<double>(*intValue);
655 doubleValue = &d;
656 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700657 }
658
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700659 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700660 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700661 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700662 {
663 return -1;
664 }
Ed Tanous271584a2019-07-09 16:24:22 -0700665 r = sd_bus_message_append_basic(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500666 m, argCode[0], static_cast<const void*>(stringValue->data()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700667 if (r < 0)
668 {
669 return r;
670 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700671 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700672 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700673 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700674 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700675 {
676 return -1;
677 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500678 if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
679 (*intValue > std::numeric_limits<int32_t>::max()))
680 {
681 return -ERANGE;
682 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700683 int32_t i = static_cast<int32_t>(*intValue);
684 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700685 if (r < 0)
686 {
687 return r;
688 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700689 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700690 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700691 {
692 // lots of ways bool could be represented here. Try them all
Ed Tanouse662eae2022-01-25 10:39:19 -0800693 int boolInt = 0;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700694 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700695 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500696 if (*intValue == 1)
697 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800698 boolInt = 1;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500699 }
700 else if (*intValue == 0)
701 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800702 boolInt = 0;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500703 }
704 else
705 {
706 return -ERANGE;
707 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700708 }
709 else if (b != nullptr)
710 {
Matt Spinlera2f02632019-01-18 10:15:35 -0600711 boolInt = *b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700712 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700713 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700714 {
Ed Tanous18f8f602023-07-18 10:07:23 -0700715 if (!stringValue->empty())
716 {
717 if (stringValue->front() == 't' ||
718 stringValue->front() == 'T')
719 {
720 boolInt = 1;
721 }
722 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700723 }
724 else
725 {
726 return -1;
727 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700728 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700729 if (r < 0)
730 {
731 return r;
732 }
733 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700734 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700735 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700736 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700737 {
738 return -1;
739 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500740 if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
741 (*intValue > std::numeric_limits<int16_t>::max()))
742 {
743 return -ERANGE;
744 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700745 int16_t n = static_cast<int16_t>(*intValue);
746 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700747 if (r < 0)
748 {
749 return r;
750 }
751 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700752 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700753 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700754 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700755 {
756 return -1;
757 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700758 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700759 if (r < 0)
760 {
761 return r;
762 }
763 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700764 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700765 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500766 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700767 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700768 {
769 return -1;
770 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000771 if (*uintValue > std::numeric_limits<uint8_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500772 {
773 return -ERANGE;
774 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700775 uint8_t y = static_cast<uint8_t>(*uintValue);
776 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700777 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700778 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700779 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500780 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700781 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700782 {
783 return -1;
784 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000785 if (*uintValue > std::numeric_limits<uint16_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500786 {
787 return -ERANGE;
788 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700789 uint16_t q = static_cast<uint16_t>(*uintValue);
790 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700791 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700792 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700793 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500794 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700795 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700796 {
797 return -1;
798 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000799 if (*uintValue > std::numeric_limits<uint32_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500800 {
801 return -ERANGE;
802 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700803 uint32_t u = static_cast<uint32_t>(*uintValue);
804 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700805 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700806 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700807 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500808 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700809 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700810 {
811 return -1;
812 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700813 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700814 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700815 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700816 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500817 if (doubleValue == nullptr)
818 {
819 return -1;
820 }
821 if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
822 (*doubleValue > std::numeric_limits<double>::max()))
823 {
824 return -ERANGE;
825 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700826 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700827 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700828 else if (argCode.starts_with("a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700829 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700830 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700831 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700832 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700833 if (r < 0)
834 {
835 return r;
836 }
837
Ed Tanous0dfeda62019-10-24 11:21:38 -0700838 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700839 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700840 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700841 if (r < 0)
842 {
843 return r;
844 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700845 }
846 sd_bus_message_close_container(m);
847 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700848 else if (argCode.starts_with("v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700849 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700850 std::string containedType = argCode.substr(1);
Ed Tanous62598e32023-07-17 17:06:25 -0700851 BMCWEB_LOG_DEBUG("variant type: {} appending variant of type: {}",
852 argCode, containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700853 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700854 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700855 if (r < 0)
856 {
857 return r;
858 }
859
Ed Tanous81ce6092020-12-17 16:54:55 +0000860 r = convertJsonToDbus(m, containedType, inputJson);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700861 if (r < 0)
862 {
863 return r;
864 }
865
866 r = sd_bus_message_close_container(m);
867 if (r < 0)
868 {
869 return r;
870 }
871 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700872 else if (argCode.starts_with("(") && argCode.ends_with(")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700873 {
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300874 std::string containedType = argCode.substr(1, argCode.size() - 2);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700875 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700876 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800877 if (r < 0)
878 {
879 return r;
880 }
881
Ed Tanous1abe55e2018-09-05 08:30:59 -0700882 nlohmann::json::const_iterator it = j->begin();
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300883 for (const std::string& argCode2 : dbusArgSplit(containedType))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700884 {
885 if (it == j->end())
886 {
887 return -1;
888 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000889 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700890 if (r < 0)
891 {
892 return r;
893 }
894 it++;
895 }
896 r = sd_bus_message_close_container(m);
897 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700898 else if (argCode.starts_with("{") && argCode.ends_with("}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700899 {
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300900 std::string containedType = argCode.substr(1, argCode.size() - 2);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700901 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700902 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800903 if (r < 0)
904 {
905 return r;
906 }
907
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700908 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700909 if (codes.size() != 2)
910 {
911 return -1;
912 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700913 const std::string& keyType = codes[0];
914 const std::string& valueType = codes[1];
Ed Tanous3174e4d2020-10-07 11:41:22 -0700915 for (const auto& it : j->items())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700916 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700917 r = convertJsonToDbus(m, keyType, it.key());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700918 if (r < 0)
919 {
920 return r;
921 }
922
Ed Tanous2c70f802020-09-28 14:29:23 -0700923 r = convertJsonToDbus(m, valueType, it.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700924 if (r < 0)
925 {
926 return r;
927 }
928 }
929 r = sd_bus_message_close_container(m);
930 }
931 else
932 {
933 return -2;
934 }
935 if (r < 0)
936 {
937 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700938 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700939
Ed Tanous1abe55e2018-09-05 08:30:59 -0700940 if (argTypes.size() > 1)
941 {
942 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700943 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700944 }
Matt Spinler127ea542019-01-14 11:04:28 -0600945
946 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700947}
948
Matt Spinlerd22a7132019-01-14 12:14:30 -0600949template <typename T>
Patrick Williams59d494e2022-07-22 19:26:55 -0500950int readMessageItem(const std::string& typeCode, sdbusplus::message_t& m,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500951 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600952{
953 T value;
Ed Tanousf79ce6a2024-03-20 12:27:06 -0700954 // When T == char*, this warning fires. Unclear how to resolve
955 // Given that sd-bus takes a void pointer to a char*, and that's
956 // Not something we can fix.
957 // NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600958 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
959 if (r < 0)
960 {
Ed Tanous62598e32023-07-17 17:06:25 -0700961 BMCWEB_LOG_ERROR("sd_bus_message_read_basic on type {} failed!",
962 typeCode);
Matt Spinlerd22a7132019-01-14 12:14:30 -0600963 return r;
964 }
965
966 data = value;
967 return 0;
968}
969
Patrick Williams59d494e2022-07-22 19:26:55 -0500970int convertDBusToJSON(const std::string& returnType, sdbusplus::message_t& m,
971 nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600972
Ed Tanous23a21a12020-07-25 04:45:05 +0000973inline int readDictEntryFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -0500974 sdbusplus::message_t& m,
Ed Tanous23a21a12020-07-25 04:45:05 +0000975 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600976{
977 std::vector<std::string> types = dbusArgSplit(typeCode);
978 if (types.size() != 2)
979 {
Ed Tanous62598e32023-07-17 17:06:25 -0700980 BMCWEB_LOG_ERROR("wrong number contained types in dictionary: {}",
981 types.size());
Matt Spinler6df8f992019-01-14 12:47:47 -0600982 return -1;
983 }
984
985 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
986 typeCode.c_str());
987 if (r < 0)
988 {
Ed Tanous62598e32023-07-17 17:06:25 -0700989 BMCWEB_LOG_ERROR("sd_bus_message_enter_container with rc {}", r);
Matt Spinler6df8f992019-01-14 12:47:47 -0600990 return r;
991 }
992
993 nlohmann::json key;
994 r = convertDBusToJSON(types[0], m, key);
995 if (r < 0)
996 {
997 return r;
998 }
999
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001000 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -06001001 if (keyPtr == nullptr)
1002 {
1003 // json doesn't support non-string keys. If we hit this condition,
1004 // convert the result to a string so we can proceed
Ed Tanous71f52d92021-02-19 08:51:17 -08001005 key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001006 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -07001007 // in theory this can't fail now, but lets be paranoid about it
1008 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -06001009 if (keyPtr == nullptr)
1010 {
1011 return -1;
1012 }
1013 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001014 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -06001015
1016 r = convertDBusToJSON(types[1], m, value);
1017 if (r < 0)
1018 {
1019 return r;
1020 }
1021
1022 r = sd_bus_message_exit_container(m.get());
1023 if (r < 0)
1024 {
Ed Tanous62598e32023-07-17 17:06:25 -07001025 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001026 return r;
1027 }
1028
1029 return 0;
1030}
1031
Ed Tanous23a21a12020-07-25 04:45:05 +00001032inline int readArrayFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001033 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -06001034{
1035 if (typeCode.size() < 2)
1036 {
Ed Tanous62598e32023-07-17 17:06:25 -07001037 BMCWEB_LOG_ERROR("Type code {} too small for an array", typeCode);
Matt Spinler6df8f992019-01-14 12:47:47 -06001038 return -1;
1039 }
1040
1041 std::string containedType = typeCode.substr(1);
1042
1043 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
1044 containedType.c_str());
1045 if (r < 0)
1046 {
Ed Tanous62598e32023-07-17 17:06:25 -07001047 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler6df8f992019-01-14 12:47:47 -06001048 return r;
1049 }
1050
Ed Tanous11ba3972022-07-11 09:50:41 -07001051 bool dict = containedType.starts_with("{") && containedType.ends_with("}");
Matt Spinler6df8f992019-01-14 12:47:47 -06001052
1053 if (dict)
1054 {
1055 // Remove the { }
1056 containedType = containedType.substr(1, containedType.size() - 2);
1057 data = nlohmann::json::object();
1058 }
1059 else
1060 {
1061 data = nlohmann::json::array();
1062 }
1063
1064 while (true)
1065 {
Ed Tanouse662eae2022-01-25 10:39:19 -08001066 r = sd_bus_message_at_end(m.get(), 0);
Matt Spinler6df8f992019-01-14 12:47:47 -06001067 if (r < 0)
1068 {
Ed Tanous62598e32023-07-17 17:06:25 -07001069 BMCWEB_LOG_ERROR("sd_bus_message_at_end failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001070 return r;
1071 }
1072
1073 if (r > 0)
1074 {
1075 break;
1076 }
1077
1078 // Dictionaries are only ever seen in an array
1079 if (dict)
1080 {
1081 r = readDictEntryFromMessage(containedType, m, data);
1082 if (r < 0)
1083 {
1084 return r;
1085 }
1086 }
1087 else
1088 {
1089 data.push_back(nlohmann::json());
1090
1091 r = convertDBusToJSON(containedType, m, data.back());
1092 if (r < 0)
1093 {
1094 return r;
1095 }
1096 }
1097 }
1098
1099 r = sd_bus_message_exit_container(m.get());
1100 if (r < 0)
1101 {
Ed Tanous62598e32023-07-17 17:06:25 -07001102 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001103 return r;
1104 }
1105
1106 return 0;
1107}
1108
Ed Tanous23a21a12020-07-25 04:45:05 +00001109inline int readStructFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001110 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001111{
1112 if (typeCode.size() < 3)
1113 {
Ed Tanous62598e32023-07-17 17:06:25 -07001114 BMCWEB_LOG_ERROR("Type code {} too small for a struct", typeCode);
Matt Spinler75c6c672019-01-14 13:01:46 -06001115 return -1;
1116 }
1117
1118 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1119 std::vector<std::string> types = dbusArgSplit(containedTypes);
1120
1121 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1122 containedTypes.c_str());
1123 if (r < 0)
1124 {
Ed Tanous62598e32023-07-17 17:06:25 -07001125 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler75c6c672019-01-14 13:01:46 -06001126 return r;
1127 }
1128
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001129 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001130 {
1131 data.push_back(nlohmann::json());
1132 r = convertDBusToJSON(type, m, data.back());
1133 if (r < 0)
1134 {
1135 return r;
1136 }
1137 }
1138
1139 r = sd_bus_message_exit_container(m.get());
1140 if (r < 0)
1141 {
Ed Tanous62598e32023-07-17 17:06:25 -07001142 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler75c6c672019-01-14 13:01:46 -06001143 return r;
1144 }
1145 return 0;
1146}
1147
Patrick Williams59d494e2022-07-22 19:26:55 -05001148inline int readVariantFromMessage(sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001149{
Ed Tanous543f4402022-01-06 13:12:53 -08001150 const char* containerType = nullptr;
Ed Tanous99131cd2019-10-24 11:12:47 -07001151 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001152 if (r < 0)
1153 {
Ed Tanous62598e32023-07-17 17:06:25 -07001154 BMCWEB_LOG_ERROR("sd_bus_message_peek_type failed");
Matt Spinler89c19702019-01-14 13:13:00 -06001155 return r;
1156 }
1157
1158 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1159 containerType);
1160 if (r < 0)
1161 {
Ed Tanous62598e32023-07-17 17:06:25 -07001162 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler89c19702019-01-14 13:13:00 -06001163 return r;
1164 }
1165
1166 r = convertDBusToJSON(containerType, m, data);
1167 if (r < 0)
1168 {
1169 return r;
1170 }
1171
1172 r = sd_bus_message_exit_container(m.get());
1173 if (r < 0)
1174 {
Ed Tanous62598e32023-07-17 17:06:25 -07001175 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed");
Matt Spinler89c19702019-01-14 13:13:00 -06001176 return r;
1177 }
1178
1179 return 0;
1180}
1181
Ed Tanous23a21a12020-07-25 04:45:05 +00001182inline int convertDBusToJSON(const std::string& returnType,
Patrick Williams59d494e2022-07-22 19:26:55 -05001183 sdbusplus::message_t& m, nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001184{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001185 int r = 0;
1186 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1187
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001188 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001189 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001190 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001191 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001192 {
1193 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001194 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001195 }
1196
Ed Tanousd4d25792020-09-29 15:15:03 -07001197 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001198 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001199 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001200 if (r < 0)
1201 {
1202 return r;
1203 }
1204 }
1205 else if (typeCode == "b")
1206 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001207 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001208 if (r < 0)
1209 {
1210 return r;
1211 }
1212
Matt Spinlerf39420c2019-01-30 12:57:18 -06001213 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001214 }
1215 else if (typeCode == "u")
1216 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001217 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001218 if (r < 0)
1219 {
1220 return r;
1221 }
1222 }
1223 else if (typeCode == "i")
1224 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001225 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001226 if (r < 0)
1227 {
1228 return r;
1229 }
1230 }
1231 else if (typeCode == "x")
1232 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001233 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001234 if (r < 0)
1235 {
1236 return r;
1237 }
1238 }
1239 else if (typeCode == "t")
1240 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001241 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001242 if (r < 0)
1243 {
1244 return r;
1245 }
1246 }
1247 else if (typeCode == "n")
1248 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001249 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001250 if (r < 0)
1251 {
1252 return r;
1253 }
1254 }
1255 else if (typeCode == "q")
1256 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001257 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001258 if (r < 0)
1259 {
1260 return r;
1261 }
1262 }
1263 else if (typeCode == "y")
1264 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001265 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001266 if (r < 0)
1267 {
1268 return r;
1269 }
1270 }
1271 else if (typeCode == "d")
1272 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001273 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001274 if (r < 0)
1275 {
1276 return r;
1277 }
1278 }
1279 else if (typeCode == "h")
1280 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001281 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001282 if (r < 0)
1283 {
1284 return r;
1285 }
1286 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001287 else if (typeCode.starts_with("a"))
Matt Spinler6df8f992019-01-14 12:47:47 -06001288 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001289 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001290 if (r < 0)
1291 {
1292 return r;
1293 }
1294 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001295 else if (typeCode.starts_with("(") && typeCode.ends_with(")"))
Matt Spinler75c6c672019-01-14 13:01:46 -06001296 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001297 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001298 if (r < 0)
1299 {
1300 return r;
1301 }
1302 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001303 else if (typeCode.starts_with("v"))
Matt Spinler89c19702019-01-14 13:13:00 -06001304 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001305 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001306 if (r < 0)
1307 {
1308 return r;
1309 }
1310 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001311 else
1312 {
Ed Tanous62598e32023-07-17 17:06:25 -07001313 BMCWEB_LOG_ERROR("Invalid D-Bus signature type {}", typeCode);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001314 return -2;
1315 }
1316 }
1317
Matt Spinler16caaee2019-01-15 11:40:34 -06001318 return 0;
1319}
1320
Ed Tanousb5a76932020-09-29 16:16:58 -07001321inline void handleMethodResponse(
1322 const std::shared_ptr<InProgressActionData>& transaction,
Patrick Williams59d494e2022-07-22 19:26:55 -05001323 sdbusplus::message_t& m, const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001324{
Matt Spinler39a4e392019-01-15 11:53:13 -06001325 nlohmann::json data;
1326
1327 int r = convertDBusToJSON(returnType, m, data);
1328 if (r < 0)
1329 {
1330 transaction->outputFailed = true;
1331 return;
1332 }
1333
1334 if (data.is_null())
1335 {
1336 return;
1337 }
1338
1339 if (transaction->methodResponse.is_null())
1340 {
1341 transaction->methodResponse = std::move(data);
1342 return;
1343 }
1344
1345 // If they're both dictionaries or arrays, merge into one.
1346 // Otherwise, make the results an array with every result
1347 // an entry. Could also just fail in that case, but it
1348 // seems better to get the data back somehow.
1349
1350 if (transaction->methodResponse.is_object() && data.is_object())
1351 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001352 for (const auto& obj : data.items())
Matt Spinler39a4e392019-01-15 11:53:13 -06001353 {
1354 // Note: Will overwrite the data for a duplicate key
1355 transaction->methodResponse.emplace(obj.key(),
1356 std::move(obj.value()));
1357 }
1358 return;
1359 }
1360
1361 if (transaction->methodResponse.is_array() && data.is_array())
1362 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001363 for (auto& obj : data)
Matt Spinler39a4e392019-01-15 11:53:13 -06001364 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001365 transaction->methodResponse.emplace_back(std::move(obj));
Matt Spinler39a4e392019-01-15 11:53:13 -06001366 }
1367 return;
1368 }
1369
1370 if (!transaction->convertedToArray)
1371 {
1372 // They are different types. May as well turn them into an array
1373 nlohmann::json j = std::move(transaction->methodResponse);
1374 transaction->methodResponse = nlohmann::json::array();
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001375 transaction->methodResponse.emplace_back(std::move(j));
1376 transaction->methodResponse.emplace_back(std::move(data));
Matt Spinler39a4e392019-01-15 11:53:13 -06001377 transaction->convertedToArray = true;
1378 }
1379 else
1380 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001381 transaction->methodResponse.emplace_back(std::move(data));
Matt Spinler39a4e392019-01-15 11:53:13 -06001382 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001383}
1384
Ed Tanousb5a76932020-09-29 16:16:58 -07001385inline void findActionOnInterface(
1386 const std::shared_ptr<InProgressActionData>& transaction,
1387 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001388{
Ed Tanous62598e32023-07-17 17:06:25 -07001389 BMCWEB_LOG_DEBUG("findActionOnInterface for connection {}", connectionName);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001390 crow::connections::systemBus->async_method_call(
1391 [transaction, connectionName{std::string(connectionName)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001392 const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001393 const std::string& introspectXml) {
Ed Tanous62598e32023-07-17 17:06:25 -07001394 BMCWEB_LOG_DEBUG("got xml:\n {}", introspectXml);
Ed Tanous002d39b2022-05-31 08:59:27 -07001395 if (ec)
1396 {
Ed Tanous62598e32023-07-17 17:06:25 -07001397 BMCWEB_LOG_ERROR(
1398 "Introspect call failed with error: {} on process: {}",
1399 ec.message(), connectionName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001400 return;
1401 }
1402 tinyxml2::XMLDocument doc;
Matt Spinler318bd892019-01-15 09:59:20 -06001403
Ed Tanous002d39b2022-05-31 08:59:27 -07001404 doc.Parse(introspectXml.data(), introspectXml.size());
1405 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1406 if (pRoot == nullptr)
1407 {
Ed Tanous62598e32023-07-17 17:06:25 -07001408 BMCWEB_LOG_ERROR("XML document failed to parse {}", connectionName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001409 return;
1410 }
1411 tinyxml2::XMLElement* interfaceNode =
1412 pRoot->FirstChildElement("interface");
1413 while (interfaceNode != nullptr)
1414 {
1415 const char* thisInterfaceName = interfaceNode->Attribute("name");
1416 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001417 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001418 if (!transaction->interfaceName.empty() &&
1419 (transaction->interfaceName != thisInterfaceName))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001420 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001421 interfaceNode =
1422 interfaceNode->NextSiblingElement("interface");
1423 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001424 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001425
1426 tinyxml2::XMLElement* methodNode =
1427 interfaceNode->FirstChildElement("method");
1428 while (methodNode != nullptr)
1429 {
1430 const char* thisMethodName = methodNode->Attribute("name");
Ed Tanous62598e32023-07-17 17:06:25 -07001431 BMCWEB_LOG_DEBUG("Found method: {}", thisMethodName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001432 if (thisMethodName != nullptr &&
1433 thisMethodName == transaction->methodName)
1434 {
Ed Tanous62598e32023-07-17 17:06:25 -07001435 BMCWEB_LOG_DEBUG(
1436 "Found method named {} on interface {}",
1437 thisMethodName, thisInterfaceName);
Patrick Williams59d494e2022-07-22 19:26:55 -05001438 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001439 crow::connections::systemBus->new_method_call(
1440 connectionName.c_str(),
1441 transaction->path.c_str(), thisInterfaceName,
1442 transaction->methodName.c_str());
1443
1444 tinyxml2::XMLElement* argumentNode =
1445 methodNode->FirstChildElement("arg");
1446
1447 std::string returnType;
1448
1449 // Find the output type
1450 while (argumentNode != nullptr)
1451 {
1452 const char* argDirection =
1453 argumentNode->Attribute("direction");
1454 const char* argType =
1455 argumentNode->Attribute("type");
1456 if (argDirection != nullptr && argType != nullptr &&
1457 std::string(argDirection) == "out")
1458 {
1459 returnType = argType;
1460 break;
1461 }
1462 argumentNode =
1463 argumentNode->NextSiblingElement("arg");
1464 }
1465
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001466 auto argIt = transaction->arguments.begin();
Ed Tanous002d39b2022-05-31 08:59:27 -07001467
1468 argumentNode = methodNode->FirstChildElement("arg");
1469
1470 while (argumentNode != nullptr)
1471 {
1472 const char* argDirection =
1473 argumentNode->Attribute("direction");
1474 const char* argType =
1475 argumentNode->Attribute("type");
1476 if (argDirection != nullptr && argType != nullptr &&
1477 std::string(argDirection) == "in")
1478 {
1479 if (argIt == transaction->arguments.end())
1480 {
1481 transaction->setErrorStatus(
1482 "Invalid method args");
1483 return;
1484 }
1485 if (convertJsonToDbus(m.get(),
1486 std::string(argType),
1487 *argIt) < 0)
1488 {
1489 transaction->setErrorStatus(
1490 "Invalid method arg type");
1491 return;
1492 }
1493
1494 argIt++;
1495 }
1496 argumentNode =
1497 argumentNode->NextSiblingElement("arg");
1498 }
1499
1500 crow::connections::systemBus->async_send(
Patrick Williams5a39f772023-10-20 11:20:21 -05001501 m, [transaction, returnType](
1502 const boost::system::error_code& ec2,
1503 sdbusplus::message_t& m2) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001504 if (ec2)
1505 {
1506 transaction->methodFailed = true;
1507 const sd_bus_error* e = m2.get_error();
1508
1509 if (e != nullptr)
1510 {
1511 setErrorResponse(
Lei YU28dd5ca2023-03-17 13:17:05 +08001512 transaction->asyncResp->res,
Ed Tanous002d39b2022-05-31 08:59:27 -07001513 boost::beast::http::status::bad_request,
1514 e->name, e->message);
1515 }
1516 else
1517 {
1518 setErrorResponse(
Lei YU28dd5ca2023-03-17 13:17:05 +08001519 transaction->asyncResp->res,
Ed Tanous002d39b2022-05-31 08:59:27 -07001520 boost::beast::http::status::bad_request,
1521 "Method call failed", methodFailedMsg);
1522 }
1523 return;
1524 }
1525 transaction->methodPassed = true;
1526
1527 handleMethodResponse(transaction, m2, returnType);
Patrick Williams5a39f772023-10-20 11:20:21 -05001528 });
Ed Tanous002d39b2022-05-31 08:59:27 -07001529 break;
1530 }
1531 methodNode = methodNode->NextSiblingElement("method");
1532 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001533 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001534 interfaceNode = interfaceNode->NextSiblingElement("interface");
1535 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001536 },
Ed Tanous1abe55e2018-09-05 08:30:59 -07001537 connectionName, transaction->path,
1538 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001539}
1540
zhanghch058d1b46d2021-04-01 11:18:24 +08001541inline void handleAction(const crow::Request& req,
1542 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001543 const std::string& objectPath,
1544 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001545{
Ed Tanous62598e32023-07-17 17:06:25 -07001546 BMCWEB_LOG_DEBUG("handleAction on path: {} and method {}", objectPath,
1547 methodName);
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001548 nlohmann::json requestDbusData;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001549
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001550 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
1551 if (ret == JsonParseResult::BadContentType)
1552 {
1553 setErrorResponse(asyncResp->res,
1554 boost::beast::http::status::unsupported_media_type,
1555 invalidContentType, unsupportedMediaMsg);
1556 return;
1557 }
1558 if (ret != JsonParseResult::Success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001559 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001560 setErrorResponse(asyncResp->res,
1561 boost::beast::http::status::bad_request, noJsonDesc,
1562 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001563 return;
1564 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001565 nlohmann::json::iterator data = requestDbusData.find("data");
1566 if (data == requestDbusData.end())
1567 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001568 setErrorResponse(asyncResp->res,
1569 boost::beast::http::status::bad_request, noJsonDesc,
1570 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001571 return;
1572 }
1573
1574 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001575 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001576 setErrorResponse(asyncResp->res,
1577 boost::beast::http::status::bad_request, noJsonDesc,
1578 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001579 return;
1580 }
Lei YU28dd5ca2023-03-17 13:17:05 +08001581 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001582
1583 transaction->path = objectPath;
1584 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001585 transaction->arguments = std::move(*data);
George Liu2b731192023-01-11 16:27:13 +08001586 dbus::utility::getDbusObject(
1587 objectPath, {},
Ed Tanous1abe55e2018-09-05 08:30:59 -07001588 [transaction](
George Liu2b731192023-01-11 16:27:13 +08001589 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001590 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1591 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001592 if (ec || interfaceNames.empty())
1593 {
Ed Tanous62598e32023-07-17 17:06:25 -07001594 BMCWEB_LOG_ERROR("Can't find object");
Lei YU28dd5ca2023-03-17 13:17:05 +08001595 setErrorResponse(transaction->asyncResp->res,
Ed Tanous002d39b2022-05-31 08:59:27 -07001596 boost::beast::http::status::not_found,
1597 notFoundDesc, notFoundMsg);
1598 return;
1599 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001600
Ed Tanous62598e32023-07-17 17:06:25 -07001601 BMCWEB_LOG_DEBUG("GetObject returned {} object(s)",
1602 interfaceNames.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001603
Ed Tanous002d39b2022-05-31 08:59:27 -07001604 for (const std::pair<std::string, std::vector<std::string>>& object :
1605 interfaceNames)
1606 {
1607 findActionOnInterface(transaction, object.first);
1608 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001609 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001610}
1611
zhanghch058d1b46d2021-04-01 11:18:24 +08001612inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1613 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001614{
Ed Tanous62598e32023-07-17 17:06:25 -07001615 BMCWEB_LOG_DEBUG("handleDelete on path: {}", objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06001616
George Liu2b731192023-01-11 16:27:13 +08001617 dbus::utility::getDbusObject(
1618 objectPath, {},
zhanghch058d1b46d2021-04-01 11:18:24 +08001619 [asyncResp, objectPath](
George Liu2b731192023-01-11 16:27:13 +08001620 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001621 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1622 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001623 if (ec || interfaceNames.empty())
1624 {
Ed Tanous62598e32023-07-17 17:06:25 -07001625 BMCWEB_LOG_ERROR("Can't find object");
Ed Tanous002d39b2022-05-31 08:59:27 -07001626 setErrorResponse(asyncResp->res,
1627 boost::beast::http::status::method_not_allowed,
1628 methodNotAllowedDesc, methodNotAllowedMsg);
1629 return;
1630 }
Matt Spinlerde818812018-12-11 16:39:20 -06001631
Lei YU28dd5ca2023-03-17 13:17:05 +08001632 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001633 transaction->path = objectPath;
1634 transaction->methodName = "Delete";
1635 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
Matt Spinlerde818812018-12-11 16:39:20 -06001636
Ed Tanous002d39b2022-05-31 08:59:27 -07001637 for (const std::pair<std::string, std::vector<std::string>>& object :
1638 interfaceNames)
1639 {
1640 findActionOnInterface(transaction, object.first);
1641 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001642 });
Matt Spinlerde818812018-12-11 16:39:20 -06001643}
1644
zhanghch058d1b46d2021-04-01 11:18:24 +08001645inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1646 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001647{
George Liu7a1dbc42022-12-07 16:03:22 +08001648 dbus::utility::getSubTreePaths(
1649 objectPath, depth, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001650 [asyncResp](
George Liu7a1dbc42022-12-07 16:03:22 +08001651 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001652 const dbus::utility::MapperGetSubTreePathsResponse& objectPaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001653 if (ec)
1654 {
1655 setErrorResponse(asyncResp->res,
1656 boost::beast::http::status::not_found,
1657 notFoundDesc, notFoundMsg);
1658 }
1659 else
1660 {
1661 asyncResp->res.jsonValue["status"] = "ok";
1662 asyncResp->res.jsonValue["message"] = "200 OK";
1663 asyncResp->res.jsonValue["data"] = objectPaths;
1664 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001665 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001666}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001667
zhanghch058d1b46d2021-04-01 11:18:24 +08001668inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1669 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001670{
Ed Tanous62598e32023-07-17 17:06:25 -07001671 BMCWEB_LOG_DEBUG("Doing enumerate on {}", objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07001672
Ed Tanous14766872022-03-15 10:44:42 -07001673 asyncResp->res.jsonValue["message"] = "200 OK";
1674 asyncResp->res.jsonValue["status"] = "ok";
1675 asyncResp->res.jsonValue["data"] = nlohmann::json::object();
Ed Tanous049a0512018-11-01 13:58:42 -07001676
George Liue99073f2022-12-09 11:06:16 +08001677 dbus::utility::getSubTree(
1678 objectPath, 0, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001679 [objectPath, asyncResp](
George Liue99073f2022-12-09 11:06:16 +08001680 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001681 const dbus::utility::MapperGetSubTreeResponse& objectNames) {
Patrick Williams89492a12023-05-10 07:51:34 -05001682 auto transaction = std::make_shared<InProgressEnumerateData>(objectPath,
1683 asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001684
Ed Tanous002d39b2022-05-31 08:59:27 -07001685 transaction->subtree =
1686 std::make_shared<dbus::utility::MapperGetSubTreeResponse>(
1687 objectNames);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001688
Ed Tanous002d39b2022-05-31 08:59:27 -07001689 if (ec)
1690 {
Ed Tanous62598e32023-07-17 17:06:25 -07001691 BMCWEB_LOG_ERROR("GetSubTree failed on {}",
1692 transaction->objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07001693 setErrorResponse(transaction->asyncResp->res,
1694 boost::beast::http::status::not_found,
1695 notFoundDesc, notFoundMsg);
1696 return;
1697 }
Ed Tanous64530012018-02-06 17:08:16 -08001698
Ed Tanous002d39b2022-05-31 08:59:27 -07001699 // Add the data for the path passed in to the results
1700 // as if GetSubTree returned it, and continue on enumerating
1701 getObjectAndEnumerate(transaction);
Patrick Williams5a39f772023-10-20 11:20:21 -05001702 });
Ed Tanous64530012018-02-06 17:08:16 -08001703}
Ed Tanous911ac312017-08-15 09:37:42 -07001704
zhanghch058d1b46d2021-04-01 11:18:24 +08001705inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1706 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001707{
Ed Tanous62598e32023-07-17 17:06:25 -07001708 BMCWEB_LOG_DEBUG("handleGet: {} prop:{}", objectPath, destProperty);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001709 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001710 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001711
Ed Tanous1abe55e2018-09-05 08:30:59 -07001712 std::shared_ptr<std::string> path =
1713 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001714
George Liu2b731192023-01-11 16:27:13 +08001715 dbus::utility::getDbusObject(
1716 *path, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001717 [asyncResp, path,
George Liu2b731192023-01-11 16:27:13 +08001718 propertyName](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001719 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001720 if (ec || objectNames.empty())
1721 {
1722 setErrorResponse(asyncResp->res,
1723 boost::beast::http::status::not_found,
1724 notFoundDesc, notFoundMsg);
1725 return;
1726 }
1727 std::shared_ptr<nlohmann::json> response =
1728 std::make_shared<nlohmann::json>(nlohmann::json::object());
1729 // The mapper should never give us an empty interface names
1730 // list, but check anyway
1731 for (const std::pair<std::string, std::vector<std::string>>&
1732 connection : objectNames)
1733 {
1734 const std::vector<std::string>& interfaceNames = connection.second;
1735
1736 if (interfaceNames.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 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001743
1744 for (const std::string& interface : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001745 {
Patrick Williams59d494e2022-07-22 19:26:55 -05001746 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001747 crow::connections::systemBus->new_method_call(
1748 connection.first.c_str(), path->c_str(),
1749 "org.freedesktop.DBus.Properties", "GetAll");
1750 m.append(interface);
1751 crow::connections::systemBus->async_send(
1752 m, [asyncResp, response,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001753 propertyName](const boost::system::error_code& ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05001754 sdbusplus::message_t& msg) {
Patrick Williams5a39f772023-10-20 11:20:21 -05001755 if (ec2)
1756 {
1757 BMCWEB_LOG_ERROR("Bad dbus request error: {}", ec2);
1758 }
1759 else
1760 {
1761 nlohmann::json properties;
1762 int r = convertDBusToJSON("a{sv}", msg, properties);
1763 if (r < 0)
Ed Tanous002d39b2022-05-31 08:59:27 -07001764 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001765 BMCWEB_LOG_ERROR("convertDBusToJSON failed");
Ed Tanous002d39b2022-05-31 08:59:27 -07001766 }
1767 else
1768 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001769 for (const auto& prop : properties.items())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001770 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001771 // if property name is empty, or
1772 // matches our search query, add it
1773 // to the response json
Ed Tanous1abe55e2018-09-05 08:30:59 -07001774
Patrick Williams5a39f772023-10-20 11:20:21 -05001775 if (propertyName->empty())
1776 {
1777 (*response)[prop.key()] =
1778 std::move(prop.value());
1779 }
1780 else if (prop.key() == *propertyName)
1781 {
1782 *response = std::move(prop.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001783 }
1784 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001785 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001786 }
1787 if (response.use_count() == 1)
1788 {
1789 if (!propertyName->empty() && response->empty())
Ed Tanous002d39b2022-05-31 08:59:27 -07001790 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001791 setErrorResponse(
1792 asyncResp->res,
1793 boost::beast::http::status::not_found,
1794 propNotFoundDesc, notFoundMsg);
Ed Tanous002d39b2022-05-31 08:59:27 -07001795 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001796 else
1797 {
1798 asyncResp->res.jsonValue["status"] = "ok";
1799 asyncResp->res.jsonValue["message"] = "200 OK";
1800 asyncResp->res.jsonValue["data"] = *response;
1801 }
1802 }
1803 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001804 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001805 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001806 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001807}
1808
Ed Tanous1abe55e2018-09-05 08:30:59 -07001809struct AsyncPutRequest
1810{
Ed Tanous4e23a442022-06-06 09:57:26 -07001811 explicit AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
zhanghch058d1b46d2021-04-01 11:18:24 +08001812 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001813 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001814 ~AsyncPutRequest()
1815 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001816 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001817 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001818 setErrorResponse(asyncResp->res,
1819 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001820 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001821 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001822 }
1823
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001824 AsyncPutRequest(const AsyncPutRequest&) = delete;
1825 AsyncPutRequest(AsyncPutRequest&&) = delete;
1826 AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1827 AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1828
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001829 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001830 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001831 setErrorResponse(asyncResp->res,
1832 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001833 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001834 }
1835
zhanghch058d1b46d2021-04-01 11:18:24 +08001836 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001837 std::string objectPath;
1838 std::string propertyName;
1839 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001840};
1841
zhanghch058d1b46d2021-04-01 11:18:24 +08001842inline void handlePut(const crow::Request& req,
1843 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001844 const std::string& objectPath,
1845 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001846{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001847 if (destProperty.empty())
1848 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001849 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001850 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001851 return;
1852 }
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001853 nlohmann::json requestDbusData;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001854
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001855 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
1856 if (ret == JsonParseResult::BadContentType)
1857 {
1858 setErrorResponse(asyncResp->res,
1859 boost::beast::http::status::unsupported_media_type,
1860 invalidContentType, unsupportedMediaMsg);
1861 return;
1862 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001863
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001864 if (ret != JsonParseResult::Success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001865 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001866 setErrorResponse(asyncResp->res,
1867 boost::beast::http::status::bad_request, noJsonDesc,
1868 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001869 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001870 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001871
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001872 auto propertyIt = requestDbusData.find("data");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001873 if (propertyIt == requestDbusData.end())
1874 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001875 setErrorResponse(asyncResp->res,
1876 boost::beast::http::status::bad_request, noJsonDesc,
1877 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001878 return;
1879 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001880 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001881 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001882 transaction->objectPath = objectPath;
1883 transaction->propertyName = destProperty;
1884 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001885
George Liu2b731192023-01-11 16:27:13 +08001886 dbus::utility::getDbusObject(
1887 transaction->objectPath, {},
1888 [transaction](const boost::system::error_code& ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001889 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001890 if (!ec2 && objectNames.empty())
1891 {
1892 setErrorResponse(transaction->asyncResp->res,
1893 boost::beast::http::status::not_found,
1894 propNotFoundDesc, notFoundMsg);
1895 return;
1896 }
Ed Tanous911ac312017-08-15 09:37:42 -07001897
Ed Tanous002d39b2022-05-31 08:59:27 -07001898 for (const std::pair<std::string, std::vector<std::string>>&
1899 connection : objectNames)
1900 {
1901 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001902
Ed Tanous002d39b2022-05-31 08:59:27 -07001903 crow::connections::systemBus->async_method_call(
1904 [connectionName{std::string(connectionName)},
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001905 transaction](const boost::system::error_code& ec3,
Ed Tanous002d39b2022-05-31 08:59:27 -07001906 const std::string& introspectXml) {
1907 if (ec3)
1908 {
Ed Tanous62598e32023-07-17 17:06:25 -07001909 BMCWEB_LOG_ERROR(
1910 "Introspect call failed with error: {} on process: {}",
1911 ec3.message(), connectionName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001912 transaction->setErrorStatus("Unexpected Error");
1913 return;
1914 }
1915 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001916
Ed Tanous002d39b2022-05-31 08:59:27 -07001917 doc.Parse(introspectXml.c_str());
1918 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1919 if (pRoot == nullptr)
1920 {
Ed Tanous62598e32023-07-17 17:06:25 -07001921 BMCWEB_LOG_ERROR("XML document failed to parse: {}",
1922 introspectXml);
Ed Tanous002d39b2022-05-31 08:59:27 -07001923 transaction->setErrorStatus("Unexpected Error");
1924 return;
1925 }
1926 tinyxml2::XMLElement* ifaceNode =
1927 pRoot->FirstChildElement("interface");
1928 while (ifaceNode != nullptr)
1929 {
1930 const char* interfaceName = ifaceNode->Attribute("name");
Ed Tanous62598e32023-07-17 17:06:25 -07001931 BMCWEB_LOG_DEBUG("found interface {}", interfaceName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001932 tinyxml2::XMLElement* propNode =
1933 ifaceNode->FirstChildElement("property");
1934 while (propNode != nullptr)
1935 {
1936 const char* propertyName = propNode->Attribute("name");
Ed Tanous62598e32023-07-17 17:06:25 -07001937 BMCWEB_LOG_DEBUG("Found property {}", propertyName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001938 if (propertyName == transaction->propertyName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001939 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001940 const char* argType = propNode->Attribute("type");
1941 if (argType != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001942 {
Patrick Williams59d494e2022-07-22 19:26:55 -05001943 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001944 crow::connections::systemBus
1945 ->new_method_call(
1946 connectionName.c_str(),
1947 transaction->objectPath.c_str(),
1948 "org.freedesktop.DBus."
1949 "Properties",
1950 "Set");
1951 m.append(interfaceName,
1952 transaction->propertyName);
1953 int r = sd_bus_message_open_container(
1954 m.get(), SD_BUS_TYPE_VARIANT, argType);
1955 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001956 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001957 transaction->setErrorStatus(
1958 "Unexpected Error");
1959 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001960 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001961 r = convertJsonToDbus(
1962 m.get(), argType,
1963 transaction->propertyValue);
1964 if (r < 0)
1965 {
1966 if (r == -ERANGE)
1967 {
1968 transaction->setErrorStatus(
1969 "Provided property value "
1970 "is out of range for the "
1971 "property type");
1972 }
1973 else
1974 {
1975 transaction->setErrorStatus(
1976 "Invalid arg type");
1977 }
1978 return;
1979 }
1980 r = sd_bus_message_close_container(m.get());
1981 if (r < 0)
1982 {
1983 transaction->setErrorStatus(
1984 "Unexpected Error");
1985 return;
1986 }
1987 crow::connections::systemBus->async_send(
Patrick Williams5a39f772023-10-20 11:20:21 -05001988 m, [transaction](
1989 const boost::system::error_code& ec,
1990 sdbusplus::message_t& m2) {
Ed Tanous62598e32023-07-17 17:06:25 -07001991 BMCWEB_LOG_DEBUG("sent");
Ed Tanous002d39b2022-05-31 08:59:27 -07001992 if (ec)
1993 {
1994 const sd_bus_error* e = m2.get_error();
1995 setErrorResponse(
1996 transaction->asyncResp->res,
1997 boost::beast::http::status::
1998 forbidden,
1999 (e) != nullptr
2000 ? e->name
2001 : ec.category().name(),
2002 (e) != nullptr ? e->message
2003 : ec.message());
2004 }
2005 else
2006 {
2007 transaction->asyncResp->res
2008 .jsonValue["status"] = "ok";
2009 transaction->asyncResp->res
2010 .jsonValue["message"] = "200 OK";
2011 transaction->asyncResp->res
2012 .jsonValue["data"] = nullptr;
2013 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002014 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002015 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002016 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002017 propNode = propNode->NextSiblingElement("property");
2018 }
2019 ifaceNode = ifaceNode->NextSiblingElement("interface");
2020 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002021 },
Ed Tanous002d39b2022-05-31 08:59:27 -07002022 connectionName, transaction->objectPath,
2023 "org.freedesktop.DBus.Introspectable", "Introspect");
2024 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002025 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07002026}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002027
zhanghch058d1b46d2021-04-01 11:18:24 +08002028inline void handleDBusUrl(const crow::Request& req,
2029 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002030 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002031{
Ed Tanous049a0512018-11-01 13:58:42 -07002032 // If accessing a single attribute, fill in and update objectPath,
2033 // otherwise leave destProperty blank
Ed Tanouse05aec52022-01-25 10:28:56 -08002034 std::string destProperty;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002035 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002036 size_t attrPosition = objectPath.find(attrSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002037 if (attrPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002038 {
2039 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2040 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002041 objectPath.resize(attrPosition);
Ed Tanous049a0512018-11-01 13:58:42 -07002042 }
2043
Ed Tanousb41187f2019-10-24 16:30:02 -07002044 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002045 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002046 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002047 size_t actionPosition = objectPath.find(actionSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002048 if (actionPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002049 {
2050 std::string postProperty =
2051 objectPath.substr((actionPosition + strlen(actionSeperator)),
2052 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002053 objectPath.resize(actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002054 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002055 return;
2056 }
2057 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002058 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002059 {
Ed Tanous11ba3972022-07-11 09:50:41 -07002060 if (objectPath.ends_with("/enumerate"))
Ed Tanous049a0512018-11-01 13:58:42 -07002061 {
2062 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2063 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002064 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002065 }
Ed Tanous11ba3972022-07-11 09:50:41 -07002066 else if (objectPath.ends_with("/list"))
Ed Tanous049a0512018-11-01 13:58:42 -07002067 {
2068 objectPath.erase(objectPath.end() - sizeof("list"),
2069 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002070 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002071 }
2072 else
2073 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002074 // Trim any trailing "/" at the end
Ed Tanous11ba3972022-07-11 09:50:41 -07002075 if (objectPath.ends_with("/"))
Ed Tanousf839dfe2018-11-12 11:11:15 -08002076 {
2077 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002078 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002079 }
2080 else
2081 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002082 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002083 }
Ed Tanous049a0512018-11-01 13:58:42 -07002084 }
2085 return;
2086 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002087 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002088 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002089 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002090 return;
2091 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002092 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002093 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002094 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002095 return;
2096 }
Ed Tanous049a0512018-11-01 13:58:42 -07002097
zhanghch058d1b46d2021-04-01 11:18:24 +08002098 setErrorResponse(asyncResp->res,
2099 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002100 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002101}
2102
Ed Tanous1656b292022-05-04 11:33:42 -07002103inline void
2104 handleBusSystemPost(const crow::Request& req,
2105 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2106 const std::string& processName,
2107 const std::string& requestedPath)
2108{
2109 std::vector<std::string> strs;
Ed Tanous50ebd4a2023-01-19 19:03:17 -08002110
2111 bmcweb::split(strs, requestedPath, '/');
Ed Tanous1656b292022-05-04 11:33:42 -07002112 std::string objectPath;
2113 std::string interfaceName;
2114 std::string methodName;
2115 auto it = strs.begin();
2116 if (it == strs.end())
2117 {
2118 objectPath = "/";
2119 }
2120 while (it != strs.end())
2121 {
2122 // Check if segment contains ".". If it does, it must be an
2123 // interface
2124 if (it->find(".") != std::string::npos)
2125 {
2126 break;
2127 // This check is necessary as the trailing slash gets
2128 // parsed as part of our <path> specifier above, which
2129 // causes the normal trailing backslash redirector to
2130 // fail.
2131 }
2132 if (!it->empty())
2133 {
2134 objectPath += "/" + *it;
2135 }
2136 it++;
2137 }
2138 if (it != strs.end())
2139 {
2140 interfaceName = *it;
2141 it++;
2142
2143 // after interface, we might have a method name
2144 if (it != strs.end())
2145 {
2146 methodName = *it;
2147 it++;
2148 }
2149 }
2150 if (it != strs.end())
2151 {
2152 // if there is more levels past the method name, something
2153 // went wrong, return not found
2154 asyncResp->res.result(boost::beast::http::status::not_found);
2155 return;
2156 }
2157 if (interfaceName.empty())
2158 {
2159 crow::connections::systemBus->async_method_call(
2160 [asyncResp, processName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002161 objectPath](const boost::system::error_code& ec,
Ed Tanous1656b292022-05-04 11:33:42 -07002162 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002163 if (ec)
2164 {
Ed Tanous62598e32023-07-17 17:06:25 -07002165 BMCWEB_LOG_ERROR(
2166 "Introspect call failed with error: {} on process: {} path: {}",
2167 ec.message(), processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002168 return;
2169 }
2170 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002171
Ed Tanous002d39b2022-05-31 08:59:27 -07002172 doc.Parse(introspectXml.c_str());
2173 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2174 if (pRoot == nullptr)
2175 {
Ed Tanous62598e32023-07-17 17:06:25 -07002176 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
2177 processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002178 asyncResp->res.jsonValue["status"] = "XML parse error";
2179 asyncResp->res.result(
2180 boost::beast::http::status::internal_server_error);
2181 return;
2182 }
2183
Ed Tanous62598e32023-07-17 17:06:25 -07002184 BMCWEB_LOG_DEBUG("{}", introspectXml);
Ed Tanous002d39b2022-05-31 08:59:27 -07002185 asyncResp->res.jsonValue["status"] = "ok";
2186 asyncResp->res.jsonValue["bus_name"] = processName;
2187 asyncResp->res.jsonValue["object_path"] = objectPath;
2188
2189 nlohmann::json& interfacesArray =
2190 asyncResp->res.jsonValue["interfaces"];
2191 interfacesArray = nlohmann::json::array();
2192 tinyxml2::XMLElement* interface =
2193 pRoot->FirstChildElement("interface");
2194
2195 while (interface != nullptr)
2196 {
2197 const char* ifaceName = interface->Attribute("name");
2198 if (ifaceName != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002199 {
Ed Tanous8a592812022-06-04 09:06:59 -07002200 nlohmann::json::object_t interfaceObj;
2201 interfaceObj["name"] = ifaceName;
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002202 interfacesArray.emplace_back(std::move(interfaceObj));
Ed Tanous1656b292022-05-04 11:33:42 -07002203 }
2204
Ed Tanous002d39b2022-05-31 08:59:27 -07002205 interface = interface->NextSiblingElement("interface");
2206 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002207 },
Ed Tanous1656b292022-05-04 11:33:42 -07002208 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2209 "Introspect");
2210 }
2211 else if (methodName.empty())
2212 {
2213 crow::connections::systemBus->async_method_call(
2214 [asyncResp, processName, objectPath,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002215 interfaceName](const boost::system::error_code& ec,
Ed Tanous1656b292022-05-04 11:33:42 -07002216 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002217 if (ec)
2218 {
Ed Tanous62598e32023-07-17 17:06:25 -07002219 BMCWEB_LOG_ERROR(
2220 "Introspect call failed with error: {} on process: {} path: {}",
2221 ec.message(), processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002222 return;
2223 }
2224 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002225
Ed Tanous002d39b2022-05-31 08:59:27 -07002226 doc.Parse(introspectXml.data(), introspectXml.size());
2227 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2228 if (pRoot == nullptr)
2229 {
Ed Tanous62598e32023-07-17 17:06:25 -07002230 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
2231 processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002232 asyncResp->res.result(
2233 boost::beast::http::status::internal_server_error);
2234 return;
2235 }
2236
2237 asyncResp->res.jsonValue["status"] = "ok";
2238 asyncResp->res.jsonValue["bus_name"] = processName;
2239 asyncResp->res.jsonValue["interface"] = interfaceName;
2240 asyncResp->res.jsonValue["object_path"] = objectPath;
2241
2242 nlohmann::json& methodsArray = asyncResp->res.jsonValue["methods"];
2243 methodsArray = nlohmann::json::array();
2244
2245 nlohmann::json& signalsArray = asyncResp->res.jsonValue["signals"];
2246 signalsArray = nlohmann::json::array();
2247
2248 nlohmann::json& propertiesObj =
2249 asyncResp->res.jsonValue["properties"];
2250 propertiesObj = nlohmann::json::object();
2251
2252 // if we know we're the only call, build the
2253 // json directly
2254 tinyxml2::XMLElement* interface =
2255 pRoot->FirstChildElement("interface");
2256 while (interface != nullptr)
2257 {
2258 const char* ifaceName = interface->Attribute("name");
2259
2260 if (ifaceName != nullptr && ifaceName == interfaceName)
Ed Tanous1656b292022-05-04 11:33:42 -07002261 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002262 break;
Ed Tanous1656b292022-05-04 11:33:42 -07002263 }
Ed Tanous14766872022-03-15 10:44:42 -07002264
Ed Tanous002d39b2022-05-31 08:59:27 -07002265 interface = interface->NextSiblingElement("interface");
2266 }
2267 if (interface == nullptr)
2268 {
2269 // if we got to the end of the list and
2270 // never found a match, throw 404
2271 asyncResp->res.result(boost::beast::http::status::not_found);
2272 return;
2273 }
Ed Tanous1656b292022-05-04 11:33:42 -07002274
Ed Tanous002d39b2022-05-31 08:59:27 -07002275 tinyxml2::XMLElement* methods =
2276 interface->FirstChildElement("method");
2277 while (methods != nullptr)
2278 {
2279 nlohmann::json argsArray = nlohmann::json::array();
2280 tinyxml2::XMLElement* arg = methods->FirstChildElement("arg");
2281 while (arg != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002282 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002283 nlohmann::json thisArg;
2284 for (const char* fieldName : std::array<const char*, 3>{
2285 "name", "direction", "type"})
Ed Tanous1656b292022-05-04 11:33:42 -07002286 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002287 const char* fieldValue = arg->Attribute(fieldName);
2288 if (fieldValue != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002289 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002290 thisArg[fieldName] = fieldValue;
2291 }
2292 }
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002293 argsArray.emplace_back(std::move(thisArg));
Ed Tanous002d39b2022-05-31 08:59:27 -07002294 arg = arg->NextSiblingElement("arg");
2295 }
2296
2297 const char* name = methods->Attribute("name");
2298 if (name != nullptr)
2299 {
2300 std::string uri;
2301 uri.reserve(14 + processName.size() + objectPath.size() +
2302 interfaceName.size() + strlen(name));
2303 uri += "/bus/system/";
2304 uri += processName;
2305 uri += objectPath;
2306 uri += "/";
2307 uri += interfaceName;
2308 uri += "/";
2309 uri += name;
2310
2311 nlohmann::json::object_t object;
2312 object["name"] = name;
2313 object["uri"] = std::move(uri);
2314 object["args"] = argsArray;
2315
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002316 methodsArray.emplace_back(std::move(object));
Ed Tanous002d39b2022-05-31 08:59:27 -07002317 }
2318 methods = methods->NextSiblingElement("method");
2319 }
2320 tinyxml2::XMLElement* signals =
2321 interface->FirstChildElement("signal");
2322 while (signals != nullptr)
2323 {
2324 nlohmann::json argsArray = nlohmann::json::array();
2325
2326 tinyxml2::XMLElement* arg = signals->FirstChildElement("arg");
2327 while (arg != nullptr)
2328 {
2329 const char* name = arg->Attribute("name");
2330 const char* type = arg->Attribute("type");
2331 if (name != nullptr && type != nullptr)
2332 {
2333 argsArray.push_back({
2334 {"name", name},
2335 {"type", type},
2336 });
2337 }
2338 arg = arg->NextSiblingElement("arg");
2339 }
2340 const char* name = signals->Attribute("name");
2341 if (name != nullptr)
2342 {
2343 nlohmann::json::object_t object;
2344 object["name"] = name;
2345 object["args"] = argsArray;
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002346 signalsArray.emplace_back(std::move(object));
Ed Tanous002d39b2022-05-31 08:59:27 -07002347 }
2348
2349 signals = signals->NextSiblingElement("signal");
2350 }
2351
2352 tinyxml2::XMLElement* property =
2353 interface->FirstChildElement("property");
2354 while (property != nullptr)
2355 {
2356 const char* name = property->Attribute("name");
2357 const char* type = property->Attribute("type");
2358 if (type != nullptr && name != nullptr)
2359 {
Patrick Williams59d494e2022-07-22 19:26:55 -05002360 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07002361 crow::connections::systemBus->new_method_call(
2362 processName.c_str(), objectPath.c_str(),
2363 "org.freedesktop."
2364 "DBus."
2365 "Properties",
2366 "Get");
2367 m.append(interfaceName, name);
2368 nlohmann::json& propertyItem = propertiesObj[name];
2369 crow::connections::systemBus->async_send(
2370 m, [&propertyItem,
Ed Tanous8b242752023-06-27 17:17:13 -07002371 asyncResp](const boost::system::error_code& ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05002372 sdbusplus::message_t& msg) {
Patrick Williams5a39f772023-10-20 11:20:21 -05002373 if (ec2)
2374 {
2375 return;
2376 }
Ed Tanous1656b292022-05-04 11:33:42 -07002377
Patrick Williams5a39f772023-10-20 11:20:21 -05002378 convertDBusToJSON("v", msg, propertyItem);
2379 });
Ed Tanous1656b292022-05-04 11:33:42 -07002380 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002381 property = property->NextSiblingElement("property");
2382 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002383 },
Ed Tanous1656b292022-05-04 11:33:42 -07002384 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2385 "Introspect");
2386 }
2387 else
2388 {
2389 if (req.method() != boost::beast::http::verb::post)
2390 {
2391 asyncResp->res.result(boost::beast::http::status::not_found);
2392 return;
2393 }
2394
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002395 nlohmann::json requestDbusData;
2396 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
2397 if (ret == JsonParseResult::BadContentType)
Ed Tanous1656b292022-05-04 11:33:42 -07002398 {
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002399 setErrorResponse(asyncResp->res,
2400 boost::beast::http::status::unsupported_media_type,
2401 invalidContentType, unsupportedMediaMsg);
Ed Tanous1656b292022-05-04 11:33:42 -07002402 return;
2403 }
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002404 if (ret != JsonParseResult::Success)
2405 {
2406 setErrorResponse(asyncResp->res,
2407 boost::beast::http::status::bad_request,
2408 noJsonDesc, badReqMsg);
2409 return;
2410 }
2411
Ed Tanous1656b292022-05-04 11:33:42 -07002412 if (!requestDbusData.is_array())
2413 {
2414 asyncResp->res.result(boost::beast::http::status::bad_request);
2415 return;
2416 }
Lei YU28dd5ca2023-03-17 13:17:05 +08002417 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous1656b292022-05-04 11:33:42 -07002418
2419 transaction->path = objectPath;
2420 transaction->methodName = methodName;
2421 transaction->arguments = std::move(requestDbusData);
2422
2423 findActionOnInterface(transaction, processName);
2424 }
2425}
2426
Ed Tanous23a21a12020-07-25 04:45:05 +00002427inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002428{
2429 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002430 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002431 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002432 [](const crow::Request&,
2433 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002434 nlohmann::json::array_t buses;
2435 nlohmann::json& bus = buses.emplace_back();
2436 bus["name"] = "system";
2437 asyncResp->res.jsonValue["busses"] = std::move(buses);
2438 asyncResp->res.jsonValue["status"] = "ok";
Patrick Williams5a39f772023-10-20 11:20:21 -05002439 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002440
2441 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002442 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002443 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002444 [](const crow::Request&,
2445 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002446 auto myCallback = [asyncResp](const boost::system::error_code& ec,
zhanghch058d1b46d2021-04-01 11:18:24 +08002447 std::vector<std::string>& names) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002448 if (ec)
2449 {
Ed Tanous62598e32023-07-17 17:06:25 -07002450 BMCWEB_LOG_ERROR("Dbus call failed with code {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07002451 asyncResp->res.result(
2452 boost::beast::http::status::internal_server_error);
2453 }
2454 else
2455 {
Ed Tanous3544d2a2023-08-06 18:12:20 -07002456 std::ranges::sort(names);
Ed Tanous002d39b2022-05-31 08:59:27 -07002457 asyncResp->res.jsonValue["status"] = "ok";
2458 auto& objectsSub = asyncResp->res.jsonValue["objects"];
Ed Tanous02cad962022-06-30 16:50:15 -07002459 for (const auto& name : names)
Ed Tanous002d39b2022-05-31 08:59:27 -07002460 {
2461 nlohmann::json::object_t object;
2462 object["name"] = name;
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002463 objectsSub.emplace_back(std::move(object));
Ed Tanous002d39b2022-05-31 08:59:27 -07002464 }
2465 }
2466 };
2467 crow::connections::systemBus->async_method_call(
2468 std::move(myCallback), "org.freedesktop.DBus", "/",
2469 "org.freedesktop.DBus", "ListNames");
Patrick Williams5a39f772023-10-20 11:20:21 -05002470 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002471
2472 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002473 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002474 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002475 [](const crow::Request&,
2476 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002477 handleList(asyncResp, "/");
Patrick Williams5a39f772023-10-20 11:20:21 -05002478 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002479
2480 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002481 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002482 .methods(boost::beast::http::verb::get)(
2483 [](const crow::Request& req,
2484 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002485 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002486 std::string objectPath = "/xyz/" + path;
2487 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002488 });
zhanghch058d1b46d2021-04-01 11:18:24 +08002489
2490 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002491 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002492 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2493 boost::beast::http::verb::delete_)(
2494 [](const crow::Request& req,
2495 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2496 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002497 std::string objectPath = "/xyz/" + path;
2498 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002499 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002500
Ed Tanous049a0512018-11-01 13:58:42 -07002501 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002502 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002503 .methods(boost::beast::http::verb::get)(
2504 [](const crow::Request& req,
2505 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2506 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002507 std::string objectPath = "/org/" + path;
2508 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002509 });
Tanousf00032d2018-11-05 01:18:10 -03002510
2511 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002512 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002513 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2514 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002515 [](const crow::Request& req,
2516 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002517 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002518 std::string objectPath = "/org/" + path;
2519 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002520 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002521
Ed Tanous1abe55e2018-09-05 08:30:59 -07002522 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002523 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002524 .methods(boost::beast::http::verb::get)(
2525 [](const crow::Request&,
2526 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2527 const std::string& dumpId) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002528 if (!validateFilename(dumpId))
2529 {
2530 asyncResp->res.result(boost::beast::http::status::bad_request);
2531 return;
2532 }
2533 std::filesystem::path loc("/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002534
Ed Tanous002d39b2022-05-31 08:59:27 -07002535 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002536
Ed Tanous002d39b2022-05-31 08:59:27 -07002537 if (!std::filesystem::exists(loc) ||
2538 !std::filesystem::is_directory(loc))
2539 {
Ed Tanous62598e32023-07-17 17:06:25 -07002540 BMCWEB_LOG_ERROR("{}Not found", loc.string());
Ed Tanous002d39b2022-05-31 08:59:27 -07002541 asyncResp->res.result(boost::beast::http::status::not_found);
2542 return;
2543 }
2544 std::filesystem::directory_iterator files(loc);
zhanghch058d1b46d2021-04-01 11:18:24 +08002545
Ed Tanous002d39b2022-05-31 08:59:27 -07002546 for (const auto& file : files)
2547 {
Ed Tanous27b0cf92023-08-07 12:02:40 -07002548 if (!asyncResp->res.openFile(file))
Ed Tanous002d39b2022-05-31 08:59:27 -07002549 {
2550 continue;
2551 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002552
Ed Tanousd9f6c622022-03-17 09:12:17 -07002553 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07002554 "application/octet-stream");
zhanghch058d1b46d2021-04-01 11:18:24 +08002555
Ed Tanous002d39b2022-05-31 08:59:27 -07002556 // Assuming only one dump file will be present in the dump
2557 // id directory
2558 std::string dumpFileName = file.path().filename().string();
zhanghch058d1b46d2021-04-01 11:18:24 +08002559
Ed Tanous002d39b2022-05-31 08:59:27 -07002560 // Filename should be in alphanumeric, dot and underscore
2561 // Its based on phosphor-debug-collector application
2562 // dumpfile format
Ed Tanous4b242742023-05-11 09:51:51 -07002563 static std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
Ed Tanous002d39b2022-05-31 08:59:27 -07002564 if (!std::regex_match(dumpFileName, dumpFileRegex))
2565 {
Ed Tanous62598e32023-07-17 17:06:25 -07002566 BMCWEB_LOG_ERROR("Invalid dump filename {}", dumpFileName);
zhanghch058d1b46d2021-04-01 11:18:24 +08002567 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002568 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07002569 }
Patrick Williams89492a12023-05-10 07:51:34 -05002570 std::string contentDispositionParam = "attachment; filename=\"" +
2571 dumpFileName + "\"";
Ed Tanous002d39b2022-05-31 08:59:27 -07002572
Ed Tanousd9f6c622022-03-17 09:12:17 -07002573 asyncResp->res.addHeader(
2574 boost::beast::http::field::content_disposition,
2575 contentDispositionParam);
Ed Tanous002d39b2022-05-31 08:59:27 -07002576
Ed Tanous002d39b2022-05-31 08:59:27 -07002577 return;
2578 }
2579 asyncResp->res.result(boost::beast::http::status::not_found);
2580 return;
Patrick Williams5a39f772023-10-20 11:20:21 -05002581 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002582
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002583 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002584 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002585
2586 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002587 [](const crow::Request&,
2588 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002589 const std::string& connection) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002590 introspectObjects(connection, "/", asyncResp);
Patrick Williams5a39f772023-10-20 11:20:21 -05002591 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002592
2593 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002594 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous1656b292022-05-04 11:33:42 -07002595 .methods(boost::beast::http::verb::get,
2596 boost::beast::http::verb::post)(handleBusSystemPost);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002597}
2598} // namespace openbmc_mapper
2599} // namespace crow