blob: 72e1c31c062e5bc1589692bc27161ac9eba00101 [file] [log] [blame]
James Feist5b4aa862018-08-16 14:07:01 -07001// Copyright (c) 2018 Intel Corporation
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
Ed Tanousb9b2e0b2018-09-13 13:47:50 -070014
James Feist5b4aa862018-08-16 14:07:01 -070015#pragma once
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080016#include "app.hpp"
17#include "async_resp.hpp"
Ed Tanous95c63072024-03-26 13:19:52 -070018#include "boost_formatters.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080019#include "dbus_singleton.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +080020#include "dbus_utility.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000021#include "http_request.hpp"
22#include "http_response.hpp"
Ed Tanous95c63072024-03-26 13:19:52 -070023#include "json_formatters.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000024#include "logging.hpp"
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010025#include "parsing.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000026#include "routing.hpp"
Ed Tanous50ebd4a2023-01-19 19:03:17 -080027#include "str_utility.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000028
29#include <systemd/sd-bus-protocol.h>
30#include <systemd/sd-bus.h>
Ed Tanous911ac312017-08-15 09:37:42 -070031#include <tinyxml2.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -070032
Nan Zhoud5c80ad2022-07-11 01:16:31 +000033#include <boost/beast/http/status.hpp>
34#include <boost/beast/http/verb.hpp>
35#include <boost/container/flat_map.hpp>
36#include <boost/container/vector.hpp>
George Liue99073f2022-12-09 11:06:16 +080037#include <boost/system/error_code.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000038#include <nlohmann/json.hpp>
39#include <sdbusplus/asio/connection.hpp>
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +020040#include <sdbusplus/asio/property.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000041#include <sdbusplus/exception.hpp>
42#include <sdbusplus/message.hpp>
43#include <sdbusplus/message/native_types.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050044
Nan Zhoud5c80ad2022-07-11 01:16:31 +000045#include <algorithm>
46#include <array>
47#include <cerrno>
48#include <cstdint>
49#include <cstring>
James Feist4418c7f2019-04-15 11:09:15 -070050#include <filesystem>
Ed Tanousd4bb9bb2018-05-16 13:36:42 -070051#include <fstream>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000052#include <functional>
53#include <initializer_list>
54#include <iterator>
55#include <limits>
56#include <map>
57#include <memory>
Ed Tanous3544d2a2023-08-06 18:12:20 -070058#include <ranges>
Ramesh Iyyard9207042019-07-05 08:04:42 -050059#include <regex>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000060#include <string>
61#include <string_view>
62#include <type_traits>
Ed Tanousb5a76932020-09-29 16:16:58 -070063#include <utility>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000064#include <variant>
65#include <vector>
66
67// IWYU pragma: no_include <boost/algorithm/string/detail/classification.hpp>
68// IWYU pragma: no_include <boost/system/detail/error_code.hpp>
69// IWYU pragma: no_include <boost/system/detail/error_category.hpp>
70// IWYU pragma: no_include <errno.h>
71// IWYU pragma: no_include <string.h>
72// IWYU pragma: no_include <ext/alloc_traits.h>
73// IWYU pragma: no_include <exception>
74// IWYU pragma: no_include <boost/type_index/type_index_facade.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -070075
Ed Tanous1abe55e2018-09-05 08:30:59 -070076namespace crow
77{
78namespace openbmc_mapper
79{
Ed Tanous23a21a12020-07-25 04:45:05 +000080const constexpr char* notFoundMsg = "404 Not Found";
81const constexpr char* badReqMsg = "400 Bad Request";
82const constexpr char* methodNotAllowedMsg = "405 Method Not Allowed";
83const constexpr char* forbiddenMsg = "403 Forbidden";
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010084const constexpr char* unsupportedMediaMsg = "415 Unsupported Media Type";
Ed Tanous23a21a12020-07-25 04:45:05 +000085const constexpr char* methodFailedMsg = "500 Method Call Failed";
86const constexpr char* methodOutputFailedMsg = "500 Method Output Error";
87const constexpr char* notFoundDesc =
Matt Spinler2ae60092018-12-06 10:35:36 -060088 "org.freedesktop.DBus.Error.FileNotFound: path or object not found";
Ed Tanous23a21a12020-07-25 04:45:05 +000089const constexpr char* propNotFoundDesc =
90 "The specified property cannot be found";
91const constexpr char* noJsonDesc = "No JSON object could be decoded";
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010092const constexpr char* invalidContentType =
93 "Content-type header is missing or invalid";
Ed Tanous23a21a12020-07-25 04:45:05 +000094const constexpr char* methodNotFoundDesc =
95 "The specified method cannot be found";
96const constexpr char* methodNotAllowedDesc = "Method not allowed";
97const constexpr char* forbiddenPropDesc =
98 "The specified property cannot be created";
99const constexpr char* forbiddenResDesc =
100 "The specified resource cannot be created";
Matt Spinler2ae60092018-12-06 10:35:36 -0600101
Josh Lehan482c45a2022-03-29 17:10:44 -0700102inline bool validateFilename(const std::string& filename)
103{
Ed Tanous4b242742023-05-11 09:51:51 -0700104 static std::regex validFilename(R"(^[\w\- ]+(\.?[\w\- ]*)$)");
Josh Lehan482c45a2022-03-29 17:10:44 -0700105
106 return std::regex_match(filename, validFilename);
107}
108
Ed Tanous23a21a12020-07-25 04:45:05 +0000109inline void setErrorResponse(crow::Response& res,
110 boost::beast::http::status result,
Ed Tanous26ccae32023-02-16 10:28:44 -0800111 const std::string& desc, std::string_view msg)
Matt Spinler2ae60092018-12-06 10:35:36 -0600112{
113 res.result(result);
Ed Tanous14766872022-03-15 10:44:42 -0700114 res.jsonValue["data"]["description"] = desc;
115 res.jsonValue["message"] = msg;
116 res.jsonValue["status"] = "error";
Matt Spinler2ae60092018-12-06 10:35:36 -0600117}
118
Ed Tanousb5a76932020-09-29 16:16:58 -0700119inline void
120 introspectObjects(const std::string& processName,
121 const std::string& objectPath,
122 const std::shared_ptr<bmcweb::AsyncResp>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123{
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700124 if (transaction->res.jsonValue.is_null())
125 {
Ed Tanous14766872022-03-15 10:44:42 -0700126 transaction->res.jsonValue["status"] = "ok";
127 transaction->res.jsonValue["bus_name"] = processName;
128 transaction->res.jsonValue["objects"] = nlohmann::json::array();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700129 }
130
Ed Tanous1abe55e2018-09-05 08:30:59 -0700131 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700132 [transaction, processName{std::string(processName)},
133 objectPath{std::string(objectPath)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800134 const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +0000135 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700136 if (ec)
137 {
Ed Tanous62598e32023-07-17 17:06:25 -0700138 BMCWEB_LOG_ERROR(
139 "Introspect call failed with error: {} on process: {} path: {}",
140 ec.message(), processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -0700141 return;
142 }
143 nlohmann::json::object_t object;
144 object["path"] = objectPath;
Ed Tanous14766872022-03-15 10:44:42 -0700145
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500146 transaction->res.jsonValue["objects"].emplace_back(std::move(object));
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700147
Ed Tanous002d39b2022-05-31 08:59:27 -0700148 tinyxml2::XMLDocument doc;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700149
Ed Tanous002d39b2022-05-31 08:59:27 -0700150 doc.Parse(introspectXml.c_str());
151 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
152 if (pRoot == nullptr)
153 {
Ed Tanous62598e32023-07-17 17:06:25 -0700154 BMCWEB_LOG_ERROR("XML document failed to parse {} {}", processName,
155 objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -0700156 }
157 else
158 {
159 tinyxml2::XMLElement* node = pRoot->FirstChildElement("node");
160 while (node != nullptr)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700161 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700162 const char* childPath = node->Attribute("name");
163 if (childPath != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700164 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700165 std::string newpath;
166 if (objectPath != "/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700167 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700168 newpath += objectPath;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700169 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700170 newpath += std::string("/") + childPath;
171 // introspect the subobjects as well
172 introspectObjects(processName, newpath, transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700173 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700174
175 node = node->NextSiblingElement("node");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700176 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700177 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500178 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700179 processName, objectPath, "org.freedesktop.DBus.Introspectable",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700180 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -0700181}
Ed Tanous64530012018-02-06 17:08:16 -0800182
Ed Tanous23a21a12020-07-25 04:45:05 +0000183inline void getPropertiesForEnumerate(
184 const std::string& objectPath, const std::string& service,
Ed Tanousb5a76932020-09-29 16:16:58 -0700185 const std::string& interface,
186 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600187{
Ed Tanous62598e32023-07-17 17:06:25 -0700188 BMCWEB_LOG_DEBUG("getPropertiesForEnumerate {} {} {}", objectPath, service,
189 interface);
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600190
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +0200191 sdbusplus::asio::getAllProperties(
192 *crow::connections::systemBus, service, objectPath, interface,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800193 [asyncResp, objectPath, service,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800194 interface](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800195 const dbus::utility::DBusPropertiesMap& propertiesList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700196 if (ec)
197 {
Ed Tanous62598e32023-07-17 17:06:25 -0700198 BMCWEB_LOG_ERROR(
199 "GetAll on path {} iface {} service {} failed with code {}",
200 objectPath, interface, service, ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700201 return;
202 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600203
Ed Tanous002d39b2022-05-31 08:59:27 -0700204 nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
205 nlohmann::json& objectJson = dataJson[objectPath];
206 if (objectJson.is_null())
207 {
208 objectJson = nlohmann::json::object();
209 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600210
Ed Tanous002d39b2022-05-31 08:59:27 -0700211 for (const auto& [name, value] : propertiesList)
212 {
213 nlohmann::json& propertyJson = objectJson[name];
214 std::visit(
215 [&propertyJson](auto&& val) {
216 if constexpr (std::is_same_v<std::decay_t<decltype(val)>,
217 sdbusplus::message::unix_fd>)
218 {
219 propertyJson = val.fd;
220 }
221 else
222 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700223 propertyJson = val;
224 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500225 },
Ed Tanous002d39b2022-05-31 08:59:27 -0700226 value);
227 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500228 });
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600229}
230
231// Find any results that weren't picked up by ObjectManagers, to be
232// called after all ObjectManagers are searched for and called.
Ed Tanous23a21a12020-07-25 04:45:05 +0000233inline void findRemainingObjectsForEnumerate(
Ed Tanousb5a76932020-09-29 16:16:58 -0700234 const std::string& objectPath,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800235 const std::shared_ptr<dbus::utility::MapperGetSubTreeResponse>& subtree,
Ed Tanousb5a76932020-09-29 16:16:58 -0700236 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600237{
Ed Tanous62598e32023-07-17 17:06:25 -0700238 BMCWEB_LOG_DEBUG("findRemainingObjectsForEnumerate");
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500239 const nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600240
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500241 for (const auto& [path, interface_map] : *subtree)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600242 {
243 if (path == objectPath)
244 {
245 // An enumerate does not return the target path's properties
246 continue;
247 }
248 if (dataJson.find(path) == dataJson.end())
249 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500250 for (const auto& [service, interfaces] : interface_map)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600251 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500252 for (const auto& interface : interfaces)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600253 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700254 if (!interface.starts_with("org.freedesktop.DBus"))
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600255 {
256 getPropertiesForEnumerate(path, service, interface,
257 asyncResp);
258 }
259 }
260 }
261 }
262 }
263}
264
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600265struct InProgressEnumerateData
266{
zhanghch058d1b46d2021-04-01 11:18:24 +0800267 InProgressEnumerateData(
268 const std::string& objectPathIn,
269 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
Ed Tanous23a21a12020-07-25 04:45:05 +0000270 objectPath(objectPathIn),
zhanghch058d1b46d2021-04-01 11:18:24 +0800271 asyncResp(asyncRespIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500272 {}
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600273
274 ~InProgressEnumerateData()
275 {
Ed Tanous24b2fe82022-01-06 12:45:54 -0800276 try
277 {
278 findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
279 }
280 catch (...)
281 {
Ed Tanous62598e32023-07-17 17:06:25 -0700282 BMCWEB_LOG_CRITICAL(
283 "findRemainingObjectsForEnumerate threw exception");
Ed Tanous24b2fe82022-01-06 12:45:54 -0800284 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600285 }
286
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800287 InProgressEnumerateData(const InProgressEnumerateData&) = delete;
288 InProgressEnumerateData(InProgressEnumerateData&&) = delete;
289 InProgressEnumerateData& operator=(const InProgressEnumerateData&) = delete;
290 InProgressEnumerateData& operator=(InProgressEnumerateData&&) = delete;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600291 const std::string objectPath;
Ed Tanousb9d36b42022-02-26 21:42:46 -0800292 std::shared_ptr<dbus::utility::MapperGetSubTreeResponse> subtree;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600293 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
294};
295
Ed Tanous23a21a12020-07-25 04:45:05 +0000296inline void getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000297 const std::string& objectName, const std::string& objectManagerPath,
298 const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700299 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700300{
Ed Tanous62598e32023-07-17 17:06:25 -0700301 BMCWEB_LOG_DEBUG(
302 "getManagedObjectsForEnumerate {} object_manager_path {} connection_name {}",
303 objectName, objectManagerPath, connectionName);
George Liu5eb468d2023-06-20 17:03:24 +0800304 sdbusplus::message::object_path path(objectManagerPath);
305 dbus::utility::getManagedObjects(
306 connectionName, path,
Ed Tanous81ce6092020-12-17 16:54:55 +0000307 [transaction, objectName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800308 connectionName](const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +0000309 const dbus::utility::ManagedObjectType& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700310 if (ec)
311 {
Ed Tanous62598e32023-07-17 17:06:25 -0700312 BMCWEB_LOG_ERROR(
313 "GetManagedObjects on path {} on connection {} failed with code {}",
314 objectName, connectionName, ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700315 return;
316 }
Ed Tanous64530012018-02-06 17:08:16 -0800317
Ed Tanous002d39b2022-05-31 08:59:27 -0700318 nlohmann::json& dataJson =
319 transaction->asyncResp->res.jsonValue["data"];
Ed Tanous049a0512018-11-01 13:58:42 -0700320
Ed Tanous002d39b2022-05-31 08:59:27 -0700321 for (const auto& objectPath : objects)
322 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700323 if (objectPath.first.str.starts_with(objectName))
Ed Tanous049a0512018-11-01 13:58:42 -0700324 {
Ed Tanous62598e32023-07-17 17:06:25 -0700325 BMCWEB_LOG_DEBUG("Reading object {}", objectPath.first.str);
Ed Tanous002d39b2022-05-31 08:59:27 -0700326 nlohmann::json& objectJson = dataJson[objectPath.first.str];
327 if (objectJson.is_null())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700328 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700329 objectJson = nlohmann::json::object();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700330 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500331 for (const auto& interface : objectPath.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700332 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700333 for (const auto& property : interface.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700334 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700335 nlohmann::json& propertyJson =
336 objectJson[property.first];
337 std::visit(
338 [&propertyJson](auto&& val) {
339 if constexpr (std::is_same_v<
340 std::decay_t<decltype(val)>,
341 sdbusplus::message::unix_fd>)
342 {
343 propertyJson = val.fd;
344 }
345 else
346 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700347 propertyJson = val;
348 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500349 },
Ed Tanous002d39b2022-05-31 08:59:27 -0700350 property.second);
Ed Tanous049a0512018-11-01 13:58:42 -0700351 }
352 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700353 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700354 for (const auto& interface : objectPath.second)
355 {
356 if (interface.first == "org.freedesktop.DBus.ObjectManager")
357 {
358 getManagedObjectsForEnumerate(objectPath.first.str,
359 objectPath.first.str,
360 connectionName, transaction);
361 }
362 }
363 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500364 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700365}
366
Ed Tanous23a21a12020-07-25 04:45:05 +0000367inline void findObjectManagerPathForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000368 const std::string& objectName, const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700369 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700370{
Ed Tanous62598e32023-07-17 17:06:25 -0700371 BMCWEB_LOG_DEBUG("Finding objectmanager for path {} on connection:{}",
372 objectName, connectionName);
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700373 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000374 [transaction, objectName, connectionName](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800375 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800376 const dbus::utility::MapperGetAncestorsResponse& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700377 if (ec)
378 {
Ed Tanous62598e32023-07-17 17:06:25 -0700379 BMCWEB_LOG_ERROR("GetAncestors on path {} failed with code {}",
380 objectName, ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700381 return;
382 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700383
Ed Tanous002d39b2022-05-31 08:59:27 -0700384 for (const auto& pathGroup : objects)
385 {
386 for (const auto& connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700387 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700388 if (connectionGroup.first == connectionName)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700389 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700390 // Found the object manager path for this resource.
391 getManagedObjectsForEnumerate(objectName, pathGroup.first,
392 connectionName, transaction);
393 return;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700394 }
395 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700396 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500397 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700398 "xyz.openbmc_project.ObjectMapper",
399 "/xyz/openbmc_project/object_mapper",
Ed Tanous81ce6092020-12-17 16:54:55 +0000400 "xyz.openbmc_project.ObjectMapper", "GetAncestors", objectName,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500401 std::array<const char*, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700402}
Ed Tanous64530012018-02-06 17:08:16 -0800403
Ed Tanous7c091622019-05-23 11:42:36 -0700404// Uses GetObject to add the object info about the target /enumerate path to
405// the results of GetSubTree, as GetSubTree will not return info for the
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600406// target path, and then continues on enumerating the rest of the tree.
Ed Tanousb5a76932020-09-29 16:16:58 -0700407inline void getObjectAndEnumerate(
408 const std::shared_ptr<InProgressEnumerateData>& transaction)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600409{
George Liu2b731192023-01-11 16:27:13 +0800410 dbus::utility::getDbusObject(
411 transaction->objectPath, {},
412 [transaction](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800413 const dbus::utility::MapperGetObject& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700414 if (ec)
415 {
Ed Tanous62598e32023-07-17 17:06:25 -0700416 BMCWEB_LOG_ERROR("GetObject for path {} failed with code {}",
417 transaction->objectPath, ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700418 return;
419 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600420
Ed Tanous62598e32023-07-17 17:06:25 -0700421 BMCWEB_LOG_DEBUG("GetObject for {} has {} entries",
422 transaction->objectPath, objects.size());
Ed Tanous002d39b2022-05-31 08:59:27 -0700423 if (!objects.empty())
424 {
425 transaction->subtree->emplace_back(transaction->objectPath,
426 objects);
427 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600428
Ed Tanous002d39b2022-05-31 08:59:27 -0700429 // Map indicating connection name, and the path where the object
430 // manager exists
Ed Tanous18f8f602023-07-18 10:07:23 -0700431 boost::container::flat_map<
432 std::string, std::string, std::less<>,
433 std::vector<std::pair<std::string, std::string>>>
434 connections;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600435
Ed Tanous002d39b2022-05-31 08:59:27 -0700436 for (const auto& object : *(transaction->subtree))
437 {
438 for (const auto& connection : object.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600439 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700440 for (const auto& interface : connection.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600441 {
Ed Tanous62598e32023-07-17 17:06:25 -0700442 BMCWEB_LOG_DEBUG("{} has interface {}", connection.first,
443 interface);
Ed Tanous002d39b2022-05-31 08:59:27 -0700444 if (interface == "org.freedesktop.DBus.ObjectManager")
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600445 {
Ed Tanous62598e32023-07-17 17:06:25 -0700446 BMCWEB_LOG_DEBUG("found object manager path {}",
447 object.first);
Ed Tanousf8fe53e2022-06-30 15:55:45 -0700448 connections[connection.first] = object.first;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600449 }
450 }
451 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700452 }
Ed Tanous62598e32023-07-17 17:06:25 -0700453 BMCWEB_LOG_DEBUG("Got {} connections", connections.size());
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600454
Ed Tanous002d39b2022-05-31 08:59:27 -0700455 for (const auto& connection : connections)
456 {
457 // If we already know where the object manager is, we don't
458 // need to search for it, we can call directly in to
459 // getManagedObjects
460 if (!connection.second.empty())
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600461 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700462 getManagedObjectsForEnumerate(transaction->objectPath,
463 connection.second,
464 connection.first, transaction);
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600465 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700466 else
467 {
468 // otherwise we need to find the object manager path
469 // before we can continue
470 findObjectManagerPathForEnumerate(
471 transaction->objectPath, connection.first, transaction);
472 }
473 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500474 });
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600475}
Ed Tanous64530012018-02-06 17:08:16 -0800476
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700477// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700478struct InProgressActionData
479{
Lei YU28dd5ca2023-03-17 13:17:05 +0800480 explicit InProgressActionData(
481 const std::shared_ptr<bmcweb::AsyncResp>& res) :
482 asyncResp(res)
Ed Tanous23a21a12020-07-25 04:45:05 +0000483 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700484 ~InProgressActionData()
485 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600486 // Methods could have been called across different owners
487 // and interfaces, where some calls failed and some passed.
488 //
489 // The rules for this are:
490 // * if no method was called - error
491 // * if a method failed and none passed - error
492 // (converse: if at least one method passed - OK)
493 // * for the method output:
494 // * if output processing didn't fail, return the data
495
496 // Only deal with method returns if nothing failed earlier
Lei YU28dd5ca2023-03-17 13:17:05 +0800497 if (asyncResp->res.result() == boost::beast::http::status::ok)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700498 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600499 if (!methodPassed)
500 {
Matt Spinler06b1b632019-06-18 16:09:25 -0500501 if (!methodFailed)
Matt Spinler16caaee2019-01-15 11:40:34 -0600502 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800503 setErrorResponse(asyncResp->res,
504 boost::beast::http::status::not_found,
Matt Spinler16caaee2019-01-15 11:40:34 -0600505 methodNotFoundDesc, notFoundMsg);
506 }
507 }
508 else
509 {
510 if (outputFailed)
511 {
512 setErrorResponse(
Lei YU28dd5ca2023-03-17 13:17:05 +0800513 asyncResp->res,
514 boost::beast::http::status::internal_server_error,
Matt Spinler16caaee2019-01-15 11:40:34 -0600515 "Method output failure", methodOutputFailedMsg);
516 }
517 else
518 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800519 asyncResp->res.jsonValue["status"] = "ok";
520 asyncResp->res.jsonValue["message"] = "200 OK";
521 asyncResp->res.jsonValue["data"] = methodResponse;
Matt Spinler16caaee2019-01-15 11:40:34 -0600522 }
523 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700524 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700525 }
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800526 InProgressActionData(const InProgressActionData&) = delete;
527 InProgressActionData(InProgressActionData&&) = delete;
528 InProgressActionData& operator=(const InProgressActionData&) = delete;
529 InProgressActionData& operator=(InProgressActionData&&) = delete;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700530
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500531 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700532 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800533 setErrorResponse(asyncResp->res,
534 boost::beast::http::status::bad_request, desc,
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600535 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700536 }
Lei YU28dd5ca2023-03-17 13:17:05 +0800537 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700538 std::string path;
539 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600540 std::string interfaceName;
Matt Spinler16caaee2019-01-15 11:40:34 -0600541 bool methodPassed = false;
542 bool methodFailed = false;
543 bool outputFailed = false;
Matt Spinler39a4e392019-01-15 11:53:13 -0600544 bool convertedToArray = false;
Matt Spinler16caaee2019-01-15 11:40:34 -0600545 nlohmann::json methodResponse;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700546 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700547};
548
Ed Tanous23a21a12020-07-25 04:45:05 +0000549inline std::vector<std::string> dbusArgSplit(const std::string& string)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700550{
551 std::vector<std::string> ret;
552 if (string.empty())
553 {
554 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700555 }
Ed Tanous0f0353b2019-10-24 11:37:51 -0700556 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700557 int containerDepth = 0;
558
559 for (std::string::const_iterator character = string.begin();
560 character != string.end(); character++)
561 {
562 ret.back() += *character;
563 switch (*character)
564 {
565 case ('a'):
566 break;
567 case ('('):
568 case ('{'):
569 containerDepth++;
570 break;
571 case ('}'):
572 case (')'):
573 containerDepth--;
574 if (containerDepth == 0)
575 {
576 if (character + 1 != string.end())
577 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700578 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700579 }
580 }
581 break;
582 default:
583 if (containerDepth == 0)
584 {
585 if (character + 1 != string.end())
586 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700587 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700588 }
589 }
590 break;
591 }
592 }
Matt Spinler4ae611d2019-01-11 15:37:06 -0600593
594 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700595}
596
Ed Tanous81ce6092020-12-17 16:54:55 +0000597inline int convertJsonToDbus(sd_bus_message* m, const std::string& argType,
598 const nlohmann::json& inputJson)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700599{
600 int r = 0;
Ed Tanous296579b2024-03-11 16:58:24 -0700601 BMCWEB_LOG_DEBUG("Converting {} to type: {}", inputJson, argType);
Ed Tanous81ce6092020-12-17 16:54:55 +0000602 const std::vector<std::string> argTypes = dbusArgSplit(argType);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700603
Ed Tanous1abe55e2018-09-05 08:30:59 -0700604 // Assume a single object for now.
Ed Tanous81ce6092020-12-17 16:54:55 +0000605 const nlohmann::json* j = &inputJson;
606 nlohmann::json::const_iterator jIt = inputJson.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700607
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500608 for (const std::string& argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700609 {
610 // If we are decoding multiple objects, grab the pointer to the
611 // iterator, and increment it for the next loop
612 if (argTypes.size() > 1)
613 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000614 if (jIt == inputJson.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700615 {
616 return -2;
617 }
618 j = &*jIt;
619 jIt++;
620 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500621 const int64_t* intValue = j->get_ptr<const int64_t*>();
622 const std::string* stringValue = j->get_ptr<const std::string*>();
623 const double* doubleValue = j->get_ptr<const double*>();
624 const bool* b = j->get_ptr<const bool*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700625 int64_t v = 0;
626 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700627
Ed Tanous1abe55e2018-09-05 08:30:59 -0700628 // Do some basic type conversions that make sense. uint can be
629 // converted to int. int and uint can be converted to double
Ed Tanous66664f22019-10-11 13:05:49 -0700630 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700631 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500632 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700633 if (uintValue != nullptr)
634 {
635 v = static_cast<int64_t>(*uintValue);
636 intValue = &v;
637 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700638 }
Ed Tanous66664f22019-10-11 13:05:49 -0700639 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700640 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500641 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700642 if (uintValue != nullptr)
643 {
644 d = static_cast<double>(*uintValue);
645 doubleValue = &d;
646 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700647 }
Ed Tanous66664f22019-10-11 13:05:49 -0700648 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700649 {
Ed Tanous66664f22019-10-11 13:05:49 -0700650 if (intValue != nullptr)
651 {
652 d = static_cast<double>(*intValue);
653 doubleValue = &d;
654 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700655 }
656
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700657 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700658 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700659 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700660 {
661 return -1;
662 }
Ed Tanous271584a2019-07-09 16:24:22 -0700663 r = sd_bus_message_append_basic(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500664 m, argCode[0], static_cast<const void*>(stringValue->data()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700665 if (r < 0)
666 {
667 return r;
668 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700669 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700670 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700671 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700672 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700673 {
674 return -1;
675 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500676 if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
677 (*intValue > std::numeric_limits<int32_t>::max()))
678 {
679 return -ERANGE;
680 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700681 int32_t i = static_cast<int32_t>(*intValue);
682 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700683 if (r < 0)
684 {
685 return r;
686 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700687 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700688 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700689 {
690 // lots of ways bool could be represented here. Try them all
Ed Tanouse662eae2022-01-25 10:39:19 -0800691 int boolInt = 0;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700692 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700693 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500694 if (*intValue == 1)
695 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800696 boolInt = 1;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500697 }
698 else if (*intValue == 0)
699 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800700 boolInt = 0;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500701 }
702 else
703 {
704 return -ERANGE;
705 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700706 }
707 else if (b != nullptr)
708 {
Matt Spinlera2f02632019-01-18 10:15:35 -0600709 boolInt = *b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700710 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700711 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700712 {
Ed Tanous18f8f602023-07-18 10:07:23 -0700713 if (!stringValue->empty())
714 {
715 if (stringValue->front() == 't' ||
716 stringValue->front() == 'T')
717 {
718 boolInt = 1;
719 }
720 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700721 }
722 else
723 {
724 return -1;
725 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700726 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700727 if (r < 0)
728 {
729 return r;
730 }
731 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700732 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700733 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700734 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700735 {
736 return -1;
737 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500738 if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
739 (*intValue > std::numeric_limits<int16_t>::max()))
740 {
741 return -ERANGE;
742 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700743 int16_t n = static_cast<int16_t>(*intValue);
744 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700745 if (r < 0)
746 {
747 return r;
748 }
749 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700750 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700751 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700752 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700753 {
754 return -1;
755 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700756 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700757 if (r < 0)
758 {
759 return r;
760 }
761 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700762 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700763 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500764 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700765 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700766 {
767 return -1;
768 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000769 if (*uintValue > std::numeric_limits<uint8_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500770 {
771 return -ERANGE;
772 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700773 uint8_t y = static_cast<uint8_t>(*uintValue);
774 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700775 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700776 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700777 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500778 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700779 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700780 {
781 return -1;
782 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000783 if (*uintValue > std::numeric_limits<uint16_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500784 {
785 return -ERANGE;
786 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700787 uint16_t q = static_cast<uint16_t>(*uintValue);
788 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700789 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700790 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700791 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500792 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700793 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700794 {
795 return -1;
796 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000797 if (*uintValue > std::numeric_limits<uint32_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500798 {
799 return -ERANGE;
800 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700801 uint32_t u = static_cast<uint32_t>(*uintValue);
802 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700803 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700804 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700805 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500806 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700807 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700808 {
809 return -1;
810 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700811 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700812 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700813 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700814 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500815 if (doubleValue == nullptr)
816 {
817 return -1;
818 }
819 if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
820 (*doubleValue > std::numeric_limits<double>::max()))
821 {
822 return -ERANGE;
823 }
Ed Tanous07900812024-05-06 15:41:30 -0700824 r = sd_bus_message_append_basic(m, argCode[0], doubleValue);
825 if (r < 0)
826 {
827 return r;
828 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700829 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700830 else if (argCode.starts_with("a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700831 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700832 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700833 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700834 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700835 if (r < 0)
836 {
837 return r;
838 }
839
Ed Tanous0dfeda62019-10-24 11:21:38 -0700840 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700841 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700842 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700843 if (r < 0)
844 {
845 return r;
846 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700847 }
848 sd_bus_message_close_container(m);
849 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700850 else if (argCode.starts_with("v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700851 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700852 std::string containedType = argCode.substr(1);
Ed Tanous62598e32023-07-17 17:06:25 -0700853 BMCWEB_LOG_DEBUG("variant type: {} appending variant of type: {}",
854 argCode, containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700855 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700856 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700857 if (r < 0)
858 {
859 return r;
860 }
861
Ed Tanous81ce6092020-12-17 16:54:55 +0000862 r = convertJsonToDbus(m, containedType, inputJson);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700863 if (r < 0)
864 {
865 return r;
866 }
867
868 r = sd_bus_message_close_container(m);
869 if (r < 0)
870 {
871 return r;
872 }
873 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700874 else if (argCode.starts_with("(") && argCode.ends_with(")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700875 {
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300876 std::string containedType = argCode.substr(1, argCode.size() - 2);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700877 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700878 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800879 if (r < 0)
880 {
881 return r;
882 }
883
Ed Tanous1abe55e2018-09-05 08:30:59 -0700884 nlohmann::json::const_iterator it = j->begin();
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300885 for (const std::string& argCode2 : dbusArgSplit(containedType))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700886 {
887 if (it == j->end())
888 {
889 return -1;
890 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000891 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700892 if (r < 0)
893 {
894 return r;
895 }
896 it++;
897 }
898 r = sd_bus_message_close_container(m);
899 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700900 else if (argCode.starts_with("{") && argCode.ends_with("}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700901 {
Mikhail Zhvakinf3477562023-07-25 17:03:32 +0300902 std::string containedType = argCode.substr(1, argCode.size() - 2);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700903 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700904 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800905 if (r < 0)
906 {
907 return r;
908 }
909
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700910 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700911 if (codes.size() != 2)
912 {
913 return -1;
914 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700915 const std::string& keyType = codes[0];
916 const std::string& valueType = codes[1];
Ed Tanous3174e4d2020-10-07 11:41:22 -0700917 for (const auto& it : j->items())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700918 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700919 r = convertJsonToDbus(m, keyType, it.key());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700920 if (r < 0)
921 {
922 return r;
923 }
924
Ed Tanous2c70f802020-09-28 14:29:23 -0700925 r = convertJsonToDbus(m, valueType, it.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700926 if (r < 0)
927 {
928 return r;
929 }
930 }
931 r = sd_bus_message_close_container(m);
932 }
933 else
934 {
935 return -2;
936 }
937 if (r < 0)
938 {
939 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700940 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700941
Ed Tanous1abe55e2018-09-05 08:30:59 -0700942 if (argTypes.size() > 1)
943 {
944 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700945 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700946 }
Matt Spinler127ea542019-01-14 11:04:28 -0600947
948 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700949}
950
Matt Spinlerd22a7132019-01-14 12:14:30 -0600951template <typename T>
Patrick Williams59d494e2022-07-22 19:26:55 -0500952int readMessageItem(const std::string& typeCode, sdbusplus::message_t& m,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500953 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600954{
955 T value;
Ed Tanousf79ce6a2024-03-20 12:27:06 -0700956 // When T == char*, this warning fires. Unclear how to resolve
957 // Given that sd-bus takes a void pointer to a char*, and that's
958 // Not something we can fix.
959 // NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600960 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
961 if (r < 0)
962 {
Ed Tanous62598e32023-07-17 17:06:25 -0700963 BMCWEB_LOG_ERROR("sd_bus_message_read_basic on type {} failed!",
964 typeCode);
Matt Spinlerd22a7132019-01-14 12:14:30 -0600965 return r;
966 }
967
968 data = value;
969 return 0;
970}
971
Patrick Williams59d494e2022-07-22 19:26:55 -0500972int convertDBusToJSON(const std::string& returnType, sdbusplus::message_t& m,
973 nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600974
Ed Tanous23a21a12020-07-25 04:45:05 +0000975inline int readDictEntryFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -0500976 sdbusplus::message_t& m,
Ed Tanous23a21a12020-07-25 04:45:05 +0000977 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600978{
979 std::vector<std::string> types = dbusArgSplit(typeCode);
980 if (types.size() != 2)
981 {
Ed Tanous62598e32023-07-17 17:06:25 -0700982 BMCWEB_LOG_ERROR("wrong number contained types in dictionary: {}",
983 types.size());
Matt Spinler6df8f992019-01-14 12:47:47 -0600984 return -1;
985 }
986
987 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
988 typeCode.c_str());
989 if (r < 0)
990 {
Ed Tanous62598e32023-07-17 17:06:25 -0700991 BMCWEB_LOG_ERROR("sd_bus_message_enter_container with rc {}", r);
Matt Spinler6df8f992019-01-14 12:47:47 -0600992 return r;
993 }
994
995 nlohmann::json key;
996 r = convertDBusToJSON(types[0], m, key);
997 if (r < 0)
998 {
999 return r;
1000 }
1001
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001002 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -06001003 if (keyPtr == nullptr)
1004 {
1005 // json doesn't support non-string keys. If we hit this condition,
1006 // convert the result to a string so we can proceed
Ed Tanous71f52d92021-02-19 08:51:17 -08001007 key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001008 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -07001009 // in theory this can't fail now, but lets be paranoid about it
1010 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -06001011 if (keyPtr == nullptr)
1012 {
1013 return -1;
1014 }
1015 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001016 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -06001017
1018 r = convertDBusToJSON(types[1], m, value);
1019 if (r < 0)
1020 {
1021 return r;
1022 }
1023
1024 r = sd_bus_message_exit_container(m.get());
1025 if (r < 0)
1026 {
Ed Tanous62598e32023-07-17 17:06:25 -07001027 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001028 return r;
1029 }
1030
1031 return 0;
1032}
1033
Ed Tanous23a21a12020-07-25 04:45:05 +00001034inline int readArrayFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001035 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -06001036{
1037 if (typeCode.size() < 2)
1038 {
Ed Tanous62598e32023-07-17 17:06:25 -07001039 BMCWEB_LOG_ERROR("Type code {} too small for an array", typeCode);
Matt Spinler6df8f992019-01-14 12:47:47 -06001040 return -1;
1041 }
1042
1043 std::string containedType = typeCode.substr(1);
1044
1045 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
1046 containedType.c_str());
1047 if (r < 0)
1048 {
Ed Tanous62598e32023-07-17 17:06:25 -07001049 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler6df8f992019-01-14 12:47:47 -06001050 return r;
1051 }
1052
Ed Tanous11ba3972022-07-11 09:50:41 -07001053 bool dict = containedType.starts_with("{") && containedType.ends_with("}");
Matt Spinler6df8f992019-01-14 12:47:47 -06001054
1055 if (dict)
1056 {
1057 // Remove the { }
1058 containedType = containedType.substr(1, containedType.size() - 2);
1059 data = nlohmann::json::object();
1060 }
1061 else
1062 {
1063 data = nlohmann::json::array();
1064 }
1065
1066 while (true)
1067 {
Ed Tanouse662eae2022-01-25 10:39:19 -08001068 r = sd_bus_message_at_end(m.get(), 0);
Matt Spinler6df8f992019-01-14 12:47:47 -06001069 if (r < 0)
1070 {
Ed Tanous62598e32023-07-17 17:06:25 -07001071 BMCWEB_LOG_ERROR("sd_bus_message_at_end failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001072 return r;
1073 }
1074
1075 if (r > 0)
1076 {
1077 break;
1078 }
1079
1080 // Dictionaries are only ever seen in an array
1081 if (dict)
1082 {
1083 r = readDictEntryFromMessage(containedType, m, data);
1084 if (r < 0)
1085 {
1086 return r;
1087 }
1088 }
1089 else
1090 {
1091 data.push_back(nlohmann::json());
1092
1093 r = convertDBusToJSON(containedType, m, data.back());
1094 if (r < 0)
1095 {
1096 return r;
1097 }
1098 }
1099 }
1100
1101 r = sd_bus_message_exit_container(m.get());
1102 if (r < 0)
1103 {
Ed Tanous62598e32023-07-17 17:06:25 -07001104 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001105 return r;
1106 }
1107
1108 return 0;
1109}
1110
Ed Tanous23a21a12020-07-25 04:45:05 +00001111inline int readStructFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001112 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001113{
1114 if (typeCode.size() < 3)
1115 {
Ed Tanous62598e32023-07-17 17:06:25 -07001116 BMCWEB_LOG_ERROR("Type code {} too small for a struct", typeCode);
Matt Spinler75c6c672019-01-14 13:01:46 -06001117 return -1;
1118 }
1119
1120 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1121 std::vector<std::string> types = dbusArgSplit(containedTypes);
1122
1123 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1124 containedTypes.c_str());
1125 if (r < 0)
1126 {
Ed Tanous62598e32023-07-17 17:06:25 -07001127 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler75c6c672019-01-14 13:01:46 -06001128 return r;
1129 }
1130
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001131 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001132 {
1133 data.push_back(nlohmann::json());
1134 r = convertDBusToJSON(type, m, data.back());
1135 if (r < 0)
1136 {
1137 return r;
1138 }
1139 }
1140
1141 r = sd_bus_message_exit_container(m.get());
1142 if (r < 0)
1143 {
Ed Tanous62598e32023-07-17 17:06:25 -07001144 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler75c6c672019-01-14 13:01:46 -06001145 return r;
1146 }
1147 return 0;
1148}
1149
Patrick Williams59d494e2022-07-22 19:26:55 -05001150inline int readVariantFromMessage(sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001151{
Ed Tanous543f4402022-01-06 13:12:53 -08001152 const char* containerType = nullptr;
Ed Tanous99131cd2019-10-24 11:12:47 -07001153 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001154 if (r < 0)
1155 {
Ed Tanous62598e32023-07-17 17:06:25 -07001156 BMCWEB_LOG_ERROR("sd_bus_message_peek_type failed");
Matt Spinler89c19702019-01-14 13:13:00 -06001157 return r;
1158 }
1159
1160 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1161 containerType);
1162 if (r < 0)
1163 {
Ed Tanous62598e32023-07-17 17:06:25 -07001164 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler89c19702019-01-14 13:13:00 -06001165 return r;
1166 }
1167
1168 r = convertDBusToJSON(containerType, m, data);
1169 if (r < 0)
1170 {
1171 return r;
1172 }
1173
1174 r = sd_bus_message_exit_container(m.get());
1175 if (r < 0)
1176 {
Ed Tanous62598e32023-07-17 17:06:25 -07001177 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed");
Matt Spinler89c19702019-01-14 13:13:00 -06001178 return r;
1179 }
1180
1181 return 0;
1182}
1183
Ed Tanous23a21a12020-07-25 04:45:05 +00001184inline int convertDBusToJSON(const std::string& returnType,
Patrick Williams59d494e2022-07-22 19:26:55 -05001185 sdbusplus::message_t& m, nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001186{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001187 int r = 0;
1188 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1189
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001190 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001191 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001192 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001193 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001194 {
1195 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001196 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001197 }
1198
Ed Tanousd4d25792020-09-29 15:15:03 -07001199 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001200 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001201 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001202 if (r < 0)
1203 {
1204 return r;
1205 }
1206 }
1207 else if (typeCode == "b")
1208 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001209 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001210 if (r < 0)
1211 {
1212 return r;
1213 }
1214
Matt Spinlerf39420c2019-01-30 12:57:18 -06001215 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001216 }
1217 else if (typeCode == "u")
1218 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001219 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001220 if (r < 0)
1221 {
1222 return r;
1223 }
1224 }
1225 else if (typeCode == "i")
1226 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001227 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001228 if (r < 0)
1229 {
1230 return r;
1231 }
1232 }
1233 else if (typeCode == "x")
1234 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001235 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001236 if (r < 0)
1237 {
1238 return r;
1239 }
1240 }
1241 else if (typeCode == "t")
1242 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001243 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001244 if (r < 0)
1245 {
1246 return r;
1247 }
1248 }
1249 else if (typeCode == "n")
1250 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001251 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001252 if (r < 0)
1253 {
1254 return r;
1255 }
1256 }
1257 else if (typeCode == "q")
1258 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001259 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001260 if (r < 0)
1261 {
1262 return r;
1263 }
1264 }
1265 else if (typeCode == "y")
1266 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001267 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001268 if (r < 0)
1269 {
1270 return r;
1271 }
1272 }
1273 else if (typeCode == "d")
1274 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001275 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001276 if (r < 0)
1277 {
1278 return r;
1279 }
1280 }
1281 else if (typeCode == "h")
1282 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001283 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001284 if (r < 0)
1285 {
1286 return r;
1287 }
1288 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001289 else if (typeCode.starts_with("a"))
Matt Spinler6df8f992019-01-14 12:47:47 -06001290 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001291 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001292 if (r < 0)
1293 {
1294 return r;
1295 }
1296 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001297 else if (typeCode.starts_with("(") && typeCode.ends_with(")"))
Matt Spinler75c6c672019-01-14 13:01:46 -06001298 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001299 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001300 if (r < 0)
1301 {
1302 return r;
1303 }
1304 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001305 else if (typeCode.starts_with("v"))
Matt Spinler89c19702019-01-14 13:13:00 -06001306 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001307 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001308 if (r < 0)
1309 {
1310 return r;
1311 }
1312 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001313 else
1314 {
Ed Tanous62598e32023-07-17 17:06:25 -07001315 BMCWEB_LOG_ERROR("Invalid D-Bus signature type {}", typeCode);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001316 return -2;
1317 }
1318 }
1319
Matt Spinler16caaee2019-01-15 11:40:34 -06001320 return 0;
1321}
1322
Ed Tanousb5a76932020-09-29 16:16:58 -07001323inline void handleMethodResponse(
1324 const std::shared_ptr<InProgressActionData>& transaction,
Patrick Williams59d494e2022-07-22 19:26:55 -05001325 sdbusplus::message_t& m, const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001326{
Matt Spinler39a4e392019-01-15 11:53:13 -06001327 nlohmann::json data;
1328
1329 int r = convertDBusToJSON(returnType, m, data);
1330 if (r < 0)
1331 {
1332 transaction->outputFailed = true;
1333 return;
1334 }
1335
1336 if (data.is_null())
1337 {
1338 return;
1339 }
1340
1341 if (transaction->methodResponse.is_null())
1342 {
1343 transaction->methodResponse = std::move(data);
1344 return;
1345 }
1346
1347 // If they're both dictionaries or arrays, merge into one.
1348 // Otherwise, make the results an array with every result
1349 // an entry. Could also just fail in that case, but it
1350 // seems better to get the data back somehow.
1351
1352 if (transaction->methodResponse.is_object() && data.is_object())
1353 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001354 for (const auto& obj : data.items())
Matt Spinler39a4e392019-01-15 11:53:13 -06001355 {
1356 // Note: Will overwrite the data for a duplicate key
1357 transaction->methodResponse.emplace(obj.key(),
1358 std::move(obj.value()));
1359 }
1360 return;
1361 }
1362
1363 if (transaction->methodResponse.is_array() && data.is_array())
1364 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001365 for (auto& obj : data)
Matt Spinler39a4e392019-01-15 11:53:13 -06001366 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001367 transaction->methodResponse.emplace_back(std::move(obj));
Matt Spinler39a4e392019-01-15 11:53:13 -06001368 }
1369 return;
1370 }
1371
1372 if (!transaction->convertedToArray)
1373 {
1374 // They are different types. May as well turn them into an array
1375 nlohmann::json j = std::move(transaction->methodResponse);
1376 transaction->methodResponse = nlohmann::json::array();
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001377 transaction->methodResponse.emplace_back(std::move(j));
1378 transaction->methodResponse.emplace_back(std::move(data));
Matt Spinler39a4e392019-01-15 11:53:13 -06001379 transaction->convertedToArray = true;
1380 }
1381 else
1382 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001383 transaction->methodResponse.emplace_back(std::move(data));
Matt Spinler39a4e392019-01-15 11:53:13 -06001384 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001385}
1386
Ed Tanousb5a76932020-09-29 16:16:58 -07001387inline void findActionOnInterface(
1388 const std::shared_ptr<InProgressActionData>& transaction,
1389 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001390{
Ed Tanous62598e32023-07-17 17:06:25 -07001391 BMCWEB_LOG_DEBUG("findActionOnInterface for connection {}", connectionName);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001392 crow::connections::systemBus->async_method_call(
1393 [transaction, connectionName{std::string(connectionName)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001394 const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001395 const std::string& introspectXml) {
Ed Tanous62598e32023-07-17 17:06:25 -07001396 BMCWEB_LOG_DEBUG("got xml:\n {}", introspectXml);
Ed Tanous002d39b2022-05-31 08:59:27 -07001397 if (ec)
1398 {
Ed Tanous62598e32023-07-17 17:06:25 -07001399 BMCWEB_LOG_ERROR(
1400 "Introspect call failed with error: {} on process: {}",
1401 ec.message(), connectionName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001402 return;
1403 }
1404 tinyxml2::XMLDocument doc;
Matt Spinler318bd892019-01-15 09:59:20 -06001405
Ed Tanous002d39b2022-05-31 08:59:27 -07001406 doc.Parse(introspectXml.data(), introspectXml.size());
1407 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1408 if (pRoot == nullptr)
1409 {
Ed Tanous62598e32023-07-17 17:06:25 -07001410 BMCWEB_LOG_ERROR("XML document failed to parse {}", connectionName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001411 return;
1412 }
1413 tinyxml2::XMLElement* interfaceNode =
1414 pRoot->FirstChildElement("interface");
1415 while (interfaceNode != nullptr)
1416 {
1417 const char* thisInterfaceName = interfaceNode->Attribute("name");
1418 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001419 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001420 if (!transaction->interfaceName.empty() &&
1421 (transaction->interfaceName != thisInterfaceName))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001422 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001423 interfaceNode =
1424 interfaceNode->NextSiblingElement("interface");
1425 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001426 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001427
1428 tinyxml2::XMLElement* methodNode =
1429 interfaceNode->FirstChildElement("method");
1430 while (methodNode != nullptr)
1431 {
1432 const char* thisMethodName = methodNode->Attribute("name");
Ed Tanous62598e32023-07-17 17:06:25 -07001433 BMCWEB_LOG_DEBUG("Found method: {}", thisMethodName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001434 if (thisMethodName != nullptr &&
1435 thisMethodName == transaction->methodName)
1436 {
Ed Tanous62598e32023-07-17 17:06:25 -07001437 BMCWEB_LOG_DEBUG(
1438 "Found method named {} on interface {}",
1439 thisMethodName, thisInterfaceName);
Patrick Williams59d494e2022-07-22 19:26:55 -05001440 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001441 crow::connections::systemBus->new_method_call(
1442 connectionName.c_str(),
1443 transaction->path.c_str(), thisInterfaceName,
1444 transaction->methodName.c_str());
1445
1446 tinyxml2::XMLElement* argumentNode =
1447 methodNode->FirstChildElement("arg");
1448
1449 std::string returnType;
1450
1451 // Find the output type
1452 while (argumentNode != nullptr)
1453 {
1454 const char* argDirection =
1455 argumentNode->Attribute("direction");
1456 const char* argType =
1457 argumentNode->Attribute("type");
1458 if (argDirection != nullptr && argType != nullptr &&
1459 std::string(argDirection) == "out")
1460 {
1461 returnType = argType;
1462 break;
1463 }
1464 argumentNode =
1465 argumentNode->NextSiblingElement("arg");
1466 }
1467
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001468 auto argIt = transaction->arguments.begin();
Ed Tanous002d39b2022-05-31 08:59:27 -07001469
1470 argumentNode = methodNode->FirstChildElement("arg");
1471
1472 while (argumentNode != nullptr)
1473 {
1474 const char* argDirection =
1475 argumentNode->Attribute("direction");
1476 const char* argType =
1477 argumentNode->Attribute("type");
1478 if (argDirection != nullptr && argType != nullptr &&
1479 std::string(argDirection) == "in")
1480 {
1481 if (argIt == transaction->arguments.end())
1482 {
1483 transaction->setErrorStatus(
1484 "Invalid method args");
1485 return;
1486 }
1487 if (convertJsonToDbus(m.get(),
1488 std::string(argType),
1489 *argIt) < 0)
1490 {
1491 transaction->setErrorStatus(
1492 "Invalid method arg type");
1493 return;
1494 }
1495
1496 argIt++;
1497 }
1498 argumentNode =
1499 argumentNode->NextSiblingElement("arg");
1500 }
1501
1502 crow::connections::systemBus->async_send(
Patrick Williams5a39f772023-10-20 11:20:21 -05001503 m, [transaction, returnType](
1504 const boost::system::error_code& ec2,
1505 sdbusplus::message_t& m2) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001506 if (ec2)
1507 {
1508 transaction->methodFailed = true;
1509 const sd_bus_error* e = m2.get_error();
1510
1511 if (e != nullptr)
1512 {
1513 setErrorResponse(
Lei YU28dd5ca2023-03-17 13:17:05 +08001514 transaction->asyncResp->res,
Ed Tanous002d39b2022-05-31 08:59:27 -07001515 boost::beast::http::status::bad_request,
1516 e->name, e->message);
1517 }
1518 else
1519 {
1520 setErrorResponse(
Lei YU28dd5ca2023-03-17 13:17:05 +08001521 transaction->asyncResp->res,
Ed Tanous002d39b2022-05-31 08:59:27 -07001522 boost::beast::http::status::bad_request,
1523 "Method call failed", methodFailedMsg);
1524 }
1525 return;
1526 }
1527 transaction->methodPassed = true;
1528
1529 handleMethodResponse(transaction, m2, returnType);
Patrick Williams5a39f772023-10-20 11:20:21 -05001530 });
Ed Tanous002d39b2022-05-31 08:59:27 -07001531 break;
1532 }
1533 methodNode = methodNode->NextSiblingElement("method");
1534 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001535 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001536 interfaceNode = interfaceNode->NextSiblingElement("interface");
1537 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001538 },
Ed Tanous1abe55e2018-09-05 08:30:59 -07001539 connectionName, transaction->path,
1540 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001541}
1542
zhanghch058d1b46d2021-04-01 11:18:24 +08001543inline void handleAction(const crow::Request& req,
1544 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001545 const std::string& objectPath,
1546 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001547{
Ed Tanous62598e32023-07-17 17:06:25 -07001548 BMCWEB_LOG_DEBUG("handleAction on path: {} and method {}", objectPath,
1549 methodName);
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001550 nlohmann::json requestDbusData;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001551
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001552 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
1553 if (ret == JsonParseResult::BadContentType)
1554 {
1555 setErrorResponse(asyncResp->res,
1556 boost::beast::http::status::unsupported_media_type,
1557 invalidContentType, unsupportedMediaMsg);
1558 return;
1559 }
1560 if (ret != JsonParseResult::Success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001561 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001562 setErrorResponse(asyncResp->res,
1563 boost::beast::http::status::bad_request, noJsonDesc,
1564 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001565 return;
1566 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001567 nlohmann::json::iterator data = requestDbusData.find("data");
1568 if (data == requestDbusData.end())
1569 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001570 setErrorResponse(asyncResp->res,
1571 boost::beast::http::status::bad_request, noJsonDesc,
1572 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001573 return;
1574 }
1575
1576 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001577 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001578 setErrorResponse(asyncResp->res,
1579 boost::beast::http::status::bad_request, noJsonDesc,
1580 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001581 return;
1582 }
Lei YU28dd5ca2023-03-17 13:17:05 +08001583 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001584
1585 transaction->path = objectPath;
1586 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001587 transaction->arguments = std::move(*data);
George Liu2b731192023-01-11 16:27:13 +08001588 dbus::utility::getDbusObject(
1589 objectPath, {},
Ed Tanous1abe55e2018-09-05 08:30:59 -07001590 [transaction](
George Liu2b731192023-01-11 16:27:13 +08001591 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001592 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1593 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001594 if (ec || interfaceNames.empty())
1595 {
Ed Tanous62598e32023-07-17 17:06:25 -07001596 BMCWEB_LOG_ERROR("Can't find object");
Lei YU28dd5ca2023-03-17 13:17:05 +08001597 setErrorResponse(transaction->asyncResp->res,
Ed Tanous002d39b2022-05-31 08:59:27 -07001598 boost::beast::http::status::not_found,
1599 notFoundDesc, notFoundMsg);
1600 return;
1601 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001602
Ed Tanous62598e32023-07-17 17:06:25 -07001603 BMCWEB_LOG_DEBUG("GetObject returned {} object(s)",
1604 interfaceNames.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001605
Ed Tanous002d39b2022-05-31 08:59:27 -07001606 for (const std::pair<std::string, std::vector<std::string>>& object :
1607 interfaceNames)
1608 {
1609 findActionOnInterface(transaction, object.first);
1610 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001611 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001612}
1613
zhanghch058d1b46d2021-04-01 11:18:24 +08001614inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1615 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001616{
Ed Tanous62598e32023-07-17 17:06:25 -07001617 BMCWEB_LOG_DEBUG("handleDelete on path: {}", objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06001618
George Liu2b731192023-01-11 16:27:13 +08001619 dbus::utility::getDbusObject(
1620 objectPath, {},
zhanghch058d1b46d2021-04-01 11:18:24 +08001621 [asyncResp, objectPath](
George Liu2b731192023-01-11 16:27:13 +08001622 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001623 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1624 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001625 if (ec || interfaceNames.empty())
1626 {
Ed Tanous62598e32023-07-17 17:06:25 -07001627 BMCWEB_LOG_ERROR("Can't find object");
Ed Tanous002d39b2022-05-31 08:59:27 -07001628 setErrorResponse(asyncResp->res,
1629 boost::beast::http::status::method_not_allowed,
1630 methodNotAllowedDesc, methodNotAllowedMsg);
1631 return;
1632 }
Matt Spinlerde818812018-12-11 16:39:20 -06001633
Lei YU28dd5ca2023-03-17 13:17:05 +08001634 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001635 transaction->path = objectPath;
1636 transaction->methodName = "Delete";
1637 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
Matt Spinlerde818812018-12-11 16:39:20 -06001638
Ed Tanous002d39b2022-05-31 08:59:27 -07001639 for (const std::pair<std::string, std::vector<std::string>>& object :
1640 interfaceNames)
1641 {
1642 findActionOnInterface(transaction, object.first);
1643 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001644 });
Matt Spinlerde818812018-12-11 16:39:20 -06001645}
1646
zhanghch058d1b46d2021-04-01 11:18:24 +08001647inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1648 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001649{
George Liu7a1dbc42022-12-07 16:03:22 +08001650 dbus::utility::getSubTreePaths(
1651 objectPath, depth, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001652 [asyncResp](
George Liu7a1dbc42022-12-07 16:03:22 +08001653 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001654 const dbus::utility::MapperGetSubTreePathsResponse& objectPaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001655 if (ec)
1656 {
1657 setErrorResponse(asyncResp->res,
1658 boost::beast::http::status::not_found,
1659 notFoundDesc, notFoundMsg);
1660 }
1661 else
1662 {
1663 asyncResp->res.jsonValue["status"] = "ok";
1664 asyncResp->res.jsonValue["message"] = "200 OK";
1665 asyncResp->res.jsonValue["data"] = objectPaths;
1666 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001667 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001668}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001669
zhanghch058d1b46d2021-04-01 11:18:24 +08001670inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1671 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001672{
Ed Tanous62598e32023-07-17 17:06:25 -07001673 BMCWEB_LOG_DEBUG("Doing enumerate on {}", objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07001674
Ed Tanous14766872022-03-15 10:44:42 -07001675 asyncResp->res.jsonValue["message"] = "200 OK";
1676 asyncResp->res.jsonValue["status"] = "ok";
1677 asyncResp->res.jsonValue["data"] = nlohmann::json::object();
Ed Tanous049a0512018-11-01 13:58:42 -07001678
George Liue99073f2022-12-09 11:06:16 +08001679 dbus::utility::getSubTree(
1680 objectPath, 0, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001681 [objectPath, asyncResp](
George Liue99073f2022-12-09 11:06:16 +08001682 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001683 const dbus::utility::MapperGetSubTreeResponse& objectNames) {
Patrick Williams89492a12023-05-10 07:51:34 -05001684 auto transaction = std::make_shared<InProgressEnumerateData>(objectPath,
1685 asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001686
Ed Tanous002d39b2022-05-31 08:59:27 -07001687 transaction->subtree =
1688 std::make_shared<dbus::utility::MapperGetSubTreeResponse>(
1689 objectNames);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001690
Ed Tanous002d39b2022-05-31 08:59:27 -07001691 if (ec)
1692 {
Ed Tanous62598e32023-07-17 17:06:25 -07001693 BMCWEB_LOG_ERROR("GetSubTree failed on {}",
1694 transaction->objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07001695 setErrorResponse(transaction->asyncResp->res,
1696 boost::beast::http::status::not_found,
1697 notFoundDesc, notFoundMsg);
1698 return;
1699 }
Ed Tanous64530012018-02-06 17:08:16 -08001700
Ed Tanous002d39b2022-05-31 08:59:27 -07001701 // Add the data for the path passed in to the results
1702 // as if GetSubTree returned it, and continue on enumerating
1703 getObjectAndEnumerate(transaction);
Patrick Williams5a39f772023-10-20 11:20:21 -05001704 });
Ed Tanous64530012018-02-06 17:08:16 -08001705}
Ed Tanous911ac312017-08-15 09:37:42 -07001706
zhanghch058d1b46d2021-04-01 11:18:24 +08001707inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1708 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001709{
Ed Tanous62598e32023-07-17 17:06:25 -07001710 BMCWEB_LOG_DEBUG("handleGet: {} prop:{}", objectPath, destProperty);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001711 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001712 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001713
Ed Tanous1abe55e2018-09-05 08:30:59 -07001714 std::shared_ptr<std::string> path =
1715 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001716
George Liu2b731192023-01-11 16:27:13 +08001717 dbus::utility::getDbusObject(
1718 *path, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001719 [asyncResp, path,
George Liu2b731192023-01-11 16:27:13 +08001720 propertyName](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001721 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001722 if (ec || objectNames.empty())
1723 {
1724 setErrorResponse(asyncResp->res,
1725 boost::beast::http::status::not_found,
1726 notFoundDesc, notFoundMsg);
1727 return;
1728 }
1729 std::shared_ptr<nlohmann::json> response =
1730 std::make_shared<nlohmann::json>(nlohmann::json::object());
1731 // The mapper should never give us an empty interface names
1732 // list, but check anyway
1733 for (const std::pair<std::string, std::vector<std::string>>&
1734 connection : objectNames)
1735 {
1736 const std::vector<std::string>& interfaceNames = connection.second;
1737
1738 if (interfaceNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001739 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001740 setErrorResponse(asyncResp->res,
1741 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001742 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001743 return;
1744 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001745
1746 for (const std::string& interface : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001747 {
Patrick Williams59d494e2022-07-22 19:26:55 -05001748 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001749 crow::connections::systemBus->new_method_call(
1750 connection.first.c_str(), path->c_str(),
1751 "org.freedesktop.DBus.Properties", "GetAll");
1752 m.append(interface);
1753 crow::connections::systemBus->async_send(
1754 m, [asyncResp, response,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001755 propertyName](const boost::system::error_code& ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05001756 sdbusplus::message_t& msg) {
Patrick Williams5a39f772023-10-20 11:20:21 -05001757 if (ec2)
1758 {
1759 BMCWEB_LOG_ERROR("Bad dbus request error: {}", ec2);
1760 }
1761 else
1762 {
1763 nlohmann::json properties;
1764 int r = convertDBusToJSON("a{sv}", msg, properties);
1765 if (r < 0)
Ed Tanous002d39b2022-05-31 08:59:27 -07001766 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001767 BMCWEB_LOG_ERROR("convertDBusToJSON failed");
Ed Tanous002d39b2022-05-31 08:59:27 -07001768 }
1769 else
1770 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001771 for (const auto& prop : properties.items())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001772 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001773 // if property name is empty, or
1774 // matches our search query, add it
1775 // to the response json
Ed Tanous1abe55e2018-09-05 08:30:59 -07001776
Patrick Williams5a39f772023-10-20 11:20:21 -05001777 if (propertyName->empty())
1778 {
1779 (*response)[prop.key()] =
1780 std::move(prop.value());
1781 }
1782 else if (prop.key() == *propertyName)
1783 {
1784 *response = std::move(prop.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001785 }
1786 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001787 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001788 }
1789 if (response.use_count() == 1)
1790 {
1791 if (!propertyName->empty() && response->empty())
Ed Tanous002d39b2022-05-31 08:59:27 -07001792 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001793 setErrorResponse(
1794 asyncResp->res,
1795 boost::beast::http::status::not_found,
1796 propNotFoundDesc, notFoundMsg);
Ed Tanous002d39b2022-05-31 08:59:27 -07001797 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001798 else
1799 {
1800 asyncResp->res.jsonValue["status"] = "ok";
1801 asyncResp->res.jsonValue["message"] = "200 OK";
1802 asyncResp->res.jsonValue["data"] = *response;
1803 }
1804 }
1805 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001806 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001807 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001808 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001809}
1810
Ed Tanous1abe55e2018-09-05 08:30:59 -07001811struct AsyncPutRequest
1812{
Ed Tanous4e23a442022-06-06 09:57:26 -07001813 explicit AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
zhanghch058d1b46d2021-04-01 11:18:24 +08001814 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001815 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001816 ~AsyncPutRequest()
1817 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001818 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001819 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001820 setErrorResponse(asyncResp->res,
1821 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001822 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001823 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001824 }
1825
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001826 AsyncPutRequest(const AsyncPutRequest&) = delete;
1827 AsyncPutRequest(AsyncPutRequest&&) = delete;
1828 AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1829 AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1830
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001831 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001832 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001833 setErrorResponse(asyncResp->res,
1834 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001835 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001836 }
1837
zhanghch058d1b46d2021-04-01 11:18:24 +08001838 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001839 std::string objectPath;
1840 std::string propertyName;
1841 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001842};
1843
zhanghch058d1b46d2021-04-01 11:18:24 +08001844inline void handlePut(const crow::Request& req,
1845 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001846 const std::string& objectPath,
1847 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001848{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001849 if (destProperty.empty())
1850 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001851 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001852 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001853 return;
1854 }
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001855 nlohmann::json requestDbusData;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001856
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001857 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
1858 if (ret == JsonParseResult::BadContentType)
1859 {
1860 setErrorResponse(asyncResp->res,
1861 boost::beast::http::status::unsupported_media_type,
1862 invalidContentType, unsupportedMediaMsg);
1863 return;
1864 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001865
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001866 if (ret != JsonParseResult::Success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001867 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001868 setErrorResponse(asyncResp->res,
1869 boost::beast::http::status::bad_request, noJsonDesc,
1870 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001871 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001872 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001873
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001874 auto propertyIt = requestDbusData.find("data");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001875 if (propertyIt == requestDbusData.end())
1876 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001877 setErrorResponse(asyncResp->res,
1878 boost::beast::http::status::bad_request, noJsonDesc,
1879 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001880 return;
1881 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001882 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001883 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001884 transaction->objectPath = objectPath;
1885 transaction->propertyName = destProperty;
1886 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001887
George Liu2b731192023-01-11 16:27:13 +08001888 dbus::utility::getDbusObject(
1889 transaction->objectPath, {},
1890 [transaction](const boost::system::error_code& ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001891 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001892 if (!ec2 && objectNames.empty())
1893 {
1894 setErrorResponse(transaction->asyncResp->res,
1895 boost::beast::http::status::not_found,
1896 propNotFoundDesc, notFoundMsg);
1897 return;
1898 }
Ed Tanous911ac312017-08-15 09:37:42 -07001899
Ed Tanous002d39b2022-05-31 08:59:27 -07001900 for (const std::pair<std::string, std::vector<std::string>>&
1901 connection : objectNames)
1902 {
1903 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001904
Ed Tanous002d39b2022-05-31 08:59:27 -07001905 crow::connections::systemBus->async_method_call(
1906 [connectionName{std::string(connectionName)},
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001907 transaction](const boost::system::error_code& ec3,
Ed Tanous002d39b2022-05-31 08:59:27 -07001908 const std::string& introspectXml) {
1909 if (ec3)
1910 {
Ed Tanous62598e32023-07-17 17:06:25 -07001911 BMCWEB_LOG_ERROR(
1912 "Introspect call failed with error: {} on process: {}",
1913 ec3.message(), connectionName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001914 transaction->setErrorStatus("Unexpected Error");
1915 return;
1916 }
1917 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001918
Ed Tanous002d39b2022-05-31 08:59:27 -07001919 doc.Parse(introspectXml.c_str());
1920 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1921 if (pRoot == nullptr)
1922 {
Ed Tanous62598e32023-07-17 17:06:25 -07001923 BMCWEB_LOG_ERROR("XML document failed to parse: {}",
1924 introspectXml);
Ed Tanous002d39b2022-05-31 08:59:27 -07001925 transaction->setErrorStatus("Unexpected Error");
1926 return;
1927 }
1928 tinyxml2::XMLElement* ifaceNode =
1929 pRoot->FirstChildElement("interface");
1930 while (ifaceNode != nullptr)
1931 {
1932 const char* interfaceName = ifaceNode->Attribute("name");
Ed Tanous62598e32023-07-17 17:06:25 -07001933 BMCWEB_LOG_DEBUG("found interface {}", interfaceName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001934 tinyxml2::XMLElement* propNode =
1935 ifaceNode->FirstChildElement("property");
1936 while (propNode != nullptr)
1937 {
1938 const char* propertyName = propNode->Attribute("name");
Ed Tanous62598e32023-07-17 17:06:25 -07001939 BMCWEB_LOG_DEBUG("Found property {}", propertyName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001940 if (propertyName == transaction->propertyName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001941 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001942 const char* argType = propNode->Attribute("type");
1943 if (argType != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001944 {
Patrick Williams59d494e2022-07-22 19:26:55 -05001945 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001946 crow::connections::systemBus
1947 ->new_method_call(
1948 connectionName.c_str(),
1949 transaction->objectPath.c_str(),
1950 "org.freedesktop.DBus."
1951 "Properties",
1952 "Set");
1953 m.append(interfaceName,
1954 transaction->propertyName);
1955 int r = sd_bus_message_open_container(
1956 m.get(), SD_BUS_TYPE_VARIANT, argType);
1957 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001958 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001959 transaction->setErrorStatus(
1960 "Unexpected Error");
1961 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001962 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001963 r = convertJsonToDbus(
1964 m.get(), argType,
1965 transaction->propertyValue);
1966 if (r < 0)
1967 {
1968 if (r == -ERANGE)
1969 {
1970 transaction->setErrorStatus(
1971 "Provided property value "
1972 "is out of range for the "
1973 "property type");
1974 }
1975 else
1976 {
1977 transaction->setErrorStatus(
1978 "Invalid arg type");
1979 }
1980 return;
1981 }
1982 r = sd_bus_message_close_container(m.get());
1983 if (r < 0)
1984 {
1985 transaction->setErrorStatus(
1986 "Unexpected Error");
1987 return;
1988 }
1989 crow::connections::systemBus->async_send(
Patrick Williams5a39f772023-10-20 11:20:21 -05001990 m, [transaction](
1991 const boost::system::error_code& ec,
1992 sdbusplus::message_t& m2) {
Ed Tanous62598e32023-07-17 17:06:25 -07001993 BMCWEB_LOG_DEBUG("sent");
Ed Tanous002d39b2022-05-31 08:59:27 -07001994 if (ec)
1995 {
1996 const sd_bus_error* e = m2.get_error();
1997 setErrorResponse(
1998 transaction->asyncResp->res,
1999 boost::beast::http::status::
2000 forbidden,
2001 (e) != nullptr
2002 ? e->name
2003 : ec.category().name(),
2004 (e) != nullptr ? e->message
2005 : ec.message());
2006 }
2007 else
2008 {
2009 transaction->asyncResp->res
2010 .jsonValue["status"] = "ok";
2011 transaction->asyncResp->res
2012 .jsonValue["message"] = "200 OK";
2013 transaction->asyncResp->res
2014 .jsonValue["data"] = nullptr;
2015 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002016 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002017 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002018 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002019 propNode = propNode->NextSiblingElement("property");
2020 }
2021 ifaceNode = ifaceNode->NextSiblingElement("interface");
2022 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002023 },
Ed Tanous002d39b2022-05-31 08:59:27 -07002024 connectionName, transaction->objectPath,
2025 "org.freedesktop.DBus.Introspectable", "Introspect");
2026 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002027 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07002028}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002029
zhanghch058d1b46d2021-04-01 11:18:24 +08002030inline void handleDBusUrl(const crow::Request& req,
2031 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002032 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002033{
Ed Tanous049a0512018-11-01 13:58:42 -07002034 // If accessing a single attribute, fill in and update objectPath,
2035 // otherwise leave destProperty blank
Ed Tanouse05aec52022-01-25 10:28:56 -08002036 std::string destProperty;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002037 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002038 size_t attrPosition = objectPath.find(attrSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002039 if (attrPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002040 {
2041 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2042 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002043 objectPath.resize(attrPosition);
Ed Tanous049a0512018-11-01 13:58:42 -07002044 }
2045
Ed Tanousb41187f2019-10-24 16:30:02 -07002046 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002047 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002048 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002049 size_t actionPosition = objectPath.find(actionSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002050 if (actionPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002051 {
2052 std::string postProperty =
2053 objectPath.substr((actionPosition + strlen(actionSeperator)),
2054 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002055 objectPath.resize(actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002056 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002057 return;
2058 }
2059 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002060 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002061 {
Ed Tanous11ba3972022-07-11 09:50:41 -07002062 if (objectPath.ends_with("/enumerate"))
Ed Tanous049a0512018-11-01 13:58:42 -07002063 {
2064 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2065 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002066 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002067 }
Ed Tanous11ba3972022-07-11 09:50:41 -07002068 else if (objectPath.ends_with("/list"))
Ed Tanous049a0512018-11-01 13:58:42 -07002069 {
2070 objectPath.erase(objectPath.end() - sizeof("list"),
2071 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002072 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002073 }
2074 else
2075 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002076 // Trim any trailing "/" at the end
Ed Tanous11ba3972022-07-11 09:50:41 -07002077 if (objectPath.ends_with("/"))
Ed Tanousf839dfe2018-11-12 11:11:15 -08002078 {
2079 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002080 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002081 }
2082 else
2083 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002084 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002085 }
Ed Tanous049a0512018-11-01 13:58:42 -07002086 }
2087 return;
2088 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002089 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002090 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002091 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002092 return;
2093 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002094 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002095 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002096 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002097 return;
2098 }
Ed Tanous049a0512018-11-01 13:58:42 -07002099
zhanghch058d1b46d2021-04-01 11:18:24 +08002100 setErrorResponse(asyncResp->res,
2101 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002102 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002103}
2104
Ed Tanous1656b292022-05-04 11:33:42 -07002105inline void
2106 handleBusSystemPost(const crow::Request& req,
2107 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2108 const std::string& processName,
2109 const std::string& requestedPath)
2110{
2111 std::vector<std::string> strs;
Ed Tanous50ebd4a2023-01-19 19:03:17 -08002112
2113 bmcweb::split(strs, requestedPath, '/');
Ed Tanous1656b292022-05-04 11:33:42 -07002114 std::string objectPath;
2115 std::string interfaceName;
2116 std::string methodName;
2117 auto it = strs.begin();
2118 if (it == strs.end())
2119 {
2120 objectPath = "/";
2121 }
2122 while (it != strs.end())
2123 {
2124 // Check if segment contains ".". If it does, it must be an
2125 // interface
2126 if (it->find(".") != std::string::npos)
2127 {
2128 break;
2129 // This check is necessary as the trailing slash gets
2130 // parsed as part of our <path> specifier above, which
2131 // causes the normal trailing backslash redirector to
2132 // fail.
2133 }
2134 if (!it->empty())
2135 {
2136 objectPath += "/" + *it;
2137 }
2138 it++;
2139 }
2140 if (it != strs.end())
2141 {
2142 interfaceName = *it;
2143 it++;
2144
2145 // after interface, we might have a method name
2146 if (it != strs.end())
2147 {
2148 methodName = *it;
2149 it++;
2150 }
2151 }
2152 if (it != strs.end())
2153 {
2154 // if there is more levels past the method name, something
2155 // went wrong, return not found
2156 asyncResp->res.result(boost::beast::http::status::not_found);
2157 return;
2158 }
2159 if (interfaceName.empty())
2160 {
2161 crow::connections::systemBus->async_method_call(
2162 [asyncResp, processName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002163 objectPath](const boost::system::error_code& ec,
Ed Tanous1656b292022-05-04 11:33:42 -07002164 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002165 if (ec)
2166 {
Ed Tanous62598e32023-07-17 17:06:25 -07002167 BMCWEB_LOG_ERROR(
2168 "Introspect call failed with error: {} on process: {} path: {}",
2169 ec.message(), processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002170 return;
2171 }
2172 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002173
Ed Tanous002d39b2022-05-31 08:59:27 -07002174 doc.Parse(introspectXml.c_str());
2175 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2176 if (pRoot == nullptr)
2177 {
Ed Tanous62598e32023-07-17 17:06:25 -07002178 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
2179 processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002180 asyncResp->res.jsonValue["status"] = "XML parse error";
2181 asyncResp->res.result(
2182 boost::beast::http::status::internal_server_error);
2183 return;
2184 }
2185
Ed Tanous62598e32023-07-17 17:06:25 -07002186 BMCWEB_LOG_DEBUG("{}", introspectXml);
Ed Tanous002d39b2022-05-31 08:59:27 -07002187 asyncResp->res.jsonValue["status"] = "ok";
2188 asyncResp->res.jsonValue["bus_name"] = processName;
2189 asyncResp->res.jsonValue["object_path"] = objectPath;
2190
2191 nlohmann::json& interfacesArray =
2192 asyncResp->res.jsonValue["interfaces"];
2193 interfacesArray = nlohmann::json::array();
2194 tinyxml2::XMLElement* interface =
2195 pRoot->FirstChildElement("interface");
2196
2197 while (interface != nullptr)
2198 {
2199 const char* ifaceName = interface->Attribute("name");
2200 if (ifaceName != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002201 {
Ed Tanous8a592812022-06-04 09:06:59 -07002202 nlohmann::json::object_t interfaceObj;
2203 interfaceObj["name"] = ifaceName;
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002204 interfacesArray.emplace_back(std::move(interfaceObj));
Ed Tanous1656b292022-05-04 11:33:42 -07002205 }
2206
Ed Tanous002d39b2022-05-31 08:59:27 -07002207 interface = interface->NextSiblingElement("interface");
2208 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002209 },
Ed Tanous1656b292022-05-04 11:33:42 -07002210 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2211 "Introspect");
2212 }
2213 else if (methodName.empty())
2214 {
2215 crow::connections::systemBus->async_method_call(
2216 [asyncResp, processName, objectPath,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002217 interfaceName](const boost::system::error_code& ec,
Ed Tanous1656b292022-05-04 11:33:42 -07002218 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002219 if (ec)
2220 {
Ed Tanous62598e32023-07-17 17:06:25 -07002221 BMCWEB_LOG_ERROR(
2222 "Introspect call failed with error: {} on process: {} path: {}",
2223 ec.message(), processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002224 return;
2225 }
2226 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002227
Ed Tanous002d39b2022-05-31 08:59:27 -07002228 doc.Parse(introspectXml.data(), introspectXml.size());
2229 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2230 if (pRoot == nullptr)
2231 {
Ed Tanous62598e32023-07-17 17:06:25 -07002232 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
2233 processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002234 asyncResp->res.result(
2235 boost::beast::http::status::internal_server_error);
2236 return;
2237 }
2238
2239 asyncResp->res.jsonValue["status"] = "ok";
2240 asyncResp->res.jsonValue["bus_name"] = processName;
2241 asyncResp->res.jsonValue["interface"] = interfaceName;
2242 asyncResp->res.jsonValue["object_path"] = objectPath;
2243
2244 nlohmann::json& methodsArray = asyncResp->res.jsonValue["methods"];
2245 methodsArray = nlohmann::json::array();
2246
2247 nlohmann::json& signalsArray = asyncResp->res.jsonValue["signals"];
2248 signalsArray = nlohmann::json::array();
2249
2250 nlohmann::json& propertiesObj =
2251 asyncResp->res.jsonValue["properties"];
2252 propertiesObj = nlohmann::json::object();
2253
2254 // if we know we're the only call, build the
2255 // json directly
2256 tinyxml2::XMLElement* interface =
2257 pRoot->FirstChildElement("interface");
2258 while (interface != nullptr)
2259 {
2260 const char* ifaceName = interface->Attribute("name");
2261
2262 if (ifaceName != nullptr && ifaceName == interfaceName)
Ed Tanous1656b292022-05-04 11:33:42 -07002263 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002264 break;
Ed Tanous1656b292022-05-04 11:33:42 -07002265 }
Ed Tanous14766872022-03-15 10:44:42 -07002266
Ed Tanous002d39b2022-05-31 08:59:27 -07002267 interface = interface->NextSiblingElement("interface");
2268 }
2269 if (interface == nullptr)
2270 {
2271 // if we got to the end of the list and
2272 // never found a match, throw 404
2273 asyncResp->res.result(boost::beast::http::status::not_found);
2274 return;
2275 }
Ed Tanous1656b292022-05-04 11:33:42 -07002276
Ed Tanous002d39b2022-05-31 08:59:27 -07002277 tinyxml2::XMLElement* methods =
2278 interface->FirstChildElement("method");
2279 while (methods != nullptr)
2280 {
2281 nlohmann::json argsArray = nlohmann::json::array();
2282 tinyxml2::XMLElement* arg = methods->FirstChildElement("arg");
2283 while (arg != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002284 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002285 nlohmann::json thisArg;
2286 for (const char* fieldName : std::array<const char*, 3>{
2287 "name", "direction", "type"})
Ed Tanous1656b292022-05-04 11:33:42 -07002288 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002289 const char* fieldValue = arg->Attribute(fieldName);
2290 if (fieldValue != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002291 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002292 thisArg[fieldName] = fieldValue;
2293 }
2294 }
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002295 argsArray.emplace_back(std::move(thisArg));
Ed Tanous002d39b2022-05-31 08:59:27 -07002296 arg = arg->NextSiblingElement("arg");
2297 }
2298
2299 const char* name = methods->Attribute("name");
2300 if (name != nullptr)
2301 {
2302 std::string uri;
2303 uri.reserve(14 + processName.size() + objectPath.size() +
2304 interfaceName.size() + strlen(name));
2305 uri += "/bus/system/";
2306 uri += processName;
2307 uri += objectPath;
2308 uri += "/";
2309 uri += interfaceName;
2310 uri += "/";
2311 uri += name;
2312
2313 nlohmann::json::object_t object;
2314 object["name"] = name;
2315 object["uri"] = std::move(uri);
2316 object["args"] = argsArray;
2317
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002318 methodsArray.emplace_back(std::move(object));
Ed Tanous002d39b2022-05-31 08:59:27 -07002319 }
2320 methods = methods->NextSiblingElement("method");
2321 }
2322 tinyxml2::XMLElement* signals =
2323 interface->FirstChildElement("signal");
2324 while (signals != nullptr)
2325 {
2326 nlohmann::json argsArray = nlohmann::json::array();
2327
2328 tinyxml2::XMLElement* arg = signals->FirstChildElement("arg");
2329 while (arg != nullptr)
2330 {
2331 const char* name = arg->Attribute("name");
2332 const char* type = arg->Attribute("type");
2333 if (name != nullptr && type != nullptr)
2334 {
2335 argsArray.push_back({
2336 {"name", name},
2337 {"type", type},
2338 });
2339 }
2340 arg = arg->NextSiblingElement("arg");
2341 }
2342 const char* name = signals->Attribute("name");
2343 if (name != nullptr)
2344 {
2345 nlohmann::json::object_t object;
2346 object["name"] = name;
2347 object["args"] = argsArray;
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002348 signalsArray.emplace_back(std::move(object));
Ed Tanous002d39b2022-05-31 08:59:27 -07002349 }
2350
2351 signals = signals->NextSiblingElement("signal");
2352 }
2353
2354 tinyxml2::XMLElement* property =
2355 interface->FirstChildElement("property");
2356 while (property != nullptr)
2357 {
2358 const char* name = property->Attribute("name");
2359 const char* type = property->Attribute("type");
2360 if (type != nullptr && name != nullptr)
2361 {
Patrick Williams59d494e2022-07-22 19:26:55 -05002362 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07002363 crow::connections::systemBus->new_method_call(
2364 processName.c_str(), objectPath.c_str(),
2365 "org.freedesktop."
2366 "DBus."
2367 "Properties",
2368 "Get");
2369 m.append(interfaceName, name);
2370 nlohmann::json& propertyItem = propertiesObj[name];
2371 crow::connections::systemBus->async_send(
2372 m, [&propertyItem,
Ed Tanous8b242752023-06-27 17:17:13 -07002373 asyncResp](const boost::system::error_code& ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05002374 sdbusplus::message_t& msg) {
Patrick Williams5a39f772023-10-20 11:20:21 -05002375 if (ec2)
2376 {
2377 return;
2378 }
Ed Tanous1656b292022-05-04 11:33:42 -07002379
Ed Tanous07900812024-05-06 15:41:30 -07002380 int r = convertDBusToJSON("v", msg, propertyItem);
2381 if (r < 0)
2382 {
2383 BMCWEB_LOG_ERROR("Couldn't convert vector to json");
2384 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002385 });
Ed Tanous1656b292022-05-04 11:33:42 -07002386 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002387 property = property->NextSiblingElement("property");
2388 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002389 },
Ed Tanous1656b292022-05-04 11:33:42 -07002390 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2391 "Introspect");
2392 }
2393 else
2394 {
2395 if (req.method() != boost::beast::http::verb::post)
2396 {
2397 asyncResp->res.result(boost::beast::http::status::not_found);
2398 return;
2399 }
2400
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002401 nlohmann::json requestDbusData;
2402 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
2403 if (ret == JsonParseResult::BadContentType)
Ed Tanous1656b292022-05-04 11:33:42 -07002404 {
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002405 setErrorResponse(asyncResp->res,
2406 boost::beast::http::status::unsupported_media_type,
2407 invalidContentType, unsupportedMediaMsg);
Ed Tanous1656b292022-05-04 11:33:42 -07002408 return;
2409 }
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002410 if (ret != JsonParseResult::Success)
2411 {
2412 setErrorResponse(asyncResp->res,
2413 boost::beast::http::status::bad_request,
2414 noJsonDesc, badReqMsg);
2415 return;
2416 }
2417
Ed Tanous1656b292022-05-04 11:33:42 -07002418 if (!requestDbusData.is_array())
2419 {
2420 asyncResp->res.result(boost::beast::http::status::bad_request);
2421 return;
2422 }
Lei YU28dd5ca2023-03-17 13:17:05 +08002423 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous1656b292022-05-04 11:33:42 -07002424
2425 transaction->path = objectPath;
2426 transaction->methodName = methodName;
2427 transaction->arguments = std::move(requestDbusData);
2428
2429 findActionOnInterface(transaction, processName);
2430 }
2431}
2432
Ed Tanous23a21a12020-07-25 04:45:05 +00002433inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002434{
2435 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002436 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002437 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002438 [](const crow::Request&,
2439 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002440 nlohmann::json::array_t buses;
2441 nlohmann::json& bus = buses.emplace_back();
2442 bus["name"] = "system";
2443 asyncResp->res.jsonValue["busses"] = std::move(buses);
2444 asyncResp->res.jsonValue["status"] = "ok";
Patrick Williams5a39f772023-10-20 11:20:21 -05002445 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002446
2447 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002448 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002449 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002450 [](const crow::Request&,
2451 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002452 auto myCallback = [asyncResp](const boost::system::error_code& ec,
zhanghch058d1b46d2021-04-01 11:18:24 +08002453 std::vector<std::string>& names) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002454 if (ec)
2455 {
Ed Tanous62598e32023-07-17 17:06:25 -07002456 BMCWEB_LOG_ERROR("Dbus call failed with code {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07002457 asyncResp->res.result(
2458 boost::beast::http::status::internal_server_error);
2459 }
2460 else
2461 {
Ed Tanous3544d2a2023-08-06 18:12:20 -07002462 std::ranges::sort(names);
Ed Tanous002d39b2022-05-31 08:59:27 -07002463 asyncResp->res.jsonValue["status"] = "ok";
2464 auto& objectsSub = asyncResp->res.jsonValue["objects"];
Ed Tanous02cad962022-06-30 16:50:15 -07002465 for (const auto& name : names)
Ed Tanous002d39b2022-05-31 08:59:27 -07002466 {
2467 nlohmann::json::object_t object;
2468 object["name"] = name;
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002469 objectsSub.emplace_back(std::move(object));
Ed Tanous002d39b2022-05-31 08:59:27 -07002470 }
2471 }
2472 };
2473 crow::connections::systemBus->async_method_call(
2474 std::move(myCallback), "org.freedesktop.DBus", "/",
2475 "org.freedesktop.DBus", "ListNames");
Patrick Williams5a39f772023-10-20 11:20:21 -05002476 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002477
2478 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002479 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002480 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002481 [](const crow::Request&,
2482 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002483 handleList(asyncResp, "/");
Patrick Williams5a39f772023-10-20 11:20:21 -05002484 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002485
2486 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002487 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002488 .methods(boost::beast::http::verb::get)(
2489 [](const crow::Request& req,
2490 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002491 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002492 std::string objectPath = "/xyz/" + path;
2493 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002494 });
zhanghch058d1b46d2021-04-01 11:18:24 +08002495
2496 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002497 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002498 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2499 boost::beast::http::verb::delete_)(
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 = "/xyz/" + path;
2504 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002505 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002506
Ed Tanous049a0512018-11-01 13:58:42 -07002507 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002508 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002509 .methods(boost::beast::http::verb::get)(
2510 [](const crow::Request& req,
2511 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2512 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002513 std::string objectPath = "/org/" + path;
2514 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002515 });
Tanousf00032d2018-11-05 01:18:10 -03002516
2517 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002518 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002519 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2520 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002521 [](const crow::Request& req,
2522 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002523 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002524 std::string objectPath = "/org/" + path;
2525 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002526 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002527
Ed Tanous1abe55e2018-09-05 08:30:59 -07002528 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002529 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002530 .methods(boost::beast::http::verb::get)(
2531 [](const crow::Request&,
2532 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2533 const std::string& dumpId) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002534 if (!validateFilename(dumpId))
2535 {
2536 asyncResp->res.result(boost::beast::http::status::bad_request);
2537 return;
2538 }
2539 std::filesystem::path loc("/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002540
Ed Tanous002d39b2022-05-31 08:59:27 -07002541 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002542
Ed Tanous002d39b2022-05-31 08:59:27 -07002543 if (!std::filesystem::exists(loc) ||
2544 !std::filesystem::is_directory(loc))
2545 {
Ed Tanous62598e32023-07-17 17:06:25 -07002546 BMCWEB_LOG_ERROR("{}Not found", loc.string());
Ed Tanous002d39b2022-05-31 08:59:27 -07002547 asyncResp->res.result(boost::beast::http::status::not_found);
2548 return;
2549 }
2550 std::filesystem::directory_iterator files(loc);
zhanghch058d1b46d2021-04-01 11:18:24 +08002551
Ed Tanous002d39b2022-05-31 08:59:27 -07002552 for (const auto& file : files)
2553 {
Ed Tanous27b0cf92023-08-07 12:02:40 -07002554 if (!asyncResp->res.openFile(file))
Ed Tanous002d39b2022-05-31 08:59:27 -07002555 {
2556 continue;
2557 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002558
Ed Tanousd9f6c622022-03-17 09:12:17 -07002559 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07002560 "application/octet-stream");
zhanghch058d1b46d2021-04-01 11:18:24 +08002561
Ed Tanous002d39b2022-05-31 08:59:27 -07002562 // Assuming only one dump file will be present in the dump
2563 // id directory
2564 std::string dumpFileName = file.path().filename().string();
zhanghch058d1b46d2021-04-01 11:18:24 +08002565
Ed Tanous002d39b2022-05-31 08:59:27 -07002566 // Filename should be in alphanumeric, dot and underscore
2567 // Its based on phosphor-debug-collector application
2568 // dumpfile format
Ed Tanous4b242742023-05-11 09:51:51 -07002569 static std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
Ed Tanous002d39b2022-05-31 08:59:27 -07002570 if (!std::regex_match(dumpFileName, dumpFileRegex))
2571 {
Ed Tanous62598e32023-07-17 17:06:25 -07002572 BMCWEB_LOG_ERROR("Invalid dump filename {}", dumpFileName);
zhanghch058d1b46d2021-04-01 11:18:24 +08002573 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002574 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07002575 }
Patrick Williams89492a12023-05-10 07:51:34 -05002576 std::string contentDispositionParam = "attachment; filename=\"" +
2577 dumpFileName + "\"";
Ed Tanous002d39b2022-05-31 08:59:27 -07002578
Ed Tanousd9f6c622022-03-17 09:12:17 -07002579 asyncResp->res.addHeader(
2580 boost::beast::http::field::content_disposition,
2581 contentDispositionParam);
Ed Tanous002d39b2022-05-31 08:59:27 -07002582
Ed Tanous002d39b2022-05-31 08:59:27 -07002583 return;
2584 }
2585 asyncResp->res.result(boost::beast::http::status::not_found);
2586 return;
Patrick Williams5a39f772023-10-20 11:20:21 -05002587 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002588
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002589 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002590 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002591
2592 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002593 [](const crow::Request&,
2594 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002595 const std::string& connection) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002596 introspectObjects(connection, "/", asyncResp);
Patrick Williams5a39f772023-10-20 11:20:21 -05002597 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002598
2599 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002600 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous1656b292022-05-04 11:33:42 -07002601 .methods(boost::beast::http::verb::get,
2602 boost::beast::http::verb::post)(handleBusSystemPost);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002603}
2604} // namespace openbmc_mapper
2605} // namespace crow