blob: e1d66f56e9865bfe2e37bf00101b28c8f9cf28a3 [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 Tanous296579b2024-03-11 16:58:24 -0700600 BMCWEB_LOG_DEBUG("Converting {} to type: {}", inputJson, argType);
Ed Tanous81ce6092020-12-17 16:54:55 +0000601 const std::vector<std::string> argTypes = dbusArgSplit(argType);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700602
Ed Tanous1abe55e2018-09-05 08:30:59 -0700603 // Assume a single object for now.
Ed Tanous81ce6092020-12-17 16:54:55 +0000604 const nlohmann::json* j = &inputJson;
605 nlohmann::json::const_iterator jIt = inputJson.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700606
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500607 for (const std::string& argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700608 {
609 // If we are decoding multiple objects, grab the pointer to the
610 // iterator, and increment it for the next loop
611 if (argTypes.size() > 1)
612 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000613 if (jIt == inputJson.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700614 {
615 return -2;
616 }
617 j = &*jIt;
618 jIt++;
619 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500620 const int64_t* intValue = j->get_ptr<const int64_t*>();
621 const std::string* stringValue = j->get_ptr<const std::string*>();
622 const double* doubleValue = j->get_ptr<const double*>();
623 const bool* b = j->get_ptr<const bool*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700624 int64_t v = 0;
625 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700626
Ed Tanous1abe55e2018-09-05 08:30:59 -0700627 // Do some basic type conversions that make sense. uint can be
628 // converted to int. int and uint can be converted to double
Ed Tanous66664f22019-10-11 13:05:49 -0700629 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700630 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500631 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700632 if (uintValue != nullptr)
633 {
634 v = static_cast<int64_t>(*uintValue);
635 intValue = &v;
636 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700637 }
Ed Tanous66664f22019-10-11 13:05:49 -0700638 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700639 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500640 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700641 if (uintValue != nullptr)
642 {
643 d = static_cast<double>(*uintValue);
644 doubleValue = &d;
645 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700646 }
Ed Tanous66664f22019-10-11 13:05:49 -0700647 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700648 {
Ed Tanous66664f22019-10-11 13:05:49 -0700649 if (intValue != nullptr)
650 {
651 d = static_cast<double>(*intValue);
652 doubleValue = &d;
653 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700654 }
655
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700656 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700657 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700658 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700659 {
660 return -1;
661 }
Ed Tanous271584a2019-07-09 16:24:22 -0700662 r = sd_bus_message_append_basic(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500663 m, argCode[0], static_cast<const void*>(stringValue->data()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700664 if (r < 0)
665 {
666 return r;
667 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700668 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700669 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700670 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700671 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700672 {
673 return -1;
674 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500675 if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
676 (*intValue > std::numeric_limits<int32_t>::max()))
677 {
678 return -ERANGE;
679 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700680 int32_t i = static_cast<int32_t>(*intValue);
681 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700682 if (r < 0)
683 {
684 return r;
685 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700686 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700687 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700688 {
689 // lots of ways bool could be represented here. Try them all
Ed Tanouse662eae2022-01-25 10:39:19 -0800690 int boolInt = 0;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700691 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700692 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500693 if (*intValue == 1)
694 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800695 boolInt = 1;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500696 }
697 else if (*intValue == 0)
698 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800699 boolInt = 0;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500700 }
701 else
702 {
703 return -ERANGE;
704 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700705 }
706 else if (b != nullptr)
707 {
Matt Spinlera2f02632019-01-18 10:15:35 -0600708 boolInt = *b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700709 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700710 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700711 {
Ed Tanous18f8f602023-07-18 10:07:23 -0700712 if (!stringValue->empty())
713 {
714 if (stringValue->front() == 't' ||
715 stringValue->front() == 'T')
716 {
717 boolInt = 1;
718 }
719 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700720 }
721 else
722 {
723 return -1;
724 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700725 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700726 if (r < 0)
727 {
728 return r;
729 }
730 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700731 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700732 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700733 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700734 {
735 return -1;
736 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500737 if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
738 (*intValue > std::numeric_limits<int16_t>::max()))
739 {
740 return -ERANGE;
741 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700742 int16_t n = static_cast<int16_t>(*intValue);
743 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700744 if (r < 0)
745 {
746 return r;
747 }
748 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700749 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700750 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700751 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700752 {
753 return -1;
754 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700755 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700756 if (r < 0)
757 {
758 return r;
759 }
760 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700761 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700762 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500763 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700764 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700765 {
766 return -1;
767 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000768 if (*uintValue > std::numeric_limits<uint8_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500769 {
770 return -ERANGE;
771 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700772 uint8_t y = static_cast<uint8_t>(*uintValue);
773 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700774 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700775 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700776 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500777 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700778 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700779 {
780 return -1;
781 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000782 if (*uintValue > std::numeric_limits<uint16_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500783 {
784 return -ERANGE;
785 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700786 uint16_t q = static_cast<uint16_t>(*uintValue);
787 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700788 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700789 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700790 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500791 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700792 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700793 {
794 return -1;
795 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000796 if (*uintValue > std::numeric_limits<uint32_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500797 {
798 return -ERANGE;
799 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700800 uint32_t u = static_cast<uint32_t>(*uintValue);
801 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700802 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700803 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700804 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500805 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700806 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700807 {
808 return -1;
809 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700810 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700811 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700812 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700813 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500814 if (doubleValue == nullptr)
815 {
816 return -1;
817 }
818 if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
819 (*doubleValue > std::numeric_limits<double>::max()))
820 {
821 return -ERANGE;
822 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700823 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700824 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700825 else if (argCode.starts_with("a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700826 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700827 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700828 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700829 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700830 if (r < 0)
831 {
832 return r;
833 }
834
Ed Tanous0dfeda62019-10-24 11:21:38 -0700835 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700836 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700837 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700838 if (r < 0)
839 {
840 return r;
841 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700842 }
843 sd_bus_message_close_container(m);
844 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700845 else if (argCode.starts_with("v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700846 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700847 std::string containedType = argCode.substr(1);
Ed Tanous62598e32023-07-17 17:06:25 -0700848 BMCWEB_LOG_DEBUG("variant type: {} appending variant of type: {}",
849 argCode, containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700850 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700851 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700852 if (r < 0)
853 {
854 return r;
855 }
856
Ed Tanous81ce6092020-12-17 16:54:55 +0000857 r = convertJsonToDbus(m, containedType, inputJson);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700858 if (r < 0)
859 {
860 return r;
861 }
862
863 r = sd_bus_message_close_container(m);
864 if (r < 0)
865 {
866 return r;
867 }
868 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700869 else if (argCode.starts_with("(") && argCode.ends_with(")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700870 {
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300871 std::string containedType = argCode.substr(1, argCode.size() - 2);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700872 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700873 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800874 if (r < 0)
875 {
876 return r;
877 }
878
Ed Tanous1abe55e2018-09-05 08:30:59 -0700879 nlohmann::json::const_iterator it = j->begin();
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300880 for (const std::string& argCode2 : dbusArgSplit(containedType))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700881 {
882 if (it == j->end())
883 {
884 return -1;
885 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000886 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700887 if (r < 0)
888 {
889 return r;
890 }
891 it++;
892 }
893 r = sd_bus_message_close_container(m);
894 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700895 else if (argCode.starts_with("{") && argCode.ends_with("}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700896 {
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300897 std::string containedType = argCode.substr(1, argCode.size() - 2);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700898 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700899 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800900 if (r < 0)
901 {
902 return r;
903 }
904
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700905 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700906 if (codes.size() != 2)
907 {
908 return -1;
909 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700910 const std::string& keyType = codes[0];
911 const std::string& valueType = codes[1];
Ed Tanous3174e4d2020-10-07 11:41:22 -0700912 for (const auto& it : j->items())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700913 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700914 r = convertJsonToDbus(m, keyType, it.key());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700915 if (r < 0)
916 {
917 return r;
918 }
919
Ed Tanous2c70f802020-09-28 14:29:23 -0700920 r = convertJsonToDbus(m, valueType, it.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700921 if (r < 0)
922 {
923 return r;
924 }
925 }
926 r = sd_bus_message_close_container(m);
927 }
928 else
929 {
930 return -2;
931 }
932 if (r < 0)
933 {
934 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700935 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700936
Ed Tanous1abe55e2018-09-05 08:30:59 -0700937 if (argTypes.size() > 1)
938 {
939 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700940 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700941 }
Matt Spinler127ea542019-01-14 11:04:28 -0600942
943 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700944}
945
Matt Spinlerd22a7132019-01-14 12:14:30 -0600946template <typename T>
Patrick Williams59d494e2022-07-22 19:26:55 -0500947int readMessageItem(const std::string& typeCode, sdbusplus::message_t& m,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500948 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600949{
950 T value;
Ed Tanousf79ce6a2024-03-20 12:27:06 -0700951 // When T == char*, this warning fires. Unclear how to resolve
952 // Given that sd-bus takes a void pointer to a char*, and that's
953 // Not something we can fix.
954 // NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600955 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
956 if (r < 0)
957 {
Ed Tanous62598e32023-07-17 17:06:25 -0700958 BMCWEB_LOG_ERROR("sd_bus_message_read_basic on type {} failed!",
959 typeCode);
Matt Spinlerd22a7132019-01-14 12:14:30 -0600960 return r;
961 }
962
963 data = value;
964 return 0;
965}
966
Patrick Williams59d494e2022-07-22 19:26:55 -0500967int convertDBusToJSON(const std::string& returnType, sdbusplus::message_t& m,
968 nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600969
Ed Tanous23a21a12020-07-25 04:45:05 +0000970inline int readDictEntryFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -0500971 sdbusplus::message_t& m,
Ed Tanous23a21a12020-07-25 04:45:05 +0000972 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600973{
974 std::vector<std::string> types = dbusArgSplit(typeCode);
975 if (types.size() != 2)
976 {
Ed Tanous62598e32023-07-17 17:06:25 -0700977 BMCWEB_LOG_ERROR("wrong number contained types in dictionary: {}",
978 types.size());
Matt Spinler6df8f992019-01-14 12:47:47 -0600979 return -1;
980 }
981
982 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
983 typeCode.c_str());
984 if (r < 0)
985 {
Ed Tanous62598e32023-07-17 17:06:25 -0700986 BMCWEB_LOG_ERROR("sd_bus_message_enter_container with rc {}", r);
Matt Spinler6df8f992019-01-14 12:47:47 -0600987 return r;
988 }
989
990 nlohmann::json key;
991 r = convertDBusToJSON(types[0], m, key);
992 if (r < 0)
993 {
994 return r;
995 }
996
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500997 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -0600998 if (keyPtr == nullptr)
999 {
1000 // json doesn't support non-string keys. If we hit this condition,
1001 // convert the result to a string so we can proceed
Ed Tanous71f52d92021-02-19 08:51:17 -08001002 key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001003 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -07001004 // in theory this can't fail now, but lets be paranoid about it
1005 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -06001006 if (keyPtr == nullptr)
1007 {
1008 return -1;
1009 }
1010 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001011 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -06001012
1013 r = convertDBusToJSON(types[1], m, value);
1014 if (r < 0)
1015 {
1016 return r;
1017 }
1018
1019 r = sd_bus_message_exit_container(m.get());
1020 if (r < 0)
1021 {
Ed Tanous62598e32023-07-17 17:06:25 -07001022 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001023 return r;
1024 }
1025
1026 return 0;
1027}
1028
Ed Tanous23a21a12020-07-25 04:45:05 +00001029inline int readArrayFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001030 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -06001031{
1032 if (typeCode.size() < 2)
1033 {
Ed Tanous62598e32023-07-17 17:06:25 -07001034 BMCWEB_LOG_ERROR("Type code {} too small for an array", typeCode);
Matt Spinler6df8f992019-01-14 12:47:47 -06001035 return -1;
1036 }
1037
1038 std::string containedType = typeCode.substr(1);
1039
1040 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
1041 containedType.c_str());
1042 if (r < 0)
1043 {
Ed Tanous62598e32023-07-17 17:06:25 -07001044 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler6df8f992019-01-14 12:47:47 -06001045 return r;
1046 }
1047
Ed Tanous11ba3972022-07-11 09:50:41 -07001048 bool dict = containedType.starts_with("{") && containedType.ends_with("}");
Matt Spinler6df8f992019-01-14 12:47:47 -06001049
1050 if (dict)
1051 {
1052 // Remove the { }
1053 containedType = containedType.substr(1, containedType.size() - 2);
1054 data = nlohmann::json::object();
1055 }
1056 else
1057 {
1058 data = nlohmann::json::array();
1059 }
1060
1061 while (true)
1062 {
Ed Tanouse662eae2022-01-25 10:39:19 -08001063 r = sd_bus_message_at_end(m.get(), 0);
Matt Spinler6df8f992019-01-14 12:47:47 -06001064 if (r < 0)
1065 {
Ed Tanous62598e32023-07-17 17:06:25 -07001066 BMCWEB_LOG_ERROR("sd_bus_message_at_end failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001067 return r;
1068 }
1069
1070 if (r > 0)
1071 {
1072 break;
1073 }
1074
1075 // Dictionaries are only ever seen in an array
1076 if (dict)
1077 {
1078 r = readDictEntryFromMessage(containedType, m, data);
1079 if (r < 0)
1080 {
1081 return r;
1082 }
1083 }
1084 else
1085 {
1086 data.push_back(nlohmann::json());
1087
1088 r = convertDBusToJSON(containedType, m, data.back());
1089 if (r < 0)
1090 {
1091 return r;
1092 }
1093 }
1094 }
1095
1096 r = sd_bus_message_exit_container(m.get());
1097 if (r < 0)
1098 {
Ed Tanous62598e32023-07-17 17:06:25 -07001099 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001100 return r;
1101 }
1102
1103 return 0;
1104}
1105
Ed Tanous23a21a12020-07-25 04:45:05 +00001106inline int readStructFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001107 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001108{
1109 if (typeCode.size() < 3)
1110 {
Ed Tanous62598e32023-07-17 17:06:25 -07001111 BMCWEB_LOG_ERROR("Type code {} too small for a struct", typeCode);
Matt Spinler75c6c672019-01-14 13:01:46 -06001112 return -1;
1113 }
1114
1115 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1116 std::vector<std::string> types = dbusArgSplit(containedTypes);
1117
1118 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1119 containedTypes.c_str());
1120 if (r < 0)
1121 {
Ed Tanous62598e32023-07-17 17:06:25 -07001122 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler75c6c672019-01-14 13:01:46 -06001123 return r;
1124 }
1125
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001126 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001127 {
1128 data.push_back(nlohmann::json());
1129 r = convertDBusToJSON(type, m, data.back());
1130 if (r < 0)
1131 {
1132 return r;
1133 }
1134 }
1135
1136 r = sd_bus_message_exit_container(m.get());
1137 if (r < 0)
1138 {
Ed Tanous62598e32023-07-17 17:06:25 -07001139 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler75c6c672019-01-14 13:01:46 -06001140 return r;
1141 }
1142 return 0;
1143}
1144
Patrick Williams59d494e2022-07-22 19:26:55 -05001145inline int readVariantFromMessage(sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001146{
Ed Tanous543f4402022-01-06 13:12:53 -08001147 const char* containerType = nullptr;
Ed Tanous99131cd2019-10-24 11:12:47 -07001148 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001149 if (r < 0)
1150 {
Ed Tanous62598e32023-07-17 17:06:25 -07001151 BMCWEB_LOG_ERROR("sd_bus_message_peek_type failed");
Matt Spinler89c19702019-01-14 13:13:00 -06001152 return r;
1153 }
1154
1155 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1156 containerType);
1157 if (r < 0)
1158 {
Ed Tanous62598e32023-07-17 17:06:25 -07001159 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler89c19702019-01-14 13:13:00 -06001160 return r;
1161 }
1162
1163 r = convertDBusToJSON(containerType, m, data);
1164 if (r < 0)
1165 {
1166 return r;
1167 }
1168
1169 r = sd_bus_message_exit_container(m.get());
1170 if (r < 0)
1171 {
Ed Tanous62598e32023-07-17 17:06:25 -07001172 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed");
Matt Spinler89c19702019-01-14 13:13:00 -06001173 return r;
1174 }
1175
1176 return 0;
1177}
1178
Ed Tanous23a21a12020-07-25 04:45:05 +00001179inline int convertDBusToJSON(const std::string& returnType,
Patrick Williams59d494e2022-07-22 19:26:55 -05001180 sdbusplus::message_t& m, nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001181{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001182 int r = 0;
1183 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1184
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001185 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001186 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001187 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001188 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001189 {
1190 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001191 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001192 }
1193
Ed Tanousd4d25792020-09-29 15:15:03 -07001194 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001195 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001196 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001197 if (r < 0)
1198 {
1199 return r;
1200 }
1201 }
1202 else if (typeCode == "b")
1203 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001204 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001205 if (r < 0)
1206 {
1207 return r;
1208 }
1209
Matt Spinlerf39420c2019-01-30 12:57:18 -06001210 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001211 }
1212 else if (typeCode == "u")
1213 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001214 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001215 if (r < 0)
1216 {
1217 return r;
1218 }
1219 }
1220 else if (typeCode == "i")
1221 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001222 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001223 if (r < 0)
1224 {
1225 return r;
1226 }
1227 }
1228 else if (typeCode == "x")
1229 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001230 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001231 if (r < 0)
1232 {
1233 return r;
1234 }
1235 }
1236 else if (typeCode == "t")
1237 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001238 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001239 if (r < 0)
1240 {
1241 return r;
1242 }
1243 }
1244 else if (typeCode == "n")
1245 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001246 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001247 if (r < 0)
1248 {
1249 return r;
1250 }
1251 }
1252 else if (typeCode == "q")
1253 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001254 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001255 if (r < 0)
1256 {
1257 return r;
1258 }
1259 }
1260 else if (typeCode == "y")
1261 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001262 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001263 if (r < 0)
1264 {
1265 return r;
1266 }
1267 }
1268 else if (typeCode == "d")
1269 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001270 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001271 if (r < 0)
1272 {
1273 return r;
1274 }
1275 }
1276 else if (typeCode == "h")
1277 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001278 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001279 if (r < 0)
1280 {
1281 return r;
1282 }
1283 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001284 else if (typeCode.starts_with("a"))
Matt Spinler6df8f992019-01-14 12:47:47 -06001285 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001286 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001287 if (r < 0)
1288 {
1289 return r;
1290 }
1291 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001292 else if (typeCode.starts_with("(") && typeCode.ends_with(")"))
Matt Spinler75c6c672019-01-14 13:01:46 -06001293 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001294 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001295 if (r < 0)
1296 {
1297 return r;
1298 }
1299 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001300 else if (typeCode.starts_with("v"))
Matt Spinler89c19702019-01-14 13:13:00 -06001301 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001302 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001303 if (r < 0)
1304 {
1305 return r;
1306 }
1307 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001308 else
1309 {
Ed Tanous62598e32023-07-17 17:06:25 -07001310 BMCWEB_LOG_ERROR("Invalid D-Bus signature type {}", typeCode);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001311 return -2;
1312 }
1313 }
1314
Matt Spinler16caaee2019-01-15 11:40:34 -06001315 return 0;
1316}
1317
Ed Tanousb5a76932020-09-29 16:16:58 -07001318inline void handleMethodResponse(
1319 const std::shared_ptr<InProgressActionData>& transaction,
Patrick Williams59d494e2022-07-22 19:26:55 -05001320 sdbusplus::message_t& m, const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001321{
Matt Spinler39a4e392019-01-15 11:53:13 -06001322 nlohmann::json data;
1323
1324 int r = convertDBusToJSON(returnType, m, data);
1325 if (r < 0)
1326 {
1327 transaction->outputFailed = true;
1328 return;
1329 }
1330
1331 if (data.is_null())
1332 {
1333 return;
1334 }
1335
1336 if (transaction->methodResponse.is_null())
1337 {
1338 transaction->methodResponse = std::move(data);
1339 return;
1340 }
1341
1342 // If they're both dictionaries or arrays, merge into one.
1343 // Otherwise, make the results an array with every result
1344 // an entry. Could also just fail in that case, but it
1345 // seems better to get the data back somehow.
1346
1347 if (transaction->methodResponse.is_object() && data.is_object())
1348 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001349 for (const auto& obj : data.items())
Matt Spinler39a4e392019-01-15 11:53:13 -06001350 {
1351 // Note: Will overwrite the data for a duplicate key
1352 transaction->methodResponse.emplace(obj.key(),
1353 std::move(obj.value()));
1354 }
1355 return;
1356 }
1357
1358 if (transaction->methodResponse.is_array() && data.is_array())
1359 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001360 for (auto& obj : data)
Matt Spinler39a4e392019-01-15 11:53:13 -06001361 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001362 transaction->methodResponse.emplace_back(std::move(obj));
Matt Spinler39a4e392019-01-15 11:53:13 -06001363 }
1364 return;
1365 }
1366
1367 if (!transaction->convertedToArray)
1368 {
1369 // They are different types. May as well turn them into an array
1370 nlohmann::json j = std::move(transaction->methodResponse);
1371 transaction->methodResponse = nlohmann::json::array();
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001372 transaction->methodResponse.emplace_back(std::move(j));
1373 transaction->methodResponse.emplace_back(std::move(data));
Matt Spinler39a4e392019-01-15 11:53:13 -06001374 transaction->convertedToArray = true;
1375 }
1376 else
1377 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001378 transaction->methodResponse.emplace_back(std::move(data));
Matt Spinler39a4e392019-01-15 11:53:13 -06001379 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001380}
1381
Ed Tanousb5a76932020-09-29 16:16:58 -07001382inline void findActionOnInterface(
1383 const std::shared_ptr<InProgressActionData>& transaction,
1384 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001385{
Ed Tanous62598e32023-07-17 17:06:25 -07001386 BMCWEB_LOG_DEBUG("findActionOnInterface for connection {}", connectionName);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001387 crow::connections::systemBus->async_method_call(
1388 [transaction, connectionName{std::string(connectionName)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001389 const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001390 const std::string& introspectXml) {
Ed Tanous62598e32023-07-17 17:06:25 -07001391 BMCWEB_LOG_DEBUG("got xml:\n {}", introspectXml);
Ed Tanous002d39b2022-05-31 08:59:27 -07001392 if (ec)
1393 {
Ed Tanous62598e32023-07-17 17:06:25 -07001394 BMCWEB_LOG_ERROR(
1395 "Introspect call failed with error: {} on process: {}",
1396 ec.message(), connectionName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001397 return;
1398 }
1399 tinyxml2::XMLDocument doc;
Matt Spinler318bd892019-01-15 09:59:20 -06001400
Ed Tanous002d39b2022-05-31 08:59:27 -07001401 doc.Parse(introspectXml.data(), introspectXml.size());
1402 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1403 if (pRoot == nullptr)
1404 {
Ed Tanous62598e32023-07-17 17:06:25 -07001405 BMCWEB_LOG_ERROR("XML document failed to parse {}", connectionName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001406 return;
1407 }
1408 tinyxml2::XMLElement* interfaceNode =
1409 pRoot->FirstChildElement("interface");
1410 while (interfaceNode != nullptr)
1411 {
1412 const char* thisInterfaceName = interfaceNode->Attribute("name");
1413 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001414 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001415 if (!transaction->interfaceName.empty() &&
1416 (transaction->interfaceName != thisInterfaceName))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001417 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001418 interfaceNode =
1419 interfaceNode->NextSiblingElement("interface");
1420 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001421 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001422
1423 tinyxml2::XMLElement* methodNode =
1424 interfaceNode->FirstChildElement("method");
1425 while (methodNode != nullptr)
1426 {
1427 const char* thisMethodName = methodNode->Attribute("name");
Ed Tanous62598e32023-07-17 17:06:25 -07001428 BMCWEB_LOG_DEBUG("Found method: {}", thisMethodName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001429 if (thisMethodName != nullptr &&
1430 thisMethodName == transaction->methodName)
1431 {
Ed Tanous62598e32023-07-17 17:06:25 -07001432 BMCWEB_LOG_DEBUG(
1433 "Found method named {} on interface {}",
1434 thisMethodName, thisInterfaceName);
Patrick Williams59d494e2022-07-22 19:26:55 -05001435 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001436 crow::connections::systemBus->new_method_call(
1437 connectionName.c_str(),
1438 transaction->path.c_str(), thisInterfaceName,
1439 transaction->methodName.c_str());
1440
1441 tinyxml2::XMLElement* argumentNode =
1442 methodNode->FirstChildElement("arg");
1443
1444 std::string returnType;
1445
1446 // Find the output type
1447 while (argumentNode != nullptr)
1448 {
1449 const char* argDirection =
1450 argumentNode->Attribute("direction");
1451 const char* argType =
1452 argumentNode->Attribute("type");
1453 if (argDirection != nullptr && argType != nullptr &&
1454 std::string(argDirection) == "out")
1455 {
1456 returnType = argType;
1457 break;
1458 }
1459 argumentNode =
1460 argumentNode->NextSiblingElement("arg");
1461 }
1462
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001463 auto argIt = transaction->arguments.begin();
Ed Tanous002d39b2022-05-31 08:59:27 -07001464
1465 argumentNode = methodNode->FirstChildElement("arg");
1466
1467 while (argumentNode != nullptr)
1468 {
1469 const char* argDirection =
1470 argumentNode->Attribute("direction");
1471 const char* argType =
1472 argumentNode->Attribute("type");
1473 if (argDirection != nullptr && argType != nullptr &&
1474 std::string(argDirection) == "in")
1475 {
1476 if (argIt == transaction->arguments.end())
1477 {
1478 transaction->setErrorStatus(
1479 "Invalid method args");
1480 return;
1481 }
1482 if (convertJsonToDbus(m.get(),
1483 std::string(argType),
1484 *argIt) < 0)
1485 {
1486 transaction->setErrorStatus(
1487 "Invalid method arg type");
1488 return;
1489 }
1490
1491 argIt++;
1492 }
1493 argumentNode =
1494 argumentNode->NextSiblingElement("arg");
1495 }
1496
1497 crow::connections::systemBus->async_send(
Patrick Williams5a39f772023-10-20 11:20:21 -05001498 m, [transaction, returnType](
1499 const boost::system::error_code& ec2,
1500 sdbusplus::message_t& m2) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001501 if (ec2)
1502 {
1503 transaction->methodFailed = true;
1504 const sd_bus_error* e = m2.get_error();
1505
1506 if (e != nullptr)
1507 {
1508 setErrorResponse(
Lei YU28dd5ca2023-03-17 13:17:05 +08001509 transaction->asyncResp->res,
Ed Tanous002d39b2022-05-31 08:59:27 -07001510 boost::beast::http::status::bad_request,
1511 e->name, e->message);
1512 }
1513 else
1514 {
1515 setErrorResponse(
Lei YU28dd5ca2023-03-17 13:17:05 +08001516 transaction->asyncResp->res,
Ed Tanous002d39b2022-05-31 08:59:27 -07001517 boost::beast::http::status::bad_request,
1518 "Method call failed", methodFailedMsg);
1519 }
1520 return;
1521 }
1522 transaction->methodPassed = true;
1523
1524 handleMethodResponse(transaction, m2, returnType);
Patrick Williams5a39f772023-10-20 11:20:21 -05001525 });
Ed Tanous002d39b2022-05-31 08:59:27 -07001526 break;
1527 }
1528 methodNode = methodNode->NextSiblingElement("method");
1529 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001530 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001531 interfaceNode = interfaceNode->NextSiblingElement("interface");
1532 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001533 },
Ed Tanous1abe55e2018-09-05 08:30:59 -07001534 connectionName, transaction->path,
1535 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001536}
1537
zhanghch058d1b46d2021-04-01 11:18:24 +08001538inline void handleAction(const crow::Request& req,
1539 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001540 const std::string& objectPath,
1541 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001542{
Ed Tanous62598e32023-07-17 17:06:25 -07001543 BMCWEB_LOG_DEBUG("handleAction on path: {} and method {}", objectPath,
1544 methodName);
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001545 nlohmann::json requestDbusData;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001546
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001547 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
1548 if (ret == JsonParseResult::BadContentType)
1549 {
1550 setErrorResponse(asyncResp->res,
1551 boost::beast::http::status::unsupported_media_type,
1552 invalidContentType, unsupportedMediaMsg);
1553 return;
1554 }
1555 if (ret != JsonParseResult::Success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001556 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001557 setErrorResponse(asyncResp->res,
1558 boost::beast::http::status::bad_request, noJsonDesc,
1559 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001560 return;
1561 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001562 nlohmann::json::iterator data = requestDbusData.find("data");
1563 if (data == requestDbusData.end())
1564 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001565 setErrorResponse(asyncResp->res,
1566 boost::beast::http::status::bad_request, noJsonDesc,
1567 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001568 return;
1569 }
1570
1571 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001572 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001573 setErrorResponse(asyncResp->res,
1574 boost::beast::http::status::bad_request, noJsonDesc,
1575 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001576 return;
1577 }
Lei YU28dd5ca2023-03-17 13:17:05 +08001578 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001579
1580 transaction->path = objectPath;
1581 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001582 transaction->arguments = std::move(*data);
George Liu2b731192023-01-11 16:27:13 +08001583 dbus::utility::getDbusObject(
1584 objectPath, {},
Ed Tanous1abe55e2018-09-05 08:30:59 -07001585 [transaction](
George Liu2b731192023-01-11 16:27:13 +08001586 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001587 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1588 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001589 if (ec || interfaceNames.empty())
1590 {
Ed Tanous62598e32023-07-17 17:06:25 -07001591 BMCWEB_LOG_ERROR("Can't find object");
Lei YU28dd5ca2023-03-17 13:17:05 +08001592 setErrorResponse(transaction->asyncResp->res,
Ed Tanous002d39b2022-05-31 08:59:27 -07001593 boost::beast::http::status::not_found,
1594 notFoundDesc, notFoundMsg);
1595 return;
1596 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001597
Ed Tanous62598e32023-07-17 17:06:25 -07001598 BMCWEB_LOG_DEBUG("GetObject returned {} object(s)",
1599 interfaceNames.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001600
Ed Tanous002d39b2022-05-31 08:59:27 -07001601 for (const std::pair<std::string, std::vector<std::string>>& object :
1602 interfaceNames)
1603 {
1604 findActionOnInterface(transaction, object.first);
1605 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001606 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001607}
1608
zhanghch058d1b46d2021-04-01 11:18:24 +08001609inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1610 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001611{
Ed Tanous62598e32023-07-17 17:06:25 -07001612 BMCWEB_LOG_DEBUG("handleDelete on path: {}", objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06001613
George Liu2b731192023-01-11 16:27:13 +08001614 dbus::utility::getDbusObject(
1615 objectPath, {},
zhanghch058d1b46d2021-04-01 11:18:24 +08001616 [asyncResp, objectPath](
George Liu2b731192023-01-11 16:27:13 +08001617 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001618 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1619 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001620 if (ec || interfaceNames.empty())
1621 {
Ed Tanous62598e32023-07-17 17:06:25 -07001622 BMCWEB_LOG_ERROR("Can't find object");
Ed Tanous002d39b2022-05-31 08:59:27 -07001623 setErrorResponse(asyncResp->res,
1624 boost::beast::http::status::method_not_allowed,
1625 methodNotAllowedDesc, methodNotAllowedMsg);
1626 return;
1627 }
Matt Spinlerde818812018-12-11 16:39:20 -06001628
Lei YU28dd5ca2023-03-17 13:17:05 +08001629 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001630 transaction->path = objectPath;
1631 transaction->methodName = "Delete";
1632 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
Matt Spinlerde818812018-12-11 16:39:20 -06001633
Ed Tanous002d39b2022-05-31 08:59:27 -07001634 for (const std::pair<std::string, std::vector<std::string>>& object :
1635 interfaceNames)
1636 {
1637 findActionOnInterface(transaction, object.first);
1638 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001639 });
Matt Spinlerde818812018-12-11 16:39:20 -06001640}
1641
zhanghch058d1b46d2021-04-01 11:18:24 +08001642inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1643 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001644{
George Liu7a1dbc42022-12-07 16:03:22 +08001645 dbus::utility::getSubTreePaths(
1646 objectPath, depth, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001647 [asyncResp](
George Liu7a1dbc42022-12-07 16:03:22 +08001648 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001649 const dbus::utility::MapperGetSubTreePathsResponse& objectPaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001650 if (ec)
1651 {
1652 setErrorResponse(asyncResp->res,
1653 boost::beast::http::status::not_found,
1654 notFoundDesc, notFoundMsg);
1655 }
1656 else
1657 {
1658 asyncResp->res.jsonValue["status"] = "ok";
1659 asyncResp->res.jsonValue["message"] = "200 OK";
1660 asyncResp->res.jsonValue["data"] = objectPaths;
1661 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001662 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001663}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001664
zhanghch058d1b46d2021-04-01 11:18:24 +08001665inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1666 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001667{
Ed Tanous62598e32023-07-17 17:06:25 -07001668 BMCWEB_LOG_DEBUG("Doing enumerate on {}", objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07001669
Ed Tanous14766872022-03-15 10:44:42 -07001670 asyncResp->res.jsonValue["message"] = "200 OK";
1671 asyncResp->res.jsonValue["status"] = "ok";
1672 asyncResp->res.jsonValue["data"] = nlohmann::json::object();
Ed Tanous049a0512018-11-01 13:58:42 -07001673
George Liue99073f2022-12-09 11:06:16 +08001674 dbus::utility::getSubTree(
1675 objectPath, 0, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001676 [objectPath, asyncResp](
George Liue99073f2022-12-09 11:06:16 +08001677 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001678 const dbus::utility::MapperGetSubTreeResponse& objectNames) {
Patrick Williams89492a12023-05-10 07:51:34 -05001679 auto transaction = std::make_shared<InProgressEnumerateData>(objectPath,
1680 asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001681
Ed Tanous002d39b2022-05-31 08:59:27 -07001682 transaction->subtree =
1683 std::make_shared<dbus::utility::MapperGetSubTreeResponse>(
1684 objectNames);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001685
Ed Tanous002d39b2022-05-31 08:59:27 -07001686 if (ec)
1687 {
Ed Tanous62598e32023-07-17 17:06:25 -07001688 BMCWEB_LOG_ERROR("GetSubTree failed on {}",
1689 transaction->objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07001690 setErrorResponse(transaction->asyncResp->res,
1691 boost::beast::http::status::not_found,
1692 notFoundDesc, notFoundMsg);
1693 return;
1694 }
Ed Tanous64530012018-02-06 17:08:16 -08001695
Ed Tanous002d39b2022-05-31 08:59:27 -07001696 // Add the data for the path passed in to the results
1697 // as if GetSubTree returned it, and continue on enumerating
1698 getObjectAndEnumerate(transaction);
Patrick Williams5a39f772023-10-20 11:20:21 -05001699 });
Ed Tanous64530012018-02-06 17:08:16 -08001700}
Ed Tanous911ac312017-08-15 09:37:42 -07001701
zhanghch058d1b46d2021-04-01 11:18:24 +08001702inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1703 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001704{
Ed Tanous62598e32023-07-17 17:06:25 -07001705 BMCWEB_LOG_DEBUG("handleGet: {} prop:{}", objectPath, destProperty);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001706 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001707 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001708
Ed Tanous1abe55e2018-09-05 08:30:59 -07001709 std::shared_ptr<std::string> path =
1710 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001711
George Liu2b731192023-01-11 16:27:13 +08001712 dbus::utility::getDbusObject(
1713 *path, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001714 [asyncResp, path,
George Liu2b731192023-01-11 16:27:13 +08001715 propertyName](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001716 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001717 if (ec || objectNames.empty())
1718 {
1719 setErrorResponse(asyncResp->res,
1720 boost::beast::http::status::not_found,
1721 notFoundDesc, notFoundMsg);
1722 return;
1723 }
1724 std::shared_ptr<nlohmann::json> response =
1725 std::make_shared<nlohmann::json>(nlohmann::json::object());
1726 // The mapper should never give us an empty interface names
1727 // list, but check anyway
1728 for (const std::pair<std::string, std::vector<std::string>>&
1729 connection : objectNames)
1730 {
1731 const std::vector<std::string>& interfaceNames = connection.second;
1732
1733 if (interfaceNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001734 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001735 setErrorResponse(asyncResp->res,
1736 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001737 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001738 return;
1739 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001740
1741 for (const std::string& interface : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001742 {
Patrick Williams59d494e2022-07-22 19:26:55 -05001743 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001744 crow::connections::systemBus->new_method_call(
1745 connection.first.c_str(), path->c_str(),
1746 "org.freedesktop.DBus.Properties", "GetAll");
1747 m.append(interface);
1748 crow::connections::systemBus->async_send(
1749 m, [asyncResp, response,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001750 propertyName](const boost::system::error_code& ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05001751 sdbusplus::message_t& msg) {
Patrick Williams5a39f772023-10-20 11:20:21 -05001752 if (ec2)
1753 {
1754 BMCWEB_LOG_ERROR("Bad dbus request error: {}", ec2);
1755 }
1756 else
1757 {
1758 nlohmann::json properties;
1759 int r = convertDBusToJSON("a{sv}", msg, properties);
1760 if (r < 0)
Ed Tanous002d39b2022-05-31 08:59:27 -07001761 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001762 BMCWEB_LOG_ERROR("convertDBusToJSON failed");
Ed Tanous002d39b2022-05-31 08:59:27 -07001763 }
1764 else
1765 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001766 for (const auto& prop : properties.items())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001767 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001768 // if property name is empty, or
1769 // matches our search query, add it
1770 // to the response json
Ed Tanous1abe55e2018-09-05 08:30:59 -07001771
Patrick Williams5a39f772023-10-20 11:20:21 -05001772 if (propertyName->empty())
1773 {
1774 (*response)[prop.key()] =
1775 std::move(prop.value());
1776 }
1777 else if (prop.key() == *propertyName)
1778 {
1779 *response = std::move(prop.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001780 }
1781 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001782 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001783 }
1784 if (response.use_count() == 1)
1785 {
1786 if (!propertyName->empty() && response->empty())
Ed Tanous002d39b2022-05-31 08:59:27 -07001787 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001788 setErrorResponse(
1789 asyncResp->res,
1790 boost::beast::http::status::not_found,
1791 propNotFoundDesc, notFoundMsg);
Ed Tanous002d39b2022-05-31 08:59:27 -07001792 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001793 else
1794 {
1795 asyncResp->res.jsonValue["status"] = "ok";
1796 asyncResp->res.jsonValue["message"] = "200 OK";
1797 asyncResp->res.jsonValue["data"] = *response;
1798 }
1799 }
1800 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001801 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001802 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001803 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001804}
1805
Ed Tanous1abe55e2018-09-05 08:30:59 -07001806struct AsyncPutRequest
1807{
Ed Tanous4e23a442022-06-06 09:57:26 -07001808 explicit AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
zhanghch058d1b46d2021-04-01 11:18:24 +08001809 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001810 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001811 ~AsyncPutRequest()
1812 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001813 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001814 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001815 setErrorResponse(asyncResp->res,
1816 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001817 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001818 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001819 }
1820
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001821 AsyncPutRequest(const AsyncPutRequest&) = delete;
1822 AsyncPutRequest(AsyncPutRequest&&) = delete;
1823 AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1824 AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1825
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001826 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001827 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001828 setErrorResponse(asyncResp->res,
1829 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001830 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001831 }
1832
zhanghch058d1b46d2021-04-01 11:18:24 +08001833 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001834 std::string objectPath;
1835 std::string propertyName;
1836 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001837};
1838
zhanghch058d1b46d2021-04-01 11:18:24 +08001839inline void handlePut(const crow::Request& req,
1840 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001841 const std::string& objectPath,
1842 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001843{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001844 if (destProperty.empty())
1845 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001846 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001847 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001848 return;
1849 }
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001850 nlohmann::json requestDbusData;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001851
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001852 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
1853 if (ret == JsonParseResult::BadContentType)
1854 {
1855 setErrorResponse(asyncResp->res,
1856 boost::beast::http::status::unsupported_media_type,
1857 invalidContentType, unsupportedMediaMsg);
1858 return;
1859 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001860
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001861 if (ret != JsonParseResult::Success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001862 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001863 setErrorResponse(asyncResp->res,
1864 boost::beast::http::status::bad_request, noJsonDesc,
1865 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001866 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001867 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001868
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001869 auto propertyIt = requestDbusData.find("data");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001870 if (propertyIt == requestDbusData.end())
1871 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001872 setErrorResponse(asyncResp->res,
1873 boost::beast::http::status::bad_request, noJsonDesc,
1874 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001875 return;
1876 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001877 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001878 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001879 transaction->objectPath = objectPath;
1880 transaction->propertyName = destProperty;
1881 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001882
George Liu2b731192023-01-11 16:27:13 +08001883 dbus::utility::getDbusObject(
1884 transaction->objectPath, {},
1885 [transaction](const boost::system::error_code& ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001886 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001887 if (!ec2 && objectNames.empty())
1888 {
1889 setErrorResponse(transaction->asyncResp->res,
1890 boost::beast::http::status::not_found,
1891 propNotFoundDesc, notFoundMsg);
1892 return;
1893 }
Ed Tanous911ac312017-08-15 09:37:42 -07001894
Ed Tanous002d39b2022-05-31 08:59:27 -07001895 for (const std::pair<std::string, std::vector<std::string>>&
1896 connection : objectNames)
1897 {
1898 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001899
Ed Tanous002d39b2022-05-31 08:59:27 -07001900 crow::connections::systemBus->async_method_call(
1901 [connectionName{std::string(connectionName)},
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001902 transaction](const boost::system::error_code& ec3,
Ed Tanous002d39b2022-05-31 08:59:27 -07001903 const std::string& introspectXml) {
1904 if (ec3)
1905 {
Ed Tanous62598e32023-07-17 17:06:25 -07001906 BMCWEB_LOG_ERROR(
1907 "Introspect call failed with error: {} on process: {}",
1908 ec3.message(), connectionName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001909 transaction->setErrorStatus("Unexpected Error");
1910 return;
1911 }
1912 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001913
Ed Tanous002d39b2022-05-31 08:59:27 -07001914 doc.Parse(introspectXml.c_str());
1915 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1916 if (pRoot == nullptr)
1917 {
Ed Tanous62598e32023-07-17 17:06:25 -07001918 BMCWEB_LOG_ERROR("XML document failed to parse: {}",
1919 introspectXml);
Ed Tanous002d39b2022-05-31 08:59:27 -07001920 transaction->setErrorStatus("Unexpected Error");
1921 return;
1922 }
1923 tinyxml2::XMLElement* ifaceNode =
1924 pRoot->FirstChildElement("interface");
1925 while (ifaceNode != nullptr)
1926 {
1927 const char* interfaceName = ifaceNode->Attribute("name");
Ed Tanous62598e32023-07-17 17:06:25 -07001928 BMCWEB_LOG_DEBUG("found interface {}", interfaceName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001929 tinyxml2::XMLElement* propNode =
1930 ifaceNode->FirstChildElement("property");
1931 while (propNode != nullptr)
1932 {
1933 const char* propertyName = propNode->Attribute("name");
Ed Tanous62598e32023-07-17 17:06:25 -07001934 BMCWEB_LOG_DEBUG("Found property {}", propertyName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001935 if (propertyName == transaction->propertyName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001936 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001937 const char* argType = propNode->Attribute("type");
1938 if (argType != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001939 {
Patrick Williams59d494e2022-07-22 19:26:55 -05001940 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001941 crow::connections::systemBus
1942 ->new_method_call(
1943 connectionName.c_str(),
1944 transaction->objectPath.c_str(),
1945 "org.freedesktop.DBus."
1946 "Properties",
1947 "Set");
1948 m.append(interfaceName,
1949 transaction->propertyName);
1950 int r = sd_bus_message_open_container(
1951 m.get(), SD_BUS_TYPE_VARIANT, argType);
1952 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001953 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001954 transaction->setErrorStatus(
1955 "Unexpected Error");
1956 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001957 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001958 r = convertJsonToDbus(
1959 m.get(), argType,
1960 transaction->propertyValue);
1961 if (r < 0)
1962 {
1963 if (r == -ERANGE)
1964 {
1965 transaction->setErrorStatus(
1966 "Provided property value "
1967 "is out of range for the "
1968 "property type");
1969 }
1970 else
1971 {
1972 transaction->setErrorStatus(
1973 "Invalid arg type");
1974 }
1975 return;
1976 }
1977 r = sd_bus_message_close_container(m.get());
1978 if (r < 0)
1979 {
1980 transaction->setErrorStatus(
1981 "Unexpected Error");
1982 return;
1983 }
1984 crow::connections::systemBus->async_send(
Patrick Williams5a39f772023-10-20 11:20:21 -05001985 m, [transaction](
1986 const boost::system::error_code& ec,
1987 sdbusplus::message_t& m2) {
Ed Tanous62598e32023-07-17 17:06:25 -07001988 BMCWEB_LOG_DEBUG("sent");
Ed Tanous002d39b2022-05-31 08:59:27 -07001989 if (ec)
1990 {
1991 const sd_bus_error* e = m2.get_error();
1992 setErrorResponse(
1993 transaction->asyncResp->res,
1994 boost::beast::http::status::
1995 forbidden,
1996 (e) != nullptr
1997 ? e->name
1998 : ec.category().name(),
1999 (e) != nullptr ? e->message
2000 : ec.message());
2001 }
2002 else
2003 {
2004 transaction->asyncResp->res
2005 .jsonValue["status"] = "ok";
2006 transaction->asyncResp->res
2007 .jsonValue["message"] = "200 OK";
2008 transaction->asyncResp->res
2009 .jsonValue["data"] = nullptr;
2010 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002011 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002012 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002013 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002014 propNode = propNode->NextSiblingElement("property");
2015 }
2016 ifaceNode = ifaceNode->NextSiblingElement("interface");
2017 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002018 },
Ed Tanous002d39b2022-05-31 08:59:27 -07002019 connectionName, transaction->objectPath,
2020 "org.freedesktop.DBus.Introspectable", "Introspect");
2021 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002022 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07002023}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002024
zhanghch058d1b46d2021-04-01 11:18:24 +08002025inline void handleDBusUrl(const crow::Request& req,
2026 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002027 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002028{
Ed Tanous049a0512018-11-01 13:58:42 -07002029 // If accessing a single attribute, fill in and update objectPath,
2030 // otherwise leave destProperty blank
Ed Tanouse05aec52022-01-25 10:28:56 -08002031 std::string destProperty;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002032 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002033 size_t attrPosition = objectPath.find(attrSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002034 if (attrPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002035 {
2036 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2037 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002038 objectPath.resize(attrPosition);
Ed Tanous049a0512018-11-01 13:58:42 -07002039 }
2040
Ed Tanousb41187f2019-10-24 16:30:02 -07002041 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002042 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002043 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002044 size_t actionPosition = objectPath.find(actionSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002045 if (actionPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002046 {
2047 std::string postProperty =
2048 objectPath.substr((actionPosition + strlen(actionSeperator)),
2049 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002050 objectPath.resize(actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002051 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002052 return;
2053 }
2054 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002055 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002056 {
Ed Tanous11ba3972022-07-11 09:50:41 -07002057 if (objectPath.ends_with("/enumerate"))
Ed Tanous049a0512018-11-01 13:58:42 -07002058 {
2059 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2060 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002061 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002062 }
Ed Tanous11ba3972022-07-11 09:50:41 -07002063 else if (objectPath.ends_with("/list"))
Ed Tanous049a0512018-11-01 13:58:42 -07002064 {
2065 objectPath.erase(objectPath.end() - sizeof("list"),
2066 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002067 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002068 }
2069 else
2070 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002071 // Trim any trailing "/" at the end
Ed Tanous11ba3972022-07-11 09:50:41 -07002072 if (objectPath.ends_with("/"))
Ed Tanousf839dfe2018-11-12 11:11:15 -08002073 {
2074 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002075 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002076 }
2077 else
2078 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002079 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002080 }
Ed Tanous049a0512018-11-01 13:58:42 -07002081 }
2082 return;
2083 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002084 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002085 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002086 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002087 return;
2088 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002089 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002090 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002091 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002092 return;
2093 }
Ed Tanous049a0512018-11-01 13:58:42 -07002094
zhanghch058d1b46d2021-04-01 11:18:24 +08002095 setErrorResponse(asyncResp->res,
2096 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002097 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002098}
2099
Ed Tanous1656b292022-05-04 11:33:42 -07002100inline void
2101 handleBusSystemPost(const crow::Request& req,
2102 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2103 const std::string& processName,
2104 const std::string& requestedPath)
2105{
2106 std::vector<std::string> strs;
Ed Tanous50ebd4a2023-01-19 19:03:17 -08002107
2108 bmcweb::split(strs, requestedPath, '/');
Ed Tanous1656b292022-05-04 11:33:42 -07002109 std::string objectPath;
2110 std::string interfaceName;
2111 std::string methodName;
2112 auto it = strs.begin();
2113 if (it == strs.end())
2114 {
2115 objectPath = "/";
2116 }
2117 while (it != strs.end())
2118 {
2119 // Check if segment contains ".". If it does, it must be an
2120 // interface
2121 if (it->find(".") != std::string::npos)
2122 {
2123 break;
2124 // This check is necessary as the trailing slash gets
2125 // parsed as part of our <path> specifier above, which
2126 // causes the normal trailing backslash redirector to
2127 // fail.
2128 }
2129 if (!it->empty())
2130 {
2131 objectPath += "/" + *it;
2132 }
2133 it++;
2134 }
2135 if (it != strs.end())
2136 {
2137 interfaceName = *it;
2138 it++;
2139
2140 // after interface, we might have a method name
2141 if (it != strs.end())
2142 {
2143 methodName = *it;
2144 it++;
2145 }
2146 }
2147 if (it != strs.end())
2148 {
2149 // if there is more levels past the method name, something
2150 // went wrong, return not found
2151 asyncResp->res.result(boost::beast::http::status::not_found);
2152 return;
2153 }
2154 if (interfaceName.empty())
2155 {
2156 crow::connections::systemBus->async_method_call(
2157 [asyncResp, processName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002158 objectPath](const boost::system::error_code& ec,
Ed Tanous1656b292022-05-04 11:33:42 -07002159 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002160 if (ec)
2161 {
Ed Tanous62598e32023-07-17 17:06:25 -07002162 BMCWEB_LOG_ERROR(
2163 "Introspect call failed with error: {} on process: {} path: {}",
2164 ec.message(), processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002165 return;
2166 }
2167 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002168
Ed Tanous002d39b2022-05-31 08:59:27 -07002169 doc.Parse(introspectXml.c_str());
2170 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2171 if (pRoot == nullptr)
2172 {
Ed Tanous62598e32023-07-17 17:06:25 -07002173 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
2174 processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002175 asyncResp->res.jsonValue["status"] = "XML parse error";
2176 asyncResp->res.result(
2177 boost::beast::http::status::internal_server_error);
2178 return;
2179 }
2180
Ed Tanous62598e32023-07-17 17:06:25 -07002181 BMCWEB_LOG_DEBUG("{}", introspectXml);
Ed Tanous002d39b2022-05-31 08:59:27 -07002182 asyncResp->res.jsonValue["status"] = "ok";
2183 asyncResp->res.jsonValue["bus_name"] = processName;
2184 asyncResp->res.jsonValue["object_path"] = objectPath;
2185
2186 nlohmann::json& interfacesArray =
2187 asyncResp->res.jsonValue["interfaces"];
2188 interfacesArray = nlohmann::json::array();
2189 tinyxml2::XMLElement* interface =
2190 pRoot->FirstChildElement("interface");
2191
2192 while (interface != nullptr)
2193 {
2194 const char* ifaceName = interface->Attribute("name");
2195 if (ifaceName != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002196 {
Ed Tanous8a592812022-06-04 09:06:59 -07002197 nlohmann::json::object_t interfaceObj;
2198 interfaceObj["name"] = ifaceName;
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002199 interfacesArray.emplace_back(std::move(interfaceObj));
Ed Tanous1656b292022-05-04 11:33:42 -07002200 }
2201
Ed Tanous002d39b2022-05-31 08:59:27 -07002202 interface = interface->NextSiblingElement("interface");
2203 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002204 },
Ed Tanous1656b292022-05-04 11:33:42 -07002205 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2206 "Introspect");
2207 }
2208 else if (methodName.empty())
2209 {
2210 crow::connections::systemBus->async_method_call(
2211 [asyncResp, processName, objectPath,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002212 interfaceName](const boost::system::error_code& ec,
Ed Tanous1656b292022-05-04 11:33:42 -07002213 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002214 if (ec)
2215 {
Ed Tanous62598e32023-07-17 17:06:25 -07002216 BMCWEB_LOG_ERROR(
2217 "Introspect call failed with error: {} on process: {} path: {}",
2218 ec.message(), processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002219 return;
2220 }
2221 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002222
Ed Tanous002d39b2022-05-31 08:59:27 -07002223 doc.Parse(introspectXml.data(), introspectXml.size());
2224 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2225 if (pRoot == nullptr)
2226 {
Ed Tanous62598e32023-07-17 17:06:25 -07002227 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
2228 processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002229 asyncResp->res.result(
2230 boost::beast::http::status::internal_server_error);
2231 return;
2232 }
2233
2234 asyncResp->res.jsonValue["status"] = "ok";
2235 asyncResp->res.jsonValue["bus_name"] = processName;
2236 asyncResp->res.jsonValue["interface"] = interfaceName;
2237 asyncResp->res.jsonValue["object_path"] = objectPath;
2238
2239 nlohmann::json& methodsArray = asyncResp->res.jsonValue["methods"];
2240 methodsArray = nlohmann::json::array();
2241
2242 nlohmann::json& signalsArray = asyncResp->res.jsonValue["signals"];
2243 signalsArray = nlohmann::json::array();
2244
2245 nlohmann::json& propertiesObj =
2246 asyncResp->res.jsonValue["properties"];
2247 propertiesObj = nlohmann::json::object();
2248
2249 // if we know we're the only call, build the
2250 // json directly
2251 tinyxml2::XMLElement* interface =
2252 pRoot->FirstChildElement("interface");
2253 while (interface != nullptr)
2254 {
2255 const char* ifaceName = interface->Attribute("name");
2256
2257 if (ifaceName != nullptr && ifaceName == interfaceName)
Ed Tanous1656b292022-05-04 11:33:42 -07002258 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002259 break;
Ed Tanous1656b292022-05-04 11:33:42 -07002260 }
Ed Tanous14766872022-03-15 10:44:42 -07002261
Ed Tanous002d39b2022-05-31 08:59:27 -07002262 interface = interface->NextSiblingElement("interface");
2263 }
2264 if (interface == nullptr)
2265 {
2266 // if we got to the end of the list and
2267 // never found a match, throw 404
2268 asyncResp->res.result(boost::beast::http::status::not_found);
2269 return;
2270 }
Ed Tanous1656b292022-05-04 11:33:42 -07002271
Ed Tanous002d39b2022-05-31 08:59:27 -07002272 tinyxml2::XMLElement* methods =
2273 interface->FirstChildElement("method");
2274 while (methods != nullptr)
2275 {
2276 nlohmann::json argsArray = nlohmann::json::array();
2277 tinyxml2::XMLElement* arg = methods->FirstChildElement("arg");
2278 while (arg != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002279 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002280 nlohmann::json thisArg;
2281 for (const char* fieldName : std::array<const char*, 3>{
2282 "name", "direction", "type"})
Ed Tanous1656b292022-05-04 11:33:42 -07002283 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002284 const char* fieldValue = arg->Attribute(fieldName);
2285 if (fieldValue != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002286 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002287 thisArg[fieldName] = fieldValue;
2288 }
2289 }
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002290 argsArray.emplace_back(std::move(thisArg));
Ed Tanous002d39b2022-05-31 08:59:27 -07002291 arg = arg->NextSiblingElement("arg");
2292 }
2293
2294 const char* name = methods->Attribute("name");
2295 if (name != nullptr)
2296 {
2297 std::string uri;
2298 uri.reserve(14 + processName.size() + objectPath.size() +
2299 interfaceName.size() + strlen(name));
2300 uri += "/bus/system/";
2301 uri += processName;
2302 uri += objectPath;
2303 uri += "/";
2304 uri += interfaceName;
2305 uri += "/";
2306 uri += name;
2307
2308 nlohmann::json::object_t object;
2309 object["name"] = name;
2310 object["uri"] = std::move(uri);
2311 object["args"] = argsArray;
2312
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002313 methodsArray.emplace_back(std::move(object));
Ed Tanous002d39b2022-05-31 08:59:27 -07002314 }
2315 methods = methods->NextSiblingElement("method");
2316 }
2317 tinyxml2::XMLElement* signals =
2318 interface->FirstChildElement("signal");
2319 while (signals != nullptr)
2320 {
2321 nlohmann::json argsArray = nlohmann::json::array();
2322
2323 tinyxml2::XMLElement* arg = signals->FirstChildElement("arg");
2324 while (arg != nullptr)
2325 {
2326 const char* name = arg->Attribute("name");
2327 const char* type = arg->Attribute("type");
2328 if (name != nullptr && type != nullptr)
2329 {
2330 argsArray.push_back({
2331 {"name", name},
2332 {"type", type},
2333 });
2334 }
2335 arg = arg->NextSiblingElement("arg");
2336 }
2337 const char* name = signals->Attribute("name");
2338 if (name != nullptr)
2339 {
2340 nlohmann::json::object_t object;
2341 object["name"] = name;
2342 object["args"] = argsArray;
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002343 signalsArray.emplace_back(std::move(object));
Ed Tanous002d39b2022-05-31 08:59:27 -07002344 }
2345
2346 signals = signals->NextSiblingElement("signal");
2347 }
2348
2349 tinyxml2::XMLElement* property =
2350 interface->FirstChildElement("property");
2351 while (property != nullptr)
2352 {
2353 const char* name = property->Attribute("name");
2354 const char* type = property->Attribute("type");
2355 if (type != nullptr && name != nullptr)
2356 {
Patrick Williams59d494e2022-07-22 19:26:55 -05002357 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07002358 crow::connections::systemBus->new_method_call(
2359 processName.c_str(), objectPath.c_str(),
2360 "org.freedesktop."
2361 "DBus."
2362 "Properties",
2363 "Get");
2364 m.append(interfaceName, name);
2365 nlohmann::json& propertyItem = propertiesObj[name];
2366 crow::connections::systemBus->async_send(
2367 m, [&propertyItem,
Ed Tanous8b242752023-06-27 17:17:13 -07002368 asyncResp](const boost::system::error_code& ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05002369 sdbusplus::message_t& msg) {
Patrick Williams5a39f772023-10-20 11:20:21 -05002370 if (ec2)
2371 {
2372 return;
2373 }
Ed Tanous1656b292022-05-04 11:33:42 -07002374
Patrick Williams5a39f772023-10-20 11:20:21 -05002375 convertDBusToJSON("v", msg, propertyItem);
2376 });
Ed Tanous1656b292022-05-04 11:33:42 -07002377 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002378 property = property->NextSiblingElement("property");
2379 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002380 },
Ed Tanous1656b292022-05-04 11:33:42 -07002381 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2382 "Introspect");
2383 }
2384 else
2385 {
2386 if (req.method() != boost::beast::http::verb::post)
2387 {
2388 asyncResp->res.result(boost::beast::http::status::not_found);
2389 return;
2390 }
2391
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002392 nlohmann::json requestDbusData;
2393 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
2394 if (ret == JsonParseResult::BadContentType)
Ed Tanous1656b292022-05-04 11:33:42 -07002395 {
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002396 setErrorResponse(asyncResp->res,
2397 boost::beast::http::status::unsupported_media_type,
2398 invalidContentType, unsupportedMediaMsg);
Ed Tanous1656b292022-05-04 11:33:42 -07002399 return;
2400 }
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002401 if (ret != JsonParseResult::Success)
2402 {
2403 setErrorResponse(asyncResp->res,
2404 boost::beast::http::status::bad_request,
2405 noJsonDesc, badReqMsg);
2406 return;
2407 }
2408
Ed Tanous1656b292022-05-04 11:33:42 -07002409 if (!requestDbusData.is_array())
2410 {
2411 asyncResp->res.result(boost::beast::http::status::bad_request);
2412 return;
2413 }
Lei YU28dd5ca2023-03-17 13:17:05 +08002414 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous1656b292022-05-04 11:33:42 -07002415
2416 transaction->path = objectPath;
2417 transaction->methodName = methodName;
2418 transaction->arguments = std::move(requestDbusData);
2419
2420 findActionOnInterface(transaction, processName);
2421 }
2422}
2423
Ed Tanous23a21a12020-07-25 04:45:05 +00002424inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002425{
2426 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002427 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002428 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002429 [](const crow::Request&,
2430 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002431 nlohmann::json::array_t buses;
2432 nlohmann::json& bus = buses.emplace_back();
2433 bus["name"] = "system";
2434 asyncResp->res.jsonValue["busses"] = std::move(buses);
2435 asyncResp->res.jsonValue["status"] = "ok";
Patrick Williams5a39f772023-10-20 11:20:21 -05002436 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002437
2438 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002439 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002440 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002441 [](const crow::Request&,
2442 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002443 auto myCallback = [asyncResp](const boost::system::error_code& ec,
zhanghch058d1b46d2021-04-01 11:18:24 +08002444 std::vector<std::string>& names) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002445 if (ec)
2446 {
Ed Tanous62598e32023-07-17 17:06:25 -07002447 BMCWEB_LOG_ERROR("Dbus call failed with code {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07002448 asyncResp->res.result(
2449 boost::beast::http::status::internal_server_error);
2450 }
2451 else
2452 {
Ed Tanous3544d2a2023-08-06 18:12:20 -07002453 std::ranges::sort(names);
Ed Tanous002d39b2022-05-31 08:59:27 -07002454 asyncResp->res.jsonValue["status"] = "ok";
2455 auto& objectsSub = asyncResp->res.jsonValue["objects"];
Ed Tanous02cad962022-06-30 16:50:15 -07002456 for (const auto& name : names)
Ed Tanous002d39b2022-05-31 08:59:27 -07002457 {
2458 nlohmann::json::object_t object;
2459 object["name"] = name;
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002460 objectsSub.emplace_back(std::move(object));
Ed Tanous002d39b2022-05-31 08:59:27 -07002461 }
2462 }
2463 };
2464 crow::connections::systemBus->async_method_call(
2465 std::move(myCallback), "org.freedesktop.DBus", "/",
2466 "org.freedesktop.DBus", "ListNames");
Patrick Williams5a39f772023-10-20 11:20:21 -05002467 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002468
2469 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002470 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002471 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002472 [](const crow::Request&,
2473 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002474 handleList(asyncResp, "/");
Patrick Williams5a39f772023-10-20 11:20:21 -05002475 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002476
2477 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002478 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002479 .methods(boost::beast::http::verb::get)(
2480 [](const crow::Request& req,
2481 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002482 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002483 std::string objectPath = "/xyz/" + path;
2484 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002485 });
zhanghch058d1b46d2021-04-01 11:18:24 +08002486
2487 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002488 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002489 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2490 boost::beast::http::verb::delete_)(
2491 [](const crow::Request& req,
2492 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2493 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002494 std::string objectPath = "/xyz/" + path;
2495 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002496 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002497
Ed Tanous049a0512018-11-01 13:58:42 -07002498 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002499 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002500 .methods(boost::beast::http::verb::get)(
2501 [](const crow::Request& req,
2502 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2503 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002504 std::string objectPath = "/org/" + path;
2505 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002506 });
Tanousf00032d2018-11-05 01:18:10 -03002507
2508 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002509 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002510 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2511 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002512 [](const crow::Request& req,
2513 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002514 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002515 std::string objectPath = "/org/" + path;
2516 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002517 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002518
Ed Tanous1abe55e2018-09-05 08:30:59 -07002519 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002520 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002521 .methods(boost::beast::http::verb::get)(
2522 [](const crow::Request&,
2523 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2524 const std::string& dumpId) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002525 if (!validateFilename(dumpId))
2526 {
2527 asyncResp->res.result(boost::beast::http::status::bad_request);
2528 return;
2529 }
2530 std::filesystem::path loc("/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002531
Ed Tanous002d39b2022-05-31 08:59:27 -07002532 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002533
Ed Tanous002d39b2022-05-31 08:59:27 -07002534 if (!std::filesystem::exists(loc) ||
2535 !std::filesystem::is_directory(loc))
2536 {
Ed Tanous62598e32023-07-17 17:06:25 -07002537 BMCWEB_LOG_ERROR("{}Not found", loc.string());
Ed Tanous002d39b2022-05-31 08:59:27 -07002538 asyncResp->res.result(boost::beast::http::status::not_found);
2539 return;
2540 }
2541 std::filesystem::directory_iterator files(loc);
zhanghch058d1b46d2021-04-01 11:18:24 +08002542
Ed Tanous002d39b2022-05-31 08:59:27 -07002543 for (const auto& file : files)
2544 {
Ed Tanous27b0cf92023-08-07 12:02:40 -07002545 if (!asyncResp->res.openFile(file))
Ed Tanous002d39b2022-05-31 08:59:27 -07002546 {
2547 continue;
2548 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002549
Ed Tanousd9f6c622022-03-17 09:12:17 -07002550 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07002551 "application/octet-stream");
zhanghch058d1b46d2021-04-01 11:18:24 +08002552
Ed Tanous002d39b2022-05-31 08:59:27 -07002553 // Assuming only one dump file will be present in the dump
2554 // id directory
2555 std::string dumpFileName = file.path().filename().string();
zhanghch058d1b46d2021-04-01 11:18:24 +08002556
Ed Tanous002d39b2022-05-31 08:59:27 -07002557 // Filename should be in alphanumeric, dot and underscore
2558 // Its based on phosphor-debug-collector application
2559 // dumpfile format
Ed Tanous4b242742023-05-11 09:51:51 -07002560 static std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
Ed Tanous002d39b2022-05-31 08:59:27 -07002561 if (!std::regex_match(dumpFileName, dumpFileRegex))
2562 {
Ed Tanous62598e32023-07-17 17:06:25 -07002563 BMCWEB_LOG_ERROR("Invalid dump filename {}", dumpFileName);
zhanghch058d1b46d2021-04-01 11:18:24 +08002564 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002565 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07002566 }
Patrick Williams89492a12023-05-10 07:51:34 -05002567 std::string contentDispositionParam = "attachment; filename=\"" +
2568 dumpFileName + "\"";
Ed Tanous002d39b2022-05-31 08:59:27 -07002569
Ed Tanousd9f6c622022-03-17 09:12:17 -07002570 asyncResp->res.addHeader(
2571 boost::beast::http::field::content_disposition,
2572 contentDispositionParam);
Ed Tanous002d39b2022-05-31 08:59:27 -07002573
Ed Tanous002d39b2022-05-31 08:59:27 -07002574 return;
2575 }
2576 asyncResp->res.result(boost::beast::http::status::not_found);
2577 return;
Patrick Williams5a39f772023-10-20 11:20:21 -05002578 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002579
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002580 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002581 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002582
2583 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002584 [](const crow::Request&,
2585 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002586 const std::string& connection) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002587 introspectObjects(connection, "/", asyncResp);
Patrick Williams5a39f772023-10-20 11:20:21 -05002588 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002589
2590 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002591 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous1656b292022-05-04 11:33:42 -07002592 .methods(boost::beast::http::verb::get,
2593 boost::beast::http::verb::post)(handleBusSystemPost);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002594}
2595} // namespace openbmc_mapper
2596} // namespace crow