blob: f0b72fbcc45c99c97b6549dde8e748d4b909d2cb [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 Tanouse3cb5a32018-08-08 14:16:49 -0700824 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700825 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700826 else if (argCode.starts_with("a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700827 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700828 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700829 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700830 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700831 if (r < 0)
832 {
833 return r;
834 }
835
Ed Tanous0dfeda62019-10-24 11:21:38 -0700836 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700837 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700838 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700839 if (r < 0)
840 {
841 return r;
842 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700843 }
844 sd_bus_message_close_container(m);
845 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700846 else if (argCode.starts_with("v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700847 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700848 std::string containedType = argCode.substr(1);
Ed Tanous62598e32023-07-17 17:06:25 -0700849 BMCWEB_LOG_DEBUG("variant type: {} appending variant of type: {}",
850 argCode, containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700851 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700852 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700853 if (r < 0)
854 {
855 return r;
856 }
857
Ed Tanous81ce6092020-12-17 16:54:55 +0000858 r = convertJsonToDbus(m, containedType, inputJson);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700859 if (r < 0)
860 {
861 return r;
862 }
863
864 r = sd_bus_message_close_container(m);
865 if (r < 0)
866 {
867 return r;
868 }
869 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700870 else if (argCode.starts_with("(") && argCode.ends_with(")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700871 {
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300872 std::string containedType = argCode.substr(1, argCode.size() - 2);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700873 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700874 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800875 if (r < 0)
876 {
877 return r;
878 }
879
Ed Tanous1abe55e2018-09-05 08:30:59 -0700880 nlohmann::json::const_iterator it = j->begin();
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300881 for (const std::string& argCode2 : dbusArgSplit(containedType))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700882 {
883 if (it == j->end())
884 {
885 return -1;
886 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000887 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700888 if (r < 0)
889 {
890 return r;
891 }
892 it++;
893 }
894 r = sd_bus_message_close_container(m);
895 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700896 else if (argCode.starts_with("{") && argCode.ends_with("}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700897 {
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300898 std::string containedType = argCode.substr(1, argCode.size() - 2);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700899 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700900 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800901 if (r < 0)
902 {
903 return r;
904 }
905
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700906 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700907 if (codes.size() != 2)
908 {
909 return -1;
910 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700911 const std::string& keyType = codes[0];
912 const std::string& valueType = codes[1];
Ed Tanous3174e4d2020-10-07 11:41:22 -0700913 for (const auto& it : j->items())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700914 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700915 r = convertJsonToDbus(m, keyType, it.key());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700916 if (r < 0)
917 {
918 return r;
919 }
920
Ed Tanous2c70f802020-09-28 14:29:23 -0700921 r = convertJsonToDbus(m, valueType, it.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700922 if (r < 0)
923 {
924 return r;
925 }
926 }
927 r = sd_bus_message_close_container(m);
928 }
929 else
930 {
931 return -2;
932 }
933 if (r < 0)
934 {
935 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700936 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700937
Ed Tanous1abe55e2018-09-05 08:30:59 -0700938 if (argTypes.size() > 1)
939 {
940 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700941 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700942 }
Matt Spinler127ea542019-01-14 11:04:28 -0600943
944 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700945}
946
Matt Spinlerd22a7132019-01-14 12:14:30 -0600947template <typename T>
Patrick Williams59d494e2022-07-22 19:26:55 -0500948int readMessageItem(const std::string& typeCode, sdbusplus::message_t& m,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500949 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600950{
951 T value;
Ed Tanousf79ce6a2024-03-20 12:27:06 -0700952 // When T == char*, this warning fires. Unclear how to resolve
953 // Given that sd-bus takes a void pointer to a char*, and that's
954 // Not something we can fix.
955 // NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600956 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
957 if (r < 0)
958 {
Ed Tanous62598e32023-07-17 17:06:25 -0700959 BMCWEB_LOG_ERROR("sd_bus_message_read_basic on type {} failed!",
960 typeCode);
Matt Spinlerd22a7132019-01-14 12:14:30 -0600961 return r;
962 }
963
964 data = value;
965 return 0;
966}
967
Patrick Williams59d494e2022-07-22 19:26:55 -0500968int convertDBusToJSON(const std::string& returnType, sdbusplus::message_t& m,
969 nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600970
Ed Tanous23a21a12020-07-25 04:45:05 +0000971inline int readDictEntryFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -0500972 sdbusplus::message_t& m,
Ed Tanous23a21a12020-07-25 04:45:05 +0000973 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600974{
975 std::vector<std::string> types = dbusArgSplit(typeCode);
976 if (types.size() != 2)
977 {
Ed Tanous62598e32023-07-17 17:06:25 -0700978 BMCWEB_LOG_ERROR("wrong number contained types in dictionary: {}",
979 types.size());
Matt Spinler6df8f992019-01-14 12:47:47 -0600980 return -1;
981 }
982
983 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
984 typeCode.c_str());
985 if (r < 0)
986 {
Ed Tanous62598e32023-07-17 17:06:25 -0700987 BMCWEB_LOG_ERROR("sd_bus_message_enter_container with rc {}", r);
Matt Spinler6df8f992019-01-14 12:47:47 -0600988 return r;
989 }
990
991 nlohmann::json key;
992 r = convertDBusToJSON(types[0], m, key);
993 if (r < 0)
994 {
995 return r;
996 }
997
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500998 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -0600999 if (keyPtr == nullptr)
1000 {
1001 // json doesn't support non-string keys. If we hit this condition,
1002 // convert the result to a string so we can proceed
Ed Tanous71f52d92021-02-19 08:51:17 -08001003 key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001004 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -07001005 // in theory this can't fail now, but lets be paranoid about it
1006 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -06001007 if (keyPtr == nullptr)
1008 {
1009 return -1;
1010 }
1011 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001012 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -06001013
1014 r = convertDBusToJSON(types[1], m, value);
1015 if (r < 0)
1016 {
1017 return r;
1018 }
1019
1020 r = sd_bus_message_exit_container(m.get());
1021 if (r < 0)
1022 {
Ed Tanous62598e32023-07-17 17:06:25 -07001023 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001024 return r;
1025 }
1026
1027 return 0;
1028}
1029
Ed Tanous23a21a12020-07-25 04:45:05 +00001030inline int readArrayFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001031 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -06001032{
1033 if (typeCode.size() < 2)
1034 {
Ed Tanous62598e32023-07-17 17:06:25 -07001035 BMCWEB_LOG_ERROR("Type code {} too small for an array", typeCode);
Matt Spinler6df8f992019-01-14 12:47:47 -06001036 return -1;
1037 }
1038
1039 std::string containedType = typeCode.substr(1);
1040
1041 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
1042 containedType.c_str());
1043 if (r < 0)
1044 {
Ed Tanous62598e32023-07-17 17:06:25 -07001045 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler6df8f992019-01-14 12:47:47 -06001046 return r;
1047 }
1048
Ed Tanous11ba3972022-07-11 09:50:41 -07001049 bool dict = containedType.starts_with("{") && containedType.ends_with("}");
Matt Spinler6df8f992019-01-14 12:47:47 -06001050
1051 if (dict)
1052 {
1053 // Remove the { }
1054 containedType = containedType.substr(1, containedType.size() - 2);
1055 data = nlohmann::json::object();
1056 }
1057 else
1058 {
1059 data = nlohmann::json::array();
1060 }
1061
1062 while (true)
1063 {
Ed Tanouse662eae2022-01-25 10:39:19 -08001064 r = sd_bus_message_at_end(m.get(), 0);
Matt Spinler6df8f992019-01-14 12:47:47 -06001065 if (r < 0)
1066 {
Ed Tanous62598e32023-07-17 17:06:25 -07001067 BMCWEB_LOG_ERROR("sd_bus_message_at_end failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001068 return r;
1069 }
1070
1071 if (r > 0)
1072 {
1073 break;
1074 }
1075
1076 // Dictionaries are only ever seen in an array
1077 if (dict)
1078 {
1079 r = readDictEntryFromMessage(containedType, m, data);
1080 if (r < 0)
1081 {
1082 return r;
1083 }
1084 }
1085 else
1086 {
1087 data.push_back(nlohmann::json());
1088
1089 r = convertDBusToJSON(containedType, m, data.back());
1090 if (r < 0)
1091 {
1092 return r;
1093 }
1094 }
1095 }
1096
1097 r = sd_bus_message_exit_container(m.get());
1098 if (r < 0)
1099 {
Ed Tanous62598e32023-07-17 17:06:25 -07001100 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001101 return r;
1102 }
1103
1104 return 0;
1105}
1106
Ed Tanous23a21a12020-07-25 04:45:05 +00001107inline int readStructFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001108 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001109{
1110 if (typeCode.size() < 3)
1111 {
Ed Tanous62598e32023-07-17 17:06:25 -07001112 BMCWEB_LOG_ERROR("Type code {} too small for a struct", typeCode);
Matt Spinler75c6c672019-01-14 13:01:46 -06001113 return -1;
1114 }
1115
1116 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1117 std::vector<std::string> types = dbusArgSplit(containedTypes);
1118
1119 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1120 containedTypes.c_str());
1121 if (r < 0)
1122 {
Ed Tanous62598e32023-07-17 17:06:25 -07001123 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler75c6c672019-01-14 13:01:46 -06001124 return r;
1125 }
1126
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001127 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001128 {
1129 data.push_back(nlohmann::json());
1130 r = convertDBusToJSON(type, m, data.back());
1131 if (r < 0)
1132 {
1133 return r;
1134 }
1135 }
1136
1137 r = sd_bus_message_exit_container(m.get());
1138 if (r < 0)
1139 {
Ed Tanous62598e32023-07-17 17:06:25 -07001140 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler75c6c672019-01-14 13:01:46 -06001141 return r;
1142 }
1143 return 0;
1144}
1145
Patrick Williams59d494e2022-07-22 19:26:55 -05001146inline int readVariantFromMessage(sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001147{
Ed Tanous543f4402022-01-06 13:12:53 -08001148 const char* containerType = nullptr;
Ed Tanous99131cd2019-10-24 11:12:47 -07001149 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001150 if (r < 0)
1151 {
Ed Tanous62598e32023-07-17 17:06:25 -07001152 BMCWEB_LOG_ERROR("sd_bus_message_peek_type failed");
Matt Spinler89c19702019-01-14 13:13:00 -06001153 return r;
1154 }
1155
1156 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1157 containerType);
1158 if (r < 0)
1159 {
Ed Tanous62598e32023-07-17 17:06:25 -07001160 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler89c19702019-01-14 13:13:00 -06001161 return r;
1162 }
1163
1164 r = convertDBusToJSON(containerType, m, data);
1165 if (r < 0)
1166 {
1167 return r;
1168 }
1169
1170 r = sd_bus_message_exit_container(m.get());
1171 if (r < 0)
1172 {
Ed Tanous62598e32023-07-17 17:06:25 -07001173 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed");
Matt Spinler89c19702019-01-14 13:13:00 -06001174 return r;
1175 }
1176
1177 return 0;
1178}
1179
Ed Tanous23a21a12020-07-25 04:45:05 +00001180inline int convertDBusToJSON(const std::string& returnType,
Patrick Williams59d494e2022-07-22 19:26:55 -05001181 sdbusplus::message_t& m, nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001182{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001183 int r = 0;
1184 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1185
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001186 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001187 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001188 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001189 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001190 {
1191 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001192 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001193 }
1194
Ed Tanousd4d25792020-09-29 15:15:03 -07001195 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001196 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001197 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001198 if (r < 0)
1199 {
1200 return r;
1201 }
1202 }
1203 else if (typeCode == "b")
1204 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001205 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001206 if (r < 0)
1207 {
1208 return r;
1209 }
1210
Matt Spinlerf39420c2019-01-30 12:57:18 -06001211 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001212 }
1213 else if (typeCode == "u")
1214 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001215 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001216 if (r < 0)
1217 {
1218 return r;
1219 }
1220 }
1221 else if (typeCode == "i")
1222 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001223 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001224 if (r < 0)
1225 {
1226 return r;
1227 }
1228 }
1229 else if (typeCode == "x")
1230 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001231 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001232 if (r < 0)
1233 {
1234 return r;
1235 }
1236 }
1237 else if (typeCode == "t")
1238 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001239 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001240 if (r < 0)
1241 {
1242 return r;
1243 }
1244 }
1245 else if (typeCode == "n")
1246 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001247 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001248 if (r < 0)
1249 {
1250 return r;
1251 }
1252 }
1253 else if (typeCode == "q")
1254 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001255 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001256 if (r < 0)
1257 {
1258 return r;
1259 }
1260 }
1261 else if (typeCode == "y")
1262 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001263 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001264 if (r < 0)
1265 {
1266 return r;
1267 }
1268 }
1269 else if (typeCode == "d")
1270 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001271 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001272 if (r < 0)
1273 {
1274 return r;
1275 }
1276 }
1277 else if (typeCode == "h")
1278 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001279 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001280 if (r < 0)
1281 {
1282 return r;
1283 }
1284 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001285 else if (typeCode.starts_with("a"))
Matt Spinler6df8f992019-01-14 12:47:47 -06001286 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001287 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001288 if (r < 0)
1289 {
1290 return r;
1291 }
1292 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001293 else if (typeCode.starts_with("(") && typeCode.ends_with(")"))
Matt Spinler75c6c672019-01-14 13:01:46 -06001294 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001295 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001296 if (r < 0)
1297 {
1298 return r;
1299 }
1300 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001301 else if (typeCode.starts_with("v"))
Matt Spinler89c19702019-01-14 13:13:00 -06001302 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001303 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001304 if (r < 0)
1305 {
1306 return r;
1307 }
1308 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001309 else
1310 {
Ed Tanous62598e32023-07-17 17:06:25 -07001311 BMCWEB_LOG_ERROR("Invalid D-Bus signature type {}", typeCode);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001312 return -2;
1313 }
1314 }
1315
Matt Spinler16caaee2019-01-15 11:40:34 -06001316 return 0;
1317}
1318
Ed Tanousb5a76932020-09-29 16:16:58 -07001319inline void handleMethodResponse(
1320 const std::shared_ptr<InProgressActionData>& transaction,
Patrick Williams59d494e2022-07-22 19:26:55 -05001321 sdbusplus::message_t& m, const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001322{
Matt Spinler39a4e392019-01-15 11:53:13 -06001323 nlohmann::json data;
1324
1325 int r = convertDBusToJSON(returnType, m, data);
1326 if (r < 0)
1327 {
1328 transaction->outputFailed = true;
1329 return;
1330 }
1331
1332 if (data.is_null())
1333 {
1334 return;
1335 }
1336
1337 if (transaction->methodResponse.is_null())
1338 {
1339 transaction->methodResponse = std::move(data);
1340 return;
1341 }
1342
1343 // If they're both dictionaries or arrays, merge into one.
1344 // Otherwise, make the results an array with every result
1345 // an entry. Could also just fail in that case, but it
1346 // seems better to get the data back somehow.
1347
1348 if (transaction->methodResponse.is_object() && data.is_object())
1349 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001350 for (const auto& obj : data.items())
Matt Spinler39a4e392019-01-15 11:53:13 -06001351 {
1352 // Note: Will overwrite the data for a duplicate key
1353 transaction->methodResponse.emplace(obj.key(),
1354 std::move(obj.value()));
1355 }
1356 return;
1357 }
1358
1359 if (transaction->methodResponse.is_array() && data.is_array())
1360 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001361 for (auto& obj : data)
Matt Spinler39a4e392019-01-15 11:53:13 -06001362 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001363 transaction->methodResponse.emplace_back(std::move(obj));
Matt Spinler39a4e392019-01-15 11:53:13 -06001364 }
1365 return;
1366 }
1367
1368 if (!transaction->convertedToArray)
1369 {
1370 // They are different types. May as well turn them into an array
1371 nlohmann::json j = std::move(transaction->methodResponse);
1372 transaction->methodResponse = nlohmann::json::array();
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001373 transaction->methodResponse.emplace_back(std::move(j));
1374 transaction->methodResponse.emplace_back(std::move(data));
Matt Spinler39a4e392019-01-15 11:53:13 -06001375 transaction->convertedToArray = true;
1376 }
1377 else
1378 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001379 transaction->methodResponse.emplace_back(std::move(data));
Matt Spinler39a4e392019-01-15 11:53:13 -06001380 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001381}
1382
Ed Tanousb5a76932020-09-29 16:16:58 -07001383inline void findActionOnInterface(
1384 const std::shared_ptr<InProgressActionData>& transaction,
1385 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001386{
Ed Tanous62598e32023-07-17 17:06:25 -07001387 BMCWEB_LOG_DEBUG("findActionOnInterface for connection {}", connectionName);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001388 crow::connections::systemBus->async_method_call(
1389 [transaction, connectionName{std::string(connectionName)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001390 const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001391 const std::string& introspectXml) {
Ed Tanous62598e32023-07-17 17:06:25 -07001392 BMCWEB_LOG_DEBUG("got xml:\n {}", introspectXml);
Ed Tanous002d39b2022-05-31 08:59:27 -07001393 if (ec)
1394 {
Ed Tanous62598e32023-07-17 17:06:25 -07001395 BMCWEB_LOG_ERROR(
1396 "Introspect call failed with error: {} on process: {}",
1397 ec.message(), connectionName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001398 return;
1399 }
1400 tinyxml2::XMLDocument doc;
Matt Spinler318bd892019-01-15 09:59:20 -06001401
Ed Tanous002d39b2022-05-31 08:59:27 -07001402 doc.Parse(introspectXml.data(), introspectXml.size());
1403 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1404 if (pRoot == nullptr)
1405 {
Ed Tanous62598e32023-07-17 17:06:25 -07001406 BMCWEB_LOG_ERROR("XML document failed to parse {}", connectionName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001407 return;
1408 }
1409 tinyxml2::XMLElement* interfaceNode =
1410 pRoot->FirstChildElement("interface");
1411 while (interfaceNode != nullptr)
1412 {
1413 const char* thisInterfaceName = interfaceNode->Attribute("name");
1414 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001415 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001416 if (!transaction->interfaceName.empty() &&
1417 (transaction->interfaceName != thisInterfaceName))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001418 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001419 interfaceNode =
1420 interfaceNode->NextSiblingElement("interface");
1421 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001422 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001423
1424 tinyxml2::XMLElement* methodNode =
1425 interfaceNode->FirstChildElement("method");
1426 while (methodNode != nullptr)
1427 {
1428 const char* thisMethodName = methodNode->Attribute("name");
Ed Tanous62598e32023-07-17 17:06:25 -07001429 BMCWEB_LOG_DEBUG("Found method: {}", thisMethodName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001430 if (thisMethodName != nullptr &&
1431 thisMethodName == transaction->methodName)
1432 {
Ed Tanous62598e32023-07-17 17:06:25 -07001433 BMCWEB_LOG_DEBUG(
1434 "Found method named {} on interface {}",
1435 thisMethodName, thisInterfaceName);
Patrick Williams59d494e2022-07-22 19:26:55 -05001436 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001437 crow::connections::systemBus->new_method_call(
1438 connectionName.c_str(),
1439 transaction->path.c_str(), thisInterfaceName,
1440 transaction->methodName.c_str());
1441
1442 tinyxml2::XMLElement* argumentNode =
1443 methodNode->FirstChildElement("arg");
1444
1445 std::string returnType;
1446
1447 // Find the output type
1448 while (argumentNode != nullptr)
1449 {
1450 const char* argDirection =
1451 argumentNode->Attribute("direction");
1452 const char* argType =
1453 argumentNode->Attribute("type");
1454 if (argDirection != nullptr && argType != nullptr &&
1455 std::string(argDirection) == "out")
1456 {
1457 returnType = argType;
1458 break;
1459 }
1460 argumentNode =
1461 argumentNode->NextSiblingElement("arg");
1462 }
1463
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001464 auto argIt = transaction->arguments.begin();
Ed Tanous002d39b2022-05-31 08:59:27 -07001465
1466 argumentNode = methodNode->FirstChildElement("arg");
1467
1468 while (argumentNode != nullptr)
1469 {
1470 const char* argDirection =
1471 argumentNode->Attribute("direction");
1472 const char* argType =
1473 argumentNode->Attribute("type");
1474 if (argDirection != nullptr && argType != nullptr &&
1475 std::string(argDirection) == "in")
1476 {
1477 if (argIt == transaction->arguments.end())
1478 {
1479 transaction->setErrorStatus(
1480 "Invalid method args");
1481 return;
1482 }
1483 if (convertJsonToDbus(m.get(),
1484 std::string(argType),
1485 *argIt) < 0)
1486 {
1487 transaction->setErrorStatus(
1488 "Invalid method arg type");
1489 return;
1490 }
1491
1492 argIt++;
1493 }
1494 argumentNode =
1495 argumentNode->NextSiblingElement("arg");
1496 }
1497
1498 crow::connections::systemBus->async_send(
Patrick Williams5a39f772023-10-20 11:20:21 -05001499 m, [transaction, returnType](
1500 const boost::system::error_code& ec2,
1501 sdbusplus::message_t& m2) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001502 if (ec2)
1503 {
1504 transaction->methodFailed = true;
1505 const sd_bus_error* e = m2.get_error();
1506
1507 if (e != nullptr)
1508 {
1509 setErrorResponse(
Lei YU28dd5ca2023-03-17 13:17:05 +08001510 transaction->asyncResp->res,
Ed Tanous002d39b2022-05-31 08:59:27 -07001511 boost::beast::http::status::bad_request,
1512 e->name, e->message);
1513 }
1514 else
1515 {
1516 setErrorResponse(
Lei YU28dd5ca2023-03-17 13:17:05 +08001517 transaction->asyncResp->res,
Ed Tanous002d39b2022-05-31 08:59:27 -07001518 boost::beast::http::status::bad_request,
1519 "Method call failed", methodFailedMsg);
1520 }
1521 return;
1522 }
1523 transaction->methodPassed = true;
1524
1525 handleMethodResponse(transaction, m2, returnType);
Patrick Williams5a39f772023-10-20 11:20:21 -05001526 });
Ed Tanous002d39b2022-05-31 08:59:27 -07001527 break;
1528 }
1529 methodNode = methodNode->NextSiblingElement("method");
1530 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001531 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001532 interfaceNode = interfaceNode->NextSiblingElement("interface");
1533 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001534 },
Ed Tanous1abe55e2018-09-05 08:30:59 -07001535 connectionName, transaction->path,
1536 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001537}
1538
zhanghch058d1b46d2021-04-01 11:18:24 +08001539inline void handleAction(const crow::Request& req,
1540 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001541 const std::string& objectPath,
1542 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001543{
Ed Tanous62598e32023-07-17 17:06:25 -07001544 BMCWEB_LOG_DEBUG("handleAction on path: {} and method {}", objectPath,
1545 methodName);
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001546 nlohmann::json requestDbusData;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001547
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001548 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
1549 if (ret == JsonParseResult::BadContentType)
1550 {
1551 setErrorResponse(asyncResp->res,
1552 boost::beast::http::status::unsupported_media_type,
1553 invalidContentType, unsupportedMediaMsg);
1554 return;
1555 }
1556 if (ret != JsonParseResult::Success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001557 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001558 setErrorResponse(asyncResp->res,
1559 boost::beast::http::status::bad_request, noJsonDesc,
1560 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001561 return;
1562 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001563 nlohmann::json::iterator data = requestDbusData.find("data");
1564 if (data == requestDbusData.end())
1565 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001566 setErrorResponse(asyncResp->res,
1567 boost::beast::http::status::bad_request, noJsonDesc,
1568 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001569 return;
1570 }
1571
1572 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001573 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001574 setErrorResponse(asyncResp->res,
1575 boost::beast::http::status::bad_request, noJsonDesc,
1576 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001577 return;
1578 }
Lei YU28dd5ca2023-03-17 13:17:05 +08001579 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001580
1581 transaction->path = objectPath;
1582 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001583 transaction->arguments = std::move(*data);
George Liu2b731192023-01-11 16:27:13 +08001584 dbus::utility::getDbusObject(
1585 objectPath, {},
Ed Tanous1abe55e2018-09-05 08:30:59 -07001586 [transaction](
George Liu2b731192023-01-11 16:27:13 +08001587 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001588 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1589 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001590 if (ec || interfaceNames.empty())
1591 {
Ed Tanous62598e32023-07-17 17:06:25 -07001592 BMCWEB_LOG_ERROR("Can't find object");
Lei YU28dd5ca2023-03-17 13:17:05 +08001593 setErrorResponse(transaction->asyncResp->res,
Ed Tanous002d39b2022-05-31 08:59:27 -07001594 boost::beast::http::status::not_found,
1595 notFoundDesc, notFoundMsg);
1596 return;
1597 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001598
Ed Tanous62598e32023-07-17 17:06:25 -07001599 BMCWEB_LOG_DEBUG("GetObject returned {} object(s)",
1600 interfaceNames.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001601
Ed Tanous002d39b2022-05-31 08:59:27 -07001602 for (const std::pair<std::string, std::vector<std::string>>& object :
1603 interfaceNames)
1604 {
1605 findActionOnInterface(transaction, object.first);
1606 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001607 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001608}
1609
zhanghch058d1b46d2021-04-01 11:18:24 +08001610inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1611 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001612{
Ed Tanous62598e32023-07-17 17:06:25 -07001613 BMCWEB_LOG_DEBUG("handleDelete on path: {}", objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06001614
George Liu2b731192023-01-11 16:27:13 +08001615 dbus::utility::getDbusObject(
1616 objectPath, {},
zhanghch058d1b46d2021-04-01 11:18:24 +08001617 [asyncResp, objectPath](
George Liu2b731192023-01-11 16:27:13 +08001618 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001619 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1620 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001621 if (ec || interfaceNames.empty())
1622 {
Ed Tanous62598e32023-07-17 17:06:25 -07001623 BMCWEB_LOG_ERROR("Can't find object");
Ed Tanous002d39b2022-05-31 08:59:27 -07001624 setErrorResponse(asyncResp->res,
1625 boost::beast::http::status::method_not_allowed,
1626 methodNotAllowedDesc, methodNotAllowedMsg);
1627 return;
1628 }
Matt Spinlerde818812018-12-11 16:39:20 -06001629
Lei YU28dd5ca2023-03-17 13:17:05 +08001630 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001631 transaction->path = objectPath;
1632 transaction->methodName = "Delete";
1633 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
Matt Spinlerde818812018-12-11 16:39:20 -06001634
Ed Tanous002d39b2022-05-31 08:59:27 -07001635 for (const std::pair<std::string, std::vector<std::string>>& object :
1636 interfaceNames)
1637 {
1638 findActionOnInterface(transaction, object.first);
1639 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001640 });
Matt Spinlerde818812018-12-11 16:39:20 -06001641}
1642
zhanghch058d1b46d2021-04-01 11:18:24 +08001643inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1644 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001645{
George Liu7a1dbc42022-12-07 16:03:22 +08001646 dbus::utility::getSubTreePaths(
1647 objectPath, depth, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001648 [asyncResp](
George Liu7a1dbc42022-12-07 16:03:22 +08001649 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001650 const dbus::utility::MapperGetSubTreePathsResponse& objectPaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001651 if (ec)
1652 {
1653 setErrorResponse(asyncResp->res,
1654 boost::beast::http::status::not_found,
1655 notFoundDesc, notFoundMsg);
1656 }
1657 else
1658 {
1659 asyncResp->res.jsonValue["status"] = "ok";
1660 asyncResp->res.jsonValue["message"] = "200 OK";
1661 asyncResp->res.jsonValue["data"] = objectPaths;
1662 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001663 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001664}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001665
zhanghch058d1b46d2021-04-01 11:18:24 +08001666inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1667 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001668{
Ed Tanous62598e32023-07-17 17:06:25 -07001669 BMCWEB_LOG_DEBUG("Doing enumerate on {}", objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07001670
Ed Tanous14766872022-03-15 10:44:42 -07001671 asyncResp->res.jsonValue["message"] = "200 OK";
1672 asyncResp->res.jsonValue["status"] = "ok";
1673 asyncResp->res.jsonValue["data"] = nlohmann::json::object();
Ed Tanous049a0512018-11-01 13:58:42 -07001674
George Liue99073f2022-12-09 11:06:16 +08001675 dbus::utility::getSubTree(
1676 objectPath, 0, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001677 [objectPath, asyncResp](
George Liue99073f2022-12-09 11:06:16 +08001678 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001679 const dbus::utility::MapperGetSubTreeResponse& objectNames) {
Patrick Williams89492a12023-05-10 07:51:34 -05001680 auto transaction = std::make_shared<InProgressEnumerateData>(objectPath,
1681 asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001682
Ed Tanous002d39b2022-05-31 08:59:27 -07001683 transaction->subtree =
1684 std::make_shared<dbus::utility::MapperGetSubTreeResponse>(
1685 objectNames);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001686
Ed Tanous002d39b2022-05-31 08:59:27 -07001687 if (ec)
1688 {
Ed Tanous62598e32023-07-17 17:06:25 -07001689 BMCWEB_LOG_ERROR("GetSubTree failed on {}",
1690 transaction->objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07001691 setErrorResponse(transaction->asyncResp->res,
1692 boost::beast::http::status::not_found,
1693 notFoundDesc, notFoundMsg);
1694 return;
1695 }
Ed Tanous64530012018-02-06 17:08:16 -08001696
Ed Tanous002d39b2022-05-31 08:59:27 -07001697 // Add the data for the path passed in to the results
1698 // as if GetSubTree returned it, and continue on enumerating
1699 getObjectAndEnumerate(transaction);
Patrick Williams5a39f772023-10-20 11:20:21 -05001700 });
Ed Tanous64530012018-02-06 17:08:16 -08001701}
Ed Tanous911ac312017-08-15 09:37:42 -07001702
zhanghch058d1b46d2021-04-01 11:18:24 +08001703inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1704 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001705{
Ed Tanous62598e32023-07-17 17:06:25 -07001706 BMCWEB_LOG_DEBUG("handleGet: {} prop:{}", objectPath, destProperty);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001707 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001708 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001709
Ed Tanous1abe55e2018-09-05 08:30:59 -07001710 std::shared_ptr<std::string> path =
1711 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001712
George Liu2b731192023-01-11 16:27:13 +08001713 dbus::utility::getDbusObject(
1714 *path, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001715 [asyncResp, path,
George Liu2b731192023-01-11 16:27:13 +08001716 propertyName](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001717 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001718 if (ec || objectNames.empty())
1719 {
1720 setErrorResponse(asyncResp->res,
1721 boost::beast::http::status::not_found,
1722 notFoundDesc, notFoundMsg);
1723 return;
1724 }
1725 std::shared_ptr<nlohmann::json> response =
1726 std::make_shared<nlohmann::json>(nlohmann::json::object());
1727 // The mapper should never give us an empty interface names
1728 // list, but check anyway
1729 for (const std::pair<std::string, std::vector<std::string>>&
1730 connection : objectNames)
1731 {
1732 const std::vector<std::string>& interfaceNames = connection.second;
1733
1734 if (interfaceNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001735 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001736 setErrorResponse(asyncResp->res,
1737 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001738 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001739 return;
1740 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001741
1742 for (const std::string& interface : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001743 {
Patrick Williams59d494e2022-07-22 19:26:55 -05001744 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001745 crow::connections::systemBus->new_method_call(
1746 connection.first.c_str(), path->c_str(),
1747 "org.freedesktop.DBus.Properties", "GetAll");
1748 m.append(interface);
1749 crow::connections::systemBus->async_send(
1750 m, [asyncResp, response,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001751 propertyName](const boost::system::error_code& ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05001752 sdbusplus::message_t& msg) {
Patrick Williams5a39f772023-10-20 11:20:21 -05001753 if (ec2)
1754 {
1755 BMCWEB_LOG_ERROR("Bad dbus request error: {}", ec2);
1756 }
1757 else
1758 {
1759 nlohmann::json properties;
1760 int r = convertDBusToJSON("a{sv}", msg, properties);
1761 if (r < 0)
Ed Tanous002d39b2022-05-31 08:59:27 -07001762 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001763 BMCWEB_LOG_ERROR("convertDBusToJSON failed");
Ed Tanous002d39b2022-05-31 08:59:27 -07001764 }
1765 else
1766 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001767 for (const auto& prop : properties.items())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001768 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001769 // if property name is empty, or
1770 // matches our search query, add it
1771 // to the response json
Ed Tanous1abe55e2018-09-05 08:30:59 -07001772
Patrick Williams5a39f772023-10-20 11:20:21 -05001773 if (propertyName->empty())
1774 {
1775 (*response)[prop.key()] =
1776 std::move(prop.value());
1777 }
1778 else if (prop.key() == *propertyName)
1779 {
1780 *response = std::move(prop.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001781 }
1782 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001783 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001784 }
1785 if (response.use_count() == 1)
1786 {
1787 if (!propertyName->empty() && response->empty())
Ed Tanous002d39b2022-05-31 08:59:27 -07001788 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001789 setErrorResponse(
1790 asyncResp->res,
1791 boost::beast::http::status::not_found,
1792 propNotFoundDesc, notFoundMsg);
Ed Tanous002d39b2022-05-31 08:59:27 -07001793 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001794 else
1795 {
1796 asyncResp->res.jsonValue["status"] = "ok";
1797 asyncResp->res.jsonValue["message"] = "200 OK";
1798 asyncResp->res.jsonValue["data"] = *response;
1799 }
1800 }
1801 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001802 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001803 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001804 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001805}
1806
Ed Tanous1abe55e2018-09-05 08:30:59 -07001807struct AsyncPutRequest
1808{
Ed Tanous4e23a442022-06-06 09:57:26 -07001809 explicit AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
zhanghch058d1b46d2021-04-01 11:18:24 +08001810 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001811 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001812 ~AsyncPutRequest()
1813 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001814 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001815 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001816 setErrorResponse(asyncResp->res,
1817 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001818 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001819 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001820 }
1821
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001822 AsyncPutRequest(const AsyncPutRequest&) = delete;
1823 AsyncPutRequest(AsyncPutRequest&&) = delete;
1824 AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1825 AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1826
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001827 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001828 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001829 setErrorResponse(asyncResp->res,
1830 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001831 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001832 }
1833
zhanghch058d1b46d2021-04-01 11:18:24 +08001834 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001835 std::string objectPath;
1836 std::string propertyName;
1837 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001838};
1839
zhanghch058d1b46d2021-04-01 11:18:24 +08001840inline void handlePut(const crow::Request& req,
1841 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001842 const std::string& objectPath,
1843 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001844{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001845 if (destProperty.empty())
1846 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001847 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001848 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001849 return;
1850 }
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001851 nlohmann::json requestDbusData;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001852
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001853 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
1854 if (ret == JsonParseResult::BadContentType)
1855 {
1856 setErrorResponse(asyncResp->res,
1857 boost::beast::http::status::unsupported_media_type,
1858 invalidContentType, unsupportedMediaMsg);
1859 return;
1860 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001861
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001862 if (ret != JsonParseResult::Success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001863 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001864 setErrorResponse(asyncResp->res,
1865 boost::beast::http::status::bad_request, noJsonDesc,
1866 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001867 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001868 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001869
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001870 auto propertyIt = requestDbusData.find("data");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001871 if (propertyIt == requestDbusData.end())
1872 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001873 setErrorResponse(asyncResp->res,
1874 boost::beast::http::status::bad_request, noJsonDesc,
1875 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001876 return;
1877 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001878 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001879 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001880 transaction->objectPath = objectPath;
1881 transaction->propertyName = destProperty;
1882 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001883
George Liu2b731192023-01-11 16:27:13 +08001884 dbus::utility::getDbusObject(
1885 transaction->objectPath, {},
1886 [transaction](const boost::system::error_code& ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001887 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001888 if (!ec2 && objectNames.empty())
1889 {
1890 setErrorResponse(transaction->asyncResp->res,
1891 boost::beast::http::status::not_found,
1892 propNotFoundDesc, notFoundMsg);
1893 return;
1894 }
Ed Tanous911ac312017-08-15 09:37:42 -07001895
Ed Tanous002d39b2022-05-31 08:59:27 -07001896 for (const std::pair<std::string, std::vector<std::string>>&
1897 connection : objectNames)
1898 {
1899 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001900
Ed Tanous002d39b2022-05-31 08:59:27 -07001901 crow::connections::systemBus->async_method_call(
1902 [connectionName{std::string(connectionName)},
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001903 transaction](const boost::system::error_code& ec3,
Ed Tanous002d39b2022-05-31 08:59:27 -07001904 const std::string& introspectXml) {
1905 if (ec3)
1906 {
Ed Tanous62598e32023-07-17 17:06:25 -07001907 BMCWEB_LOG_ERROR(
1908 "Introspect call failed with error: {} on process: {}",
1909 ec3.message(), connectionName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001910 transaction->setErrorStatus("Unexpected Error");
1911 return;
1912 }
1913 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001914
Ed Tanous002d39b2022-05-31 08:59:27 -07001915 doc.Parse(introspectXml.c_str());
1916 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1917 if (pRoot == nullptr)
1918 {
Ed Tanous62598e32023-07-17 17:06:25 -07001919 BMCWEB_LOG_ERROR("XML document failed to parse: {}",
1920 introspectXml);
Ed Tanous002d39b2022-05-31 08:59:27 -07001921 transaction->setErrorStatus("Unexpected Error");
1922 return;
1923 }
1924 tinyxml2::XMLElement* ifaceNode =
1925 pRoot->FirstChildElement("interface");
1926 while (ifaceNode != nullptr)
1927 {
1928 const char* interfaceName = ifaceNode->Attribute("name");
Ed Tanous62598e32023-07-17 17:06:25 -07001929 BMCWEB_LOG_DEBUG("found interface {}", interfaceName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001930 tinyxml2::XMLElement* propNode =
1931 ifaceNode->FirstChildElement("property");
1932 while (propNode != nullptr)
1933 {
1934 const char* propertyName = propNode->Attribute("name");
Ed Tanous62598e32023-07-17 17:06:25 -07001935 BMCWEB_LOG_DEBUG("Found property {}", propertyName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001936 if (propertyName == transaction->propertyName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001937 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001938 const char* argType = propNode->Attribute("type");
1939 if (argType != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001940 {
Patrick Williams59d494e2022-07-22 19:26:55 -05001941 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001942 crow::connections::systemBus
1943 ->new_method_call(
1944 connectionName.c_str(),
1945 transaction->objectPath.c_str(),
1946 "org.freedesktop.DBus."
1947 "Properties",
1948 "Set");
1949 m.append(interfaceName,
1950 transaction->propertyName);
1951 int r = sd_bus_message_open_container(
1952 m.get(), SD_BUS_TYPE_VARIANT, argType);
1953 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001954 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001955 transaction->setErrorStatus(
1956 "Unexpected Error");
1957 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001958 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001959 r = convertJsonToDbus(
1960 m.get(), argType,
1961 transaction->propertyValue);
1962 if (r < 0)
1963 {
1964 if (r == -ERANGE)
1965 {
1966 transaction->setErrorStatus(
1967 "Provided property value "
1968 "is out of range for the "
1969 "property type");
1970 }
1971 else
1972 {
1973 transaction->setErrorStatus(
1974 "Invalid arg type");
1975 }
1976 return;
1977 }
1978 r = sd_bus_message_close_container(m.get());
1979 if (r < 0)
1980 {
1981 transaction->setErrorStatus(
1982 "Unexpected Error");
1983 return;
1984 }
1985 crow::connections::systemBus->async_send(
Patrick Williams5a39f772023-10-20 11:20:21 -05001986 m, [transaction](
1987 const boost::system::error_code& ec,
1988 sdbusplus::message_t& m2) {
Ed Tanous62598e32023-07-17 17:06:25 -07001989 BMCWEB_LOG_DEBUG("sent");
Ed Tanous002d39b2022-05-31 08:59:27 -07001990 if (ec)
1991 {
1992 const sd_bus_error* e = m2.get_error();
1993 setErrorResponse(
1994 transaction->asyncResp->res,
1995 boost::beast::http::status::
1996 forbidden,
1997 (e) != nullptr
1998 ? e->name
1999 : ec.category().name(),
2000 (e) != nullptr ? e->message
2001 : ec.message());
2002 }
2003 else
2004 {
2005 transaction->asyncResp->res
2006 .jsonValue["status"] = "ok";
2007 transaction->asyncResp->res
2008 .jsonValue["message"] = "200 OK";
2009 transaction->asyncResp->res
2010 .jsonValue["data"] = nullptr;
2011 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002012 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002013 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002014 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002015 propNode = propNode->NextSiblingElement("property");
2016 }
2017 ifaceNode = ifaceNode->NextSiblingElement("interface");
2018 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002019 },
Ed Tanous002d39b2022-05-31 08:59:27 -07002020 connectionName, transaction->objectPath,
2021 "org.freedesktop.DBus.Introspectable", "Introspect");
2022 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002023 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07002024}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002025
zhanghch058d1b46d2021-04-01 11:18:24 +08002026inline void handleDBusUrl(const crow::Request& req,
2027 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002028 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002029{
Ed Tanous049a0512018-11-01 13:58:42 -07002030 // If accessing a single attribute, fill in and update objectPath,
2031 // otherwise leave destProperty blank
Ed Tanouse05aec52022-01-25 10:28:56 -08002032 std::string destProperty;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002033 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002034 size_t attrPosition = objectPath.find(attrSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002035 if (attrPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002036 {
2037 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2038 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002039 objectPath.resize(attrPosition);
Ed Tanous049a0512018-11-01 13:58:42 -07002040 }
2041
Ed Tanousb41187f2019-10-24 16:30:02 -07002042 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002043 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002044 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002045 size_t actionPosition = objectPath.find(actionSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002046 if (actionPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002047 {
2048 std::string postProperty =
2049 objectPath.substr((actionPosition + strlen(actionSeperator)),
2050 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002051 objectPath.resize(actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002052 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002053 return;
2054 }
2055 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002056 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002057 {
Ed Tanous11ba3972022-07-11 09:50:41 -07002058 if (objectPath.ends_with("/enumerate"))
Ed Tanous049a0512018-11-01 13:58:42 -07002059 {
2060 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2061 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002062 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002063 }
Ed Tanous11ba3972022-07-11 09:50:41 -07002064 else if (objectPath.ends_with("/list"))
Ed Tanous049a0512018-11-01 13:58:42 -07002065 {
2066 objectPath.erase(objectPath.end() - sizeof("list"),
2067 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002068 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002069 }
2070 else
2071 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002072 // Trim any trailing "/" at the end
Ed Tanous11ba3972022-07-11 09:50:41 -07002073 if (objectPath.ends_with("/"))
Ed Tanousf839dfe2018-11-12 11:11:15 -08002074 {
2075 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002076 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002077 }
2078 else
2079 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002080 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002081 }
Ed Tanous049a0512018-11-01 13:58:42 -07002082 }
2083 return;
2084 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002085 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002086 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002087 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002088 return;
2089 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002090 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002091 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002092 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002093 return;
2094 }
Ed Tanous049a0512018-11-01 13:58:42 -07002095
zhanghch058d1b46d2021-04-01 11:18:24 +08002096 setErrorResponse(asyncResp->res,
2097 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002098 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002099}
2100
Ed Tanous1656b292022-05-04 11:33:42 -07002101inline void
2102 handleBusSystemPost(const crow::Request& req,
2103 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2104 const std::string& processName,
2105 const std::string& requestedPath)
2106{
2107 std::vector<std::string> strs;
Ed Tanous50ebd4a2023-01-19 19:03:17 -08002108
2109 bmcweb::split(strs, requestedPath, '/');
Ed Tanous1656b292022-05-04 11:33:42 -07002110 std::string objectPath;
2111 std::string interfaceName;
2112 std::string methodName;
2113 auto it = strs.begin();
2114 if (it == strs.end())
2115 {
2116 objectPath = "/";
2117 }
2118 while (it != strs.end())
2119 {
2120 // Check if segment contains ".". If it does, it must be an
2121 // interface
2122 if (it->find(".") != std::string::npos)
2123 {
2124 break;
2125 // This check is necessary as the trailing slash gets
2126 // parsed as part of our <path> specifier above, which
2127 // causes the normal trailing backslash redirector to
2128 // fail.
2129 }
2130 if (!it->empty())
2131 {
2132 objectPath += "/" + *it;
2133 }
2134 it++;
2135 }
2136 if (it != strs.end())
2137 {
2138 interfaceName = *it;
2139 it++;
2140
2141 // after interface, we might have a method name
2142 if (it != strs.end())
2143 {
2144 methodName = *it;
2145 it++;
2146 }
2147 }
2148 if (it != strs.end())
2149 {
2150 // if there is more levels past the method name, something
2151 // went wrong, return not found
2152 asyncResp->res.result(boost::beast::http::status::not_found);
2153 return;
2154 }
2155 if (interfaceName.empty())
2156 {
2157 crow::connections::systemBus->async_method_call(
2158 [asyncResp, processName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002159 objectPath](const boost::system::error_code& ec,
Ed Tanous1656b292022-05-04 11:33:42 -07002160 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002161 if (ec)
2162 {
Ed Tanous62598e32023-07-17 17:06:25 -07002163 BMCWEB_LOG_ERROR(
2164 "Introspect call failed with error: {} on process: {} path: {}",
2165 ec.message(), processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002166 return;
2167 }
2168 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002169
Ed Tanous002d39b2022-05-31 08:59:27 -07002170 doc.Parse(introspectXml.c_str());
2171 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2172 if (pRoot == nullptr)
2173 {
Ed Tanous62598e32023-07-17 17:06:25 -07002174 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
2175 processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002176 asyncResp->res.jsonValue["status"] = "XML parse error";
2177 asyncResp->res.result(
2178 boost::beast::http::status::internal_server_error);
2179 return;
2180 }
2181
Ed Tanous62598e32023-07-17 17:06:25 -07002182 BMCWEB_LOG_DEBUG("{}", introspectXml);
Ed Tanous002d39b2022-05-31 08:59:27 -07002183 asyncResp->res.jsonValue["status"] = "ok";
2184 asyncResp->res.jsonValue["bus_name"] = processName;
2185 asyncResp->res.jsonValue["object_path"] = objectPath;
2186
2187 nlohmann::json& interfacesArray =
2188 asyncResp->res.jsonValue["interfaces"];
2189 interfacesArray = nlohmann::json::array();
2190 tinyxml2::XMLElement* interface =
2191 pRoot->FirstChildElement("interface");
2192
2193 while (interface != nullptr)
2194 {
2195 const char* ifaceName = interface->Attribute("name");
2196 if (ifaceName != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002197 {
Ed Tanous8a592812022-06-04 09:06:59 -07002198 nlohmann::json::object_t interfaceObj;
2199 interfaceObj["name"] = ifaceName;
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002200 interfacesArray.emplace_back(std::move(interfaceObj));
Ed Tanous1656b292022-05-04 11:33:42 -07002201 }
2202
Ed Tanous002d39b2022-05-31 08:59:27 -07002203 interface = interface->NextSiblingElement("interface");
2204 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002205 },
Ed Tanous1656b292022-05-04 11:33:42 -07002206 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2207 "Introspect");
2208 }
2209 else if (methodName.empty())
2210 {
2211 crow::connections::systemBus->async_method_call(
2212 [asyncResp, processName, objectPath,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002213 interfaceName](const boost::system::error_code& ec,
Ed Tanous1656b292022-05-04 11:33:42 -07002214 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002215 if (ec)
2216 {
Ed Tanous62598e32023-07-17 17:06:25 -07002217 BMCWEB_LOG_ERROR(
2218 "Introspect call failed with error: {} on process: {} path: {}",
2219 ec.message(), processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002220 return;
2221 }
2222 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002223
Ed Tanous002d39b2022-05-31 08:59:27 -07002224 doc.Parse(introspectXml.data(), introspectXml.size());
2225 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2226 if (pRoot == nullptr)
2227 {
Ed Tanous62598e32023-07-17 17:06:25 -07002228 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
2229 processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002230 asyncResp->res.result(
2231 boost::beast::http::status::internal_server_error);
2232 return;
2233 }
2234
2235 asyncResp->res.jsonValue["status"] = "ok";
2236 asyncResp->res.jsonValue["bus_name"] = processName;
2237 asyncResp->res.jsonValue["interface"] = interfaceName;
2238 asyncResp->res.jsonValue["object_path"] = objectPath;
2239
2240 nlohmann::json& methodsArray = asyncResp->res.jsonValue["methods"];
2241 methodsArray = nlohmann::json::array();
2242
2243 nlohmann::json& signalsArray = asyncResp->res.jsonValue["signals"];
2244 signalsArray = nlohmann::json::array();
2245
2246 nlohmann::json& propertiesObj =
2247 asyncResp->res.jsonValue["properties"];
2248 propertiesObj = nlohmann::json::object();
2249
2250 // if we know we're the only call, build the
2251 // json directly
2252 tinyxml2::XMLElement* interface =
2253 pRoot->FirstChildElement("interface");
2254 while (interface != nullptr)
2255 {
2256 const char* ifaceName = interface->Attribute("name");
2257
2258 if (ifaceName != nullptr && ifaceName == interfaceName)
Ed Tanous1656b292022-05-04 11:33:42 -07002259 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002260 break;
Ed Tanous1656b292022-05-04 11:33:42 -07002261 }
Ed Tanous14766872022-03-15 10:44:42 -07002262
Ed Tanous002d39b2022-05-31 08:59:27 -07002263 interface = interface->NextSiblingElement("interface");
2264 }
2265 if (interface == nullptr)
2266 {
2267 // if we got to the end of the list and
2268 // never found a match, throw 404
2269 asyncResp->res.result(boost::beast::http::status::not_found);
2270 return;
2271 }
Ed Tanous1656b292022-05-04 11:33:42 -07002272
Ed Tanous002d39b2022-05-31 08:59:27 -07002273 tinyxml2::XMLElement* methods =
2274 interface->FirstChildElement("method");
2275 while (methods != nullptr)
2276 {
2277 nlohmann::json argsArray = nlohmann::json::array();
2278 tinyxml2::XMLElement* arg = methods->FirstChildElement("arg");
2279 while (arg != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002280 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002281 nlohmann::json thisArg;
2282 for (const char* fieldName : std::array<const char*, 3>{
2283 "name", "direction", "type"})
Ed Tanous1656b292022-05-04 11:33:42 -07002284 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002285 const char* fieldValue = arg->Attribute(fieldName);
2286 if (fieldValue != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002287 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002288 thisArg[fieldName] = fieldValue;
2289 }
2290 }
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002291 argsArray.emplace_back(std::move(thisArg));
Ed Tanous002d39b2022-05-31 08:59:27 -07002292 arg = arg->NextSiblingElement("arg");
2293 }
2294
2295 const char* name = methods->Attribute("name");
2296 if (name != nullptr)
2297 {
2298 std::string uri;
2299 uri.reserve(14 + processName.size() + objectPath.size() +
2300 interfaceName.size() + strlen(name));
2301 uri += "/bus/system/";
2302 uri += processName;
2303 uri += objectPath;
2304 uri += "/";
2305 uri += interfaceName;
2306 uri += "/";
2307 uri += name;
2308
2309 nlohmann::json::object_t object;
2310 object["name"] = name;
2311 object["uri"] = std::move(uri);
2312 object["args"] = argsArray;
2313
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002314 methodsArray.emplace_back(std::move(object));
Ed Tanous002d39b2022-05-31 08:59:27 -07002315 }
2316 methods = methods->NextSiblingElement("method");
2317 }
2318 tinyxml2::XMLElement* signals =
2319 interface->FirstChildElement("signal");
2320 while (signals != nullptr)
2321 {
2322 nlohmann::json argsArray = nlohmann::json::array();
2323
2324 tinyxml2::XMLElement* arg = signals->FirstChildElement("arg");
2325 while (arg != nullptr)
2326 {
2327 const char* name = arg->Attribute("name");
2328 const char* type = arg->Attribute("type");
2329 if (name != nullptr && type != nullptr)
2330 {
2331 argsArray.push_back({
2332 {"name", name},
2333 {"type", type},
2334 });
2335 }
2336 arg = arg->NextSiblingElement("arg");
2337 }
2338 const char* name = signals->Attribute("name");
2339 if (name != nullptr)
2340 {
2341 nlohmann::json::object_t object;
2342 object["name"] = name;
2343 object["args"] = argsArray;
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002344 signalsArray.emplace_back(std::move(object));
Ed Tanous002d39b2022-05-31 08:59:27 -07002345 }
2346
2347 signals = signals->NextSiblingElement("signal");
2348 }
2349
2350 tinyxml2::XMLElement* property =
2351 interface->FirstChildElement("property");
2352 while (property != nullptr)
2353 {
2354 const char* name = property->Attribute("name");
2355 const char* type = property->Attribute("type");
2356 if (type != nullptr && name != nullptr)
2357 {
Patrick Williams59d494e2022-07-22 19:26:55 -05002358 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07002359 crow::connections::systemBus->new_method_call(
2360 processName.c_str(), objectPath.c_str(),
2361 "org.freedesktop."
2362 "DBus."
2363 "Properties",
2364 "Get");
2365 m.append(interfaceName, name);
2366 nlohmann::json& propertyItem = propertiesObj[name];
2367 crow::connections::systemBus->async_send(
2368 m, [&propertyItem,
Ed Tanous8b242752023-06-27 17:17:13 -07002369 asyncResp](const boost::system::error_code& ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05002370 sdbusplus::message_t& msg) {
Patrick Williams5a39f772023-10-20 11:20:21 -05002371 if (ec2)
2372 {
2373 return;
2374 }
Ed Tanous1656b292022-05-04 11:33:42 -07002375
Patrick Williams5a39f772023-10-20 11:20:21 -05002376 convertDBusToJSON("v", msg, propertyItem);
2377 });
Ed Tanous1656b292022-05-04 11:33:42 -07002378 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002379 property = property->NextSiblingElement("property");
2380 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002381 },
Ed Tanous1656b292022-05-04 11:33:42 -07002382 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2383 "Introspect");
2384 }
2385 else
2386 {
2387 if (req.method() != boost::beast::http::verb::post)
2388 {
2389 asyncResp->res.result(boost::beast::http::status::not_found);
2390 return;
2391 }
2392
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002393 nlohmann::json requestDbusData;
2394 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
2395 if (ret == JsonParseResult::BadContentType)
Ed Tanous1656b292022-05-04 11:33:42 -07002396 {
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002397 setErrorResponse(asyncResp->res,
2398 boost::beast::http::status::unsupported_media_type,
2399 invalidContentType, unsupportedMediaMsg);
Ed Tanous1656b292022-05-04 11:33:42 -07002400 return;
2401 }
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002402 if (ret != JsonParseResult::Success)
2403 {
2404 setErrorResponse(asyncResp->res,
2405 boost::beast::http::status::bad_request,
2406 noJsonDesc, badReqMsg);
2407 return;
2408 }
2409
Ed Tanous1656b292022-05-04 11:33:42 -07002410 if (!requestDbusData.is_array())
2411 {
2412 asyncResp->res.result(boost::beast::http::status::bad_request);
2413 return;
2414 }
Lei YU28dd5ca2023-03-17 13:17:05 +08002415 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous1656b292022-05-04 11:33:42 -07002416
2417 transaction->path = objectPath;
2418 transaction->methodName = methodName;
2419 transaction->arguments = std::move(requestDbusData);
2420
2421 findActionOnInterface(transaction, processName);
2422 }
2423}
2424
Ed Tanous23a21a12020-07-25 04:45:05 +00002425inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002426{
2427 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002428 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002429 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002430 [](const crow::Request&,
2431 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002432 nlohmann::json::array_t buses;
2433 nlohmann::json& bus = buses.emplace_back();
2434 bus["name"] = "system";
2435 asyncResp->res.jsonValue["busses"] = std::move(buses);
2436 asyncResp->res.jsonValue["status"] = "ok";
Patrick Williams5a39f772023-10-20 11:20:21 -05002437 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002438
2439 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002440 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002441 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002442 [](const crow::Request&,
2443 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002444 auto myCallback = [asyncResp](const boost::system::error_code& ec,
zhanghch058d1b46d2021-04-01 11:18:24 +08002445 std::vector<std::string>& names) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002446 if (ec)
2447 {
Ed Tanous62598e32023-07-17 17:06:25 -07002448 BMCWEB_LOG_ERROR("Dbus call failed with code {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07002449 asyncResp->res.result(
2450 boost::beast::http::status::internal_server_error);
2451 }
2452 else
2453 {
Ed Tanous3544d2a2023-08-06 18:12:20 -07002454 std::ranges::sort(names);
Ed Tanous002d39b2022-05-31 08:59:27 -07002455 asyncResp->res.jsonValue["status"] = "ok";
2456 auto& objectsSub = asyncResp->res.jsonValue["objects"];
Ed Tanous02cad962022-06-30 16:50:15 -07002457 for (const auto& name : names)
Ed Tanous002d39b2022-05-31 08:59:27 -07002458 {
2459 nlohmann::json::object_t object;
2460 object["name"] = name;
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002461 objectsSub.emplace_back(std::move(object));
Ed Tanous002d39b2022-05-31 08:59:27 -07002462 }
2463 }
2464 };
2465 crow::connections::systemBus->async_method_call(
2466 std::move(myCallback), "org.freedesktop.DBus", "/",
2467 "org.freedesktop.DBus", "ListNames");
Patrick Williams5a39f772023-10-20 11:20:21 -05002468 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002469
2470 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002471 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002472 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002473 [](const crow::Request&,
2474 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002475 handleList(asyncResp, "/");
Patrick Williams5a39f772023-10-20 11:20:21 -05002476 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002477
2478 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002479 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002480 .methods(boost::beast::http::verb::get)(
2481 [](const crow::Request& req,
2482 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002483 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002484 std::string objectPath = "/xyz/" + path;
2485 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002486 });
zhanghch058d1b46d2021-04-01 11:18:24 +08002487
2488 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002489 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002490 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2491 boost::beast::http::verb::delete_)(
2492 [](const crow::Request& req,
2493 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2494 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002495 std::string objectPath = "/xyz/" + path;
2496 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002497 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002498
Ed Tanous049a0512018-11-01 13:58:42 -07002499 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002500 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002501 .methods(boost::beast::http::verb::get)(
2502 [](const crow::Request& req,
2503 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2504 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002505 std::string objectPath = "/org/" + path;
2506 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002507 });
Tanousf00032d2018-11-05 01:18:10 -03002508
2509 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002510 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002511 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2512 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002513 [](const crow::Request& req,
2514 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002515 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002516 std::string objectPath = "/org/" + path;
2517 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002518 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002519
Ed Tanous1abe55e2018-09-05 08:30:59 -07002520 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002521 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002522 .methods(boost::beast::http::verb::get)(
2523 [](const crow::Request&,
2524 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2525 const std::string& dumpId) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002526 if (!validateFilename(dumpId))
2527 {
2528 asyncResp->res.result(boost::beast::http::status::bad_request);
2529 return;
2530 }
2531 std::filesystem::path loc("/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002532
Ed Tanous002d39b2022-05-31 08:59:27 -07002533 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002534
Ed Tanous002d39b2022-05-31 08:59:27 -07002535 if (!std::filesystem::exists(loc) ||
2536 !std::filesystem::is_directory(loc))
2537 {
Ed Tanous62598e32023-07-17 17:06:25 -07002538 BMCWEB_LOG_ERROR("{}Not found", loc.string());
Ed Tanous002d39b2022-05-31 08:59:27 -07002539 asyncResp->res.result(boost::beast::http::status::not_found);
2540 return;
2541 }
2542 std::filesystem::directory_iterator files(loc);
zhanghch058d1b46d2021-04-01 11:18:24 +08002543
Ed Tanous002d39b2022-05-31 08:59:27 -07002544 for (const auto& file : files)
2545 {
Ed Tanous27b0cf92023-08-07 12:02:40 -07002546 if (!asyncResp->res.openFile(file))
Ed Tanous002d39b2022-05-31 08:59:27 -07002547 {
2548 continue;
2549 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002550
Ed Tanousd9f6c622022-03-17 09:12:17 -07002551 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07002552 "application/octet-stream");
zhanghch058d1b46d2021-04-01 11:18:24 +08002553
Ed Tanous002d39b2022-05-31 08:59:27 -07002554 // Assuming only one dump file will be present in the dump
2555 // id directory
2556 std::string dumpFileName = file.path().filename().string();
zhanghch058d1b46d2021-04-01 11:18:24 +08002557
Ed Tanous002d39b2022-05-31 08:59:27 -07002558 // Filename should be in alphanumeric, dot and underscore
2559 // Its based on phosphor-debug-collector application
2560 // dumpfile format
Ed Tanous4b242742023-05-11 09:51:51 -07002561 static std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
Ed Tanous002d39b2022-05-31 08:59:27 -07002562 if (!std::regex_match(dumpFileName, dumpFileRegex))
2563 {
Ed Tanous62598e32023-07-17 17:06:25 -07002564 BMCWEB_LOG_ERROR("Invalid dump filename {}", dumpFileName);
zhanghch058d1b46d2021-04-01 11:18:24 +08002565 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002566 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07002567 }
Patrick Williams89492a12023-05-10 07:51:34 -05002568 std::string contentDispositionParam = "attachment; filename=\"" +
2569 dumpFileName + "\"";
Ed Tanous002d39b2022-05-31 08:59:27 -07002570
Ed Tanousd9f6c622022-03-17 09:12:17 -07002571 asyncResp->res.addHeader(
2572 boost::beast::http::field::content_disposition,
2573 contentDispositionParam);
Ed Tanous002d39b2022-05-31 08:59:27 -07002574
Ed Tanous002d39b2022-05-31 08:59:27 -07002575 return;
2576 }
2577 asyncResp->res.result(boost::beast::http::status::not_found);
2578 return;
Patrick Williams5a39f772023-10-20 11:20:21 -05002579 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002580
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002581 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002582 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002583
2584 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002585 [](const crow::Request&,
2586 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002587 const std::string& connection) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002588 introspectObjects(connection, "/", asyncResp);
Patrick Williams5a39f772023-10-20 11:20:21 -05002589 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002590
2591 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002592 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous1656b292022-05-04 11:33:42 -07002593 .methods(boost::beast::http::verb::get,
2594 boost::beast::http::verb::post)(handleBusSystemPost);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002595}
2596} // namespace openbmc_mapper
2597} // namespace crow