blob: 17b5931199e7f0e76e952692d67076be17e3208d [file] [log] [blame]
James Feist5b4aa862018-08-16 14:07:01 -07001// Copyright (c) 2018 Intel Corporation
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
Ed Tanousb9b2e0b2018-09-13 13:47:50 -070014
James Feist5b4aa862018-08-16 14:07:01 -070015#pragma once
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080016#include "app.hpp"
17#include "async_resp.hpp"
18#include "dbus_singleton.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +080019#include "dbus_utility.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000020#include "http_request.hpp"
21#include "http_response.hpp"
22#include "logging.hpp"
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010023#include "parsing.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000024#include "routing.hpp"
Ed Tanous50ebd4a2023-01-19 19:03:17 -080025#include "str_utility.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000026
27#include <systemd/sd-bus-protocol.h>
28#include <systemd/sd-bus.h>
Ed Tanous911ac312017-08-15 09:37:42 -070029#include <tinyxml2.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -070030
Nan Zhoud5c80ad2022-07-11 01:16:31 +000031#include <boost/beast/http/status.hpp>
32#include <boost/beast/http/verb.hpp>
33#include <boost/container/flat_map.hpp>
34#include <boost/container/vector.hpp>
George Liue99073f2022-12-09 11:06:16 +080035#include <boost/system/error_code.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000036#include <nlohmann/json.hpp>
37#include <sdbusplus/asio/connection.hpp>
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +020038#include <sdbusplus/asio/property.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000039#include <sdbusplus/exception.hpp>
40#include <sdbusplus/message.hpp>
41#include <sdbusplus/message/native_types.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050042
Nan Zhoud5c80ad2022-07-11 01:16:31 +000043#include <algorithm>
44#include <array>
45#include <cerrno>
46#include <cstdint>
47#include <cstring>
James Feist4418c7f2019-04-15 11:09:15 -070048#include <filesystem>
Ed Tanousd4bb9bb2018-05-16 13:36:42 -070049#include <fstream>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000050#include <functional>
51#include <initializer_list>
52#include <iterator>
53#include <limits>
54#include <map>
55#include <memory>
Ed Tanous3544d2a2023-08-06 18:12:20 -070056#include <ranges>
Ramesh Iyyard9207042019-07-05 08:04:42 -050057#include <regex>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000058#include <string>
59#include <string_view>
60#include <type_traits>
Ed Tanousb5a76932020-09-29 16:16:58 -070061#include <utility>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000062#include <variant>
63#include <vector>
64
65// IWYU pragma: no_include <boost/algorithm/string/detail/classification.hpp>
66// IWYU pragma: no_include <boost/system/detail/error_code.hpp>
67// IWYU pragma: no_include <boost/system/detail/error_category.hpp>
68// IWYU pragma: no_include <errno.h>
69// IWYU pragma: no_include <string.h>
70// IWYU pragma: no_include <ext/alloc_traits.h>
71// IWYU pragma: no_include <exception>
72// IWYU pragma: no_include <boost/type_index/type_index_facade.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -070073
Ed Tanous1abe55e2018-09-05 08:30:59 -070074namespace crow
75{
76namespace openbmc_mapper
77{
Ed Tanous23a21a12020-07-25 04:45:05 +000078const constexpr char* notFoundMsg = "404 Not Found";
79const constexpr char* badReqMsg = "400 Bad Request";
80const constexpr char* methodNotAllowedMsg = "405 Method Not Allowed";
81const constexpr char* forbiddenMsg = "403 Forbidden";
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010082const constexpr char* unsupportedMediaMsg = "415 Unsupported Media Type";
Ed Tanous23a21a12020-07-25 04:45:05 +000083const constexpr char* methodFailedMsg = "500 Method Call Failed";
84const constexpr char* methodOutputFailedMsg = "500 Method Output Error";
85const constexpr char* notFoundDesc =
Matt Spinler2ae60092018-12-06 10:35:36 -060086 "org.freedesktop.DBus.Error.FileNotFound: path or object not found";
Ed Tanous23a21a12020-07-25 04:45:05 +000087const constexpr char* propNotFoundDesc =
88 "The specified property cannot be found";
89const constexpr char* noJsonDesc = "No JSON object could be decoded";
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010090const constexpr char* invalidContentType =
91 "Content-type header is missing or invalid";
Ed Tanous23a21a12020-07-25 04:45:05 +000092const constexpr char* methodNotFoundDesc =
93 "The specified method cannot be found";
94const constexpr char* methodNotAllowedDesc = "Method not allowed";
95const constexpr char* forbiddenPropDesc =
96 "The specified property cannot be created";
97const constexpr char* forbiddenResDesc =
98 "The specified resource cannot be created";
Matt Spinler2ae60092018-12-06 10:35:36 -060099
Josh Lehan482c45a2022-03-29 17:10:44 -0700100inline bool validateFilename(const std::string& filename)
101{
Ed Tanous4b242742023-05-11 09:51:51 -0700102 static std::regex validFilename(R"(^[\w\- ]+(\.?[\w\- ]*)$)");
Josh Lehan482c45a2022-03-29 17:10:44 -0700103
104 return std::regex_match(filename, validFilename);
105}
106
Ed Tanous23a21a12020-07-25 04:45:05 +0000107inline void setErrorResponse(crow::Response& res,
108 boost::beast::http::status result,
Ed Tanous26ccae32023-02-16 10:28:44 -0800109 const std::string& desc, std::string_view msg)
Matt Spinler2ae60092018-12-06 10:35:36 -0600110{
111 res.result(result);
Ed Tanous14766872022-03-15 10:44:42 -0700112 res.jsonValue["data"]["description"] = desc;
113 res.jsonValue["message"] = msg;
114 res.jsonValue["status"] = "error";
Matt Spinler2ae60092018-12-06 10:35:36 -0600115}
116
Ed Tanousb5a76932020-09-29 16:16:58 -0700117inline void
118 introspectObjects(const std::string& processName,
119 const std::string& objectPath,
120 const std::shared_ptr<bmcweb::AsyncResp>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700121{
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700122 if (transaction->res.jsonValue.is_null())
123 {
Ed Tanous14766872022-03-15 10:44:42 -0700124 transaction->res.jsonValue["status"] = "ok";
125 transaction->res.jsonValue["bus_name"] = processName;
126 transaction->res.jsonValue["objects"] = nlohmann::json::array();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700127 }
128
Ed Tanous1abe55e2018-09-05 08:30:59 -0700129 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700130 [transaction, processName{std::string(processName)},
131 objectPath{std::string(objectPath)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800132 const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +0000133 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700134 if (ec)
135 {
Ed Tanous62598e32023-07-17 17:06:25 -0700136 BMCWEB_LOG_ERROR(
137 "Introspect call failed with error: {} on process: {} path: {}",
138 ec.message(), processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -0700139 return;
140 }
141 nlohmann::json::object_t object;
142 object["path"] = objectPath;
Ed Tanous14766872022-03-15 10:44:42 -0700143
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500144 transaction->res.jsonValue["objects"].emplace_back(std::move(object));
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700145
Ed Tanous002d39b2022-05-31 08:59:27 -0700146 tinyxml2::XMLDocument doc;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700147
Ed Tanous002d39b2022-05-31 08:59:27 -0700148 doc.Parse(introspectXml.c_str());
149 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
150 if (pRoot == nullptr)
151 {
Ed Tanous62598e32023-07-17 17:06:25 -0700152 BMCWEB_LOG_ERROR("XML document failed to parse {} {}", processName,
153 objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -0700154 }
155 else
156 {
157 tinyxml2::XMLElement* node = pRoot->FirstChildElement("node");
158 while (node != nullptr)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700159 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700160 const char* childPath = node->Attribute("name");
161 if (childPath != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700162 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700163 std::string newpath;
164 if (objectPath != "/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700165 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700166 newpath += objectPath;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700167 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700168 newpath += std::string("/") + childPath;
169 // introspect the subobjects as well
170 introspectObjects(processName, newpath, transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700171 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700172
173 node = node->NextSiblingElement("node");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700174 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700175 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500176 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700177 processName, objectPath, "org.freedesktop.DBus.Introspectable",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700178 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -0700179}
Ed Tanous64530012018-02-06 17:08:16 -0800180
Ed Tanous23a21a12020-07-25 04:45:05 +0000181inline void getPropertiesForEnumerate(
182 const std::string& objectPath, const std::string& service,
Ed Tanousb5a76932020-09-29 16:16:58 -0700183 const std::string& interface,
184 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600185{
Ed Tanous62598e32023-07-17 17:06:25 -0700186 BMCWEB_LOG_DEBUG("getPropertiesForEnumerate {} {} {}", objectPath, service,
187 interface);
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600188
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +0200189 sdbusplus::asio::getAllProperties(
190 *crow::connections::systemBus, service, objectPath, interface,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800191 [asyncResp, objectPath, service,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800192 interface](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800193 const dbus::utility::DBusPropertiesMap& propertiesList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700194 if (ec)
195 {
Ed Tanous62598e32023-07-17 17:06:25 -0700196 BMCWEB_LOG_ERROR(
197 "GetAll on path {} iface {} service {} failed with code {}",
198 objectPath, interface, service, ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700199 return;
200 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600201
Ed Tanous002d39b2022-05-31 08:59:27 -0700202 nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
203 nlohmann::json& objectJson = dataJson[objectPath];
204 if (objectJson.is_null())
205 {
206 objectJson = nlohmann::json::object();
207 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600208
Ed Tanous002d39b2022-05-31 08:59:27 -0700209 for (const auto& [name, value] : propertiesList)
210 {
211 nlohmann::json& propertyJson = objectJson[name];
212 std::visit(
213 [&propertyJson](auto&& val) {
214 if constexpr (std::is_same_v<std::decay_t<decltype(val)>,
215 sdbusplus::message::unix_fd>)
216 {
217 propertyJson = val.fd;
218 }
219 else
220 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700221 propertyJson = val;
222 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500223 },
Ed Tanous002d39b2022-05-31 08:59:27 -0700224 value);
225 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500226 });
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600227}
228
229// Find any results that weren't picked up by ObjectManagers, to be
230// called after all ObjectManagers are searched for and called.
Ed Tanous23a21a12020-07-25 04:45:05 +0000231inline void findRemainingObjectsForEnumerate(
Ed Tanousb5a76932020-09-29 16:16:58 -0700232 const std::string& objectPath,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800233 const std::shared_ptr<dbus::utility::MapperGetSubTreeResponse>& subtree,
Ed Tanousb5a76932020-09-29 16:16:58 -0700234 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600235{
Ed Tanous62598e32023-07-17 17:06:25 -0700236 BMCWEB_LOG_DEBUG("findRemainingObjectsForEnumerate");
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500237 const nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600238
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500239 for (const auto& [path, interface_map] : *subtree)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600240 {
241 if (path == objectPath)
242 {
243 // An enumerate does not return the target path's properties
244 continue;
245 }
246 if (dataJson.find(path) == dataJson.end())
247 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500248 for (const auto& [service, interfaces] : interface_map)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600249 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500250 for (const auto& interface : interfaces)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600251 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700252 if (!interface.starts_with("org.freedesktop.DBus"))
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600253 {
254 getPropertiesForEnumerate(path, service, interface,
255 asyncResp);
256 }
257 }
258 }
259 }
260 }
261}
262
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600263struct InProgressEnumerateData
264{
zhanghch058d1b46d2021-04-01 11:18:24 +0800265 InProgressEnumerateData(
266 const std::string& objectPathIn,
267 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
Ed Tanous23a21a12020-07-25 04:45:05 +0000268 objectPath(objectPathIn),
zhanghch058d1b46d2021-04-01 11:18:24 +0800269 asyncResp(asyncRespIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500270 {}
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600271
272 ~InProgressEnumerateData()
273 {
Ed Tanous24b2fe82022-01-06 12:45:54 -0800274 try
275 {
276 findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
277 }
278 catch (...)
279 {
Ed Tanous62598e32023-07-17 17:06:25 -0700280 BMCWEB_LOG_CRITICAL(
281 "findRemainingObjectsForEnumerate threw exception");
Ed Tanous24b2fe82022-01-06 12:45:54 -0800282 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600283 }
284
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800285 InProgressEnumerateData(const InProgressEnumerateData&) = delete;
286 InProgressEnumerateData(InProgressEnumerateData&&) = delete;
287 InProgressEnumerateData& operator=(const InProgressEnumerateData&) = delete;
288 InProgressEnumerateData& operator=(InProgressEnumerateData&&) = delete;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600289 const std::string objectPath;
Ed Tanousb9d36b42022-02-26 21:42:46 -0800290 std::shared_ptr<dbus::utility::MapperGetSubTreeResponse> subtree;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600291 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
292};
293
Ed Tanous23a21a12020-07-25 04:45:05 +0000294inline void getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000295 const std::string& objectName, const std::string& objectManagerPath,
296 const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700297 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700298{
Ed Tanous62598e32023-07-17 17:06:25 -0700299 BMCWEB_LOG_DEBUG(
300 "getManagedObjectsForEnumerate {} object_manager_path {} connection_name {}",
301 objectName, objectManagerPath, connectionName);
George Liu5eb468d2023-06-20 17:03:24 +0800302 sdbusplus::message::object_path path(objectManagerPath);
303 dbus::utility::getManagedObjects(
304 connectionName, path,
Ed Tanous81ce6092020-12-17 16:54:55 +0000305 [transaction, objectName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800306 connectionName](const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +0000307 const dbus::utility::ManagedObjectType& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700308 if (ec)
309 {
Ed Tanous62598e32023-07-17 17:06:25 -0700310 BMCWEB_LOG_ERROR(
311 "GetManagedObjects on path {} on connection {} failed with code {}",
312 objectName, connectionName, ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700313 return;
314 }
Ed Tanous64530012018-02-06 17:08:16 -0800315
Ed Tanous002d39b2022-05-31 08:59:27 -0700316 nlohmann::json& dataJson =
317 transaction->asyncResp->res.jsonValue["data"];
Ed Tanous049a0512018-11-01 13:58:42 -0700318
Ed Tanous002d39b2022-05-31 08:59:27 -0700319 for (const auto& objectPath : objects)
320 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700321 if (objectPath.first.str.starts_with(objectName))
Ed Tanous049a0512018-11-01 13:58:42 -0700322 {
Ed Tanous62598e32023-07-17 17:06:25 -0700323 BMCWEB_LOG_DEBUG("Reading object {}", objectPath.first.str);
Ed Tanous002d39b2022-05-31 08:59:27 -0700324 nlohmann::json& objectJson = dataJson[objectPath.first.str];
325 if (objectJson.is_null())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700326 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700327 objectJson = nlohmann::json::object();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700328 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500329 for (const auto& interface : objectPath.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700330 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700331 for (const auto& property : interface.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700332 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700333 nlohmann::json& propertyJson =
334 objectJson[property.first];
335 std::visit(
336 [&propertyJson](auto&& val) {
337 if constexpr (std::is_same_v<
338 std::decay_t<decltype(val)>,
339 sdbusplus::message::unix_fd>)
340 {
341 propertyJson = val.fd;
342 }
343 else
344 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700345 propertyJson = val;
346 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500347 },
Ed Tanous002d39b2022-05-31 08:59:27 -0700348 property.second);
Ed Tanous049a0512018-11-01 13:58:42 -0700349 }
350 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700351 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700352 for (const auto& interface : objectPath.second)
353 {
354 if (interface.first == "org.freedesktop.DBus.ObjectManager")
355 {
356 getManagedObjectsForEnumerate(objectPath.first.str,
357 objectPath.first.str,
358 connectionName, transaction);
359 }
360 }
361 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500362 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700363}
364
Ed Tanous23a21a12020-07-25 04:45:05 +0000365inline void findObjectManagerPathForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000366 const std::string& objectName, const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700367 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700368{
Ed Tanous62598e32023-07-17 17:06:25 -0700369 BMCWEB_LOG_DEBUG("Finding objectmanager for path {} on connection:{}",
370 objectName, connectionName);
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700371 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000372 [transaction, objectName, connectionName](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800373 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800374 const dbus::utility::MapperGetAncestorsResponse& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700375 if (ec)
376 {
Ed Tanous62598e32023-07-17 17:06:25 -0700377 BMCWEB_LOG_ERROR("GetAncestors on path {} failed with code {}",
378 objectName, ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700379 return;
380 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700381
Ed Tanous002d39b2022-05-31 08:59:27 -0700382 for (const auto& pathGroup : objects)
383 {
384 for (const auto& connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700385 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700386 if (connectionGroup.first == connectionName)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700387 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700388 // Found the object manager path for this resource.
389 getManagedObjectsForEnumerate(objectName, pathGroup.first,
390 connectionName, transaction);
391 return;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700392 }
393 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700394 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500395 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700396 "xyz.openbmc_project.ObjectMapper",
397 "/xyz/openbmc_project/object_mapper",
Ed Tanous81ce6092020-12-17 16:54:55 +0000398 "xyz.openbmc_project.ObjectMapper", "GetAncestors", objectName,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500399 std::array<const char*, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700400}
Ed Tanous64530012018-02-06 17:08:16 -0800401
Ed Tanous7c091622019-05-23 11:42:36 -0700402// Uses GetObject to add the object info about the target /enumerate path to
403// the results of GetSubTree, as GetSubTree will not return info for the
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600404// target path, and then continues on enumerating the rest of the tree.
Ed Tanousb5a76932020-09-29 16:16:58 -0700405inline void getObjectAndEnumerate(
406 const std::shared_ptr<InProgressEnumerateData>& transaction)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600407{
George Liu2b731192023-01-11 16:27:13 +0800408 dbus::utility::getDbusObject(
409 transaction->objectPath, {},
410 [transaction](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800411 const dbus::utility::MapperGetObject& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700412 if (ec)
413 {
Ed Tanous62598e32023-07-17 17:06:25 -0700414 BMCWEB_LOG_ERROR("GetObject for path {} failed with code {}",
415 transaction->objectPath, ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700416 return;
417 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600418
Ed Tanous62598e32023-07-17 17:06:25 -0700419 BMCWEB_LOG_DEBUG("GetObject for {} has {} entries",
420 transaction->objectPath, objects.size());
Ed Tanous002d39b2022-05-31 08:59:27 -0700421 if (!objects.empty())
422 {
423 transaction->subtree->emplace_back(transaction->objectPath,
424 objects);
425 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600426
Ed Tanous002d39b2022-05-31 08:59:27 -0700427 // Map indicating connection name, and the path where the object
428 // manager exists
Ed Tanous18f8f602023-07-18 10:07:23 -0700429 boost::container::flat_map<
430 std::string, std::string, std::less<>,
431 std::vector<std::pair<std::string, std::string>>>
432 connections;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600433
Ed Tanous002d39b2022-05-31 08:59:27 -0700434 for (const auto& object : *(transaction->subtree))
435 {
436 for (const auto& connection : object.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600437 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700438 for (const auto& interface : connection.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600439 {
Ed Tanous62598e32023-07-17 17:06:25 -0700440 BMCWEB_LOG_DEBUG("{} has interface {}", connection.first,
441 interface);
Ed Tanous002d39b2022-05-31 08:59:27 -0700442 if (interface == "org.freedesktop.DBus.ObjectManager")
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600443 {
Ed Tanous62598e32023-07-17 17:06:25 -0700444 BMCWEB_LOG_DEBUG("found object manager path {}",
445 object.first);
Ed Tanousf8fe53e2022-06-30 15:55:45 -0700446 connections[connection.first] = object.first;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600447 }
448 }
449 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700450 }
Ed Tanous62598e32023-07-17 17:06:25 -0700451 BMCWEB_LOG_DEBUG("Got {} connections", connections.size());
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600452
Ed Tanous002d39b2022-05-31 08:59:27 -0700453 for (const auto& connection : connections)
454 {
455 // If we already know where the object manager is, we don't
456 // need to search for it, we can call directly in to
457 // getManagedObjects
458 if (!connection.second.empty())
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600459 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700460 getManagedObjectsForEnumerate(transaction->objectPath,
461 connection.second,
462 connection.first, transaction);
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600463 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700464 else
465 {
466 // otherwise we need to find the object manager path
467 // before we can continue
468 findObjectManagerPathForEnumerate(
469 transaction->objectPath, connection.first, transaction);
470 }
471 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500472 });
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600473}
Ed Tanous64530012018-02-06 17:08:16 -0800474
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700475// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700476struct InProgressActionData
477{
Lei YU28dd5ca2023-03-17 13:17:05 +0800478 explicit InProgressActionData(
479 const std::shared_ptr<bmcweb::AsyncResp>& res) :
480 asyncResp(res)
Ed Tanous23a21a12020-07-25 04:45:05 +0000481 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700482 ~InProgressActionData()
483 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600484 // Methods could have been called across different owners
485 // and interfaces, where some calls failed and some passed.
486 //
487 // The rules for this are:
488 // * if no method was called - error
489 // * if a method failed and none passed - error
490 // (converse: if at least one method passed - OK)
491 // * for the method output:
492 // * if output processing didn't fail, return the data
493
494 // Only deal with method returns if nothing failed earlier
Lei YU28dd5ca2023-03-17 13:17:05 +0800495 if (asyncResp->res.result() == boost::beast::http::status::ok)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700496 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600497 if (!methodPassed)
498 {
Matt Spinler06b1b632019-06-18 16:09:25 -0500499 if (!methodFailed)
Matt Spinler16caaee2019-01-15 11:40:34 -0600500 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800501 setErrorResponse(asyncResp->res,
502 boost::beast::http::status::not_found,
Matt Spinler16caaee2019-01-15 11:40:34 -0600503 methodNotFoundDesc, notFoundMsg);
504 }
505 }
506 else
507 {
508 if (outputFailed)
509 {
510 setErrorResponse(
Lei YU28dd5ca2023-03-17 13:17:05 +0800511 asyncResp->res,
512 boost::beast::http::status::internal_server_error,
Matt Spinler16caaee2019-01-15 11:40:34 -0600513 "Method output failure", methodOutputFailedMsg);
514 }
515 else
516 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800517 asyncResp->res.jsonValue["status"] = "ok";
518 asyncResp->res.jsonValue["message"] = "200 OK";
519 asyncResp->res.jsonValue["data"] = methodResponse;
Matt Spinler16caaee2019-01-15 11:40:34 -0600520 }
521 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700522 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700523 }
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800524 InProgressActionData(const InProgressActionData&) = delete;
525 InProgressActionData(InProgressActionData&&) = delete;
526 InProgressActionData& operator=(const InProgressActionData&) = delete;
527 InProgressActionData& operator=(InProgressActionData&&) = delete;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700528
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500529 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700530 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800531 setErrorResponse(asyncResp->res,
532 boost::beast::http::status::bad_request, desc,
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600533 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700534 }
Lei YU28dd5ca2023-03-17 13:17:05 +0800535 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700536 std::string path;
537 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600538 std::string interfaceName;
Matt Spinler16caaee2019-01-15 11:40:34 -0600539 bool methodPassed = false;
540 bool methodFailed = false;
541 bool outputFailed = false;
Matt Spinler39a4e392019-01-15 11:53:13 -0600542 bool convertedToArray = false;
Matt Spinler16caaee2019-01-15 11:40:34 -0600543 nlohmann::json methodResponse;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700544 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700545};
546
Ed Tanous23a21a12020-07-25 04:45:05 +0000547inline std::vector<std::string> dbusArgSplit(const std::string& string)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700548{
549 std::vector<std::string> ret;
550 if (string.empty())
551 {
552 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700553 }
Ed Tanous0f0353b2019-10-24 11:37:51 -0700554 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700555 int containerDepth = 0;
556
557 for (std::string::const_iterator character = string.begin();
558 character != string.end(); character++)
559 {
560 ret.back() += *character;
561 switch (*character)
562 {
563 case ('a'):
564 break;
565 case ('('):
566 case ('{'):
567 containerDepth++;
568 break;
569 case ('}'):
570 case (')'):
571 containerDepth--;
572 if (containerDepth == 0)
573 {
574 if (character + 1 != string.end())
575 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700576 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700577 }
578 }
579 break;
580 default:
581 if (containerDepth == 0)
582 {
583 if (character + 1 != string.end())
584 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700585 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700586 }
587 }
588 break;
589 }
590 }
Matt Spinler4ae611d2019-01-11 15:37:06 -0600591
592 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700593}
594
Ed Tanous81ce6092020-12-17 16:54:55 +0000595inline int convertJsonToDbus(sd_bus_message* m, const std::string& argType,
596 const nlohmann::json& inputJson)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700597{
598 int r = 0;
Ed Tanous296579b2024-03-11 16:58:24 -0700599 BMCWEB_LOG_DEBUG("Converting {} to type: {}", inputJson, argType);
Ed Tanous81ce6092020-12-17 16:54:55 +0000600 const std::vector<std::string> argTypes = dbusArgSplit(argType);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700601
Ed Tanous1abe55e2018-09-05 08:30:59 -0700602 // Assume a single object for now.
Ed Tanous81ce6092020-12-17 16:54:55 +0000603 const nlohmann::json* j = &inputJson;
604 nlohmann::json::const_iterator jIt = inputJson.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700605
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500606 for (const std::string& argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700607 {
608 // If we are decoding multiple objects, grab the pointer to the
609 // iterator, and increment it for the next loop
610 if (argTypes.size() > 1)
611 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000612 if (jIt == inputJson.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700613 {
614 return -2;
615 }
616 j = &*jIt;
617 jIt++;
618 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500619 const int64_t* intValue = j->get_ptr<const int64_t*>();
620 const std::string* stringValue = j->get_ptr<const std::string*>();
621 const double* doubleValue = j->get_ptr<const double*>();
622 const bool* b = j->get_ptr<const bool*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700623 int64_t v = 0;
624 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700625
Ed Tanous1abe55e2018-09-05 08:30:59 -0700626 // Do some basic type conversions that make sense. uint can be
627 // converted to int. int and uint can be converted to double
Ed Tanous66664f22019-10-11 13:05:49 -0700628 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700629 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500630 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700631 if (uintValue != nullptr)
632 {
633 v = static_cast<int64_t>(*uintValue);
634 intValue = &v;
635 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700636 }
Ed Tanous66664f22019-10-11 13:05:49 -0700637 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700638 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500639 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700640 if (uintValue != nullptr)
641 {
642 d = static_cast<double>(*uintValue);
643 doubleValue = &d;
644 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700645 }
Ed Tanous66664f22019-10-11 13:05:49 -0700646 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700647 {
Ed Tanous66664f22019-10-11 13:05:49 -0700648 if (intValue != nullptr)
649 {
650 d = static_cast<double>(*intValue);
651 doubleValue = &d;
652 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700653 }
654
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700655 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700656 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700657 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700658 {
659 return -1;
660 }
Ed Tanous271584a2019-07-09 16:24:22 -0700661 r = sd_bus_message_append_basic(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500662 m, argCode[0], static_cast<const void*>(stringValue->data()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700663 if (r < 0)
664 {
665 return r;
666 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700667 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700668 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700669 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700670 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700671 {
672 return -1;
673 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500674 if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
675 (*intValue > std::numeric_limits<int32_t>::max()))
676 {
677 return -ERANGE;
678 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700679 int32_t i = static_cast<int32_t>(*intValue);
680 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700681 if (r < 0)
682 {
683 return r;
684 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700685 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700686 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700687 {
688 // lots of ways bool could be represented here. Try them all
Ed Tanouse662eae2022-01-25 10:39:19 -0800689 int boolInt = 0;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700690 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700691 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500692 if (*intValue == 1)
693 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800694 boolInt = 1;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500695 }
696 else if (*intValue == 0)
697 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800698 boolInt = 0;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500699 }
700 else
701 {
702 return -ERANGE;
703 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700704 }
705 else if (b != nullptr)
706 {
Matt Spinlera2f02632019-01-18 10:15:35 -0600707 boolInt = *b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700708 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700709 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700710 {
Ed Tanous18f8f602023-07-18 10:07:23 -0700711 if (!stringValue->empty())
712 {
713 if (stringValue->front() == 't' ||
714 stringValue->front() == 'T')
715 {
716 boolInt = 1;
717 }
718 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700719 }
720 else
721 {
722 return -1;
723 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700724 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700725 if (r < 0)
726 {
727 return r;
728 }
729 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700730 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700731 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700732 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700733 {
734 return -1;
735 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500736 if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
737 (*intValue > std::numeric_limits<int16_t>::max()))
738 {
739 return -ERANGE;
740 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700741 int16_t n = static_cast<int16_t>(*intValue);
742 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700743 if (r < 0)
744 {
745 return r;
746 }
747 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700748 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700749 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700750 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700751 {
752 return -1;
753 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700754 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700755 if (r < 0)
756 {
757 return r;
758 }
759 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700760 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700761 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500762 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700763 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700764 {
765 return -1;
766 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000767 if (*uintValue > std::numeric_limits<uint8_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500768 {
769 return -ERANGE;
770 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700771 uint8_t y = static_cast<uint8_t>(*uintValue);
772 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700773 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700774 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700775 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500776 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700777 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700778 {
779 return -1;
780 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000781 if (*uintValue > std::numeric_limits<uint16_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500782 {
783 return -ERANGE;
784 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700785 uint16_t q = static_cast<uint16_t>(*uintValue);
786 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700787 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700788 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700789 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500790 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700791 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700792 {
793 return -1;
794 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000795 if (*uintValue > std::numeric_limits<uint32_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500796 {
797 return -ERANGE;
798 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700799 uint32_t u = static_cast<uint32_t>(*uintValue);
800 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700801 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700802 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700803 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500804 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700805 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700806 {
807 return -1;
808 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700809 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700810 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700811 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700812 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500813 if (doubleValue == nullptr)
814 {
815 return -1;
816 }
817 if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
818 (*doubleValue > std::numeric_limits<double>::max()))
819 {
820 return -ERANGE;
821 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700822 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700823 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700824 else if (argCode.starts_with("a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700825 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700826 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700827 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700828 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700829 if (r < 0)
830 {
831 return r;
832 }
833
Ed Tanous0dfeda62019-10-24 11:21:38 -0700834 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700835 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700836 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700837 if (r < 0)
838 {
839 return r;
840 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700841 }
842 sd_bus_message_close_container(m);
843 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700844 else if (argCode.starts_with("v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700845 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700846 std::string containedType = argCode.substr(1);
Ed Tanous62598e32023-07-17 17:06:25 -0700847 BMCWEB_LOG_DEBUG("variant type: {} appending variant of type: {}",
848 argCode, containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700849 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700850 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700851 if (r < 0)
852 {
853 return r;
854 }
855
Ed Tanous81ce6092020-12-17 16:54:55 +0000856 r = convertJsonToDbus(m, containedType, inputJson);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700857 if (r < 0)
858 {
859 return r;
860 }
861
862 r = sd_bus_message_close_container(m);
863 if (r < 0)
864 {
865 return r;
866 }
867 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700868 else if (argCode.starts_with("(") && argCode.ends_with(")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700869 {
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300870 std::string containedType = argCode.substr(1, argCode.size() - 2);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700871 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700872 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800873 if (r < 0)
874 {
875 return r;
876 }
877
Ed Tanous1abe55e2018-09-05 08:30:59 -0700878 nlohmann::json::const_iterator it = j->begin();
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300879 for (const std::string& argCode2 : dbusArgSplit(containedType))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700880 {
881 if (it == j->end())
882 {
883 return -1;
884 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000885 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700886 if (r < 0)
887 {
888 return r;
889 }
890 it++;
891 }
892 r = sd_bus_message_close_container(m);
893 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700894 else if (argCode.starts_with("{") && argCode.ends_with("}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700895 {
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300896 std::string containedType = argCode.substr(1, argCode.size() - 2);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700897 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700898 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800899 if (r < 0)
900 {
901 return r;
902 }
903
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700904 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700905 if (codes.size() != 2)
906 {
907 return -1;
908 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700909 const std::string& keyType = codes[0];
910 const std::string& valueType = codes[1];
Ed Tanous3174e4d2020-10-07 11:41:22 -0700911 for (const auto& it : j->items())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700912 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700913 r = convertJsonToDbus(m, keyType, it.key());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700914 if (r < 0)
915 {
916 return r;
917 }
918
Ed Tanous2c70f802020-09-28 14:29:23 -0700919 r = convertJsonToDbus(m, valueType, it.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700920 if (r < 0)
921 {
922 return r;
923 }
924 }
925 r = sd_bus_message_close_container(m);
926 }
927 else
928 {
929 return -2;
930 }
931 if (r < 0)
932 {
933 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700934 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700935
Ed Tanous1abe55e2018-09-05 08:30:59 -0700936 if (argTypes.size() > 1)
937 {
938 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700939 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700940 }
Matt Spinler127ea542019-01-14 11:04:28 -0600941
942 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700943}
944
Matt Spinlerd22a7132019-01-14 12:14:30 -0600945template <typename T>
Patrick Williams59d494e2022-07-22 19:26:55 -0500946int readMessageItem(const std::string& typeCode, sdbusplus::message_t& m,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500947 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600948{
949 T value;
Ed Tanousf79ce6a2024-03-20 12:27:06 -0700950 // When T == char*, this warning fires. Unclear how to resolve
951 // Given that sd-bus takes a void pointer to a char*, and that's
952 // Not something we can fix.
953 // NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600954 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
955 if (r < 0)
956 {
Ed Tanous62598e32023-07-17 17:06:25 -0700957 BMCWEB_LOG_ERROR("sd_bus_message_read_basic on type {} failed!",
958 typeCode);
Matt Spinlerd22a7132019-01-14 12:14:30 -0600959 return r;
960 }
961
962 data = value;
963 return 0;
964}
965
Patrick Williams59d494e2022-07-22 19:26:55 -0500966int convertDBusToJSON(const std::string& returnType, sdbusplus::message_t& m,
967 nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600968
Ed Tanous23a21a12020-07-25 04:45:05 +0000969inline int readDictEntryFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -0500970 sdbusplus::message_t& m,
Ed Tanous23a21a12020-07-25 04:45:05 +0000971 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600972{
973 std::vector<std::string> types = dbusArgSplit(typeCode);
974 if (types.size() != 2)
975 {
Ed Tanous62598e32023-07-17 17:06:25 -0700976 BMCWEB_LOG_ERROR("wrong number contained types in dictionary: {}",
977 types.size());
Matt Spinler6df8f992019-01-14 12:47:47 -0600978 return -1;
979 }
980
981 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
982 typeCode.c_str());
983 if (r < 0)
984 {
Ed Tanous62598e32023-07-17 17:06:25 -0700985 BMCWEB_LOG_ERROR("sd_bus_message_enter_container with rc {}", r);
Matt Spinler6df8f992019-01-14 12:47:47 -0600986 return r;
987 }
988
989 nlohmann::json key;
990 r = convertDBusToJSON(types[0], m, key);
991 if (r < 0)
992 {
993 return r;
994 }
995
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500996 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -0600997 if (keyPtr == nullptr)
998 {
999 // json doesn't support non-string keys. If we hit this condition,
1000 // convert the result to a string so we can proceed
Ed Tanous71f52d92021-02-19 08:51:17 -08001001 key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001002 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -07001003 // in theory this can't fail now, but lets be paranoid about it
1004 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -06001005 if (keyPtr == nullptr)
1006 {
1007 return -1;
1008 }
1009 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001010 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -06001011
1012 r = convertDBusToJSON(types[1], m, value);
1013 if (r < 0)
1014 {
1015 return r;
1016 }
1017
1018 r = sd_bus_message_exit_container(m.get());
1019 if (r < 0)
1020 {
Ed Tanous62598e32023-07-17 17:06:25 -07001021 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001022 return r;
1023 }
1024
1025 return 0;
1026}
1027
Ed Tanous23a21a12020-07-25 04:45:05 +00001028inline int readArrayFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001029 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -06001030{
1031 if (typeCode.size() < 2)
1032 {
Ed Tanous62598e32023-07-17 17:06:25 -07001033 BMCWEB_LOG_ERROR("Type code {} too small for an array", typeCode);
Matt Spinler6df8f992019-01-14 12:47:47 -06001034 return -1;
1035 }
1036
1037 std::string containedType = typeCode.substr(1);
1038
1039 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
1040 containedType.c_str());
1041 if (r < 0)
1042 {
Ed Tanous62598e32023-07-17 17:06:25 -07001043 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler6df8f992019-01-14 12:47:47 -06001044 return r;
1045 }
1046
Ed Tanous11ba3972022-07-11 09:50:41 -07001047 bool dict = containedType.starts_with("{") && containedType.ends_with("}");
Matt Spinler6df8f992019-01-14 12:47:47 -06001048
1049 if (dict)
1050 {
1051 // Remove the { }
1052 containedType = containedType.substr(1, containedType.size() - 2);
1053 data = nlohmann::json::object();
1054 }
1055 else
1056 {
1057 data = nlohmann::json::array();
1058 }
1059
1060 while (true)
1061 {
Ed Tanouse662eae2022-01-25 10:39:19 -08001062 r = sd_bus_message_at_end(m.get(), 0);
Matt Spinler6df8f992019-01-14 12:47:47 -06001063 if (r < 0)
1064 {
Ed Tanous62598e32023-07-17 17:06:25 -07001065 BMCWEB_LOG_ERROR("sd_bus_message_at_end failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001066 return r;
1067 }
1068
1069 if (r > 0)
1070 {
1071 break;
1072 }
1073
1074 // Dictionaries are only ever seen in an array
1075 if (dict)
1076 {
1077 r = readDictEntryFromMessage(containedType, m, data);
1078 if (r < 0)
1079 {
1080 return r;
1081 }
1082 }
1083 else
1084 {
1085 data.push_back(nlohmann::json());
1086
1087 r = convertDBusToJSON(containedType, m, data.back());
1088 if (r < 0)
1089 {
1090 return r;
1091 }
1092 }
1093 }
1094
1095 r = sd_bus_message_exit_container(m.get());
1096 if (r < 0)
1097 {
Ed Tanous62598e32023-07-17 17:06:25 -07001098 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001099 return r;
1100 }
1101
1102 return 0;
1103}
1104
Ed Tanous23a21a12020-07-25 04:45:05 +00001105inline int readStructFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001106 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001107{
1108 if (typeCode.size() < 3)
1109 {
Ed Tanous62598e32023-07-17 17:06:25 -07001110 BMCWEB_LOG_ERROR("Type code {} too small for a struct", typeCode);
Matt Spinler75c6c672019-01-14 13:01:46 -06001111 return -1;
1112 }
1113
1114 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1115 std::vector<std::string> types = dbusArgSplit(containedTypes);
1116
1117 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1118 containedTypes.c_str());
1119 if (r < 0)
1120 {
Ed Tanous62598e32023-07-17 17:06:25 -07001121 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler75c6c672019-01-14 13:01:46 -06001122 return r;
1123 }
1124
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001125 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001126 {
1127 data.push_back(nlohmann::json());
1128 r = convertDBusToJSON(type, m, data.back());
1129 if (r < 0)
1130 {
1131 return r;
1132 }
1133 }
1134
1135 r = sd_bus_message_exit_container(m.get());
1136 if (r < 0)
1137 {
Ed Tanous62598e32023-07-17 17:06:25 -07001138 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler75c6c672019-01-14 13:01:46 -06001139 return r;
1140 }
1141 return 0;
1142}
1143
Patrick Williams59d494e2022-07-22 19:26:55 -05001144inline int readVariantFromMessage(sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001145{
Ed Tanous543f4402022-01-06 13:12:53 -08001146 const char* containerType = nullptr;
Ed Tanous99131cd2019-10-24 11:12:47 -07001147 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001148 if (r < 0)
1149 {
Ed Tanous62598e32023-07-17 17:06:25 -07001150 BMCWEB_LOG_ERROR("sd_bus_message_peek_type failed");
Matt Spinler89c19702019-01-14 13:13:00 -06001151 return r;
1152 }
1153
1154 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1155 containerType);
1156 if (r < 0)
1157 {
Ed Tanous62598e32023-07-17 17:06:25 -07001158 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler89c19702019-01-14 13:13:00 -06001159 return r;
1160 }
1161
1162 r = convertDBusToJSON(containerType, m, data);
1163 if (r < 0)
1164 {
1165 return r;
1166 }
1167
1168 r = sd_bus_message_exit_container(m.get());
1169 if (r < 0)
1170 {
Ed Tanous62598e32023-07-17 17:06:25 -07001171 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed");
Matt Spinler89c19702019-01-14 13:13:00 -06001172 return r;
1173 }
1174
1175 return 0;
1176}
1177
Ed Tanous23a21a12020-07-25 04:45:05 +00001178inline int convertDBusToJSON(const std::string& returnType,
Patrick Williams59d494e2022-07-22 19:26:55 -05001179 sdbusplus::message_t& m, nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001180{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001181 int r = 0;
1182 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1183
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001184 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001185 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001186 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001187 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001188 {
1189 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001190 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001191 }
1192
Ed Tanousd4d25792020-09-29 15:15:03 -07001193 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001194 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001195 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001196 if (r < 0)
1197 {
1198 return r;
1199 }
1200 }
1201 else if (typeCode == "b")
1202 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001203 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001204 if (r < 0)
1205 {
1206 return r;
1207 }
1208
Matt Spinlerf39420c2019-01-30 12:57:18 -06001209 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001210 }
1211 else if (typeCode == "u")
1212 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001213 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001214 if (r < 0)
1215 {
1216 return r;
1217 }
1218 }
1219 else if (typeCode == "i")
1220 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001221 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001222 if (r < 0)
1223 {
1224 return r;
1225 }
1226 }
1227 else if (typeCode == "x")
1228 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001229 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001230 if (r < 0)
1231 {
1232 return r;
1233 }
1234 }
1235 else if (typeCode == "t")
1236 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001237 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001238 if (r < 0)
1239 {
1240 return r;
1241 }
1242 }
1243 else if (typeCode == "n")
1244 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001245 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001246 if (r < 0)
1247 {
1248 return r;
1249 }
1250 }
1251 else if (typeCode == "q")
1252 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001253 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001254 if (r < 0)
1255 {
1256 return r;
1257 }
1258 }
1259 else if (typeCode == "y")
1260 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001261 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001262 if (r < 0)
1263 {
1264 return r;
1265 }
1266 }
1267 else if (typeCode == "d")
1268 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001269 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001270 if (r < 0)
1271 {
1272 return r;
1273 }
1274 }
1275 else if (typeCode == "h")
1276 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001277 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001278 if (r < 0)
1279 {
1280 return r;
1281 }
1282 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001283 else if (typeCode.starts_with("a"))
Matt Spinler6df8f992019-01-14 12:47:47 -06001284 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001285 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001286 if (r < 0)
1287 {
1288 return r;
1289 }
1290 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001291 else if (typeCode.starts_with("(") && typeCode.ends_with(")"))
Matt Spinler75c6c672019-01-14 13:01:46 -06001292 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001293 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001294 if (r < 0)
1295 {
1296 return r;
1297 }
1298 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001299 else if (typeCode.starts_with("v"))
Matt Spinler89c19702019-01-14 13:13:00 -06001300 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001301 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001302 if (r < 0)
1303 {
1304 return r;
1305 }
1306 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001307 else
1308 {
Ed Tanous62598e32023-07-17 17:06:25 -07001309 BMCWEB_LOG_ERROR("Invalid D-Bus signature type {}", typeCode);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001310 return -2;
1311 }
1312 }
1313
Matt Spinler16caaee2019-01-15 11:40:34 -06001314 return 0;
1315}
1316
Ed Tanousb5a76932020-09-29 16:16:58 -07001317inline void handleMethodResponse(
1318 const std::shared_ptr<InProgressActionData>& transaction,
Patrick Williams59d494e2022-07-22 19:26:55 -05001319 sdbusplus::message_t& m, const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001320{
Matt Spinler39a4e392019-01-15 11:53:13 -06001321 nlohmann::json data;
1322
1323 int r = convertDBusToJSON(returnType, m, data);
1324 if (r < 0)
1325 {
1326 transaction->outputFailed = true;
1327 return;
1328 }
1329
1330 if (data.is_null())
1331 {
1332 return;
1333 }
1334
1335 if (transaction->methodResponse.is_null())
1336 {
1337 transaction->methodResponse = std::move(data);
1338 return;
1339 }
1340
1341 // If they're both dictionaries or arrays, merge into one.
1342 // Otherwise, make the results an array with every result
1343 // an entry. Could also just fail in that case, but it
1344 // seems better to get the data back somehow.
1345
1346 if (transaction->methodResponse.is_object() && data.is_object())
1347 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001348 for (const auto& obj : data.items())
Matt Spinler39a4e392019-01-15 11:53:13 -06001349 {
1350 // Note: Will overwrite the data for a duplicate key
1351 transaction->methodResponse.emplace(obj.key(),
1352 std::move(obj.value()));
1353 }
1354 return;
1355 }
1356
1357 if (transaction->methodResponse.is_array() && data.is_array())
1358 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001359 for (auto& obj : data)
Matt Spinler39a4e392019-01-15 11:53:13 -06001360 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001361 transaction->methodResponse.emplace_back(std::move(obj));
Matt Spinler39a4e392019-01-15 11:53:13 -06001362 }
1363 return;
1364 }
1365
1366 if (!transaction->convertedToArray)
1367 {
1368 // They are different types. May as well turn them into an array
1369 nlohmann::json j = std::move(transaction->methodResponse);
1370 transaction->methodResponse = nlohmann::json::array();
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001371 transaction->methodResponse.emplace_back(std::move(j));
1372 transaction->methodResponse.emplace_back(std::move(data));
Matt Spinler39a4e392019-01-15 11:53:13 -06001373 transaction->convertedToArray = true;
1374 }
1375 else
1376 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001377 transaction->methodResponse.emplace_back(std::move(data));
Matt Spinler39a4e392019-01-15 11:53:13 -06001378 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001379}
1380
Ed Tanousb5a76932020-09-29 16:16:58 -07001381inline void findActionOnInterface(
1382 const std::shared_ptr<InProgressActionData>& transaction,
1383 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001384{
Ed Tanous62598e32023-07-17 17:06:25 -07001385 BMCWEB_LOG_DEBUG("findActionOnInterface for connection {}", connectionName);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001386 crow::connections::systemBus->async_method_call(
1387 [transaction, connectionName{std::string(connectionName)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001388 const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001389 const std::string& introspectXml) {
Ed Tanous62598e32023-07-17 17:06:25 -07001390 BMCWEB_LOG_DEBUG("got xml:\n {}", introspectXml);
Ed Tanous002d39b2022-05-31 08:59:27 -07001391 if (ec)
1392 {
Ed Tanous62598e32023-07-17 17:06:25 -07001393 BMCWEB_LOG_ERROR(
1394 "Introspect call failed with error: {} on process: {}",
1395 ec.message(), connectionName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001396 return;
1397 }
1398 tinyxml2::XMLDocument doc;
Matt Spinler318bd892019-01-15 09:59:20 -06001399
Ed Tanous002d39b2022-05-31 08:59:27 -07001400 doc.Parse(introspectXml.data(), introspectXml.size());
1401 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1402 if (pRoot == nullptr)
1403 {
Ed Tanous62598e32023-07-17 17:06:25 -07001404 BMCWEB_LOG_ERROR("XML document failed to parse {}", connectionName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001405 return;
1406 }
1407 tinyxml2::XMLElement* interfaceNode =
1408 pRoot->FirstChildElement("interface");
1409 while (interfaceNode != nullptr)
1410 {
1411 const char* thisInterfaceName = interfaceNode->Attribute("name");
1412 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001413 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001414 if (!transaction->interfaceName.empty() &&
1415 (transaction->interfaceName != thisInterfaceName))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001416 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001417 interfaceNode =
1418 interfaceNode->NextSiblingElement("interface");
1419 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001420 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001421
1422 tinyxml2::XMLElement* methodNode =
1423 interfaceNode->FirstChildElement("method");
1424 while (methodNode != nullptr)
1425 {
1426 const char* thisMethodName = methodNode->Attribute("name");
Ed Tanous62598e32023-07-17 17:06:25 -07001427 BMCWEB_LOG_DEBUG("Found method: {}", thisMethodName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001428 if (thisMethodName != nullptr &&
1429 thisMethodName == transaction->methodName)
1430 {
Ed Tanous62598e32023-07-17 17:06:25 -07001431 BMCWEB_LOG_DEBUG(
1432 "Found method named {} on interface {}",
1433 thisMethodName, thisInterfaceName);
Patrick Williams59d494e2022-07-22 19:26:55 -05001434 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001435 crow::connections::systemBus->new_method_call(
1436 connectionName.c_str(),
1437 transaction->path.c_str(), thisInterfaceName,
1438 transaction->methodName.c_str());
1439
1440 tinyxml2::XMLElement* argumentNode =
1441 methodNode->FirstChildElement("arg");
1442
1443 std::string returnType;
1444
1445 // Find the output type
1446 while (argumentNode != nullptr)
1447 {
1448 const char* argDirection =
1449 argumentNode->Attribute("direction");
1450 const char* argType =
1451 argumentNode->Attribute("type");
1452 if (argDirection != nullptr && argType != nullptr &&
1453 std::string(argDirection) == "out")
1454 {
1455 returnType = argType;
1456 break;
1457 }
1458 argumentNode =
1459 argumentNode->NextSiblingElement("arg");
1460 }
1461
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001462 auto argIt = transaction->arguments.begin();
Ed Tanous002d39b2022-05-31 08:59:27 -07001463
1464 argumentNode = methodNode->FirstChildElement("arg");
1465
1466 while (argumentNode != nullptr)
1467 {
1468 const char* argDirection =
1469 argumentNode->Attribute("direction");
1470 const char* argType =
1471 argumentNode->Attribute("type");
1472 if (argDirection != nullptr && argType != nullptr &&
1473 std::string(argDirection) == "in")
1474 {
1475 if (argIt == transaction->arguments.end())
1476 {
1477 transaction->setErrorStatus(
1478 "Invalid method args");
1479 return;
1480 }
1481 if (convertJsonToDbus(m.get(),
1482 std::string(argType),
1483 *argIt) < 0)
1484 {
1485 transaction->setErrorStatus(
1486 "Invalid method arg type");
1487 return;
1488 }
1489
1490 argIt++;
1491 }
1492 argumentNode =
1493 argumentNode->NextSiblingElement("arg");
1494 }
1495
1496 crow::connections::systemBus->async_send(
Patrick Williams5a39f772023-10-20 11:20:21 -05001497 m, [transaction, returnType](
1498 const boost::system::error_code& ec2,
1499 sdbusplus::message_t& m2) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001500 if (ec2)
1501 {
1502 transaction->methodFailed = true;
1503 const sd_bus_error* e = m2.get_error();
1504
1505 if (e != nullptr)
1506 {
1507 setErrorResponse(
Lei YU28dd5ca2023-03-17 13:17:05 +08001508 transaction->asyncResp->res,
Ed Tanous002d39b2022-05-31 08:59:27 -07001509 boost::beast::http::status::bad_request,
1510 e->name, e->message);
1511 }
1512 else
1513 {
1514 setErrorResponse(
Lei YU28dd5ca2023-03-17 13:17:05 +08001515 transaction->asyncResp->res,
Ed Tanous002d39b2022-05-31 08:59:27 -07001516 boost::beast::http::status::bad_request,
1517 "Method call failed", methodFailedMsg);
1518 }
1519 return;
1520 }
1521 transaction->methodPassed = true;
1522
1523 handleMethodResponse(transaction, m2, returnType);
Patrick Williams5a39f772023-10-20 11:20:21 -05001524 });
Ed Tanous002d39b2022-05-31 08:59:27 -07001525 break;
1526 }
1527 methodNode = methodNode->NextSiblingElement("method");
1528 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001529 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001530 interfaceNode = interfaceNode->NextSiblingElement("interface");
1531 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001532 },
Ed Tanous1abe55e2018-09-05 08:30:59 -07001533 connectionName, transaction->path,
1534 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001535}
1536
zhanghch058d1b46d2021-04-01 11:18:24 +08001537inline void handleAction(const crow::Request& req,
1538 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001539 const std::string& objectPath,
1540 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001541{
Ed Tanous62598e32023-07-17 17:06:25 -07001542 BMCWEB_LOG_DEBUG("handleAction on path: {} and method {}", objectPath,
1543 methodName);
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001544 nlohmann::json requestDbusData;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001545
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001546 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
1547 if (ret == JsonParseResult::BadContentType)
1548 {
1549 setErrorResponse(asyncResp->res,
1550 boost::beast::http::status::unsupported_media_type,
1551 invalidContentType, unsupportedMediaMsg);
1552 return;
1553 }
1554 if (ret != JsonParseResult::Success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001555 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001556 setErrorResponse(asyncResp->res,
1557 boost::beast::http::status::bad_request, noJsonDesc,
1558 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001559 return;
1560 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001561 nlohmann::json::iterator data = requestDbusData.find("data");
1562 if (data == requestDbusData.end())
1563 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001564 setErrorResponse(asyncResp->res,
1565 boost::beast::http::status::bad_request, noJsonDesc,
1566 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001567 return;
1568 }
1569
1570 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001571 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001572 setErrorResponse(asyncResp->res,
1573 boost::beast::http::status::bad_request, noJsonDesc,
1574 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001575 return;
1576 }
Lei YU28dd5ca2023-03-17 13:17:05 +08001577 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001578
1579 transaction->path = objectPath;
1580 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001581 transaction->arguments = std::move(*data);
George Liu2b731192023-01-11 16:27:13 +08001582 dbus::utility::getDbusObject(
1583 objectPath, {},
Ed Tanous1abe55e2018-09-05 08:30:59 -07001584 [transaction](
George Liu2b731192023-01-11 16:27:13 +08001585 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001586 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1587 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001588 if (ec || interfaceNames.empty())
1589 {
Ed Tanous62598e32023-07-17 17:06:25 -07001590 BMCWEB_LOG_ERROR("Can't find object");
Lei YU28dd5ca2023-03-17 13:17:05 +08001591 setErrorResponse(transaction->asyncResp->res,
Ed Tanous002d39b2022-05-31 08:59:27 -07001592 boost::beast::http::status::not_found,
1593 notFoundDesc, notFoundMsg);
1594 return;
1595 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001596
Ed Tanous62598e32023-07-17 17:06:25 -07001597 BMCWEB_LOG_DEBUG("GetObject returned {} object(s)",
1598 interfaceNames.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001599
Ed Tanous002d39b2022-05-31 08:59:27 -07001600 for (const std::pair<std::string, std::vector<std::string>>& object :
1601 interfaceNames)
1602 {
1603 findActionOnInterface(transaction, object.first);
1604 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001605 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001606}
1607
zhanghch058d1b46d2021-04-01 11:18:24 +08001608inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1609 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001610{
Ed Tanous62598e32023-07-17 17:06:25 -07001611 BMCWEB_LOG_DEBUG("handleDelete on path: {}", objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06001612
George Liu2b731192023-01-11 16:27:13 +08001613 dbus::utility::getDbusObject(
1614 objectPath, {},
zhanghch058d1b46d2021-04-01 11:18:24 +08001615 [asyncResp, objectPath](
George Liu2b731192023-01-11 16:27:13 +08001616 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001617 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1618 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001619 if (ec || interfaceNames.empty())
1620 {
Ed Tanous62598e32023-07-17 17:06:25 -07001621 BMCWEB_LOG_ERROR("Can't find object");
Ed Tanous002d39b2022-05-31 08:59:27 -07001622 setErrorResponse(asyncResp->res,
1623 boost::beast::http::status::method_not_allowed,
1624 methodNotAllowedDesc, methodNotAllowedMsg);
1625 return;
1626 }
Matt Spinlerde818812018-12-11 16:39:20 -06001627
Lei YU28dd5ca2023-03-17 13:17:05 +08001628 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001629 transaction->path = objectPath;
1630 transaction->methodName = "Delete";
1631 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
Matt Spinlerde818812018-12-11 16:39:20 -06001632
Ed Tanous002d39b2022-05-31 08:59:27 -07001633 for (const std::pair<std::string, std::vector<std::string>>& object :
1634 interfaceNames)
1635 {
1636 findActionOnInterface(transaction, object.first);
1637 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001638 });
Matt Spinlerde818812018-12-11 16:39:20 -06001639}
1640
zhanghch058d1b46d2021-04-01 11:18:24 +08001641inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1642 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001643{
George Liu7a1dbc42022-12-07 16:03:22 +08001644 dbus::utility::getSubTreePaths(
1645 objectPath, depth, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001646 [asyncResp](
George Liu7a1dbc42022-12-07 16:03:22 +08001647 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001648 const dbus::utility::MapperGetSubTreePathsResponse& objectPaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001649 if (ec)
1650 {
1651 setErrorResponse(asyncResp->res,
1652 boost::beast::http::status::not_found,
1653 notFoundDesc, notFoundMsg);
1654 }
1655 else
1656 {
1657 asyncResp->res.jsonValue["status"] = "ok";
1658 asyncResp->res.jsonValue["message"] = "200 OK";
1659 asyncResp->res.jsonValue["data"] = objectPaths;
1660 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001661 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001662}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001663
zhanghch058d1b46d2021-04-01 11:18:24 +08001664inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1665 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001666{
Ed Tanous62598e32023-07-17 17:06:25 -07001667 BMCWEB_LOG_DEBUG("Doing enumerate on {}", objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07001668
Ed Tanous14766872022-03-15 10:44:42 -07001669 asyncResp->res.jsonValue["message"] = "200 OK";
1670 asyncResp->res.jsonValue["status"] = "ok";
1671 asyncResp->res.jsonValue["data"] = nlohmann::json::object();
Ed Tanous049a0512018-11-01 13:58:42 -07001672
George Liue99073f2022-12-09 11:06:16 +08001673 dbus::utility::getSubTree(
1674 objectPath, 0, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001675 [objectPath, asyncResp](
George Liue99073f2022-12-09 11:06:16 +08001676 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001677 const dbus::utility::MapperGetSubTreeResponse& objectNames) {
Patrick Williams89492a12023-05-10 07:51:34 -05001678 auto transaction = std::make_shared<InProgressEnumerateData>(objectPath,
1679 asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001680
Ed Tanous002d39b2022-05-31 08:59:27 -07001681 transaction->subtree =
1682 std::make_shared<dbus::utility::MapperGetSubTreeResponse>(
1683 objectNames);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001684
Ed Tanous002d39b2022-05-31 08:59:27 -07001685 if (ec)
1686 {
Ed Tanous62598e32023-07-17 17:06:25 -07001687 BMCWEB_LOG_ERROR("GetSubTree failed on {}",
1688 transaction->objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07001689 setErrorResponse(transaction->asyncResp->res,
1690 boost::beast::http::status::not_found,
1691 notFoundDesc, notFoundMsg);
1692 return;
1693 }
Ed Tanous64530012018-02-06 17:08:16 -08001694
Ed Tanous002d39b2022-05-31 08:59:27 -07001695 // Add the data for the path passed in to the results
1696 // as if GetSubTree returned it, and continue on enumerating
1697 getObjectAndEnumerate(transaction);
Patrick Williams5a39f772023-10-20 11:20:21 -05001698 });
Ed Tanous64530012018-02-06 17:08:16 -08001699}
Ed Tanous911ac312017-08-15 09:37:42 -07001700
zhanghch058d1b46d2021-04-01 11:18:24 +08001701inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1702 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001703{
Ed Tanous62598e32023-07-17 17:06:25 -07001704 BMCWEB_LOG_DEBUG("handleGet: {} prop:{}", objectPath, destProperty);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001705 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001706 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001707
Ed Tanous1abe55e2018-09-05 08:30:59 -07001708 std::shared_ptr<std::string> path =
1709 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001710
George Liu2b731192023-01-11 16:27:13 +08001711 dbus::utility::getDbusObject(
1712 *path, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001713 [asyncResp, path,
George Liu2b731192023-01-11 16:27:13 +08001714 propertyName](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001715 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001716 if (ec || objectNames.empty())
1717 {
1718 setErrorResponse(asyncResp->res,
1719 boost::beast::http::status::not_found,
1720 notFoundDesc, notFoundMsg);
1721 return;
1722 }
1723 std::shared_ptr<nlohmann::json> response =
1724 std::make_shared<nlohmann::json>(nlohmann::json::object());
1725 // The mapper should never give us an empty interface names
1726 // list, but check anyway
1727 for (const std::pair<std::string, std::vector<std::string>>&
1728 connection : objectNames)
1729 {
1730 const std::vector<std::string>& interfaceNames = connection.second;
1731
1732 if (interfaceNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001733 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001734 setErrorResponse(asyncResp->res,
1735 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001736 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001737 return;
1738 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001739
1740 for (const std::string& interface : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001741 {
Patrick Williams59d494e2022-07-22 19:26:55 -05001742 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001743 crow::connections::systemBus->new_method_call(
1744 connection.first.c_str(), path->c_str(),
1745 "org.freedesktop.DBus.Properties", "GetAll");
1746 m.append(interface);
1747 crow::connections::systemBus->async_send(
1748 m, [asyncResp, response,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001749 propertyName](const boost::system::error_code& ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05001750 sdbusplus::message_t& msg) {
Patrick Williams5a39f772023-10-20 11:20:21 -05001751 if (ec2)
1752 {
1753 BMCWEB_LOG_ERROR("Bad dbus request error: {}", ec2);
1754 }
1755 else
1756 {
1757 nlohmann::json properties;
1758 int r = convertDBusToJSON("a{sv}", msg, properties);
1759 if (r < 0)
Ed Tanous002d39b2022-05-31 08:59:27 -07001760 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001761 BMCWEB_LOG_ERROR("convertDBusToJSON failed");
Ed Tanous002d39b2022-05-31 08:59:27 -07001762 }
1763 else
1764 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001765 for (const auto& prop : properties.items())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001766 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001767 // if property name is empty, or
1768 // matches our search query, add it
1769 // to the response json
Ed Tanous1abe55e2018-09-05 08:30:59 -07001770
Patrick Williams5a39f772023-10-20 11:20:21 -05001771 if (propertyName->empty())
1772 {
1773 (*response)[prop.key()] =
1774 std::move(prop.value());
1775 }
1776 else if (prop.key() == *propertyName)
1777 {
1778 *response = std::move(prop.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001779 }
1780 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001781 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001782 }
1783 if (response.use_count() == 1)
1784 {
1785 if (!propertyName->empty() && response->empty())
Ed Tanous002d39b2022-05-31 08:59:27 -07001786 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001787 setErrorResponse(
1788 asyncResp->res,
1789 boost::beast::http::status::not_found,
1790 propNotFoundDesc, notFoundMsg);
Ed Tanous002d39b2022-05-31 08:59:27 -07001791 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001792 else
1793 {
1794 asyncResp->res.jsonValue["status"] = "ok";
1795 asyncResp->res.jsonValue["message"] = "200 OK";
1796 asyncResp->res.jsonValue["data"] = *response;
1797 }
1798 }
1799 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001800 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001801 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001802 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001803}
1804
Ed Tanous1abe55e2018-09-05 08:30:59 -07001805struct AsyncPutRequest
1806{
Ed Tanous4e23a442022-06-06 09:57:26 -07001807 explicit AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
zhanghch058d1b46d2021-04-01 11:18:24 +08001808 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001809 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001810 ~AsyncPutRequest()
1811 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001812 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001813 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001814 setErrorResponse(asyncResp->res,
1815 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001816 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001817 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001818 }
1819
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001820 AsyncPutRequest(const AsyncPutRequest&) = delete;
1821 AsyncPutRequest(AsyncPutRequest&&) = delete;
1822 AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1823 AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1824
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001825 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001826 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001827 setErrorResponse(asyncResp->res,
1828 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001829 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001830 }
1831
zhanghch058d1b46d2021-04-01 11:18:24 +08001832 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001833 std::string objectPath;
1834 std::string propertyName;
1835 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001836};
1837
zhanghch058d1b46d2021-04-01 11:18:24 +08001838inline void handlePut(const crow::Request& req,
1839 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001840 const std::string& objectPath,
1841 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001842{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001843 if (destProperty.empty())
1844 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001845 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001846 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001847 return;
1848 }
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001849 nlohmann::json requestDbusData;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001850
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001851 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
1852 if (ret == JsonParseResult::BadContentType)
1853 {
1854 setErrorResponse(asyncResp->res,
1855 boost::beast::http::status::unsupported_media_type,
1856 invalidContentType, unsupportedMediaMsg);
1857 return;
1858 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001859
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001860 if (ret != JsonParseResult::Success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001861 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001862 setErrorResponse(asyncResp->res,
1863 boost::beast::http::status::bad_request, noJsonDesc,
1864 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001865 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001866 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001867
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001868 auto propertyIt = requestDbusData.find("data");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001869 if (propertyIt == requestDbusData.end())
1870 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001871 setErrorResponse(asyncResp->res,
1872 boost::beast::http::status::bad_request, noJsonDesc,
1873 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001874 return;
1875 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001876 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001877 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001878 transaction->objectPath = objectPath;
1879 transaction->propertyName = destProperty;
1880 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001881
George Liu2b731192023-01-11 16:27:13 +08001882 dbus::utility::getDbusObject(
1883 transaction->objectPath, {},
1884 [transaction](const boost::system::error_code& ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001885 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001886 if (!ec2 && objectNames.empty())
1887 {
1888 setErrorResponse(transaction->asyncResp->res,
1889 boost::beast::http::status::not_found,
1890 propNotFoundDesc, notFoundMsg);
1891 return;
1892 }
Ed Tanous911ac312017-08-15 09:37:42 -07001893
Ed Tanous002d39b2022-05-31 08:59:27 -07001894 for (const std::pair<std::string, std::vector<std::string>>&
1895 connection : objectNames)
1896 {
1897 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001898
Ed Tanous002d39b2022-05-31 08:59:27 -07001899 crow::connections::systemBus->async_method_call(
1900 [connectionName{std::string(connectionName)},
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001901 transaction](const boost::system::error_code& ec3,
Ed Tanous002d39b2022-05-31 08:59:27 -07001902 const std::string& introspectXml) {
1903 if (ec3)
1904 {
Ed Tanous62598e32023-07-17 17:06:25 -07001905 BMCWEB_LOG_ERROR(
1906 "Introspect call failed with error: {} on process: {}",
1907 ec3.message(), connectionName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001908 transaction->setErrorStatus("Unexpected Error");
1909 return;
1910 }
1911 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001912
Ed Tanous002d39b2022-05-31 08:59:27 -07001913 doc.Parse(introspectXml.c_str());
1914 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1915 if (pRoot == nullptr)
1916 {
Ed Tanous62598e32023-07-17 17:06:25 -07001917 BMCWEB_LOG_ERROR("XML document failed to parse: {}",
1918 introspectXml);
Ed Tanous002d39b2022-05-31 08:59:27 -07001919 transaction->setErrorStatus("Unexpected Error");
1920 return;
1921 }
1922 tinyxml2::XMLElement* ifaceNode =
1923 pRoot->FirstChildElement("interface");
1924 while (ifaceNode != nullptr)
1925 {
1926 const char* interfaceName = ifaceNode->Attribute("name");
Ed Tanous62598e32023-07-17 17:06:25 -07001927 BMCWEB_LOG_DEBUG("found interface {}", interfaceName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001928 tinyxml2::XMLElement* propNode =
1929 ifaceNode->FirstChildElement("property");
1930 while (propNode != nullptr)
1931 {
1932 const char* propertyName = propNode->Attribute("name");
Ed Tanous62598e32023-07-17 17:06:25 -07001933 BMCWEB_LOG_DEBUG("Found property {}", propertyName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001934 if (propertyName == transaction->propertyName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001935 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001936 const char* argType = propNode->Attribute("type");
1937 if (argType != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001938 {
Patrick Williams59d494e2022-07-22 19:26:55 -05001939 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001940 crow::connections::systemBus
1941 ->new_method_call(
1942 connectionName.c_str(),
1943 transaction->objectPath.c_str(),
1944 "org.freedesktop.DBus."
1945 "Properties",
1946 "Set");
1947 m.append(interfaceName,
1948 transaction->propertyName);
1949 int r = sd_bus_message_open_container(
1950 m.get(), SD_BUS_TYPE_VARIANT, argType);
1951 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001952 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001953 transaction->setErrorStatus(
1954 "Unexpected Error");
1955 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001956 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001957 r = convertJsonToDbus(
1958 m.get(), argType,
1959 transaction->propertyValue);
1960 if (r < 0)
1961 {
1962 if (r == -ERANGE)
1963 {
1964 transaction->setErrorStatus(
1965 "Provided property value "
1966 "is out of range for the "
1967 "property type");
1968 }
1969 else
1970 {
1971 transaction->setErrorStatus(
1972 "Invalid arg type");
1973 }
1974 return;
1975 }
1976 r = sd_bus_message_close_container(m.get());
1977 if (r < 0)
1978 {
1979 transaction->setErrorStatus(
1980 "Unexpected Error");
1981 return;
1982 }
1983 crow::connections::systemBus->async_send(
Patrick Williams5a39f772023-10-20 11:20:21 -05001984 m, [transaction](
1985 const boost::system::error_code& ec,
1986 sdbusplus::message_t& m2) {
Ed Tanous62598e32023-07-17 17:06:25 -07001987 BMCWEB_LOG_DEBUG("sent");
Ed Tanous002d39b2022-05-31 08:59:27 -07001988 if (ec)
1989 {
1990 const sd_bus_error* e = m2.get_error();
1991 setErrorResponse(
1992 transaction->asyncResp->res,
1993 boost::beast::http::status::
1994 forbidden,
1995 (e) != nullptr
1996 ? e->name
1997 : ec.category().name(),
1998 (e) != nullptr ? e->message
1999 : ec.message());
2000 }
2001 else
2002 {
2003 transaction->asyncResp->res
2004 .jsonValue["status"] = "ok";
2005 transaction->asyncResp->res
2006 .jsonValue["message"] = "200 OK";
2007 transaction->asyncResp->res
2008 .jsonValue["data"] = nullptr;
2009 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002010 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002011 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002012 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002013 propNode = propNode->NextSiblingElement("property");
2014 }
2015 ifaceNode = ifaceNode->NextSiblingElement("interface");
2016 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002017 },
Ed Tanous002d39b2022-05-31 08:59:27 -07002018 connectionName, transaction->objectPath,
2019 "org.freedesktop.DBus.Introspectable", "Introspect");
2020 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002021 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07002022}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002023
zhanghch058d1b46d2021-04-01 11:18:24 +08002024inline void handleDBusUrl(const crow::Request& req,
2025 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002026 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002027{
Ed Tanous049a0512018-11-01 13:58:42 -07002028 // If accessing a single attribute, fill in and update objectPath,
2029 // otherwise leave destProperty blank
Ed Tanouse05aec52022-01-25 10:28:56 -08002030 std::string destProperty;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002031 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002032 size_t attrPosition = objectPath.find(attrSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002033 if (attrPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002034 {
2035 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2036 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002037 objectPath.resize(attrPosition);
Ed Tanous049a0512018-11-01 13:58:42 -07002038 }
2039
Ed Tanousb41187f2019-10-24 16:30:02 -07002040 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002041 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002042 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002043 size_t actionPosition = objectPath.find(actionSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002044 if (actionPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002045 {
2046 std::string postProperty =
2047 objectPath.substr((actionPosition + strlen(actionSeperator)),
2048 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002049 objectPath.resize(actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002050 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002051 return;
2052 }
2053 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002054 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002055 {
Ed Tanous11ba3972022-07-11 09:50:41 -07002056 if (objectPath.ends_with("/enumerate"))
Ed Tanous049a0512018-11-01 13:58:42 -07002057 {
2058 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2059 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002060 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002061 }
Ed Tanous11ba3972022-07-11 09:50:41 -07002062 else if (objectPath.ends_with("/list"))
Ed Tanous049a0512018-11-01 13:58:42 -07002063 {
2064 objectPath.erase(objectPath.end() - sizeof("list"),
2065 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002066 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002067 }
2068 else
2069 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002070 // Trim any trailing "/" at the end
Ed Tanous11ba3972022-07-11 09:50:41 -07002071 if (objectPath.ends_with("/"))
Ed Tanousf839dfe2018-11-12 11:11:15 -08002072 {
2073 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002074 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002075 }
2076 else
2077 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002078 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002079 }
Ed Tanous049a0512018-11-01 13:58:42 -07002080 }
2081 return;
2082 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002083 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002084 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002085 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002086 return;
2087 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002088 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002089 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002090 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002091 return;
2092 }
Ed Tanous049a0512018-11-01 13:58:42 -07002093
zhanghch058d1b46d2021-04-01 11:18:24 +08002094 setErrorResponse(asyncResp->res,
2095 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002096 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002097}
2098
Ed Tanous1656b292022-05-04 11:33:42 -07002099inline void
2100 handleBusSystemPost(const crow::Request& req,
2101 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2102 const std::string& processName,
2103 const std::string& requestedPath)
2104{
2105 std::vector<std::string> strs;
Ed Tanous50ebd4a2023-01-19 19:03:17 -08002106
2107 bmcweb::split(strs, requestedPath, '/');
Ed Tanous1656b292022-05-04 11:33:42 -07002108 std::string objectPath;
2109 std::string interfaceName;
2110 std::string methodName;
2111 auto it = strs.begin();
2112 if (it == strs.end())
2113 {
2114 objectPath = "/";
2115 }
2116 while (it != strs.end())
2117 {
2118 // Check if segment contains ".". If it does, it must be an
2119 // interface
2120 if (it->find(".") != std::string::npos)
2121 {
2122 break;
2123 // This check is necessary as the trailing slash gets
2124 // parsed as part of our <path> specifier above, which
2125 // causes the normal trailing backslash redirector to
2126 // fail.
2127 }
2128 if (!it->empty())
2129 {
2130 objectPath += "/" + *it;
2131 }
2132 it++;
2133 }
2134 if (it != strs.end())
2135 {
2136 interfaceName = *it;
2137 it++;
2138
2139 // after interface, we might have a method name
2140 if (it != strs.end())
2141 {
2142 methodName = *it;
2143 it++;
2144 }
2145 }
2146 if (it != strs.end())
2147 {
2148 // if there is more levels past the method name, something
2149 // went wrong, return not found
2150 asyncResp->res.result(boost::beast::http::status::not_found);
2151 return;
2152 }
2153 if (interfaceName.empty())
2154 {
2155 crow::connections::systemBus->async_method_call(
2156 [asyncResp, processName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002157 objectPath](const boost::system::error_code& ec,
Ed Tanous1656b292022-05-04 11:33:42 -07002158 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002159 if (ec)
2160 {
Ed Tanous62598e32023-07-17 17:06:25 -07002161 BMCWEB_LOG_ERROR(
2162 "Introspect call failed with error: {} on process: {} path: {}",
2163 ec.message(), processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002164 return;
2165 }
2166 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002167
Ed Tanous002d39b2022-05-31 08:59:27 -07002168 doc.Parse(introspectXml.c_str());
2169 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2170 if (pRoot == nullptr)
2171 {
Ed Tanous62598e32023-07-17 17:06:25 -07002172 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
2173 processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002174 asyncResp->res.jsonValue["status"] = "XML parse error";
2175 asyncResp->res.result(
2176 boost::beast::http::status::internal_server_error);
2177 return;
2178 }
2179
Ed Tanous62598e32023-07-17 17:06:25 -07002180 BMCWEB_LOG_DEBUG("{}", introspectXml);
Ed Tanous002d39b2022-05-31 08:59:27 -07002181 asyncResp->res.jsonValue["status"] = "ok";
2182 asyncResp->res.jsonValue["bus_name"] = processName;
2183 asyncResp->res.jsonValue["object_path"] = objectPath;
2184
2185 nlohmann::json& interfacesArray =
2186 asyncResp->res.jsonValue["interfaces"];
2187 interfacesArray = nlohmann::json::array();
2188 tinyxml2::XMLElement* interface =
2189 pRoot->FirstChildElement("interface");
2190
2191 while (interface != nullptr)
2192 {
2193 const char* ifaceName = interface->Attribute("name");
2194 if (ifaceName != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002195 {
Ed Tanous8a592812022-06-04 09:06:59 -07002196 nlohmann::json::object_t interfaceObj;
2197 interfaceObj["name"] = ifaceName;
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002198 interfacesArray.emplace_back(std::move(interfaceObj));
Ed Tanous1656b292022-05-04 11:33:42 -07002199 }
2200
Ed Tanous002d39b2022-05-31 08:59:27 -07002201 interface = interface->NextSiblingElement("interface");
2202 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002203 },
Ed Tanous1656b292022-05-04 11:33:42 -07002204 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2205 "Introspect");
2206 }
2207 else if (methodName.empty())
2208 {
2209 crow::connections::systemBus->async_method_call(
2210 [asyncResp, processName, objectPath,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002211 interfaceName](const boost::system::error_code& ec,
Ed Tanous1656b292022-05-04 11:33:42 -07002212 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002213 if (ec)
2214 {
Ed Tanous62598e32023-07-17 17:06:25 -07002215 BMCWEB_LOG_ERROR(
2216 "Introspect call failed with error: {} on process: {} path: {}",
2217 ec.message(), processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002218 return;
2219 }
2220 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002221
Ed Tanous002d39b2022-05-31 08:59:27 -07002222 doc.Parse(introspectXml.data(), introspectXml.size());
2223 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2224 if (pRoot == nullptr)
2225 {
Ed Tanous62598e32023-07-17 17:06:25 -07002226 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
2227 processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002228 asyncResp->res.result(
2229 boost::beast::http::status::internal_server_error);
2230 return;
2231 }
2232
2233 asyncResp->res.jsonValue["status"] = "ok";
2234 asyncResp->res.jsonValue["bus_name"] = processName;
2235 asyncResp->res.jsonValue["interface"] = interfaceName;
2236 asyncResp->res.jsonValue["object_path"] = objectPath;
2237
2238 nlohmann::json& methodsArray = asyncResp->res.jsonValue["methods"];
2239 methodsArray = nlohmann::json::array();
2240
2241 nlohmann::json& signalsArray = asyncResp->res.jsonValue["signals"];
2242 signalsArray = nlohmann::json::array();
2243
2244 nlohmann::json& propertiesObj =
2245 asyncResp->res.jsonValue["properties"];
2246 propertiesObj = nlohmann::json::object();
2247
2248 // if we know we're the only call, build the
2249 // json directly
2250 tinyxml2::XMLElement* interface =
2251 pRoot->FirstChildElement("interface");
2252 while (interface != nullptr)
2253 {
2254 const char* ifaceName = interface->Attribute("name");
2255
2256 if (ifaceName != nullptr && ifaceName == interfaceName)
Ed Tanous1656b292022-05-04 11:33:42 -07002257 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002258 break;
Ed Tanous1656b292022-05-04 11:33:42 -07002259 }
Ed Tanous14766872022-03-15 10:44:42 -07002260
Ed Tanous002d39b2022-05-31 08:59:27 -07002261 interface = interface->NextSiblingElement("interface");
2262 }
2263 if (interface == nullptr)
2264 {
2265 // if we got to the end of the list and
2266 // never found a match, throw 404
2267 asyncResp->res.result(boost::beast::http::status::not_found);
2268 return;
2269 }
Ed Tanous1656b292022-05-04 11:33:42 -07002270
Ed Tanous002d39b2022-05-31 08:59:27 -07002271 tinyxml2::XMLElement* methods =
2272 interface->FirstChildElement("method");
2273 while (methods != nullptr)
2274 {
2275 nlohmann::json argsArray = nlohmann::json::array();
2276 tinyxml2::XMLElement* arg = methods->FirstChildElement("arg");
2277 while (arg != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002278 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002279 nlohmann::json thisArg;
2280 for (const char* fieldName : std::array<const char*, 3>{
2281 "name", "direction", "type"})
Ed Tanous1656b292022-05-04 11:33:42 -07002282 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002283 const char* fieldValue = arg->Attribute(fieldName);
2284 if (fieldValue != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002285 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002286 thisArg[fieldName] = fieldValue;
2287 }
2288 }
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002289 argsArray.emplace_back(std::move(thisArg));
Ed Tanous002d39b2022-05-31 08:59:27 -07002290 arg = arg->NextSiblingElement("arg");
2291 }
2292
2293 const char* name = methods->Attribute("name");
2294 if (name != nullptr)
2295 {
2296 std::string uri;
2297 uri.reserve(14 + processName.size() + objectPath.size() +
2298 interfaceName.size() + strlen(name));
2299 uri += "/bus/system/";
2300 uri += processName;
2301 uri += objectPath;
2302 uri += "/";
2303 uri += interfaceName;
2304 uri += "/";
2305 uri += name;
2306
2307 nlohmann::json::object_t object;
2308 object["name"] = name;
2309 object["uri"] = std::move(uri);
2310 object["args"] = argsArray;
2311
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002312 methodsArray.emplace_back(std::move(object));
Ed Tanous002d39b2022-05-31 08:59:27 -07002313 }
2314 methods = methods->NextSiblingElement("method");
2315 }
2316 tinyxml2::XMLElement* signals =
2317 interface->FirstChildElement("signal");
2318 while (signals != nullptr)
2319 {
2320 nlohmann::json argsArray = nlohmann::json::array();
2321
2322 tinyxml2::XMLElement* arg = signals->FirstChildElement("arg");
2323 while (arg != nullptr)
2324 {
2325 const char* name = arg->Attribute("name");
2326 const char* type = arg->Attribute("type");
2327 if (name != nullptr && type != nullptr)
2328 {
2329 argsArray.push_back({
2330 {"name", name},
2331 {"type", type},
2332 });
2333 }
2334 arg = arg->NextSiblingElement("arg");
2335 }
2336 const char* name = signals->Attribute("name");
2337 if (name != nullptr)
2338 {
2339 nlohmann::json::object_t object;
2340 object["name"] = name;
2341 object["args"] = argsArray;
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002342 signalsArray.emplace_back(std::move(object));
Ed Tanous002d39b2022-05-31 08:59:27 -07002343 }
2344
2345 signals = signals->NextSiblingElement("signal");
2346 }
2347
2348 tinyxml2::XMLElement* property =
2349 interface->FirstChildElement("property");
2350 while (property != nullptr)
2351 {
2352 const char* name = property->Attribute("name");
2353 const char* type = property->Attribute("type");
2354 if (type != nullptr && name != nullptr)
2355 {
Patrick Williams59d494e2022-07-22 19:26:55 -05002356 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07002357 crow::connections::systemBus->new_method_call(
2358 processName.c_str(), objectPath.c_str(),
2359 "org.freedesktop."
2360 "DBus."
2361 "Properties",
2362 "Get");
2363 m.append(interfaceName, name);
2364 nlohmann::json& propertyItem = propertiesObj[name];
2365 crow::connections::systemBus->async_send(
2366 m, [&propertyItem,
Ed Tanous8b242752023-06-27 17:17:13 -07002367 asyncResp](const boost::system::error_code& ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05002368 sdbusplus::message_t& msg) {
Patrick Williams5a39f772023-10-20 11:20:21 -05002369 if (ec2)
2370 {
2371 return;
2372 }
Ed Tanous1656b292022-05-04 11:33:42 -07002373
Patrick Williams5a39f772023-10-20 11:20:21 -05002374 convertDBusToJSON("v", msg, propertyItem);
2375 });
Ed Tanous1656b292022-05-04 11:33:42 -07002376 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002377 property = property->NextSiblingElement("property");
2378 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002379 },
Ed Tanous1656b292022-05-04 11:33:42 -07002380 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2381 "Introspect");
2382 }
2383 else
2384 {
2385 if (req.method() != boost::beast::http::verb::post)
2386 {
2387 asyncResp->res.result(boost::beast::http::status::not_found);
2388 return;
2389 }
2390
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002391 nlohmann::json requestDbusData;
2392 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
2393 if (ret == JsonParseResult::BadContentType)
Ed Tanous1656b292022-05-04 11:33:42 -07002394 {
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002395 setErrorResponse(asyncResp->res,
2396 boost::beast::http::status::unsupported_media_type,
2397 invalidContentType, unsupportedMediaMsg);
Ed Tanous1656b292022-05-04 11:33:42 -07002398 return;
2399 }
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002400 if (ret != JsonParseResult::Success)
2401 {
2402 setErrorResponse(asyncResp->res,
2403 boost::beast::http::status::bad_request,
2404 noJsonDesc, badReqMsg);
2405 return;
2406 }
2407
Ed Tanous1656b292022-05-04 11:33:42 -07002408 if (!requestDbusData.is_array())
2409 {
2410 asyncResp->res.result(boost::beast::http::status::bad_request);
2411 return;
2412 }
Lei YU28dd5ca2023-03-17 13:17:05 +08002413 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous1656b292022-05-04 11:33:42 -07002414
2415 transaction->path = objectPath;
2416 transaction->methodName = methodName;
2417 transaction->arguments = std::move(requestDbusData);
2418
2419 findActionOnInterface(transaction, processName);
2420 }
2421}
2422
Ed Tanous23a21a12020-07-25 04:45:05 +00002423inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002424{
2425 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002426 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002427 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002428 [](const crow::Request&,
2429 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002430 nlohmann::json::array_t buses;
2431 nlohmann::json& bus = buses.emplace_back();
2432 bus["name"] = "system";
2433 asyncResp->res.jsonValue["busses"] = std::move(buses);
2434 asyncResp->res.jsonValue["status"] = "ok";
Patrick Williams5a39f772023-10-20 11:20:21 -05002435 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002436
2437 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002438 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002439 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002440 [](const crow::Request&,
2441 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002442 auto myCallback = [asyncResp](const boost::system::error_code& ec,
zhanghch058d1b46d2021-04-01 11:18:24 +08002443 std::vector<std::string>& names) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002444 if (ec)
2445 {
Ed Tanous62598e32023-07-17 17:06:25 -07002446 BMCWEB_LOG_ERROR("Dbus call failed with code {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07002447 asyncResp->res.result(
2448 boost::beast::http::status::internal_server_error);
2449 }
2450 else
2451 {
Ed Tanous3544d2a2023-08-06 18:12:20 -07002452 std::ranges::sort(names);
Ed Tanous002d39b2022-05-31 08:59:27 -07002453 asyncResp->res.jsonValue["status"] = "ok";
2454 auto& objectsSub = asyncResp->res.jsonValue["objects"];
Ed Tanous02cad962022-06-30 16:50:15 -07002455 for (const auto& name : names)
Ed Tanous002d39b2022-05-31 08:59:27 -07002456 {
2457 nlohmann::json::object_t object;
2458 object["name"] = name;
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002459 objectsSub.emplace_back(std::move(object));
Ed Tanous002d39b2022-05-31 08:59:27 -07002460 }
2461 }
2462 };
2463 crow::connections::systemBus->async_method_call(
2464 std::move(myCallback), "org.freedesktop.DBus", "/",
2465 "org.freedesktop.DBus", "ListNames");
Patrick Williams5a39f772023-10-20 11:20:21 -05002466 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002467
2468 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002469 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002470 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002471 [](const crow::Request&,
2472 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002473 handleList(asyncResp, "/");
Patrick Williams5a39f772023-10-20 11:20:21 -05002474 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002475
2476 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002477 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002478 .methods(boost::beast::http::verb::get)(
2479 [](const crow::Request& req,
2480 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002481 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002482 std::string objectPath = "/xyz/" + path;
2483 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002484 });
zhanghch058d1b46d2021-04-01 11:18:24 +08002485
2486 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002487 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002488 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2489 boost::beast::http::verb::delete_)(
2490 [](const crow::Request& req,
2491 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2492 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002493 std::string objectPath = "/xyz/" + path;
2494 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002495 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002496
Ed Tanous049a0512018-11-01 13:58:42 -07002497 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002498 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002499 .methods(boost::beast::http::verb::get)(
2500 [](const crow::Request& req,
2501 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2502 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002503 std::string objectPath = "/org/" + path;
2504 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002505 });
Tanousf00032d2018-11-05 01:18:10 -03002506
2507 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002508 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002509 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2510 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002511 [](const crow::Request& req,
2512 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002513 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002514 std::string objectPath = "/org/" + path;
2515 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002516 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002517
Ed Tanous1abe55e2018-09-05 08:30:59 -07002518 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002519 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002520 .methods(boost::beast::http::verb::get)(
2521 [](const crow::Request&,
2522 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2523 const std::string& dumpId) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002524 if (!validateFilename(dumpId))
2525 {
2526 asyncResp->res.result(boost::beast::http::status::bad_request);
2527 return;
2528 }
2529 std::filesystem::path loc("/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002530
Ed Tanous002d39b2022-05-31 08:59:27 -07002531 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002532
Ed Tanous002d39b2022-05-31 08:59:27 -07002533 if (!std::filesystem::exists(loc) ||
2534 !std::filesystem::is_directory(loc))
2535 {
Ed Tanous62598e32023-07-17 17:06:25 -07002536 BMCWEB_LOG_ERROR("{}Not found", loc.string());
Ed Tanous002d39b2022-05-31 08:59:27 -07002537 asyncResp->res.result(boost::beast::http::status::not_found);
2538 return;
2539 }
2540 std::filesystem::directory_iterator files(loc);
zhanghch058d1b46d2021-04-01 11:18:24 +08002541
Ed Tanous002d39b2022-05-31 08:59:27 -07002542 for (const auto& file : files)
2543 {
Ed Tanous27b0cf92023-08-07 12:02:40 -07002544 if (!asyncResp->res.openFile(file))
Ed Tanous002d39b2022-05-31 08:59:27 -07002545 {
2546 continue;
2547 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002548
Ed Tanousd9f6c622022-03-17 09:12:17 -07002549 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07002550 "application/octet-stream");
zhanghch058d1b46d2021-04-01 11:18:24 +08002551
Ed Tanous002d39b2022-05-31 08:59:27 -07002552 // Assuming only one dump file will be present in the dump
2553 // id directory
2554 std::string dumpFileName = file.path().filename().string();
zhanghch058d1b46d2021-04-01 11:18:24 +08002555
Ed Tanous002d39b2022-05-31 08:59:27 -07002556 // Filename should be in alphanumeric, dot and underscore
2557 // Its based on phosphor-debug-collector application
2558 // dumpfile format
Ed Tanous4b242742023-05-11 09:51:51 -07002559 static std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
Ed Tanous002d39b2022-05-31 08:59:27 -07002560 if (!std::regex_match(dumpFileName, dumpFileRegex))
2561 {
Ed Tanous62598e32023-07-17 17:06:25 -07002562 BMCWEB_LOG_ERROR("Invalid dump filename {}", dumpFileName);
zhanghch058d1b46d2021-04-01 11:18:24 +08002563 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002564 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07002565 }
Patrick Williams89492a12023-05-10 07:51:34 -05002566 std::string contentDispositionParam = "attachment; filename=\"" +
2567 dumpFileName + "\"";
Ed Tanous002d39b2022-05-31 08:59:27 -07002568
Ed Tanousd9f6c622022-03-17 09:12:17 -07002569 asyncResp->res.addHeader(
2570 boost::beast::http::field::content_disposition,
2571 contentDispositionParam);
Ed Tanous002d39b2022-05-31 08:59:27 -07002572
Ed Tanous002d39b2022-05-31 08:59:27 -07002573 return;
2574 }
2575 asyncResp->res.result(boost::beast::http::status::not_found);
2576 return;
Patrick Williams5a39f772023-10-20 11:20:21 -05002577 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002578
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002579 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002580 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002581
2582 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002583 [](const crow::Request&,
2584 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002585 const std::string& connection) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002586 introspectObjects(connection, "/", asyncResp);
Patrick Williams5a39f772023-10-20 11:20:21 -05002587 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002588
2589 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002590 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous1656b292022-05-04 11:33:42 -07002591 .methods(boost::beast::http::verb::get,
2592 boost::beast::http::verb::post)(handleBusSystemPost);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002593}
2594} // namespace openbmc_mapper
2595} // namespace crow