blob: 5bdc4ec0b704dcf184080ad838fb88bc44fea47e [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>
Ramesh Iyyard9207042019-07-05 08:04:42 -050059#include <regex>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000060#include <string>
61#include <string_view>
62#include <type_traits>
Ed Tanousb5a76932020-09-29 16:16:58 -070063#include <utility>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000064#include <variant>
65#include <vector>
66
67// IWYU pragma: no_include <boost/algorithm/string/detail/classification.hpp>
68// IWYU pragma: no_include <boost/system/detail/error_code.hpp>
69// IWYU pragma: no_include <boost/system/detail/error_category.hpp>
70// IWYU pragma: no_include <errno.h>
71// IWYU pragma: no_include <string.h>
72// IWYU pragma: no_include <ext/alloc_traits.h>
73// IWYU pragma: no_include <exception>
74// IWYU pragma: no_include <boost/type_index/type_index_facade.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -070075
Ed Tanous1abe55e2018-09-05 08:30:59 -070076namespace crow
77{
78namespace openbmc_mapper
79{
Ed Tanous23a21a12020-07-25 04:45:05 +000080const constexpr char* notFoundMsg = "404 Not Found";
81const constexpr char* badReqMsg = "400 Bad Request";
82const constexpr char* methodNotAllowedMsg = "405 Method Not Allowed";
83const constexpr char* forbiddenMsg = "403 Forbidden";
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010084const constexpr char* unsupportedMediaMsg = "415 Unsupported Media Type";
Ed Tanous23a21a12020-07-25 04:45:05 +000085const constexpr char* methodFailedMsg = "500 Method Call Failed";
86const constexpr char* methodOutputFailedMsg = "500 Method Output Error";
87const constexpr char* notFoundDesc =
Matt Spinler2ae60092018-12-06 10:35:36 -060088 "org.freedesktop.DBus.Error.FileNotFound: path or object not found";
Ed Tanous23a21a12020-07-25 04:45:05 +000089const constexpr char* propNotFoundDesc =
90 "The specified property cannot be found";
91const constexpr char* noJsonDesc = "No JSON object could be decoded";
Ed Tanous1aa0c2b2022-02-08 12:24:30 +010092const constexpr char* invalidContentType =
93 "Content-type header is missing or invalid";
Ed Tanous23a21a12020-07-25 04:45:05 +000094const constexpr char* methodNotFoundDesc =
95 "The specified method cannot be found";
96const constexpr char* methodNotAllowedDesc = "Method not allowed";
97const constexpr char* forbiddenPropDesc =
98 "The specified property cannot be created";
99const constexpr char* forbiddenResDesc =
100 "The specified resource cannot be created";
Matt Spinler2ae60092018-12-06 10:35:36 -0600101
Josh Lehan482c45a2022-03-29 17:10:44 -0700102inline bool validateFilename(const std::string& filename)
103{
104 std::regex validFilename(R"(^[\w\- ]+(\.?[\w\- ]*)$)");
105
106 return std::regex_match(filename, validFilename);
107}
108
Ed Tanous23a21a12020-07-25 04:45:05 +0000109inline void setErrorResponse(crow::Response& res,
110 boost::beast::http::status result,
Ed Tanous26ccae32023-02-16 10:28:44 -0800111 const std::string& desc, std::string_view msg)
Matt Spinler2ae60092018-12-06 10:35:36 -0600112{
113 res.result(result);
Ed Tanous14766872022-03-15 10:44:42 -0700114 res.jsonValue["data"]["description"] = desc;
115 res.jsonValue["message"] = msg;
116 res.jsonValue["status"] = "error";
Matt Spinler2ae60092018-12-06 10:35:36 -0600117}
118
Ed Tanousb5a76932020-09-29 16:16:58 -0700119inline void
120 introspectObjects(const std::string& processName,
121 const std::string& objectPath,
122 const std::shared_ptr<bmcweb::AsyncResp>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123{
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700124 if (transaction->res.jsonValue.is_null())
125 {
Ed Tanous14766872022-03-15 10:44:42 -0700126 transaction->res.jsonValue["status"] = "ok";
127 transaction->res.jsonValue["bus_name"] = processName;
128 transaction->res.jsonValue["objects"] = nlohmann::json::array();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700129 }
130
Ed Tanous1abe55e2018-09-05 08:30:59 -0700131 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700132 [transaction, processName{std::string(processName)},
133 objectPath{std::string(objectPath)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800134 const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +0000135 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700136 if (ec)
137 {
138 BMCWEB_LOG_ERROR
139 << "Introspect call failed with error: " << ec.message()
140 << " on process: " << processName << " path: " << objectPath
141 << "\n";
142 return;
143 }
144 nlohmann::json::object_t object;
145 object["path"] = objectPath;
Ed Tanous14766872022-03-15 10:44:42 -0700146
Ed Tanous002d39b2022-05-31 08:59:27 -0700147 transaction->res.jsonValue["objects"].push_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 {
155 BMCWEB_LOG_ERROR << "XML document failed to parse " << processName
156 << " " << objectPath << "\n";
157 }
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 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700179 },
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{
189 BMCWEB_LOG_DEBUG << "getPropertiesForEnumerate " << objectPath << " "
190 << service << " " << interface;
191
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 {
199 BMCWEB_LOG_ERROR << "GetAll on path " << objectPath << " iface "
200 << interface << " service " << service
201 << " failed with code " << ec;
202 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 Tanousd1a64812021-12-13 12:14:05 -0800224
Ed Tanous002d39b2022-05-31 08:59:27 -0700225 propertyJson = val;
226 }
227 },
228 value);
229 }
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +0200230 });
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600231}
232
233// Find any results that weren't picked up by ObjectManagers, to be
234// called after all ObjectManagers are searched for and called.
Ed Tanous23a21a12020-07-25 04:45:05 +0000235inline void findRemainingObjectsForEnumerate(
Ed Tanousb5a76932020-09-29 16:16:58 -0700236 const std::string& objectPath,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800237 const std::shared_ptr<dbus::utility::MapperGetSubTreeResponse>& subtree,
Ed Tanousb5a76932020-09-29 16:16:58 -0700238 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600239{
240 BMCWEB_LOG_DEBUG << "findRemainingObjectsForEnumerate";
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500241 const nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600242
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500243 for (const auto& [path, interface_map] : *subtree)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600244 {
245 if (path == objectPath)
246 {
247 // An enumerate does not return the target path's properties
248 continue;
249 }
250 if (dataJson.find(path) == dataJson.end())
251 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500252 for (const auto& [service, interfaces] : interface_map)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600253 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500254 for (const auto& interface : interfaces)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600255 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700256 if (!interface.starts_with("org.freedesktop.DBus"))
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600257 {
258 getPropertiesForEnumerate(path, service, interface,
259 asyncResp);
260 }
261 }
262 }
263 }
264 }
265}
266
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600267struct InProgressEnumerateData
268{
zhanghch058d1b46d2021-04-01 11:18:24 +0800269 InProgressEnumerateData(
270 const std::string& objectPathIn,
271 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
Ed Tanous23a21a12020-07-25 04:45:05 +0000272 objectPath(objectPathIn),
zhanghch058d1b46d2021-04-01 11:18:24 +0800273 asyncResp(asyncRespIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500274 {}
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600275
276 ~InProgressEnumerateData()
277 {
Ed Tanous24b2fe82022-01-06 12:45:54 -0800278 try
279 {
280 findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
281 }
282 catch (...)
283 {
284 BMCWEB_LOG_CRITICAL
285 << "findRemainingObjectsForEnumerate threw exception";
286 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600287 }
288
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800289 InProgressEnumerateData(const InProgressEnumerateData&) = delete;
290 InProgressEnumerateData(InProgressEnumerateData&&) = delete;
291 InProgressEnumerateData& operator=(const InProgressEnumerateData&) = delete;
292 InProgressEnumerateData& operator=(InProgressEnumerateData&&) = delete;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600293 const std::string objectPath;
Ed Tanousb9d36b42022-02-26 21:42:46 -0800294 std::shared_ptr<dbus::utility::MapperGetSubTreeResponse> subtree;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600295 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
296};
297
Ed Tanous23a21a12020-07-25 04:45:05 +0000298inline void getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000299 const std::string& objectName, const std::string& objectManagerPath,
300 const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700301 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700302{
Ed Tanous81ce6092020-12-17 16:54:55 +0000303 BMCWEB_LOG_DEBUG << "getManagedObjectsForEnumerate " << objectName
304 << " object_manager_path " << objectManagerPath
305 << " connection_name " << connectionName;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700306 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000307 [transaction, objectName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800308 connectionName](const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +0000309 const dbus::utility::ManagedObjectType& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700310 if (ec)
311 {
312 BMCWEB_LOG_ERROR << "GetManagedObjects on path " << objectName
313 << " on connection " << connectionName
314 << " failed with code " << ec;
315 return;
316 }
Ed Tanous64530012018-02-06 17:08:16 -0800317
Ed Tanous002d39b2022-05-31 08:59:27 -0700318 nlohmann::json& dataJson =
319 transaction->asyncResp->res.jsonValue["data"];
Ed Tanous049a0512018-11-01 13:58:42 -0700320
Ed Tanous002d39b2022-05-31 08:59:27 -0700321 for (const auto& objectPath : objects)
322 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700323 if (objectPath.first.str.starts_with(objectName))
Ed Tanous049a0512018-11-01 13:58:42 -0700324 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700325 BMCWEB_LOG_DEBUG << "Reading object " << objectPath.first.str;
326 nlohmann::json& objectJson = dataJson[objectPath.first.str];
327 if (objectJson.is_null())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700328 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700329 objectJson = nlohmann::json::object();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700330 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500331 for (const auto& interface : objectPath.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700332 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700333 for (const auto& property : interface.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700334 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700335 nlohmann::json& propertyJson =
336 objectJson[property.first];
337 std::visit(
338 [&propertyJson](auto&& val) {
339 if constexpr (std::is_same_v<
340 std::decay_t<decltype(val)>,
341 sdbusplus::message::unix_fd>)
342 {
343 propertyJson = val.fd;
344 }
345 else
346 {
347
348 propertyJson = val;
349 }
350 },
351 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 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700365 },
Ed Tanous81ce6092020-12-17 16:54:55 +0000366 connectionName, objectManagerPath, "org.freedesktop.DBus.ObjectManager",
367 "GetManagedObjects");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700368}
369
Ed Tanous23a21a12020-07-25 04:45:05 +0000370inline void findObjectManagerPathForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000371 const std::string& objectName, const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700372 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700373{
Ed Tanous81ce6092020-12-17 16:54:55 +0000374 BMCWEB_LOG_DEBUG << "Finding objectmanager for path " << objectName
375 << " on connection:" << connectionName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700376 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000377 [transaction, objectName, connectionName](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800378 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800379 const dbus::utility::MapperGetAncestorsResponse& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700380 if (ec)
381 {
382 BMCWEB_LOG_ERROR << "GetAncestors on path " << objectName
383 << " failed with code " << ec;
384 return;
385 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700386
Ed Tanous002d39b2022-05-31 08:59:27 -0700387 for (const auto& pathGroup : objects)
388 {
389 for (const auto& connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700390 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700391 if (connectionGroup.first == connectionName)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700392 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700393 // Found the object manager path for this resource.
394 getManagedObjectsForEnumerate(objectName, pathGroup.first,
395 connectionName, transaction);
396 return;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700397 }
398 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700399 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700400 },
401 "xyz.openbmc_project.ObjectMapper",
402 "/xyz/openbmc_project/object_mapper",
Ed Tanous81ce6092020-12-17 16:54:55 +0000403 "xyz.openbmc_project.ObjectMapper", "GetAncestors", objectName,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500404 std::array<const char*, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700405}
Ed Tanous64530012018-02-06 17:08:16 -0800406
Ed Tanous7c091622019-05-23 11:42:36 -0700407// Uses GetObject to add the object info about the target /enumerate path to
408// the results of GetSubTree, as GetSubTree will not return info for the
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600409// target path, and then continues on enumerating the rest of the tree.
Ed Tanousb5a76932020-09-29 16:16:58 -0700410inline void getObjectAndEnumerate(
411 const std::shared_ptr<InProgressEnumerateData>& transaction)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600412{
George Liu2b731192023-01-11 16:27:13 +0800413 dbus::utility::getDbusObject(
414 transaction->objectPath, {},
415 [transaction](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800416 const dbus::utility::MapperGetObject& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700417 if (ec)
418 {
419 BMCWEB_LOG_ERROR << "GetObject for path " << transaction->objectPath
420 << " failed with code " << ec;
421 return;
422 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600423
Ed Tanous002d39b2022-05-31 08:59:27 -0700424 BMCWEB_LOG_DEBUG << "GetObject for " << transaction->objectPath
425 << " has " << objects.size() << " entries";
426 if (!objects.empty())
427 {
428 transaction->subtree->emplace_back(transaction->objectPath,
429 objects);
430 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600431
Ed Tanous002d39b2022-05-31 08:59:27 -0700432 // Map indicating connection name, and the path where the object
433 // manager exists
434 boost::container::flat_map<std::string, std::string> connections;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600435
Ed Tanous002d39b2022-05-31 08:59:27 -0700436 for (const auto& object : *(transaction->subtree))
437 {
438 for (const auto& connection : object.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600439 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700440 for (const auto& interface : connection.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600441 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700442 BMCWEB_LOG_DEBUG << connection.first << " has interface "
443 << interface;
444 if (interface == "org.freedesktop.DBus.ObjectManager")
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600445 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700446 BMCWEB_LOG_DEBUG << "found object manager path "
447 << object.first;
Ed Tanousf8fe53e2022-06-30 15:55:45 -0700448 connections[connection.first] = object.first;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600449 }
450 }
451 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700452 }
453 BMCWEB_LOG_DEBUG << "Got " << connections.size() << " connections";
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600454
Ed Tanous002d39b2022-05-31 08:59:27 -0700455 for (const auto& connection : connections)
456 {
457 // If we already know where the object manager is, we don't
458 // need to search for it, we can call directly in to
459 // getManagedObjects
460 if (!connection.second.empty())
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600461 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700462 getManagedObjectsForEnumerate(transaction->objectPath,
463 connection.second,
464 connection.first, transaction);
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600465 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700466 else
467 {
468 // otherwise we need to find the object manager path
469 // before we can continue
470 findObjectManagerPathForEnumerate(
471 transaction->objectPath, connection.first, transaction);
472 }
473 }
George Liu2b731192023-01-11 16:27:13 +0800474 });
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600475}
Ed Tanous64530012018-02-06 17:08:16 -0800476
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700477// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700478struct InProgressActionData
479{
Lei YU28dd5ca2023-03-17 13:17:05 +0800480 explicit InProgressActionData(
481 const std::shared_ptr<bmcweb::AsyncResp>& res) :
482 asyncResp(res)
Ed Tanous23a21a12020-07-25 04:45:05 +0000483 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700484 ~InProgressActionData()
485 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600486 // Methods could have been called across different owners
487 // and interfaces, where some calls failed and some passed.
488 //
489 // The rules for this are:
490 // * if no method was called - error
491 // * if a method failed and none passed - error
492 // (converse: if at least one method passed - OK)
493 // * for the method output:
494 // * if output processing didn't fail, return the data
495
496 // Only deal with method returns if nothing failed earlier
Lei YU28dd5ca2023-03-17 13:17:05 +0800497 if (asyncResp->res.result() == boost::beast::http::status::ok)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700498 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600499 if (!methodPassed)
500 {
Matt Spinler06b1b632019-06-18 16:09:25 -0500501 if (!methodFailed)
Matt Spinler16caaee2019-01-15 11:40:34 -0600502 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800503 setErrorResponse(asyncResp->res,
504 boost::beast::http::status::not_found,
Matt Spinler16caaee2019-01-15 11:40:34 -0600505 methodNotFoundDesc, notFoundMsg);
506 }
507 }
508 else
509 {
510 if (outputFailed)
511 {
512 setErrorResponse(
Lei YU28dd5ca2023-03-17 13:17:05 +0800513 asyncResp->res,
514 boost::beast::http::status::internal_server_error,
Matt Spinler16caaee2019-01-15 11:40:34 -0600515 "Method output failure", methodOutputFailedMsg);
516 }
517 else
518 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800519 asyncResp->res.jsonValue["status"] = "ok";
520 asyncResp->res.jsonValue["message"] = "200 OK";
521 asyncResp->res.jsonValue["data"] = methodResponse;
Matt Spinler16caaee2019-01-15 11:40:34 -0600522 }
523 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700524 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700525 }
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800526 InProgressActionData(const InProgressActionData&) = delete;
527 InProgressActionData(InProgressActionData&&) = delete;
528 InProgressActionData& operator=(const InProgressActionData&) = delete;
529 InProgressActionData& operator=(InProgressActionData&&) = delete;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700530
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500531 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700532 {
Lei YU28dd5ca2023-03-17 13:17:05 +0800533 setErrorResponse(asyncResp->res,
534 boost::beast::http::status::bad_request, desc,
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600535 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700536 }
Lei YU28dd5ca2023-03-17 13:17:05 +0800537 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700538 std::string path;
539 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600540 std::string interfaceName;
Matt Spinler16caaee2019-01-15 11:40:34 -0600541 bool methodPassed = false;
542 bool methodFailed = false;
543 bool outputFailed = false;
Matt Spinler39a4e392019-01-15 11:53:13 -0600544 bool convertedToArray = false;
Matt Spinler16caaee2019-01-15 11:40:34 -0600545 nlohmann::json methodResponse;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700546 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700547};
548
Ed Tanous23a21a12020-07-25 04:45:05 +0000549inline std::vector<std::string> dbusArgSplit(const std::string& string)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700550{
551 std::vector<std::string> ret;
552 if (string.empty())
553 {
554 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700555 }
Ed Tanous0f0353b2019-10-24 11:37:51 -0700556 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700557 int containerDepth = 0;
558
559 for (std::string::const_iterator character = string.begin();
560 character != string.end(); character++)
561 {
562 ret.back() += *character;
563 switch (*character)
564 {
565 case ('a'):
566 break;
567 case ('('):
568 case ('{'):
569 containerDepth++;
570 break;
571 case ('}'):
572 case (')'):
573 containerDepth--;
574 if (containerDepth == 0)
575 {
576 if (character + 1 != string.end())
577 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700578 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700579 }
580 }
581 break;
582 default:
583 if (containerDepth == 0)
584 {
585 if (character + 1 != string.end())
586 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700587 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700588 }
589 }
590 break;
591 }
592 }
Matt Spinler4ae611d2019-01-11 15:37:06 -0600593
594 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700595}
596
Ed Tanous81ce6092020-12-17 16:54:55 +0000597inline int convertJsonToDbus(sd_bus_message* m, const std::string& argType,
598 const nlohmann::json& inputJson)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700599{
600 int r = 0;
Ed Tanous71f52d92021-02-19 08:51:17 -0800601 BMCWEB_LOG_DEBUG << "Converting "
602 << inputJson.dump(2, ' ', true,
603 nlohmann::json::error_handler_t::replace)
Ed Tanous81ce6092020-12-17 16:54:55 +0000604 << " to type: " << argType;
605 const std::vector<std::string> argTypes = dbusArgSplit(argType);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700606
Ed Tanous1abe55e2018-09-05 08:30:59 -0700607 // Assume a single object for now.
Ed Tanous81ce6092020-12-17 16:54:55 +0000608 const nlohmann::json* j = &inputJson;
609 nlohmann::json::const_iterator jIt = inputJson.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700610
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500611 for (const std::string& argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700612 {
613 // If we are decoding multiple objects, grab the pointer to the
614 // iterator, and increment it for the next loop
615 if (argTypes.size() > 1)
616 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000617 if (jIt == inputJson.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700618 {
619 return -2;
620 }
621 j = &*jIt;
622 jIt++;
623 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500624 const int64_t* intValue = j->get_ptr<const int64_t*>();
625 const std::string* stringValue = j->get_ptr<const std::string*>();
626 const double* doubleValue = j->get_ptr<const double*>();
627 const bool* b = j->get_ptr<const bool*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700628 int64_t v = 0;
629 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700630
Ed Tanous1abe55e2018-09-05 08:30:59 -0700631 // Do some basic type conversions that make sense. uint can be
632 // converted to int. int and uint can be converted to double
Ed Tanous66664f22019-10-11 13:05:49 -0700633 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700634 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500635 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700636 if (uintValue != nullptr)
637 {
638 v = static_cast<int64_t>(*uintValue);
639 intValue = &v;
640 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700641 }
Ed Tanous66664f22019-10-11 13:05:49 -0700642 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700643 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500644 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700645 if (uintValue != nullptr)
646 {
647 d = static_cast<double>(*uintValue);
648 doubleValue = &d;
649 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700650 }
Ed Tanous66664f22019-10-11 13:05:49 -0700651 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700652 {
Ed Tanous66664f22019-10-11 13:05:49 -0700653 if (intValue != nullptr)
654 {
655 d = static_cast<double>(*intValue);
656 doubleValue = &d;
657 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700658 }
659
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700660 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700661 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700662 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700663 {
664 return -1;
665 }
Ed Tanous271584a2019-07-09 16:24:22 -0700666 r = sd_bus_message_append_basic(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500667 m, argCode[0], static_cast<const void*>(stringValue->data()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700668 if (r < 0)
669 {
670 return r;
671 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700672 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700673 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700674 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700675 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700676 {
677 return -1;
678 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500679 if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
680 (*intValue > std::numeric_limits<int32_t>::max()))
681 {
682 return -ERANGE;
683 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700684 int32_t i = static_cast<int32_t>(*intValue);
685 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700686 if (r < 0)
687 {
688 return r;
689 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700690 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700691 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700692 {
693 // lots of ways bool could be represented here. Try them all
Ed Tanouse662eae2022-01-25 10:39:19 -0800694 int boolInt = 0;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700695 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700696 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500697 if (*intValue == 1)
698 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800699 boolInt = 1;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500700 }
701 else if (*intValue == 0)
702 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800703 boolInt = 0;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500704 }
705 else
706 {
707 return -ERANGE;
708 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700709 }
710 else if (b != nullptr)
711 {
Matt Spinlera2f02632019-01-18 10:15:35 -0600712 boolInt = *b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700713 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700714 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700715 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700716 boolInt = boost::istarts_with(*stringValue, "t") ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700717 }
718 else
719 {
720 return -1;
721 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700722 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700723 if (r < 0)
724 {
725 return r;
726 }
727 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700728 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700729 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700730 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700731 {
732 return -1;
733 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500734 if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
735 (*intValue > std::numeric_limits<int16_t>::max()))
736 {
737 return -ERANGE;
738 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700739 int16_t n = static_cast<int16_t>(*intValue);
740 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700741 if (r < 0)
742 {
743 return r;
744 }
745 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700746 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700747 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700748 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700749 {
750 return -1;
751 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700752 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700753 if (r < 0)
754 {
755 return r;
756 }
757 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700758 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700759 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500760 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700761 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700762 {
763 return -1;
764 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000765 if (*uintValue > std::numeric_limits<uint8_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500766 {
767 return -ERANGE;
768 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700769 uint8_t y = static_cast<uint8_t>(*uintValue);
770 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700771 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700772 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700773 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500774 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700775 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700776 {
777 return -1;
778 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000779 if (*uintValue > std::numeric_limits<uint16_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500780 {
781 return -ERANGE;
782 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700783 uint16_t q = static_cast<uint16_t>(*uintValue);
784 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700785 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700786 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700787 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500788 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700789 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700790 {
791 return -1;
792 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000793 if (*uintValue > std::numeric_limits<uint32_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500794 {
795 return -ERANGE;
796 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700797 uint32_t u = static_cast<uint32_t>(*uintValue);
798 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700799 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700800 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700801 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500802 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700803 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700804 {
805 return -1;
806 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700807 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700808 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700809 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700810 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500811 if (doubleValue == nullptr)
812 {
813 return -1;
814 }
815 if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
816 (*doubleValue > std::numeric_limits<double>::max()))
817 {
818 return -ERANGE;
819 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700820 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700821 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700822 else if (argCode.starts_with("a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700823 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700824 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700825 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700826 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700827 if (r < 0)
828 {
829 return r;
830 }
831
Ed Tanous0dfeda62019-10-24 11:21:38 -0700832 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700833 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700834 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700835 if (r < 0)
836 {
837 return r;
838 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700839 }
840 sd_bus_message_close_container(m);
841 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700842 else if (argCode.starts_with("v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700843 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700844 std::string containedType = argCode.substr(1);
845 BMCWEB_LOG_DEBUG << "variant type: " << argCode
846 << " appending variant of type: " << containedType;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700847 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700848 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700849 if (r < 0)
850 {
851 return r;
852 }
853
Ed Tanous81ce6092020-12-17 16:54:55 +0000854 r = convertJsonToDbus(m, containedType, inputJson);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700855 if (r < 0)
856 {
857 return r;
858 }
859
860 r = sd_bus_message_close_container(m);
861 if (r < 0)
862 {
863 return r;
864 }
865 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700866 else if (argCode.starts_with("(") && argCode.ends_with(")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700867 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700868 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700869 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700870 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800871 if (r < 0)
872 {
873 return r;
874 }
875
Ed Tanous1abe55e2018-09-05 08:30:59 -0700876 nlohmann::json::const_iterator it = j->begin();
Ed Tanous81ce6092020-12-17 16:54:55 +0000877 for (const std::string& argCode2 : dbusArgSplit(argType))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700878 {
879 if (it == j->end())
880 {
881 return -1;
882 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000883 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700884 if (r < 0)
885 {
886 return r;
887 }
888 it++;
889 }
890 r = sd_bus_message_close_container(m);
891 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700892 else if (argCode.starts_with("{") && argCode.ends_with("}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700893 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700894 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700895 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700896 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800897 if (r < 0)
898 {
899 return r;
900 }
901
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700902 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700903 if (codes.size() != 2)
904 {
905 return -1;
906 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700907 const std::string& keyType = codes[0];
908 const std::string& valueType = codes[1];
Ed Tanous3174e4d2020-10-07 11:41:22 -0700909 for (const auto& it : j->items())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700910 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700911 r = convertJsonToDbus(m, keyType, it.key());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700912 if (r < 0)
913 {
914 return r;
915 }
916
Ed Tanous2c70f802020-09-28 14:29:23 -0700917 r = convertJsonToDbus(m, valueType, it.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700918 if (r < 0)
919 {
920 return r;
921 }
922 }
923 r = sd_bus_message_close_container(m);
924 }
925 else
926 {
927 return -2;
928 }
929 if (r < 0)
930 {
931 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700932 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700933
Ed Tanous1abe55e2018-09-05 08:30:59 -0700934 if (argTypes.size() > 1)
935 {
936 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700937 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700938 }
Matt Spinler127ea542019-01-14 11:04:28 -0600939
940 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700941}
942
Matt Spinlerd22a7132019-01-14 12:14:30 -0600943template <typename T>
Patrick Williams59d494e2022-07-22 19:26:55 -0500944int readMessageItem(const std::string& typeCode, sdbusplus::message_t& m,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500945 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600946{
947 T value;
948
949 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
950 if (r < 0)
951 {
952 BMCWEB_LOG_ERROR << "sd_bus_message_read_basic on type " << typeCode
953 << " failed!";
954 return r;
955 }
956
957 data = value;
958 return 0;
959}
960
Patrick Williams59d494e2022-07-22 19:26:55 -0500961int convertDBusToJSON(const std::string& returnType, sdbusplus::message_t& m,
962 nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600963
Ed Tanous23a21a12020-07-25 04:45:05 +0000964inline int readDictEntryFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -0500965 sdbusplus::message_t& m,
Ed Tanous23a21a12020-07-25 04:45:05 +0000966 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600967{
968 std::vector<std::string> types = dbusArgSplit(typeCode);
969 if (types.size() != 2)
970 {
971 BMCWEB_LOG_ERROR << "wrong number contained types in dictionary: "
972 << types.size();
973 return -1;
974 }
975
976 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
977 typeCode.c_str());
978 if (r < 0)
979 {
980 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container with rc " << r;
981 return r;
982 }
983
984 nlohmann::json key;
985 r = convertDBusToJSON(types[0], m, key);
986 if (r < 0)
987 {
988 return r;
989 }
990
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500991 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -0600992 if (keyPtr == nullptr)
993 {
994 // json doesn't support non-string keys. If we hit this condition,
995 // convert the result to a string so we can proceed
Ed Tanous71f52d92021-02-19 08:51:17 -0800996 key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500997 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -0700998 // in theory this can't fail now, but lets be paranoid about it
999 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -06001000 if (keyPtr == nullptr)
1001 {
1002 return -1;
1003 }
1004 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001005 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -06001006
1007 r = convertDBusToJSON(types[1], m, value);
1008 if (r < 0)
1009 {
1010 return r;
1011 }
1012
1013 r = sd_bus_message_exit_container(m.get());
1014 if (r < 0)
1015 {
1016 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1017 return r;
1018 }
1019
1020 return 0;
1021}
1022
Ed Tanous23a21a12020-07-25 04:45:05 +00001023inline int readArrayFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001024 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -06001025{
1026 if (typeCode.size() < 2)
1027 {
1028 BMCWEB_LOG_ERROR << "Type code " << typeCode
1029 << " too small for an array";
1030 return -1;
1031 }
1032
1033 std::string containedType = typeCode.substr(1);
1034
1035 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
1036 containedType.c_str());
1037 if (r < 0)
1038 {
1039 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1040 << r;
1041 return r;
1042 }
1043
Ed Tanous11ba3972022-07-11 09:50:41 -07001044 bool dict = containedType.starts_with("{") && containedType.ends_with("}");
Matt Spinler6df8f992019-01-14 12:47:47 -06001045
1046 if (dict)
1047 {
1048 // Remove the { }
1049 containedType = containedType.substr(1, containedType.size() - 2);
1050 data = nlohmann::json::object();
1051 }
1052 else
1053 {
1054 data = nlohmann::json::array();
1055 }
1056
1057 while (true)
1058 {
Ed Tanouse662eae2022-01-25 10:39:19 -08001059 r = sd_bus_message_at_end(m.get(), 0);
Matt Spinler6df8f992019-01-14 12:47:47 -06001060 if (r < 0)
1061 {
1062 BMCWEB_LOG_ERROR << "sd_bus_message_at_end failed";
1063 return r;
1064 }
1065
1066 if (r > 0)
1067 {
1068 break;
1069 }
1070
1071 // Dictionaries are only ever seen in an array
1072 if (dict)
1073 {
1074 r = readDictEntryFromMessage(containedType, m, data);
1075 if (r < 0)
1076 {
1077 return r;
1078 }
1079 }
1080 else
1081 {
1082 data.push_back(nlohmann::json());
1083
1084 r = convertDBusToJSON(containedType, m, data.back());
1085 if (r < 0)
1086 {
1087 return r;
1088 }
1089 }
1090 }
1091
1092 r = sd_bus_message_exit_container(m.get());
1093 if (r < 0)
1094 {
1095 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1096 return r;
1097 }
1098
1099 return 0;
1100}
1101
Ed Tanous23a21a12020-07-25 04:45:05 +00001102inline int readStructFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001103 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001104{
1105 if (typeCode.size() < 3)
1106 {
1107 BMCWEB_LOG_ERROR << "Type code " << typeCode
1108 << " too small for a struct";
1109 return -1;
1110 }
1111
1112 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1113 std::vector<std::string> types = dbusArgSplit(containedTypes);
1114
1115 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1116 containedTypes.c_str());
1117 if (r < 0)
1118 {
1119 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1120 << r;
1121 return r;
1122 }
1123
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001124 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001125 {
1126 data.push_back(nlohmann::json());
1127 r = convertDBusToJSON(type, m, data.back());
1128 if (r < 0)
1129 {
1130 return r;
1131 }
1132 }
1133
1134 r = sd_bus_message_exit_container(m.get());
1135 if (r < 0)
1136 {
1137 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1138 return r;
1139 }
1140 return 0;
1141}
1142
Patrick Williams59d494e2022-07-22 19:26:55 -05001143inline int readVariantFromMessage(sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001144{
Ed Tanous543f4402022-01-06 13:12:53 -08001145 const char* containerType = nullptr;
Ed Tanous99131cd2019-10-24 11:12:47 -07001146 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001147 if (r < 0)
1148 {
1149 BMCWEB_LOG_ERROR << "sd_bus_message_peek_type failed";
1150 return r;
1151 }
1152
1153 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1154 containerType);
1155 if (r < 0)
1156 {
1157 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1158 << r;
1159 return r;
1160 }
1161
1162 r = convertDBusToJSON(containerType, m, data);
1163 if (r < 0)
1164 {
1165 return r;
1166 }
1167
1168 r = sd_bus_message_exit_container(m.get());
1169 if (r < 0)
1170 {
1171 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed";
1172 return r;
1173 }
1174
1175 return 0;
1176}
1177
Ed Tanous23a21a12020-07-25 04:45:05 +00001178inline int convertDBusToJSON(const std::string& returnType,
Patrick Williams59d494e2022-07-22 19:26:55 -05001179 sdbusplus::message_t& m, nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001180{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001181 int r = 0;
1182 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1183
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001184 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001185 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001186 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001187 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001188 {
1189 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001190 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001191 }
1192
Ed Tanousd4d25792020-09-29 15:15:03 -07001193 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001194 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001195 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001196 if (r < 0)
1197 {
1198 return r;
1199 }
1200 }
1201 else if (typeCode == "b")
1202 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001203 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001204 if (r < 0)
1205 {
1206 return r;
1207 }
1208
Matt Spinlerf39420c2019-01-30 12:57:18 -06001209 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001210 }
1211 else if (typeCode == "u")
1212 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001213 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001214 if (r < 0)
1215 {
1216 return r;
1217 }
1218 }
1219 else if (typeCode == "i")
1220 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001221 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001222 if (r < 0)
1223 {
1224 return r;
1225 }
1226 }
1227 else if (typeCode == "x")
1228 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001229 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001230 if (r < 0)
1231 {
1232 return r;
1233 }
1234 }
1235 else if (typeCode == "t")
1236 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001237 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001238 if (r < 0)
1239 {
1240 return r;
1241 }
1242 }
1243 else if (typeCode == "n")
1244 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001245 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001246 if (r < 0)
1247 {
1248 return r;
1249 }
1250 }
1251 else if (typeCode == "q")
1252 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001253 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001254 if (r < 0)
1255 {
1256 return r;
1257 }
1258 }
1259 else if (typeCode == "y")
1260 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001261 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001262 if (r < 0)
1263 {
1264 return r;
1265 }
1266 }
1267 else if (typeCode == "d")
1268 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001269 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001270 if (r < 0)
1271 {
1272 return r;
1273 }
1274 }
1275 else if (typeCode == "h")
1276 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001277 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001278 if (r < 0)
1279 {
1280 return r;
1281 }
1282 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001283 else if (typeCode.starts_with("a"))
Matt Spinler6df8f992019-01-14 12:47:47 -06001284 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001285 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001286 if (r < 0)
1287 {
1288 return r;
1289 }
1290 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001291 else if (typeCode.starts_with("(") && typeCode.ends_with(")"))
Matt Spinler75c6c672019-01-14 13:01:46 -06001292 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001293 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001294 if (r < 0)
1295 {
1296 return r;
1297 }
1298 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001299 else if (typeCode.starts_with("v"))
Matt Spinler89c19702019-01-14 13:13:00 -06001300 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001301 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001302 if (r < 0)
1303 {
1304 return r;
1305 }
1306 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001307 else
1308 {
Matt Spinlerd22a7132019-01-14 12:14:30 -06001309 BMCWEB_LOG_ERROR << "Invalid D-Bus signature type " << typeCode;
1310 return -2;
1311 }
1312 }
1313
Matt Spinler16caaee2019-01-15 11:40:34 -06001314 return 0;
1315}
1316
Ed Tanousb5a76932020-09-29 16:16:58 -07001317inline void handleMethodResponse(
1318 const std::shared_ptr<InProgressActionData>& transaction,
Patrick Williams59d494e2022-07-22 19:26:55 -05001319 sdbusplus::message_t& m, const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001320{
Matt Spinler39a4e392019-01-15 11:53:13 -06001321 nlohmann::json data;
1322
1323 int r = convertDBusToJSON(returnType, m, data);
1324 if (r < 0)
1325 {
1326 transaction->outputFailed = true;
1327 return;
1328 }
1329
1330 if (data.is_null())
1331 {
1332 return;
1333 }
1334
1335 if (transaction->methodResponse.is_null())
1336 {
1337 transaction->methodResponse = std::move(data);
1338 return;
1339 }
1340
1341 // If they're both dictionaries or arrays, merge into one.
1342 // Otherwise, make the results an array with every result
1343 // an entry. Could also just fail in that case, but it
1344 // seems better to get the data back somehow.
1345
1346 if (transaction->methodResponse.is_object() && data.is_object())
1347 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001348 for (const auto& obj : data.items())
Matt Spinler39a4e392019-01-15 11:53:13 -06001349 {
1350 // Note: Will overwrite the data for a duplicate key
1351 transaction->methodResponse.emplace(obj.key(),
1352 std::move(obj.value()));
1353 }
1354 return;
1355 }
1356
1357 if (transaction->methodResponse.is_array() && data.is_array())
1358 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001359 for (auto& obj : data)
Matt Spinler39a4e392019-01-15 11:53:13 -06001360 {
1361 transaction->methodResponse.push_back(std::move(obj));
1362 }
1363 return;
1364 }
1365
1366 if (!transaction->convertedToArray)
1367 {
1368 // They are different types. May as well turn them into an array
1369 nlohmann::json j = std::move(transaction->methodResponse);
1370 transaction->methodResponse = nlohmann::json::array();
1371 transaction->methodResponse.push_back(std::move(j));
1372 transaction->methodResponse.push_back(std::move(data));
1373 transaction->convertedToArray = true;
1374 }
1375 else
1376 {
1377 transaction->methodResponse.push_back(std::move(data));
1378 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001379}
1380
Ed Tanousb5a76932020-09-29 16:16:58 -07001381inline void findActionOnInterface(
1382 const std::shared_ptr<InProgressActionData>& transaction,
1383 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001384{
1385 BMCWEB_LOG_DEBUG << "findActionOnInterface for connection "
1386 << connectionName;
1387 crow::connections::systemBus->async_method_call(
1388 [transaction, connectionName{std::string(connectionName)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001389 const boost::system::error_code& ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001390 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001391 BMCWEB_LOG_DEBUG << "got xml:\n " << introspectXml;
1392 if (ec)
1393 {
1394 BMCWEB_LOG_ERROR
1395 << "Introspect call failed with error: " << ec.message()
1396 << " on process: " << connectionName << "\n";
1397 return;
1398 }
1399 tinyxml2::XMLDocument doc;
Matt Spinler318bd892019-01-15 09:59:20 -06001400
Ed Tanous002d39b2022-05-31 08:59:27 -07001401 doc.Parse(introspectXml.data(), introspectXml.size());
1402 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1403 if (pRoot == nullptr)
1404 {
1405 BMCWEB_LOG_ERROR << "XML document failed to parse "
1406 << connectionName << "\n";
1407 return;
1408 }
1409 tinyxml2::XMLElement* interfaceNode =
1410 pRoot->FirstChildElement("interface");
1411 while (interfaceNode != nullptr)
1412 {
1413 const char* thisInterfaceName = interfaceNode->Attribute("name");
1414 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001415 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001416 if (!transaction->interfaceName.empty() &&
1417 (transaction->interfaceName != thisInterfaceName))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001418 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001419 interfaceNode =
1420 interfaceNode->NextSiblingElement("interface");
1421 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001422 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001423
1424 tinyxml2::XMLElement* methodNode =
1425 interfaceNode->FirstChildElement("method");
1426 while (methodNode != nullptr)
1427 {
1428 const char* thisMethodName = methodNode->Attribute("name");
1429 BMCWEB_LOG_DEBUG << "Found method: " << thisMethodName;
1430 if (thisMethodName != nullptr &&
1431 thisMethodName == transaction->methodName)
1432 {
1433 BMCWEB_LOG_DEBUG << "Found method named "
1434 << thisMethodName << " on interface "
1435 << thisInterfaceName;
Patrick Williams59d494e2022-07-22 19:26:55 -05001436 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001437 crow::connections::systemBus->new_method_call(
1438 connectionName.c_str(),
1439 transaction->path.c_str(), thisInterfaceName,
1440 transaction->methodName.c_str());
1441
1442 tinyxml2::XMLElement* argumentNode =
1443 methodNode->FirstChildElement("arg");
1444
1445 std::string returnType;
1446
1447 // Find the output type
1448 while (argumentNode != nullptr)
1449 {
1450 const char* argDirection =
1451 argumentNode->Attribute("direction");
1452 const char* argType =
1453 argumentNode->Attribute("type");
1454 if (argDirection != nullptr && argType != nullptr &&
1455 std::string(argDirection) == "out")
1456 {
1457 returnType = argType;
1458 break;
1459 }
1460 argumentNode =
1461 argumentNode->NextSiblingElement("arg");
1462 }
1463
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001464 auto argIt = transaction->arguments.begin();
Ed Tanous002d39b2022-05-31 08:59:27 -07001465
1466 argumentNode = methodNode->FirstChildElement("arg");
1467
1468 while (argumentNode != nullptr)
1469 {
1470 const char* argDirection =
1471 argumentNode->Attribute("direction");
1472 const char* argType =
1473 argumentNode->Attribute("type");
1474 if (argDirection != nullptr && argType != nullptr &&
1475 std::string(argDirection) == "in")
1476 {
1477 if (argIt == transaction->arguments.end())
1478 {
1479 transaction->setErrorStatus(
1480 "Invalid method args");
1481 return;
1482 }
1483 if (convertJsonToDbus(m.get(),
1484 std::string(argType),
1485 *argIt) < 0)
1486 {
1487 transaction->setErrorStatus(
1488 "Invalid method arg type");
1489 return;
1490 }
1491
1492 argIt++;
1493 }
1494 argumentNode =
1495 argumentNode->NextSiblingElement("arg");
1496 }
1497
1498 crow::connections::systemBus->async_send(
1499 m,
1500 [transaction,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001501 returnType](const boost::system::error_code& ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05001502 sdbusplus::message_t& m2) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001503 if (ec2)
1504 {
1505 transaction->methodFailed = true;
1506 const sd_bus_error* e = m2.get_error();
1507
1508 if (e != nullptr)
1509 {
1510 setErrorResponse(
Lei YU28dd5ca2023-03-17 13:17:05 +08001511 transaction->asyncResp->res,
Ed Tanous002d39b2022-05-31 08:59:27 -07001512 boost::beast::http::status::bad_request,
1513 e->name, e->message);
1514 }
1515 else
1516 {
1517 setErrorResponse(
Lei YU28dd5ca2023-03-17 13:17:05 +08001518 transaction->asyncResp->res,
Ed Tanous002d39b2022-05-31 08:59:27 -07001519 boost::beast::http::status::bad_request,
1520 "Method call failed", methodFailedMsg);
1521 }
1522 return;
1523 }
1524 transaction->methodPassed = true;
1525
1526 handleMethodResponse(transaction, m2, returnType);
1527 });
1528 break;
1529 }
1530 methodNode = methodNode->NextSiblingElement("method");
1531 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001532 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001533 interfaceNode = interfaceNode->NextSiblingElement("interface");
1534 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001535 },
1536 connectionName, transaction->path,
1537 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001538}
1539
zhanghch058d1b46d2021-04-01 11:18:24 +08001540inline void handleAction(const crow::Request& req,
1541 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001542 const std::string& objectPath,
1543 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001544{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001545 BMCWEB_LOG_DEBUG << "handleAction on path: " << objectPath << " and method "
1546 << methodName;
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001547 nlohmann::json requestDbusData;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001548
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001549 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
1550 if (ret == JsonParseResult::BadContentType)
1551 {
1552 setErrorResponse(asyncResp->res,
1553 boost::beast::http::status::unsupported_media_type,
1554 invalidContentType, unsupportedMediaMsg);
1555 return;
1556 }
1557 if (ret != JsonParseResult::Success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001558 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001559 setErrorResponse(asyncResp->res,
1560 boost::beast::http::status::bad_request, noJsonDesc,
1561 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001562 return;
1563 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001564 nlohmann::json::iterator data = requestDbusData.find("data");
1565 if (data == requestDbusData.end())
1566 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001567 setErrorResponse(asyncResp->res,
1568 boost::beast::http::status::bad_request, noJsonDesc,
1569 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001570 return;
1571 }
1572
1573 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001574 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001575 setErrorResponse(asyncResp->res,
1576 boost::beast::http::status::bad_request, noJsonDesc,
1577 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001578 return;
1579 }
Lei YU28dd5ca2023-03-17 13:17:05 +08001580 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001581
1582 transaction->path = objectPath;
1583 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001584 transaction->arguments = std::move(*data);
George Liu2b731192023-01-11 16:27:13 +08001585 dbus::utility::getDbusObject(
1586 objectPath, {},
Ed Tanous1abe55e2018-09-05 08:30:59 -07001587 [transaction](
George Liu2b731192023-01-11 16:27:13 +08001588 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001589 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1590 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001591 if (ec || interfaceNames.empty())
1592 {
1593 BMCWEB_LOG_ERROR << "Can't find object";
Lei YU28dd5ca2023-03-17 13:17:05 +08001594 setErrorResponse(transaction->asyncResp->res,
Ed Tanous002d39b2022-05-31 08:59:27 -07001595 boost::beast::http::status::not_found,
1596 notFoundDesc, notFoundMsg);
1597 return;
1598 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001599
Ed Tanous002d39b2022-05-31 08:59:27 -07001600 BMCWEB_LOG_DEBUG << "GetObject returned " << interfaceNames.size()
1601 << " object(s)";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001602
Ed Tanous002d39b2022-05-31 08:59:27 -07001603 for (const std::pair<std::string, std::vector<std::string>>& object :
1604 interfaceNames)
1605 {
1606 findActionOnInterface(transaction, object.first);
1607 }
George Liu2b731192023-01-11 16:27:13 +08001608 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001609}
1610
zhanghch058d1b46d2021-04-01 11:18:24 +08001611inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1612 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001613{
1614 BMCWEB_LOG_DEBUG << "handleDelete on path: " << objectPath;
1615
George Liu2b731192023-01-11 16:27:13 +08001616 dbus::utility::getDbusObject(
1617 objectPath, {},
zhanghch058d1b46d2021-04-01 11:18:24 +08001618 [asyncResp, objectPath](
George Liu2b731192023-01-11 16:27:13 +08001619 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001620 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1621 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001622 if (ec || interfaceNames.empty())
1623 {
1624 BMCWEB_LOG_ERROR << "Can't find object";
1625 setErrorResponse(asyncResp->res,
1626 boost::beast::http::status::method_not_allowed,
1627 methodNotAllowedDesc, methodNotAllowedMsg);
1628 return;
1629 }
Matt Spinlerde818812018-12-11 16:39:20 -06001630
Lei YU28dd5ca2023-03-17 13:17:05 +08001631 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001632 transaction->path = objectPath;
1633 transaction->methodName = "Delete";
1634 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
Matt Spinlerde818812018-12-11 16:39:20 -06001635
Ed Tanous002d39b2022-05-31 08:59:27 -07001636 for (const std::pair<std::string, std::vector<std::string>>& object :
1637 interfaceNames)
1638 {
1639 findActionOnInterface(transaction, object.first);
1640 }
George Liu2b731192023-01-11 16:27:13 +08001641 });
Matt Spinlerde818812018-12-11 16:39:20 -06001642}
1643
zhanghch058d1b46d2021-04-01 11:18:24 +08001644inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1645 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001646{
George Liu7a1dbc42022-12-07 16:03:22 +08001647 dbus::utility::getSubTreePaths(
1648 objectPath, depth, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001649 [asyncResp](
George Liu7a1dbc42022-12-07 16:03:22 +08001650 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001651 const dbus::utility::MapperGetSubTreePathsResponse& objectPaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001652 if (ec)
1653 {
1654 setErrorResponse(asyncResp->res,
1655 boost::beast::http::status::not_found,
1656 notFoundDesc, notFoundMsg);
1657 }
1658 else
1659 {
1660 asyncResp->res.jsonValue["status"] = "ok";
1661 asyncResp->res.jsonValue["message"] = "200 OK";
1662 asyncResp->res.jsonValue["data"] = objectPaths;
1663 }
George Liu7a1dbc42022-12-07 16:03:22 +08001664 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001665}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001666
zhanghch058d1b46d2021-04-01 11:18:24 +08001667inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1668 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001669{
Ed Tanous049a0512018-11-01 13:58:42 -07001670 BMCWEB_LOG_DEBUG << "Doing enumerate on " << objectPath;
Ed Tanous049a0512018-11-01 13:58:42 -07001671
Ed Tanous14766872022-03-15 10:44:42 -07001672 asyncResp->res.jsonValue["message"] = "200 OK";
1673 asyncResp->res.jsonValue["status"] = "ok";
1674 asyncResp->res.jsonValue["data"] = nlohmann::json::object();
Ed Tanous049a0512018-11-01 13:58:42 -07001675
George Liue99073f2022-12-09 11:06:16 +08001676 dbus::utility::getSubTree(
1677 objectPath, 0, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001678 [objectPath, asyncResp](
George Liue99073f2022-12-09 11:06:16 +08001679 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001680 const dbus::utility::MapperGetSubTreeResponse& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001681 auto transaction =
1682 std::make_shared<InProgressEnumerateData>(objectPath, asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001683
Ed Tanous002d39b2022-05-31 08:59:27 -07001684 transaction->subtree =
1685 std::make_shared<dbus::utility::MapperGetSubTreeResponse>(
1686 objectNames);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001687
Ed Tanous002d39b2022-05-31 08:59:27 -07001688 if (ec)
1689 {
1690 BMCWEB_LOG_ERROR << "GetSubTree failed on "
1691 << transaction->objectPath;
1692 setErrorResponse(transaction->asyncResp->res,
1693 boost::beast::http::status::not_found,
1694 notFoundDesc, notFoundMsg);
1695 return;
1696 }
Ed Tanous64530012018-02-06 17:08:16 -08001697
Ed Tanous002d39b2022-05-31 08:59:27 -07001698 // Add the data for the path passed in to the results
1699 // as if GetSubTree returned it, and continue on enumerating
1700 getObjectAndEnumerate(transaction);
George Liue99073f2022-12-09 11:06:16 +08001701 });
Ed Tanous64530012018-02-06 17:08:16 -08001702}
Ed Tanous911ac312017-08-15 09:37:42 -07001703
zhanghch058d1b46d2021-04-01 11:18:24 +08001704inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1705 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001706{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001707 BMCWEB_LOG_DEBUG << "handleGet: " << objectPath << " prop:" << destProperty;
1708 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001709 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001710
Ed Tanous1abe55e2018-09-05 08:30:59 -07001711 std::shared_ptr<std::string> path =
1712 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001713
George Liu2b731192023-01-11 16:27:13 +08001714 dbus::utility::getDbusObject(
1715 *path, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001716 [asyncResp, path,
George Liu2b731192023-01-11 16:27:13 +08001717 propertyName](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001718 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001719 if (ec || objectNames.empty())
1720 {
1721 setErrorResponse(asyncResp->res,
1722 boost::beast::http::status::not_found,
1723 notFoundDesc, notFoundMsg);
1724 return;
1725 }
1726 std::shared_ptr<nlohmann::json> response =
1727 std::make_shared<nlohmann::json>(nlohmann::json::object());
1728 // The mapper should never give us an empty interface names
1729 // list, but check anyway
1730 for (const std::pair<std::string, std::vector<std::string>>&
1731 connection : objectNames)
1732 {
1733 const std::vector<std::string>& interfaceNames = connection.second;
1734
1735 if (interfaceNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001736 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001737 setErrorResponse(asyncResp->res,
1738 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001739 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001740 return;
1741 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001742
1743 for (const std::string& interface : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001744 {
Patrick Williams59d494e2022-07-22 19:26:55 -05001745 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001746 crow::connections::systemBus->new_method_call(
1747 connection.first.c_str(), path->c_str(),
1748 "org.freedesktop.DBus.Properties", "GetAll");
1749 m.append(interface);
1750 crow::connections::systemBus->async_send(
1751 m, [asyncResp, response,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001752 propertyName](const boost::system::error_code& ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05001753 sdbusplus::message_t& msg) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001754 if (ec2)
1755 {
1756 BMCWEB_LOG_ERROR << "Bad dbus request error: "
1757 << ec2;
1758 }
1759 else
1760 {
1761 nlohmann::json properties;
1762 int r = convertDBusToJSON("a{sv}", msg, properties);
1763 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001764 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001765 BMCWEB_LOG_ERROR << "convertDBusToJSON failed";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001766 }
1767 else
1768 {
Patrick Williams62bafc02022-09-08 17:35:35 -05001769 for (const auto& prop : properties.items())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001770 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001771 // if property name is empty, or
1772 // matches our search query, add it
1773 // to the response json
Ed Tanous1abe55e2018-09-05 08:30:59 -07001774
Ed Tanous002d39b2022-05-31 08:59:27 -07001775 if (propertyName->empty())
1776 {
1777 (*response)[prop.key()] =
1778 std::move(prop.value());
1779 }
1780 else if (prop.key() == *propertyName)
1781 {
1782 *response = std::move(prop.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001783 }
1784 }
1785 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001786 }
1787 if (response.use_count() == 1)
1788 {
1789 if (!propertyName->empty() && response->empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001790 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001791 setErrorResponse(
1792 asyncResp->res,
1793 boost::beast::http::status::not_found,
1794 propNotFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001795 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001796 else
1797 {
1798 asyncResp->res.jsonValue["status"] = "ok";
1799 asyncResp->res.jsonValue["message"] = "200 OK";
1800 asyncResp->res.jsonValue["data"] = *response;
1801 }
1802 }
1803 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001804 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001805 }
George Liu2b731192023-01-11 16:27:13 +08001806 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001807}
1808
Ed Tanous1abe55e2018-09-05 08:30:59 -07001809struct AsyncPutRequest
1810{
Ed Tanous4e23a442022-06-06 09:57:26 -07001811 explicit AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
zhanghch058d1b46d2021-04-01 11:18:24 +08001812 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001813 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001814 ~AsyncPutRequest()
1815 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001816 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001817 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001818 setErrorResponse(asyncResp->res,
1819 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001820 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001821 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001822 }
1823
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001824 AsyncPutRequest(const AsyncPutRequest&) = delete;
1825 AsyncPutRequest(AsyncPutRequest&&) = delete;
1826 AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1827 AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1828
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001829 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001830 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001831 setErrorResponse(asyncResp->res,
1832 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001833 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001834 }
1835
zhanghch058d1b46d2021-04-01 11:18:24 +08001836 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001837 std::string objectPath;
1838 std::string propertyName;
1839 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001840};
1841
zhanghch058d1b46d2021-04-01 11:18:24 +08001842inline void handlePut(const crow::Request& req,
1843 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001844 const std::string& objectPath,
1845 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001846{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001847 if (destProperty.empty())
1848 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001849 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001850 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001851 return;
1852 }
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001853 nlohmann::json requestDbusData;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001854
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001855 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
1856 if (ret == JsonParseResult::BadContentType)
1857 {
1858 setErrorResponse(asyncResp->res,
1859 boost::beast::http::status::unsupported_media_type,
1860 invalidContentType, unsupportedMediaMsg);
1861 return;
1862 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001863
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01001864 if (ret != JsonParseResult::Success)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001865 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001866 setErrorResponse(asyncResp->res,
1867 boost::beast::http::status::bad_request, noJsonDesc,
1868 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001869 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001870 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001871
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001872 auto propertyIt = requestDbusData.find("data");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001873 if (propertyIt == requestDbusData.end())
1874 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001875 setErrorResponse(asyncResp->res,
1876 boost::beast::http::status::bad_request, noJsonDesc,
1877 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001878 return;
1879 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001880 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001881 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001882 transaction->objectPath = objectPath;
1883 transaction->propertyName = destProperty;
1884 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001885
George Liu2b731192023-01-11 16:27:13 +08001886 dbus::utility::getDbusObject(
1887 transaction->objectPath, {},
1888 [transaction](const boost::system::error_code& ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001889 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001890 if (!ec2 && objectNames.empty())
1891 {
1892 setErrorResponse(transaction->asyncResp->res,
1893 boost::beast::http::status::not_found,
1894 propNotFoundDesc, notFoundMsg);
1895 return;
1896 }
Ed Tanous911ac312017-08-15 09:37:42 -07001897
Ed Tanous002d39b2022-05-31 08:59:27 -07001898 for (const std::pair<std::string, std::vector<std::string>>&
1899 connection : objectNames)
1900 {
1901 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001902
Ed Tanous002d39b2022-05-31 08:59:27 -07001903 crow::connections::systemBus->async_method_call(
1904 [connectionName{std::string(connectionName)},
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001905 transaction](const boost::system::error_code& ec3,
Ed Tanous002d39b2022-05-31 08:59:27 -07001906 const std::string& introspectXml) {
1907 if (ec3)
1908 {
1909 BMCWEB_LOG_ERROR << "Introspect call failed with error: "
1910 << ec3.message()
1911 << " on process: " << connectionName;
1912 transaction->setErrorStatus("Unexpected Error");
1913 return;
1914 }
1915 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001916
Ed Tanous002d39b2022-05-31 08:59:27 -07001917 doc.Parse(introspectXml.c_str());
1918 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1919 if (pRoot == nullptr)
1920 {
1921 BMCWEB_LOG_ERROR << "XML document failed to parse: "
1922 << introspectXml;
1923 transaction->setErrorStatus("Unexpected Error");
1924 return;
1925 }
1926 tinyxml2::XMLElement* ifaceNode =
1927 pRoot->FirstChildElement("interface");
1928 while (ifaceNode != nullptr)
1929 {
1930 const char* interfaceName = ifaceNode->Attribute("name");
1931 BMCWEB_LOG_DEBUG << "found interface " << interfaceName;
1932 tinyxml2::XMLElement* propNode =
1933 ifaceNode->FirstChildElement("property");
1934 while (propNode != nullptr)
1935 {
1936 const char* propertyName = propNode->Attribute("name");
1937 BMCWEB_LOG_DEBUG << "Found property " << propertyName;
1938 if (propertyName == transaction->propertyName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001939 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001940 const char* argType = propNode->Attribute("type");
1941 if (argType != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001942 {
Patrick Williams59d494e2022-07-22 19:26:55 -05001943 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001944 crow::connections::systemBus
1945 ->new_method_call(
1946 connectionName.c_str(),
1947 transaction->objectPath.c_str(),
1948 "org.freedesktop.DBus."
1949 "Properties",
1950 "Set");
1951 m.append(interfaceName,
1952 transaction->propertyName);
1953 int r = sd_bus_message_open_container(
1954 m.get(), SD_BUS_TYPE_VARIANT, argType);
1955 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001956 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001957 transaction->setErrorStatus(
1958 "Unexpected Error");
1959 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001960 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001961 r = convertJsonToDbus(
1962 m.get(), argType,
1963 transaction->propertyValue);
1964 if (r < 0)
1965 {
1966 if (r == -ERANGE)
1967 {
1968 transaction->setErrorStatus(
1969 "Provided property value "
1970 "is out of range for the "
1971 "property type");
1972 }
1973 else
1974 {
1975 transaction->setErrorStatus(
1976 "Invalid arg type");
1977 }
1978 return;
1979 }
1980 r = sd_bus_message_close_container(m.get());
1981 if (r < 0)
1982 {
1983 transaction->setErrorStatus(
1984 "Unexpected Error");
1985 return;
1986 }
1987 crow::connections::systemBus->async_send(
1988 m,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001989 [transaction](
1990 const boost::system::error_code& ec,
1991 sdbusplus::message_t& m2) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001992 BMCWEB_LOG_DEBUG << "sent";
1993 if (ec)
1994 {
1995 const sd_bus_error* e = m2.get_error();
1996 setErrorResponse(
1997 transaction->asyncResp->res,
1998 boost::beast::http::status::
1999 forbidden,
2000 (e) != nullptr
2001 ? e->name
2002 : ec.category().name(),
2003 (e) != nullptr ? e->message
2004 : ec.message());
2005 }
2006 else
2007 {
2008 transaction->asyncResp->res
2009 .jsonValue["status"] = "ok";
2010 transaction->asyncResp->res
2011 .jsonValue["message"] = "200 OK";
2012 transaction->asyncResp->res
2013 .jsonValue["data"] = nullptr;
2014 }
2015 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002016 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002017 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002018 propNode = propNode->NextSiblingElement("property");
2019 }
2020 ifaceNode = ifaceNode->NextSiblingElement("interface");
2021 }
2022 },
2023 connectionName, transaction->objectPath,
2024 "org.freedesktop.DBus.Introspectable", "Introspect");
2025 }
George Liu2b731192023-01-11 16:27:13 +08002026 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07002027}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002028
zhanghch058d1b46d2021-04-01 11:18:24 +08002029inline void handleDBusUrl(const crow::Request& req,
2030 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002031 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002032{
Ed Tanous049a0512018-11-01 13:58:42 -07002033
2034 // If accessing a single attribute, fill in and update objectPath,
2035 // otherwise leave destProperty blank
Ed Tanouse05aec52022-01-25 10:28:56 -08002036 std::string destProperty;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002037 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002038 size_t attrPosition = objectPath.find(attrSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002039 if (attrPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002040 {
2041 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2042 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002043 objectPath.resize(attrPosition);
Ed Tanous049a0512018-11-01 13:58:42 -07002044 }
2045
Ed Tanousb41187f2019-10-24 16:30:02 -07002046 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002047 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002048 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002049 size_t actionPosition = objectPath.find(actionSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002050 if (actionPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002051 {
2052 std::string postProperty =
2053 objectPath.substr((actionPosition + strlen(actionSeperator)),
2054 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002055 objectPath.resize(actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002056 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002057 return;
2058 }
2059 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002060 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002061 {
Ed Tanous11ba3972022-07-11 09:50:41 -07002062 if (objectPath.ends_with("/enumerate"))
Ed Tanous049a0512018-11-01 13:58:42 -07002063 {
2064 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2065 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002066 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002067 }
Ed Tanous11ba3972022-07-11 09:50:41 -07002068 else if (objectPath.ends_with("/list"))
Ed Tanous049a0512018-11-01 13:58:42 -07002069 {
2070 objectPath.erase(objectPath.end() - sizeof("list"),
2071 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002072 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002073 }
2074 else
2075 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002076 // Trim any trailing "/" at the end
Ed Tanous11ba3972022-07-11 09:50:41 -07002077 if (objectPath.ends_with("/"))
Ed Tanousf839dfe2018-11-12 11:11:15 -08002078 {
2079 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002080 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002081 }
2082 else
2083 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002084 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002085 }
Ed Tanous049a0512018-11-01 13:58:42 -07002086 }
2087 return;
2088 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002089 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002090 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002091 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002092 return;
2093 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002094 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002095 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002096 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002097 return;
2098 }
Ed Tanous049a0512018-11-01 13:58:42 -07002099
zhanghch058d1b46d2021-04-01 11:18:24 +08002100 setErrorResponse(asyncResp->res,
2101 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002102 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002103}
2104
Ed Tanous1656b292022-05-04 11:33:42 -07002105inline void
2106 handleBusSystemPost(const crow::Request& req,
2107 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2108 const std::string& processName,
2109 const std::string& requestedPath)
2110{
2111 std::vector<std::string> strs;
Ed Tanous50ebd4a2023-01-19 19:03:17 -08002112
2113 bmcweb::split(strs, requestedPath, '/');
Ed Tanous1656b292022-05-04 11:33:42 -07002114 std::string objectPath;
2115 std::string interfaceName;
2116 std::string methodName;
2117 auto it = strs.begin();
2118 if (it == strs.end())
2119 {
2120 objectPath = "/";
2121 }
2122 while (it != strs.end())
2123 {
2124 // Check if segment contains ".". If it does, it must be an
2125 // interface
2126 if (it->find(".") != std::string::npos)
2127 {
2128 break;
2129 // This check is necessary as the trailing slash gets
2130 // parsed as part of our <path> specifier above, which
2131 // causes the normal trailing backslash redirector to
2132 // fail.
2133 }
2134 if (!it->empty())
2135 {
2136 objectPath += "/" + *it;
2137 }
2138 it++;
2139 }
2140 if (it != strs.end())
2141 {
2142 interfaceName = *it;
2143 it++;
2144
2145 // after interface, we might have a method name
2146 if (it != strs.end())
2147 {
2148 methodName = *it;
2149 it++;
2150 }
2151 }
2152 if (it != strs.end())
2153 {
2154 // if there is more levels past the method name, something
2155 // went wrong, return not found
2156 asyncResp->res.result(boost::beast::http::status::not_found);
2157 return;
2158 }
2159 if (interfaceName.empty())
2160 {
2161 crow::connections::systemBus->async_method_call(
2162 [asyncResp, processName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002163 objectPath](const boost::system::error_code& ec,
Ed Tanous1656b292022-05-04 11:33:42 -07002164 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002165 if (ec)
2166 {
2167 BMCWEB_LOG_ERROR
2168 << "Introspect call failed with error: " << ec.message()
2169 << " on process: " << processName << " path: " << objectPath
2170 << "\n";
2171 return;
2172 }
2173 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002174
Ed Tanous002d39b2022-05-31 08:59:27 -07002175 doc.Parse(introspectXml.c_str());
2176 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2177 if (pRoot == nullptr)
2178 {
2179 BMCWEB_LOG_ERROR << "XML document failed to parse "
2180 << processName << " " << objectPath << "\n";
2181 asyncResp->res.jsonValue["status"] = "XML parse error";
2182 asyncResp->res.result(
2183 boost::beast::http::status::internal_server_error);
2184 return;
2185 }
2186
2187 BMCWEB_LOG_DEBUG << introspectXml;
2188 asyncResp->res.jsonValue["status"] = "ok";
2189 asyncResp->res.jsonValue["bus_name"] = processName;
2190 asyncResp->res.jsonValue["object_path"] = objectPath;
2191
2192 nlohmann::json& interfacesArray =
2193 asyncResp->res.jsonValue["interfaces"];
2194 interfacesArray = nlohmann::json::array();
2195 tinyxml2::XMLElement* interface =
2196 pRoot->FirstChildElement("interface");
2197
2198 while (interface != nullptr)
2199 {
2200 const char* ifaceName = interface->Attribute("name");
2201 if (ifaceName != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002202 {
Ed Tanous8a592812022-06-04 09:06:59 -07002203 nlohmann::json::object_t interfaceObj;
2204 interfaceObj["name"] = ifaceName;
2205 interfacesArray.push_back(std::move(interfaceObj));
Ed Tanous1656b292022-05-04 11:33:42 -07002206 }
2207
Ed Tanous002d39b2022-05-31 08:59:27 -07002208 interface = interface->NextSiblingElement("interface");
2209 }
Ed Tanous1656b292022-05-04 11:33:42 -07002210 },
2211 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2212 "Introspect");
2213 }
2214 else if (methodName.empty())
2215 {
2216 crow::connections::systemBus->async_method_call(
2217 [asyncResp, processName, objectPath,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002218 interfaceName](const boost::system::error_code& ec,
Ed Tanous1656b292022-05-04 11:33:42 -07002219 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002220 if (ec)
2221 {
2222 BMCWEB_LOG_ERROR
2223 << "Introspect call failed with error: " << ec.message()
2224 << " on process: " << processName << " path: " << objectPath
2225 << "\n";
2226 return;
2227 }
2228 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002229
Ed Tanous002d39b2022-05-31 08:59:27 -07002230 doc.Parse(introspectXml.data(), introspectXml.size());
2231 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2232 if (pRoot == nullptr)
2233 {
2234 BMCWEB_LOG_ERROR << "XML document failed to parse "
2235 << processName << " " << objectPath << "\n";
2236 asyncResp->res.result(
2237 boost::beast::http::status::internal_server_error);
2238 return;
2239 }
2240
2241 asyncResp->res.jsonValue["status"] = "ok";
2242 asyncResp->res.jsonValue["bus_name"] = processName;
2243 asyncResp->res.jsonValue["interface"] = interfaceName;
2244 asyncResp->res.jsonValue["object_path"] = objectPath;
2245
2246 nlohmann::json& methodsArray = asyncResp->res.jsonValue["methods"];
2247 methodsArray = nlohmann::json::array();
2248
2249 nlohmann::json& signalsArray = asyncResp->res.jsonValue["signals"];
2250 signalsArray = nlohmann::json::array();
2251
2252 nlohmann::json& propertiesObj =
2253 asyncResp->res.jsonValue["properties"];
2254 propertiesObj = nlohmann::json::object();
2255
2256 // if we know we're the only call, build the
2257 // json directly
2258 tinyxml2::XMLElement* interface =
2259 pRoot->FirstChildElement("interface");
2260 while (interface != nullptr)
2261 {
2262 const char* ifaceName = interface->Attribute("name");
2263
2264 if (ifaceName != nullptr && ifaceName == interfaceName)
Ed Tanous1656b292022-05-04 11:33:42 -07002265 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002266 break;
Ed Tanous1656b292022-05-04 11:33:42 -07002267 }
Ed Tanous14766872022-03-15 10:44:42 -07002268
Ed Tanous002d39b2022-05-31 08:59:27 -07002269 interface = interface->NextSiblingElement("interface");
2270 }
2271 if (interface == nullptr)
2272 {
2273 // if we got to the end of the list and
2274 // never found a match, throw 404
2275 asyncResp->res.result(boost::beast::http::status::not_found);
2276 return;
2277 }
Ed Tanous1656b292022-05-04 11:33:42 -07002278
Ed Tanous002d39b2022-05-31 08:59:27 -07002279 tinyxml2::XMLElement* methods =
2280 interface->FirstChildElement("method");
2281 while (methods != nullptr)
2282 {
2283 nlohmann::json argsArray = nlohmann::json::array();
2284 tinyxml2::XMLElement* arg = methods->FirstChildElement("arg");
2285 while (arg != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002286 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002287 nlohmann::json thisArg;
2288 for (const char* fieldName : std::array<const char*, 3>{
2289 "name", "direction", "type"})
Ed Tanous1656b292022-05-04 11:33:42 -07002290 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002291 const char* fieldValue = arg->Attribute(fieldName);
2292 if (fieldValue != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002293 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002294 thisArg[fieldName] = fieldValue;
2295 }
2296 }
2297 argsArray.push_back(std::move(thisArg));
2298 arg = arg->NextSiblingElement("arg");
2299 }
2300
2301 const char* name = methods->Attribute("name");
2302 if (name != nullptr)
2303 {
2304 std::string uri;
2305 uri.reserve(14 + processName.size() + objectPath.size() +
2306 interfaceName.size() + strlen(name));
2307 uri += "/bus/system/";
2308 uri += processName;
2309 uri += objectPath;
2310 uri += "/";
2311 uri += interfaceName;
2312 uri += "/";
2313 uri += name;
2314
2315 nlohmann::json::object_t object;
2316 object["name"] = name;
2317 object["uri"] = std::move(uri);
2318 object["args"] = argsArray;
2319
2320 methodsArray.push_back(std::move(object));
2321 }
2322 methods = methods->NextSiblingElement("method");
2323 }
2324 tinyxml2::XMLElement* signals =
2325 interface->FirstChildElement("signal");
2326 while (signals != nullptr)
2327 {
2328 nlohmann::json argsArray = nlohmann::json::array();
2329
2330 tinyxml2::XMLElement* arg = signals->FirstChildElement("arg");
2331 while (arg != nullptr)
2332 {
2333 const char* name = arg->Attribute("name");
2334 const char* type = arg->Attribute("type");
2335 if (name != nullptr && type != nullptr)
2336 {
2337 argsArray.push_back({
2338 {"name", name},
2339 {"type", type},
2340 });
2341 }
2342 arg = arg->NextSiblingElement("arg");
2343 }
2344 const char* name = signals->Attribute("name");
2345 if (name != nullptr)
2346 {
2347 nlohmann::json::object_t object;
2348 object["name"] = name;
2349 object["args"] = argsArray;
2350 signalsArray.push_back(std::move(object));
2351 }
2352
2353 signals = signals->NextSiblingElement("signal");
2354 }
2355
2356 tinyxml2::XMLElement* property =
2357 interface->FirstChildElement("property");
2358 while (property != nullptr)
2359 {
2360 const char* name = property->Attribute("name");
2361 const char* type = property->Attribute("type");
2362 if (type != nullptr && name != nullptr)
2363 {
Patrick Williams59d494e2022-07-22 19:26:55 -05002364 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07002365 crow::connections::systemBus->new_method_call(
2366 processName.c_str(), objectPath.c_str(),
2367 "org.freedesktop."
2368 "DBus."
2369 "Properties",
2370 "Get");
2371 m.append(interfaceName, name);
2372 nlohmann::json& propertyItem = propertiesObj[name];
2373 crow::connections::systemBus->async_send(
2374 m, [&propertyItem,
Ed Tanous02cad962022-06-30 16:50:15 -07002375 asyncResp](const boost::system::error_code& e,
Patrick Williams59d494e2022-07-22 19:26:55 -05002376 sdbusplus::message_t& msg) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002377 if (e)
Ed Tanous1656b292022-05-04 11:33:42 -07002378 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002379 return;
Ed Tanous1656b292022-05-04 11:33:42 -07002380 }
Ed Tanous1656b292022-05-04 11:33:42 -07002381
Ed Tanous002d39b2022-05-31 08:59:27 -07002382 convertDBusToJSON("v", msg, propertyItem);
2383 });
Ed Tanous1656b292022-05-04 11:33:42 -07002384 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002385 property = property->NextSiblingElement("property");
2386 }
Ed Tanous1656b292022-05-04 11:33:42 -07002387 },
2388 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2389 "Introspect");
2390 }
2391 else
2392 {
2393 if (req.method() != boost::beast::http::verb::post)
2394 {
2395 asyncResp->res.result(boost::beast::http::status::not_found);
2396 return;
2397 }
2398
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002399 nlohmann::json requestDbusData;
2400 JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
2401 if (ret == JsonParseResult::BadContentType)
Ed Tanous1656b292022-05-04 11:33:42 -07002402 {
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002403 setErrorResponse(asyncResp->res,
2404 boost::beast::http::status::unsupported_media_type,
2405 invalidContentType, unsupportedMediaMsg);
Ed Tanous1656b292022-05-04 11:33:42 -07002406 return;
2407 }
Ed Tanous1aa0c2b2022-02-08 12:24:30 +01002408 if (ret != JsonParseResult::Success)
2409 {
2410 setErrorResponse(asyncResp->res,
2411 boost::beast::http::status::bad_request,
2412 noJsonDesc, badReqMsg);
2413 return;
2414 }
2415
Ed Tanous1656b292022-05-04 11:33:42 -07002416 if (!requestDbusData.is_array())
2417 {
2418 asyncResp->res.result(boost::beast::http::status::bad_request);
2419 return;
2420 }
Lei YU28dd5ca2023-03-17 13:17:05 +08002421 auto transaction = std::make_shared<InProgressActionData>(asyncResp);
Ed Tanous1656b292022-05-04 11:33:42 -07002422
2423 transaction->path = objectPath;
2424 transaction->methodName = methodName;
2425 transaction->arguments = std::move(requestDbusData);
2426
2427 findActionOnInterface(transaction, processName);
2428 }
2429}
2430
Ed Tanous23a21a12020-07-25 04:45:05 +00002431inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002432{
2433 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002434 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002435 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002436 [](const crow::Request&,
2437 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002438 nlohmann::json::array_t buses;
2439 nlohmann::json& bus = buses.emplace_back();
2440 bus["name"] = "system";
2441 asyncResp->res.jsonValue["busses"] = std::move(buses);
2442 asyncResp->res.jsonValue["status"] = "ok";
2443 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002444
2445 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002446 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002447 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002448 [](const crow::Request&,
2449 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002450 auto myCallback = [asyncResp](const boost::system::error_code& ec,
zhanghch058d1b46d2021-04-01 11:18:24 +08002451 std::vector<std::string>& names) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002452 if (ec)
2453 {
2454 BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
2455 asyncResp->res.result(
2456 boost::beast::http::status::internal_server_error);
2457 }
2458 else
2459 {
2460 std::sort(names.begin(), names.end());
2461 asyncResp->res.jsonValue["status"] = "ok";
2462 auto& objectsSub = asyncResp->res.jsonValue["objects"];
Ed Tanous02cad962022-06-30 16:50:15 -07002463 for (const auto& name : names)
Ed Tanous002d39b2022-05-31 08:59:27 -07002464 {
2465 nlohmann::json::object_t object;
2466 object["name"] = name;
2467 objectsSub.push_back(std::move(object));
2468 }
2469 }
2470 };
2471 crow::connections::systemBus->async_method_call(
2472 std::move(myCallback), "org.freedesktop.DBus", "/",
2473 "org.freedesktop.DBus", "ListNames");
2474 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002475
2476 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002477 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002478 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002479 [](const crow::Request&,
2480 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002481 handleList(asyncResp, "/");
2482 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002483
2484 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002485 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002486 .methods(boost::beast::http::verb::get)(
2487 [](const crow::Request& req,
2488 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002489 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002490 std::string objectPath = "/xyz/" + path;
2491 handleDBusUrl(req, asyncResp, objectPath);
2492 });
zhanghch058d1b46d2021-04-01 11:18:24 +08002493
2494 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002495 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002496 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2497 boost::beast::http::verb::delete_)(
2498 [](const crow::Request& req,
2499 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2500 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002501 std::string objectPath = "/xyz/" + path;
2502 handleDBusUrl(req, asyncResp, objectPath);
2503 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002504
Ed Tanous049a0512018-11-01 13:58:42 -07002505 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002506 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002507 .methods(boost::beast::http::verb::get)(
2508 [](const crow::Request& req,
2509 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2510 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002511 std::string objectPath = "/org/" + path;
2512 handleDBusUrl(req, asyncResp, objectPath);
2513 });
Tanousf00032d2018-11-05 01:18:10 -03002514
2515 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002516 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002517 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2518 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002519 [](const crow::Request& req,
2520 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002521 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002522 std::string objectPath = "/org/" + path;
2523 handleDBusUrl(req, asyncResp, objectPath);
2524 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002525
Ed Tanous1abe55e2018-09-05 08:30:59 -07002526 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002527 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002528 .methods(boost::beast::http::verb::get)(
2529 [](const crow::Request&,
2530 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2531 const std::string& dumpId) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002532 if (!validateFilename(dumpId))
2533 {
2534 asyncResp->res.result(boost::beast::http::status::bad_request);
2535 return;
2536 }
2537 std::filesystem::path loc("/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002538
Ed Tanous002d39b2022-05-31 08:59:27 -07002539 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002540
Ed Tanous002d39b2022-05-31 08:59:27 -07002541 if (!std::filesystem::exists(loc) ||
2542 !std::filesystem::is_directory(loc))
2543 {
2544 BMCWEB_LOG_ERROR << loc.string() << "Not found";
2545 asyncResp->res.result(boost::beast::http::status::not_found);
2546 return;
2547 }
2548 std::filesystem::directory_iterator files(loc);
zhanghch058d1b46d2021-04-01 11:18:24 +08002549
Ed Tanous002d39b2022-05-31 08:59:27 -07002550 for (const auto& file : files)
2551 {
2552 std::ifstream readFile(file.path());
2553 if (!readFile.good())
2554 {
2555 continue;
2556 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002557
Ed Tanousd9f6c622022-03-17 09:12:17 -07002558 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07002559 "application/octet-stream");
zhanghch058d1b46d2021-04-01 11:18:24 +08002560
Ed Tanous002d39b2022-05-31 08:59:27 -07002561 // Assuming only one dump file will be present in the dump
2562 // id directory
2563 std::string dumpFileName = file.path().filename().string();
zhanghch058d1b46d2021-04-01 11:18:24 +08002564
Ed Tanous002d39b2022-05-31 08:59:27 -07002565 // Filename should be in alphanumeric, dot and underscore
2566 // Its based on phosphor-debug-collector application
2567 // dumpfile format
2568 std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
2569 if (!std::regex_match(dumpFileName, dumpFileRegex))
2570 {
2571 BMCWEB_LOG_ERROR << "Invalid dump filename " << dumpFileName;
zhanghch058d1b46d2021-04-01 11:18:24 +08002572 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002573 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07002574 }
2575 std::string contentDispositionParam =
2576 "attachment; filename=\"" + dumpFileName + "\"";
2577
Ed Tanousd9f6c622022-03-17 09:12:17 -07002578 asyncResp->res.addHeader(
2579 boost::beast::http::field::content_disposition,
2580 contentDispositionParam);
Ed Tanous002d39b2022-05-31 08:59:27 -07002581
2582 asyncResp->res.body() = {std::istreambuf_iterator<char>(readFile),
2583 std::istreambuf_iterator<char>()};
2584 return;
2585 }
2586 asyncResp->res.result(boost::beast::http::status::not_found);
2587 return;
2588 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002589
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002590 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002591 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002592
2593 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002594 [](const crow::Request&,
2595 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002596 const std::string& connection) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002597 introspectObjects(connection, "/", asyncResp);
2598 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002599
2600 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002601 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous1656b292022-05-04 11:33:42 -07002602 .methods(boost::beast::http::verb::get,
2603 boost::beast::http::verb::post)(handleBusSystemPost);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002604}
2605} // namespace openbmc_mapper
2606} // namespace crow