blob: 1892213dc437e342d2e0e5d2c8ec142994562596 [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"
Ed Tanous95c63072024-03-26 13:19:52 -070018#include "boost_formatters.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080019#include "dbus_singleton.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +080020#include "dbus_utility.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000021#include "http_request.hpp"
22#include "http_response.hpp"
Ed Tanous95c63072024-03-26 13:19:52 -070023#include "json_formatters.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000024#include "logging.hpp"
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010025#include "parsing.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000026#include "routing.hpp"
Ed Tanous50ebd4a2023-01-19 19:03:17 -080027#include "str_utility.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000028
29#include <systemd/sd-bus-protocol.h>
30#include <systemd/sd-bus.h>
Ed Tanous911ac312017-08-15 09:37:42 -070031#include <tinyxml2.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -070032
Nan Zhoud5c80ad2022-07-11 01:16:31 +000033#include <boost/beast/http/status.hpp>
34#include <boost/beast/http/verb.hpp>
35#include <boost/container/flat_map.hpp>
36#include <boost/container/vector.hpp>
George Liue99073f2022-12-09 11:06:16 +080037#include <boost/system/error_code.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000038#include <nlohmann/json.hpp>
39#include <sdbusplus/asio/connection.hpp>
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +020040#include <sdbusplus/asio/property.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000041#include <sdbusplus/exception.hpp>
42#include <sdbusplus/message.hpp>
43#include <sdbusplus/message/native_types.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050044
Nan Zhoud5c80ad2022-07-11 01:16:31 +000045#include <algorithm>
46#include <array>
47#include <cerrno>
48#include <cstdint>
49#include <cstring>
James Feist4418c7f2019-04-15 11:09:15 -070050#include <filesystem>
Ed Tanousd4bb9bb2018-05-16 13:36:42 -070051#include <fstream>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000052#include <functional>
53#include <initializer_list>
54#include <iterator>
55#include <limits>
56#include <map>
57#include <memory>
Ed Tanous3544d2a2023-08-06 18:12:20 -070058#include <ranges>
Ramesh Iyyard9207042019-07-05 08:04:42 -050059#include <regex>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000060#include <string>
61#include <string_view>
62#include <type_traits>
Ed Tanousb5a76932020-09-29 16:16:58 -070063#include <utility>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000064#include <variant>
65#include <vector>
66
67// IWYU pragma: no_include <boost/algorithm/string/detail/classification.hpp>
68// IWYU pragma: no_include <boost/system/detail/error_code.hpp>
69// IWYU pragma: no_include <boost/system/detail/error_category.hpp>
70// IWYU pragma: no_include <errno.h>
71// IWYU pragma: no_include <string.h>
72// IWYU pragma: no_include <ext/alloc_traits.h>
73// IWYU pragma: no_include <exception>
74// IWYU pragma: no_include <boost/type_index/type_index_facade.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -070075
Ed Tanous1abe55e2018-09-05 08:30:59 -070076namespace crow
77{
78namespace openbmc_mapper
79{
Ed Tanous23a21a12020-07-25 04:45:05 +000080const constexpr char* notFoundMsg = "404 Not Found";
81const constexpr char* badReqMsg = "400 Bad Request";
82const constexpr char* methodNotAllowedMsg = "405 Method Not Allowed";
83const constexpr char* forbiddenMsg = "403 Forbidden";
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010084const constexpr char* unsupportedMediaMsg = "415 Unsupported Media Type";
Ed Tanous23a21a12020-07-25 04:45:05 +000085const constexpr char* methodFailedMsg = "500 Method Call Failed";
86const constexpr char* methodOutputFailedMsg = "500 Method Output Error";
87const constexpr char* notFoundDesc =
Matt Spinler2ae60092018-12-06 10:35:36 -060088 "org.freedesktop.DBus.Error.FileNotFound: path or object not found";
Ed Tanous23a21a12020-07-25 04:45:05 +000089const constexpr char* propNotFoundDesc =
90 "The specified property cannot be found";
91const constexpr char* noJsonDesc = "No JSON object could be decoded";
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010092const constexpr char* invalidContentType =
93 "Content-type header is missing or invalid";
Ed Tanous23a21a12020-07-25 04:45:05 +000094const constexpr char* methodNotFoundDesc =
95 "The specified method cannot be found";
96const constexpr char* methodNotAllowedDesc = "Method not allowed";
97const constexpr char* forbiddenPropDesc =
98 "The specified property cannot be created";
99const constexpr char* forbiddenResDesc =
100 "The specified resource cannot be created";
Matt Spinler2ae60092018-12-06 10:35:36 -0600101
Josh Lehan482c45a2022-03-29 17:10:44 -0700102inline bool validateFilename(const std::string& filename)
103{
Ed Tanous4b242742023-05-11 09:51:51 -0700104 static std::regex validFilename(R"(^[\w\- ]+(\.?[\w\- ]*)$)");
Josh Lehan482c45a2022-03-29 17:10:44 -0700105
106 return std::regex_match(filename, validFilename);
107}
108
Ed Tanous23a21a12020-07-25 04:45:05 +0000109inline void setErrorResponse(crow::Response& res,
110 boost::beast::http::status result,
Ed Tanous26ccae32023-02-16 10:28:44 -0800111 const std::string& desc, std::string_view msg)
Matt Spinler2ae60092018-12-06 10:35:36 -0600112{
113 res.result(result);
Ed Tanous14766872022-03-15 10:44:42 -0700114 res.jsonValue["data"]["description"] = desc;
115 res.jsonValue["message"] = msg;
116 res.jsonValue["status"] = "error";
Matt Spinler2ae60092018-12-06 10:35:36 -0600117}
118
Ed Tanousb5a76932020-09-29 16:16:58 -0700119inline void
120 introspectObjects(const std::string& processName,
121 const std::string& objectPath,
122 const std::shared_ptr<bmcweb::AsyncResp>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123{
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700124 if (transaction->res.jsonValue.is_null())
125 {
Ed Tanous14766872022-03-15 10:44:42 -0700126 transaction->res.jsonValue["status"] = "ok";
127 transaction->res.jsonValue["bus_name"] = processName;
128 transaction->res.jsonValue["objects"] = nlohmann::json::array();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700129 }
130
Ed Tanous1abe55e2018-09-05 08:30:59 -0700131 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700132 [transaction, processName{std::string(processName)},
133 objectPath{std::string(objectPath)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800134 const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +0000135 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700136 if (ec)
137 {
Ed Tanous62598e32023-07-17 17:06:25 -0700138 BMCWEB_LOG_ERROR(
139 "Introspect call failed with error: {} on process: {} path: {}",
140 ec.message(), processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -0700141 return;
142 }
143 nlohmann::json::object_t object;
144 object["path"] = objectPath;
Ed Tanous14766872022-03-15 10:44:42 -0700145
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500146 transaction->res.jsonValue["objects"].emplace_back(std::move(object));
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700147
Ed Tanous002d39b2022-05-31 08:59:27 -0700148 tinyxml2::XMLDocument doc;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700149
Ed Tanous002d39b2022-05-31 08:59:27 -0700150 doc.Parse(introspectXml.c_str());
151 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
152 if (pRoot == nullptr)
153 {
Ed Tanous62598e32023-07-17 17:06:25 -0700154 BMCWEB_LOG_ERROR("XML document failed to parse {} {}", processName,
155 objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -0700156 }
157 else
158 {
159 tinyxml2::XMLElement* node = pRoot->FirstChildElement("node");
160 while (node != nullptr)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700161 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700162 const char* childPath = node->Attribute("name");
163 if (childPath != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700164 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700165 std::string newpath;
166 if (objectPath != "/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700167 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700168 newpath += objectPath;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700169 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700170 newpath += std::string("/") + childPath;
171 // introspect the subobjects as well
172 introspectObjects(processName, newpath, transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700173 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700174
175 node = node->NextSiblingElement("node");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700176 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700177 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500178 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700179 processName, objectPath, "org.freedesktop.DBus.Introspectable",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700180 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -0700181}
Ed Tanous64530012018-02-06 17:08:16 -0800182
Ed Tanous23a21a12020-07-25 04:45:05 +0000183inline void getPropertiesForEnumerate(
184 const std::string& objectPath, const std::string& service,
Ed Tanousb5a76932020-09-29 16:16:58 -0700185 const std::string& interface,
186 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600187{
Ed Tanous62598e32023-07-17 17:06:25 -0700188 BMCWEB_LOG_DEBUG("getPropertiesForEnumerate {} {} {}", objectPath, service,
189 interface);
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600190
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +0200191 sdbusplus::asio::getAllProperties(
192 *crow::connections::systemBus, service, objectPath, interface,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800193 [asyncResp, objectPath, service,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800194 interface](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800195 const dbus::utility::DBusPropertiesMap& propertiesList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700196 if (ec)
197 {
Ed Tanous62598e32023-07-17 17:06:25 -0700198 BMCWEB_LOG_ERROR(
199 "GetAll on path {} iface {} service {} failed with code {}",
200 objectPath, interface, service, ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700201 return;
202 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600203
Ed Tanous002d39b2022-05-31 08:59:27 -0700204 nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
205 nlohmann::json& objectJson = dataJson[objectPath];
206 if (objectJson.is_null())
207 {
208 objectJson = nlohmann::json::object();
209 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600210
Ed Tanous002d39b2022-05-31 08:59:27 -0700211 for (const auto& [name, value] : propertiesList)
212 {
213 nlohmann::json& propertyJson = objectJson[name];
214 std::visit(
215 [&propertyJson](auto&& val) {
216 if constexpr (std::is_same_v<std::decay_t<decltype(val)>,
217 sdbusplus::message::unix_fd>)
218 {
219 propertyJson = val.fd;
220 }
221 else
222 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700223 propertyJson = val;
224 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500225 },
Ed Tanous002d39b2022-05-31 08:59:27 -0700226 value);
227 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500228 });
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600229}
230
231// Find any results that weren't picked up by ObjectManagers, to be
232// called after all ObjectManagers are searched for and called.
Ed Tanous23a21a12020-07-25 04:45:05 +0000233inline void findRemainingObjectsForEnumerate(
Ed Tanousb5a76932020-09-29 16:16:58 -0700234 const std::string& objectPath,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800235 const std::shared_ptr<dbus::utility::MapperGetSubTreeResponse>& subtree,
Ed Tanousb5a76932020-09-29 16:16:58 -0700236 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600237{
Ed Tanous62598e32023-07-17 17:06:25 -0700238 BMCWEB_LOG_DEBUG("findRemainingObjectsForEnumerate");
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500239 const nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600240
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500241 for (const auto& [path, interface_map] : *subtree)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600242 {
243 if (path == objectPath)
244 {
245 // An enumerate does not return the target path's properties
246 continue;
247 }
248 if (dataJson.find(path) == dataJson.end())
249 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500250 for (const auto& [service, interfaces] : interface_map)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600251 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500252 for (const auto& interface : interfaces)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600253 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700254 if (!interface.starts_with("org.freedesktop.DBus"))
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600255 {
256 getPropertiesForEnumerate(path, service, interface,
257 asyncResp);
258 }
259 }
260 }
261 }
262 }
263}
264
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600265struct InProgressEnumerateData
266{
zhanghch058d1b46d2021-04-01 11:18:24 +0800267 InProgressEnumerateData(
268 const std::string& objectPathIn,
269 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
Ed Tanous23a21a12020-07-25 04:45:05 +0000270 objectPath(objectPathIn),
zhanghch058d1b46d2021-04-01 11:18:24 +0800271 asyncResp(asyncRespIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500272 {}
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600273
274 ~InProgressEnumerateData()
275 {
Ed Tanous24b2fe82022-01-06 12:45:54 -0800276 try
277 {
278 findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
279 }
280 catch (...)
281 {
Ed Tanous62598e32023-07-17 17:06:25 -0700282 BMCWEB_LOG_CRITICAL(
283 "findRemainingObjectsForEnumerate threw exception");
Ed Tanous24b2fe82022-01-06 12:45:54 -0800284 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600285 }
286
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800287 InProgressEnumerateData(const InProgressEnumerateData&) = delete;
288 InProgressEnumerateData(InProgressEnumerateData&&) = delete;
289 InProgressEnumerateData& operator=(const InProgressEnumerateData&) = delete;
290 InProgressEnumerateData& operator=(InProgressEnumerateData&&) = delete;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600291 const std::string objectPath;
Ed Tanousb9d36b42022-02-26 21:42:46 -0800292 std::shared_ptr<dbus::utility::MapperGetSubTreeResponse> subtree;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600293 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
294};
295
Ed Tanous23a21a12020-07-25 04:45:05 +0000296inline void getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000297 const std::string& objectName, const std::string& objectManagerPath,
298 const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700299 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700300{
Ed Tanous62598e32023-07-17 17:06:25 -0700301 BMCWEB_LOG_DEBUG(
302 "getManagedObjectsForEnumerate {} object_manager_path {} connection_name {}",
303 objectName, objectManagerPath, connectionName);
George Liu5eb468d2023-06-20 17:03:24 +0800304 sdbusplus::message::object_path path(objectManagerPath);
305 dbus::utility::getManagedObjects(
306 connectionName, path,
Ed Tanous81ce6092020-12-17 16:54:55 +0000307 [transaction, objectName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800308 connectionName](const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +0000309 const dbus::utility::ManagedObjectType& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700310 if (ec)
311 {
Ed Tanous62598e32023-07-17 17:06:25 -0700312 BMCWEB_LOG_ERROR(
313 "GetManagedObjects on path {} on connection {} failed with code {}",
314 objectName, connectionName, ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700315 return;
316 }
Ed Tanous64530012018-02-06 17:08:16 -0800317
Ed Tanous002d39b2022-05-31 08:59:27 -0700318 nlohmann::json& dataJson =
319 transaction->asyncResp->res.jsonValue["data"];
Ed Tanous049a0512018-11-01 13:58:42 -0700320
Ed Tanous002d39b2022-05-31 08:59:27 -0700321 for (const auto& objectPath : objects)
322 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700323 if (objectPath.first.str.starts_with(objectName))
Ed Tanous049a0512018-11-01 13:58:42 -0700324 {
Ed Tanous62598e32023-07-17 17:06:25 -0700325 BMCWEB_LOG_DEBUG("Reading object {}", objectPath.first.str);
Ed Tanous002d39b2022-05-31 08:59:27 -0700326 nlohmann::json& objectJson = dataJson[objectPath.first.str];
327 if (objectJson.is_null())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700328 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700329 objectJson = nlohmann::json::object();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700330 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500331 for (const auto& interface : objectPath.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700332 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700333 for (const auto& property : interface.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700334 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700335 nlohmann::json& propertyJson =
336 objectJson[property.first];
337 std::visit(
338 [&propertyJson](auto&& val) {
339 if constexpr (std::is_same_v<
340 std::decay_t<decltype(val)>,
341 sdbusplus::message::unix_fd>)
342 {
343 propertyJson = val.fd;
344 }
345 else
346 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700347 propertyJson = val;
348 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500349 },
Ed Tanous002d39b2022-05-31 08:59:27 -0700350 property.second);
Ed Tanous049a0512018-11-01 13:58:42 -0700351 }
352 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700353 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700354 for (const auto& interface : objectPath.second)
355 {
356 if (interface.first == "org.freedesktop.DBus.ObjectManager")
357 {
358 getManagedObjectsForEnumerate(objectPath.first.str,
359 objectPath.first.str,
360 connectionName, transaction);
361 }
362 }
363 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500364 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700365}
366
Ed Tanous23a21a12020-07-25 04:45:05 +0000367inline void findObjectManagerPathForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000368 const std::string& objectName, const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700369 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700370{
Ed Tanous62598e32023-07-17 17:06:25 -0700371 BMCWEB_LOG_DEBUG("Finding objectmanager for path {} on connection:{}",
372 objectName, connectionName);
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700373 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000374 [transaction, objectName, connectionName](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800375 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800376 const dbus::utility::MapperGetAncestorsResponse& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700377 if (ec)
378 {
Ed Tanous62598e32023-07-17 17:06:25 -0700379 BMCWEB_LOG_ERROR("GetAncestors on path {} failed with code {}",
380 objectName, ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700381 return;
382 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700383
Ed Tanous002d39b2022-05-31 08:59:27 -0700384 for (const auto& pathGroup : objects)
385 {
386 for (const auto& connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700387 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700388 if (connectionGroup.first == connectionName)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700389 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700390 // Found the object manager path for this resource.
391 getManagedObjectsForEnumerate(objectName, pathGroup.first,
392 connectionName, transaction);
393 return;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700394 }
395 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700396 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500397 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700398 "xyz.openbmc_project.ObjectMapper",
399 "/xyz/openbmc_project/object_mapper",
Ed Tanous81ce6092020-12-17 16:54:55 +0000400 "xyz.openbmc_project.ObjectMapper", "GetAncestors", objectName,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500401 std::array<const char*, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700402}
Ed Tanous64530012018-02-06 17:08:16 -0800403
Ed Tanous7c091622019-05-23 11:42:36 -0700404// Uses GetObject to add the object info about the target /enumerate path to
405// the results of GetSubTree, as GetSubTree will not return info for the
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600406// target path, and then continues on enumerating the rest of the tree.
Ed Tanousb5a76932020-09-29 16:16:58 -0700407inline void getObjectAndEnumerate(
408 const std::shared_ptr<InProgressEnumerateData>& transaction)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600409{
George Liu2b731192023-01-11 16:27:13 +0800410 dbus::utility::getDbusObject(
411 transaction->objectPath, {},
412 [transaction](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800413 const dbus::utility::MapperGetObject& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700414 if (ec)
415 {
Ed Tanous62598e32023-07-17 17:06:25 -0700416 BMCWEB_LOG_ERROR("GetObject for path {} failed with code {}",
417 transaction->objectPath, ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700418 return;
419 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600420
Ed Tanous62598e32023-07-17 17:06:25 -0700421 BMCWEB_LOG_DEBUG("GetObject for {} has {} entries",
422 transaction->objectPath, objects.size());
Ed Tanous002d39b2022-05-31 08:59:27 -0700423 if (!objects.empty())
424 {
425 transaction->subtree->emplace_back(transaction->objectPath,
426 objects);
427 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600428
Ed Tanous002d39b2022-05-31 08:59:27 -0700429 // Map indicating connection name, and the path where the object
430 // manager exists
Ed Tanous18f8f602023-07-18 10:07:23 -0700431 boost::container::flat_map<
432 std::string, std::string, std::less<>,
433 std::vector<std::pair<std::string, std::string>>>
434 connections;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600435
Ed Tanous002d39b2022-05-31 08:59:27 -0700436 for (const auto& object : *(transaction->subtree))
437 {
438 for (const auto& connection : object.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600439 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700440 for (const auto& interface : connection.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600441 {
Ed Tanous62598e32023-07-17 17:06:25 -0700442 BMCWEB_LOG_DEBUG("{} has interface {}", connection.first,
443 interface);
Ed Tanous002d39b2022-05-31 08:59:27 -0700444 if (interface == "org.freedesktop.DBus.ObjectManager")
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600445 {
Ed Tanous62598e32023-07-17 17:06:25 -0700446 BMCWEB_LOG_DEBUG("found object manager path {}",
447 object.first);
Ed Tanousf8fe53e2022-06-30 15:55:45 -0700448 connections[connection.first] = object.first;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600449 }
450 }
451 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700452 }
Ed Tanous62598e32023-07-17 17:06:25 -0700453 BMCWEB_LOG_DEBUG("Got {} connections", connections.size());
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600454
Ed Tanous002d39b2022-05-31 08:59:27 -0700455 for (const auto& connection : connections)
456 {
457 // If we already know where the object manager is, we don't
458 // need to search for it, we can call directly in to
459 // getManagedObjects
460 if (!connection.second.empty())
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600461 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700462 getManagedObjectsForEnumerate(transaction->objectPath,
463 connection.second,
464 connection.first, transaction);
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600465 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700466 else
467 {
468 // otherwise we need to find the object manager path
469 // before we can continue
470 findObjectManagerPathForEnumerate(
471 transaction->objectPath, connection.first, transaction);
472 }
473 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500474 });
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600475}
Ed Tanous64530012018-02-06 17:08:16 -0800476
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700477// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700478struct InProgressActionData
479{
Lei YU28dd5ca2023-03-17 13:17:05 +0800480 explicit InProgressActionData(
481 const std::shared_ptr<bmcweb::AsyncResp>& res) :
482 asyncResp(res)
Ed Tanous23a21a12020-07-25 04:45:05 +0000483 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700484 ~InProgressActionData()
485 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600486 // Methods could have been called across different owners
487 // and interfaces, where some calls failed and some passed.
488 //
489 // The rules for this are:
490 // * if no method was called - error
491 // * if a method failed and none passed - error
492 // (converse: if at least one method passed - OK)
493 // * for the method output:
494 // * if output processing didn't fail, return the data
495
496 // Only deal with method returns if nothing failed earlier
Lei YU28dd5ca2023-03-17 13:17:05 +0800497 if (asyncResp->res.result() == boost::beast::http::status::ok)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700498 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600499 if (!methodPassed)
500 {
Matt Spinler06b1b632019-06-18 16:09:25 -0500501 if (!methodFailed)
Matt Spinler16caaee2019-01-15 11:40:34 -0600502 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800503 setErrorResponse(asyncResp->res,
504 boost::beast::http::status::not_found,
Matt Spinler16caaee2019-01-15 11:40:34 -0600505 methodNotFoundDesc, notFoundMsg);
506 }
507 }
508 else
509 {
510 if (outputFailed)
511 {
512 setErrorResponse(
Lei YU28dd5ca2023-03-17 13:17:05 +0800513 asyncResp->res,
514 boost::beast::http::status::internal_server_error,
Matt Spinler16caaee2019-01-15 11:40:34 -0600515 "Method output failure", methodOutputFailedMsg);
516 }
517 else
518 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800519 asyncResp->res.jsonValue["status"] = "ok";
520 asyncResp->res.jsonValue["message"] = "200 OK";
521 asyncResp->res.jsonValue["data"] = methodResponse;
Matt Spinler16caaee2019-01-15 11:40:34 -0600522 }
523 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700524 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700525 }
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800526 InProgressActionData(const InProgressActionData&) = delete;
527 InProgressActionData(InProgressActionData&&) = delete;
528 InProgressActionData& operator=(const InProgressActionData&) = delete;
529 InProgressActionData& operator=(InProgressActionData&&) = delete;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700530
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500531 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700532 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800533 setErrorResponse(asyncResp->res,
534 boost::beast::http::status::bad_request, desc,
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600535 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700536 }
Lei YU28dd5ca2023-03-17 13:17:05 +0800537 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700538 std::string path;
539 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600540 std::string interfaceName;
Matt Spinler16caaee2019-01-15 11:40:34 -0600541 bool methodPassed = false;
542 bool methodFailed = false;
543 bool outputFailed = false;
Matt Spinler39a4e392019-01-15 11:53:13 -0600544 bool convertedToArray = false;
Matt Spinler16caaee2019-01-15 11:40:34 -0600545 nlohmann::json methodResponse;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700546 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700547};
548
Ed Tanous23a21a12020-07-25 04:45:05 +0000549inline std::vector<std::string> dbusArgSplit(const std::string& string)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700550{
551 std::vector<std::string> ret;
552 if (string.empty())
553 {
554 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700555 }
Ed Tanous0f0353b2019-10-24 11:37:51 -0700556 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700557 int containerDepth = 0;
558
559 for (std::string::const_iterator character = string.begin();
560 character != string.end(); character++)
561 {
562 ret.back() += *character;
563 switch (*character)
564 {
565 case ('a'):
566 break;
567 case ('('):
568 case ('{'):
569 containerDepth++;
570 break;
571 case ('}'):
572 case (')'):
573 containerDepth--;
574 if (containerDepth == 0)
575 {
576 if (character + 1 != string.end())
577 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700578 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700579 }
580 }
581 break;
582 default:
583 if (containerDepth == 0)
584 {
585 if (character + 1 != string.end())
586 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700587 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700588 }
589 }
590 break;
591 }
592 }
Matt Spinler4ae611d2019-01-11 15:37:06 -0600593
594 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700595}
596
Ed Tanous81ce6092020-12-17 16:54:55 +0000597inline int convertJsonToDbus(sd_bus_message* m, const std::string& argType,
598 const nlohmann::json& inputJson)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700599{
600 int r = 0;
Ed Tanous296579b2024-03-11 16:58:24 -0700601 BMCWEB_LOG_DEBUG("Converting {} to type: {}", inputJson, argType);
Ed Tanous81ce6092020-12-17 16:54:55 +0000602 const std::vector<std::string> argTypes = dbusArgSplit(argType);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700603
Ed Tanous1abe55e2018-09-05 08:30:59 -0700604 // Assume a single object for now.
Ed Tanous81ce6092020-12-17 16:54:55 +0000605 const nlohmann::json* j = &inputJson;
606 nlohmann::json::const_iterator jIt = inputJson.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700607
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500608 for (const std::string& argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700609 {
610 // If we are decoding multiple objects, grab the pointer to the
611 // iterator, and increment it for the next loop
612 if (argTypes.size() > 1)
613 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000614 if (jIt == inputJson.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700615 {
616 return -2;
617 }
618 j = &*jIt;
619 jIt++;
620 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500621 const int64_t* intValue = j->get_ptr<const int64_t*>();
622 const std::string* stringValue = j->get_ptr<const std::string*>();
623 const double* doubleValue = j->get_ptr<const double*>();
624 const bool* b = j->get_ptr<const bool*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700625 int64_t v = 0;
626 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700627
Ed Tanous1abe55e2018-09-05 08:30:59 -0700628 // Do some basic type conversions that make sense. uint can be
629 // converted to int. int and uint can be converted to double
Ed Tanous66664f22019-10-11 13:05:49 -0700630 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700631 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500632 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700633 if (uintValue != nullptr)
634 {
635 v = static_cast<int64_t>(*uintValue);
636 intValue = &v;
637 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700638 }
Ed Tanous66664f22019-10-11 13:05:49 -0700639 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700640 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500641 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700642 if (uintValue != nullptr)
643 {
644 d = static_cast<double>(*uintValue);
645 doubleValue = &d;
646 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700647 }
Ed Tanous66664f22019-10-11 13:05:49 -0700648 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700649 {
Ed Tanous66664f22019-10-11 13:05:49 -0700650 if (intValue != nullptr)
651 {
652 d = static_cast<double>(*intValue);
653 doubleValue = &d;
654 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700655 }
656
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700657 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700658 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700659 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700660 {
661 return -1;
662 }
Ed Tanous271584a2019-07-09 16:24:22 -0700663 r = sd_bus_message_append_basic(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500664 m, argCode[0], static_cast<const void*>(stringValue->data()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700665 if (r < 0)
666 {
667 return r;
668 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700669 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700670 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700671 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700672 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700673 {
674 return -1;
675 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500676 if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
677 (*intValue > std::numeric_limits<int32_t>::max()))
678 {
679 return -ERANGE;
680 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700681 int32_t i = static_cast<int32_t>(*intValue);
682 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700683 if (r < 0)
684 {
685 return r;
686 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700687 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700688 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700689 {
690 // lots of ways bool could be represented here. Try them all
Ed Tanouse662eae2022-01-25 10:39:19 -0800691 int boolInt = 0;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700692 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700693 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500694 if (*intValue == 1)
695 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800696 boolInt = 1;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500697 }
698 else if (*intValue == 0)
699 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800700 boolInt = 0;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500701 }
702 else
703 {
704 return -ERANGE;
705 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700706 }
707 else if (b != nullptr)
708 {
Matt Spinlera2f02632019-01-18 10:15:35 -0600709 boolInt = *b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700710 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700711 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700712 {
Ed Tanous18f8f602023-07-18 10:07:23 -0700713 if (!stringValue->empty())
714 {
715 if (stringValue->front() == 't' ||
716 stringValue->front() == 'T')
717 {
718 boolInt = 1;
719 }
720 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700721 }
722 else
723 {
724 return -1;
725 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700726 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700727 if (r < 0)
728 {
729 return r;
730 }
731 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700732 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700733 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700734 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700735 {
736 return -1;
737 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500738 if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
739 (*intValue > std::numeric_limits<int16_t>::max()))
740 {
741 return -ERANGE;
742 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700743 int16_t n = static_cast<int16_t>(*intValue);
744 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700745 if (r < 0)
746 {
747 return r;
748 }
749 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700750 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700751 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700752 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700753 {
754 return -1;
755 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700756 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700757 if (r < 0)
758 {
759 return r;
760 }
761 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700762 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700763 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500764 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700765 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700766 {
767 return -1;
768 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000769 if (*uintValue > std::numeric_limits<uint8_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500770 {
771 return -ERANGE;
772 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700773 uint8_t y = static_cast<uint8_t>(*uintValue);
774 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700775 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700776 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700777 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500778 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700779 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700780 {
781 return -1;
782 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000783 if (*uintValue > std::numeric_limits<uint16_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500784 {
785 return -ERANGE;
786 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700787 uint16_t q = static_cast<uint16_t>(*uintValue);
788 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700789 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700790 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700791 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500792 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700793 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700794 {
795 return -1;
796 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000797 if (*uintValue > std::numeric_limits<uint32_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500798 {
799 return -ERANGE;
800 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700801 uint32_t u = static_cast<uint32_t>(*uintValue);
802 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700803 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700804 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700805 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500806 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700807 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700808 {
809 return -1;
810 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700811 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700812 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700813 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700814 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500815 if (doubleValue == nullptr)
816 {
817 return -1;
818 }
819 if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
820 (*doubleValue > std::numeric_limits<double>::max()))
821 {
822 return -ERANGE;
823 }
Ed Tanous07900812024-05-06 15:41:30 -0700824 r = sd_bus_message_append_basic(m, argCode[0], doubleValue);
825 if (r < 0)
826 {
827 return r;
828 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700829 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700830 else if (argCode.starts_with("a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700831 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700832 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700833 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700834 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700835 if (r < 0)
836 {
837 return r;
838 }
839
Ed Tanous0dfeda62019-10-24 11:21:38 -0700840 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700841 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700842 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700843 if (r < 0)
844 {
845 return r;
846 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700847 }
848 sd_bus_message_close_container(m);
849 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700850 else if (argCode.starts_with("v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700851 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700852 std::string containedType = argCode.substr(1);
Ed Tanous62598e32023-07-17 17:06:25 -0700853 BMCWEB_LOG_DEBUG("variant type: {} appending variant of type: {}",
854 argCode, containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700855 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700856 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700857 if (r < 0)
858 {
859 return r;
860 }
861
Ed Tanous81ce6092020-12-17 16:54:55 +0000862 r = convertJsonToDbus(m, containedType, inputJson);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700863 if (r < 0)
864 {
865 return r;
866 }
867
868 r = sd_bus_message_close_container(m);
869 if (r < 0)
870 {
871 return r;
872 }
873 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700874 else if (argCode.starts_with("(") && argCode.ends_with(")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700875 {
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300876 std::string containedType = argCode.substr(1, argCode.size() - 2);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700877 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700878 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800879 if (r < 0)
880 {
881 return r;
882 }
883
Ed Tanous1abe55e2018-09-05 08:30:59 -0700884 nlohmann::json::const_iterator it = j->begin();
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300885 for (const std::string& argCode2 : dbusArgSplit(containedType))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700886 {
887 if (it == j->end())
888 {
889 return -1;
890 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000891 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700892 if (r < 0)
893 {
894 return r;
895 }
896 it++;
897 }
898 r = sd_bus_message_close_container(m);
899 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700900 else if (argCode.starts_with("{") && argCode.ends_with("}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700901 {
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300902 std::string containedType = argCode.substr(1, argCode.size() - 2);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700903 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700904 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800905 if (r < 0)
906 {
907 return r;
908 }
909
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700910 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700911 if (codes.size() != 2)
912 {
913 return -1;
914 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700915 const std::string& keyType = codes[0];
916 const std::string& valueType = codes[1];
Ed Tanous0bdda662023-08-03 17:27:34 -0700917 const nlohmann::json::object_t* arr =
918 j->get_ptr<const nlohmann::json::object_t*>();
919 if (arr == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700920 {
Ed Tanous0bdda662023-08-03 17:27:34 -0700921 return -1;
922 }
923 for (const auto& it : *arr)
924 {
925 r = convertJsonToDbus(m, keyType, it.first);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700926 if (r < 0)
927 {
928 return r;
929 }
930
Ed Tanous0bdda662023-08-03 17:27:34 -0700931 r = convertJsonToDbus(m, valueType, it.second);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700932 if (r < 0)
933 {
934 return r;
935 }
936 }
937 r = sd_bus_message_close_container(m);
938 }
939 else
940 {
941 return -2;
942 }
943 if (r < 0)
944 {
945 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700946 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700947
Ed Tanous1abe55e2018-09-05 08:30:59 -0700948 if (argTypes.size() > 1)
949 {
950 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700951 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700952 }
Matt Spinler127ea542019-01-14 11:04:28 -0600953
954 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700955}
956
Matt Spinlerd22a7132019-01-14 12:14:30 -0600957template <typename T>
Patrick Williams59d494e2022-07-22 19:26:55 -0500958int readMessageItem(const std::string& typeCode, sdbusplus::message_t& m,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500959 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600960{
961 T value;
Ed Tanousf79ce6a2024-03-20 12:27:06 -0700962 // When T == char*, this warning fires. Unclear how to resolve
963 // Given that sd-bus takes a void pointer to a char*, and that's
964 // Not something we can fix.
965 // NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600966 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
967 if (r < 0)
968 {
Ed Tanous62598e32023-07-17 17:06:25 -0700969 BMCWEB_LOG_ERROR("sd_bus_message_read_basic on type {} failed!",
970 typeCode);
Matt Spinlerd22a7132019-01-14 12:14:30 -0600971 return r;
972 }
973
974 data = value;
975 return 0;
976}
977
Patrick Williams59d494e2022-07-22 19:26:55 -0500978int convertDBusToJSON(const std::string& returnType, sdbusplus::message_t& m,
979 nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600980
Ed Tanous23a21a12020-07-25 04:45:05 +0000981inline int readDictEntryFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -0500982 sdbusplus::message_t& m,
Ed Tanous23a21a12020-07-25 04:45:05 +0000983 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600984{
985 std::vector<std::string> types = dbusArgSplit(typeCode);
986 if (types.size() != 2)
987 {
Ed Tanous62598e32023-07-17 17:06:25 -0700988 BMCWEB_LOG_ERROR("wrong number contained types in dictionary: {}",
989 types.size());
Matt Spinler6df8f992019-01-14 12:47:47 -0600990 return -1;
991 }
992
993 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
994 typeCode.c_str());
995 if (r < 0)
996 {
Ed Tanous62598e32023-07-17 17:06:25 -0700997 BMCWEB_LOG_ERROR("sd_bus_message_enter_container with rc {}", r);
Matt Spinler6df8f992019-01-14 12:47:47 -0600998 return r;
999 }
1000
1001 nlohmann::json key;
1002 r = convertDBusToJSON(types[0], m, key);
1003 if (r < 0)
1004 {
1005 return r;
1006 }
1007
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001008 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -06001009 if (keyPtr == nullptr)
1010 {
1011 // json doesn't support non-string keys. If we hit this condition,
1012 // convert the result to a string so we can proceed
Ed Tanous71f52d92021-02-19 08:51:17 -08001013 key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001014 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -07001015 // in theory this can't fail now, but lets be paranoid about it
1016 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -06001017 if (keyPtr == nullptr)
1018 {
1019 return -1;
1020 }
1021 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001022 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -06001023
1024 r = convertDBusToJSON(types[1], m, value);
1025 if (r < 0)
1026 {
1027 return r;
1028 }
1029
1030 r = sd_bus_message_exit_container(m.get());
1031 if (r < 0)
1032 {
Ed Tanous62598e32023-07-17 17:06:25 -07001033 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001034 return r;
1035 }
1036
1037 return 0;
1038}
1039
Ed Tanous23a21a12020-07-25 04:45:05 +00001040inline int readArrayFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001041 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -06001042{
1043 if (typeCode.size() < 2)
1044 {
Ed Tanous62598e32023-07-17 17:06:25 -07001045 BMCWEB_LOG_ERROR("Type code {} too small for an array", typeCode);
Matt Spinler6df8f992019-01-14 12:47:47 -06001046 return -1;
1047 }
1048
1049 std::string containedType = typeCode.substr(1);
1050
1051 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
1052 containedType.c_str());
1053 if (r < 0)
1054 {
Ed Tanous62598e32023-07-17 17:06:25 -07001055 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler6df8f992019-01-14 12:47:47 -06001056 return r;
1057 }
1058
Ed Tanous11ba3972022-07-11 09:50:41 -07001059 bool dict = containedType.starts_with("{") && containedType.ends_with("}");
Matt Spinler6df8f992019-01-14 12:47:47 -06001060
1061 if (dict)
1062 {
1063 // Remove the { }
1064 containedType = containedType.substr(1, containedType.size() - 2);
1065 data = nlohmann::json::object();
1066 }
1067 else
1068 {
1069 data = nlohmann::json::array();
1070 }
1071
1072 while (true)
1073 {
Ed Tanouse662eae2022-01-25 10:39:19 -08001074 r = sd_bus_message_at_end(m.get(), 0);
Matt Spinler6df8f992019-01-14 12:47:47 -06001075 if (r < 0)
1076 {
Ed Tanous62598e32023-07-17 17:06:25 -07001077 BMCWEB_LOG_ERROR("sd_bus_message_at_end failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001078 return r;
1079 }
1080
1081 if (r > 0)
1082 {
1083 break;
1084 }
1085
1086 // Dictionaries are only ever seen in an array
1087 if (dict)
1088 {
1089 r = readDictEntryFromMessage(containedType, m, data);
1090 if (r < 0)
1091 {
1092 return r;
1093 }
1094 }
1095 else
1096 {
1097 data.push_back(nlohmann::json());
1098
1099 r = convertDBusToJSON(containedType, m, data.back());
1100 if (r < 0)
1101 {
1102 return r;
1103 }
1104 }
1105 }
1106
1107 r = sd_bus_message_exit_container(m.get());
1108 if (r < 0)
1109 {
Ed Tanous62598e32023-07-17 17:06:25 -07001110 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001111 return r;
1112 }
1113
1114 return 0;
1115}
1116
Ed Tanous23a21a12020-07-25 04:45:05 +00001117inline int readStructFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001118 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001119{
1120 if (typeCode.size() < 3)
1121 {
Ed Tanous62598e32023-07-17 17:06:25 -07001122 BMCWEB_LOG_ERROR("Type code {} too small for a struct", typeCode);
Matt Spinler75c6c672019-01-14 13:01:46 -06001123 return -1;
1124 }
1125
1126 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1127 std::vector<std::string> types = dbusArgSplit(containedTypes);
1128
1129 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1130 containedTypes.c_str());
1131 if (r < 0)
1132 {
Ed Tanous62598e32023-07-17 17:06:25 -07001133 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler75c6c672019-01-14 13:01:46 -06001134 return r;
1135 }
1136
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001137 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001138 {
1139 data.push_back(nlohmann::json());
1140 r = convertDBusToJSON(type, m, data.back());
1141 if (r < 0)
1142 {
1143 return r;
1144 }
1145 }
1146
1147 r = sd_bus_message_exit_container(m.get());
1148 if (r < 0)
1149 {
Ed Tanous62598e32023-07-17 17:06:25 -07001150 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler75c6c672019-01-14 13:01:46 -06001151 return r;
1152 }
1153 return 0;
1154}
1155
Patrick Williams59d494e2022-07-22 19:26:55 -05001156inline int readVariantFromMessage(sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001157{
Ed Tanous543f4402022-01-06 13:12:53 -08001158 const char* containerType = nullptr;
Ed Tanous99131cd2019-10-24 11:12:47 -07001159 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001160 if (r < 0)
1161 {
Ed Tanous62598e32023-07-17 17:06:25 -07001162 BMCWEB_LOG_ERROR("sd_bus_message_peek_type failed");
Matt Spinler89c19702019-01-14 13:13:00 -06001163 return r;
1164 }
1165
1166 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1167 containerType);
1168 if (r < 0)
1169 {
Ed Tanous62598e32023-07-17 17:06:25 -07001170 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler89c19702019-01-14 13:13:00 -06001171 return r;
1172 }
1173
1174 r = convertDBusToJSON(containerType, m, data);
1175 if (r < 0)
1176 {
1177 return r;
1178 }
1179
1180 r = sd_bus_message_exit_container(m.get());
1181 if (r < 0)
1182 {
Ed Tanous62598e32023-07-17 17:06:25 -07001183 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed");
Matt Spinler89c19702019-01-14 13:13:00 -06001184 return r;
1185 }
1186
1187 return 0;
1188}
1189
Ed Tanous23a21a12020-07-25 04:45:05 +00001190inline int convertDBusToJSON(const std::string& returnType,
Patrick Williams59d494e2022-07-22 19:26:55 -05001191 sdbusplus::message_t& m, nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001192{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001193 int r = 0;
1194 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1195
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001196 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001197 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001198 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001199 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001200 {
1201 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001202 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001203 }
1204
Ed Tanousd4d25792020-09-29 15:15:03 -07001205 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001206 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001207 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001208 if (r < 0)
1209 {
1210 return r;
1211 }
1212 }
1213 else if (typeCode == "b")
1214 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001215 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001216 if (r < 0)
1217 {
1218 return r;
1219 }
1220
Matt Spinlerf39420c2019-01-30 12:57:18 -06001221 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001222 }
1223 else if (typeCode == "u")
1224 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001225 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001226 if (r < 0)
1227 {
1228 return r;
1229 }
1230 }
1231 else if (typeCode == "i")
1232 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001233 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001234 if (r < 0)
1235 {
1236 return r;
1237 }
1238 }
1239 else if (typeCode == "x")
1240 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001241 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001242 if (r < 0)
1243 {
1244 return r;
1245 }
1246 }
1247 else if (typeCode == "t")
1248 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001249 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001250 if (r < 0)
1251 {
1252 return r;
1253 }
1254 }
1255 else if (typeCode == "n")
1256 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001257 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001258 if (r < 0)
1259 {
1260 return r;
1261 }
1262 }
1263 else if (typeCode == "q")
1264 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001265 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001266 if (r < 0)
1267 {
1268 return r;
1269 }
1270 }
1271 else if (typeCode == "y")
1272 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001273 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001274 if (r < 0)
1275 {
1276 return r;
1277 }
1278 }
1279 else if (typeCode == "d")
1280 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001281 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001282 if (r < 0)
1283 {
1284 return r;
1285 }
1286 }
1287 else if (typeCode == "h")
1288 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001289 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001290 if (r < 0)
1291 {
1292 return r;
1293 }
1294 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001295 else if (typeCode.starts_with("a"))
Matt Spinler6df8f992019-01-14 12:47:47 -06001296 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001297 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001298 if (r < 0)
1299 {
1300 return r;
1301 }
1302 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001303 else if (typeCode.starts_with("(") && typeCode.ends_with(")"))
Matt Spinler75c6c672019-01-14 13:01:46 -06001304 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001305 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001306 if (r < 0)
1307 {
1308 return r;
1309 }
1310 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001311 else if (typeCode.starts_with("v"))
Matt Spinler89c19702019-01-14 13:13:00 -06001312 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001313 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001314 if (r < 0)
1315 {
1316 return r;
1317 }
1318 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001319 else
1320 {
Ed Tanous62598e32023-07-17 17:06:25 -07001321 BMCWEB_LOG_ERROR("Invalid D-Bus signature type {}", typeCode);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001322 return -2;
1323 }
1324 }
1325
Matt Spinler16caaee2019-01-15 11:40:34 -06001326 return 0;
1327}
1328
Ed Tanousb5a76932020-09-29 16:16:58 -07001329inline void handleMethodResponse(
1330 const std::shared_ptr<InProgressActionData>& transaction,
Patrick Williams59d494e2022-07-22 19:26:55 -05001331 sdbusplus::message_t& m, const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001332{
Matt Spinler39a4e392019-01-15 11:53:13 -06001333 nlohmann::json data;
1334
1335 int r = convertDBusToJSON(returnType, m, data);
1336 if (r < 0)
1337 {
1338 transaction->outputFailed = true;
1339 return;
1340 }
1341
1342 if (data.is_null())
1343 {
1344 return;
1345 }
1346
1347 if (transaction->methodResponse.is_null())
1348 {
1349 transaction->methodResponse = std::move(data);
1350 return;
1351 }
1352
1353 // If they're both dictionaries or arrays, merge into one.
1354 // Otherwise, make the results an array with every result
1355 // an entry. Could also just fail in that case, but it
1356 // seems better to get the data back somehow.
Ed Tanous0bdda662023-08-03 17:27:34 -07001357 nlohmann::json::object_t* dataobj =
1358 data.get_ptr<nlohmann::json::object_t*>();
1359 if (transaction->methodResponse.is_object() && dataobj != nullptr)
Matt Spinler39a4e392019-01-15 11:53:13 -06001360 {
Ed Tanous0bdda662023-08-03 17:27:34 -07001361 for (auto& obj : *dataobj)
Matt Spinler39a4e392019-01-15 11:53:13 -06001362 {
1363 // Note: Will overwrite the data for a duplicate key
Ed Tanous0bdda662023-08-03 17:27:34 -07001364 transaction->methodResponse.emplace(obj.first,
1365 std::move(obj.second));
Matt Spinler39a4e392019-01-15 11:53:13 -06001366 }
1367 return;
1368 }
1369
Ed Tanous0bdda662023-08-03 17:27:34 -07001370 nlohmann::json::array_t* dataarr = data.get_ptr<nlohmann::json::array_t*>();
1371 if (transaction->methodResponse.is_array() && dataarr != nullptr)
Matt Spinler39a4e392019-01-15 11:53:13 -06001372 {
Ed Tanous0bdda662023-08-03 17:27:34 -07001373 for (auto& obj : *dataarr)
Matt Spinler39a4e392019-01-15 11:53:13 -06001374 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001375 transaction->methodResponse.emplace_back(std::move(obj));
Matt Spinler39a4e392019-01-15 11:53:13 -06001376 }
1377 return;
1378 }
1379
1380 if (!transaction->convertedToArray)
1381 {
1382 // They are different types. May as well turn them into an array
1383 nlohmann::json j = std::move(transaction->methodResponse);
1384 transaction->methodResponse = nlohmann::json::array();
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001385 transaction->methodResponse.emplace_back(std::move(j));
1386 transaction->methodResponse.emplace_back(std::move(data));
Matt Spinler39a4e392019-01-15 11:53:13 -06001387 transaction->convertedToArray = true;
1388 }
1389 else
1390 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001391 transaction->methodResponse.emplace_back(std::move(data));
Matt Spinler39a4e392019-01-15 11:53:13 -06001392 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001393}
1394
Ed Tanousb5a76932020-09-29 16:16:58 -07001395inline void findActionOnInterface(
1396 const std::shared_ptr<InProgressActionData>& transaction,
1397 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001398{
Ed Tanous62598e32023-07-17 17:06:25 -07001399 BMCWEB_LOG_DEBUG("findActionOnInterface for connection {}", connectionName);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001400 crow::connections::systemBus->async_method_call(
1401 [transaction, connectionName{std::string(connectionName)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001402 const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001403 const std::string& introspectXml) {
Ed Tanous62598e32023-07-17 17:06:25 -07001404 BMCWEB_LOG_DEBUG("got xml:\n {}", introspectXml);
Ed Tanous002d39b2022-05-31 08:59:27 -07001405 if (ec)
1406 {
Ed Tanous62598e32023-07-17 17:06:25 -07001407 BMCWEB_LOG_ERROR(
1408 "Introspect call failed with error: {} on process: {}",
1409 ec.message(), connectionName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001410 return;
1411 }
1412 tinyxml2::XMLDocument doc;
Matt Spinler318bd892019-01-15 09:59:20 -06001413
Ed Tanous002d39b2022-05-31 08:59:27 -07001414 doc.Parse(introspectXml.data(), introspectXml.size());
1415 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1416 if (pRoot == nullptr)
1417 {
Ed Tanous62598e32023-07-17 17:06:25 -07001418 BMCWEB_LOG_ERROR("XML document failed to parse {}", connectionName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001419 return;
1420 }
1421 tinyxml2::XMLElement* interfaceNode =
1422 pRoot->FirstChildElement("interface");
1423 while (interfaceNode != nullptr)
1424 {
1425 const char* thisInterfaceName = interfaceNode->Attribute("name");
1426 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001427 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001428 if (!transaction->interfaceName.empty() &&
1429 (transaction->interfaceName != thisInterfaceName))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001430 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001431 interfaceNode =
1432 interfaceNode->NextSiblingElement("interface");
1433 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001434 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001435
1436 tinyxml2::XMLElement* methodNode =
1437 interfaceNode->FirstChildElement("method");
1438 while (methodNode != nullptr)
1439 {
1440 const char* thisMethodName = methodNode->Attribute("name");
Ed Tanous62598e32023-07-17 17:06:25 -07001441 BMCWEB_LOG_DEBUG("Found method: {}", thisMethodName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001442 if (thisMethodName != nullptr &&
1443 thisMethodName == transaction->methodName)
1444 {
Ed Tanous62598e32023-07-17 17:06:25 -07001445 BMCWEB_LOG_DEBUG(
1446 "Found method named {} on interface {}",
1447 thisMethodName, thisInterfaceName);
Patrick Williams59d494e2022-07-22 19:26:55 -05001448 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001449 crow::connections::systemBus->new_method_call(
1450 connectionName.c_str(),
1451 transaction->path.c_str(), thisInterfaceName,
1452 transaction->methodName.c_str());
1453
1454 tinyxml2::XMLElement* argumentNode =
1455 methodNode->FirstChildElement("arg");
1456
1457 std::string returnType;
1458
1459 // Find the output type
1460 while (argumentNode != nullptr)
1461 {
1462 const char* argDirection =
1463 argumentNode->Attribute("direction");
1464 const char* argType =
1465 argumentNode->Attribute("type");
1466 if (argDirection != nullptr && argType != nullptr &&
1467 std::string(argDirection) == "out")
1468 {
1469 returnType = argType;
1470 break;
1471 }
1472 argumentNode =
1473 argumentNode->NextSiblingElement("arg");
1474 }
1475
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001476 auto argIt = transaction->arguments.begin();
Ed Tanous002d39b2022-05-31 08:59:27 -07001477
1478 argumentNode = methodNode->FirstChildElement("arg");
1479
1480 while (argumentNode != nullptr)
1481 {
1482 const char* argDirection =
1483 argumentNode->Attribute("direction");
1484 const char* argType =
1485 argumentNode->Attribute("type");
1486 if (argDirection != nullptr && argType != nullptr &&
1487 std::string(argDirection) == "in")
1488 {
1489 if (argIt == transaction->arguments.end())
1490 {
1491 transaction->setErrorStatus(
1492 "Invalid method args");
1493 return;
1494 }
1495 if (convertJsonToDbus(m.get(),
1496 std::string(argType),
1497 *argIt) < 0)
1498 {
1499 transaction->setErrorStatus(
1500 "Invalid method arg type");
1501 return;
1502 }
1503
1504 argIt++;
1505 }
1506 argumentNode =
1507 argumentNode->NextSiblingElement("arg");
1508 }
1509
1510 crow::connections::systemBus->async_send(
Patrick Williams5a39f772023-10-20 11:20:21 -05001511 m, [transaction, returnType](
1512 const boost::system::error_code& ec2,
1513 sdbusplus::message_t& m2) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001514 if (ec2)
1515 {
1516 transaction->methodFailed = true;
1517 const sd_bus_error* e = m2.get_error();
1518
1519 if (e != nullptr)
1520 {
1521 setErrorResponse(
Lei YU28dd5ca2023-03-17 13:17:05 +08001522 transaction->asyncResp->res,
Ed Tanous002d39b2022-05-31 08:59:27 -07001523 boost::beast::http::status::bad_request,
1524 e->name, e->message);
1525 }
1526 else
1527 {
1528 setErrorResponse(
Lei YU28dd5ca2023-03-17 13:17:05 +08001529 transaction->asyncResp->res,
Ed Tanous002d39b2022-05-31 08:59:27 -07001530 boost::beast::http::status::bad_request,
1531 "Method call failed", methodFailedMsg);
1532 }
1533 return;
1534 }
1535 transaction->methodPassed = true;
1536
1537 handleMethodResponse(transaction, m2, returnType);
Patrick Williams5a39f772023-10-20 11:20:21 -05001538 });
Ed Tanous002d39b2022-05-31 08:59:27 -07001539 break;
1540 }
1541 methodNode = methodNode->NextSiblingElement("method");
1542 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001543 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001544 interfaceNode = interfaceNode->NextSiblingElement("interface");
1545 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001546 },
Ed Tanous1abe55e2018-09-05 08:30:59 -07001547 connectionName, transaction->path,
1548 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001549}
1550
zhanghch058d1b46d2021-04-01 11:18:24 +08001551inline void handleAction(const crow::Request& req,
1552 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001553 const std::string& objectPath,
1554 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001555{
Ed Tanous62598e32023-07-17 17:06:25 -07001556 BMCWEB_LOG_DEBUG("handleAction on path: {} and method {}", objectPath,
1557 methodName);
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001558 nlohmann::json requestDbusData;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001559
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001560 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
1561 if (ret == JsonParseResult::BadContentType)
1562 {
1563 setErrorResponse(asyncResp->res,
1564 boost::beast::http::status::unsupported_media_type,
1565 invalidContentType, unsupportedMediaMsg);
1566 return;
1567 }
1568 if (ret != JsonParseResult::Success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001569 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001570 setErrorResponse(asyncResp->res,
1571 boost::beast::http::status::bad_request, noJsonDesc,
1572 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001573 return;
1574 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001575 nlohmann::json::iterator data = requestDbusData.find("data");
1576 if (data == requestDbusData.end())
1577 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001578 setErrorResponse(asyncResp->res,
1579 boost::beast::http::status::bad_request, noJsonDesc,
1580 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001581 return;
1582 }
1583
1584 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001585 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001586 setErrorResponse(asyncResp->res,
1587 boost::beast::http::status::bad_request, noJsonDesc,
1588 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001589 return;
1590 }
Lei YU28dd5ca2023-03-17 13:17:05 +08001591 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001592
1593 transaction->path = objectPath;
1594 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001595 transaction->arguments = std::move(*data);
George Liu2b731192023-01-11 16:27:13 +08001596 dbus::utility::getDbusObject(
1597 objectPath, {},
Ed Tanous1abe55e2018-09-05 08:30:59 -07001598 [transaction](
George Liu2b731192023-01-11 16:27:13 +08001599 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001600 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1601 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001602 if (ec || interfaceNames.empty())
1603 {
Ed Tanous62598e32023-07-17 17:06:25 -07001604 BMCWEB_LOG_ERROR("Can't find object");
Lei YU28dd5ca2023-03-17 13:17:05 +08001605 setErrorResponse(transaction->asyncResp->res,
Ed Tanous002d39b2022-05-31 08:59:27 -07001606 boost::beast::http::status::not_found,
1607 notFoundDesc, notFoundMsg);
1608 return;
1609 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001610
Ed Tanous62598e32023-07-17 17:06:25 -07001611 BMCWEB_LOG_DEBUG("GetObject returned {} object(s)",
1612 interfaceNames.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001613
Ed Tanous002d39b2022-05-31 08:59:27 -07001614 for (const std::pair<std::string, std::vector<std::string>>& object :
1615 interfaceNames)
1616 {
1617 findActionOnInterface(transaction, object.first);
1618 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001619 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001620}
1621
zhanghch058d1b46d2021-04-01 11:18:24 +08001622inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1623 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001624{
Ed Tanous62598e32023-07-17 17:06:25 -07001625 BMCWEB_LOG_DEBUG("handleDelete on path: {}", objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06001626
George Liu2b731192023-01-11 16:27:13 +08001627 dbus::utility::getDbusObject(
1628 objectPath, {},
zhanghch058d1b46d2021-04-01 11:18:24 +08001629 [asyncResp, objectPath](
George Liu2b731192023-01-11 16:27:13 +08001630 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001631 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1632 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001633 if (ec || interfaceNames.empty())
1634 {
Ed Tanous62598e32023-07-17 17:06:25 -07001635 BMCWEB_LOG_ERROR("Can't find object");
Ed Tanous002d39b2022-05-31 08:59:27 -07001636 setErrorResponse(asyncResp->res,
1637 boost::beast::http::status::method_not_allowed,
1638 methodNotAllowedDesc, methodNotAllowedMsg);
1639 return;
1640 }
Matt Spinlerde818812018-12-11 16:39:20 -06001641
Lei YU28dd5ca2023-03-17 13:17:05 +08001642 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001643 transaction->path = objectPath;
1644 transaction->methodName = "Delete";
1645 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
Matt Spinlerde818812018-12-11 16:39:20 -06001646
Ed Tanous002d39b2022-05-31 08:59:27 -07001647 for (const std::pair<std::string, std::vector<std::string>>& object :
1648 interfaceNames)
1649 {
1650 findActionOnInterface(transaction, object.first);
1651 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001652 });
Matt Spinlerde818812018-12-11 16:39:20 -06001653}
1654
zhanghch058d1b46d2021-04-01 11:18:24 +08001655inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1656 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001657{
George Liu7a1dbc42022-12-07 16:03:22 +08001658 dbus::utility::getSubTreePaths(
1659 objectPath, depth, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001660 [asyncResp](
George Liu7a1dbc42022-12-07 16:03:22 +08001661 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001662 const dbus::utility::MapperGetSubTreePathsResponse& objectPaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001663 if (ec)
1664 {
1665 setErrorResponse(asyncResp->res,
1666 boost::beast::http::status::not_found,
1667 notFoundDesc, notFoundMsg);
1668 }
1669 else
1670 {
1671 asyncResp->res.jsonValue["status"] = "ok";
1672 asyncResp->res.jsonValue["message"] = "200 OK";
1673 asyncResp->res.jsonValue["data"] = objectPaths;
1674 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001675 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001676}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001677
zhanghch058d1b46d2021-04-01 11:18:24 +08001678inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1679 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001680{
Ed Tanous62598e32023-07-17 17:06:25 -07001681 BMCWEB_LOG_DEBUG("Doing enumerate on {}", objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07001682
Ed Tanous14766872022-03-15 10:44:42 -07001683 asyncResp->res.jsonValue["message"] = "200 OK";
1684 asyncResp->res.jsonValue["status"] = "ok";
1685 asyncResp->res.jsonValue["data"] = nlohmann::json::object();
Ed Tanous049a0512018-11-01 13:58:42 -07001686
George Liue99073f2022-12-09 11:06:16 +08001687 dbus::utility::getSubTree(
1688 objectPath, 0, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001689 [objectPath, asyncResp](
George Liue99073f2022-12-09 11:06:16 +08001690 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001691 const dbus::utility::MapperGetSubTreeResponse& objectNames) {
Patrick Williams89492a12023-05-10 07:51:34 -05001692 auto transaction = std::make_shared<InProgressEnumerateData>(objectPath,
1693 asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001694
Ed Tanous002d39b2022-05-31 08:59:27 -07001695 transaction->subtree =
1696 std::make_shared<dbus::utility::MapperGetSubTreeResponse>(
1697 objectNames);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001698
Ed Tanous002d39b2022-05-31 08:59:27 -07001699 if (ec)
1700 {
Ed Tanous62598e32023-07-17 17:06:25 -07001701 BMCWEB_LOG_ERROR("GetSubTree failed on {}",
1702 transaction->objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07001703 setErrorResponse(transaction->asyncResp->res,
1704 boost::beast::http::status::not_found,
1705 notFoundDesc, notFoundMsg);
1706 return;
1707 }
Ed Tanous64530012018-02-06 17:08:16 -08001708
Ed Tanous002d39b2022-05-31 08:59:27 -07001709 // Add the data for the path passed in to the results
1710 // as if GetSubTree returned it, and continue on enumerating
1711 getObjectAndEnumerate(transaction);
Patrick Williams5a39f772023-10-20 11:20:21 -05001712 });
Ed Tanous64530012018-02-06 17:08:16 -08001713}
Ed Tanous911ac312017-08-15 09:37:42 -07001714
zhanghch058d1b46d2021-04-01 11:18:24 +08001715inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1716 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001717{
Ed Tanous62598e32023-07-17 17:06:25 -07001718 BMCWEB_LOG_DEBUG("handleGet: {} prop:{}", objectPath, destProperty);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001719 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001720 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001721
Ed Tanous1abe55e2018-09-05 08:30:59 -07001722 std::shared_ptr<std::string> path =
1723 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001724
George Liu2b731192023-01-11 16:27:13 +08001725 dbus::utility::getDbusObject(
1726 *path, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001727 [asyncResp, path,
George Liu2b731192023-01-11 16:27:13 +08001728 propertyName](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001729 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001730 if (ec || objectNames.empty())
1731 {
1732 setErrorResponse(asyncResp->res,
1733 boost::beast::http::status::not_found,
1734 notFoundDesc, notFoundMsg);
1735 return;
1736 }
1737 std::shared_ptr<nlohmann::json> response =
1738 std::make_shared<nlohmann::json>(nlohmann::json::object());
1739 // The mapper should never give us an empty interface names
1740 // list, but check anyway
1741 for (const std::pair<std::string, std::vector<std::string>>&
1742 connection : objectNames)
1743 {
1744 const std::vector<std::string>& interfaceNames = connection.second;
1745
1746 if (interfaceNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001747 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001748 setErrorResponse(asyncResp->res,
1749 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001750 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001751 return;
1752 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001753
1754 for (const std::string& interface : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001755 {
Patrick Williams59d494e2022-07-22 19:26:55 -05001756 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001757 crow::connections::systemBus->new_method_call(
1758 connection.first.c_str(), path->c_str(),
1759 "org.freedesktop.DBus.Properties", "GetAll");
1760 m.append(interface);
1761 crow::connections::systemBus->async_send(
1762 m, [asyncResp, response,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001763 propertyName](const boost::system::error_code& ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05001764 sdbusplus::message_t& msg) {
Patrick Williams5a39f772023-10-20 11:20:21 -05001765 if (ec2)
1766 {
1767 BMCWEB_LOG_ERROR("Bad dbus request error: {}", ec2);
1768 }
1769 else
1770 {
1771 nlohmann::json properties;
1772 int r = convertDBusToJSON("a{sv}", msg, properties);
1773 if (r < 0)
Ed Tanous002d39b2022-05-31 08:59:27 -07001774 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001775 BMCWEB_LOG_ERROR("convertDBusToJSON failed");
Ed Tanous002d39b2022-05-31 08:59:27 -07001776 }
1777 else
1778 {
Ed Tanous0bdda662023-08-03 17:27:34 -07001779 nlohmann::json::object_t* obj =
1780 properties.get_ptr<nlohmann::json::object_t*>();
1781 if (obj == nullptr)
1782 {
1783 return;
1784 }
1785 for (auto& prop : *obj)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001786 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001787 // if property name is empty, or
1788 // matches our search query, add it
1789 // to the response json
Ed Tanous1abe55e2018-09-05 08:30:59 -07001790
Patrick Williams5a39f772023-10-20 11:20:21 -05001791 if (propertyName->empty())
1792 {
Ed Tanous0bdda662023-08-03 17:27:34 -07001793 (*response)[prop.first] =
1794 std::move(prop.second);
Patrick Williams5a39f772023-10-20 11:20:21 -05001795 }
Ed Tanous0bdda662023-08-03 17:27:34 -07001796 else if (prop.first == *propertyName)
Patrick Williams5a39f772023-10-20 11:20:21 -05001797 {
Ed Tanous0bdda662023-08-03 17:27:34 -07001798 *response = std::move(prop.second);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001799 }
1800 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001801 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001802 }
1803 if (response.use_count() == 1)
1804 {
1805 if (!propertyName->empty() && response->empty())
Ed Tanous002d39b2022-05-31 08:59:27 -07001806 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001807 setErrorResponse(
1808 asyncResp->res,
1809 boost::beast::http::status::not_found,
1810 propNotFoundDesc, notFoundMsg);
Ed Tanous002d39b2022-05-31 08:59:27 -07001811 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001812 else
1813 {
1814 asyncResp->res.jsonValue["status"] = "ok";
1815 asyncResp->res.jsonValue["message"] = "200 OK";
1816 asyncResp->res.jsonValue["data"] = *response;
1817 }
1818 }
1819 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001820 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001821 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001822 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001823}
1824
Ed Tanous1abe55e2018-09-05 08:30:59 -07001825struct AsyncPutRequest
1826{
Ed Tanous4e23a442022-06-06 09:57:26 -07001827 explicit AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
zhanghch058d1b46d2021-04-01 11:18:24 +08001828 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001829 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001830 ~AsyncPutRequest()
1831 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001832 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001833 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001834 setErrorResponse(asyncResp->res,
1835 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001836 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001837 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001838 }
1839
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001840 AsyncPutRequest(const AsyncPutRequest&) = delete;
1841 AsyncPutRequest(AsyncPutRequest&&) = delete;
1842 AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1843 AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1844
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001845 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001846 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001847 setErrorResponse(asyncResp->res,
1848 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001849 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001850 }
1851
zhanghch058d1b46d2021-04-01 11:18:24 +08001852 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001853 std::string objectPath;
1854 std::string propertyName;
1855 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001856};
1857
zhanghch058d1b46d2021-04-01 11:18:24 +08001858inline void handlePut(const crow::Request& req,
1859 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001860 const std::string& objectPath,
1861 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001862{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001863 if (destProperty.empty())
1864 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001865 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001866 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001867 return;
1868 }
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001869 nlohmann::json requestDbusData;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001870
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001871 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
1872 if (ret == JsonParseResult::BadContentType)
1873 {
1874 setErrorResponse(asyncResp->res,
1875 boost::beast::http::status::unsupported_media_type,
1876 invalidContentType, unsupportedMediaMsg);
1877 return;
1878 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001879
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001880 if (ret != JsonParseResult::Success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001881 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001882 setErrorResponse(asyncResp->res,
1883 boost::beast::http::status::bad_request, noJsonDesc,
1884 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001885 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001886 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001887
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001888 auto propertyIt = requestDbusData.find("data");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001889 if (propertyIt == requestDbusData.end())
1890 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001891 setErrorResponse(asyncResp->res,
1892 boost::beast::http::status::bad_request, noJsonDesc,
1893 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001894 return;
1895 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001896 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001897 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001898 transaction->objectPath = objectPath;
1899 transaction->propertyName = destProperty;
1900 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001901
George Liu2b731192023-01-11 16:27:13 +08001902 dbus::utility::getDbusObject(
1903 transaction->objectPath, {},
1904 [transaction](const boost::system::error_code& ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001905 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001906 if (!ec2 && objectNames.empty())
1907 {
1908 setErrorResponse(transaction->asyncResp->res,
1909 boost::beast::http::status::not_found,
1910 propNotFoundDesc, notFoundMsg);
1911 return;
1912 }
Ed Tanous911ac312017-08-15 09:37:42 -07001913
Ed Tanous002d39b2022-05-31 08:59:27 -07001914 for (const std::pair<std::string, std::vector<std::string>>&
1915 connection : objectNames)
1916 {
1917 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001918
Ed Tanous002d39b2022-05-31 08:59:27 -07001919 crow::connections::systemBus->async_method_call(
1920 [connectionName{std::string(connectionName)},
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001921 transaction](const boost::system::error_code& ec3,
Ed Tanous002d39b2022-05-31 08:59:27 -07001922 const std::string& introspectXml) {
1923 if (ec3)
1924 {
Ed Tanous62598e32023-07-17 17:06:25 -07001925 BMCWEB_LOG_ERROR(
1926 "Introspect call failed with error: {} on process: {}",
1927 ec3.message(), connectionName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001928 transaction->setErrorStatus("Unexpected Error");
1929 return;
1930 }
1931 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001932
Ed Tanous002d39b2022-05-31 08:59:27 -07001933 doc.Parse(introspectXml.c_str());
1934 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1935 if (pRoot == nullptr)
1936 {
Ed Tanous62598e32023-07-17 17:06:25 -07001937 BMCWEB_LOG_ERROR("XML document failed to parse: {}",
1938 introspectXml);
Ed Tanous002d39b2022-05-31 08:59:27 -07001939 transaction->setErrorStatus("Unexpected Error");
1940 return;
1941 }
1942 tinyxml2::XMLElement* ifaceNode =
1943 pRoot->FirstChildElement("interface");
1944 while (ifaceNode != nullptr)
1945 {
1946 const char* interfaceName = ifaceNode->Attribute("name");
Ed Tanous62598e32023-07-17 17:06:25 -07001947 BMCWEB_LOG_DEBUG("found interface {}", interfaceName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001948 tinyxml2::XMLElement* propNode =
1949 ifaceNode->FirstChildElement("property");
1950 while (propNode != nullptr)
1951 {
1952 const char* propertyName = propNode->Attribute("name");
Ed Tanous62598e32023-07-17 17:06:25 -07001953 BMCWEB_LOG_DEBUG("Found property {}", propertyName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001954 if (propertyName == transaction->propertyName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001955 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001956 const char* argType = propNode->Attribute("type");
1957 if (argType != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001958 {
Patrick Williams59d494e2022-07-22 19:26:55 -05001959 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001960 crow::connections::systemBus
1961 ->new_method_call(
1962 connectionName.c_str(),
1963 transaction->objectPath.c_str(),
1964 "org.freedesktop.DBus."
1965 "Properties",
1966 "Set");
1967 m.append(interfaceName,
1968 transaction->propertyName);
1969 int r = sd_bus_message_open_container(
1970 m.get(), SD_BUS_TYPE_VARIANT, argType);
1971 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001972 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001973 transaction->setErrorStatus(
1974 "Unexpected Error");
1975 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001976 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001977 r = convertJsonToDbus(
1978 m.get(), argType,
1979 transaction->propertyValue);
1980 if (r < 0)
1981 {
1982 if (r == -ERANGE)
1983 {
1984 transaction->setErrorStatus(
1985 "Provided property value "
1986 "is out of range for the "
1987 "property type");
1988 }
1989 else
1990 {
1991 transaction->setErrorStatus(
1992 "Invalid arg type");
1993 }
1994 return;
1995 }
1996 r = sd_bus_message_close_container(m.get());
1997 if (r < 0)
1998 {
1999 transaction->setErrorStatus(
2000 "Unexpected Error");
2001 return;
2002 }
2003 crow::connections::systemBus->async_send(
Patrick Williams5a39f772023-10-20 11:20:21 -05002004 m, [transaction](
2005 const boost::system::error_code& ec,
2006 sdbusplus::message_t& m2) {
Ed Tanous62598e32023-07-17 17:06:25 -07002007 BMCWEB_LOG_DEBUG("sent");
Ed Tanous002d39b2022-05-31 08:59:27 -07002008 if (ec)
2009 {
2010 const sd_bus_error* e = m2.get_error();
2011 setErrorResponse(
2012 transaction->asyncResp->res,
2013 boost::beast::http::status::
2014 forbidden,
2015 (e) != nullptr
2016 ? e->name
2017 : ec.category().name(),
2018 (e) != nullptr ? e->message
2019 : ec.message());
2020 }
2021 else
2022 {
2023 transaction->asyncResp->res
2024 .jsonValue["status"] = "ok";
2025 transaction->asyncResp->res
2026 .jsonValue["message"] = "200 OK";
2027 transaction->asyncResp->res
2028 .jsonValue["data"] = nullptr;
2029 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002030 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002031 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002032 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002033 propNode = propNode->NextSiblingElement("property");
2034 }
2035 ifaceNode = ifaceNode->NextSiblingElement("interface");
2036 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002037 },
Ed Tanous002d39b2022-05-31 08:59:27 -07002038 connectionName, transaction->objectPath,
2039 "org.freedesktop.DBus.Introspectable", "Introspect");
2040 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002041 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07002042}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002043
zhanghch058d1b46d2021-04-01 11:18:24 +08002044inline void handleDBusUrl(const crow::Request& req,
2045 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002046 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002047{
Ed Tanous049a0512018-11-01 13:58:42 -07002048 // If accessing a single attribute, fill in and update objectPath,
2049 // otherwise leave destProperty blank
Ed Tanouse05aec52022-01-25 10:28:56 -08002050 std::string destProperty;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002051 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002052 size_t attrPosition = objectPath.find(attrSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002053 if (attrPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002054 {
2055 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2056 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002057 objectPath.resize(attrPosition);
Ed Tanous049a0512018-11-01 13:58:42 -07002058 }
2059
Ed Tanousb41187f2019-10-24 16:30:02 -07002060 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002061 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002062 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002063 size_t actionPosition = objectPath.find(actionSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002064 if (actionPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002065 {
2066 std::string postProperty =
2067 objectPath.substr((actionPosition + strlen(actionSeperator)),
2068 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002069 objectPath.resize(actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002070 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002071 return;
2072 }
2073 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002074 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002075 {
Ed Tanous11ba3972022-07-11 09:50:41 -07002076 if (objectPath.ends_with("/enumerate"))
Ed Tanous049a0512018-11-01 13:58:42 -07002077 {
2078 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2079 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002080 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002081 }
Ed Tanous11ba3972022-07-11 09:50:41 -07002082 else if (objectPath.ends_with("/list"))
Ed Tanous049a0512018-11-01 13:58:42 -07002083 {
2084 objectPath.erase(objectPath.end() - sizeof("list"),
2085 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002086 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002087 }
2088 else
2089 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002090 // Trim any trailing "/" at the end
Ed Tanous11ba3972022-07-11 09:50:41 -07002091 if (objectPath.ends_with("/"))
Ed Tanousf839dfe2018-11-12 11:11:15 -08002092 {
2093 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002094 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002095 }
2096 else
2097 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002098 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002099 }
Ed Tanous049a0512018-11-01 13:58:42 -07002100 }
2101 return;
2102 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002103 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002104 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002105 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002106 return;
2107 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002108 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002109 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002110 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002111 return;
2112 }
Ed Tanous049a0512018-11-01 13:58:42 -07002113
zhanghch058d1b46d2021-04-01 11:18:24 +08002114 setErrorResponse(asyncResp->res,
2115 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002116 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002117}
2118
Ed Tanous1656b292022-05-04 11:33:42 -07002119inline void
2120 handleBusSystemPost(const crow::Request& req,
2121 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2122 const std::string& processName,
2123 const std::string& requestedPath)
2124{
2125 std::vector<std::string> strs;
Ed Tanous50ebd4a2023-01-19 19:03:17 -08002126
2127 bmcweb::split(strs, requestedPath, '/');
Ed Tanous1656b292022-05-04 11:33:42 -07002128 std::string objectPath;
2129 std::string interfaceName;
2130 std::string methodName;
2131 auto it = strs.begin();
2132 if (it == strs.end())
2133 {
2134 objectPath = "/";
2135 }
2136 while (it != strs.end())
2137 {
2138 // Check if segment contains ".". If it does, it must be an
2139 // interface
2140 if (it->find(".") != std::string::npos)
2141 {
2142 break;
2143 // This check is necessary as the trailing slash gets
2144 // parsed as part of our <path> specifier above, which
2145 // causes the normal trailing backslash redirector to
2146 // fail.
2147 }
2148 if (!it->empty())
2149 {
2150 objectPath += "/" + *it;
2151 }
2152 it++;
2153 }
2154 if (it != strs.end())
2155 {
2156 interfaceName = *it;
2157 it++;
2158
2159 // after interface, we might have a method name
2160 if (it != strs.end())
2161 {
2162 methodName = *it;
2163 it++;
2164 }
2165 }
2166 if (it != strs.end())
2167 {
2168 // if there is more levels past the method name, something
2169 // went wrong, return not found
2170 asyncResp->res.result(boost::beast::http::status::not_found);
2171 return;
2172 }
2173 if (interfaceName.empty())
2174 {
2175 crow::connections::systemBus->async_method_call(
2176 [asyncResp, processName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002177 objectPath](const boost::system::error_code& ec,
Ed Tanous1656b292022-05-04 11:33:42 -07002178 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002179 if (ec)
2180 {
Ed Tanous62598e32023-07-17 17:06:25 -07002181 BMCWEB_LOG_ERROR(
2182 "Introspect call failed with error: {} on process: {} path: {}",
2183 ec.message(), processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002184 return;
2185 }
2186 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002187
Ed Tanous002d39b2022-05-31 08:59:27 -07002188 doc.Parse(introspectXml.c_str());
2189 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2190 if (pRoot == nullptr)
2191 {
Ed Tanous62598e32023-07-17 17:06:25 -07002192 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
2193 processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002194 asyncResp->res.jsonValue["status"] = "XML parse error";
2195 asyncResp->res.result(
2196 boost::beast::http::status::internal_server_error);
2197 return;
2198 }
2199
Ed Tanous62598e32023-07-17 17:06:25 -07002200 BMCWEB_LOG_DEBUG("{}", introspectXml);
Ed Tanous002d39b2022-05-31 08:59:27 -07002201 asyncResp->res.jsonValue["status"] = "ok";
2202 asyncResp->res.jsonValue["bus_name"] = processName;
2203 asyncResp->res.jsonValue["object_path"] = objectPath;
2204
2205 nlohmann::json& interfacesArray =
2206 asyncResp->res.jsonValue["interfaces"];
2207 interfacesArray = nlohmann::json::array();
2208 tinyxml2::XMLElement* interface =
2209 pRoot->FirstChildElement("interface");
2210
2211 while (interface != nullptr)
2212 {
2213 const char* ifaceName = interface->Attribute("name");
2214 if (ifaceName != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002215 {
Ed Tanous8a592812022-06-04 09:06:59 -07002216 nlohmann::json::object_t interfaceObj;
2217 interfaceObj["name"] = ifaceName;
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002218 interfacesArray.emplace_back(std::move(interfaceObj));
Ed Tanous1656b292022-05-04 11:33:42 -07002219 }
2220
Ed Tanous002d39b2022-05-31 08:59:27 -07002221 interface = interface->NextSiblingElement("interface");
2222 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002223 },
Ed Tanous1656b292022-05-04 11:33:42 -07002224 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2225 "Introspect");
2226 }
2227 else if (methodName.empty())
2228 {
2229 crow::connections::systemBus->async_method_call(
2230 [asyncResp, processName, objectPath,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002231 interfaceName](const boost::system::error_code& ec,
Ed Tanous1656b292022-05-04 11:33:42 -07002232 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002233 if (ec)
2234 {
Ed Tanous62598e32023-07-17 17:06:25 -07002235 BMCWEB_LOG_ERROR(
2236 "Introspect call failed with error: {} on process: {} path: {}",
2237 ec.message(), processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002238 return;
2239 }
2240 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002241
Ed Tanous002d39b2022-05-31 08:59:27 -07002242 doc.Parse(introspectXml.data(), introspectXml.size());
2243 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2244 if (pRoot == nullptr)
2245 {
Ed Tanous62598e32023-07-17 17:06:25 -07002246 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
2247 processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002248 asyncResp->res.result(
2249 boost::beast::http::status::internal_server_error);
2250 return;
2251 }
2252
2253 asyncResp->res.jsonValue["status"] = "ok";
2254 asyncResp->res.jsonValue["bus_name"] = processName;
2255 asyncResp->res.jsonValue["interface"] = interfaceName;
2256 asyncResp->res.jsonValue["object_path"] = objectPath;
2257
2258 nlohmann::json& methodsArray = asyncResp->res.jsonValue["methods"];
2259 methodsArray = nlohmann::json::array();
2260
2261 nlohmann::json& signalsArray = asyncResp->res.jsonValue["signals"];
2262 signalsArray = nlohmann::json::array();
2263
2264 nlohmann::json& propertiesObj =
2265 asyncResp->res.jsonValue["properties"];
2266 propertiesObj = nlohmann::json::object();
2267
2268 // if we know we're the only call, build the
2269 // json directly
2270 tinyxml2::XMLElement* interface =
2271 pRoot->FirstChildElement("interface");
2272 while (interface != nullptr)
2273 {
2274 const char* ifaceName = interface->Attribute("name");
2275
2276 if (ifaceName != nullptr && ifaceName == interfaceName)
Ed Tanous1656b292022-05-04 11:33:42 -07002277 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002278 break;
Ed Tanous1656b292022-05-04 11:33:42 -07002279 }
Ed Tanous14766872022-03-15 10:44:42 -07002280
Ed Tanous002d39b2022-05-31 08:59:27 -07002281 interface = interface->NextSiblingElement("interface");
2282 }
2283 if (interface == nullptr)
2284 {
2285 // if we got to the end of the list and
2286 // never found a match, throw 404
2287 asyncResp->res.result(boost::beast::http::status::not_found);
2288 return;
2289 }
Ed Tanous1656b292022-05-04 11:33:42 -07002290
Ed Tanous002d39b2022-05-31 08:59:27 -07002291 tinyxml2::XMLElement* methods =
2292 interface->FirstChildElement("method");
2293 while (methods != nullptr)
2294 {
2295 nlohmann::json argsArray = nlohmann::json::array();
2296 tinyxml2::XMLElement* arg = methods->FirstChildElement("arg");
2297 while (arg != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002298 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002299 nlohmann::json thisArg;
2300 for (const char* fieldName : std::array<const char*, 3>{
2301 "name", "direction", "type"})
Ed Tanous1656b292022-05-04 11:33:42 -07002302 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002303 const char* fieldValue = arg->Attribute(fieldName);
2304 if (fieldValue != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002305 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002306 thisArg[fieldName] = fieldValue;
2307 }
2308 }
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002309 argsArray.emplace_back(std::move(thisArg));
Ed Tanous002d39b2022-05-31 08:59:27 -07002310 arg = arg->NextSiblingElement("arg");
2311 }
2312
2313 const char* name = methods->Attribute("name");
2314 if (name != nullptr)
2315 {
2316 std::string uri;
2317 uri.reserve(14 + processName.size() + objectPath.size() +
2318 interfaceName.size() + strlen(name));
2319 uri += "/bus/system/";
2320 uri += processName;
2321 uri += objectPath;
2322 uri += "/";
2323 uri += interfaceName;
2324 uri += "/";
2325 uri += name;
2326
2327 nlohmann::json::object_t object;
2328 object["name"] = name;
2329 object["uri"] = std::move(uri);
2330 object["args"] = argsArray;
2331
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002332 methodsArray.emplace_back(std::move(object));
Ed Tanous002d39b2022-05-31 08:59:27 -07002333 }
2334 methods = methods->NextSiblingElement("method");
2335 }
2336 tinyxml2::XMLElement* signals =
2337 interface->FirstChildElement("signal");
2338 while (signals != nullptr)
2339 {
2340 nlohmann::json argsArray = nlohmann::json::array();
2341
2342 tinyxml2::XMLElement* arg = signals->FirstChildElement("arg");
2343 while (arg != nullptr)
2344 {
2345 const char* name = arg->Attribute("name");
2346 const char* type = arg->Attribute("type");
2347 if (name != nullptr && type != nullptr)
2348 {
Ed Tanous20fa6a22024-05-20 18:02:58 -07002349 nlohmann::json::object_t params;
2350 params["name"] = name;
2351 params["type"] = type;
2352 argsArray.push_back(std::move(params));
Ed Tanous002d39b2022-05-31 08:59:27 -07002353 }
2354 arg = arg->NextSiblingElement("arg");
2355 }
2356 const char* name = signals->Attribute("name");
2357 if (name != nullptr)
2358 {
2359 nlohmann::json::object_t object;
2360 object["name"] = name;
2361 object["args"] = argsArray;
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002362 signalsArray.emplace_back(std::move(object));
Ed Tanous002d39b2022-05-31 08:59:27 -07002363 }
2364
2365 signals = signals->NextSiblingElement("signal");
2366 }
2367
2368 tinyxml2::XMLElement* property =
2369 interface->FirstChildElement("property");
2370 while (property != nullptr)
2371 {
2372 const char* name = property->Attribute("name");
2373 const char* type = property->Attribute("type");
2374 if (type != nullptr && name != nullptr)
2375 {
Patrick Williams59d494e2022-07-22 19:26:55 -05002376 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07002377 crow::connections::systemBus->new_method_call(
2378 processName.c_str(), objectPath.c_str(),
2379 "org.freedesktop."
2380 "DBus."
2381 "Properties",
2382 "Get");
2383 m.append(interfaceName, name);
2384 nlohmann::json& propertyItem = propertiesObj[name];
2385 crow::connections::systemBus->async_send(
2386 m, [&propertyItem,
Ed Tanous8b242752023-06-27 17:17:13 -07002387 asyncResp](const boost::system::error_code& ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05002388 sdbusplus::message_t& msg) {
Patrick Williams5a39f772023-10-20 11:20:21 -05002389 if (ec2)
2390 {
2391 return;
2392 }
Ed Tanous1656b292022-05-04 11:33:42 -07002393
Ed Tanous07900812024-05-06 15:41:30 -07002394 int r = convertDBusToJSON("v", msg, propertyItem);
2395 if (r < 0)
2396 {
2397 BMCWEB_LOG_ERROR("Couldn't convert vector to json");
2398 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002399 });
Ed Tanous1656b292022-05-04 11:33:42 -07002400 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002401 property = property->NextSiblingElement("property");
2402 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002403 },
Ed Tanous1656b292022-05-04 11:33:42 -07002404 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2405 "Introspect");
2406 }
2407 else
2408 {
2409 if (req.method() != boost::beast::http::verb::post)
2410 {
2411 asyncResp->res.result(boost::beast::http::status::not_found);
2412 return;
2413 }
2414
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002415 nlohmann::json requestDbusData;
2416 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
2417 if (ret == JsonParseResult::BadContentType)
Ed Tanous1656b292022-05-04 11:33:42 -07002418 {
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002419 setErrorResponse(asyncResp->res,
2420 boost::beast::http::status::unsupported_media_type,
2421 invalidContentType, unsupportedMediaMsg);
Ed Tanous1656b292022-05-04 11:33:42 -07002422 return;
2423 }
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002424 if (ret != JsonParseResult::Success)
2425 {
2426 setErrorResponse(asyncResp->res,
2427 boost::beast::http::status::bad_request,
2428 noJsonDesc, badReqMsg);
2429 return;
2430 }
2431
Ed Tanous1656b292022-05-04 11:33:42 -07002432 if (!requestDbusData.is_array())
2433 {
2434 asyncResp->res.result(boost::beast::http::status::bad_request);
2435 return;
2436 }
Lei YU28dd5ca2023-03-17 13:17:05 +08002437 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous1656b292022-05-04 11:33:42 -07002438
2439 transaction->path = objectPath;
2440 transaction->methodName = methodName;
2441 transaction->arguments = std::move(requestDbusData);
2442
2443 findActionOnInterface(transaction, processName);
2444 }
2445}
2446
Ed Tanous23a21a12020-07-25 04:45:05 +00002447inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002448{
2449 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002450 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002451 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002452 [](const crow::Request&,
2453 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002454 nlohmann::json::array_t buses;
2455 nlohmann::json& bus = buses.emplace_back();
2456 bus["name"] = "system";
2457 asyncResp->res.jsonValue["busses"] = std::move(buses);
2458 asyncResp->res.jsonValue["status"] = "ok";
Patrick Williams5a39f772023-10-20 11:20:21 -05002459 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002460
2461 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002462 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002463 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002464 [](const crow::Request&,
2465 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002466 auto myCallback = [asyncResp](const boost::system::error_code& ec,
zhanghch058d1b46d2021-04-01 11:18:24 +08002467 std::vector<std::string>& names) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002468 if (ec)
2469 {
Ed Tanous62598e32023-07-17 17:06:25 -07002470 BMCWEB_LOG_ERROR("Dbus call failed with code {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07002471 asyncResp->res.result(
2472 boost::beast::http::status::internal_server_error);
2473 }
2474 else
2475 {
Ed Tanous3544d2a2023-08-06 18:12:20 -07002476 std::ranges::sort(names);
Ed Tanous002d39b2022-05-31 08:59:27 -07002477 asyncResp->res.jsonValue["status"] = "ok";
2478 auto& objectsSub = asyncResp->res.jsonValue["objects"];
Ed Tanous02cad962022-06-30 16:50:15 -07002479 for (const auto& name : names)
Ed Tanous002d39b2022-05-31 08:59:27 -07002480 {
2481 nlohmann::json::object_t object;
2482 object["name"] = name;
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002483 objectsSub.emplace_back(std::move(object));
Ed Tanous002d39b2022-05-31 08:59:27 -07002484 }
2485 }
2486 };
2487 crow::connections::systemBus->async_method_call(
2488 std::move(myCallback), "org.freedesktop.DBus", "/",
2489 "org.freedesktop.DBus", "ListNames");
Patrick Williams5a39f772023-10-20 11:20:21 -05002490 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002491
2492 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002493 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002494 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002495 [](const crow::Request&,
2496 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002497 handleList(asyncResp, "/");
Patrick Williams5a39f772023-10-20 11:20:21 -05002498 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002499
2500 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002501 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002502 .methods(boost::beast::http::verb::get)(
2503 [](const crow::Request& req,
2504 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002505 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002506 std::string objectPath = "/xyz/" + path;
2507 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002508 });
zhanghch058d1b46d2021-04-01 11:18:24 +08002509
2510 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002511 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002512 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2513 boost::beast::http::verb::delete_)(
2514 [](const crow::Request& req,
2515 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2516 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002517 std::string objectPath = "/xyz/" + path;
2518 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002519 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002520
Ed Tanous049a0512018-11-01 13:58:42 -07002521 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002522 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002523 .methods(boost::beast::http::verb::get)(
2524 [](const crow::Request& req,
2525 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2526 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002527 std::string objectPath = "/org/" + path;
2528 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002529 });
Tanousf00032d2018-11-05 01:18:10 -03002530
2531 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002532 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002533 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2534 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002535 [](const crow::Request& req,
2536 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002537 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002538 std::string objectPath = "/org/" + path;
2539 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002540 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002541
Ed Tanous1abe55e2018-09-05 08:30:59 -07002542 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002543 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002544 .methods(boost::beast::http::verb::get)(
2545 [](const crow::Request&,
2546 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2547 const std::string& dumpId) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002548 if (!validateFilename(dumpId))
2549 {
2550 asyncResp->res.result(boost::beast::http::status::bad_request);
2551 return;
2552 }
2553 std::filesystem::path loc("/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002554
Ed Tanous002d39b2022-05-31 08:59:27 -07002555 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002556
Ed Tanous002d39b2022-05-31 08:59:27 -07002557 if (!std::filesystem::exists(loc) ||
2558 !std::filesystem::is_directory(loc))
2559 {
Ed Tanous62598e32023-07-17 17:06:25 -07002560 BMCWEB_LOG_ERROR("{}Not found", loc.string());
Ed Tanous002d39b2022-05-31 08:59:27 -07002561 asyncResp->res.result(boost::beast::http::status::not_found);
2562 return;
2563 }
2564 std::filesystem::directory_iterator files(loc);
zhanghch058d1b46d2021-04-01 11:18:24 +08002565
Ed Tanous002d39b2022-05-31 08:59:27 -07002566 for (const auto& file : files)
2567 {
Ed Tanous27b0cf92023-08-07 12:02:40 -07002568 if (!asyncResp->res.openFile(file))
Ed Tanous002d39b2022-05-31 08:59:27 -07002569 {
2570 continue;
2571 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002572
Ed Tanousd9f6c622022-03-17 09:12:17 -07002573 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07002574 "application/octet-stream");
zhanghch058d1b46d2021-04-01 11:18:24 +08002575
Ed Tanous002d39b2022-05-31 08:59:27 -07002576 // Assuming only one dump file will be present in the dump
2577 // id directory
2578 std::string dumpFileName = file.path().filename().string();
zhanghch058d1b46d2021-04-01 11:18:24 +08002579
Ed Tanous002d39b2022-05-31 08:59:27 -07002580 // Filename should be in alphanumeric, dot and underscore
2581 // Its based on phosphor-debug-collector application
2582 // dumpfile format
Ed Tanous4b242742023-05-11 09:51:51 -07002583 static std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
Ed Tanous002d39b2022-05-31 08:59:27 -07002584 if (!std::regex_match(dumpFileName, dumpFileRegex))
2585 {
Ed Tanous62598e32023-07-17 17:06:25 -07002586 BMCWEB_LOG_ERROR("Invalid dump filename {}", dumpFileName);
zhanghch058d1b46d2021-04-01 11:18:24 +08002587 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002588 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07002589 }
Patrick Williams89492a12023-05-10 07:51:34 -05002590 std::string contentDispositionParam = "attachment; filename=\"" +
2591 dumpFileName + "\"";
Ed Tanous002d39b2022-05-31 08:59:27 -07002592
Ed Tanousd9f6c622022-03-17 09:12:17 -07002593 asyncResp->res.addHeader(
2594 boost::beast::http::field::content_disposition,
2595 contentDispositionParam);
Ed Tanous002d39b2022-05-31 08:59:27 -07002596
Ed Tanous002d39b2022-05-31 08:59:27 -07002597 return;
2598 }
2599 asyncResp->res.result(boost::beast::http::status::not_found);
2600 return;
Patrick Williams5a39f772023-10-20 11:20:21 -05002601 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002602
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002603 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002604 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002605
2606 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002607 [](const crow::Request&,
2608 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002609 const std::string& connection) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002610 introspectObjects(connection, "/", asyncResp);
Patrick Williams5a39f772023-10-20 11:20:21 -05002611 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002612
2613 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002614 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous1656b292022-05-04 11:33:42 -07002615 .methods(boost::beast::http::verb::get,
2616 boost::beast::http::verb::post)(handleBusSystemPost);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002617}
2618} // namespace openbmc_mapper
2619} // namespace crow