blob: 2665b2e6d161e5ccb514f92f4d2e9e7d16dd1e63 [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"
23#include "routing.hpp"
Ed Tanous50ebd4a2023-01-19 19:03:17 -080024#include "str_utility.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000025
26#include <systemd/sd-bus-protocol.h>
27#include <systemd/sd-bus.h>
Ed Tanous911ac312017-08-15 09:37:42 -070028#include <tinyxml2.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -070029
Ed Tanous11ba3972022-07-11 09:50:41 -070030#include <boost/algorithm/string/classification.hpp>
31#include <boost/algorithm/string/predicate.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000032#include <boost/beast/http/status.hpp>
33#include <boost/beast/http/verb.hpp>
34#include <boost/container/flat_map.hpp>
35#include <boost/container/vector.hpp>
36#include <boost/iterator/iterator_facade.hpp>
George Liue99073f2022-12-09 11:06:16 +080037#include <boost/system/error_code.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000038#include <nlohmann/json.hpp>
39#include <sdbusplus/asio/connection.hpp>
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +020040#include <sdbusplus/asio/property.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000041#include <sdbusplus/exception.hpp>
42#include <sdbusplus/message.hpp>
43#include <sdbusplus/message/native_types.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050044
Nan Zhoud5c80ad2022-07-11 01:16:31 +000045#include <algorithm>
46#include <array>
47#include <cerrno>
48#include <cstdint>
49#include <cstring>
James Feist4418c7f2019-04-15 11:09:15 -070050#include <filesystem>
Ed Tanousd4bb9bb2018-05-16 13:36:42 -070051#include <fstream>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000052#include <functional>
53#include <initializer_list>
54#include <iterator>
55#include <limits>
56#include <map>
57#include <memory>
Ramesh Iyyard9207042019-07-05 08:04:42 -050058#include <regex>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000059#include <string>
60#include <string_view>
61#include <type_traits>
Ed Tanousb5a76932020-09-29 16:16:58 -070062#include <utility>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000063#include <variant>
64#include <vector>
65
66// IWYU pragma: no_include <boost/algorithm/string/detail/classification.hpp>
67// IWYU pragma: no_include <boost/system/detail/error_code.hpp>
68// IWYU pragma: no_include <boost/system/detail/error_category.hpp>
69// IWYU pragma: no_include <errno.h>
70// IWYU pragma: no_include <string.h>
71// IWYU pragma: no_include <ext/alloc_traits.h>
72// IWYU pragma: no_include <exception>
73// IWYU pragma: no_include <boost/type_index/type_index_facade.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -070074
Ed Tanous1abe55e2018-09-05 08:30:59 -070075namespace crow
76{
77namespace openbmc_mapper
78{
Ed Tanous23a21a12020-07-25 04:45:05 +000079const constexpr char* notFoundMsg = "404 Not Found";
80const constexpr char* badReqMsg = "400 Bad Request";
81const constexpr char* methodNotAllowedMsg = "405 Method Not Allowed";
82const constexpr char* forbiddenMsg = "403 Forbidden";
83const constexpr char* methodFailedMsg = "500 Method Call Failed";
84const constexpr char* methodOutputFailedMsg = "500 Method Output Error";
85const constexpr char* notFoundDesc =
Matt Spinler2ae60092018-12-06 10:35:36 -060086 "org.freedesktop.DBus.Error.FileNotFound: path or object not found";
Ed Tanous23a21a12020-07-25 04:45:05 +000087const constexpr char* propNotFoundDesc =
88 "The specified property cannot be found";
89const constexpr char* noJsonDesc = "No JSON object could be decoded";
90const constexpr char* methodNotFoundDesc =
91 "The specified method cannot be found";
92const constexpr char* methodNotAllowedDesc = "Method not allowed";
93const constexpr char* forbiddenPropDesc =
94 "The specified property cannot be created";
95const constexpr char* forbiddenResDesc =
96 "The specified resource cannot be created";
Matt Spinler2ae60092018-12-06 10:35:36 -060097
Josh Lehan482c45a2022-03-29 17:10:44 -070098inline bool validateFilename(const std::string& filename)
99{
100 std::regex validFilename(R"(^[\w\- ]+(\.?[\w\- ]*)$)");
101
102 return std::regex_match(filename, validFilename);
103}
104
Ed Tanous23a21a12020-07-25 04:45:05 +0000105inline void setErrorResponse(crow::Response& res,
106 boost::beast::http::status result,
107 const std::string& desc,
108 const std::string_view msg)
Matt Spinler2ae60092018-12-06 10:35:36 -0600109{
110 res.result(result);
Ed Tanous14766872022-03-15 10:44:42 -0700111 res.jsonValue["data"]["description"] = desc;
112 res.jsonValue["message"] = msg;
113 res.jsonValue["status"] = "error";
Matt Spinler2ae60092018-12-06 10:35:36 -0600114}
115
Ed Tanousb5a76932020-09-29 16:16:58 -0700116inline void
117 introspectObjects(const std::string& processName,
118 const std::string& objectPath,
119 const std::shared_ptr<bmcweb::AsyncResp>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700120{
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700121 if (transaction->res.jsonValue.is_null())
122 {
Ed Tanous14766872022-03-15 10:44:42 -0700123 transaction->res.jsonValue["status"] = "ok";
124 transaction->res.jsonValue["bus_name"] = processName;
125 transaction->res.jsonValue["objects"] = nlohmann::json::array();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700126 }
127
Ed Tanous1abe55e2018-09-05 08:30:59 -0700128 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700129 [transaction, processName{std::string(processName)},
130 objectPath{std::string(objectPath)}](
131 const boost::system::error_code ec,
Ed Tanous81ce6092020-12-17 16:54:55 +0000132 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700133 if (ec)
134 {
135 BMCWEB_LOG_ERROR
136 << "Introspect call failed with error: " << ec.message()
137 << " on process: " << processName << " path: " << objectPath
138 << "\n";
139 return;
140 }
141 nlohmann::json::object_t object;
142 object["path"] = objectPath;
Ed Tanous14766872022-03-15 10:44:42 -0700143
Ed Tanous002d39b2022-05-31 08:59:27 -0700144 transaction->res.jsonValue["objects"].push_back(std::move(object));
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700145
Ed Tanous002d39b2022-05-31 08:59:27 -0700146 tinyxml2::XMLDocument doc;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700147
Ed Tanous002d39b2022-05-31 08:59:27 -0700148 doc.Parse(introspectXml.c_str());
149 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
150 if (pRoot == nullptr)
151 {
152 BMCWEB_LOG_ERROR << "XML document failed to parse " << processName
153 << " " << objectPath << "\n";
154 }
155 else
156 {
157 tinyxml2::XMLElement* node = pRoot->FirstChildElement("node");
158 while (node != nullptr)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700159 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700160 const char* childPath = node->Attribute("name");
161 if (childPath != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700162 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700163 std::string newpath;
164 if (objectPath != "/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700165 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700166 newpath += objectPath;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700167 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700168 newpath += std::string("/") + childPath;
169 // introspect the subobjects as well
170 introspectObjects(processName, newpath, transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700171 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700172
173 node = node->NextSiblingElement("node");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700174 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700175 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700176 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700177 processName, objectPath, "org.freedesktop.DBus.Introspectable",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700178 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -0700179}
Ed Tanous64530012018-02-06 17:08:16 -0800180
Ed Tanous23a21a12020-07-25 04:45:05 +0000181inline void getPropertiesForEnumerate(
182 const std::string& objectPath, const std::string& service,
Ed Tanousb5a76932020-09-29 16:16:58 -0700183 const std::string& interface,
184 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600185{
186 BMCWEB_LOG_DEBUG << "getPropertiesForEnumerate " << objectPath << " "
187 << service << " " << interface;
188
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +0200189 sdbusplus::asio::getAllProperties(
190 *crow::connections::systemBus, service, objectPath, interface,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800191 [asyncResp, objectPath, service,
192 interface](const boost::system::error_code ec,
193 const dbus::utility::DBusPropertiesMap& propertiesList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700194 if (ec)
195 {
196 BMCWEB_LOG_ERROR << "GetAll on path " << objectPath << " iface "
197 << interface << " service " << service
198 << " failed with code " << ec;
199 return;
200 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600201
Ed Tanous002d39b2022-05-31 08:59:27 -0700202 nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
203 nlohmann::json& objectJson = dataJson[objectPath];
204 if (objectJson.is_null())
205 {
206 objectJson = nlohmann::json::object();
207 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600208
Ed Tanous002d39b2022-05-31 08:59:27 -0700209 for (const auto& [name, value] : propertiesList)
210 {
211 nlohmann::json& propertyJson = objectJson[name];
212 std::visit(
213 [&propertyJson](auto&& val) {
214 if constexpr (std::is_same_v<std::decay_t<decltype(val)>,
215 sdbusplus::message::unix_fd>)
216 {
217 propertyJson = val.fd;
218 }
219 else
220 {
Ed Tanousd1a64812021-12-13 12:14:05 -0800221
Ed Tanous002d39b2022-05-31 08:59:27 -0700222 propertyJson = val;
223 }
224 },
225 value);
226 }
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +0200227 });
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600228}
229
230// Find any results that weren't picked up by ObjectManagers, to be
231// called after all ObjectManagers are searched for and called.
Ed Tanous23a21a12020-07-25 04:45:05 +0000232inline void findRemainingObjectsForEnumerate(
Ed Tanousb5a76932020-09-29 16:16:58 -0700233 const std::string& objectPath,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800234 const std::shared_ptr<dbus::utility::MapperGetSubTreeResponse>& subtree,
Ed Tanousb5a76932020-09-29 16:16:58 -0700235 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600236{
237 BMCWEB_LOG_DEBUG << "findRemainingObjectsForEnumerate";
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500238 const nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600239
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500240 for (const auto& [path, interface_map] : *subtree)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600241 {
242 if (path == objectPath)
243 {
244 // An enumerate does not return the target path's properties
245 continue;
246 }
247 if (dataJson.find(path) == dataJson.end())
248 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500249 for (const auto& [service, interfaces] : interface_map)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600250 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500251 for (const auto& interface : interfaces)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600252 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700253 if (!interface.starts_with("org.freedesktop.DBus"))
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600254 {
255 getPropertiesForEnumerate(path, service, interface,
256 asyncResp);
257 }
258 }
259 }
260 }
261 }
262}
263
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600264struct InProgressEnumerateData
265{
zhanghch058d1b46d2021-04-01 11:18:24 +0800266 InProgressEnumerateData(
267 const std::string& objectPathIn,
268 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
Ed Tanous23a21a12020-07-25 04:45:05 +0000269 objectPath(objectPathIn),
zhanghch058d1b46d2021-04-01 11:18:24 +0800270 asyncResp(asyncRespIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500271 {}
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600272
273 ~InProgressEnumerateData()
274 {
Ed Tanous24b2fe82022-01-06 12:45:54 -0800275 try
276 {
277 findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
278 }
279 catch (...)
280 {
281 BMCWEB_LOG_CRITICAL
282 << "findRemainingObjectsForEnumerate threw exception";
283 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600284 }
285
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800286 InProgressEnumerateData(const InProgressEnumerateData&) = delete;
287 InProgressEnumerateData(InProgressEnumerateData&&) = delete;
288 InProgressEnumerateData& operator=(const InProgressEnumerateData&) = delete;
289 InProgressEnumerateData& operator=(InProgressEnumerateData&&) = delete;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600290 const std::string objectPath;
Ed Tanousb9d36b42022-02-26 21:42:46 -0800291 std::shared_ptr<dbus::utility::MapperGetSubTreeResponse> subtree;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600292 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
293};
294
Ed Tanous23a21a12020-07-25 04:45:05 +0000295inline void getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000296 const std::string& objectName, const std::string& objectManagerPath,
297 const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700298 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700299{
Ed Tanous81ce6092020-12-17 16:54:55 +0000300 BMCWEB_LOG_DEBUG << "getManagedObjectsForEnumerate " << objectName
301 << " object_manager_path " << objectManagerPath
302 << " connection_name " << connectionName;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700303 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000304 [transaction, objectName,
305 connectionName](const boost::system::error_code ec,
306 const dbus::utility::ManagedObjectType& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700307 if (ec)
308 {
309 BMCWEB_LOG_ERROR << "GetManagedObjects on path " << objectName
310 << " on connection " << connectionName
311 << " failed with code " << ec;
312 return;
313 }
Ed Tanous64530012018-02-06 17:08:16 -0800314
Ed Tanous002d39b2022-05-31 08:59:27 -0700315 nlohmann::json& dataJson =
316 transaction->asyncResp->res.jsonValue["data"];
Ed Tanous049a0512018-11-01 13:58:42 -0700317
Ed Tanous002d39b2022-05-31 08:59:27 -0700318 for (const auto& objectPath : objects)
319 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700320 if (objectPath.first.str.starts_with(objectName))
Ed Tanous049a0512018-11-01 13:58:42 -0700321 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700322 BMCWEB_LOG_DEBUG << "Reading object " << objectPath.first.str;
323 nlohmann::json& objectJson = dataJson[objectPath.first.str];
324 if (objectJson.is_null())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700325 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700326 objectJson = nlohmann::json::object();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700327 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500328 for (const auto& interface : objectPath.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700329 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700330 for (const auto& property : interface.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700331 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700332 nlohmann::json& propertyJson =
333 objectJson[property.first];
334 std::visit(
335 [&propertyJson](auto&& val) {
336 if constexpr (std::is_same_v<
337 std::decay_t<decltype(val)>,
338 sdbusplus::message::unix_fd>)
339 {
340 propertyJson = val.fd;
341 }
342 else
343 {
344
345 propertyJson = val;
346 }
347 },
348 property.second);
Ed Tanous049a0512018-11-01 13:58:42 -0700349 }
350 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700351 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700352 for (const auto& interface : objectPath.second)
353 {
354 if (interface.first == "org.freedesktop.DBus.ObjectManager")
355 {
356 getManagedObjectsForEnumerate(objectPath.first.str,
357 objectPath.first.str,
358 connectionName, transaction);
359 }
360 }
361 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700362 },
Ed Tanous81ce6092020-12-17 16:54:55 +0000363 connectionName, objectManagerPath, "org.freedesktop.DBus.ObjectManager",
364 "GetManagedObjects");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700365}
366
Ed Tanous23a21a12020-07-25 04:45:05 +0000367inline void findObjectManagerPathForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000368 const std::string& objectName, const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700369 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700370{
Ed Tanous81ce6092020-12-17 16:54:55 +0000371 BMCWEB_LOG_DEBUG << "Finding objectmanager for path " << objectName
372 << " on connection:" << connectionName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700373 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000374 [transaction, objectName, connectionName](
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700375 const boost::system::error_code ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800376 const dbus::utility::MapperGetAncestorsResponse& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700377 if (ec)
378 {
379 BMCWEB_LOG_ERROR << "GetAncestors on path " << objectName
380 << " failed with code " << ec;
381 return;
382 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700383
Ed Tanous002d39b2022-05-31 08:59:27 -0700384 for (const auto& pathGroup : objects)
385 {
386 for (const auto& connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700387 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700388 if (connectionGroup.first == connectionName)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700389 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700390 // Found the object manager path for this resource.
391 getManagedObjectsForEnumerate(objectName, pathGroup.first,
392 connectionName, transaction);
393 return;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700394 }
395 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700396 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700397 },
398 "xyz.openbmc_project.ObjectMapper",
399 "/xyz/openbmc_project/object_mapper",
Ed Tanous81ce6092020-12-17 16:54:55 +0000400 "xyz.openbmc_project.ObjectMapper", "GetAncestors", objectName,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500401 std::array<const char*, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700402}
Ed Tanous64530012018-02-06 17:08:16 -0800403
Ed Tanous7c091622019-05-23 11:42:36 -0700404// Uses GetObject to add the object info about the target /enumerate path to
405// the results of GetSubTree, as GetSubTree will not return info for the
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600406// target path, and then continues on enumerating the rest of the tree.
Ed Tanousb5a76932020-09-29 16:16:58 -0700407inline void getObjectAndEnumerate(
408 const std::shared_ptr<InProgressEnumerateData>& transaction)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600409{
George Liu2b731192023-01-11 16:27:13 +0800410 dbus::utility::getDbusObject(
411 transaction->objectPath, {},
412 [transaction](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800413 const dbus::utility::MapperGetObject& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700414 if (ec)
415 {
416 BMCWEB_LOG_ERROR << "GetObject for path " << transaction->objectPath
417 << " failed with code " << ec;
418 return;
419 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600420
Ed Tanous002d39b2022-05-31 08:59:27 -0700421 BMCWEB_LOG_DEBUG << "GetObject for " << transaction->objectPath
422 << " has " << objects.size() << " entries";
423 if (!objects.empty())
424 {
425 transaction->subtree->emplace_back(transaction->objectPath,
426 objects);
427 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600428
Ed Tanous002d39b2022-05-31 08:59:27 -0700429 // Map indicating connection name, and the path where the object
430 // manager exists
431 boost::container::flat_map<std::string, std::string> connections;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600432
Ed Tanous002d39b2022-05-31 08:59:27 -0700433 for (const auto& object : *(transaction->subtree))
434 {
435 for (const auto& connection : object.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600436 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700437 for (const auto& interface : connection.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600438 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700439 BMCWEB_LOG_DEBUG << connection.first << " has interface "
440 << interface;
441 if (interface == "org.freedesktop.DBus.ObjectManager")
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600442 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700443 BMCWEB_LOG_DEBUG << "found object manager path "
444 << object.first;
Ed Tanousf8fe53e2022-06-30 15:55:45 -0700445 connections[connection.first] = object.first;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600446 }
447 }
448 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700449 }
450 BMCWEB_LOG_DEBUG << "Got " << connections.size() << " connections";
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600451
Ed Tanous002d39b2022-05-31 08:59:27 -0700452 for (const auto& connection : connections)
453 {
454 // If we already know where the object manager is, we don't
455 // need to search for it, we can call directly in to
456 // getManagedObjects
457 if (!connection.second.empty())
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600458 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700459 getManagedObjectsForEnumerate(transaction->objectPath,
460 connection.second,
461 connection.first, transaction);
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600462 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700463 else
464 {
465 // otherwise we need to find the object manager path
466 // before we can continue
467 findObjectManagerPathForEnumerate(
468 transaction->objectPath, connection.first, transaction);
469 }
470 }
George Liu2b731192023-01-11 16:27:13 +0800471 });
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600472}
Ed Tanous64530012018-02-06 17:08:16 -0800473
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700474// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700475struct InProgressActionData
476{
Ed Tanous4e23a442022-06-06 09:57:26 -0700477 explicit InProgressActionData(crow::Response& resIn) : res(resIn)
Ed Tanous23a21a12020-07-25 04:45:05 +0000478 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700479 ~InProgressActionData()
480 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600481 // Methods could have been called across different owners
482 // and interfaces, where some calls failed and some passed.
483 //
484 // The rules for this are:
485 // * if no method was called - error
486 // * if a method failed and none passed - error
487 // (converse: if at least one method passed - OK)
488 // * for the method output:
489 // * if output processing didn't fail, return the data
490
491 // Only deal with method returns if nothing failed earlier
492 if (res.result() == boost::beast::http::status::ok)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700493 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600494 if (!methodPassed)
495 {
Matt Spinler06b1b632019-06-18 16:09:25 -0500496 if (!methodFailed)
Matt Spinler16caaee2019-01-15 11:40:34 -0600497 {
498 setErrorResponse(res, boost::beast::http::status::not_found,
499 methodNotFoundDesc, notFoundMsg);
500 }
501 }
502 else
503 {
504 if (outputFailed)
505 {
506 setErrorResponse(
507 res, boost::beast::http::status::internal_server_error,
508 "Method output failure", methodOutputFailedMsg);
509 }
510 else
511 {
Ed Tanous14766872022-03-15 10:44:42 -0700512 res.jsonValue["status"] = "ok";
513 res.jsonValue["message"] = "200 OK";
514 res.jsonValue["data"] = methodResponse;
Matt Spinler16caaee2019-01-15 11:40:34 -0600515 }
516 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700517 }
Matt Spinler16caaee2019-01-15 11:40:34 -0600518
Ed Tanous1abe55e2018-09-05 08:30:59 -0700519 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700520 }
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800521 InProgressActionData(const InProgressActionData&) = delete;
522 InProgressActionData(InProgressActionData&&) = delete;
523 InProgressActionData& operator=(const InProgressActionData&) = delete;
524 InProgressActionData& operator=(InProgressActionData&&) = delete;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700525
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500526 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700527 {
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600528 setErrorResponse(res, boost::beast::http::status::bad_request, desc,
529 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700530 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500531 crow::Response& res;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700532 std::string path;
533 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600534 std::string interfaceName;
Matt Spinler16caaee2019-01-15 11:40:34 -0600535 bool methodPassed = false;
536 bool methodFailed = false;
537 bool outputFailed = false;
Matt Spinler39a4e392019-01-15 11:53:13 -0600538 bool convertedToArray = false;
Matt Spinler16caaee2019-01-15 11:40:34 -0600539 nlohmann::json methodResponse;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700540 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700541};
542
Ed Tanous23a21a12020-07-25 04:45:05 +0000543inline std::vector<std::string> dbusArgSplit(const std::string& string)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700544{
545 std::vector<std::string> ret;
546 if (string.empty())
547 {
548 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700549 }
Ed Tanous0f0353b2019-10-24 11:37:51 -0700550 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700551 int containerDepth = 0;
552
553 for (std::string::const_iterator character = string.begin();
554 character != string.end(); character++)
555 {
556 ret.back() += *character;
557 switch (*character)
558 {
559 case ('a'):
560 break;
561 case ('('):
562 case ('{'):
563 containerDepth++;
564 break;
565 case ('}'):
566 case (')'):
567 containerDepth--;
568 if (containerDepth == 0)
569 {
570 if (character + 1 != string.end())
571 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700572 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700573 }
574 }
575 break;
576 default:
577 if (containerDepth == 0)
578 {
579 if (character + 1 != string.end())
580 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700581 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700582 }
583 }
584 break;
585 }
586 }
Matt Spinler4ae611d2019-01-11 15:37:06 -0600587
588 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700589}
590
Ed Tanous81ce6092020-12-17 16:54:55 +0000591inline int convertJsonToDbus(sd_bus_message* m, const std::string& argType,
592 const nlohmann::json& inputJson)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700593{
594 int r = 0;
Ed Tanous71f52d92021-02-19 08:51:17 -0800595 BMCWEB_LOG_DEBUG << "Converting "
596 << inputJson.dump(2, ' ', true,
597 nlohmann::json::error_handler_t::replace)
Ed Tanous81ce6092020-12-17 16:54:55 +0000598 << " to type: " << argType;
599 const std::vector<std::string> argTypes = dbusArgSplit(argType);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700600
Ed Tanous1abe55e2018-09-05 08:30:59 -0700601 // Assume a single object for now.
Ed Tanous81ce6092020-12-17 16:54:55 +0000602 const nlohmann::json* j = &inputJson;
603 nlohmann::json::const_iterator jIt = inputJson.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700604
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500605 for (const std::string& argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700606 {
607 // If we are decoding multiple objects, grab the pointer to the
608 // iterator, and increment it for the next loop
609 if (argTypes.size() > 1)
610 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000611 if (jIt == inputJson.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700612 {
613 return -2;
614 }
615 j = &*jIt;
616 jIt++;
617 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500618 const int64_t* intValue = j->get_ptr<const int64_t*>();
619 const std::string* stringValue = j->get_ptr<const std::string*>();
620 const double* doubleValue = j->get_ptr<const double*>();
621 const bool* b = j->get_ptr<const bool*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700622 int64_t v = 0;
623 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700624
Ed Tanous1abe55e2018-09-05 08:30:59 -0700625 // Do some basic type conversions that make sense. uint can be
626 // converted to int. int and uint can be converted to double
Ed Tanous66664f22019-10-11 13:05:49 -0700627 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700628 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500629 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700630 if (uintValue != nullptr)
631 {
632 v = static_cast<int64_t>(*uintValue);
633 intValue = &v;
634 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700635 }
Ed Tanous66664f22019-10-11 13:05:49 -0700636 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700637 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500638 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700639 if (uintValue != nullptr)
640 {
641 d = static_cast<double>(*uintValue);
642 doubleValue = &d;
643 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700644 }
Ed Tanous66664f22019-10-11 13:05:49 -0700645 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700646 {
Ed Tanous66664f22019-10-11 13:05:49 -0700647 if (intValue != nullptr)
648 {
649 d = static_cast<double>(*intValue);
650 doubleValue = &d;
651 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700652 }
653
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700654 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700655 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700656 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700657 {
658 return -1;
659 }
Ed Tanous271584a2019-07-09 16:24:22 -0700660 r = sd_bus_message_append_basic(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500661 m, argCode[0], static_cast<const void*>(stringValue->data()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700662 if (r < 0)
663 {
664 return r;
665 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700666 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700667 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700668 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700669 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700670 {
671 return -1;
672 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500673 if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
674 (*intValue > std::numeric_limits<int32_t>::max()))
675 {
676 return -ERANGE;
677 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700678 int32_t i = static_cast<int32_t>(*intValue);
679 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700680 if (r < 0)
681 {
682 return r;
683 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700684 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700685 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700686 {
687 // lots of ways bool could be represented here. Try them all
Ed Tanouse662eae2022-01-25 10:39:19 -0800688 int boolInt = 0;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700689 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700690 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500691 if (*intValue == 1)
692 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800693 boolInt = 1;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500694 }
695 else if (*intValue == 0)
696 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800697 boolInt = 0;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500698 }
699 else
700 {
701 return -ERANGE;
702 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700703 }
704 else if (b != nullptr)
705 {
Matt Spinlera2f02632019-01-18 10:15:35 -0600706 boolInt = *b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700707 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700708 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700709 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700710 boolInt = boost::istarts_with(*stringValue, "t") ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700711 }
712 else
713 {
714 return -1;
715 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700716 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700717 if (r < 0)
718 {
719 return r;
720 }
721 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700722 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700723 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700724 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700725 {
726 return -1;
727 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500728 if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
729 (*intValue > std::numeric_limits<int16_t>::max()))
730 {
731 return -ERANGE;
732 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700733 int16_t n = static_cast<int16_t>(*intValue);
734 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700735 if (r < 0)
736 {
737 return r;
738 }
739 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700740 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700741 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700742 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700743 {
744 return -1;
745 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700746 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700747 if (r < 0)
748 {
749 return r;
750 }
751 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700752 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700753 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500754 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700755 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700756 {
757 return -1;
758 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000759 if (*uintValue > std::numeric_limits<uint8_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500760 {
761 return -ERANGE;
762 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700763 uint8_t y = static_cast<uint8_t>(*uintValue);
764 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700765 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700766 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700767 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500768 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700769 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700770 {
771 return -1;
772 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000773 if (*uintValue > std::numeric_limits<uint16_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500774 {
775 return -ERANGE;
776 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700777 uint16_t q = static_cast<uint16_t>(*uintValue);
778 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700779 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700780 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700781 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500782 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700783 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700784 {
785 return -1;
786 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000787 if (*uintValue > std::numeric_limits<uint32_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500788 {
789 return -ERANGE;
790 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700791 uint32_t u = static_cast<uint32_t>(*uintValue);
792 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700793 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700794 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700795 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500796 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700797 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700798 {
799 return -1;
800 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700801 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700802 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700803 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700804 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500805 if (doubleValue == nullptr)
806 {
807 return -1;
808 }
809 if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
810 (*doubleValue > std::numeric_limits<double>::max()))
811 {
812 return -ERANGE;
813 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700814 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700815 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700816 else if (argCode.starts_with("a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700817 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700818 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700819 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700820 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700821 if (r < 0)
822 {
823 return r;
824 }
825
Ed Tanous0dfeda62019-10-24 11:21:38 -0700826 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700827 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700828 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700829 if (r < 0)
830 {
831 return r;
832 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700833 }
834 sd_bus_message_close_container(m);
835 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700836 else if (argCode.starts_with("v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700837 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700838 std::string containedType = argCode.substr(1);
839 BMCWEB_LOG_DEBUG << "variant type: " << argCode
840 << " appending variant of type: " << containedType;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700841 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700842 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700843 if (r < 0)
844 {
845 return r;
846 }
847
Ed Tanous81ce6092020-12-17 16:54:55 +0000848 r = convertJsonToDbus(m, containedType, inputJson);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700849 if (r < 0)
850 {
851 return r;
852 }
853
854 r = sd_bus_message_close_container(m);
855 if (r < 0)
856 {
857 return r;
858 }
859 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700860 else if (argCode.starts_with("(") && argCode.ends_with(")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700861 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700862 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700863 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700864 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800865 if (r < 0)
866 {
867 return r;
868 }
869
Ed Tanous1abe55e2018-09-05 08:30:59 -0700870 nlohmann::json::const_iterator it = j->begin();
Ed Tanous81ce6092020-12-17 16:54:55 +0000871 for (const std::string& argCode2 : dbusArgSplit(argType))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700872 {
873 if (it == j->end())
874 {
875 return -1;
876 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000877 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700878 if (r < 0)
879 {
880 return r;
881 }
882 it++;
883 }
884 r = sd_bus_message_close_container(m);
885 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700886 else if (argCode.starts_with("{") && argCode.ends_with("}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700887 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700888 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700889 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700890 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800891 if (r < 0)
892 {
893 return r;
894 }
895
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700896 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700897 if (codes.size() != 2)
898 {
899 return -1;
900 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700901 const std::string& keyType = codes[0];
902 const std::string& valueType = codes[1];
Ed Tanous3174e4d2020-10-07 11:41:22 -0700903 for (const auto& it : j->items())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700904 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700905 r = convertJsonToDbus(m, keyType, it.key());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700906 if (r < 0)
907 {
908 return r;
909 }
910
Ed Tanous2c70f802020-09-28 14:29:23 -0700911 r = convertJsonToDbus(m, valueType, it.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700912 if (r < 0)
913 {
914 return r;
915 }
916 }
917 r = sd_bus_message_close_container(m);
918 }
919 else
920 {
921 return -2;
922 }
923 if (r < 0)
924 {
925 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700926 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700927
Ed Tanous1abe55e2018-09-05 08:30:59 -0700928 if (argTypes.size() > 1)
929 {
930 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700931 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700932 }
Matt Spinler127ea542019-01-14 11:04:28 -0600933
934 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700935}
936
Matt Spinlerd22a7132019-01-14 12:14:30 -0600937template <typename T>
Patrick Williams59d494e2022-07-22 19:26:55 -0500938int readMessageItem(const std::string& typeCode, sdbusplus::message_t& m,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500939 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600940{
941 T value;
942
943 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
944 if (r < 0)
945 {
946 BMCWEB_LOG_ERROR << "sd_bus_message_read_basic on type " << typeCode
947 << " failed!";
948 return r;
949 }
950
951 data = value;
952 return 0;
953}
954
Patrick Williams59d494e2022-07-22 19:26:55 -0500955int convertDBusToJSON(const std::string& returnType, sdbusplus::message_t& m,
956 nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600957
Ed Tanous23a21a12020-07-25 04:45:05 +0000958inline int readDictEntryFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -0500959 sdbusplus::message_t& m,
Ed Tanous23a21a12020-07-25 04:45:05 +0000960 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600961{
962 std::vector<std::string> types = dbusArgSplit(typeCode);
963 if (types.size() != 2)
964 {
965 BMCWEB_LOG_ERROR << "wrong number contained types in dictionary: "
966 << types.size();
967 return -1;
968 }
969
970 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
971 typeCode.c_str());
972 if (r < 0)
973 {
974 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container with rc " << r;
975 return r;
976 }
977
978 nlohmann::json key;
979 r = convertDBusToJSON(types[0], m, key);
980 if (r < 0)
981 {
982 return r;
983 }
984
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500985 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -0600986 if (keyPtr == nullptr)
987 {
988 // json doesn't support non-string keys. If we hit this condition,
989 // convert the result to a string so we can proceed
Ed Tanous71f52d92021-02-19 08:51:17 -0800990 key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500991 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -0700992 // in theory this can't fail now, but lets be paranoid about it
993 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -0600994 if (keyPtr == nullptr)
995 {
996 return -1;
997 }
998 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500999 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -06001000
1001 r = convertDBusToJSON(types[1], m, value);
1002 if (r < 0)
1003 {
1004 return r;
1005 }
1006
1007 r = sd_bus_message_exit_container(m.get());
1008 if (r < 0)
1009 {
1010 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1011 return r;
1012 }
1013
1014 return 0;
1015}
1016
Ed Tanous23a21a12020-07-25 04:45:05 +00001017inline int readArrayFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001018 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -06001019{
1020 if (typeCode.size() < 2)
1021 {
1022 BMCWEB_LOG_ERROR << "Type code " << typeCode
1023 << " too small for an array";
1024 return -1;
1025 }
1026
1027 std::string containedType = typeCode.substr(1);
1028
1029 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
1030 containedType.c_str());
1031 if (r < 0)
1032 {
1033 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1034 << r;
1035 return r;
1036 }
1037
Ed Tanous11ba3972022-07-11 09:50:41 -07001038 bool dict = containedType.starts_with("{") && containedType.ends_with("}");
Matt Spinler6df8f992019-01-14 12:47:47 -06001039
1040 if (dict)
1041 {
1042 // Remove the { }
1043 containedType = containedType.substr(1, containedType.size() - 2);
1044 data = nlohmann::json::object();
1045 }
1046 else
1047 {
1048 data = nlohmann::json::array();
1049 }
1050
1051 while (true)
1052 {
Ed Tanouse662eae2022-01-25 10:39:19 -08001053 r = sd_bus_message_at_end(m.get(), 0);
Matt Spinler6df8f992019-01-14 12:47:47 -06001054 if (r < 0)
1055 {
1056 BMCWEB_LOG_ERROR << "sd_bus_message_at_end failed";
1057 return r;
1058 }
1059
1060 if (r > 0)
1061 {
1062 break;
1063 }
1064
1065 // Dictionaries are only ever seen in an array
1066 if (dict)
1067 {
1068 r = readDictEntryFromMessage(containedType, m, data);
1069 if (r < 0)
1070 {
1071 return r;
1072 }
1073 }
1074 else
1075 {
1076 data.push_back(nlohmann::json());
1077
1078 r = convertDBusToJSON(containedType, m, data.back());
1079 if (r < 0)
1080 {
1081 return r;
1082 }
1083 }
1084 }
1085
1086 r = sd_bus_message_exit_container(m.get());
1087 if (r < 0)
1088 {
1089 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1090 return r;
1091 }
1092
1093 return 0;
1094}
1095
Ed Tanous23a21a12020-07-25 04:45:05 +00001096inline int readStructFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001097 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001098{
1099 if (typeCode.size() < 3)
1100 {
1101 BMCWEB_LOG_ERROR << "Type code " << typeCode
1102 << " too small for a struct";
1103 return -1;
1104 }
1105
1106 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1107 std::vector<std::string> types = dbusArgSplit(containedTypes);
1108
1109 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1110 containedTypes.c_str());
1111 if (r < 0)
1112 {
1113 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1114 << r;
1115 return r;
1116 }
1117
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001118 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001119 {
1120 data.push_back(nlohmann::json());
1121 r = convertDBusToJSON(type, m, data.back());
1122 if (r < 0)
1123 {
1124 return r;
1125 }
1126 }
1127
1128 r = sd_bus_message_exit_container(m.get());
1129 if (r < 0)
1130 {
1131 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1132 return r;
1133 }
1134 return 0;
1135}
1136
Patrick Williams59d494e2022-07-22 19:26:55 -05001137inline int readVariantFromMessage(sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001138{
Ed Tanous543f4402022-01-06 13:12:53 -08001139 const char* containerType = nullptr;
Ed Tanous99131cd2019-10-24 11:12:47 -07001140 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001141 if (r < 0)
1142 {
1143 BMCWEB_LOG_ERROR << "sd_bus_message_peek_type failed";
1144 return r;
1145 }
1146
1147 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1148 containerType);
1149 if (r < 0)
1150 {
1151 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1152 << r;
1153 return r;
1154 }
1155
1156 r = convertDBusToJSON(containerType, m, data);
1157 if (r < 0)
1158 {
1159 return r;
1160 }
1161
1162 r = sd_bus_message_exit_container(m.get());
1163 if (r < 0)
1164 {
1165 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed";
1166 return r;
1167 }
1168
1169 return 0;
1170}
1171
Ed Tanous23a21a12020-07-25 04:45:05 +00001172inline int convertDBusToJSON(const std::string& returnType,
Patrick Williams59d494e2022-07-22 19:26:55 -05001173 sdbusplus::message_t& m, nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001174{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001175 int r = 0;
1176 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1177
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001178 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001179 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001180 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001181 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001182 {
1183 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001184 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001185 }
1186
Ed Tanousd4d25792020-09-29 15:15:03 -07001187 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001188 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001189 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001190 if (r < 0)
1191 {
1192 return r;
1193 }
1194 }
1195 else if (typeCode == "b")
1196 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001197 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001198 if (r < 0)
1199 {
1200 return r;
1201 }
1202
Matt Spinlerf39420c2019-01-30 12:57:18 -06001203 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001204 }
1205 else if (typeCode == "u")
1206 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001207 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001208 if (r < 0)
1209 {
1210 return r;
1211 }
1212 }
1213 else if (typeCode == "i")
1214 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001215 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001216 if (r < 0)
1217 {
1218 return r;
1219 }
1220 }
1221 else if (typeCode == "x")
1222 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001223 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001224 if (r < 0)
1225 {
1226 return r;
1227 }
1228 }
1229 else if (typeCode == "t")
1230 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001231 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001232 if (r < 0)
1233 {
1234 return r;
1235 }
1236 }
1237 else if (typeCode == "n")
1238 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001239 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001240 if (r < 0)
1241 {
1242 return r;
1243 }
1244 }
1245 else if (typeCode == "q")
1246 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001247 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001248 if (r < 0)
1249 {
1250 return r;
1251 }
1252 }
1253 else if (typeCode == "y")
1254 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001255 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001256 if (r < 0)
1257 {
1258 return r;
1259 }
1260 }
1261 else if (typeCode == "d")
1262 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001263 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001264 if (r < 0)
1265 {
1266 return r;
1267 }
1268 }
1269 else if (typeCode == "h")
1270 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001271 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001272 if (r < 0)
1273 {
1274 return r;
1275 }
1276 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001277 else if (typeCode.starts_with("a"))
Matt Spinler6df8f992019-01-14 12:47:47 -06001278 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001279 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001280 if (r < 0)
1281 {
1282 return r;
1283 }
1284 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001285 else if (typeCode.starts_with("(") && typeCode.ends_with(")"))
Matt Spinler75c6c672019-01-14 13:01:46 -06001286 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001287 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001288 if (r < 0)
1289 {
1290 return r;
1291 }
1292 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001293 else if (typeCode.starts_with("v"))
Matt Spinler89c19702019-01-14 13:13:00 -06001294 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001295 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001296 if (r < 0)
1297 {
1298 return r;
1299 }
1300 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001301 else
1302 {
Matt Spinlerd22a7132019-01-14 12:14:30 -06001303 BMCWEB_LOG_ERROR << "Invalid D-Bus signature type " << typeCode;
1304 return -2;
1305 }
1306 }
1307
Matt Spinler16caaee2019-01-15 11:40:34 -06001308 return 0;
1309}
1310
Ed Tanousb5a76932020-09-29 16:16:58 -07001311inline void handleMethodResponse(
1312 const std::shared_ptr<InProgressActionData>& transaction,
Patrick Williams59d494e2022-07-22 19:26:55 -05001313 sdbusplus::message_t& m, const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001314{
Matt Spinler39a4e392019-01-15 11:53:13 -06001315 nlohmann::json data;
1316
1317 int r = convertDBusToJSON(returnType, m, data);
1318 if (r < 0)
1319 {
1320 transaction->outputFailed = true;
1321 return;
1322 }
1323
1324 if (data.is_null())
1325 {
1326 return;
1327 }
1328
1329 if (transaction->methodResponse.is_null())
1330 {
1331 transaction->methodResponse = std::move(data);
1332 return;
1333 }
1334
1335 // If they're both dictionaries or arrays, merge into one.
1336 // Otherwise, make the results an array with every result
1337 // an entry. Could also just fail in that case, but it
1338 // seems better to get the data back somehow.
1339
1340 if (transaction->methodResponse.is_object() && data.is_object())
1341 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001342 for (const auto& obj : data.items())
Matt Spinler39a4e392019-01-15 11:53:13 -06001343 {
1344 // Note: Will overwrite the data for a duplicate key
1345 transaction->methodResponse.emplace(obj.key(),
1346 std::move(obj.value()));
1347 }
1348 return;
1349 }
1350
1351 if (transaction->methodResponse.is_array() && data.is_array())
1352 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001353 for (auto& obj : data)
Matt Spinler39a4e392019-01-15 11:53:13 -06001354 {
1355 transaction->methodResponse.push_back(std::move(obj));
1356 }
1357 return;
1358 }
1359
1360 if (!transaction->convertedToArray)
1361 {
1362 // They are different types. May as well turn them into an array
1363 nlohmann::json j = std::move(transaction->methodResponse);
1364 transaction->methodResponse = nlohmann::json::array();
1365 transaction->methodResponse.push_back(std::move(j));
1366 transaction->methodResponse.push_back(std::move(data));
1367 transaction->convertedToArray = true;
1368 }
1369 else
1370 {
1371 transaction->methodResponse.push_back(std::move(data));
1372 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001373}
1374
Ed Tanousb5a76932020-09-29 16:16:58 -07001375inline void findActionOnInterface(
1376 const std::shared_ptr<InProgressActionData>& transaction,
1377 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001378{
1379 BMCWEB_LOG_DEBUG << "findActionOnInterface for connection "
1380 << connectionName;
1381 crow::connections::systemBus->async_method_call(
1382 [transaction, connectionName{std::string(connectionName)}](
1383 const boost::system::error_code ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001384 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001385 BMCWEB_LOG_DEBUG << "got xml:\n " << introspectXml;
1386 if (ec)
1387 {
1388 BMCWEB_LOG_ERROR
1389 << "Introspect call failed with error: " << ec.message()
1390 << " on process: " << connectionName << "\n";
1391 return;
1392 }
1393 tinyxml2::XMLDocument doc;
Matt Spinler318bd892019-01-15 09:59:20 -06001394
Ed Tanous002d39b2022-05-31 08:59:27 -07001395 doc.Parse(introspectXml.data(), introspectXml.size());
1396 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1397 if (pRoot == nullptr)
1398 {
1399 BMCWEB_LOG_ERROR << "XML document failed to parse "
1400 << connectionName << "\n";
1401 return;
1402 }
1403 tinyxml2::XMLElement* interfaceNode =
1404 pRoot->FirstChildElement("interface");
1405 while (interfaceNode != nullptr)
1406 {
1407 const char* thisInterfaceName = interfaceNode->Attribute("name");
1408 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001409 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001410 if (!transaction->interfaceName.empty() &&
1411 (transaction->interfaceName != thisInterfaceName))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001412 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001413 interfaceNode =
1414 interfaceNode->NextSiblingElement("interface");
1415 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001416 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001417
1418 tinyxml2::XMLElement* methodNode =
1419 interfaceNode->FirstChildElement("method");
1420 while (methodNode != nullptr)
1421 {
1422 const char* thisMethodName = methodNode->Attribute("name");
1423 BMCWEB_LOG_DEBUG << "Found method: " << thisMethodName;
1424 if (thisMethodName != nullptr &&
1425 thisMethodName == transaction->methodName)
1426 {
1427 BMCWEB_LOG_DEBUG << "Found method named "
1428 << thisMethodName << " on interface "
1429 << thisInterfaceName;
Patrick Williams59d494e2022-07-22 19:26:55 -05001430 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001431 crow::connections::systemBus->new_method_call(
1432 connectionName.c_str(),
1433 transaction->path.c_str(), thisInterfaceName,
1434 transaction->methodName.c_str());
1435
1436 tinyxml2::XMLElement* argumentNode =
1437 methodNode->FirstChildElement("arg");
1438
1439 std::string returnType;
1440
1441 // Find the output type
1442 while (argumentNode != nullptr)
1443 {
1444 const char* argDirection =
1445 argumentNode->Attribute("direction");
1446 const char* argType =
1447 argumentNode->Attribute("type");
1448 if (argDirection != nullptr && argType != nullptr &&
1449 std::string(argDirection) == "out")
1450 {
1451 returnType = argType;
1452 break;
1453 }
1454 argumentNode =
1455 argumentNode->NextSiblingElement("arg");
1456 }
1457
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001458 auto argIt = transaction->arguments.begin();
Ed Tanous002d39b2022-05-31 08:59:27 -07001459
1460 argumentNode = methodNode->FirstChildElement("arg");
1461
1462 while (argumentNode != nullptr)
1463 {
1464 const char* argDirection =
1465 argumentNode->Attribute("direction");
1466 const char* argType =
1467 argumentNode->Attribute("type");
1468 if (argDirection != nullptr && argType != nullptr &&
1469 std::string(argDirection) == "in")
1470 {
1471 if (argIt == transaction->arguments.end())
1472 {
1473 transaction->setErrorStatus(
1474 "Invalid method args");
1475 return;
1476 }
1477 if (convertJsonToDbus(m.get(),
1478 std::string(argType),
1479 *argIt) < 0)
1480 {
1481 transaction->setErrorStatus(
1482 "Invalid method arg type");
1483 return;
1484 }
1485
1486 argIt++;
1487 }
1488 argumentNode =
1489 argumentNode->NextSiblingElement("arg");
1490 }
1491
1492 crow::connections::systemBus->async_send(
1493 m,
1494 [transaction,
1495 returnType](boost::system::error_code ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05001496 sdbusplus::message_t& m2) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001497 if (ec2)
1498 {
1499 transaction->methodFailed = true;
1500 const sd_bus_error* e = m2.get_error();
1501
1502 if (e != nullptr)
1503 {
1504 setErrorResponse(
1505 transaction->res,
1506 boost::beast::http::status::bad_request,
1507 e->name, e->message);
1508 }
1509 else
1510 {
1511 setErrorResponse(
1512 transaction->res,
1513 boost::beast::http::status::bad_request,
1514 "Method call failed", methodFailedMsg);
1515 }
1516 return;
1517 }
1518 transaction->methodPassed = true;
1519
1520 handleMethodResponse(transaction, m2, returnType);
1521 });
1522 break;
1523 }
1524 methodNode = methodNode->NextSiblingElement("method");
1525 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001526 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001527 interfaceNode = interfaceNode->NextSiblingElement("interface");
1528 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001529 },
1530 connectionName, transaction->path,
1531 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001532}
1533
zhanghch058d1b46d2021-04-01 11:18:24 +08001534inline void handleAction(const crow::Request& req,
1535 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001536 const std::string& objectPath,
1537 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001538{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001539 BMCWEB_LOG_DEBUG << "handleAction on path: " << objectPath << " and method "
1540 << methodName;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001541 nlohmann::json requestDbusData =
1542 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001543
Ed Tanous1abe55e2018-09-05 08:30:59 -07001544 if (requestDbusData.is_discarded())
1545 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001546 setErrorResponse(asyncResp->res,
1547 boost::beast::http::status::bad_request, noJsonDesc,
1548 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001549 return;
1550 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001551 nlohmann::json::iterator data = requestDbusData.find("data");
1552 if (data == requestDbusData.end())
1553 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001554 setErrorResponse(asyncResp->res,
1555 boost::beast::http::status::bad_request, noJsonDesc,
1556 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001557 return;
1558 }
1559
1560 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001561 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001562 setErrorResponse(asyncResp->res,
1563 boost::beast::http::status::bad_request, noJsonDesc,
1564 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001565 return;
1566 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001567 auto transaction = std::make_shared<InProgressActionData>(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001568
1569 transaction->path = objectPath;
1570 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001571 transaction->arguments = std::move(*data);
George Liu2b731192023-01-11 16:27:13 +08001572 dbus::utility::getDbusObject(
1573 objectPath, {},
Ed Tanous1abe55e2018-09-05 08:30:59 -07001574 [transaction](
George Liu2b731192023-01-11 16:27:13 +08001575 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001576 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1577 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001578 if (ec || interfaceNames.empty())
1579 {
1580 BMCWEB_LOG_ERROR << "Can't find object";
1581 setErrorResponse(transaction->res,
1582 boost::beast::http::status::not_found,
1583 notFoundDesc, notFoundMsg);
1584 return;
1585 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001586
Ed Tanous002d39b2022-05-31 08:59:27 -07001587 BMCWEB_LOG_DEBUG << "GetObject returned " << interfaceNames.size()
1588 << " object(s)";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001589
Ed Tanous002d39b2022-05-31 08:59:27 -07001590 for (const std::pair<std::string, std::vector<std::string>>& object :
1591 interfaceNames)
1592 {
1593 findActionOnInterface(transaction, object.first);
1594 }
George Liu2b731192023-01-11 16:27:13 +08001595 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001596}
1597
zhanghch058d1b46d2021-04-01 11:18:24 +08001598inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1599 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001600{
1601 BMCWEB_LOG_DEBUG << "handleDelete on path: " << objectPath;
1602
George Liu2b731192023-01-11 16:27:13 +08001603 dbus::utility::getDbusObject(
1604 objectPath, {},
zhanghch058d1b46d2021-04-01 11:18:24 +08001605 [asyncResp, objectPath](
George Liu2b731192023-01-11 16:27:13 +08001606 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001607 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1608 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001609 if (ec || interfaceNames.empty())
1610 {
1611 BMCWEB_LOG_ERROR << "Can't find object";
1612 setErrorResponse(asyncResp->res,
1613 boost::beast::http::status::method_not_allowed,
1614 methodNotAllowedDesc, methodNotAllowedMsg);
1615 return;
1616 }
Matt Spinlerde818812018-12-11 16:39:20 -06001617
Ed Tanous002d39b2022-05-31 08:59:27 -07001618 auto transaction =
1619 std::make_shared<InProgressActionData>(asyncResp->res);
1620 transaction->path = objectPath;
1621 transaction->methodName = "Delete";
1622 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
Matt Spinlerde818812018-12-11 16:39:20 -06001623
Ed Tanous002d39b2022-05-31 08:59:27 -07001624 for (const std::pair<std::string, std::vector<std::string>>& object :
1625 interfaceNames)
1626 {
1627 findActionOnInterface(transaction, object.first);
1628 }
George Liu2b731192023-01-11 16:27:13 +08001629 });
Matt Spinlerde818812018-12-11 16:39:20 -06001630}
1631
zhanghch058d1b46d2021-04-01 11:18:24 +08001632inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1633 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001634{
George Liu7a1dbc42022-12-07 16:03:22 +08001635 dbus::utility::getSubTreePaths(
1636 objectPath, depth, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001637 [asyncResp](
George Liu7a1dbc42022-12-07 16:03:22 +08001638 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001639 const dbus::utility::MapperGetSubTreePathsResponse& objectPaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001640 if (ec)
1641 {
1642 setErrorResponse(asyncResp->res,
1643 boost::beast::http::status::not_found,
1644 notFoundDesc, notFoundMsg);
1645 }
1646 else
1647 {
1648 asyncResp->res.jsonValue["status"] = "ok";
1649 asyncResp->res.jsonValue["message"] = "200 OK";
1650 asyncResp->res.jsonValue["data"] = objectPaths;
1651 }
George Liu7a1dbc42022-12-07 16:03:22 +08001652 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001653}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001654
zhanghch058d1b46d2021-04-01 11:18:24 +08001655inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1656 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001657{
Ed Tanous049a0512018-11-01 13:58:42 -07001658 BMCWEB_LOG_DEBUG << "Doing enumerate on " << objectPath;
Ed Tanous049a0512018-11-01 13:58:42 -07001659
Ed Tanous14766872022-03-15 10:44:42 -07001660 asyncResp->res.jsonValue["message"] = "200 OK";
1661 asyncResp->res.jsonValue["status"] = "ok";
1662 asyncResp->res.jsonValue["data"] = nlohmann::json::object();
Ed Tanous049a0512018-11-01 13:58:42 -07001663
George Liue99073f2022-12-09 11:06:16 +08001664 dbus::utility::getSubTree(
1665 objectPath, 0, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001666 [objectPath, asyncResp](
George Liue99073f2022-12-09 11:06:16 +08001667 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001668 const dbus::utility::MapperGetSubTreeResponse& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001669 auto transaction =
1670 std::make_shared<InProgressEnumerateData>(objectPath, asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001671
Ed Tanous002d39b2022-05-31 08:59:27 -07001672 transaction->subtree =
1673 std::make_shared<dbus::utility::MapperGetSubTreeResponse>(
1674 objectNames);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001675
Ed Tanous002d39b2022-05-31 08:59:27 -07001676 if (ec)
1677 {
1678 BMCWEB_LOG_ERROR << "GetSubTree failed on "
1679 << transaction->objectPath;
1680 setErrorResponse(transaction->asyncResp->res,
1681 boost::beast::http::status::not_found,
1682 notFoundDesc, notFoundMsg);
1683 return;
1684 }
Ed Tanous64530012018-02-06 17:08:16 -08001685
Ed Tanous002d39b2022-05-31 08:59:27 -07001686 // Add the data for the path passed in to the results
1687 // as if GetSubTree returned it, and continue on enumerating
1688 getObjectAndEnumerate(transaction);
George Liue99073f2022-12-09 11:06:16 +08001689 });
Ed Tanous64530012018-02-06 17:08:16 -08001690}
Ed Tanous911ac312017-08-15 09:37:42 -07001691
zhanghch058d1b46d2021-04-01 11:18:24 +08001692inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1693 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001694{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001695 BMCWEB_LOG_DEBUG << "handleGet: " << objectPath << " prop:" << destProperty;
1696 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001697 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001698
Ed Tanous1abe55e2018-09-05 08:30:59 -07001699 std::shared_ptr<std::string> path =
1700 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001701
George Liu2b731192023-01-11 16:27:13 +08001702 dbus::utility::getDbusObject(
1703 *path, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001704 [asyncResp, path,
George Liu2b731192023-01-11 16:27:13 +08001705 propertyName](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001706 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001707 if (ec || objectNames.empty())
1708 {
1709 setErrorResponse(asyncResp->res,
1710 boost::beast::http::status::not_found,
1711 notFoundDesc, notFoundMsg);
1712 return;
1713 }
1714 std::shared_ptr<nlohmann::json> response =
1715 std::make_shared<nlohmann::json>(nlohmann::json::object());
1716 // The mapper should never give us an empty interface names
1717 // list, but check anyway
1718 for (const std::pair<std::string, std::vector<std::string>>&
1719 connection : objectNames)
1720 {
1721 const std::vector<std::string>& interfaceNames = connection.second;
1722
1723 if (interfaceNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001724 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001725 setErrorResponse(asyncResp->res,
1726 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001727 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001728 return;
1729 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001730
1731 for (const std::string& interface : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001732 {
Patrick Williams59d494e2022-07-22 19:26:55 -05001733 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001734 crow::connections::systemBus->new_method_call(
1735 connection.first.c_str(), path->c_str(),
1736 "org.freedesktop.DBus.Properties", "GetAll");
1737 m.append(interface);
1738 crow::connections::systemBus->async_send(
1739 m, [asyncResp, response,
1740 propertyName](const boost::system::error_code ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05001741 sdbusplus::message_t& msg) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001742 if (ec2)
1743 {
1744 BMCWEB_LOG_ERROR << "Bad dbus request error: "
1745 << ec2;
1746 }
1747 else
1748 {
1749 nlohmann::json properties;
1750 int r = convertDBusToJSON("a{sv}", msg, properties);
1751 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001752 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001753 BMCWEB_LOG_ERROR << "convertDBusToJSON failed";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001754 }
1755 else
1756 {
Patrick Williams62bafc02022-09-08 17:35:35 -05001757 for (const auto& prop : properties.items())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001758 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001759 // if property name is empty, or
1760 // matches our search query, add it
1761 // to the response json
Ed Tanous1abe55e2018-09-05 08:30:59 -07001762
Ed Tanous002d39b2022-05-31 08:59:27 -07001763 if (propertyName->empty())
1764 {
1765 (*response)[prop.key()] =
1766 std::move(prop.value());
1767 }
1768 else if (prop.key() == *propertyName)
1769 {
1770 *response = std::move(prop.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001771 }
1772 }
1773 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001774 }
1775 if (response.use_count() == 1)
1776 {
1777 if (!propertyName->empty() && response->empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001778 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001779 setErrorResponse(
1780 asyncResp->res,
1781 boost::beast::http::status::not_found,
1782 propNotFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001783 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001784 else
1785 {
1786 asyncResp->res.jsonValue["status"] = "ok";
1787 asyncResp->res.jsonValue["message"] = "200 OK";
1788 asyncResp->res.jsonValue["data"] = *response;
1789 }
1790 }
1791 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001792 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001793 }
George Liu2b731192023-01-11 16:27:13 +08001794 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001795}
1796
Ed Tanous1abe55e2018-09-05 08:30:59 -07001797struct AsyncPutRequest
1798{
Ed Tanous4e23a442022-06-06 09:57:26 -07001799 explicit AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
zhanghch058d1b46d2021-04-01 11:18:24 +08001800 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001801 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001802 ~AsyncPutRequest()
1803 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001804 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001805 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001806 setErrorResponse(asyncResp->res,
1807 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001808 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001809 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001810 }
1811
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001812 AsyncPutRequest(const AsyncPutRequest&) = delete;
1813 AsyncPutRequest(AsyncPutRequest&&) = delete;
1814 AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1815 AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1816
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001817 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001818 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001819 setErrorResponse(asyncResp->res,
1820 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001821 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001822 }
1823
zhanghch058d1b46d2021-04-01 11:18:24 +08001824 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001825 std::string objectPath;
1826 std::string propertyName;
1827 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001828};
1829
zhanghch058d1b46d2021-04-01 11:18:24 +08001830inline void handlePut(const crow::Request& req,
1831 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001832 const std::string& objectPath,
1833 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001834{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001835 if (destProperty.empty())
1836 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001837 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001838 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001839 return;
1840 }
1841
Ed Tanous1abe55e2018-09-05 08:30:59 -07001842 nlohmann::json requestDbusData =
1843 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001844
Ed Tanous1abe55e2018-09-05 08:30:59 -07001845 if (requestDbusData.is_discarded())
1846 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001847 setErrorResponse(asyncResp->res,
1848 boost::beast::http::status::bad_request, noJsonDesc,
1849 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001850 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001851 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001852
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001853 auto propertyIt = requestDbusData.find("data");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001854 if (propertyIt == requestDbusData.end())
1855 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001856 setErrorResponse(asyncResp->res,
1857 boost::beast::http::status::bad_request, noJsonDesc,
1858 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001859 return;
1860 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001861 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001862 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001863 transaction->objectPath = objectPath;
1864 transaction->propertyName = destProperty;
1865 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001866
George Liu2b731192023-01-11 16:27:13 +08001867 dbus::utility::getDbusObject(
1868 transaction->objectPath, {},
1869 [transaction](const boost::system::error_code& ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001870 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001871 if (!ec2 && objectNames.empty())
1872 {
1873 setErrorResponse(transaction->asyncResp->res,
1874 boost::beast::http::status::not_found,
1875 propNotFoundDesc, notFoundMsg);
1876 return;
1877 }
Ed Tanous911ac312017-08-15 09:37:42 -07001878
Ed Tanous002d39b2022-05-31 08:59:27 -07001879 for (const std::pair<std::string, std::vector<std::string>>&
1880 connection : objectNames)
1881 {
1882 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001883
Ed Tanous002d39b2022-05-31 08:59:27 -07001884 crow::connections::systemBus->async_method_call(
1885 [connectionName{std::string(connectionName)},
1886 transaction](const boost::system::error_code ec3,
1887 const std::string& introspectXml) {
1888 if (ec3)
1889 {
1890 BMCWEB_LOG_ERROR << "Introspect call failed with error: "
1891 << ec3.message()
1892 << " on process: " << connectionName;
1893 transaction->setErrorStatus("Unexpected Error");
1894 return;
1895 }
1896 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001897
Ed Tanous002d39b2022-05-31 08:59:27 -07001898 doc.Parse(introspectXml.c_str());
1899 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1900 if (pRoot == nullptr)
1901 {
1902 BMCWEB_LOG_ERROR << "XML document failed to parse: "
1903 << introspectXml;
1904 transaction->setErrorStatus("Unexpected Error");
1905 return;
1906 }
1907 tinyxml2::XMLElement* ifaceNode =
1908 pRoot->FirstChildElement("interface");
1909 while (ifaceNode != nullptr)
1910 {
1911 const char* interfaceName = ifaceNode->Attribute("name");
1912 BMCWEB_LOG_DEBUG << "found interface " << interfaceName;
1913 tinyxml2::XMLElement* propNode =
1914 ifaceNode->FirstChildElement("property");
1915 while (propNode != nullptr)
1916 {
1917 const char* propertyName = propNode->Attribute("name");
1918 BMCWEB_LOG_DEBUG << "Found property " << propertyName;
1919 if (propertyName == transaction->propertyName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001920 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001921 const char* argType = propNode->Attribute("type");
1922 if (argType != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001923 {
Patrick Williams59d494e2022-07-22 19:26:55 -05001924 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001925 crow::connections::systemBus
1926 ->new_method_call(
1927 connectionName.c_str(),
1928 transaction->objectPath.c_str(),
1929 "org.freedesktop.DBus."
1930 "Properties",
1931 "Set");
1932 m.append(interfaceName,
1933 transaction->propertyName);
1934 int r = sd_bus_message_open_container(
1935 m.get(), SD_BUS_TYPE_VARIANT, argType);
1936 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001937 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001938 transaction->setErrorStatus(
1939 "Unexpected Error");
1940 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001941 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001942 r = convertJsonToDbus(
1943 m.get(), argType,
1944 transaction->propertyValue);
1945 if (r < 0)
1946 {
1947 if (r == -ERANGE)
1948 {
1949 transaction->setErrorStatus(
1950 "Provided property value "
1951 "is out of range for the "
1952 "property type");
1953 }
1954 else
1955 {
1956 transaction->setErrorStatus(
1957 "Invalid arg type");
1958 }
1959 return;
1960 }
1961 r = sd_bus_message_close_container(m.get());
1962 if (r < 0)
1963 {
1964 transaction->setErrorStatus(
1965 "Unexpected Error");
1966 return;
1967 }
1968 crow::connections::systemBus->async_send(
1969 m,
Patrick Williams59d494e2022-07-22 19:26:55 -05001970 [transaction](boost::system::error_code ec,
1971 sdbusplus::message_t& m2) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001972 BMCWEB_LOG_DEBUG << "sent";
1973 if (ec)
1974 {
1975 const sd_bus_error* e = m2.get_error();
1976 setErrorResponse(
1977 transaction->asyncResp->res,
1978 boost::beast::http::status::
1979 forbidden,
1980 (e) != nullptr
1981 ? e->name
1982 : ec.category().name(),
1983 (e) != nullptr ? e->message
1984 : ec.message());
1985 }
1986 else
1987 {
1988 transaction->asyncResp->res
1989 .jsonValue["status"] = "ok";
1990 transaction->asyncResp->res
1991 .jsonValue["message"] = "200 OK";
1992 transaction->asyncResp->res
1993 .jsonValue["data"] = nullptr;
1994 }
1995 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001996 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001997 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001998 propNode = propNode->NextSiblingElement("property");
1999 }
2000 ifaceNode = ifaceNode->NextSiblingElement("interface");
2001 }
2002 },
2003 connectionName, transaction->objectPath,
2004 "org.freedesktop.DBus.Introspectable", "Introspect");
2005 }
George Liu2b731192023-01-11 16:27:13 +08002006 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07002007}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002008
zhanghch058d1b46d2021-04-01 11:18:24 +08002009inline void handleDBusUrl(const crow::Request& req,
2010 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002011 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002012{
Ed Tanous049a0512018-11-01 13:58:42 -07002013
2014 // If accessing a single attribute, fill in and update objectPath,
2015 // otherwise leave destProperty blank
Ed Tanouse05aec52022-01-25 10:28:56 -08002016 std::string destProperty;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002017 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002018 size_t attrPosition = objectPath.find(attrSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002019 if (attrPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002020 {
2021 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2022 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002023 objectPath.resize(attrPosition);
Ed Tanous049a0512018-11-01 13:58:42 -07002024 }
2025
Ed Tanousb41187f2019-10-24 16:30:02 -07002026 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002027 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002028 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002029 size_t actionPosition = objectPath.find(actionSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002030 if (actionPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002031 {
2032 std::string postProperty =
2033 objectPath.substr((actionPosition + strlen(actionSeperator)),
2034 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002035 objectPath.resize(actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002036 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002037 return;
2038 }
2039 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002040 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002041 {
Ed Tanous11ba3972022-07-11 09:50:41 -07002042 if (objectPath.ends_with("/enumerate"))
Ed Tanous049a0512018-11-01 13:58:42 -07002043 {
2044 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2045 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002046 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002047 }
Ed Tanous11ba3972022-07-11 09:50:41 -07002048 else if (objectPath.ends_with("/list"))
Ed Tanous049a0512018-11-01 13:58:42 -07002049 {
2050 objectPath.erase(objectPath.end() - sizeof("list"),
2051 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002052 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002053 }
2054 else
2055 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002056 // Trim any trailing "/" at the end
Ed Tanous11ba3972022-07-11 09:50:41 -07002057 if (objectPath.ends_with("/"))
Ed Tanousf839dfe2018-11-12 11:11:15 -08002058 {
2059 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002060 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002061 }
2062 else
2063 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002064 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002065 }
Ed Tanous049a0512018-11-01 13:58:42 -07002066 }
2067 return;
2068 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002069 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002070 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002071 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002072 return;
2073 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002074 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002075 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002076 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002077 return;
2078 }
Ed Tanous049a0512018-11-01 13:58:42 -07002079
zhanghch058d1b46d2021-04-01 11:18:24 +08002080 setErrorResponse(asyncResp->res,
2081 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002082 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002083}
2084
Ed Tanous1656b292022-05-04 11:33:42 -07002085inline void
2086 handleBusSystemPost(const crow::Request& req,
2087 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2088 const std::string& processName,
2089 const std::string& requestedPath)
2090{
2091 std::vector<std::string> strs;
Ed Tanous50ebd4a2023-01-19 19:03:17 -08002092
2093 bmcweb::split(strs, requestedPath, '/');
Ed Tanous1656b292022-05-04 11:33:42 -07002094 std::string objectPath;
2095 std::string interfaceName;
2096 std::string methodName;
2097 auto it = strs.begin();
2098 if (it == strs.end())
2099 {
2100 objectPath = "/";
2101 }
2102 while (it != strs.end())
2103 {
2104 // Check if segment contains ".". If it does, it must be an
2105 // interface
2106 if (it->find(".") != std::string::npos)
2107 {
2108 break;
2109 // This check is necessary as the trailing slash gets
2110 // parsed as part of our <path> specifier above, which
2111 // causes the normal trailing backslash redirector to
2112 // fail.
2113 }
2114 if (!it->empty())
2115 {
2116 objectPath += "/" + *it;
2117 }
2118 it++;
2119 }
2120 if (it != strs.end())
2121 {
2122 interfaceName = *it;
2123 it++;
2124
2125 // after interface, we might have a method name
2126 if (it != strs.end())
2127 {
2128 methodName = *it;
2129 it++;
2130 }
2131 }
2132 if (it != strs.end())
2133 {
2134 // if there is more levels past the method name, something
2135 // went wrong, return not found
2136 asyncResp->res.result(boost::beast::http::status::not_found);
2137 return;
2138 }
2139 if (interfaceName.empty())
2140 {
2141 crow::connections::systemBus->async_method_call(
2142 [asyncResp, processName,
2143 objectPath](const boost::system::error_code ec,
2144 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002145 if (ec)
2146 {
2147 BMCWEB_LOG_ERROR
2148 << "Introspect call failed with error: " << ec.message()
2149 << " on process: " << processName << " path: " << objectPath
2150 << "\n";
2151 return;
2152 }
2153 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002154
Ed Tanous002d39b2022-05-31 08:59:27 -07002155 doc.Parse(introspectXml.c_str());
2156 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2157 if (pRoot == nullptr)
2158 {
2159 BMCWEB_LOG_ERROR << "XML document failed to parse "
2160 << processName << " " << objectPath << "\n";
2161 asyncResp->res.jsonValue["status"] = "XML parse error";
2162 asyncResp->res.result(
2163 boost::beast::http::status::internal_server_error);
2164 return;
2165 }
2166
2167 BMCWEB_LOG_DEBUG << introspectXml;
2168 asyncResp->res.jsonValue["status"] = "ok";
2169 asyncResp->res.jsonValue["bus_name"] = processName;
2170 asyncResp->res.jsonValue["object_path"] = objectPath;
2171
2172 nlohmann::json& interfacesArray =
2173 asyncResp->res.jsonValue["interfaces"];
2174 interfacesArray = nlohmann::json::array();
2175 tinyxml2::XMLElement* interface =
2176 pRoot->FirstChildElement("interface");
2177
2178 while (interface != nullptr)
2179 {
2180 const char* ifaceName = interface->Attribute("name");
2181 if (ifaceName != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002182 {
Ed Tanous8a592812022-06-04 09:06:59 -07002183 nlohmann::json::object_t interfaceObj;
2184 interfaceObj["name"] = ifaceName;
2185 interfacesArray.push_back(std::move(interfaceObj));
Ed Tanous1656b292022-05-04 11:33:42 -07002186 }
2187
Ed Tanous002d39b2022-05-31 08:59:27 -07002188 interface = interface->NextSiblingElement("interface");
2189 }
Ed Tanous1656b292022-05-04 11:33:42 -07002190 },
2191 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2192 "Introspect");
2193 }
2194 else if (methodName.empty())
2195 {
2196 crow::connections::systemBus->async_method_call(
2197 [asyncResp, processName, objectPath,
2198 interfaceName](const boost::system::error_code ec,
2199 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002200 if (ec)
2201 {
2202 BMCWEB_LOG_ERROR
2203 << "Introspect call failed with error: " << ec.message()
2204 << " on process: " << processName << " path: " << objectPath
2205 << "\n";
2206 return;
2207 }
2208 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002209
Ed Tanous002d39b2022-05-31 08:59:27 -07002210 doc.Parse(introspectXml.data(), introspectXml.size());
2211 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2212 if (pRoot == nullptr)
2213 {
2214 BMCWEB_LOG_ERROR << "XML document failed to parse "
2215 << processName << " " << objectPath << "\n";
2216 asyncResp->res.result(
2217 boost::beast::http::status::internal_server_error);
2218 return;
2219 }
2220
2221 asyncResp->res.jsonValue["status"] = "ok";
2222 asyncResp->res.jsonValue["bus_name"] = processName;
2223 asyncResp->res.jsonValue["interface"] = interfaceName;
2224 asyncResp->res.jsonValue["object_path"] = objectPath;
2225
2226 nlohmann::json& methodsArray = asyncResp->res.jsonValue["methods"];
2227 methodsArray = nlohmann::json::array();
2228
2229 nlohmann::json& signalsArray = asyncResp->res.jsonValue["signals"];
2230 signalsArray = nlohmann::json::array();
2231
2232 nlohmann::json& propertiesObj =
2233 asyncResp->res.jsonValue["properties"];
2234 propertiesObj = nlohmann::json::object();
2235
2236 // if we know we're the only call, build the
2237 // json directly
2238 tinyxml2::XMLElement* interface =
2239 pRoot->FirstChildElement("interface");
2240 while (interface != nullptr)
2241 {
2242 const char* ifaceName = interface->Attribute("name");
2243
2244 if (ifaceName != nullptr && ifaceName == interfaceName)
Ed Tanous1656b292022-05-04 11:33:42 -07002245 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002246 break;
Ed Tanous1656b292022-05-04 11:33:42 -07002247 }
Ed Tanous14766872022-03-15 10:44:42 -07002248
Ed Tanous002d39b2022-05-31 08:59:27 -07002249 interface = interface->NextSiblingElement("interface");
2250 }
2251 if (interface == nullptr)
2252 {
2253 // if we got to the end of the list and
2254 // never found a match, throw 404
2255 asyncResp->res.result(boost::beast::http::status::not_found);
2256 return;
2257 }
Ed Tanous1656b292022-05-04 11:33:42 -07002258
Ed Tanous002d39b2022-05-31 08:59:27 -07002259 tinyxml2::XMLElement* methods =
2260 interface->FirstChildElement("method");
2261 while (methods != nullptr)
2262 {
2263 nlohmann::json argsArray = nlohmann::json::array();
2264 tinyxml2::XMLElement* arg = methods->FirstChildElement("arg");
2265 while (arg != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002266 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002267 nlohmann::json thisArg;
2268 for (const char* fieldName : std::array<const char*, 3>{
2269 "name", "direction", "type"})
Ed Tanous1656b292022-05-04 11:33:42 -07002270 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002271 const char* fieldValue = arg->Attribute(fieldName);
2272 if (fieldValue != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002273 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002274 thisArg[fieldName] = fieldValue;
2275 }
2276 }
2277 argsArray.push_back(std::move(thisArg));
2278 arg = arg->NextSiblingElement("arg");
2279 }
2280
2281 const char* name = methods->Attribute("name");
2282 if (name != nullptr)
2283 {
2284 std::string uri;
2285 uri.reserve(14 + processName.size() + objectPath.size() +
2286 interfaceName.size() + strlen(name));
2287 uri += "/bus/system/";
2288 uri += processName;
2289 uri += objectPath;
2290 uri += "/";
2291 uri += interfaceName;
2292 uri += "/";
2293 uri += name;
2294
2295 nlohmann::json::object_t object;
2296 object["name"] = name;
2297 object["uri"] = std::move(uri);
2298 object["args"] = argsArray;
2299
2300 methodsArray.push_back(std::move(object));
2301 }
2302 methods = methods->NextSiblingElement("method");
2303 }
2304 tinyxml2::XMLElement* signals =
2305 interface->FirstChildElement("signal");
2306 while (signals != nullptr)
2307 {
2308 nlohmann::json argsArray = nlohmann::json::array();
2309
2310 tinyxml2::XMLElement* arg = signals->FirstChildElement("arg");
2311 while (arg != nullptr)
2312 {
2313 const char* name = arg->Attribute("name");
2314 const char* type = arg->Attribute("type");
2315 if (name != nullptr && type != nullptr)
2316 {
2317 argsArray.push_back({
2318 {"name", name},
2319 {"type", type},
2320 });
2321 }
2322 arg = arg->NextSiblingElement("arg");
2323 }
2324 const char* name = signals->Attribute("name");
2325 if (name != nullptr)
2326 {
2327 nlohmann::json::object_t object;
2328 object["name"] = name;
2329 object["args"] = argsArray;
2330 signalsArray.push_back(std::move(object));
2331 }
2332
2333 signals = signals->NextSiblingElement("signal");
2334 }
2335
2336 tinyxml2::XMLElement* property =
2337 interface->FirstChildElement("property");
2338 while (property != nullptr)
2339 {
2340 const char* name = property->Attribute("name");
2341 const char* type = property->Attribute("type");
2342 if (type != nullptr && name != nullptr)
2343 {
Patrick Williams59d494e2022-07-22 19:26:55 -05002344 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07002345 crow::connections::systemBus->new_method_call(
2346 processName.c_str(), objectPath.c_str(),
2347 "org.freedesktop."
2348 "DBus."
2349 "Properties",
2350 "Get");
2351 m.append(interfaceName, name);
2352 nlohmann::json& propertyItem = propertiesObj[name];
2353 crow::connections::systemBus->async_send(
2354 m, [&propertyItem,
Ed Tanous02cad962022-06-30 16:50:15 -07002355 asyncResp](const boost::system::error_code& e,
Patrick Williams59d494e2022-07-22 19:26:55 -05002356 sdbusplus::message_t& msg) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002357 if (e)
Ed Tanous1656b292022-05-04 11:33:42 -07002358 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002359 return;
Ed Tanous1656b292022-05-04 11:33:42 -07002360 }
Ed Tanous1656b292022-05-04 11:33:42 -07002361
Ed Tanous002d39b2022-05-31 08:59:27 -07002362 convertDBusToJSON("v", msg, propertyItem);
2363 });
Ed Tanous1656b292022-05-04 11:33:42 -07002364 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002365 property = property->NextSiblingElement("property");
2366 }
Ed Tanous1656b292022-05-04 11:33:42 -07002367 },
2368 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2369 "Introspect");
2370 }
2371 else
2372 {
2373 if (req.method() != boost::beast::http::verb::post)
2374 {
2375 asyncResp->res.result(boost::beast::http::status::not_found);
2376 return;
2377 }
2378
2379 nlohmann::json requestDbusData =
2380 nlohmann::json::parse(req.body, nullptr, false);
2381
2382 if (requestDbusData.is_discarded())
2383 {
2384 asyncResp->res.result(boost::beast::http::status::bad_request);
2385 return;
2386 }
2387 if (!requestDbusData.is_array())
2388 {
2389 asyncResp->res.result(boost::beast::http::status::bad_request);
2390 return;
2391 }
2392 auto transaction =
2393 std::make_shared<InProgressActionData>(asyncResp->res);
2394
2395 transaction->path = objectPath;
2396 transaction->methodName = methodName;
2397 transaction->arguments = std::move(requestDbusData);
2398
2399 findActionOnInterface(transaction, processName);
2400 }
2401}
2402
Ed Tanous23a21a12020-07-25 04:45:05 +00002403inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002404{
2405 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002406 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002407 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002408 [](const crow::Request&,
2409 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002410 nlohmann::json::array_t buses;
2411 nlohmann::json& bus = buses.emplace_back();
2412 bus["name"] = "system";
2413 asyncResp->res.jsonValue["busses"] = std::move(buses);
2414 asyncResp->res.jsonValue["status"] = "ok";
2415 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002416
2417 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002418 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002419 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002420 [](const crow::Request&,
2421 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002422 auto myCallback = [asyncResp](const boost::system::error_code ec,
zhanghch058d1b46d2021-04-01 11:18:24 +08002423 std::vector<std::string>& names) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002424 if (ec)
2425 {
2426 BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
2427 asyncResp->res.result(
2428 boost::beast::http::status::internal_server_error);
2429 }
2430 else
2431 {
2432 std::sort(names.begin(), names.end());
2433 asyncResp->res.jsonValue["status"] = "ok";
2434 auto& objectsSub = asyncResp->res.jsonValue["objects"];
Ed Tanous02cad962022-06-30 16:50:15 -07002435 for (const auto& name : names)
Ed Tanous002d39b2022-05-31 08:59:27 -07002436 {
2437 nlohmann::json::object_t object;
2438 object["name"] = name;
2439 objectsSub.push_back(std::move(object));
2440 }
2441 }
2442 };
2443 crow::connections::systemBus->async_method_call(
2444 std::move(myCallback), "org.freedesktop.DBus", "/",
2445 "org.freedesktop.DBus", "ListNames");
2446 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002447
2448 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002449 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002450 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002451 [](const crow::Request&,
2452 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002453 handleList(asyncResp, "/");
2454 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002455
2456 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002457 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002458 .methods(boost::beast::http::verb::get)(
2459 [](const crow::Request& req,
2460 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002461 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002462 std::string objectPath = "/xyz/" + path;
2463 handleDBusUrl(req, asyncResp, objectPath);
2464 });
zhanghch058d1b46d2021-04-01 11:18:24 +08002465
2466 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002467 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002468 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2469 boost::beast::http::verb::delete_)(
2470 [](const crow::Request& req,
2471 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2472 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002473 std::string objectPath = "/xyz/" + path;
2474 handleDBusUrl(req, asyncResp, objectPath);
2475 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002476
Ed Tanous049a0512018-11-01 13:58:42 -07002477 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002478 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002479 .methods(boost::beast::http::verb::get)(
2480 [](const crow::Request& req,
2481 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2482 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002483 std::string objectPath = "/org/" + path;
2484 handleDBusUrl(req, asyncResp, objectPath);
2485 });
Tanousf00032d2018-11-05 01:18:10 -03002486
2487 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002488 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002489 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2490 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002491 [](const crow::Request& req,
2492 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002493 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002494 std::string objectPath = "/org/" + path;
2495 handleDBusUrl(req, asyncResp, objectPath);
2496 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002497
Ed Tanous1abe55e2018-09-05 08:30:59 -07002498 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002499 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002500 .methods(boost::beast::http::verb::get)(
2501 [](const crow::Request&,
2502 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2503 const std::string& dumpId) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002504 if (!validateFilename(dumpId))
2505 {
2506 asyncResp->res.result(boost::beast::http::status::bad_request);
2507 return;
2508 }
2509 std::filesystem::path loc("/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002510
Ed Tanous002d39b2022-05-31 08:59:27 -07002511 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002512
Ed Tanous002d39b2022-05-31 08:59:27 -07002513 if (!std::filesystem::exists(loc) ||
2514 !std::filesystem::is_directory(loc))
2515 {
2516 BMCWEB_LOG_ERROR << loc.string() << "Not found";
2517 asyncResp->res.result(boost::beast::http::status::not_found);
2518 return;
2519 }
2520 std::filesystem::directory_iterator files(loc);
zhanghch058d1b46d2021-04-01 11:18:24 +08002521
Ed Tanous002d39b2022-05-31 08:59:27 -07002522 for (const auto& file : files)
2523 {
2524 std::ifstream readFile(file.path());
2525 if (!readFile.good())
2526 {
2527 continue;
2528 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002529
Ed Tanousd9f6c622022-03-17 09:12:17 -07002530 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07002531 "application/octet-stream");
zhanghch058d1b46d2021-04-01 11:18:24 +08002532
Ed Tanous002d39b2022-05-31 08:59:27 -07002533 // Assuming only one dump file will be present in the dump
2534 // id directory
2535 std::string dumpFileName = file.path().filename().string();
zhanghch058d1b46d2021-04-01 11:18:24 +08002536
Ed Tanous002d39b2022-05-31 08:59:27 -07002537 // Filename should be in alphanumeric, dot and underscore
2538 // Its based on phosphor-debug-collector application
2539 // dumpfile format
2540 std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
2541 if (!std::regex_match(dumpFileName, dumpFileRegex))
2542 {
2543 BMCWEB_LOG_ERROR << "Invalid dump filename " << dumpFileName;
zhanghch058d1b46d2021-04-01 11:18:24 +08002544 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002545 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07002546 }
2547 std::string contentDispositionParam =
2548 "attachment; filename=\"" + dumpFileName + "\"";
2549
Ed Tanousd9f6c622022-03-17 09:12:17 -07002550 asyncResp->res.addHeader(
2551 boost::beast::http::field::content_disposition,
2552 contentDispositionParam);
Ed Tanous002d39b2022-05-31 08:59:27 -07002553
2554 asyncResp->res.body() = {std::istreambuf_iterator<char>(readFile),
2555 std::istreambuf_iterator<char>()};
2556 return;
2557 }
2558 asyncResp->res.result(boost::beast::http::status::not_found);
2559 return;
2560 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002561
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002562 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002563 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002564
2565 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002566 [](const crow::Request&,
2567 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002568 const std::string& connection) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002569 introspectObjects(connection, "/", asyncResp);
2570 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002571
2572 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002573 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous1656b292022-05-04 11:33:42 -07002574 .methods(boost::beast::http::verb::get,
2575 boost::beast::http::verb::post)(handleBusSystemPost);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002576}
2577} // namespace openbmc_mapper
2578} // namespace crow