blob: d4700a379b256faef609bbeef348cf0e813e3bb0 [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
Nan Zhoud5c80ad2022-07-11 01:16:31 +000016#include "http_request.hpp"
17#include "http_response.hpp"
18#include "logging.hpp"
19#include "routing.hpp"
20
21#include <systemd/sd-bus-protocol.h>
22#include <systemd/sd-bus.h>
Ed Tanous911ac312017-08-15 09:37:42 -070023#include <tinyxml2.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -070024
Ed Tanous04e438c2020-10-03 08:06:26 -070025#include <app.hpp>
Ed Tanouse3cb5a32018-08-08 14:16:49 -070026#include <async_resp.hpp>
Ed Tanous11ba3972022-07-11 09:50:41 -070027#include <boost/algorithm/string/classification.hpp>
28#include <boost/algorithm/string/predicate.hpp>
29#include <boost/algorithm/string/split.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000030#include <boost/beast/http/status.hpp>
31#include <boost/beast/http/verb.hpp>
32#include <boost/container/flat_map.hpp>
33#include <boost/container/vector.hpp>
34#include <boost/iterator/iterator_facade.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -070035#include <dbus_singleton.hpp>
James Feist5b4aa862018-08-16 14:07:01 -070036#include <dbus_utility.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000037#include <nlohmann/json.hpp>
38#include <sdbusplus/asio/connection.hpp>
39#include <sdbusplus/exception.hpp>
40#include <sdbusplus/message.hpp>
41#include <sdbusplus/message/native_types.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050042
Nan Zhoud5c80ad2022-07-11 01:16:31 +000043#include <algorithm>
44#include <array>
45#include <cerrno>
46#include <cstdint>
47#include <cstring>
James Feist4418c7f2019-04-15 11:09:15 -070048#include <filesystem>
Ed Tanousd4bb9bb2018-05-16 13:36:42 -070049#include <fstream>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000050#include <functional>
51#include <initializer_list>
52#include <iterator>
53#include <limits>
54#include <map>
55#include <memory>
Ramesh Iyyard9207042019-07-05 08:04:42 -050056#include <regex>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000057#include <string>
58#include <string_view>
59#include <type_traits>
Ed Tanousb5a76932020-09-29 16:16:58 -070060#include <utility>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000061#include <variant>
62#include <vector>
63
64// IWYU pragma: no_include <boost/algorithm/string/detail/classification.hpp>
65// IWYU pragma: no_include <boost/system/detail/error_code.hpp>
66// IWYU pragma: no_include <boost/system/detail/error_category.hpp>
67// IWYU pragma: no_include <errno.h>
68// IWYU pragma: no_include <string.h>
69// IWYU pragma: no_include <ext/alloc_traits.h>
70// IWYU pragma: no_include <exception>
71// IWYU pragma: no_include <boost/type_index/type_index_facade.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -070072
Ed Tanous1abe55e2018-09-05 08:30:59 -070073namespace crow
74{
75namespace openbmc_mapper
76{
Ed Tanous23a21a12020-07-25 04:45:05 +000077const constexpr char* notFoundMsg = "404 Not Found";
78const constexpr char* badReqMsg = "400 Bad Request";
79const constexpr char* methodNotAllowedMsg = "405 Method Not Allowed";
80const constexpr char* forbiddenMsg = "403 Forbidden";
81const constexpr char* methodFailedMsg = "500 Method Call Failed";
82const constexpr char* methodOutputFailedMsg = "500 Method Output Error";
83const constexpr char* notFoundDesc =
Matt Spinler2ae60092018-12-06 10:35:36 -060084 "org.freedesktop.DBus.Error.FileNotFound: path or object not found";
Ed Tanous23a21a12020-07-25 04:45:05 +000085const constexpr char* propNotFoundDesc =
86 "The specified property cannot be found";
87const constexpr char* noJsonDesc = "No JSON object could be decoded";
88const constexpr char* methodNotFoundDesc =
89 "The specified method cannot be found";
90const constexpr char* methodNotAllowedDesc = "Method not allowed";
91const constexpr char* forbiddenPropDesc =
92 "The specified property cannot be created";
93const constexpr char* forbiddenResDesc =
94 "The specified resource cannot be created";
Matt Spinler2ae60092018-12-06 10:35:36 -060095
Josh Lehan482c45a2022-03-29 17:10:44 -070096inline bool validateFilename(const std::string& filename)
97{
98 std::regex validFilename(R"(^[\w\- ]+(\.?[\w\- ]*)$)");
99
100 return std::regex_match(filename, validFilename);
101}
102
Ed Tanous23a21a12020-07-25 04:45:05 +0000103inline void setErrorResponse(crow::Response& res,
104 boost::beast::http::status result,
105 const std::string& desc,
106 const std::string_view msg)
Matt Spinler2ae60092018-12-06 10:35:36 -0600107{
108 res.result(result);
Ed Tanous14766872022-03-15 10:44:42 -0700109 res.jsonValue["data"]["description"] = desc;
110 res.jsonValue["message"] = msg;
111 res.jsonValue["status"] = "error";
Matt Spinler2ae60092018-12-06 10:35:36 -0600112}
113
Ed Tanousb5a76932020-09-29 16:16:58 -0700114inline void
115 introspectObjects(const std::string& processName,
116 const std::string& objectPath,
117 const std::shared_ptr<bmcweb::AsyncResp>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700118{
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700119 if (transaction->res.jsonValue.is_null())
120 {
Ed Tanous14766872022-03-15 10:44:42 -0700121 transaction->res.jsonValue["status"] = "ok";
122 transaction->res.jsonValue["bus_name"] = processName;
123 transaction->res.jsonValue["objects"] = nlohmann::json::array();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700124 }
125
Ed Tanous1abe55e2018-09-05 08:30:59 -0700126 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700127 [transaction, processName{std::string(processName)},
128 objectPath{std::string(objectPath)}](
129 const boost::system::error_code ec,
Ed Tanous81ce6092020-12-17 16:54:55 +0000130 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700131 if (ec)
132 {
133 BMCWEB_LOG_ERROR
134 << "Introspect call failed with error: " << ec.message()
135 << " on process: " << processName << " path: " << objectPath
136 << "\n";
137 return;
138 }
139 nlohmann::json::object_t object;
140 object["path"] = objectPath;
Ed Tanous14766872022-03-15 10:44:42 -0700141
Ed Tanous002d39b2022-05-31 08:59:27 -0700142 transaction->res.jsonValue["objects"].push_back(std::move(object));
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700143
Ed Tanous002d39b2022-05-31 08:59:27 -0700144 tinyxml2::XMLDocument doc;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700145
Ed Tanous002d39b2022-05-31 08:59:27 -0700146 doc.Parse(introspectXml.c_str());
147 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
148 if (pRoot == nullptr)
149 {
150 BMCWEB_LOG_ERROR << "XML document failed to parse " << processName
151 << " " << objectPath << "\n";
152 }
153 else
154 {
155 tinyxml2::XMLElement* node = pRoot->FirstChildElement("node");
156 while (node != nullptr)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700157 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700158 const char* childPath = node->Attribute("name");
159 if (childPath != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700160 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700161 std::string newpath;
162 if (objectPath != "/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700163 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700164 newpath += objectPath;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700165 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700166 newpath += std::string("/") + childPath;
167 // introspect the subobjects as well
168 introspectObjects(processName, newpath, transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700169 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700170
171 node = node->NextSiblingElement("node");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700172 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700173 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700174 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700175 processName, objectPath, "org.freedesktop.DBus.Introspectable",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700176 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -0700177}
Ed Tanous64530012018-02-06 17:08:16 -0800178
Ed Tanous23a21a12020-07-25 04:45:05 +0000179inline void getPropertiesForEnumerate(
180 const std::string& objectPath, const std::string& service,
Ed Tanousb5a76932020-09-29 16:16:58 -0700181 const std::string& interface,
182 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600183{
184 BMCWEB_LOG_DEBUG << "getPropertiesForEnumerate " << objectPath << " "
185 << service << " " << interface;
186
187 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -0800188 [asyncResp, objectPath, service,
189 interface](const boost::system::error_code ec,
190 const dbus::utility::DBusPropertiesMap& propertiesList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700191 if (ec)
192 {
193 BMCWEB_LOG_ERROR << "GetAll on path " << objectPath << " iface "
194 << interface << " service " << service
195 << " failed with code " << ec;
196 return;
197 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600198
Ed Tanous002d39b2022-05-31 08:59:27 -0700199 nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
200 nlohmann::json& objectJson = dataJson[objectPath];
201 if (objectJson.is_null())
202 {
203 objectJson = nlohmann::json::object();
204 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600205
Ed Tanous002d39b2022-05-31 08:59:27 -0700206 for (const auto& [name, value] : propertiesList)
207 {
208 nlohmann::json& propertyJson = objectJson[name];
209 std::visit(
210 [&propertyJson](auto&& val) {
211 if constexpr (std::is_same_v<std::decay_t<decltype(val)>,
212 sdbusplus::message::unix_fd>)
213 {
214 propertyJson = val.fd;
215 }
216 else
217 {
Ed Tanousd1a64812021-12-13 12:14:05 -0800218
Ed Tanous002d39b2022-05-31 08:59:27 -0700219 propertyJson = val;
220 }
221 },
222 value);
223 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600224 },
225 service, objectPath, "org.freedesktop.DBus.Properties", "GetAll",
226 interface);
227}
228
229// Find any results that weren't picked up by ObjectManagers, to be
230// called after all ObjectManagers are searched for and called.
Ed Tanous23a21a12020-07-25 04:45:05 +0000231inline void findRemainingObjectsForEnumerate(
Ed Tanousb5a76932020-09-29 16:16:58 -0700232 const std::string& objectPath,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800233 const std::shared_ptr<dbus::utility::MapperGetSubTreeResponse>& subtree,
Ed Tanousb5a76932020-09-29 16:16:58 -0700234 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600235{
236 BMCWEB_LOG_DEBUG << "findRemainingObjectsForEnumerate";
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500237 const nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600238
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500239 for (const auto& [path, interface_map] : *subtree)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600240 {
241 if (path == objectPath)
242 {
243 // An enumerate does not return the target path's properties
244 continue;
245 }
246 if (dataJson.find(path) == dataJson.end())
247 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500248 for (const auto& [service, interfaces] : interface_map)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600249 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500250 for (const auto& interface : interfaces)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600251 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700252 if (!interface.starts_with("org.freedesktop.DBus"))
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600253 {
254 getPropertiesForEnumerate(path, service, interface,
255 asyncResp);
256 }
257 }
258 }
259 }
260 }
261}
262
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600263struct InProgressEnumerateData
264{
zhanghch058d1b46d2021-04-01 11:18:24 +0800265 InProgressEnumerateData(
266 const std::string& objectPathIn,
267 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
Ed Tanous23a21a12020-07-25 04:45:05 +0000268 objectPath(objectPathIn),
zhanghch058d1b46d2021-04-01 11:18:24 +0800269 asyncResp(asyncRespIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500270 {}
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600271
272 ~InProgressEnumerateData()
273 {
Ed Tanous24b2fe82022-01-06 12:45:54 -0800274 try
275 {
276 findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
277 }
278 catch (...)
279 {
280 BMCWEB_LOG_CRITICAL
281 << "findRemainingObjectsForEnumerate threw exception";
282 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600283 }
284
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800285 InProgressEnumerateData(const InProgressEnumerateData&) = delete;
286 InProgressEnumerateData(InProgressEnumerateData&&) = delete;
287 InProgressEnumerateData& operator=(const InProgressEnumerateData&) = delete;
288 InProgressEnumerateData& operator=(InProgressEnumerateData&&) = delete;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600289 const std::string objectPath;
Ed Tanousb9d36b42022-02-26 21:42:46 -0800290 std::shared_ptr<dbus::utility::MapperGetSubTreeResponse> subtree;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600291 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
292};
293
Ed Tanous23a21a12020-07-25 04:45:05 +0000294inline void getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000295 const std::string& objectName, const std::string& objectManagerPath,
296 const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700297 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700298{
Ed Tanous81ce6092020-12-17 16:54:55 +0000299 BMCWEB_LOG_DEBUG << "getManagedObjectsForEnumerate " << objectName
300 << " object_manager_path " << objectManagerPath
301 << " connection_name " << connectionName;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700302 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000303 [transaction, objectName,
304 connectionName](const boost::system::error_code ec,
305 const dbus::utility::ManagedObjectType& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700306 if (ec)
307 {
308 BMCWEB_LOG_ERROR << "GetManagedObjects on path " << objectName
309 << " on connection " << connectionName
310 << " failed with code " << ec;
311 return;
312 }
Ed Tanous64530012018-02-06 17:08:16 -0800313
Ed Tanous002d39b2022-05-31 08:59:27 -0700314 nlohmann::json& dataJson =
315 transaction->asyncResp->res.jsonValue["data"];
Ed Tanous049a0512018-11-01 13:58:42 -0700316
Ed Tanous002d39b2022-05-31 08:59:27 -0700317 for (const auto& objectPath : objects)
318 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700319 if (objectPath.first.str.starts_with(objectName))
Ed Tanous049a0512018-11-01 13:58:42 -0700320 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700321 BMCWEB_LOG_DEBUG << "Reading object " << objectPath.first.str;
322 nlohmann::json& objectJson = dataJson[objectPath.first.str];
323 if (objectJson.is_null())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700324 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700325 objectJson = nlohmann::json::object();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700326 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500327 for (const auto& interface : objectPath.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700328 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700329 for (const auto& property : interface.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700330 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700331 nlohmann::json& propertyJson =
332 objectJson[property.first];
333 std::visit(
334 [&propertyJson](auto&& val) {
335 if constexpr (std::is_same_v<
336 std::decay_t<decltype(val)>,
337 sdbusplus::message::unix_fd>)
338 {
339 propertyJson = val.fd;
340 }
341 else
342 {
343
344 propertyJson = val;
345 }
346 },
347 property.second);
Ed Tanous049a0512018-11-01 13:58:42 -0700348 }
349 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700350 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700351 for (const auto& interface : objectPath.second)
352 {
353 if (interface.first == "org.freedesktop.DBus.ObjectManager")
354 {
355 getManagedObjectsForEnumerate(objectPath.first.str,
356 objectPath.first.str,
357 connectionName, transaction);
358 }
359 }
360 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700361 },
Ed Tanous81ce6092020-12-17 16:54:55 +0000362 connectionName, objectManagerPath, "org.freedesktop.DBus.ObjectManager",
363 "GetManagedObjects");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700364}
365
Ed Tanous23a21a12020-07-25 04:45:05 +0000366inline void findObjectManagerPathForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000367 const std::string& objectName, const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700368 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700369{
Ed Tanous81ce6092020-12-17 16:54:55 +0000370 BMCWEB_LOG_DEBUG << "Finding objectmanager for path " << objectName
371 << " on connection:" << connectionName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700372 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000373 [transaction, objectName, connectionName](
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700374 const boost::system::error_code ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800375 const dbus::utility::MapperGetAncestorsResponse& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700376 if (ec)
377 {
378 BMCWEB_LOG_ERROR << "GetAncestors on path " << objectName
379 << " failed with code " << ec;
380 return;
381 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700382
Ed Tanous002d39b2022-05-31 08:59:27 -0700383 for (const auto& pathGroup : objects)
384 {
385 for (const auto& connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700386 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700387 if (connectionGroup.first == connectionName)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700388 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700389 // Found the object manager path for this resource.
390 getManagedObjectsForEnumerate(objectName, pathGroup.first,
391 connectionName, transaction);
392 return;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700393 }
394 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700395 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700396 },
397 "xyz.openbmc_project.ObjectMapper",
398 "/xyz/openbmc_project/object_mapper",
Ed Tanous81ce6092020-12-17 16:54:55 +0000399 "xyz.openbmc_project.ObjectMapper", "GetAncestors", objectName,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500400 std::array<const char*, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700401}
Ed Tanous64530012018-02-06 17:08:16 -0800402
Ed Tanous7c091622019-05-23 11:42:36 -0700403// Uses GetObject to add the object info about the target /enumerate path to
404// the results of GetSubTree, as GetSubTree will not return info for the
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600405// target path, and then continues on enumerating the rest of the tree.
Ed Tanousb5a76932020-09-29 16:16:58 -0700406inline void getObjectAndEnumerate(
407 const std::shared_ptr<InProgressEnumerateData>& transaction)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600408{
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600409 crow::connections::systemBus->async_method_call(
410 [transaction](const boost::system::error_code ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800411 const dbus::utility::MapperGetObject& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700412 if (ec)
413 {
414 BMCWEB_LOG_ERROR << "GetObject for path " << transaction->objectPath
415 << " failed with code " << ec;
416 return;
417 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600418
Ed Tanous002d39b2022-05-31 08:59:27 -0700419 BMCWEB_LOG_DEBUG << "GetObject for " << transaction->objectPath
420 << " has " << objects.size() << " entries";
421 if (!objects.empty())
422 {
423 transaction->subtree->emplace_back(transaction->objectPath,
424 objects);
425 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600426
Ed Tanous002d39b2022-05-31 08:59:27 -0700427 // Map indicating connection name, and the path where the object
428 // manager exists
429 boost::container::flat_map<std::string, std::string> connections;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600430
Ed Tanous002d39b2022-05-31 08:59:27 -0700431 for (const auto& object : *(transaction->subtree))
432 {
433 for (const auto& connection : object.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600434 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700435 std::string& objectManagerPath = connections[connection.first];
436 for (const auto& interface : connection.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600437 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700438 BMCWEB_LOG_DEBUG << connection.first << " has interface "
439 << interface;
440 if (interface == "org.freedesktop.DBus.ObjectManager")
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600441 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700442 BMCWEB_LOG_DEBUG << "found object manager path "
443 << object.first;
444 objectManagerPath = object.first;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600445 }
446 }
447 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700448 }
449 BMCWEB_LOG_DEBUG << "Got " << connections.size() << " connections";
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600450
Ed Tanous002d39b2022-05-31 08:59:27 -0700451 for (const auto& connection : connections)
452 {
453 // If we already know where the object manager is, we don't
454 // need to search for it, we can call directly in to
455 // getManagedObjects
456 if (!connection.second.empty())
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600457 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700458 getManagedObjectsForEnumerate(transaction->objectPath,
459 connection.second,
460 connection.first, transaction);
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600461 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700462 else
463 {
464 // otherwise we need to find the object manager path
465 // before we can continue
466 findObjectManagerPathForEnumerate(
467 transaction->objectPath, connection.first, transaction);
468 }
469 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600470 },
471 "xyz.openbmc_project.ObjectMapper",
472 "/xyz/openbmc_project/object_mapper",
473 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500474 transaction->objectPath, std::array<const char*, 0>());
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600475}
Ed Tanous64530012018-02-06 17:08:16 -0800476
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700477// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700478struct InProgressActionData
479{
Ed Tanous4e23a442022-06-06 09:57:26 -0700480 explicit InProgressActionData(crow::Response& resIn) : res(resIn)
Ed Tanous23a21a12020-07-25 04:45:05 +0000481 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700482 ~InProgressActionData()
483 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600484 // Methods could have been called across different owners
485 // and interfaces, where some calls failed and some passed.
486 //
487 // The rules for this are:
488 // * if no method was called - error
489 // * if a method failed and none passed - error
490 // (converse: if at least one method passed - OK)
491 // * for the method output:
492 // * if output processing didn't fail, return the data
493
494 // Only deal with method returns if nothing failed earlier
495 if (res.result() == boost::beast::http::status::ok)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700496 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600497 if (!methodPassed)
498 {
Matt Spinler06b1b632019-06-18 16:09:25 -0500499 if (!methodFailed)
Matt Spinler16caaee2019-01-15 11:40:34 -0600500 {
501 setErrorResponse(res, boost::beast::http::status::not_found,
502 methodNotFoundDesc, notFoundMsg);
503 }
504 }
505 else
506 {
507 if (outputFailed)
508 {
509 setErrorResponse(
510 res, boost::beast::http::status::internal_server_error,
511 "Method output failure", methodOutputFailedMsg);
512 }
513 else
514 {
Ed Tanous14766872022-03-15 10:44:42 -0700515 res.jsonValue["status"] = "ok";
516 res.jsonValue["message"] = "200 OK";
517 res.jsonValue["data"] = methodResponse;
Matt Spinler16caaee2019-01-15 11:40:34 -0600518 }
519 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700520 }
Matt Spinler16caaee2019-01-15 11:40:34 -0600521
Ed Tanous1abe55e2018-09-05 08:30:59 -0700522 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700523 }
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800524 InProgressActionData(const InProgressActionData&) = delete;
525 InProgressActionData(InProgressActionData&&) = delete;
526 InProgressActionData& operator=(const InProgressActionData&) = delete;
527 InProgressActionData& operator=(InProgressActionData&&) = delete;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700528
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500529 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700530 {
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600531 setErrorResponse(res, boost::beast::http::status::bad_request, desc,
532 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700533 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500534 crow::Response& res;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700535 std::string path;
536 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600537 std::string interfaceName;
Matt Spinler16caaee2019-01-15 11:40:34 -0600538 bool methodPassed = false;
539 bool methodFailed = false;
540 bool outputFailed = false;
Matt Spinler39a4e392019-01-15 11:53:13 -0600541 bool convertedToArray = false;
Matt Spinler16caaee2019-01-15 11:40:34 -0600542 nlohmann::json methodResponse;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700543 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700544};
545
Ed Tanous23a21a12020-07-25 04:45:05 +0000546inline std::vector<std::string> dbusArgSplit(const std::string& string)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700547{
548 std::vector<std::string> ret;
549 if (string.empty())
550 {
551 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700552 }
Ed Tanous0f0353b2019-10-24 11:37:51 -0700553 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700554 int containerDepth = 0;
555
556 for (std::string::const_iterator character = string.begin();
557 character != string.end(); character++)
558 {
559 ret.back() += *character;
560 switch (*character)
561 {
562 case ('a'):
563 break;
564 case ('('):
565 case ('{'):
566 containerDepth++;
567 break;
568 case ('}'):
569 case (')'):
570 containerDepth--;
571 if (containerDepth == 0)
572 {
573 if (character + 1 != string.end())
574 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700575 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700576 }
577 }
578 break;
579 default:
580 if (containerDepth == 0)
581 {
582 if (character + 1 != string.end())
583 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700584 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700585 }
586 }
587 break;
588 }
589 }
Matt Spinler4ae611d2019-01-11 15:37:06 -0600590
591 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700592}
593
Ed Tanous81ce6092020-12-17 16:54:55 +0000594inline int convertJsonToDbus(sd_bus_message* m, const std::string& argType,
595 const nlohmann::json& inputJson)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700596{
597 int r = 0;
Ed Tanous71f52d92021-02-19 08:51:17 -0800598 BMCWEB_LOG_DEBUG << "Converting "
599 << inputJson.dump(2, ' ', true,
600 nlohmann::json::error_handler_t::replace)
Ed Tanous81ce6092020-12-17 16:54:55 +0000601 << " to type: " << argType;
602 const std::vector<std::string> argTypes = dbusArgSplit(argType);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700603
Ed Tanous1abe55e2018-09-05 08:30:59 -0700604 // Assume a single object for now.
Ed Tanous81ce6092020-12-17 16:54:55 +0000605 const nlohmann::json* j = &inputJson;
606 nlohmann::json::const_iterator jIt = inputJson.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700607
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500608 for (const std::string& argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700609 {
610 // If we are decoding multiple objects, grab the pointer to the
611 // iterator, and increment it for the next loop
612 if (argTypes.size() > 1)
613 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000614 if (jIt == inputJson.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700615 {
616 return -2;
617 }
618 j = &*jIt;
619 jIt++;
620 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500621 const int64_t* intValue = j->get_ptr<const int64_t*>();
622 const std::string* stringValue = j->get_ptr<const std::string*>();
623 const double* doubleValue = j->get_ptr<const double*>();
624 const bool* b = j->get_ptr<const bool*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700625 int64_t v = 0;
626 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700627
Ed Tanous1abe55e2018-09-05 08:30:59 -0700628 // Do some basic type conversions that make sense. uint can be
629 // converted to int. int and uint can be converted to double
Ed Tanous66664f22019-10-11 13:05:49 -0700630 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700631 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500632 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700633 if (uintValue != nullptr)
634 {
635 v = static_cast<int64_t>(*uintValue);
636 intValue = &v;
637 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700638 }
Ed Tanous66664f22019-10-11 13:05:49 -0700639 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700640 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500641 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700642 if (uintValue != nullptr)
643 {
644 d = static_cast<double>(*uintValue);
645 doubleValue = &d;
646 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700647 }
Ed Tanous66664f22019-10-11 13:05:49 -0700648 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700649 {
Ed Tanous66664f22019-10-11 13:05:49 -0700650 if (intValue != nullptr)
651 {
652 d = static_cast<double>(*intValue);
653 doubleValue = &d;
654 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700655 }
656
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700657 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700658 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700659 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700660 {
661 return -1;
662 }
Ed Tanous271584a2019-07-09 16:24:22 -0700663 r = sd_bus_message_append_basic(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500664 m, argCode[0], static_cast<const void*>(stringValue->data()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700665 if (r < 0)
666 {
667 return r;
668 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700669 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700670 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700671 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700672 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700673 {
674 return -1;
675 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500676 if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
677 (*intValue > std::numeric_limits<int32_t>::max()))
678 {
679 return -ERANGE;
680 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700681 int32_t i = static_cast<int32_t>(*intValue);
682 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700683 if (r < 0)
684 {
685 return r;
686 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700687 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700688 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700689 {
690 // lots of ways bool could be represented here. Try them all
Ed Tanouse662eae2022-01-25 10:39:19 -0800691 int boolInt = 0;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700692 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700693 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500694 if (*intValue == 1)
695 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800696 boolInt = 1;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500697 }
698 else if (*intValue == 0)
699 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800700 boolInt = 0;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500701 }
702 else
703 {
704 return -ERANGE;
705 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700706 }
707 else if (b != nullptr)
708 {
Matt Spinlera2f02632019-01-18 10:15:35 -0600709 boolInt = *b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700710 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700711 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700712 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700713 boolInt = boost::istarts_with(*stringValue, "t") ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700714 }
715 else
716 {
717 return -1;
718 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700719 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700720 if (r < 0)
721 {
722 return r;
723 }
724 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700725 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700726 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700727 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700728 {
729 return -1;
730 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500731 if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
732 (*intValue > std::numeric_limits<int16_t>::max()))
733 {
734 return -ERANGE;
735 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700736 int16_t n = static_cast<int16_t>(*intValue);
737 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700738 if (r < 0)
739 {
740 return r;
741 }
742 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700743 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700744 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700745 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700746 {
747 return -1;
748 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700749 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700750 if (r < 0)
751 {
752 return r;
753 }
754 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700755 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700756 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500757 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700758 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700759 {
760 return -1;
761 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000762 if (*uintValue > std::numeric_limits<uint8_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500763 {
764 return -ERANGE;
765 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700766 uint8_t y = static_cast<uint8_t>(*uintValue);
767 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700768 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700769 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700770 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500771 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700772 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700773 {
774 return -1;
775 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000776 if (*uintValue > std::numeric_limits<uint16_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500777 {
778 return -ERANGE;
779 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700780 uint16_t q = static_cast<uint16_t>(*uintValue);
781 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700782 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700783 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700784 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500785 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700786 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700787 {
788 return -1;
789 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000790 if (*uintValue > std::numeric_limits<uint32_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500791 {
792 return -ERANGE;
793 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700794 uint32_t u = static_cast<uint32_t>(*uintValue);
795 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700796 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700797 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700798 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500799 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700800 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700801 {
802 return -1;
803 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700804 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700805 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700806 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700807 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500808 if (doubleValue == nullptr)
809 {
810 return -1;
811 }
812 if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
813 (*doubleValue > std::numeric_limits<double>::max()))
814 {
815 return -ERANGE;
816 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700817 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700818 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700819 else if (argCode.starts_with("a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700820 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700821 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700822 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700823 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700824 if (r < 0)
825 {
826 return r;
827 }
828
Ed Tanous0dfeda62019-10-24 11:21:38 -0700829 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700830 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700831 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700832 if (r < 0)
833 {
834 return r;
835 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700836 }
837 sd_bus_message_close_container(m);
838 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700839 else if (argCode.starts_with("v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700840 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700841 std::string containedType = argCode.substr(1);
842 BMCWEB_LOG_DEBUG << "variant type: " << argCode
843 << " appending variant of type: " << containedType;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700844 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700845 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700846 if (r < 0)
847 {
848 return r;
849 }
850
Ed Tanous81ce6092020-12-17 16:54:55 +0000851 r = convertJsonToDbus(m, containedType, inputJson);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700852 if (r < 0)
853 {
854 return r;
855 }
856
857 r = sd_bus_message_close_container(m);
858 if (r < 0)
859 {
860 return r;
861 }
862 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700863 else if (argCode.starts_with("(") && argCode.ends_with(")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700864 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700865 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700866 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700867 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800868 if (r < 0)
869 {
870 return r;
871 }
872
Ed Tanous1abe55e2018-09-05 08:30:59 -0700873 nlohmann::json::const_iterator it = j->begin();
Ed Tanous81ce6092020-12-17 16:54:55 +0000874 for (const std::string& argCode2 : dbusArgSplit(argType))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700875 {
876 if (it == j->end())
877 {
878 return -1;
879 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000880 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700881 if (r < 0)
882 {
883 return r;
884 }
885 it++;
886 }
887 r = sd_bus_message_close_container(m);
888 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700889 else if (argCode.starts_with("{") && argCode.ends_with("}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700890 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700891 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700892 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700893 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800894 if (r < 0)
895 {
896 return r;
897 }
898
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700899 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700900 if (codes.size() != 2)
901 {
902 return -1;
903 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700904 const std::string& keyType = codes[0];
905 const std::string& valueType = codes[1];
Ed Tanous3174e4d2020-10-07 11:41:22 -0700906 for (const auto& it : j->items())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700907 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700908 r = convertJsonToDbus(m, keyType, it.key());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700909 if (r < 0)
910 {
911 return r;
912 }
913
Ed Tanous2c70f802020-09-28 14:29:23 -0700914 r = convertJsonToDbus(m, valueType, it.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700915 if (r < 0)
916 {
917 return r;
918 }
919 }
920 r = sd_bus_message_close_container(m);
921 }
922 else
923 {
924 return -2;
925 }
926 if (r < 0)
927 {
928 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700929 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700930
Ed Tanous1abe55e2018-09-05 08:30:59 -0700931 if (argTypes.size() > 1)
932 {
933 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700934 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700935 }
Matt Spinler127ea542019-01-14 11:04:28 -0600936
937 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700938}
939
Matt Spinlerd22a7132019-01-14 12:14:30 -0600940template <typename T>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500941int readMessageItem(const std::string& typeCode, sdbusplus::message::message& m,
942 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600943{
944 T value;
945
946 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
947 if (r < 0)
948 {
949 BMCWEB_LOG_ERROR << "sd_bus_message_read_basic on type " << typeCode
950 << " failed!";
951 return r;
952 }
953
954 data = value;
955 return 0;
956}
957
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500958int convertDBusToJSON(const std::string& returnType,
959 sdbusplus::message::message& m, nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600960
Ed Tanous23a21a12020-07-25 04:45:05 +0000961inline int readDictEntryFromMessage(const std::string& typeCode,
962 sdbusplus::message::message& m,
963 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600964{
965 std::vector<std::string> types = dbusArgSplit(typeCode);
966 if (types.size() != 2)
967 {
968 BMCWEB_LOG_ERROR << "wrong number contained types in dictionary: "
969 << types.size();
970 return -1;
971 }
972
973 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
974 typeCode.c_str());
975 if (r < 0)
976 {
977 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container with rc " << r;
978 return r;
979 }
980
981 nlohmann::json key;
982 r = convertDBusToJSON(types[0], m, key);
983 if (r < 0)
984 {
985 return r;
986 }
987
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500988 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -0600989 if (keyPtr == nullptr)
990 {
991 // json doesn't support non-string keys. If we hit this condition,
992 // convert the result to a string so we can proceed
Ed Tanous71f52d92021-02-19 08:51:17 -0800993 key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500994 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -0700995 // in theory this can't fail now, but lets be paranoid about it
996 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -0600997 if (keyPtr == nullptr)
998 {
999 return -1;
1000 }
1001 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001002 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -06001003
1004 r = convertDBusToJSON(types[1], m, value);
1005 if (r < 0)
1006 {
1007 return r;
1008 }
1009
1010 r = sd_bus_message_exit_container(m.get());
1011 if (r < 0)
1012 {
1013 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1014 return r;
1015 }
1016
1017 return 0;
1018}
1019
Ed Tanous23a21a12020-07-25 04:45:05 +00001020inline int readArrayFromMessage(const std::string& typeCode,
1021 sdbusplus::message::message& m,
1022 nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -06001023{
1024 if (typeCode.size() < 2)
1025 {
1026 BMCWEB_LOG_ERROR << "Type code " << typeCode
1027 << " too small for an array";
1028 return -1;
1029 }
1030
1031 std::string containedType = typeCode.substr(1);
1032
1033 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
1034 containedType.c_str());
1035 if (r < 0)
1036 {
1037 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1038 << r;
1039 return r;
1040 }
1041
Ed Tanous11ba3972022-07-11 09:50:41 -07001042 bool dict = containedType.starts_with("{") && containedType.ends_with("}");
Matt Spinler6df8f992019-01-14 12:47:47 -06001043
1044 if (dict)
1045 {
1046 // Remove the { }
1047 containedType = containedType.substr(1, containedType.size() - 2);
1048 data = nlohmann::json::object();
1049 }
1050 else
1051 {
1052 data = nlohmann::json::array();
1053 }
1054
1055 while (true)
1056 {
Ed Tanouse662eae2022-01-25 10:39:19 -08001057 r = sd_bus_message_at_end(m.get(), 0);
Matt Spinler6df8f992019-01-14 12:47:47 -06001058 if (r < 0)
1059 {
1060 BMCWEB_LOG_ERROR << "sd_bus_message_at_end failed";
1061 return r;
1062 }
1063
1064 if (r > 0)
1065 {
1066 break;
1067 }
1068
1069 // Dictionaries are only ever seen in an array
1070 if (dict)
1071 {
1072 r = readDictEntryFromMessage(containedType, m, data);
1073 if (r < 0)
1074 {
1075 return r;
1076 }
1077 }
1078 else
1079 {
1080 data.push_back(nlohmann::json());
1081
1082 r = convertDBusToJSON(containedType, m, data.back());
1083 if (r < 0)
1084 {
1085 return r;
1086 }
1087 }
1088 }
1089
1090 r = sd_bus_message_exit_container(m.get());
1091 if (r < 0)
1092 {
1093 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1094 return r;
1095 }
1096
1097 return 0;
1098}
1099
Ed Tanous23a21a12020-07-25 04:45:05 +00001100inline int readStructFromMessage(const std::string& typeCode,
1101 sdbusplus::message::message& m,
1102 nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001103{
1104 if (typeCode.size() < 3)
1105 {
1106 BMCWEB_LOG_ERROR << "Type code " << typeCode
1107 << " too small for a struct";
1108 return -1;
1109 }
1110
1111 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1112 std::vector<std::string> types = dbusArgSplit(containedTypes);
1113
1114 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1115 containedTypes.c_str());
1116 if (r < 0)
1117 {
1118 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1119 << r;
1120 return r;
1121 }
1122
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001123 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001124 {
1125 data.push_back(nlohmann::json());
1126 r = convertDBusToJSON(type, m, data.back());
1127 if (r < 0)
1128 {
1129 return r;
1130 }
1131 }
1132
1133 r = sd_bus_message_exit_container(m.get());
1134 if (r < 0)
1135 {
1136 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1137 return r;
1138 }
1139 return 0;
1140}
1141
Ed Tanous23a21a12020-07-25 04:45:05 +00001142inline int readVariantFromMessage(sdbusplus::message::message& m,
1143 nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001144{
Ed Tanous543f4402022-01-06 13:12:53 -08001145 const char* containerType = nullptr;
Ed Tanous99131cd2019-10-24 11:12:47 -07001146 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001147 if (r < 0)
1148 {
1149 BMCWEB_LOG_ERROR << "sd_bus_message_peek_type failed";
1150 return r;
1151 }
1152
1153 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1154 containerType);
1155 if (r < 0)
1156 {
1157 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1158 << r;
1159 return r;
1160 }
1161
1162 r = convertDBusToJSON(containerType, m, data);
1163 if (r < 0)
1164 {
1165 return r;
1166 }
1167
1168 r = sd_bus_message_exit_container(m.get());
1169 if (r < 0)
1170 {
1171 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed";
1172 return r;
1173 }
1174
1175 return 0;
1176}
1177
Ed Tanous23a21a12020-07-25 04:45:05 +00001178inline int convertDBusToJSON(const std::string& returnType,
1179 sdbusplus::message::message& m,
1180 nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001181{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001182 int r = 0;
1183 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1184
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001185 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001186 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001187 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001188 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001189 {
1190 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001191 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001192 }
1193
Ed Tanousd4d25792020-09-29 15:15:03 -07001194 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001195 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001196 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001197 if (r < 0)
1198 {
1199 return r;
1200 }
1201 }
1202 else if (typeCode == "b")
1203 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001204 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001205 if (r < 0)
1206 {
1207 return r;
1208 }
1209
Matt Spinlerf39420c2019-01-30 12:57:18 -06001210 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001211 }
1212 else if (typeCode == "u")
1213 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001214 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001215 if (r < 0)
1216 {
1217 return r;
1218 }
1219 }
1220 else if (typeCode == "i")
1221 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001222 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001223 if (r < 0)
1224 {
1225 return r;
1226 }
1227 }
1228 else if (typeCode == "x")
1229 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001230 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001231 if (r < 0)
1232 {
1233 return r;
1234 }
1235 }
1236 else if (typeCode == "t")
1237 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001238 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001239 if (r < 0)
1240 {
1241 return r;
1242 }
1243 }
1244 else if (typeCode == "n")
1245 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001246 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001247 if (r < 0)
1248 {
1249 return r;
1250 }
1251 }
1252 else if (typeCode == "q")
1253 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001254 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001255 if (r < 0)
1256 {
1257 return r;
1258 }
1259 }
1260 else if (typeCode == "y")
1261 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001262 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001263 if (r < 0)
1264 {
1265 return r;
1266 }
1267 }
1268 else if (typeCode == "d")
1269 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001270 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001271 if (r < 0)
1272 {
1273 return r;
1274 }
1275 }
1276 else if (typeCode == "h")
1277 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001278 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001279 if (r < 0)
1280 {
1281 return r;
1282 }
1283 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001284 else if (typeCode.starts_with("a"))
Matt Spinler6df8f992019-01-14 12:47:47 -06001285 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001286 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001287 if (r < 0)
1288 {
1289 return r;
1290 }
1291 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001292 else if (typeCode.starts_with("(") && typeCode.ends_with(")"))
Matt Spinler75c6c672019-01-14 13:01:46 -06001293 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001294 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001295 if (r < 0)
1296 {
1297 return r;
1298 }
1299 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001300 else if (typeCode.starts_with("v"))
Matt Spinler89c19702019-01-14 13:13:00 -06001301 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001302 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001303 if (r < 0)
1304 {
1305 return r;
1306 }
1307 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001308 else
1309 {
Matt Spinlerd22a7132019-01-14 12:14:30 -06001310 BMCWEB_LOG_ERROR << "Invalid D-Bus signature type " << typeCode;
1311 return -2;
1312 }
1313 }
1314
Matt Spinler16caaee2019-01-15 11:40:34 -06001315 return 0;
1316}
1317
Ed Tanousb5a76932020-09-29 16:16:58 -07001318inline void handleMethodResponse(
1319 const std::shared_ptr<InProgressActionData>& transaction,
1320 sdbusplus::message::message& m, const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001321{
Matt Spinler39a4e392019-01-15 11:53:13 -06001322 nlohmann::json data;
1323
1324 int r = convertDBusToJSON(returnType, m, data);
1325 if (r < 0)
1326 {
1327 transaction->outputFailed = true;
1328 return;
1329 }
1330
1331 if (data.is_null())
1332 {
1333 return;
1334 }
1335
1336 if (transaction->methodResponse.is_null())
1337 {
1338 transaction->methodResponse = std::move(data);
1339 return;
1340 }
1341
1342 // If they're both dictionaries or arrays, merge into one.
1343 // Otherwise, make the results an array with every result
1344 // an entry. Could also just fail in that case, but it
1345 // seems better to get the data back somehow.
1346
1347 if (transaction->methodResponse.is_object() && data.is_object())
1348 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001349 for (const auto& obj : data.items())
Matt Spinler39a4e392019-01-15 11:53:13 -06001350 {
1351 // Note: Will overwrite the data for a duplicate key
1352 transaction->methodResponse.emplace(obj.key(),
1353 std::move(obj.value()));
1354 }
1355 return;
1356 }
1357
1358 if (transaction->methodResponse.is_array() && data.is_array())
1359 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001360 for (auto& obj : data)
Matt Spinler39a4e392019-01-15 11:53:13 -06001361 {
1362 transaction->methodResponse.push_back(std::move(obj));
1363 }
1364 return;
1365 }
1366
1367 if (!transaction->convertedToArray)
1368 {
1369 // They are different types. May as well turn them into an array
1370 nlohmann::json j = std::move(transaction->methodResponse);
1371 transaction->methodResponse = nlohmann::json::array();
1372 transaction->methodResponse.push_back(std::move(j));
1373 transaction->methodResponse.push_back(std::move(data));
1374 transaction->convertedToArray = true;
1375 }
1376 else
1377 {
1378 transaction->methodResponse.push_back(std::move(data));
1379 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001380}
1381
Ed Tanousb5a76932020-09-29 16:16:58 -07001382inline void findActionOnInterface(
1383 const std::shared_ptr<InProgressActionData>& transaction,
1384 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001385{
1386 BMCWEB_LOG_DEBUG << "findActionOnInterface for connection "
1387 << connectionName;
1388 crow::connections::systemBus->async_method_call(
1389 [transaction, connectionName{std::string(connectionName)}](
1390 const boost::system::error_code ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001391 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001392 BMCWEB_LOG_DEBUG << "got xml:\n " << introspectXml;
1393 if (ec)
1394 {
1395 BMCWEB_LOG_ERROR
1396 << "Introspect call failed with error: " << ec.message()
1397 << " on process: " << connectionName << "\n";
1398 return;
1399 }
1400 tinyxml2::XMLDocument doc;
Matt Spinler318bd892019-01-15 09:59:20 -06001401
Ed Tanous002d39b2022-05-31 08:59:27 -07001402 doc.Parse(introspectXml.data(), introspectXml.size());
1403 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1404 if (pRoot == nullptr)
1405 {
1406 BMCWEB_LOG_ERROR << "XML document failed to parse "
1407 << connectionName << "\n";
1408 return;
1409 }
1410 tinyxml2::XMLElement* interfaceNode =
1411 pRoot->FirstChildElement("interface");
1412 while (interfaceNode != nullptr)
1413 {
1414 const char* thisInterfaceName = interfaceNode->Attribute("name");
1415 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001416 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001417 if (!transaction->interfaceName.empty() &&
1418 (transaction->interfaceName != thisInterfaceName))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001419 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001420 interfaceNode =
1421 interfaceNode->NextSiblingElement("interface");
1422 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001423 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001424
1425 tinyxml2::XMLElement* methodNode =
1426 interfaceNode->FirstChildElement("method");
1427 while (methodNode != nullptr)
1428 {
1429 const char* thisMethodName = methodNode->Attribute("name");
1430 BMCWEB_LOG_DEBUG << "Found method: " << thisMethodName;
1431 if (thisMethodName != nullptr &&
1432 thisMethodName == transaction->methodName)
1433 {
1434 BMCWEB_LOG_DEBUG << "Found method named "
1435 << thisMethodName << " on interface "
1436 << thisInterfaceName;
1437 sdbusplus::message::message m =
1438 crow::connections::systemBus->new_method_call(
1439 connectionName.c_str(),
1440 transaction->path.c_str(), thisInterfaceName,
1441 transaction->methodName.c_str());
1442
1443 tinyxml2::XMLElement* argumentNode =
1444 methodNode->FirstChildElement("arg");
1445
1446 std::string returnType;
1447
1448 // Find the output type
1449 while (argumentNode != nullptr)
1450 {
1451 const char* argDirection =
1452 argumentNode->Attribute("direction");
1453 const char* argType =
1454 argumentNode->Attribute("type");
1455 if (argDirection != nullptr && argType != nullptr &&
1456 std::string(argDirection) == "out")
1457 {
1458 returnType = argType;
1459 break;
1460 }
1461 argumentNode =
1462 argumentNode->NextSiblingElement("arg");
1463 }
1464
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001465 auto argIt = transaction->arguments.begin();
Ed Tanous002d39b2022-05-31 08:59:27 -07001466
1467 argumentNode = methodNode->FirstChildElement("arg");
1468
1469 while (argumentNode != nullptr)
1470 {
1471 const char* argDirection =
1472 argumentNode->Attribute("direction");
1473 const char* argType =
1474 argumentNode->Attribute("type");
1475 if (argDirection != nullptr && argType != nullptr &&
1476 std::string(argDirection) == "in")
1477 {
1478 if (argIt == transaction->arguments.end())
1479 {
1480 transaction->setErrorStatus(
1481 "Invalid method args");
1482 return;
1483 }
1484 if (convertJsonToDbus(m.get(),
1485 std::string(argType),
1486 *argIt) < 0)
1487 {
1488 transaction->setErrorStatus(
1489 "Invalid method arg type");
1490 return;
1491 }
1492
1493 argIt++;
1494 }
1495 argumentNode =
1496 argumentNode->NextSiblingElement("arg");
1497 }
1498
1499 crow::connections::systemBus->async_send(
1500 m,
1501 [transaction,
1502 returnType](boost::system::error_code ec2,
1503 sdbusplus::message::message& m2) {
1504 if (ec2)
1505 {
1506 transaction->methodFailed = true;
1507 const sd_bus_error* e = m2.get_error();
1508
1509 if (e != nullptr)
1510 {
1511 setErrorResponse(
1512 transaction->res,
1513 boost::beast::http::status::bad_request,
1514 e->name, e->message);
1515 }
1516 else
1517 {
1518 setErrorResponse(
1519 transaction->res,
1520 boost::beast::http::status::bad_request,
1521 "Method call failed", methodFailedMsg);
1522 }
1523 return;
1524 }
1525 transaction->methodPassed = true;
1526
1527 handleMethodResponse(transaction, m2, returnType);
1528 });
1529 break;
1530 }
1531 methodNode = methodNode->NextSiblingElement("method");
1532 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001533 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001534 interfaceNode = interfaceNode->NextSiblingElement("interface");
1535 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001536 },
1537 connectionName, transaction->path,
1538 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001539}
1540
zhanghch058d1b46d2021-04-01 11:18:24 +08001541inline void handleAction(const crow::Request& req,
1542 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001543 const std::string& objectPath,
1544 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001545{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001546 BMCWEB_LOG_DEBUG << "handleAction on path: " << objectPath << " and method "
1547 << methodName;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001548 nlohmann::json requestDbusData =
1549 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001550
Ed Tanous1abe55e2018-09-05 08:30:59 -07001551 if (requestDbusData.is_discarded())
1552 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001553 setErrorResponse(asyncResp->res,
1554 boost::beast::http::status::bad_request, noJsonDesc,
1555 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001556 return;
1557 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001558 nlohmann::json::iterator data = requestDbusData.find("data");
1559 if (data == requestDbusData.end())
1560 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001561 setErrorResponse(asyncResp->res,
1562 boost::beast::http::status::bad_request, noJsonDesc,
1563 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001564 return;
1565 }
1566
1567 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001568 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001569 setErrorResponse(asyncResp->res,
1570 boost::beast::http::status::bad_request, noJsonDesc,
1571 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001572 return;
1573 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001574 auto transaction = std::make_shared<InProgressActionData>(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001575
1576 transaction->path = objectPath;
1577 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001578 transaction->arguments = std::move(*data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001579 crow::connections::systemBus->async_method_call(
1580 [transaction](
1581 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001582 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1583 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001584 if (ec || interfaceNames.empty())
1585 {
1586 BMCWEB_LOG_ERROR << "Can't find object";
1587 setErrorResponse(transaction->res,
1588 boost::beast::http::status::not_found,
1589 notFoundDesc, notFoundMsg);
1590 return;
1591 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001592
Ed Tanous002d39b2022-05-31 08:59:27 -07001593 BMCWEB_LOG_DEBUG << "GetObject returned " << interfaceNames.size()
1594 << " object(s)";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001595
Ed Tanous002d39b2022-05-31 08:59:27 -07001596 for (const std::pair<std::string, std::vector<std::string>>& object :
1597 interfaceNames)
1598 {
1599 findActionOnInterface(transaction, object.first);
1600 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001601 },
1602 "xyz.openbmc_project.ObjectMapper",
1603 "/xyz/openbmc_project/object_mapper",
1604 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
1605 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001606}
1607
zhanghch058d1b46d2021-04-01 11:18:24 +08001608inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1609 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001610{
1611 BMCWEB_LOG_DEBUG << "handleDelete on path: " << objectPath;
1612
1613 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +08001614 [asyncResp, objectPath](
Matt Spinlerde818812018-12-11 16:39:20 -06001615 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001616 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1617 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001618 if (ec || interfaceNames.empty())
1619 {
1620 BMCWEB_LOG_ERROR << "Can't find object";
1621 setErrorResponse(asyncResp->res,
1622 boost::beast::http::status::method_not_allowed,
1623 methodNotAllowedDesc, methodNotAllowedMsg);
1624 return;
1625 }
Matt Spinlerde818812018-12-11 16:39:20 -06001626
Ed Tanous002d39b2022-05-31 08:59:27 -07001627 auto transaction =
1628 std::make_shared<InProgressActionData>(asyncResp->res);
1629 transaction->path = objectPath;
1630 transaction->methodName = "Delete";
1631 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
Matt Spinlerde818812018-12-11 16:39:20 -06001632
Ed Tanous002d39b2022-05-31 08:59:27 -07001633 for (const std::pair<std::string, std::vector<std::string>>& object :
1634 interfaceNames)
1635 {
1636 findActionOnInterface(transaction, object.first);
1637 }
Matt Spinlerde818812018-12-11 16:39:20 -06001638 },
1639 "xyz.openbmc_project.ObjectMapper",
1640 "/xyz/openbmc_project/object_mapper",
1641 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001642 std::array<const char*, 0>());
Matt Spinlerde818812018-12-11 16:39:20 -06001643}
1644
zhanghch058d1b46d2021-04-01 11:18:24 +08001645inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1646 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001647{
1648 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001649 [asyncResp](
1650 const boost::system::error_code ec,
1651 const dbus::utility::MapperGetSubTreePathsResponse& objectPaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001652 if (ec)
1653 {
1654 setErrorResponse(asyncResp->res,
1655 boost::beast::http::status::not_found,
1656 notFoundDesc, notFoundMsg);
1657 }
1658 else
1659 {
1660 asyncResp->res.jsonValue["status"] = "ok";
1661 asyncResp->res.jsonValue["message"] = "200 OK";
1662 asyncResp->res.jsonValue["data"] = objectPaths;
1663 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001664 },
1665 "xyz.openbmc_project.ObjectMapper",
1666 "/xyz/openbmc_project/object_mapper",
1667 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", objectPath,
Ed Tanousf839dfe2018-11-12 11:11:15 -08001668 depth, std::array<std::string, 0>());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001669}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001670
zhanghch058d1b46d2021-04-01 11:18:24 +08001671inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1672 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001673{
Ed Tanous049a0512018-11-01 13:58:42 -07001674 BMCWEB_LOG_DEBUG << "Doing enumerate on " << objectPath;
Ed Tanous049a0512018-11-01 13:58:42 -07001675
Ed Tanous14766872022-03-15 10:44:42 -07001676 asyncResp->res.jsonValue["message"] = "200 OK";
1677 asyncResp->res.jsonValue["status"] = "ok";
1678 asyncResp->res.jsonValue["data"] = nlohmann::json::object();
Ed Tanous049a0512018-11-01 13:58:42 -07001679
Ed Tanous1abe55e2018-09-05 08:30:59 -07001680 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001681 [objectPath, asyncResp](
1682 const boost::system::error_code ec,
1683 const dbus::utility::MapperGetSubTreeResponse& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001684 auto transaction =
1685 std::make_shared<InProgressEnumerateData>(objectPath, asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001686
Ed Tanous002d39b2022-05-31 08:59:27 -07001687 transaction->subtree =
1688 std::make_shared<dbus::utility::MapperGetSubTreeResponse>(
1689 objectNames);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001690
Ed Tanous002d39b2022-05-31 08:59:27 -07001691 if (ec)
1692 {
1693 BMCWEB_LOG_ERROR << "GetSubTree failed on "
1694 << transaction->objectPath;
1695 setErrorResponse(transaction->asyncResp->res,
1696 boost::beast::http::status::not_found,
1697 notFoundDesc, notFoundMsg);
1698 return;
1699 }
Ed Tanous64530012018-02-06 17:08:16 -08001700
Ed Tanous002d39b2022-05-31 08:59:27 -07001701 // Add the data for the path passed in to the results
1702 // as if GetSubTree returned it, and continue on enumerating
1703 getObjectAndEnumerate(transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001704 },
1705 "xyz.openbmc_project.ObjectMapper",
1706 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -07001707 "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath, 0,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001708 std::array<const char*, 0>());
Ed Tanous64530012018-02-06 17:08:16 -08001709}
Ed Tanous911ac312017-08-15 09:37:42 -07001710
zhanghch058d1b46d2021-04-01 11:18:24 +08001711inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1712 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001713{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001714 BMCWEB_LOG_DEBUG << "handleGet: " << objectPath << " prop:" << destProperty;
1715 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001716 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001717
Ed Tanous1abe55e2018-09-05 08:30:59 -07001718 std::shared_ptr<std::string> path =
1719 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001720
Ed Tanous1abe55e2018-09-05 08:30:59 -07001721 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001722 [asyncResp, path,
1723 propertyName](const boost::system::error_code ec,
1724 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001725 if (ec || objectNames.empty())
1726 {
1727 setErrorResponse(asyncResp->res,
1728 boost::beast::http::status::not_found,
1729 notFoundDesc, notFoundMsg);
1730 return;
1731 }
1732 std::shared_ptr<nlohmann::json> response =
1733 std::make_shared<nlohmann::json>(nlohmann::json::object());
1734 // The mapper should never give us an empty interface names
1735 // list, but check anyway
1736 for (const std::pair<std::string, std::vector<std::string>>&
1737 connection : objectNames)
1738 {
1739 const std::vector<std::string>& interfaceNames = connection.second;
1740
1741 if (interfaceNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001742 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001743 setErrorResponse(asyncResp->res,
1744 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001745 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001746 return;
1747 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001748
1749 for (const std::string& interface : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001750 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001751 sdbusplus::message::message m =
1752 crow::connections::systemBus->new_method_call(
1753 connection.first.c_str(), path->c_str(),
1754 "org.freedesktop.DBus.Properties", "GetAll");
1755 m.append(interface);
1756 crow::connections::systemBus->async_send(
1757 m, [asyncResp, response,
1758 propertyName](const boost::system::error_code ec2,
1759 sdbusplus::message::message& msg) {
1760 if (ec2)
1761 {
1762 BMCWEB_LOG_ERROR << "Bad dbus request error: "
1763 << ec2;
1764 }
1765 else
1766 {
1767 nlohmann::json properties;
1768 int r = convertDBusToJSON("a{sv}", msg, properties);
1769 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001770 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001771 BMCWEB_LOG_ERROR << "convertDBusToJSON failed";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001772 }
1773 else
1774 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001775 for (auto& prop : properties.items())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001776 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001777 // if property name is empty, or
1778 // matches our search query, add it
1779 // to the response json
Ed Tanous1abe55e2018-09-05 08:30:59 -07001780
Ed Tanous002d39b2022-05-31 08:59:27 -07001781 if (propertyName->empty())
1782 {
1783 (*response)[prop.key()] =
1784 std::move(prop.value());
1785 }
1786 else if (prop.key() == *propertyName)
1787 {
1788 *response = std::move(prop.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001789 }
1790 }
1791 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001792 }
1793 if (response.use_count() == 1)
1794 {
1795 if (!propertyName->empty() && response->empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001796 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001797 setErrorResponse(
1798 asyncResp->res,
1799 boost::beast::http::status::not_found,
1800 propNotFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001801 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001802 else
1803 {
1804 asyncResp->res.jsonValue["status"] = "ok";
1805 asyncResp->res.jsonValue["message"] = "200 OK";
1806 asyncResp->res.jsonValue["data"] = *response;
1807 }
1808 }
1809 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001810 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001811 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001812 },
1813 "xyz.openbmc_project.ObjectMapper",
1814 "/xyz/openbmc_project/object_mapper",
1815 "xyz.openbmc_project.ObjectMapper", "GetObject", *path,
1816 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001817}
1818
Ed Tanous1abe55e2018-09-05 08:30:59 -07001819struct AsyncPutRequest
1820{
Ed Tanous4e23a442022-06-06 09:57:26 -07001821 explicit AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
zhanghch058d1b46d2021-04-01 11:18:24 +08001822 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001823 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001824 ~AsyncPutRequest()
1825 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001826 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001827 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001828 setErrorResponse(asyncResp->res,
1829 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001830 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001831 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001832 }
1833
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001834 AsyncPutRequest(const AsyncPutRequest&) = delete;
1835 AsyncPutRequest(AsyncPutRequest&&) = delete;
1836 AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1837 AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1838
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001839 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001840 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001841 setErrorResponse(asyncResp->res,
1842 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001843 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001844 }
1845
zhanghch058d1b46d2021-04-01 11:18:24 +08001846 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001847 std::string objectPath;
1848 std::string propertyName;
1849 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001850};
1851
zhanghch058d1b46d2021-04-01 11:18:24 +08001852inline void handlePut(const crow::Request& req,
1853 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001854 const std::string& objectPath,
1855 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001856{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001857 if (destProperty.empty())
1858 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001859 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001860 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001861 return;
1862 }
1863
Ed Tanous1abe55e2018-09-05 08:30:59 -07001864 nlohmann::json requestDbusData =
1865 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001866
Ed Tanous1abe55e2018-09-05 08:30:59 -07001867 if (requestDbusData.is_discarded())
1868 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001869 setErrorResponse(asyncResp->res,
1870 boost::beast::http::status::bad_request, noJsonDesc,
1871 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001872 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001873 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001874
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001875 auto propertyIt = requestDbusData.find("data");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001876 if (propertyIt == requestDbusData.end())
1877 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001878 setErrorResponse(asyncResp->res,
1879 boost::beast::http::status::bad_request, noJsonDesc,
1880 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001881 return;
1882 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001883 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001884 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001885 transaction->objectPath = objectPath;
1886 transaction->propertyName = destProperty;
1887 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001888
Ed Tanous1abe55e2018-09-05 08:30:59 -07001889 crow::connections::systemBus->async_method_call(
Ed Tanous23a21a12020-07-25 04:45:05 +00001890 [transaction](const boost::system::error_code ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001891 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001892 if (!ec2 && objectNames.empty())
1893 {
1894 setErrorResponse(transaction->asyncResp->res,
1895 boost::beast::http::status::not_found,
1896 propNotFoundDesc, notFoundMsg);
1897 return;
1898 }
Ed Tanous911ac312017-08-15 09:37:42 -07001899
Ed Tanous002d39b2022-05-31 08:59:27 -07001900 for (const std::pair<std::string, std::vector<std::string>>&
1901 connection : objectNames)
1902 {
1903 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001904
Ed Tanous002d39b2022-05-31 08:59:27 -07001905 crow::connections::systemBus->async_method_call(
1906 [connectionName{std::string(connectionName)},
1907 transaction](const boost::system::error_code ec3,
1908 const std::string& introspectXml) {
1909 if (ec3)
1910 {
1911 BMCWEB_LOG_ERROR << "Introspect call failed with error: "
1912 << ec3.message()
1913 << " on process: " << connectionName;
1914 transaction->setErrorStatus("Unexpected Error");
1915 return;
1916 }
1917 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001918
Ed Tanous002d39b2022-05-31 08:59:27 -07001919 doc.Parse(introspectXml.c_str());
1920 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1921 if (pRoot == nullptr)
1922 {
1923 BMCWEB_LOG_ERROR << "XML document failed to parse: "
1924 << introspectXml;
1925 transaction->setErrorStatus("Unexpected Error");
1926 return;
1927 }
1928 tinyxml2::XMLElement* ifaceNode =
1929 pRoot->FirstChildElement("interface");
1930 while (ifaceNode != nullptr)
1931 {
1932 const char* interfaceName = ifaceNode->Attribute("name");
1933 BMCWEB_LOG_DEBUG << "found interface " << interfaceName;
1934 tinyxml2::XMLElement* propNode =
1935 ifaceNode->FirstChildElement("property");
1936 while (propNode != nullptr)
1937 {
1938 const char* propertyName = propNode->Attribute("name");
1939 BMCWEB_LOG_DEBUG << "Found property " << propertyName;
1940 if (propertyName == transaction->propertyName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001941 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001942 const char* argType = propNode->Attribute("type");
1943 if (argType != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001944 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001945 sdbusplus::message::message m =
1946 crow::connections::systemBus
1947 ->new_method_call(
1948 connectionName.c_str(),
1949 transaction->objectPath.c_str(),
1950 "org.freedesktop.DBus."
1951 "Properties",
1952 "Set");
1953 m.append(interfaceName,
1954 transaction->propertyName);
1955 int r = sd_bus_message_open_container(
1956 m.get(), SD_BUS_TYPE_VARIANT, argType);
1957 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001958 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001959 transaction->setErrorStatus(
1960 "Unexpected Error");
1961 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001962 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001963 r = convertJsonToDbus(
1964 m.get(), argType,
1965 transaction->propertyValue);
1966 if (r < 0)
1967 {
1968 if (r == -ERANGE)
1969 {
1970 transaction->setErrorStatus(
1971 "Provided property value "
1972 "is out of range for the "
1973 "property type");
1974 }
1975 else
1976 {
1977 transaction->setErrorStatus(
1978 "Invalid arg type");
1979 }
1980 return;
1981 }
1982 r = sd_bus_message_close_container(m.get());
1983 if (r < 0)
1984 {
1985 transaction->setErrorStatus(
1986 "Unexpected Error");
1987 return;
1988 }
1989 crow::connections::systemBus->async_send(
1990 m,
1991 [transaction](
1992 boost::system::error_code ec,
1993 sdbusplus::message::message& m2) {
1994 BMCWEB_LOG_DEBUG << "sent";
1995 if (ec)
1996 {
1997 const sd_bus_error* e = m2.get_error();
1998 setErrorResponse(
1999 transaction->asyncResp->res,
2000 boost::beast::http::status::
2001 forbidden,
2002 (e) != nullptr
2003 ? e->name
2004 : ec.category().name(),
2005 (e) != nullptr ? e->message
2006 : ec.message());
2007 }
2008 else
2009 {
2010 transaction->asyncResp->res
2011 .jsonValue["status"] = "ok";
2012 transaction->asyncResp->res
2013 .jsonValue["message"] = "200 OK";
2014 transaction->asyncResp->res
2015 .jsonValue["data"] = nullptr;
2016 }
2017 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002018 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002019 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002020 propNode = propNode->NextSiblingElement("property");
2021 }
2022 ifaceNode = ifaceNode->NextSiblingElement("interface");
2023 }
2024 },
2025 connectionName, transaction->objectPath,
2026 "org.freedesktop.DBus.Introspectable", "Introspect");
2027 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002028 },
2029 "xyz.openbmc_project.ObjectMapper",
2030 "/xyz/openbmc_project/object_mapper",
2031 "xyz.openbmc_project.ObjectMapper", "GetObject",
2032 transaction->objectPath, std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07002033}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002034
zhanghch058d1b46d2021-04-01 11:18:24 +08002035inline void handleDBusUrl(const crow::Request& req,
2036 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002037 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002038{
Ed Tanous049a0512018-11-01 13:58:42 -07002039
2040 // If accessing a single attribute, fill in and update objectPath,
2041 // otherwise leave destProperty blank
Ed Tanouse05aec52022-01-25 10:28:56 -08002042 std::string destProperty;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002043 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002044 size_t attrPosition = objectPath.find(attrSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002045 if (attrPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002046 {
2047 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2048 objectPath.length());
2049 objectPath = objectPath.substr(0, attrPosition);
2050 }
2051
Ed Tanousb41187f2019-10-24 16:30:02 -07002052 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002053 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002054 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002055 size_t actionPosition = objectPath.find(actionSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002056 if (actionPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002057 {
2058 std::string postProperty =
2059 objectPath.substr((actionPosition + strlen(actionSeperator)),
2060 objectPath.length());
2061 objectPath = objectPath.substr(0, actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002062 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002063 return;
2064 }
2065 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002066 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002067 {
Ed Tanous11ba3972022-07-11 09:50:41 -07002068 if (objectPath.ends_with("/enumerate"))
Ed Tanous049a0512018-11-01 13:58:42 -07002069 {
2070 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2071 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002072 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002073 }
Ed Tanous11ba3972022-07-11 09:50:41 -07002074 else if (objectPath.ends_with("/list"))
Ed Tanous049a0512018-11-01 13:58:42 -07002075 {
2076 objectPath.erase(objectPath.end() - sizeof("list"),
2077 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002078 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002079 }
2080 else
2081 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002082 // Trim any trailing "/" at the end
Ed Tanous11ba3972022-07-11 09:50:41 -07002083 if (objectPath.ends_with("/"))
Ed Tanousf839dfe2018-11-12 11:11:15 -08002084 {
2085 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002086 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002087 }
2088 else
2089 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002090 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002091 }
Ed Tanous049a0512018-11-01 13:58:42 -07002092 }
2093 return;
2094 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002095 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002096 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002097 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002098 return;
2099 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002100 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002101 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002102 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002103 return;
2104 }
Ed Tanous049a0512018-11-01 13:58:42 -07002105
zhanghch058d1b46d2021-04-01 11:18:24 +08002106 setErrorResponse(asyncResp->res,
2107 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002108 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002109}
2110
Ed Tanous1656b292022-05-04 11:33:42 -07002111inline void
2112 handleBusSystemPost(const crow::Request& req,
2113 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2114 const std::string& processName,
2115 const std::string& requestedPath)
2116{
2117 std::vector<std::string> strs;
2118 boost::split(strs, requestedPath, boost::is_any_of("/"));
2119 std::string objectPath;
2120 std::string interfaceName;
2121 std::string methodName;
2122 auto it = strs.begin();
2123 if (it == strs.end())
2124 {
2125 objectPath = "/";
2126 }
2127 while (it != strs.end())
2128 {
2129 // Check if segment contains ".". If it does, it must be an
2130 // interface
2131 if (it->find(".") != std::string::npos)
2132 {
2133 break;
2134 // This check is necessary as the trailing slash gets
2135 // parsed as part of our <path> specifier above, which
2136 // causes the normal trailing backslash redirector to
2137 // fail.
2138 }
2139 if (!it->empty())
2140 {
2141 objectPath += "/" + *it;
2142 }
2143 it++;
2144 }
2145 if (it != strs.end())
2146 {
2147 interfaceName = *it;
2148 it++;
2149
2150 // after interface, we might have a method name
2151 if (it != strs.end())
2152 {
2153 methodName = *it;
2154 it++;
2155 }
2156 }
2157 if (it != strs.end())
2158 {
2159 // if there is more levels past the method name, something
2160 // went wrong, return not found
2161 asyncResp->res.result(boost::beast::http::status::not_found);
2162 return;
2163 }
2164 if (interfaceName.empty())
2165 {
2166 crow::connections::systemBus->async_method_call(
2167 [asyncResp, processName,
2168 objectPath](const boost::system::error_code ec,
2169 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002170 if (ec)
2171 {
2172 BMCWEB_LOG_ERROR
2173 << "Introspect call failed with error: " << ec.message()
2174 << " on process: " << processName << " path: " << objectPath
2175 << "\n";
2176 return;
2177 }
2178 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002179
Ed Tanous002d39b2022-05-31 08:59:27 -07002180 doc.Parse(introspectXml.c_str());
2181 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2182 if (pRoot == nullptr)
2183 {
2184 BMCWEB_LOG_ERROR << "XML document failed to parse "
2185 << processName << " " << objectPath << "\n";
2186 asyncResp->res.jsonValue["status"] = "XML parse error";
2187 asyncResp->res.result(
2188 boost::beast::http::status::internal_server_error);
2189 return;
2190 }
2191
2192 BMCWEB_LOG_DEBUG << introspectXml;
2193 asyncResp->res.jsonValue["status"] = "ok";
2194 asyncResp->res.jsonValue["bus_name"] = processName;
2195 asyncResp->res.jsonValue["object_path"] = objectPath;
2196
2197 nlohmann::json& interfacesArray =
2198 asyncResp->res.jsonValue["interfaces"];
2199 interfacesArray = nlohmann::json::array();
2200 tinyxml2::XMLElement* interface =
2201 pRoot->FirstChildElement("interface");
2202
2203 while (interface != nullptr)
2204 {
2205 const char* ifaceName = interface->Attribute("name");
2206 if (ifaceName != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002207 {
Ed Tanous8a592812022-06-04 09:06:59 -07002208 nlohmann::json::object_t interfaceObj;
2209 interfaceObj["name"] = ifaceName;
2210 interfacesArray.push_back(std::move(interfaceObj));
Ed Tanous1656b292022-05-04 11:33:42 -07002211 }
2212
Ed Tanous002d39b2022-05-31 08:59:27 -07002213 interface = interface->NextSiblingElement("interface");
2214 }
Ed Tanous1656b292022-05-04 11:33:42 -07002215 },
2216 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2217 "Introspect");
2218 }
2219 else if (methodName.empty())
2220 {
2221 crow::connections::systemBus->async_method_call(
2222 [asyncResp, processName, objectPath,
2223 interfaceName](const boost::system::error_code ec,
2224 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002225 if (ec)
2226 {
2227 BMCWEB_LOG_ERROR
2228 << "Introspect call failed with error: " << ec.message()
2229 << " on process: " << processName << " path: " << objectPath
2230 << "\n";
2231 return;
2232 }
2233 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002234
Ed Tanous002d39b2022-05-31 08:59:27 -07002235 doc.Parse(introspectXml.data(), introspectXml.size());
2236 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2237 if (pRoot == nullptr)
2238 {
2239 BMCWEB_LOG_ERROR << "XML document failed to parse "
2240 << processName << " " << objectPath << "\n";
2241 asyncResp->res.result(
2242 boost::beast::http::status::internal_server_error);
2243 return;
2244 }
2245
2246 asyncResp->res.jsonValue["status"] = "ok";
2247 asyncResp->res.jsonValue["bus_name"] = processName;
2248 asyncResp->res.jsonValue["interface"] = interfaceName;
2249 asyncResp->res.jsonValue["object_path"] = objectPath;
2250
2251 nlohmann::json& methodsArray = asyncResp->res.jsonValue["methods"];
2252 methodsArray = nlohmann::json::array();
2253
2254 nlohmann::json& signalsArray = asyncResp->res.jsonValue["signals"];
2255 signalsArray = nlohmann::json::array();
2256
2257 nlohmann::json& propertiesObj =
2258 asyncResp->res.jsonValue["properties"];
2259 propertiesObj = nlohmann::json::object();
2260
2261 // if we know we're the only call, build the
2262 // json directly
2263 tinyxml2::XMLElement* interface =
2264 pRoot->FirstChildElement("interface");
2265 while (interface != nullptr)
2266 {
2267 const char* ifaceName = interface->Attribute("name");
2268
2269 if (ifaceName != nullptr && ifaceName == interfaceName)
Ed Tanous1656b292022-05-04 11:33:42 -07002270 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002271 break;
Ed Tanous1656b292022-05-04 11:33:42 -07002272 }
Ed Tanous14766872022-03-15 10:44:42 -07002273
Ed Tanous002d39b2022-05-31 08:59:27 -07002274 interface = interface->NextSiblingElement("interface");
2275 }
2276 if (interface == nullptr)
2277 {
2278 // if we got to the end of the list and
2279 // never found a match, throw 404
2280 asyncResp->res.result(boost::beast::http::status::not_found);
2281 return;
2282 }
Ed Tanous1656b292022-05-04 11:33:42 -07002283
Ed Tanous002d39b2022-05-31 08:59:27 -07002284 tinyxml2::XMLElement* methods =
2285 interface->FirstChildElement("method");
2286 while (methods != nullptr)
2287 {
2288 nlohmann::json argsArray = nlohmann::json::array();
2289 tinyxml2::XMLElement* arg = methods->FirstChildElement("arg");
2290 while (arg != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002291 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002292 nlohmann::json thisArg;
2293 for (const char* fieldName : std::array<const char*, 3>{
2294 "name", "direction", "type"})
Ed Tanous1656b292022-05-04 11:33:42 -07002295 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002296 const char* fieldValue = arg->Attribute(fieldName);
2297 if (fieldValue != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002298 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002299 thisArg[fieldName] = fieldValue;
2300 }
2301 }
2302 argsArray.push_back(std::move(thisArg));
2303 arg = arg->NextSiblingElement("arg");
2304 }
2305
2306 const char* name = methods->Attribute("name");
2307 if (name != nullptr)
2308 {
2309 std::string uri;
2310 uri.reserve(14 + processName.size() + objectPath.size() +
2311 interfaceName.size() + strlen(name));
2312 uri += "/bus/system/";
2313 uri += processName;
2314 uri += objectPath;
2315 uri += "/";
2316 uri += interfaceName;
2317 uri += "/";
2318 uri += name;
2319
2320 nlohmann::json::object_t object;
2321 object["name"] = name;
2322 object["uri"] = std::move(uri);
2323 object["args"] = argsArray;
2324
2325 methodsArray.push_back(std::move(object));
2326 }
2327 methods = methods->NextSiblingElement("method");
2328 }
2329 tinyxml2::XMLElement* signals =
2330 interface->FirstChildElement("signal");
2331 while (signals != nullptr)
2332 {
2333 nlohmann::json argsArray = nlohmann::json::array();
2334
2335 tinyxml2::XMLElement* arg = signals->FirstChildElement("arg");
2336 while (arg != nullptr)
2337 {
2338 const char* name = arg->Attribute("name");
2339 const char* type = arg->Attribute("type");
2340 if (name != nullptr && type != nullptr)
2341 {
2342 argsArray.push_back({
2343 {"name", name},
2344 {"type", type},
2345 });
2346 }
2347 arg = arg->NextSiblingElement("arg");
2348 }
2349 const char* name = signals->Attribute("name");
2350 if (name != nullptr)
2351 {
2352 nlohmann::json::object_t object;
2353 object["name"] = name;
2354 object["args"] = argsArray;
2355 signalsArray.push_back(std::move(object));
2356 }
2357
2358 signals = signals->NextSiblingElement("signal");
2359 }
2360
2361 tinyxml2::XMLElement* property =
2362 interface->FirstChildElement("property");
2363 while (property != nullptr)
2364 {
2365 const char* name = property->Attribute("name");
2366 const char* type = property->Attribute("type");
2367 if (type != nullptr && name != nullptr)
2368 {
2369 sdbusplus::message::message m =
2370 crow::connections::systemBus->new_method_call(
2371 processName.c_str(), objectPath.c_str(),
2372 "org.freedesktop."
2373 "DBus."
2374 "Properties",
2375 "Get");
2376 m.append(interfaceName, name);
2377 nlohmann::json& propertyItem = propertiesObj[name];
2378 crow::connections::systemBus->async_send(
2379 m, [&propertyItem,
Ed Tanous02cad962022-06-30 16:50:15 -07002380 asyncResp](const boost::system::error_code& e,
Ed Tanous002d39b2022-05-31 08:59:27 -07002381 sdbusplus::message::message& msg) {
2382 if (e)
Ed Tanous1656b292022-05-04 11:33:42 -07002383 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002384 return;
Ed Tanous1656b292022-05-04 11:33:42 -07002385 }
Ed Tanous1656b292022-05-04 11:33:42 -07002386
Ed Tanous002d39b2022-05-31 08:59:27 -07002387 convertDBusToJSON("v", msg, propertyItem);
2388 });
Ed Tanous1656b292022-05-04 11:33:42 -07002389 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002390 property = property->NextSiblingElement("property");
2391 }
Ed Tanous1656b292022-05-04 11:33:42 -07002392 },
2393 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2394 "Introspect");
2395 }
2396 else
2397 {
2398 if (req.method() != boost::beast::http::verb::post)
2399 {
2400 asyncResp->res.result(boost::beast::http::status::not_found);
2401 return;
2402 }
2403
2404 nlohmann::json requestDbusData =
2405 nlohmann::json::parse(req.body, nullptr, false);
2406
2407 if (requestDbusData.is_discarded())
2408 {
2409 asyncResp->res.result(boost::beast::http::status::bad_request);
2410 return;
2411 }
2412 if (!requestDbusData.is_array())
2413 {
2414 asyncResp->res.result(boost::beast::http::status::bad_request);
2415 return;
2416 }
2417 auto transaction =
2418 std::make_shared<InProgressActionData>(asyncResp->res);
2419
2420 transaction->path = objectPath;
2421 transaction->methodName = methodName;
2422 transaction->arguments = std::move(requestDbusData);
2423
2424 findActionOnInterface(transaction, processName);
2425 }
2426}
2427
Ed Tanous23a21a12020-07-25 04:45:05 +00002428inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002429{
2430 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002431 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002432 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002433 [](const crow::Request&,
2434 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002435 nlohmann::json::array_t buses;
2436 nlohmann::json& bus = buses.emplace_back();
2437 bus["name"] = "system";
2438 asyncResp->res.jsonValue["busses"] = std::move(buses);
2439 asyncResp->res.jsonValue["status"] = "ok";
2440 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002441
2442 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002443 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002444 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002445 [](const crow::Request&,
2446 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002447 auto myCallback = [asyncResp](const boost::system::error_code ec,
zhanghch058d1b46d2021-04-01 11:18:24 +08002448 std::vector<std::string>& names) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002449 if (ec)
2450 {
2451 BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
2452 asyncResp->res.result(
2453 boost::beast::http::status::internal_server_error);
2454 }
2455 else
2456 {
2457 std::sort(names.begin(), names.end());
2458 asyncResp->res.jsonValue["status"] = "ok";
2459 auto& objectsSub = asyncResp->res.jsonValue["objects"];
Ed Tanous02cad962022-06-30 16:50:15 -07002460 for (const auto& name : names)
Ed Tanous002d39b2022-05-31 08:59:27 -07002461 {
2462 nlohmann::json::object_t object;
2463 object["name"] = name;
2464 objectsSub.push_back(std::move(object));
2465 }
2466 }
2467 };
2468 crow::connections::systemBus->async_method_call(
2469 std::move(myCallback), "org.freedesktop.DBus", "/",
2470 "org.freedesktop.DBus", "ListNames");
2471 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002472
2473 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002474 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002475 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002476 [](const crow::Request&,
2477 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002478 handleList(asyncResp, "/");
2479 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002480
2481 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002482 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002483 .methods(boost::beast::http::verb::get)(
2484 [](const crow::Request& req,
2485 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002486 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002487 std::string objectPath = "/xyz/" + path;
2488 handleDBusUrl(req, asyncResp, objectPath);
2489 });
zhanghch058d1b46d2021-04-01 11:18:24 +08002490
2491 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002492 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002493 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2494 boost::beast::http::verb::delete_)(
2495 [](const crow::Request& req,
2496 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2497 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002498 std::string objectPath = "/xyz/" + path;
2499 handleDBusUrl(req, asyncResp, objectPath);
2500 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002501
Ed Tanous049a0512018-11-01 13:58:42 -07002502 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002503 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002504 .methods(boost::beast::http::verb::get)(
2505 [](const crow::Request& req,
2506 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2507 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002508 std::string objectPath = "/org/" + path;
2509 handleDBusUrl(req, asyncResp, objectPath);
2510 });
Tanousf00032d2018-11-05 01:18:10 -03002511
2512 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002513 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002514 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2515 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002516 [](const crow::Request& req,
2517 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002518 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002519 std::string objectPath = "/org/" + path;
2520 handleDBusUrl(req, asyncResp, objectPath);
2521 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002522
Ed Tanous1abe55e2018-09-05 08:30:59 -07002523 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002524 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002525 .methods(boost::beast::http::verb::get)(
2526 [](const crow::Request&,
2527 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2528 const std::string& dumpId) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002529 if (!validateFilename(dumpId))
2530 {
2531 asyncResp->res.result(boost::beast::http::status::bad_request);
2532 return;
2533 }
2534 std::filesystem::path loc("/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002535
Ed Tanous002d39b2022-05-31 08:59:27 -07002536 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002537
Ed Tanous002d39b2022-05-31 08:59:27 -07002538 if (!std::filesystem::exists(loc) ||
2539 !std::filesystem::is_directory(loc))
2540 {
2541 BMCWEB_LOG_ERROR << loc.string() << "Not found";
2542 asyncResp->res.result(boost::beast::http::status::not_found);
2543 return;
2544 }
2545 std::filesystem::directory_iterator files(loc);
zhanghch058d1b46d2021-04-01 11:18:24 +08002546
Ed Tanous002d39b2022-05-31 08:59:27 -07002547 for (const auto& file : files)
2548 {
2549 std::ifstream readFile(file.path());
2550 if (!readFile.good())
2551 {
2552 continue;
2553 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002554
Ed Tanous002d39b2022-05-31 08:59:27 -07002555 asyncResp->res.addHeader("Content-Type",
2556 "application/octet-stream");
zhanghch058d1b46d2021-04-01 11:18:24 +08002557
Ed Tanous002d39b2022-05-31 08:59:27 -07002558 // Assuming only one dump file will be present in the dump
2559 // id directory
2560 std::string dumpFileName = file.path().filename().string();
zhanghch058d1b46d2021-04-01 11:18:24 +08002561
Ed Tanous002d39b2022-05-31 08:59:27 -07002562 // Filename should be in alphanumeric, dot and underscore
2563 // Its based on phosphor-debug-collector application
2564 // dumpfile format
2565 std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
2566 if (!std::regex_match(dumpFileName, dumpFileRegex))
2567 {
2568 BMCWEB_LOG_ERROR << "Invalid dump filename " << dumpFileName;
zhanghch058d1b46d2021-04-01 11:18:24 +08002569 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002570 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07002571 }
2572 std::string contentDispositionParam =
2573 "attachment; filename=\"" + dumpFileName + "\"";
2574
2575 asyncResp->res.addHeader("Content-Disposition",
2576 contentDispositionParam);
2577
2578 asyncResp->res.body() = {std::istreambuf_iterator<char>(readFile),
2579 std::istreambuf_iterator<char>()};
2580 return;
2581 }
2582 asyncResp->res.result(boost::beast::http::status::not_found);
2583 return;
2584 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002585
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002586 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002587 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002588
2589 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002590 [](const crow::Request&,
2591 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002592 const std::string& connection) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002593 introspectObjects(connection, "/", asyncResp);
2594 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002595
2596 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002597 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous1656b292022-05-04 11:33:42 -07002598 .methods(boost::beast::http::verb::get,
2599 boost::beast::http::verb::post)(handleBusSystemPost);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002600}
2601} // namespace openbmc_mapper
2602} // namespace crow