blob: e0c16d9e8fb596388a1c3107ed670426886c4b68 [file] [log] [blame]
James Feist5b4aa862018-08-16 14:07:01 -07001// Copyright (c) 2018 Intel Corporation
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
Ed Tanousb9b2e0b2018-09-13 13:47:50 -070014
James Feist5b4aa862018-08-16 14:07:01 -070015#pragma once
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080016#include "app.hpp"
17#include "async_resp.hpp"
18#include "dbus_singleton.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +080019#include "dbus_utility.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000020#include "http_request.hpp"
21#include "http_response.hpp"
22#include "logging.hpp"
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010023#include "parsing.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000024#include "routing.hpp"
Ed Tanous50ebd4a2023-01-19 19:03:17 -080025#include "str_utility.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000026
27#include <systemd/sd-bus-protocol.h>
28#include <systemd/sd-bus.h>
Ed Tanous911ac312017-08-15 09:37:42 -070029#include <tinyxml2.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -070030
Ed Tanous11ba3972022-07-11 09:50:41 -070031#include <boost/algorithm/string/classification.hpp>
32#include <boost/algorithm/string/predicate.hpp>
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>
37#include <boost/iterator/iterator_facade.hpp>
George Liue99073f2022-12-09 11:06:16 +080038#include <boost/system/error_code.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000039#include <nlohmann/json.hpp>
40#include <sdbusplus/asio/connection.hpp>
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +020041#include <sdbusplus/asio/property.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000042#include <sdbusplus/exception.hpp>
43#include <sdbusplus/message.hpp>
44#include <sdbusplus/message/native_types.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050045
Nan Zhoud5c80ad2022-07-11 01:16:31 +000046#include <algorithm>
47#include <array>
48#include <cerrno>
49#include <cstdint>
50#include <cstring>
James Feist4418c7f2019-04-15 11:09:15 -070051#include <filesystem>
Ed Tanousd4bb9bb2018-05-16 13:36:42 -070052#include <fstream>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000053#include <functional>
54#include <initializer_list>
55#include <iterator>
56#include <limits>
57#include <map>
58#include <memory>
Ed Tanous3544d2a2023-08-06 18:12:20 -070059#include <ranges>
Ramesh Iyyard9207042019-07-05 08:04:42 -050060#include <regex>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000061#include <string>
62#include <string_view>
63#include <type_traits>
Ed Tanousb5a76932020-09-29 16:16:58 -070064#include <utility>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000065#include <variant>
66#include <vector>
67
68// IWYU pragma: no_include <boost/algorithm/string/detail/classification.hpp>
69// IWYU pragma: no_include <boost/system/detail/error_code.hpp>
70// IWYU pragma: no_include <boost/system/detail/error_category.hpp>
71// IWYU pragma: no_include <errno.h>
72// IWYU pragma: no_include <string.h>
73// IWYU pragma: no_include <ext/alloc_traits.h>
74// IWYU pragma: no_include <exception>
75// IWYU pragma: no_include <boost/type_index/type_index_facade.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -070076
Ed Tanous1abe55e2018-09-05 08:30:59 -070077namespace crow
78{
79namespace openbmc_mapper
80{
Ed Tanous23a21a12020-07-25 04:45:05 +000081const constexpr char* notFoundMsg = "404 Not Found";
82const constexpr char* badReqMsg = "400 Bad Request";
83const constexpr char* methodNotAllowedMsg = "405 Method Not Allowed";
84const constexpr char* forbiddenMsg = "403 Forbidden";
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010085const constexpr char* unsupportedMediaMsg = "415 Unsupported Media Type";
Ed Tanous23a21a12020-07-25 04:45:05 +000086const constexpr char* methodFailedMsg = "500 Method Call Failed";
87const constexpr char* methodOutputFailedMsg = "500 Method Output Error";
88const constexpr char* notFoundDesc =
Matt Spinler2ae60092018-12-06 10:35:36 -060089 "org.freedesktop.DBus.Error.FileNotFound: path or object not found";
Ed Tanous23a21a12020-07-25 04:45:05 +000090const constexpr char* propNotFoundDesc =
91 "The specified property cannot be found";
92const constexpr char* noJsonDesc = "No JSON object could be decoded";
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010093const constexpr char* invalidContentType =
94 "Content-type header is missing or invalid";
Ed Tanous23a21a12020-07-25 04:45:05 +000095const constexpr char* methodNotFoundDesc =
96 "The specified method cannot be found";
97const constexpr char* methodNotAllowedDesc = "Method not allowed";
98const constexpr char* forbiddenPropDesc =
99 "The specified property cannot be created";
100const constexpr char* forbiddenResDesc =
101 "The specified resource cannot be created";
Matt Spinler2ae60092018-12-06 10:35:36 -0600102
Josh Lehan482c45a2022-03-29 17:10:44 -0700103inline bool validateFilename(const std::string& filename)
104{
Ed Tanous4b242742023-05-11 09:51:51 -0700105 static std::regex validFilename(R"(^[\w\- ]+(\.?[\w\- ]*)$)");
Josh Lehan482c45a2022-03-29 17:10:44 -0700106
107 return std::regex_match(filename, validFilename);
108}
109
Ed Tanous23a21a12020-07-25 04:45:05 +0000110inline void setErrorResponse(crow::Response& res,
111 boost::beast::http::status result,
Ed Tanous26ccae32023-02-16 10:28:44 -0800112 const std::string& desc, std::string_view msg)
Matt Spinler2ae60092018-12-06 10:35:36 -0600113{
114 res.result(result);
Ed Tanous14766872022-03-15 10:44:42 -0700115 res.jsonValue["data"]["description"] = desc;
116 res.jsonValue["message"] = msg;
117 res.jsonValue["status"] = "error";
Matt Spinler2ae60092018-12-06 10:35:36 -0600118}
119
Ed Tanousb5a76932020-09-29 16:16:58 -0700120inline void
121 introspectObjects(const std::string& processName,
122 const std::string& objectPath,
123 const std::shared_ptr<bmcweb::AsyncResp>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700124{
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700125 if (transaction->res.jsonValue.is_null())
126 {
Ed Tanous14766872022-03-15 10:44:42 -0700127 transaction->res.jsonValue["status"] = "ok";
128 transaction->res.jsonValue["bus_name"] = processName;
129 transaction->res.jsonValue["objects"] = nlohmann::json::array();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700130 }
131
Ed Tanous1abe55e2018-09-05 08:30:59 -0700132 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700133 [transaction, processName{std::string(processName)},
134 objectPath{std::string(objectPath)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800135 const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +0000136 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700137 if (ec)
138 {
Ed Tanous62598e32023-07-17 17:06:25 -0700139 BMCWEB_LOG_ERROR(
140 "Introspect call failed with error: {} on process: {} path: {}",
141 ec.message(), processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -0700142 return;
143 }
144 nlohmann::json::object_t object;
145 object["path"] = objectPath;
Ed Tanous14766872022-03-15 10:44:42 -0700146
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500147 transaction->res.jsonValue["objects"].emplace_back(std::move(object));
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700148
Ed Tanous002d39b2022-05-31 08:59:27 -0700149 tinyxml2::XMLDocument doc;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700150
Ed Tanous002d39b2022-05-31 08:59:27 -0700151 doc.Parse(introspectXml.c_str());
152 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
153 if (pRoot == nullptr)
154 {
Ed Tanous62598e32023-07-17 17:06:25 -0700155 BMCWEB_LOG_ERROR("XML document failed to parse {} {}", processName,
156 objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -0700157 }
158 else
159 {
160 tinyxml2::XMLElement* node = pRoot->FirstChildElement("node");
161 while (node != nullptr)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700162 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700163 const char* childPath = node->Attribute("name");
164 if (childPath != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700165 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700166 std::string newpath;
167 if (objectPath != "/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700168 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700169 newpath += objectPath;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700170 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700171 newpath += std::string("/") + childPath;
172 // introspect the subobjects as well
173 introspectObjects(processName, newpath, transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700174 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700175
176 node = node->NextSiblingElement("node");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700177 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700178 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500179 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700180 processName, objectPath, "org.freedesktop.DBus.Introspectable",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700181 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -0700182}
Ed Tanous64530012018-02-06 17:08:16 -0800183
Ed Tanous23a21a12020-07-25 04:45:05 +0000184inline void getPropertiesForEnumerate(
185 const std::string& objectPath, const std::string& service,
Ed Tanousb5a76932020-09-29 16:16:58 -0700186 const std::string& interface,
187 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600188{
Ed Tanous62598e32023-07-17 17:06:25 -0700189 BMCWEB_LOG_DEBUG("getPropertiesForEnumerate {} {} {}", objectPath, service,
190 interface);
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600191
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +0200192 sdbusplus::asio::getAllProperties(
193 *crow::connections::systemBus, service, objectPath, interface,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800194 [asyncResp, objectPath, service,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800195 interface](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800196 const dbus::utility::DBusPropertiesMap& propertiesList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700197 if (ec)
198 {
Ed Tanous62598e32023-07-17 17:06:25 -0700199 BMCWEB_LOG_ERROR(
200 "GetAll on path {} iface {} service {} failed with code {}",
201 objectPath, interface, service, ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700202 return;
203 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600204
Ed Tanous002d39b2022-05-31 08:59:27 -0700205 nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
206 nlohmann::json& objectJson = dataJson[objectPath];
207 if (objectJson.is_null())
208 {
209 objectJson = nlohmann::json::object();
210 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600211
Ed Tanous002d39b2022-05-31 08:59:27 -0700212 for (const auto& [name, value] : propertiesList)
213 {
214 nlohmann::json& propertyJson = objectJson[name];
215 std::visit(
216 [&propertyJson](auto&& val) {
217 if constexpr (std::is_same_v<std::decay_t<decltype(val)>,
218 sdbusplus::message::unix_fd>)
219 {
220 propertyJson = val.fd;
221 }
222 else
223 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700224 propertyJson = val;
225 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500226 },
Ed Tanous002d39b2022-05-31 08:59:27 -0700227 value);
228 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500229 });
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600230}
231
232// Find any results that weren't picked up by ObjectManagers, to be
233// called after all ObjectManagers are searched for and called.
Ed Tanous23a21a12020-07-25 04:45:05 +0000234inline void findRemainingObjectsForEnumerate(
Ed Tanousb5a76932020-09-29 16:16:58 -0700235 const std::string& objectPath,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800236 const std::shared_ptr<dbus::utility::MapperGetSubTreeResponse>& subtree,
Ed Tanousb5a76932020-09-29 16:16:58 -0700237 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600238{
Ed Tanous62598e32023-07-17 17:06:25 -0700239 BMCWEB_LOG_DEBUG("findRemainingObjectsForEnumerate");
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500240 const nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600241
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500242 for (const auto& [path, interface_map] : *subtree)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600243 {
244 if (path == objectPath)
245 {
246 // An enumerate does not return the target path's properties
247 continue;
248 }
249 if (dataJson.find(path) == dataJson.end())
250 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500251 for (const auto& [service, interfaces] : interface_map)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600252 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500253 for (const auto& interface : interfaces)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600254 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700255 if (!interface.starts_with("org.freedesktop.DBus"))
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600256 {
257 getPropertiesForEnumerate(path, service, interface,
258 asyncResp);
259 }
260 }
261 }
262 }
263 }
264}
265
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600266struct InProgressEnumerateData
267{
zhanghch058d1b46d2021-04-01 11:18:24 +0800268 InProgressEnumerateData(
269 const std::string& objectPathIn,
270 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
Ed Tanous23a21a12020-07-25 04:45:05 +0000271 objectPath(objectPathIn),
zhanghch058d1b46d2021-04-01 11:18:24 +0800272 asyncResp(asyncRespIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500273 {}
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600274
275 ~InProgressEnumerateData()
276 {
Ed Tanous24b2fe82022-01-06 12:45:54 -0800277 try
278 {
279 findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
280 }
281 catch (...)
282 {
Ed Tanous62598e32023-07-17 17:06:25 -0700283 BMCWEB_LOG_CRITICAL(
284 "findRemainingObjectsForEnumerate threw exception");
Ed Tanous24b2fe82022-01-06 12:45:54 -0800285 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600286 }
287
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800288 InProgressEnumerateData(const InProgressEnumerateData&) = delete;
289 InProgressEnumerateData(InProgressEnumerateData&&) = delete;
290 InProgressEnumerateData& operator=(const InProgressEnumerateData&) = delete;
291 InProgressEnumerateData& operator=(InProgressEnumerateData&&) = delete;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600292 const std::string objectPath;
Ed Tanousb9d36b42022-02-26 21:42:46 -0800293 std::shared_ptr<dbus::utility::MapperGetSubTreeResponse> subtree;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600294 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
295};
296
Ed Tanous23a21a12020-07-25 04:45:05 +0000297inline void getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000298 const std::string& objectName, const std::string& objectManagerPath,
299 const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700300 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700301{
Ed Tanous62598e32023-07-17 17:06:25 -0700302 BMCWEB_LOG_DEBUG(
303 "getManagedObjectsForEnumerate {} object_manager_path {} connection_name {}",
304 objectName, objectManagerPath, connectionName);
George Liu5eb468d2023-06-20 17:03:24 +0800305 sdbusplus::message::object_path path(objectManagerPath);
306 dbus::utility::getManagedObjects(
307 connectionName, path,
Ed Tanous81ce6092020-12-17 16:54:55 +0000308 [transaction, objectName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800309 connectionName](const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +0000310 const dbus::utility::ManagedObjectType& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700311 if (ec)
312 {
Ed Tanous62598e32023-07-17 17:06:25 -0700313 BMCWEB_LOG_ERROR(
314 "GetManagedObjects on path {} on connection {} failed with code {}",
315 objectName, connectionName, ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700316 return;
317 }
Ed Tanous64530012018-02-06 17:08:16 -0800318
Ed Tanous002d39b2022-05-31 08:59:27 -0700319 nlohmann::json& dataJson =
320 transaction->asyncResp->res.jsonValue["data"];
Ed Tanous049a0512018-11-01 13:58:42 -0700321
Ed Tanous002d39b2022-05-31 08:59:27 -0700322 for (const auto& objectPath : objects)
323 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700324 if (objectPath.first.str.starts_with(objectName))
Ed Tanous049a0512018-11-01 13:58:42 -0700325 {
Ed Tanous62598e32023-07-17 17:06:25 -0700326 BMCWEB_LOG_DEBUG("Reading object {}", objectPath.first.str);
Ed Tanous002d39b2022-05-31 08:59:27 -0700327 nlohmann::json& objectJson = dataJson[objectPath.first.str];
328 if (objectJson.is_null())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700329 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700330 objectJson = nlohmann::json::object();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700331 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500332 for (const auto& interface : objectPath.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700333 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700334 for (const auto& property : interface.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700335 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700336 nlohmann::json& propertyJson =
337 objectJson[property.first];
338 std::visit(
339 [&propertyJson](auto&& val) {
340 if constexpr (std::is_same_v<
341 std::decay_t<decltype(val)>,
342 sdbusplus::message::unix_fd>)
343 {
344 propertyJson = val.fd;
345 }
346 else
347 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700348 propertyJson = val;
349 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500350 },
Ed Tanous002d39b2022-05-31 08:59:27 -0700351 property.second);
Ed Tanous049a0512018-11-01 13:58:42 -0700352 }
353 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700354 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700355 for (const auto& interface : objectPath.second)
356 {
357 if (interface.first == "org.freedesktop.DBus.ObjectManager")
358 {
359 getManagedObjectsForEnumerate(objectPath.first.str,
360 objectPath.first.str,
361 connectionName, transaction);
362 }
363 }
364 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500365 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700366}
367
Ed Tanous23a21a12020-07-25 04:45:05 +0000368inline void findObjectManagerPathForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000369 const std::string& objectName, const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700370 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700371{
Ed Tanous62598e32023-07-17 17:06:25 -0700372 BMCWEB_LOG_DEBUG("Finding objectmanager for path {} on connection:{}",
373 objectName, connectionName);
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700374 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000375 [transaction, objectName, connectionName](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800376 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800377 const dbus::utility::MapperGetAncestorsResponse& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700378 if (ec)
379 {
Ed Tanous62598e32023-07-17 17:06:25 -0700380 BMCWEB_LOG_ERROR("GetAncestors on path {} failed with code {}",
381 objectName, ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700382 return;
383 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700384
Ed Tanous002d39b2022-05-31 08:59:27 -0700385 for (const auto& pathGroup : objects)
386 {
387 for (const auto& connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700388 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700389 if (connectionGroup.first == connectionName)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700390 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700391 // Found the object manager path for this resource.
392 getManagedObjectsForEnumerate(objectName, pathGroup.first,
393 connectionName, transaction);
394 return;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700395 }
396 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700397 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500398 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700399 "xyz.openbmc_project.ObjectMapper",
400 "/xyz/openbmc_project/object_mapper",
Ed Tanous81ce6092020-12-17 16:54:55 +0000401 "xyz.openbmc_project.ObjectMapper", "GetAncestors", objectName,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500402 std::array<const char*, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700403}
Ed Tanous64530012018-02-06 17:08:16 -0800404
Ed Tanous7c091622019-05-23 11:42:36 -0700405// Uses GetObject to add the object info about the target /enumerate path to
406// the results of GetSubTree, as GetSubTree will not return info for the
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600407// target path, and then continues on enumerating the rest of the tree.
Ed Tanousb5a76932020-09-29 16:16:58 -0700408inline void getObjectAndEnumerate(
409 const std::shared_ptr<InProgressEnumerateData>& transaction)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600410{
George Liu2b731192023-01-11 16:27:13 +0800411 dbus::utility::getDbusObject(
412 transaction->objectPath, {},
413 [transaction](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800414 const dbus::utility::MapperGetObject& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700415 if (ec)
416 {
Ed Tanous62598e32023-07-17 17:06:25 -0700417 BMCWEB_LOG_ERROR("GetObject for path {} failed with code {}",
418 transaction->objectPath, ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700419 return;
420 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600421
Ed Tanous62598e32023-07-17 17:06:25 -0700422 BMCWEB_LOG_DEBUG("GetObject for {} has {} entries",
423 transaction->objectPath, objects.size());
Ed Tanous002d39b2022-05-31 08:59:27 -0700424 if (!objects.empty())
425 {
426 transaction->subtree->emplace_back(transaction->objectPath,
427 objects);
428 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600429
Ed Tanous002d39b2022-05-31 08:59:27 -0700430 // Map indicating connection name, and the path where the object
431 // manager exists
432 boost::container::flat_map<std::string, std::string> connections;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600433
Ed Tanous002d39b2022-05-31 08:59:27 -0700434 for (const auto& object : *(transaction->subtree))
435 {
436 for (const auto& connection : object.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600437 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700438 for (const auto& interface : connection.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600439 {
Ed Tanous62598e32023-07-17 17:06:25 -0700440 BMCWEB_LOG_DEBUG("{} has interface {}", connection.first,
441 interface);
Ed Tanous002d39b2022-05-31 08:59:27 -0700442 if (interface == "org.freedesktop.DBus.ObjectManager")
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600443 {
Ed Tanous62598e32023-07-17 17:06:25 -0700444 BMCWEB_LOG_DEBUG("found object manager path {}",
445 object.first);
Ed Tanousf8fe53e2022-06-30 15:55:45 -0700446 connections[connection.first] = object.first;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600447 }
448 }
449 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700450 }
Ed Tanous62598e32023-07-17 17:06:25 -0700451 BMCWEB_LOG_DEBUG("Got {} connections", connections.size());
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600452
Ed Tanous002d39b2022-05-31 08:59:27 -0700453 for (const auto& connection : connections)
454 {
455 // If we already know where the object manager is, we don't
456 // need to search for it, we can call directly in to
457 // getManagedObjects
458 if (!connection.second.empty())
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600459 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700460 getManagedObjectsForEnumerate(transaction->objectPath,
461 connection.second,
462 connection.first, transaction);
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600463 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700464 else
465 {
466 // otherwise we need to find the object manager path
467 // before we can continue
468 findObjectManagerPathForEnumerate(
469 transaction->objectPath, connection.first, transaction);
470 }
471 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500472 });
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600473}
Ed Tanous64530012018-02-06 17:08:16 -0800474
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700475// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700476struct InProgressActionData
477{
Lei YU28dd5ca2023-03-17 13:17:05 +0800478 explicit InProgressActionData(
479 const std::shared_ptr<bmcweb::AsyncResp>& res) :
480 asyncResp(res)
Ed Tanous23a21a12020-07-25 04:45:05 +0000481 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700482 ~InProgressActionData()
483 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600484 // Methods could have been called across different owners
485 // and interfaces, where some calls failed and some passed.
486 //
487 // The rules for this are:
488 // * if no method was called - error
489 // * if a method failed and none passed - error
490 // (converse: if at least one method passed - OK)
491 // * for the method output:
492 // * if output processing didn't fail, return the data
493
494 // Only deal with method returns if nothing failed earlier
Lei YU28dd5ca2023-03-17 13:17:05 +0800495 if (asyncResp->res.result() == boost::beast::http::status::ok)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700496 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600497 if (!methodPassed)
498 {
Matt Spinler06b1b632019-06-18 16:09:25 -0500499 if (!methodFailed)
Matt Spinler16caaee2019-01-15 11:40:34 -0600500 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800501 setErrorResponse(asyncResp->res,
502 boost::beast::http::status::not_found,
Matt Spinler16caaee2019-01-15 11:40:34 -0600503 methodNotFoundDesc, notFoundMsg);
504 }
505 }
506 else
507 {
508 if (outputFailed)
509 {
510 setErrorResponse(
Lei YU28dd5ca2023-03-17 13:17:05 +0800511 asyncResp->res,
512 boost::beast::http::status::internal_server_error,
Matt Spinler16caaee2019-01-15 11:40:34 -0600513 "Method output failure", methodOutputFailedMsg);
514 }
515 else
516 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800517 asyncResp->res.jsonValue["status"] = "ok";
518 asyncResp->res.jsonValue["message"] = "200 OK";
519 asyncResp->res.jsonValue["data"] = methodResponse;
Matt Spinler16caaee2019-01-15 11:40:34 -0600520 }
521 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700522 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700523 }
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800524 InProgressActionData(const InProgressActionData&) = delete;
525 InProgressActionData(InProgressActionData&&) = delete;
526 InProgressActionData& operator=(const InProgressActionData&) = delete;
527 InProgressActionData& operator=(InProgressActionData&&) = delete;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700528
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500529 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700530 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800531 setErrorResponse(asyncResp->res,
532 boost::beast::http::status::bad_request, desc,
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600533 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700534 }
Lei YU28dd5ca2023-03-17 13:17:05 +0800535 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700536 std::string path;
537 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600538 std::string interfaceName;
Matt Spinler16caaee2019-01-15 11:40:34 -0600539 bool methodPassed = false;
540 bool methodFailed = false;
541 bool outputFailed = false;
Matt Spinler39a4e392019-01-15 11:53:13 -0600542 bool convertedToArray = false;
Matt Spinler16caaee2019-01-15 11:40:34 -0600543 nlohmann::json methodResponse;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700544 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700545};
546
Ed Tanous23a21a12020-07-25 04:45:05 +0000547inline std::vector<std::string> dbusArgSplit(const std::string& string)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700548{
549 std::vector<std::string> ret;
550 if (string.empty())
551 {
552 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700553 }
Ed Tanous0f0353b2019-10-24 11:37:51 -0700554 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700555 int containerDepth = 0;
556
557 for (std::string::const_iterator character = string.begin();
558 character != string.end(); character++)
559 {
560 ret.back() += *character;
561 switch (*character)
562 {
563 case ('a'):
564 break;
565 case ('('):
566 case ('{'):
567 containerDepth++;
568 break;
569 case ('}'):
570 case (')'):
571 containerDepth--;
572 if (containerDepth == 0)
573 {
574 if (character + 1 != string.end())
575 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700576 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700577 }
578 }
579 break;
580 default:
581 if (containerDepth == 0)
582 {
583 if (character + 1 != string.end())
584 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700585 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700586 }
587 }
588 break;
589 }
590 }
Matt Spinler4ae611d2019-01-11 15:37:06 -0600591
592 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700593}
594
Ed Tanous81ce6092020-12-17 16:54:55 +0000595inline int convertJsonToDbus(sd_bus_message* m, const std::string& argType,
596 const nlohmann::json& inputJson)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700597{
598 int r = 0;
Ed Tanous62598e32023-07-17 17:06:25 -0700599 BMCWEB_LOG_DEBUG(
600 "Converting {} to type: {}",
601 inputJson.dump(2, ' ', true, nlohmann::json::error_handler_t::replace),
602 argType);
Ed Tanous81ce6092020-12-17 16:54:55 +0000603 const std::vector<std::string> argTypes = dbusArgSplit(argType);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700604
Ed Tanous1abe55e2018-09-05 08:30:59 -0700605 // Assume a single object for now.
Ed Tanous81ce6092020-12-17 16:54:55 +0000606 const nlohmann::json* j = &inputJson;
607 nlohmann::json::const_iterator jIt = inputJson.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700608
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500609 for (const std::string& argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700610 {
611 // If we are decoding multiple objects, grab the pointer to the
612 // iterator, and increment it for the next loop
613 if (argTypes.size() > 1)
614 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000615 if (jIt == inputJson.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700616 {
617 return -2;
618 }
619 j = &*jIt;
620 jIt++;
621 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500622 const int64_t* intValue = j->get_ptr<const int64_t*>();
623 const std::string* stringValue = j->get_ptr<const std::string*>();
624 const double* doubleValue = j->get_ptr<const double*>();
625 const bool* b = j->get_ptr<const bool*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700626 int64_t v = 0;
627 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700628
Ed Tanous1abe55e2018-09-05 08:30:59 -0700629 // Do some basic type conversions that make sense. uint can be
630 // converted to int. int and uint can be converted to double
Ed Tanous66664f22019-10-11 13:05:49 -0700631 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700632 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500633 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700634 if (uintValue != nullptr)
635 {
636 v = static_cast<int64_t>(*uintValue);
637 intValue = &v;
638 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700639 }
Ed Tanous66664f22019-10-11 13:05:49 -0700640 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700641 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500642 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700643 if (uintValue != nullptr)
644 {
645 d = static_cast<double>(*uintValue);
646 doubleValue = &d;
647 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700648 }
Ed Tanous66664f22019-10-11 13:05:49 -0700649 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700650 {
Ed Tanous66664f22019-10-11 13:05:49 -0700651 if (intValue != nullptr)
652 {
653 d = static_cast<double>(*intValue);
654 doubleValue = &d;
655 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700656 }
657
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700658 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700659 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700660 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700661 {
662 return -1;
663 }
Ed Tanous271584a2019-07-09 16:24:22 -0700664 r = sd_bus_message_append_basic(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500665 m, argCode[0], static_cast<const void*>(stringValue->data()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700666 if (r < 0)
667 {
668 return r;
669 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700670 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700671 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700672 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700673 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700674 {
675 return -1;
676 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500677 if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
678 (*intValue > std::numeric_limits<int32_t>::max()))
679 {
680 return -ERANGE;
681 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700682 int32_t i = static_cast<int32_t>(*intValue);
683 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700684 if (r < 0)
685 {
686 return r;
687 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700688 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700689 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700690 {
691 // lots of ways bool could be represented here. Try them all
Ed Tanouse662eae2022-01-25 10:39:19 -0800692 int boolInt = 0;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700693 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700694 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500695 if (*intValue == 1)
696 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800697 boolInt = 1;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500698 }
699 else if (*intValue == 0)
700 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800701 boolInt = 0;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500702 }
703 else
704 {
705 return -ERANGE;
706 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700707 }
708 else if (b != nullptr)
709 {
Matt Spinlera2f02632019-01-18 10:15:35 -0600710 boolInt = *b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700711 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700712 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700713 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700714 boolInt = boost::istarts_with(*stringValue, "t") ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700715 }
716 else
717 {
718 return -1;
719 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700720 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700721 if (r < 0)
722 {
723 return r;
724 }
725 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700726 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700727 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700728 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700729 {
730 return -1;
731 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500732 if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
733 (*intValue > std::numeric_limits<int16_t>::max()))
734 {
735 return -ERANGE;
736 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700737 int16_t n = static_cast<int16_t>(*intValue);
738 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700739 if (r < 0)
740 {
741 return r;
742 }
743 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700744 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700745 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700746 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700747 {
748 return -1;
749 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700750 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700751 if (r < 0)
752 {
753 return r;
754 }
755 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700756 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700757 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500758 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700759 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700760 {
761 return -1;
762 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000763 if (*uintValue > std::numeric_limits<uint8_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500764 {
765 return -ERANGE;
766 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700767 uint8_t y = static_cast<uint8_t>(*uintValue);
768 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700769 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700770 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700771 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500772 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700773 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700774 {
775 return -1;
776 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000777 if (*uintValue > std::numeric_limits<uint16_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500778 {
779 return -ERANGE;
780 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700781 uint16_t q = static_cast<uint16_t>(*uintValue);
782 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700783 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700784 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700785 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500786 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700787 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700788 {
789 return -1;
790 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000791 if (*uintValue > std::numeric_limits<uint32_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500792 {
793 return -ERANGE;
794 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700795 uint32_t u = static_cast<uint32_t>(*uintValue);
796 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700797 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700798 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700799 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500800 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700801 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700802 {
803 return -1;
804 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700805 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700806 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700807 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700808 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500809 if (doubleValue == nullptr)
810 {
811 return -1;
812 }
813 if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
814 (*doubleValue > std::numeric_limits<double>::max()))
815 {
816 return -ERANGE;
817 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700818 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700819 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700820 else if (argCode.starts_with("a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700821 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700822 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700823 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700824 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700825 if (r < 0)
826 {
827 return r;
828 }
829
Ed Tanous0dfeda62019-10-24 11:21:38 -0700830 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700831 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700832 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700833 if (r < 0)
834 {
835 return r;
836 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700837 }
838 sd_bus_message_close_container(m);
839 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700840 else if (argCode.starts_with("v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700841 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700842 std::string containedType = argCode.substr(1);
Ed Tanous62598e32023-07-17 17:06:25 -0700843 BMCWEB_LOG_DEBUG("variant type: {} appending variant of type: {}",
844 argCode, containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700845 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700846 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700847 if (r < 0)
848 {
849 return r;
850 }
851
Ed Tanous81ce6092020-12-17 16:54:55 +0000852 r = convertJsonToDbus(m, containedType, inputJson);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700853 if (r < 0)
854 {
855 return r;
856 }
857
858 r = sd_bus_message_close_container(m);
859 if (r < 0)
860 {
861 return r;
862 }
863 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700864 else if (argCode.starts_with("(") && argCode.ends_with(")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700865 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700866 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700867 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700868 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800869 if (r < 0)
870 {
871 return r;
872 }
873
Ed Tanous1abe55e2018-09-05 08:30:59 -0700874 nlohmann::json::const_iterator it = j->begin();
Ed Tanous81ce6092020-12-17 16:54:55 +0000875 for (const std::string& argCode2 : dbusArgSplit(argType))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700876 {
877 if (it == j->end())
878 {
879 return -1;
880 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000881 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700882 if (r < 0)
883 {
884 return r;
885 }
886 it++;
887 }
888 r = sd_bus_message_close_container(m);
889 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700890 else if (argCode.starts_with("{") && argCode.ends_with("}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700891 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700892 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700893 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700894 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800895 if (r < 0)
896 {
897 return r;
898 }
899
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700900 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700901 if (codes.size() != 2)
902 {
903 return -1;
904 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700905 const std::string& keyType = codes[0];
906 const std::string& valueType = codes[1];
Ed Tanous3174e4d2020-10-07 11:41:22 -0700907 for (const auto& it : j->items())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700908 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700909 r = convertJsonToDbus(m, keyType, it.key());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700910 if (r < 0)
911 {
912 return r;
913 }
914
Ed Tanous2c70f802020-09-28 14:29:23 -0700915 r = convertJsonToDbus(m, valueType, it.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700916 if (r < 0)
917 {
918 return r;
919 }
920 }
921 r = sd_bus_message_close_container(m);
922 }
923 else
924 {
925 return -2;
926 }
927 if (r < 0)
928 {
929 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700930 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700931
Ed Tanous1abe55e2018-09-05 08:30:59 -0700932 if (argTypes.size() > 1)
933 {
934 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700935 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700936 }
Matt Spinler127ea542019-01-14 11:04:28 -0600937
938 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700939}
940
Matt Spinlerd22a7132019-01-14 12:14:30 -0600941template <typename T>
Patrick Williams59d494e2022-07-22 19:26:55 -0500942int readMessageItem(const std::string& typeCode, sdbusplus::message_t& m,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500943 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600944{
945 T value;
946
947 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
948 if (r < 0)
949 {
Ed Tanous62598e32023-07-17 17:06:25 -0700950 BMCWEB_LOG_ERROR("sd_bus_message_read_basic on type {} failed!",
951 typeCode);
Matt Spinlerd22a7132019-01-14 12:14:30 -0600952 return r;
953 }
954
955 data = value;
956 return 0;
957}
958
Patrick Williams59d494e2022-07-22 19:26:55 -0500959int convertDBusToJSON(const std::string& returnType, sdbusplus::message_t& m,
960 nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600961
Ed Tanous23a21a12020-07-25 04:45:05 +0000962inline int readDictEntryFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -0500963 sdbusplus::message_t& m,
Ed Tanous23a21a12020-07-25 04:45:05 +0000964 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600965{
966 std::vector<std::string> types = dbusArgSplit(typeCode);
967 if (types.size() != 2)
968 {
Ed Tanous62598e32023-07-17 17:06:25 -0700969 BMCWEB_LOG_ERROR("wrong number contained types in dictionary: {}",
970 types.size());
Matt Spinler6df8f992019-01-14 12:47:47 -0600971 return -1;
972 }
973
974 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
975 typeCode.c_str());
976 if (r < 0)
977 {
Ed Tanous62598e32023-07-17 17:06:25 -0700978 BMCWEB_LOG_ERROR("sd_bus_message_enter_container with rc {}", r);
Matt Spinler6df8f992019-01-14 12:47:47 -0600979 return r;
980 }
981
982 nlohmann::json key;
983 r = convertDBusToJSON(types[0], m, key);
984 if (r < 0)
985 {
986 return r;
987 }
988
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500989 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -0600990 if (keyPtr == nullptr)
991 {
992 // json doesn't support non-string keys. If we hit this condition,
993 // convert the result to a string so we can proceed
Ed Tanous71f52d92021-02-19 08:51:17 -0800994 key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500995 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -0700996 // in theory this can't fail now, but lets be paranoid about it
997 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -0600998 if (keyPtr == nullptr)
999 {
1000 return -1;
1001 }
1002 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001003 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -06001004
1005 r = convertDBusToJSON(types[1], m, value);
1006 if (r < 0)
1007 {
1008 return r;
1009 }
1010
1011 r = sd_bus_message_exit_container(m.get());
1012 if (r < 0)
1013 {
Ed Tanous62598e32023-07-17 17:06:25 -07001014 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001015 return r;
1016 }
1017
1018 return 0;
1019}
1020
Ed Tanous23a21a12020-07-25 04:45:05 +00001021inline int readArrayFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001022 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -06001023{
1024 if (typeCode.size() < 2)
1025 {
Ed Tanous62598e32023-07-17 17:06:25 -07001026 BMCWEB_LOG_ERROR("Type code {} too small for an array", typeCode);
Matt Spinler6df8f992019-01-14 12:47:47 -06001027 return -1;
1028 }
1029
1030 std::string containedType = typeCode.substr(1);
1031
1032 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
1033 containedType.c_str());
1034 if (r < 0)
1035 {
Ed Tanous62598e32023-07-17 17:06:25 -07001036 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler6df8f992019-01-14 12:47:47 -06001037 return r;
1038 }
1039
Ed Tanous11ba3972022-07-11 09:50:41 -07001040 bool dict = containedType.starts_with("{") && containedType.ends_with("}");
Matt Spinler6df8f992019-01-14 12:47:47 -06001041
1042 if (dict)
1043 {
1044 // Remove the { }
1045 containedType = containedType.substr(1, containedType.size() - 2);
1046 data = nlohmann::json::object();
1047 }
1048 else
1049 {
1050 data = nlohmann::json::array();
1051 }
1052
1053 while (true)
1054 {
Ed Tanouse662eae2022-01-25 10:39:19 -08001055 r = sd_bus_message_at_end(m.get(), 0);
Matt Spinler6df8f992019-01-14 12:47:47 -06001056 if (r < 0)
1057 {
Ed Tanous62598e32023-07-17 17:06:25 -07001058 BMCWEB_LOG_ERROR("sd_bus_message_at_end failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001059 return r;
1060 }
1061
1062 if (r > 0)
1063 {
1064 break;
1065 }
1066
1067 // Dictionaries are only ever seen in an array
1068 if (dict)
1069 {
1070 r = readDictEntryFromMessage(containedType, m, data);
1071 if (r < 0)
1072 {
1073 return r;
1074 }
1075 }
1076 else
1077 {
1078 data.push_back(nlohmann::json());
1079
1080 r = convertDBusToJSON(containedType, m, data.back());
1081 if (r < 0)
1082 {
1083 return r;
1084 }
1085 }
1086 }
1087
1088 r = sd_bus_message_exit_container(m.get());
1089 if (r < 0)
1090 {
Ed Tanous62598e32023-07-17 17:06:25 -07001091 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler6df8f992019-01-14 12:47:47 -06001092 return r;
1093 }
1094
1095 return 0;
1096}
1097
Ed Tanous23a21a12020-07-25 04:45:05 +00001098inline int readStructFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001099 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001100{
1101 if (typeCode.size() < 3)
1102 {
Ed Tanous62598e32023-07-17 17:06:25 -07001103 BMCWEB_LOG_ERROR("Type code {} too small for a struct", typeCode);
Matt Spinler75c6c672019-01-14 13:01:46 -06001104 return -1;
1105 }
1106
1107 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1108 std::vector<std::string> types = dbusArgSplit(containedTypes);
1109
1110 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1111 containedTypes.c_str());
1112 if (r < 0)
1113 {
Ed Tanous62598e32023-07-17 17:06:25 -07001114 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler75c6c672019-01-14 13:01:46 -06001115 return r;
1116 }
1117
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001118 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001119 {
1120 data.push_back(nlohmann::json());
1121 r = convertDBusToJSON(type, m, data.back());
1122 if (r < 0)
1123 {
1124 return r;
1125 }
1126 }
1127
1128 r = sd_bus_message_exit_container(m.get());
1129 if (r < 0)
1130 {
Ed Tanous62598e32023-07-17 17:06:25 -07001131 BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
Matt Spinler75c6c672019-01-14 13:01:46 -06001132 return r;
1133 }
1134 return 0;
1135}
1136
Patrick Williams59d494e2022-07-22 19:26:55 -05001137inline int readVariantFromMessage(sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001138{
Ed Tanous543f4402022-01-06 13:12:53 -08001139 const char* containerType = nullptr;
Ed Tanous99131cd2019-10-24 11:12:47 -07001140 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001141 if (r < 0)
1142 {
Ed Tanous62598e32023-07-17 17:06:25 -07001143 BMCWEB_LOG_ERROR("sd_bus_message_peek_type failed");
Matt Spinler89c19702019-01-14 13:13:00 -06001144 return r;
1145 }
1146
1147 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1148 containerType);
1149 if (r < 0)
1150 {
Ed Tanous62598e32023-07-17 17:06:25 -07001151 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
Matt Spinler89c19702019-01-14 13:13:00 -06001152 return r;
1153 }
1154
1155 r = convertDBusToJSON(containerType, m, data);
1156 if (r < 0)
1157 {
1158 return r;
1159 }
1160
1161 r = sd_bus_message_exit_container(m.get());
1162 if (r < 0)
1163 {
Ed Tanous62598e32023-07-17 17:06:25 -07001164 BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed");
Matt Spinler89c19702019-01-14 13:13:00 -06001165 return r;
1166 }
1167
1168 return 0;
1169}
1170
Ed Tanous23a21a12020-07-25 04:45:05 +00001171inline int convertDBusToJSON(const std::string& returnType,
Patrick Williams59d494e2022-07-22 19:26:55 -05001172 sdbusplus::message_t& m, nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001173{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001174 int r = 0;
1175 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1176
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001177 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001178 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001179 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001180 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001181 {
1182 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001183 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001184 }
1185
Ed Tanousd4d25792020-09-29 15:15:03 -07001186 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001187 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001188 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001189 if (r < 0)
1190 {
1191 return r;
1192 }
1193 }
1194 else if (typeCode == "b")
1195 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001196 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001197 if (r < 0)
1198 {
1199 return r;
1200 }
1201
Matt Spinlerf39420c2019-01-30 12:57:18 -06001202 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001203 }
1204 else if (typeCode == "u")
1205 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001206 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001207 if (r < 0)
1208 {
1209 return r;
1210 }
1211 }
1212 else if (typeCode == "i")
1213 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001214 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001215 if (r < 0)
1216 {
1217 return r;
1218 }
1219 }
1220 else if (typeCode == "x")
1221 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001222 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001223 if (r < 0)
1224 {
1225 return r;
1226 }
1227 }
1228 else if (typeCode == "t")
1229 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001230 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001231 if (r < 0)
1232 {
1233 return r;
1234 }
1235 }
1236 else if (typeCode == "n")
1237 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001238 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001239 if (r < 0)
1240 {
1241 return r;
1242 }
1243 }
1244 else if (typeCode == "q")
1245 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001246 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001247 if (r < 0)
1248 {
1249 return r;
1250 }
1251 }
1252 else if (typeCode == "y")
1253 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001254 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001255 if (r < 0)
1256 {
1257 return r;
1258 }
1259 }
1260 else if (typeCode == "d")
1261 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001262 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001263 if (r < 0)
1264 {
1265 return r;
1266 }
1267 }
1268 else if (typeCode == "h")
1269 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001270 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001271 if (r < 0)
1272 {
1273 return r;
1274 }
1275 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001276 else if (typeCode.starts_with("a"))
Matt Spinler6df8f992019-01-14 12:47:47 -06001277 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001278 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001279 if (r < 0)
1280 {
1281 return r;
1282 }
1283 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001284 else if (typeCode.starts_with("(") && typeCode.ends_with(")"))
Matt Spinler75c6c672019-01-14 13:01:46 -06001285 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001286 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001287 if (r < 0)
1288 {
1289 return r;
1290 }
1291 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001292 else if (typeCode.starts_with("v"))
Matt Spinler89c19702019-01-14 13:13:00 -06001293 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001294 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001295 if (r < 0)
1296 {
1297 return r;
1298 }
1299 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001300 else
1301 {
Ed Tanous62598e32023-07-17 17:06:25 -07001302 BMCWEB_LOG_ERROR("Invalid D-Bus signature type {}", typeCode);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001303 return -2;
1304 }
1305 }
1306
Matt Spinler16caaee2019-01-15 11:40:34 -06001307 return 0;
1308}
1309
Ed Tanousb5a76932020-09-29 16:16:58 -07001310inline void handleMethodResponse(
1311 const std::shared_ptr<InProgressActionData>& transaction,
Patrick Williams59d494e2022-07-22 19:26:55 -05001312 sdbusplus::message_t& m, const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001313{
Matt Spinler39a4e392019-01-15 11:53:13 -06001314 nlohmann::json data;
1315
1316 int r = convertDBusToJSON(returnType, m, data);
1317 if (r < 0)
1318 {
1319 transaction->outputFailed = true;
1320 return;
1321 }
1322
1323 if (data.is_null())
1324 {
1325 return;
1326 }
1327
1328 if (transaction->methodResponse.is_null())
1329 {
1330 transaction->methodResponse = std::move(data);
1331 return;
1332 }
1333
1334 // If they're both dictionaries or arrays, merge into one.
1335 // Otherwise, make the results an array with every result
1336 // an entry. Could also just fail in that case, but it
1337 // seems better to get the data back somehow.
1338
1339 if (transaction->methodResponse.is_object() && data.is_object())
1340 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001341 for (const auto& obj : data.items())
Matt Spinler39a4e392019-01-15 11:53:13 -06001342 {
1343 // Note: Will overwrite the data for a duplicate key
1344 transaction->methodResponse.emplace(obj.key(),
1345 std::move(obj.value()));
1346 }
1347 return;
1348 }
1349
1350 if (transaction->methodResponse.is_array() && data.is_array())
1351 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001352 for (auto& obj : data)
Matt Spinler39a4e392019-01-15 11:53:13 -06001353 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001354 transaction->methodResponse.emplace_back(std::move(obj));
Matt Spinler39a4e392019-01-15 11:53:13 -06001355 }
1356 return;
1357 }
1358
1359 if (!transaction->convertedToArray)
1360 {
1361 // They are different types. May as well turn them into an array
1362 nlohmann::json j = std::move(transaction->methodResponse);
1363 transaction->methodResponse = nlohmann::json::array();
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001364 transaction->methodResponse.emplace_back(std::move(j));
1365 transaction->methodResponse.emplace_back(std::move(data));
Matt Spinler39a4e392019-01-15 11:53:13 -06001366 transaction->convertedToArray = true;
1367 }
1368 else
1369 {
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001370 transaction->methodResponse.emplace_back(std::move(data));
Matt Spinler39a4e392019-01-15 11:53:13 -06001371 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001372}
1373
Ed Tanousb5a76932020-09-29 16:16:58 -07001374inline void findActionOnInterface(
1375 const std::shared_ptr<InProgressActionData>& transaction,
1376 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001377{
Ed Tanous62598e32023-07-17 17:06:25 -07001378 BMCWEB_LOG_DEBUG("findActionOnInterface for connection {}", connectionName);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001379 crow::connections::systemBus->async_method_call(
1380 [transaction, connectionName{std::string(connectionName)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001381 const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001382 const std::string& introspectXml) {
Ed Tanous62598e32023-07-17 17:06:25 -07001383 BMCWEB_LOG_DEBUG("got xml:\n {}", introspectXml);
Ed Tanous002d39b2022-05-31 08:59:27 -07001384 if (ec)
1385 {
Ed Tanous62598e32023-07-17 17:06:25 -07001386 BMCWEB_LOG_ERROR(
1387 "Introspect call failed with error: {} on process: {}",
1388 ec.message(), connectionName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001389 return;
1390 }
1391 tinyxml2::XMLDocument doc;
Matt Spinler318bd892019-01-15 09:59:20 -06001392
Ed Tanous002d39b2022-05-31 08:59:27 -07001393 doc.Parse(introspectXml.data(), introspectXml.size());
1394 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1395 if (pRoot == nullptr)
1396 {
Ed Tanous62598e32023-07-17 17:06:25 -07001397 BMCWEB_LOG_ERROR("XML document failed to parse {}", connectionName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001398 return;
1399 }
1400 tinyxml2::XMLElement* interfaceNode =
1401 pRoot->FirstChildElement("interface");
1402 while (interfaceNode != nullptr)
1403 {
1404 const char* thisInterfaceName = interfaceNode->Attribute("name");
1405 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001406 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001407 if (!transaction->interfaceName.empty() &&
1408 (transaction->interfaceName != thisInterfaceName))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001409 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001410 interfaceNode =
1411 interfaceNode->NextSiblingElement("interface");
1412 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001413 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001414
1415 tinyxml2::XMLElement* methodNode =
1416 interfaceNode->FirstChildElement("method");
1417 while (methodNode != nullptr)
1418 {
1419 const char* thisMethodName = methodNode->Attribute("name");
Ed Tanous62598e32023-07-17 17:06:25 -07001420 BMCWEB_LOG_DEBUG("Found method: {}", thisMethodName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001421 if (thisMethodName != nullptr &&
1422 thisMethodName == transaction->methodName)
1423 {
Ed Tanous62598e32023-07-17 17:06:25 -07001424 BMCWEB_LOG_DEBUG(
1425 "Found method named {} on interface {}",
1426 thisMethodName, thisInterfaceName);
Patrick Williams59d494e2022-07-22 19:26:55 -05001427 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001428 crow::connections::systemBus->new_method_call(
1429 connectionName.c_str(),
1430 transaction->path.c_str(), thisInterfaceName,
1431 transaction->methodName.c_str());
1432
1433 tinyxml2::XMLElement* argumentNode =
1434 methodNode->FirstChildElement("arg");
1435
1436 std::string returnType;
1437
1438 // Find the output type
1439 while (argumentNode != nullptr)
1440 {
1441 const char* argDirection =
1442 argumentNode->Attribute("direction");
1443 const char* argType =
1444 argumentNode->Attribute("type");
1445 if (argDirection != nullptr && argType != nullptr &&
1446 std::string(argDirection) == "out")
1447 {
1448 returnType = argType;
1449 break;
1450 }
1451 argumentNode =
1452 argumentNode->NextSiblingElement("arg");
1453 }
1454
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001455 auto argIt = transaction->arguments.begin();
Ed Tanous002d39b2022-05-31 08:59:27 -07001456
1457 argumentNode = methodNode->FirstChildElement("arg");
1458
1459 while (argumentNode != nullptr)
1460 {
1461 const char* argDirection =
1462 argumentNode->Attribute("direction");
1463 const char* argType =
1464 argumentNode->Attribute("type");
1465 if (argDirection != nullptr && argType != nullptr &&
1466 std::string(argDirection) == "in")
1467 {
1468 if (argIt == transaction->arguments.end())
1469 {
1470 transaction->setErrorStatus(
1471 "Invalid method args");
1472 return;
1473 }
1474 if (convertJsonToDbus(m.get(),
1475 std::string(argType),
1476 *argIt) < 0)
1477 {
1478 transaction->setErrorStatus(
1479 "Invalid method arg type");
1480 return;
1481 }
1482
1483 argIt++;
1484 }
1485 argumentNode =
1486 argumentNode->NextSiblingElement("arg");
1487 }
1488
1489 crow::connections::systemBus->async_send(
Patrick Williams5a39f772023-10-20 11:20:21 -05001490 m, [transaction, returnType](
1491 const boost::system::error_code& ec2,
1492 sdbusplus::message_t& m2) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001493 if (ec2)
1494 {
1495 transaction->methodFailed = true;
1496 const sd_bus_error* e = m2.get_error();
1497
1498 if (e != nullptr)
1499 {
1500 setErrorResponse(
Lei YU28dd5ca2023-03-17 13:17:05 +08001501 transaction->asyncResp->res,
Ed Tanous002d39b2022-05-31 08:59:27 -07001502 boost::beast::http::status::bad_request,
1503 e->name, e->message);
1504 }
1505 else
1506 {
1507 setErrorResponse(
Lei YU28dd5ca2023-03-17 13:17:05 +08001508 transaction->asyncResp->res,
Ed Tanous002d39b2022-05-31 08:59:27 -07001509 boost::beast::http::status::bad_request,
1510 "Method call failed", methodFailedMsg);
1511 }
1512 return;
1513 }
1514 transaction->methodPassed = true;
1515
1516 handleMethodResponse(transaction, m2, returnType);
Patrick Williams5a39f772023-10-20 11:20:21 -05001517 });
Ed Tanous002d39b2022-05-31 08:59:27 -07001518 break;
1519 }
1520 methodNode = methodNode->NextSiblingElement("method");
1521 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001522 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001523 interfaceNode = interfaceNode->NextSiblingElement("interface");
1524 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001525 },
Ed Tanous1abe55e2018-09-05 08:30:59 -07001526 connectionName, transaction->path,
1527 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001528}
1529
zhanghch058d1b46d2021-04-01 11:18:24 +08001530inline void handleAction(const crow::Request& req,
1531 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001532 const std::string& objectPath,
1533 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001534{
Ed Tanous62598e32023-07-17 17:06:25 -07001535 BMCWEB_LOG_DEBUG("handleAction on path: {} and method {}", objectPath,
1536 methodName);
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001537 nlohmann::json requestDbusData;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001538
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001539 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
1540 if (ret == JsonParseResult::BadContentType)
1541 {
1542 setErrorResponse(asyncResp->res,
1543 boost::beast::http::status::unsupported_media_type,
1544 invalidContentType, unsupportedMediaMsg);
1545 return;
1546 }
1547 if (ret != JsonParseResult::Success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001548 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001549 setErrorResponse(asyncResp->res,
1550 boost::beast::http::status::bad_request, noJsonDesc,
1551 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001552 return;
1553 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001554 nlohmann::json::iterator data = requestDbusData.find("data");
1555 if (data == requestDbusData.end())
1556 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001557 setErrorResponse(asyncResp->res,
1558 boost::beast::http::status::bad_request, noJsonDesc,
1559 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001560 return;
1561 }
1562
1563 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001564 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001565 setErrorResponse(asyncResp->res,
1566 boost::beast::http::status::bad_request, noJsonDesc,
1567 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001568 return;
1569 }
Lei YU28dd5ca2023-03-17 13:17:05 +08001570 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001571
1572 transaction->path = objectPath;
1573 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001574 transaction->arguments = std::move(*data);
George Liu2b731192023-01-11 16:27:13 +08001575 dbus::utility::getDbusObject(
1576 objectPath, {},
Ed Tanous1abe55e2018-09-05 08:30:59 -07001577 [transaction](
George Liu2b731192023-01-11 16:27:13 +08001578 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001579 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1580 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001581 if (ec || interfaceNames.empty())
1582 {
Ed Tanous62598e32023-07-17 17:06:25 -07001583 BMCWEB_LOG_ERROR("Can't find object");
Lei YU28dd5ca2023-03-17 13:17:05 +08001584 setErrorResponse(transaction->asyncResp->res,
Ed Tanous002d39b2022-05-31 08:59:27 -07001585 boost::beast::http::status::not_found,
1586 notFoundDesc, notFoundMsg);
1587 return;
1588 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001589
Ed Tanous62598e32023-07-17 17:06:25 -07001590 BMCWEB_LOG_DEBUG("GetObject returned {} object(s)",
1591 interfaceNames.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001592
Ed Tanous002d39b2022-05-31 08:59:27 -07001593 for (const std::pair<std::string, std::vector<std::string>>& object :
1594 interfaceNames)
1595 {
1596 findActionOnInterface(transaction, object.first);
1597 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001598 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001599}
1600
zhanghch058d1b46d2021-04-01 11:18:24 +08001601inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1602 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001603{
Ed Tanous62598e32023-07-17 17:06:25 -07001604 BMCWEB_LOG_DEBUG("handleDelete on path: {}", objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06001605
George Liu2b731192023-01-11 16:27:13 +08001606 dbus::utility::getDbusObject(
1607 objectPath, {},
zhanghch058d1b46d2021-04-01 11:18:24 +08001608 [asyncResp, objectPath](
George Liu2b731192023-01-11 16:27:13 +08001609 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001610 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1611 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001612 if (ec || interfaceNames.empty())
1613 {
Ed Tanous62598e32023-07-17 17:06:25 -07001614 BMCWEB_LOG_ERROR("Can't find object");
Ed Tanous002d39b2022-05-31 08:59:27 -07001615 setErrorResponse(asyncResp->res,
1616 boost::beast::http::status::method_not_allowed,
1617 methodNotAllowedDesc, methodNotAllowedMsg);
1618 return;
1619 }
Matt Spinlerde818812018-12-11 16:39:20 -06001620
Lei YU28dd5ca2023-03-17 13:17:05 +08001621 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001622 transaction->path = objectPath;
1623 transaction->methodName = "Delete";
1624 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
Matt Spinlerde818812018-12-11 16:39:20 -06001625
Ed Tanous002d39b2022-05-31 08:59:27 -07001626 for (const std::pair<std::string, std::vector<std::string>>& object :
1627 interfaceNames)
1628 {
1629 findActionOnInterface(transaction, object.first);
1630 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001631 });
Matt Spinlerde818812018-12-11 16:39:20 -06001632}
1633
zhanghch058d1b46d2021-04-01 11:18:24 +08001634inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1635 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001636{
George Liu7a1dbc42022-12-07 16:03:22 +08001637 dbus::utility::getSubTreePaths(
1638 objectPath, depth, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001639 [asyncResp](
George Liu7a1dbc42022-12-07 16:03:22 +08001640 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001641 const dbus::utility::MapperGetSubTreePathsResponse& objectPaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001642 if (ec)
1643 {
1644 setErrorResponse(asyncResp->res,
1645 boost::beast::http::status::not_found,
1646 notFoundDesc, notFoundMsg);
1647 }
1648 else
1649 {
1650 asyncResp->res.jsonValue["status"] = "ok";
1651 asyncResp->res.jsonValue["message"] = "200 OK";
1652 asyncResp->res.jsonValue["data"] = objectPaths;
1653 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001654 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001655}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001656
zhanghch058d1b46d2021-04-01 11:18:24 +08001657inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1658 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001659{
Ed Tanous62598e32023-07-17 17:06:25 -07001660 BMCWEB_LOG_DEBUG("Doing enumerate on {}", objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07001661
Ed Tanous14766872022-03-15 10:44:42 -07001662 asyncResp->res.jsonValue["message"] = "200 OK";
1663 asyncResp->res.jsonValue["status"] = "ok";
1664 asyncResp->res.jsonValue["data"] = nlohmann::json::object();
Ed Tanous049a0512018-11-01 13:58:42 -07001665
George Liue99073f2022-12-09 11:06:16 +08001666 dbus::utility::getSubTree(
1667 objectPath, 0, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001668 [objectPath, asyncResp](
George Liue99073f2022-12-09 11:06:16 +08001669 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001670 const dbus::utility::MapperGetSubTreeResponse& objectNames) {
Patrick Williams89492a12023-05-10 07:51:34 -05001671 auto transaction = std::make_shared<InProgressEnumerateData>(objectPath,
1672 asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001673
Ed Tanous002d39b2022-05-31 08:59:27 -07001674 transaction->subtree =
1675 std::make_shared<dbus::utility::MapperGetSubTreeResponse>(
1676 objectNames);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001677
Ed Tanous002d39b2022-05-31 08:59:27 -07001678 if (ec)
1679 {
Ed Tanous62598e32023-07-17 17:06:25 -07001680 BMCWEB_LOG_ERROR("GetSubTree failed on {}",
1681 transaction->objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07001682 setErrorResponse(transaction->asyncResp->res,
1683 boost::beast::http::status::not_found,
1684 notFoundDesc, notFoundMsg);
1685 return;
1686 }
Ed Tanous64530012018-02-06 17:08:16 -08001687
Ed Tanous002d39b2022-05-31 08:59:27 -07001688 // Add the data for the path passed in to the results
1689 // as if GetSubTree returned it, and continue on enumerating
1690 getObjectAndEnumerate(transaction);
Patrick Williams5a39f772023-10-20 11:20:21 -05001691 });
Ed Tanous64530012018-02-06 17:08:16 -08001692}
Ed Tanous911ac312017-08-15 09:37:42 -07001693
zhanghch058d1b46d2021-04-01 11:18:24 +08001694inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1695 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001696{
Ed Tanous62598e32023-07-17 17:06:25 -07001697 BMCWEB_LOG_DEBUG("handleGet: {} prop:{}", objectPath, destProperty);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001698 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001699 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001700
Ed Tanous1abe55e2018-09-05 08:30:59 -07001701 std::shared_ptr<std::string> path =
1702 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001703
George Liu2b731192023-01-11 16:27:13 +08001704 dbus::utility::getDbusObject(
1705 *path, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001706 [asyncResp, path,
George Liu2b731192023-01-11 16:27:13 +08001707 propertyName](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001708 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001709 if (ec || objectNames.empty())
1710 {
1711 setErrorResponse(asyncResp->res,
1712 boost::beast::http::status::not_found,
1713 notFoundDesc, notFoundMsg);
1714 return;
1715 }
1716 std::shared_ptr<nlohmann::json> response =
1717 std::make_shared<nlohmann::json>(nlohmann::json::object());
1718 // The mapper should never give us an empty interface names
1719 // list, but check anyway
1720 for (const std::pair<std::string, std::vector<std::string>>&
1721 connection : objectNames)
1722 {
1723 const std::vector<std::string>& interfaceNames = connection.second;
1724
1725 if (interfaceNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001726 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001727 setErrorResponse(asyncResp->res,
1728 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001729 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001730 return;
1731 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001732
1733 for (const std::string& interface : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001734 {
Patrick Williams59d494e2022-07-22 19:26:55 -05001735 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001736 crow::connections::systemBus->new_method_call(
1737 connection.first.c_str(), path->c_str(),
1738 "org.freedesktop.DBus.Properties", "GetAll");
1739 m.append(interface);
1740 crow::connections::systemBus->async_send(
1741 m, [asyncResp, response,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001742 propertyName](const boost::system::error_code& ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05001743 sdbusplus::message_t& msg) {
Patrick Williams5a39f772023-10-20 11:20:21 -05001744 if (ec2)
1745 {
1746 BMCWEB_LOG_ERROR("Bad dbus request error: {}", ec2);
1747 }
1748 else
1749 {
1750 nlohmann::json properties;
1751 int r = convertDBusToJSON("a{sv}", msg, properties);
1752 if (r < 0)
Ed Tanous002d39b2022-05-31 08:59:27 -07001753 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001754 BMCWEB_LOG_ERROR("convertDBusToJSON failed");
Ed Tanous002d39b2022-05-31 08:59:27 -07001755 }
1756 else
1757 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001758 for (const auto& prop : properties.items())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001759 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001760 // if property name is empty, or
1761 // matches our search query, add it
1762 // to the response json
Ed Tanous1abe55e2018-09-05 08:30:59 -07001763
Patrick Williams5a39f772023-10-20 11:20:21 -05001764 if (propertyName->empty())
1765 {
1766 (*response)[prop.key()] =
1767 std::move(prop.value());
1768 }
1769 else if (prop.key() == *propertyName)
1770 {
1771 *response = std::move(prop.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001772 }
1773 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001774 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001775 }
1776 if (response.use_count() == 1)
1777 {
1778 if (!propertyName->empty() && response->empty())
Ed Tanous002d39b2022-05-31 08:59:27 -07001779 {
Patrick Williams5a39f772023-10-20 11:20:21 -05001780 setErrorResponse(
1781 asyncResp->res,
1782 boost::beast::http::status::not_found,
1783 propNotFoundDesc, notFoundMsg);
Ed Tanous002d39b2022-05-31 08:59:27 -07001784 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001785 else
1786 {
1787 asyncResp->res.jsonValue["status"] = "ok";
1788 asyncResp->res.jsonValue["message"] = "200 OK";
1789 asyncResp->res.jsonValue["data"] = *response;
1790 }
1791 }
1792 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001793 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001794 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001795 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001796}
1797
Ed Tanous1abe55e2018-09-05 08:30:59 -07001798struct AsyncPutRequest
1799{
Ed Tanous4e23a442022-06-06 09:57:26 -07001800 explicit AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
zhanghch058d1b46d2021-04-01 11:18:24 +08001801 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001802 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001803 ~AsyncPutRequest()
1804 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001805 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001806 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001807 setErrorResponse(asyncResp->res,
1808 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001809 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001810 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001811 }
1812
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001813 AsyncPutRequest(const AsyncPutRequest&) = delete;
1814 AsyncPutRequest(AsyncPutRequest&&) = delete;
1815 AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1816 AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1817
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001818 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001819 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001820 setErrorResponse(asyncResp->res,
1821 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001822 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001823 }
1824
zhanghch058d1b46d2021-04-01 11:18:24 +08001825 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001826 std::string objectPath;
1827 std::string propertyName;
1828 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001829};
1830
zhanghch058d1b46d2021-04-01 11:18:24 +08001831inline void handlePut(const crow::Request& req,
1832 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001833 const std::string& objectPath,
1834 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001835{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001836 if (destProperty.empty())
1837 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001838 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001839 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001840 return;
1841 }
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001842 nlohmann::json requestDbusData;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001843
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001844 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
1845 if (ret == JsonParseResult::BadContentType)
1846 {
1847 setErrorResponse(asyncResp->res,
1848 boost::beast::http::status::unsupported_media_type,
1849 invalidContentType, unsupportedMediaMsg);
1850 return;
1851 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001852
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001853 if (ret != JsonParseResult::Success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001854 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001855 setErrorResponse(asyncResp->res,
1856 boost::beast::http::status::bad_request, noJsonDesc,
1857 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001858 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001859 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001860
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001861 auto propertyIt = requestDbusData.find("data");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001862 if (propertyIt == requestDbusData.end())
1863 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001864 setErrorResponse(asyncResp->res,
1865 boost::beast::http::status::bad_request, noJsonDesc,
1866 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001867 return;
1868 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001869 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001870 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001871 transaction->objectPath = objectPath;
1872 transaction->propertyName = destProperty;
1873 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001874
George Liu2b731192023-01-11 16:27:13 +08001875 dbus::utility::getDbusObject(
1876 transaction->objectPath, {},
1877 [transaction](const boost::system::error_code& ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001878 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001879 if (!ec2 && objectNames.empty())
1880 {
1881 setErrorResponse(transaction->asyncResp->res,
1882 boost::beast::http::status::not_found,
1883 propNotFoundDesc, notFoundMsg);
1884 return;
1885 }
Ed Tanous911ac312017-08-15 09:37:42 -07001886
Ed Tanous002d39b2022-05-31 08:59:27 -07001887 for (const std::pair<std::string, std::vector<std::string>>&
1888 connection : objectNames)
1889 {
1890 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001891
Ed Tanous002d39b2022-05-31 08:59:27 -07001892 crow::connections::systemBus->async_method_call(
1893 [connectionName{std::string(connectionName)},
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001894 transaction](const boost::system::error_code& ec3,
Ed Tanous002d39b2022-05-31 08:59:27 -07001895 const std::string& introspectXml) {
1896 if (ec3)
1897 {
Ed Tanous62598e32023-07-17 17:06:25 -07001898 BMCWEB_LOG_ERROR(
1899 "Introspect call failed with error: {} on process: {}",
1900 ec3.message(), connectionName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001901 transaction->setErrorStatus("Unexpected Error");
1902 return;
1903 }
1904 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001905
Ed Tanous002d39b2022-05-31 08:59:27 -07001906 doc.Parse(introspectXml.c_str());
1907 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1908 if (pRoot == nullptr)
1909 {
Ed Tanous62598e32023-07-17 17:06:25 -07001910 BMCWEB_LOG_ERROR("XML document failed to parse: {}",
1911 introspectXml);
Ed Tanous002d39b2022-05-31 08:59:27 -07001912 transaction->setErrorStatus("Unexpected Error");
1913 return;
1914 }
1915 tinyxml2::XMLElement* ifaceNode =
1916 pRoot->FirstChildElement("interface");
1917 while (ifaceNode != nullptr)
1918 {
1919 const char* interfaceName = ifaceNode->Attribute("name");
Ed Tanous62598e32023-07-17 17:06:25 -07001920 BMCWEB_LOG_DEBUG("found interface {}", interfaceName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001921 tinyxml2::XMLElement* propNode =
1922 ifaceNode->FirstChildElement("property");
1923 while (propNode != nullptr)
1924 {
1925 const char* propertyName = propNode->Attribute("name");
Ed Tanous62598e32023-07-17 17:06:25 -07001926 BMCWEB_LOG_DEBUG("Found property {}", propertyName);
Ed Tanous002d39b2022-05-31 08:59:27 -07001927 if (propertyName == transaction->propertyName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001928 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001929 const char* argType = propNode->Attribute("type");
1930 if (argType != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001931 {
Patrick Williams59d494e2022-07-22 19:26:55 -05001932 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001933 crow::connections::systemBus
1934 ->new_method_call(
1935 connectionName.c_str(),
1936 transaction->objectPath.c_str(),
1937 "org.freedesktop.DBus."
1938 "Properties",
1939 "Set");
1940 m.append(interfaceName,
1941 transaction->propertyName);
1942 int r = sd_bus_message_open_container(
1943 m.get(), SD_BUS_TYPE_VARIANT, argType);
1944 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001945 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001946 transaction->setErrorStatus(
1947 "Unexpected Error");
1948 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001949 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001950 r = convertJsonToDbus(
1951 m.get(), argType,
1952 transaction->propertyValue);
1953 if (r < 0)
1954 {
1955 if (r == -ERANGE)
1956 {
1957 transaction->setErrorStatus(
1958 "Provided property value "
1959 "is out of range for the "
1960 "property type");
1961 }
1962 else
1963 {
1964 transaction->setErrorStatus(
1965 "Invalid arg type");
1966 }
1967 return;
1968 }
1969 r = sd_bus_message_close_container(m.get());
1970 if (r < 0)
1971 {
1972 transaction->setErrorStatus(
1973 "Unexpected Error");
1974 return;
1975 }
1976 crow::connections::systemBus->async_send(
Patrick Williams5a39f772023-10-20 11:20:21 -05001977 m, [transaction](
1978 const boost::system::error_code& ec,
1979 sdbusplus::message_t& m2) {
Ed Tanous62598e32023-07-17 17:06:25 -07001980 BMCWEB_LOG_DEBUG("sent");
Ed Tanous002d39b2022-05-31 08:59:27 -07001981 if (ec)
1982 {
1983 const sd_bus_error* e = m2.get_error();
1984 setErrorResponse(
1985 transaction->asyncResp->res,
1986 boost::beast::http::status::
1987 forbidden,
1988 (e) != nullptr
1989 ? e->name
1990 : ec.category().name(),
1991 (e) != nullptr ? e->message
1992 : ec.message());
1993 }
1994 else
1995 {
1996 transaction->asyncResp->res
1997 .jsonValue["status"] = "ok";
1998 transaction->asyncResp->res
1999 .jsonValue["message"] = "200 OK";
2000 transaction->asyncResp->res
2001 .jsonValue["data"] = nullptr;
2002 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002003 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002004 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002005 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002006 propNode = propNode->NextSiblingElement("property");
2007 }
2008 ifaceNode = ifaceNode->NextSiblingElement("interface");
2009 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002010 },
Ed Tanous002d39b2022-05-31 08:59:27 -07002011 connectionName, transaction->objectPath,
2012 "org.freedesktop.DBus.Introspectable", "Introspect");
2013 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002014 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07002015}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002016
zhanghch058d1b46d2021-04-01 11:18:24 +08002017inline void handleDBusUrl(const crow::Request& req,
2018 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002019 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002020{
Ed Tanous049a0512018-11-01 13:58:42 -07002021 // If accessing a single attribute, fill in and update objectPath,
2022 // otherwise leave destProperty blank
Ed Tanouse05aec52022-01-25 10:28:56 -08002023 std::string destProperty;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002024 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002025 size_t attrPosition = objectPath.find(attrSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002026 if (attrPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002027 {
2028 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2029 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002030 objectPath.resize(attrPosition);
Ed Tanous049a0512018-11-01 13:58:42 -07002031 }
2032
Ed Tanousb41187f2019-10-24 16:30:02 -07002033 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002034 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002035 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002036 size_t actionPosition = objectPath.find(actionSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002037 if (actionPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002038 {
2039 std::string postProperty =
2040 objectPath.substr((actionPosition + strlen(actionSeperator)),
2041 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002042 objectPath.resize(actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002043 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002044 return;
2045 }
2046 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002047 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002048 {
Ed Tanous11ba3972022-07-11 09:50:41 -07002049 if (objectPath.ends_with("/enumerate"))
Ed Tanous049a0512018-11-01 13:58:42 -07002050 {
2051 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2052 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002053 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002054 }
Ed Tanous11ba3972022-07-11 09:50:41 -07002055 else if (objectPath.ends_with("/list"))
Ed Tanous049a0512018-11-01 13:58:42 -07002056 {
2057 objectPath.erase(objectPath.end() - sizeof("list"),
2058 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002059 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002060 }
2061 else
2062 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002063 // Trim any trailing "/" at the end
Ed Tanous11ba3972022-07-11 09:50:41 -07002064 if (objectPath.ends_with("/"))
Ed Tanousf839dfe2018-11-12 11:11:15 -08002065 {
2066 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002067 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002068 }
2069 else
2070 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002071 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002072 }
Ed Tanous049a0512018-11-01 13:58:42 -07002073 }
2074 return;
2075 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002076 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002077 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002078 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002079 return;
2080 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002081 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002082 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002083 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002084 return;
2085 }
Ed Tanous049a0512018-11-01 13:58:42 -07002086
zhanghch058d1b46d2021-04-01 11:18:24 +08002087 setErrorResponse(asyncResp->res,
2088 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002089 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002090}
2091
Ed Tanous1656b292022-05-04 11:33:42 -07002092inline void
2093 handleBusSystemPost(const crow::Request& req,
2094 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2095 const std::string& processName,
2096 const std::string& requestedPath)
2097{
2098 std::vector<std::string> strs;
Ed Tanous50ebd4a2023-01-19 19:03:17 -08002099
2100 bmcweb::split(strs, requestedPath, '/');
Ed Tanous1656b292022-05-04 11:33:42 -07002101 std::string objectPath;
2102 std::string interfaceName;
2103 std::string methodName;
2104 auto it = strs.begin();
2105 if (it == strs.end())
2106 {
2107 objectPath = "/";
2108 }
2109 while (it != strs.end())
2110 {
2111 // Check if segment contains ".". If it does, it must be an
2112 // interface
2113 if (it->find(".") != std::string::npos)
2114 {
2115 break;
2116 // This check is necessary as the trailing slash gets
2117 // parsed as part of our <path> specifier above, which
2118 // causes the normal trailing backslash redirector to
2119 // fail.
2120 }
2121 if (!it->empty())
2122 {
2123 objectPath += "/" + *it;
2124 }
2125 it++;
2126 }
2127 if (it != strs.end())
2128 {
2129 interfaceName = *it;
2130 it++;
2131
2132 // after interface, we might have a method name
2133 if (it != strs.end())
2134 {
2135 methodName = *it;
2136 it++;
2137 }
2138 }
2139 if (it != strs.end())
2140 {
2141 // if there is more levels past the method name, something
2142 // went wrong, return not found
2143 asyncResp->res.result(boost::beast::http::status::not_found);
2144 return;
2145 }
2146 if (interfaceName.empty())
2147 {
2148 crow::connections::systemBus->async_method_call(
2149 [asyncResp, processName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002150 objectPath](const boost::system::error_code& ec,
Ed Tanous1656b292022-05-04 11:33:42 -07002151 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002152 if (ec)
2153 {
Ed Tanous62598e32023-07-17 17:06:25 -07002154 BMCWEB_LOG_ERROR(
2155 "Introspect call failed with error: {} on process: {} path: {}",
2156 ec.message(), processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002157 return;
2158 }
2159 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002160
Ed Tanous002d39b2022-05-31 08:59:27 -07002161 doc.Parse(introspectXml.c_str());
2162 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2163 if (pRoot == nullptr)
2164 {
Ed Tanous62598e32023-07-17 17:06:25 -07002165 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
2166 processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002167 asyncResp->res.jsonValue["status"] = "XML parse error";
2168 asyncResp->res.result(
2169 boost::beast::http::status::internal_server_error);
2170 return;
2171 }
2172
Ed Tanous62598e32023-07-17 17:06:25 -07002173 BMCWEB_LOG_DEBUG("{}", introspectXml);
Ed Tanous002d39b2022-05-31 08:59:27 -07002174 asyncResp->res.jsonValue["status"] = "ok";
2175 asyncResp->res.jsonValue["bus_name"] = processName;
2176 asyncResp->res.jsonValue["object_path"] = objectPath;
2177
2178 nlohmann::json& interfacesArray =
2179 asyncResp->res.jsonValue["interfaces"];
2180 interfacesArray = nlohmann::json::array();
2181 tinyxml2::XMLElement* interface =
2182 pRoot->FirstChildElement("interface");
2183
2184 while (interface != nullptr)
2185 {
2186 const char* ifaceName = interface->Attribute("name");
2187 if (ifaceName != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002188 {
Ed Tanous8a592812022-06-04 09:06:59 -07002189 nlohmann::json::object_t interfaceObj;
2190 interfaceObj["name"] = ifaceName;
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002191 interfacesArray.emplace_back(std::move(interfaceObj));
Ed Tanous1656b292022-05-04 11:33:42 -07002192 }
2193
Ed Tanous002d39b2022-05-31 08:59:27 -07002194 interface = interface->NextSiblingElement("interface");
2195 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002196 },
Ed Tanous1656b292022-05-04 11:33:42 -07002197 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2198 "Introspect");
2199 }
2200 else if (methodName.empty())
2201 {
2202 crow::connections::systemBus->async_method_call(
2203 [asyncResp, processName, objectPath,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002204 interfaceName](const boost::system::error_code& ec,
Ed Tanous1656b292022-05-04 11:33:42 -07002205 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002206 if (ec)
2207 {
Ed Tanous62598e32023-07-17 17:06:25 -07002208 BMCWEB_LOG_ERROR(
2209 "Introspect call failed with error: {} on process: {} path: {}",
2210 ec.message(), processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002211 return;
2212 }
2213 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002214
Ed Tanous002d39b2022-05-31 08:59:27 -07002215 doc.Parse(introspectXml.data(), introspectXml.size());
2216 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2217 if (pRoot == nullptr)
2218 {
Ed Tanous62598e32023-07-17 17:06:25 -07002219 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
2220 processName, objectPath);
Ed Tanous002d39b2022-05-31 08:59:27 -07002221 asyncResp->res.result(
2222 boost::beast::http::status::internal_server_error);
2223 return;
2224 }
2225
2226 asyncResp->res.jsonValue["status"] = "ok";
2227 asyncResp->res.jsonValue["bus_name"] = processName;
2228 asyncResp->res.jsonValue["interface"] = interfaceName;
2229 asyncResp->res.jsonValue["object_path"] = objectPath;
2230
2231 nlohmann::json& methodsArray = asyncResp->res.jsonValue["methods"];
2232 methodsArray = nlohmann::json::array();
2233
2234 nlohmann::json& signalsArray = asyncResp->res.jsonValue["signals"];
2235 signalsArray = nlohmann::json::array();
2236
2237 nlohmann::json& propertiesObj =
2238 asyncResp->res.jsonValue["properties"];
2239 propertiesObj = nlohmann::json::object();
2240
2241 // if we know we're the only call, build the
2242 // json directly
2243 tinyxml2::XMLElement* interface =
2244 pRoot->FirstChildElement("interface");
2245 while (interface != nullptr)
2246 {
2247 const char* ifaceName = interface->Attribute("name");
2248
2249 if (ifaceName != nullptr && ifaceName == interfaceName)
Ed Tanous1656b292022-05-04 11:33:42 -07002250 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002251 break;
Ed Tanous1656b292022-05-04 11:33:42 -07002252 }
Ed Tanous14766872022-03-15 10:44:42 -07002253
Ed Tanous002d39b2022-05-31 08:59:27 -07002254 interface = interface->NextSiblingElement("interface");
2255 }
2256 if (interface == nullptr)
2257 {
2258 // if we got to the end of the list and
2259 // never found a match, throw 404
2260 asyncResp->res.result(boost::beast::http::status::not_found);
2261 return;
2262 }
Ed Tanous1656b292022-05-04 11:33:42 -07002263
Ed Tanous002d39b2022-05-31 08:59:27 -07002264 tinyxml2::XMLElement* methods =
2265 interface->FirstChildElement("method");
2266 while (methods != nullptr)
2267 {
2268 nlohmann::json argsArray = nlohmann::json::array();
2269 tinyxml2::XMLElement* arg = methods->FirstChildElement("arg");
2270 while (arg != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002271 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002272 nlohmann::json thisArg;
2273 for (const char* fieldName : std::array<const char*, 3>{
2274 "name", "direction", "type"})
Ed Tanous1656b292022-05-04 11:33:42 -07002275 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002276 const char* fieldValue = arg->Attribute(fieldName);
2277 if (fieldValue != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002278 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002279 thisArg[fieldName] = fieldValue;
2280 }
2281 }
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002282 argsArray.emplace_back(std::move(thisArg));
Ed Tanous002d39b2022-05-31 08:59:27 -07002283 arg = arg->NextSiblingElement("arg");
2284 }
2285
2286 const char* name = methods->Attribute("name");
2287 if (name != nullptr)
2288 {
2289 std::string uri;
2290 uri.reserve(14 + processName.size() + objectPath.size() +
2291 interfaceName.size() + strlen(name));
2292 uri += "/bus/system/";
2293 uri += processName;
2294 uri += objectPath;
2295 uri += "/";
2296 uri += interfaceName;
2297 uri += "/";
2298 uri += name;
2299
2300 nlohmann::json::object_t object;
2301 object["name"] = name;
2302 object["uri"] = std::move(uri);
2303 object["args"] = argsArray;
2304
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002305 methodsArray.emplace_back(std::move(object));
Ed Tanous002d39b2022-05-31 08:59:27 -07002306 }
2307 methods = methods->NextSiblingElement("method");
2308 }
2309 tinyxml2::XMLElement* signals =
2310 interface->FirstChildElement("signal");
2311 while (signals != nullptr)
2312 {
2313 nlohmann::json argsArray = nlohmann::json::array();
2314
2315 tinyxml2::XMLElement* arg = signals->FirstChildElement("arg");
2316 while (arg != nullptr)
2317 {
2318 const char* name = arg->Attribute("name");
2319 const char* type = arg->Attribute("type");
2320 if (name != nullptr && type != nullptr)
2321 {
2322 argsArray.push_back({
2323 {"name", name},
2324 {"type", type},
2325 });
2326 }
2327 arg = arg->NextSiblingElement("arg");
2328 }
2329 const char* name = signals->Attribute("name");
2330 if (name != nullptr)
2331 {
2332 nlohmann::json::object_t object;
2333 object["name"] = name;
2334 object["args"] = argsArray;
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002335 signalsArray.emplace_back(std::move(object));
Ed Tanous002d39b2022-05-31 08:59:27 -07002336 }
2337
2338 signals = signals->NextSiblingElement("signal");
2339 }
2340
2341 tinyxml2::XMLElement* property =
2342 interface->FirstChildElement("property");
2343 while (property != nullptr)
2344 {
2345 const char* name = property->Attribute("name");
2346 const char* type = property->Attribute("type");
2347 if (type != nullptr && name != nullptr)
2348 {
Patrick Williams59d494e2022-07-22 19:26:55 -05002349 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07002350 crow::connections::systemBus->new_method_call(
2351 processName.c_str(), objectPath.c_str(),
2352 "org.freedesktop."
2353 "DBus."
2354 "Properties",
2355 "Get");
2356 m.append(interfaceName, name);
2357 nlohmann::json& propertyItem = propertiesObj[name];
2358 crow::connections::systemBus->async_send(
2359 m, [&propertyItem,
Ed Tanous8b242752023-06-27 17:17:13 -07002360 asyncResp](const boost::system::error_code& ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05002361 sdbusplus::message_t& msg) {
Patrick Williams5a39f772023-10-20 11:20:21 -05002362 if (ec2)
2363 {
2364 return;
2365 }
Ed Tanous1656b292022-05-04 11:33:42 -07002366
Patrick Williams5a39f772023-10-20 11:20:21 -05002367 convertDBusToJSON("v", msg, propertyItem);
2368 });
Ed Tanous1656b292022-05-04 11:33:42 -07002369 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002370 property = property->NextSiblingElement("property");
2371 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002372 },
Ed Tanous1656b292022-05-04 11:33:42 -07002373 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2374 "Introspect");
2375 }
2376 else
2377 {
2378 if (req.method() != boost::beast::http::verb::post)
2379 {
2380 asyncResp->res.result(boost::beast::http::status::not_found);
2381 return;
2382 }
2383
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002384 nlohmann::json requestDbusData;
2385 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
2386 if (ret == JsonParseResult::BadContentType)
Ed Tanous1656b292022-05-04 11:33:42 -07002387 {
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002388 setErrorResponse(asyncResp->res,
2389 boost::beast::http::status::unsupported_media_type,
2390 invalidContentType, unsupportedMediaMsg);
Ed Tanous1656b292022-05-04 11:33:42 -07002391 return;
2392 }
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002393 if (ret != JsonParseResult::Success)
2394 {
2395 setErrorResponse(asyncResp->res,
2396 boost::beast::http::status::bad_request,
2397 noJsonDesc, badReqMsg);
2398 return;
2399 }
2400
Ed Tanous1656b292022-05-04 11:33:42 -07002401 if (!requestDbusData.is_array())
2402 {
2403 asyncResp->res.result(boost::beast::http::status::bad_request);
2404 return;
2405 }
Lei YU28dd5ca2023-03-17 13:17:05 +08002406 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous1656b292022-05-04 11:33:42 -07002407
2408 transaction->path = objectPath;
2409 transaction->methodName = methodName;
2410 transaction->arguments = std::move(requestDbusData);
2411
2412 findActionOnInterface(transaction, processName);
2413 }
2414}
2415
Ed Tanous23a21a12020-07-25 04:45:05 +00002416inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002417{
2418 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002419 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002420 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002421 [](const crow::Request&,
2422 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002423 nlohmann::json::array_t buses;
2424 nlohmann::json& bus = buses.emplace_back();
2425 bus["name"] = "system";
2426 asyncResp->res.jsonValue["busses"] = std::move(buses);
2427 asyncResp->res.jsonValue["status"] = "ok";
Patrick Williams5a39f772023-10-20 11:20:21 -05002428 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002429
2430 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002431 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002432 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002433 [](const crow::Request&,
2434 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002435 auto myCallback = [asyncResp](const boost::system::error_code& ec,
zhanghch058d1b46d2021-04-01 11:18:24 +08002436 std::vector<std::string>& names) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002437 if (ec)
2438 {
Ed Tanous62598e32023-07-17 17:06:25 -07002439 BMCWEB_LOG_ERROR("Dbus call failed with code {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07002440 asyncResp->res.result(
2441 boost::beast::http::status::internal_server_error);
2442 }
2443 else
2444 {
Ed Tanous3544d2a2023-08-06 18:12:20 -07002445 std::ranges::sort(names);
Ed Tanous002d39b2022-05-31 08:59:27 -07002446 asyncResp->res.jsonValue["status"] = "ok";
2447 auto& objectsSub = asyncResp->res.jsonValue["objects"];
Ed Tanous02cad962022-06-30 16:50:15 -07002448 for (const auto& name : names)
Ed Tanous002d39b2022-05-31 08:59:27 -07002449 {
2450 nlohmann::json::object_t object;
2451 object["name"] = name;
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002452 objectsSub.emplace_back(std::move(object));
Ed Tanous002d39b2022-05-31 08:59:27 -07002453 }
2454 }
2455 };
2456 crow::connections::systemBus->async_method_call(
2457 std::move(myCallback), "org.freedesktop.DBus", "/",
2458 "org.freedesktop.DBus", "ListNames");
Patrick Williams5a39f772023-10-20 11:20:21 -05002459 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002460
2461 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002462 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002463 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002464 [](const crow::Request&,
2465 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002466 handleList(asyncResp, "/");
Patrick Williams5a39f772023-10-20 11:20:21 -05002467 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002468
2469 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002470 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002471 .methods(boost::beast::http::verb::get)(
2472 [](const crow::Request& req,
2473 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002474 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002475 std::string objectPath = "/xyz/" + path;
2476 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002477 });
zhanghch058d1b46d2021-04-01 11:18:24 +08002478
2479 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002480 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002481 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2482 boost::beast::http::verb::delete_)(
2483 [](const crow::Request& req,
2484 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2485 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002486 std::string objectPath = "/xyz/" + path;
2487 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002488 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002489
Ed Tanous049a0512018-11-01 13:58:42 -07002490 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002491 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002492 .methods(boost::beast::http::verb::get)(
2493 [](const crow::Request& req,
2494 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2495 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002496 std::string objectPath = "/org/" + path;
2497 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002498 });
Tanousf00032d2018-11-05 01:18:10 -03002499
2500 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002501 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002502 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2503 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002504 [](const crow::Request& req,
2505 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002506 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002507 std::string objectPath = "/org/" + path;
2508 handleDBusUrl(req, asyncResp, objectPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05002509 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002510
Ed Tanous1abe55e2018-09-05 08:30:59 -07002511 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002512 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002513 .methods(boost::beast::http::verb::get)(
2514 [](const crow::Request&,
2515 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2516 const std::string& dumpId) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002517 if (!validateFilename(dumpId))
2518 {
2519 asyncResp->res.result(boost::beast::http::status::bad_request);
2520 return;
2521 }
2522 std::filesystem::path loc("/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002523
Ed Tanous002d39b2022-05-31 08:59:27 -07002524 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002525
Ed Tanous002d39b2022-05-31 08:59:27 -07002526 if (!std::filesystem::exists(loc) ||
2527 !std::filesystem::is_directory(loc))
2528 {
Ed Tanous62598e32023-07-17 17:06:25 -07002529 BMCWEB_LOG_ERROR("{}Not found", loc.string());
Ed Tanous002d39b2022-05-31 08:59:27 -07002530 asyncResp->res.result(boost::beast::http::status::not_found);
2531 return;
2532 }
2533 std::filesystem::directory_iterator files(loc);
zhanghch058d1b46d2021-04-01 11:18:24 +08002534
Ed Tanous002d39b2022-05-31 08:59:27 -07002535 for (const auto& file : files)
2536 {
Ed Tanous27b0cf92023-08-07 12:02:40 -07002537 if (!asyncResp->res.openFile(file))
Ed Tanous002d39b2022-05-31 08:59:27 -07002538 {
2539 continue;
2540 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002541
Ed Tanousd9f6c622022-03-17 09:12:17 -07002542 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07002543 "application/octet-stream");
zhanghch058d1b46d2021-04-01 11:18:24 +08002544
Ed Tanous002d39b2022-05-31 08:59:27 -07002545 // Assuming only one dump file will be present in the dump
2546 // id directory
2547 std::string dumpFileName = file.path().filename().string();
zhanghch058d1b46d2021-04-01 11:18:24 +08002548
Ed Tanous002d39b2022-05-31 08:59:27 -07002549 // Filename should be in alphanumeric, dot and underscore
2550 // Its based on phosphor-debug-collector application
2551 // dumpfile format
Ed Tanous4b242742023-05-11 09:51:51 -07002552 static std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
Ed Tanous002d39b2022-05-31 08:59:27 -07002553 if (!std::regex_match(dumpFileName, dumpFileRegex))
2554 {
Ed Tanous62598e32023-07-17 17:06:25 -07002555 BMCWEB_LOG_ERROR("Invalid dump filename {}", dumpFileName);
zhanghch058d1b46d2021-04-01 11:18:24 +08002556 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002557 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07002558 }
Patrick Williams89492a12023-05-10 07:51:34 -05002559 std::string contentDispositionParam = "attachment; filename=\"" +
2560 dumpFileName + "\"";
Ed Tanous002d39b2022-05-31 08:59:27 -07002561
Ed Tanousd9f6c622022-03-17 09:12:17 -07002562 asyncResp->res.addHeader(
2563 boost::beast::http::field::content_disposition,
2564 contentDispositionParam);
Ed Tanous002d39b2022-05-31 08:59:27 -07002565
Ed Tanous002d39b2022-05-31 08:59:27 -07002566 return;
2567 }
2568 asyncResp->res.result(boost::beast::http::status::not_found);
2569 return;
Patrick Williams5a39f772023-10-20 11:20:21 -05002570 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002571
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002572 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002573 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002574
2575 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002576 [](const crow::Request&,
2577 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002578 const std::string& connection) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002579 introspectObjects(connection, "/", asyncResp);
Patrick Williams5a39f772023-10-20 11:20:21 -05002580 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002581
2582 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002583 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous1656b292022-05-04 11:33:42 -07002584 .methods(boost::beast::http::verb::get,
2585 boost::beast::http::verb::post)(handleBusSystemPost);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002586}
2587} // namespace openbmc_mapper
2588} // namespace crow