blob: 948bc367e53ba798798f29ab1b6772a5098b2827 [file] [log] [blame]
James Feist5b4aa862018-08-16 14:07:01 -07001// Copyright (c) 2018 Intel Corporation
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
Ed Tanousb9b2e0b2018-09-13 13:47:50 -070014
James Feist5b4aa862018-08-16 14:07:01 -070015#pragma once
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080016#include "app.hpp"
17#include "async_resp.hpp"
18#include "dbus_singleton.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +080019#include "dbus_utility.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000020#include "http_request.hpp"
21#include "http_response.hpp"
22#include "logging.hpp"
23#include "routing.hpp"
24
25#include <systemd/sd-bus-protocol.h>
26#include <systemd/sd-bus.h>
Ed Tanous911ac312017-08-15 09:37:42 -070027#include <tinyxml2.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -070028
Ed Tanous11ba3972022-07-11 09:50:41 -070029#include <boost/algorithm/string/classification.hpp>
30#include <boost/algorithm/string/predicate.hpp>
31#include <boost/algorithm/string/split.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000032#include <boost/beast/http/status.hpp>
33#include <boost/beast/http/verb.hpp>
34#include <boost/container/flat_map.hpp>
35#include <boost/container/vector.hpp>
36#include <boost/iterator/iterator_facade.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000037#include <nlohmann/json.hpp>
38#include <sdbusplus/asio/connection.hpp>
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +020039#include <sdbusplus/asio/property.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000040#include <sdbusplus/exception.hpp>
41#include <sdbusplus/message.hpp>
42#include <sdbusplus/message/native_types.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050043
Nan Zhoud5c80ad2022-07-11 01:16:31 +000044#include <algorithm>
45#include <array>
46#include <cerrno>
47#include <cstdint>
48#include <cstring>
James Feist4418c7f2019-04-15 11:09:15 -070049#include <filesystem>
Ed Tanousd4bb9bb2018-05-16 13:36:42 -070050#include <fstream>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000051#include <functional>
52#include <initializer_list>
53#include <iterator>
54#include <limits>
55#include <map>
56#include <memory>
Ramesh Iyyard9207042019-07-05 08:04:42 -050057#include <regex>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000058#include <string>
59#include <string_view>
60#include <type_traits>
Ed Tanousb5a76932020-09-29 16:16:58 -070061#include <utility>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000062#include <variant>
63#include <vector>
64
65// IWYU pragma: no_include <boost/algorithm/string/detail/classification.hpp>
66// IWYU pragma: no_include <boost/system/detail/error_code.hpp>
67// IWYU pragma: no_include <boost/system/detail/error_category.hpp>
68// IWYU pragma: no_include <errno.h>
69// IWYU pragma: no_include <string.h>
70// IWYU pragma: no_include <ext/alloc_traits.h>
71// IWYU pragma: no_include <exception>
72// IWYU pragma: no_include <boost/type_index/type_index_facade.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -070073
Ed Tanous1abe55e2018-09-05 08:30:59 -070074namespace crow
75{
76namespace openbmc_mapper
77{
Ed Tanous23a21a12020-07-25 04:45:05 +000078const constexpr char* notFoundMsg = "404 Not Found";
79const constexpr char* badReqMsg = "400 Bad Request";
80const constexpr char* methodNotAllowedMsg = "405 Method Not Allowed";
81const constexpr char* forbiddenMsg = "403 Forbidden";
82const constexpr char* methodFailedMsg = "500 Method Call Failed";
83const constexpr char* methodOutputFailedMsg = "500 Method Output Error";
84const constexpr char* notFoundDesc =
Matt Spinler2ae60092018-12-06 10:35:36 -060085 "org.freedesktop.DBus.Error.FileNotFound: path or object not found";
Ed Tanous23a21a12020-07-25 04:45:05 +000086const constexpr char* propNotFoundDesc =
87 "The specified property cannot be found";
88const constexpr char* noJsonDesc = "No JSON object could be decoded";
89const constexpr char* methodNotFoundDesc =
90 "The specified method cannot be found";
91const constexpr char* methodNotAllowedDesc = "Method not allowed";
92const constexpr char* forbiddenPropDesc =
93 "The specified property cannot be created";
94const constexpr char* forbiddenResDesc =
95 "The specified resource cannot be created";
Matt Spinler2ae60092018-12-06 10:35:36 -060096
Josh Lehan482c45a2022-03-29 17:10:44 -070097inline bool validateFilename(const std::string& filename)
98{
99 std::regex validFilename(R"(^[\w\- ]+(\.?[\w\- ]*)$)");
100
101 return std::regex_match(filename, validFilename);
102}
103
Ed Tanous23a21a12020-07-25 04:45:05 +0000104inline void setErrorResponse(crow::Response& res,
105 boost::beast::http::status result,
106 const std::string& desc,
107 const std::string_view msg)
Matt Spinler2ae60092018-12-06 10:35:36 -0600108{
109 res.result(result);
Ed Tanous14766872022-03-15 10:44:42 -0700110 res.jsonValue["data"]["description"] = desc;
111 res.jsonValue["message"] = msg;
112 res.jsonValue["status"] = "error";
Matt Spinler2ae60092018-12-06 10:35:36 -0600113}
114
Ed Tanousb5a76932020-09-29 16:16:58 -0700115inline void
116 introspectObjects(const std::string& processName,
117 const std::string& objectPath,
118 const std::shared_ptr<bmcweb::AsyncResp>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700119{
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700120 if (transaction->res.jsonValue.is_null())
121 {
Ed Tanous14766872022-03-15 10:44:42 -0700122 transaction->res.jsonValue["status"] = "ok";
123 transaction->res.jsonValue["bus_name"] = processName;
124 transaction->res.jsonValue["objects"] = nlohmann::json::array();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700125 }
126
Ed Tanous1abe55e2018-09-05 08:30:59 -0700127 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700128 [transaction, processName{std::string(processName)},
129 objectPath{std::string(objectPath)}](
130 const boost::system::error_code ec,
Ed Tanous81ce6092020-12-17 16:54:55 +0000131 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700132 if (ec)
133 {
134 BMCWEB_LOG_ERROR
135 << "Introspect call failed with error: " << ec.message()
136 << " on process: " << processName << " path: " << objectPath
137 << "\n";
138 return;
139 }
140 nlohmann::json::object_t object;
141 object["path"] = objectPath;
Ed Tanous14766872022-03-15 10:44:42 -0700142
Ed Tanous002d39b2022-05-31 08:59:27 -0700143 transaction->res.jsonValue["objects"].push_back(std::move(object));
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700144
Ed Tanous002d39b2022-05-31 08:59:27 -0700145 tinyxml2::XMLDocument doc;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700146
Ed Tanous002d39b2022-05-31 08:59:27 -0700147 doc.Parse(introspectXml.c_str());
148 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
149 if (pRoot == nullptr)
150 {
151 BMCWEB_LOG_ERROR << "XML document failed to parse " << processName
152 << " " << objectPath << "\n";
153 }
154 else
155 {
156 tinyxml2::XMLElement* node = pRoot->FirstChildElement("node");
157 while (node != nullptr)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700158 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700159 const char* childPath = node->Attribute("name");
160 if (childPath != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700161 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700162 std::string newpath;
163 if (objectPath != "/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700164 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700165 newpath += objectPath;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700166 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700167 newpath += std::string("/") + childPath;
168 // introspect the subobjects as well
169 introspectObjects(processName, newpath, transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700170 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700171
172 node = node->NextSiblingElement("node");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700173 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700174 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700175 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700176 processName, objectPath, "org.freedesktop.DBus.Introspectable",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700177 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -0700178}
Ed Tanous64530012018-02-06 17:08:16 -0800179
Ed Tanous23a21a12020-07-25 04:45:05 +0000180inline void getPropertiesForEnumerate(
181 const std::string& objectPath, const std::string& service,
Ed Tanousb5a76932020-09-29 16:16:58 -0700182 const std::string& interface,
183 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600184{
185 BMCWEB_LOG_DEBUG << "getPropertiesForEnumerate " << objectPath << " "
186 << service << " " << interface;
187
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +0200188 sdbusplus::asio::getAllProperties(
189 *crow::connections::systemBus, service, objectPath, interface,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800190 [asyncResp, objectPath, service,
191 interface](const boost::system::error_code ec,
192 const dbus::utility::DBusPropertiesMap& propertiesList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700193 if (ec)
194 {
195 BMCWEB_LOG_ERROR << "GetAll on path " << objectPath << " iface "
196 << interface << " service " << service
197 << " failed with code " << ec;
198 return;
199 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600200
Ed Tanous002d39b2022-05-31 08:59:27 -0700201 nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
202 nlohmann::json& objectJson = dataJson[objectPath];
203 if (objectJson.is_null())
204 {
205 objectJson = nlohmann::json::object();
206 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600207
Ed Tanous002d39b2022-05-31 08:59:27 -0700208 for (const auto& [name, value] : propertiesList)
209 {
210 nlohmann::json& propertyJson = objectJson[name];
211 std::visit(
212 [&propertyJson](auto&& val) {
213 if constexpr (std::is_same_v<std::decay_t<decltype(val)>,
214 sdbusplus::message::unix_fd>)
215 {
216 propertyJson = val.fd;
217 }
218 else
219 {
Ed Tanousd1a64812021-12-13 12:14:05 -0800220
Ed Tanous002d39b2022-05-31 08:59:27 -0700221 propertyJson = val;
222 }
223 },
224 value);
225 }
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +0200226 });
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600227}
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{
George Liu2b731192023-01-11 16:27:13 +0800409 dbus::utility::getDbusObject(
410 transaction->objectPath, {},
411 [transaction](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800412 const dbus::utility::MapperGetObject& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700413 if (ec)
414 {
415 BMCWEB_LOG_ERROR << "GetObject for path " << transaction->objectPath
416 << " failed with code " << ec;
417 return;
418 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600419
Ed Tanous002d39b2022-05-31 08:59:27 -0700420 BMCWEB_LOG_DEBUG << "GetObject for " << transaction->objectPath
421 << " has " << objects.size() << " entries";
422 if (!objects.empty())
423 {
424 transaction->subtree->emplace_back(transaction->objectPath,
425 objects);
426 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600427
Ed Tanous002d39b2022-05-31 08:59:27 -0700428 // Map indicating connection name, and the path where the object
429 // manager exists
430 boost::container::flat_map<std::string, std::string> connections;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600431
Ed Tanous002d39b2022-05-31 08:59:27 -0700432 for (const auto& object : *(transaction->subtree))
433 {
434 for (const auto& connection : object.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600435 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700436 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;
Ed Tanousf8fe53e2022-06-30 15:55:45 -0700444 connections[connection.first] = 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 }
George Liu2b731192023-01-11 16:27:13 +0800470 });
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600471}
Ed Tanous64530012018-02-06 17:08:16 -0800472
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700473// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700474struct InProgressActionData
475{
Ed Tanous4e23a442022-06-06 09:57:26 -0700476 explicit InProgressActionData(crow::Response& resIn) : res(resIn)
Ed Tanous23a21a12020-07-25 04:45:05 +0000477 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700478 ~InProgressActionData()
479 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600480 // Methods could have been called across different owners
481 // and interfaces, where some calls failed and some passed.
482 //
483 // The rules for this are:
484 // * if no method was called - error
485 // * if a method failed and none passed - error
486 // (converse: if at least one method passed - OK)
487 // * for the method output:
488 // * if output processing didn't fail, return the data
489
490 // Only deal with method returns if nothing failed earlier
491 if (res.result() == boost::beast::http::status::ok)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700492 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600493 if (!methodPassed)
494 {
Matt Spinler06b1b632019-06-18 16:09:25 -0500495 if (!methodFailed)
Matt Spinler16caaee2019-01-15 11:40:34 -0600496 {
497 setErrorResponse(res, boost::beast::http::status::not_found,
498 methodNotFoundDesc, notFoundMsg);
499 }
500 }
501 else
502 {
503 if (outputFailed)
504 {
505 setErrorResponse(
506 res, boost::beast::http::status::internal_server_error,
507 "Method output failure", methodOutputFailedMsg);
508 }
509 else
510 {
Ed Tanous14766872022-03-15 10:44:42 -0700511 res.jsonValue["status"] = "ok";
512 res.jsonValue["message"] = "200 OK";
513 res.jsonValue["data"] = methodResponse;
Matt Spinler16caaee2019-01-15 11:40:34 -0600514 }
515 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700516 }
Matt Spinler16caaee2019-01-15 11:40:34 -0600517
Ed Tanous1abe55e2018-09-05 08:30:59 -0700518 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700519 }
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800520 InProgressActionData(const InProgressActionData&) = delete;
521 InProgressActionData(InProgressActionData&&) = delete;
522 InProgressActionData& operator=(const InProgressActionData&) = delete;
523 InProgressActionData& operator=(InProgressActionData&&) = delete;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700524
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500525 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700526 {
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600527 setErrorResponse(res, boost::beast::http::status::bad_request, desc,
528 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700529 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500530 crow::Response& res;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700531 std::string path;
532 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600533 std::string interfaceName;
Matt Spinler16caaee2019-01-15 11:40:34 -0600534 bool methodPassed = false;
535 bool methodFailed = false;
536 bool outputFailed = false;
Matt Spinler39a4e392019-01-15 11:53:13 -0600537 bool convertedToArray = false;
Matt Spinler16caaee2019-01-15 11:40:34 -0600538 nlohmann::json methodResponse;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700539 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700540};
541
Ed Tanous23a21a12020-07-25 04:45:05 +0000542inline std::vector<std::string> dbusArgSplit(const std::string& string)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700543{
544 std::vector<std::string> ret;
545 if (string.empty())
546 {
547 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700548 }
Ed Tanous0f0353b2019-10-24 11:37:51 -0700549 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700550 int containerDepth = 0;
551
552 for (std::string::const_iterator character = string.begin();
553 character != string.end(); character++)
554 {
555 ret.back() += *character;
556 switch (*character)
557 {
558 case ('a'):
559 break;
560 case ('('):
561 case ('{'):
562 containerDepth++;
563 break;
564 case ('}'):
565 case (')'):
566 containerDepth--;
567 if (containerDepth == 0)
568 {
569 if (character + 1 != string.end())
570 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700571 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700572 }
573 }
574 break;
575 default:
576 if (containerDepth == 0)
577 {
578 if (character + 1 != string.end())
579 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700580 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700581 }
582 }
583 break;
584 }
585 }
Matt Spinler4ae611d2019-01-11 15:37:06 -0600586
587 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700588}
589
Ed Tanous81ce6092020-12-17 16:54:55 +0000590inline int convertJsonToDbus(sd_bus_message* m, const std::string& argType,
591 const nlohmann::json& inputJson)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700592{
593 int r = 0;
Ed Tanous71f52d92021-02-19 08:51:17 -0800594 BMCWEB_LOG_DEBUG << "Converting "
595 << inputJson.dump(2, ' ', true,
596 nlohmann::json::error_handler_t::replace)
Ed Tanous81ce6092020-12-17 16:54:55 +0000597 << " to type: " << argType;
598 const std::vector<std::string> argTypes = dbusArgSplit(argType);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700599
Ed Tanous1abe55e2018-09-05 08:30:59 -0700600 // Assume a single object for now.
Ed Tanous81ce6092020-12-17 16:54:55 +0000601 const nlohmann::json* j = &inputJson;
602 nlohmann::json::const_iterator jIt = inputJson.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700603
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500604 for (const std::string& argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700605 {
606 // If we are decoding multiple objects, grab the pointer to the
607 // iterator, and increment it for the next loop
608 if (argTypes.size() > 1)
609 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000610 if (jIt == inputJson.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700611 {
612 return -2;
613 }
614 j = &*jIt;
615 jIt++;
616 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500617 const int64_t* intValue = j->get_ptr<const int64_t*>();
618 const std::string* stringValue = j->get_ptr<const std::string*>();
619 const double* doubleValue = j->get_ptr<const double*>();
620 const bool* b = j->get_ptr<const bool*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700621 int64_t v = 0;
622 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700623
Ed Tanous1abe55e2018-09-05 08:30:59 -0700624 // Do some basic type conversions that make sense. uint can be
625 // converted to int. int and uint can be converted to double
Ed Tanous66664f22019-10-11 13:05:49 -0700626 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700627 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500628 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700629 if (uintValue != nullptr)
630 {
631 v = static_cast<int64_t>(*uintValue);
632 intValue = &v;
633 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700634 }
Ed Tanous66664f22019-10-11 13:05:49 -0700635 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700636 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500637 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700638 if (uintValue != nullptr)
639 {
640 d = static_cast<double>(*uintValue);
641 doubleValue = &d;
642 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700643 }
Ed Tanous66664f22019-10-11 13:05:49 -0700644 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700645 {
Ed Tanous66664f22019-10-11 13:05:49 -0700646 if (intValue != nullptr)
647 {
648 d = static_cast<double>(*intValue);
649 doubleValue = &d;
650 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700651 }
652
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700653 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700654 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700655 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700656 {
657 return -1;
658 }
Ed Tanous271584a2019-07-09 16:24:22 -0700659 r = sd_bus_message_append_basic(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500660 m, argCode[0], static_cast<const void*>(stringValue->data()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700661 if (r < 0)
662 {
663 return r;
664 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700665 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700666 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700667 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700668 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700669 {
670 return -1;
671 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500672 if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
673 (*intValue > std::numeric_limits<int32_t>::max()))
674 {
675 return -ERANGE;
676 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700677 int32_t i = static_cast<int32_t>(*intValue);
678 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700679 if (r < 0)
680 {
681 return r;
682 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700683 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700684 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700685 {
686 // lots of ways bool could be represented here. Try them all
Ed Tanouse662eae2022-01-25 10:39:19 -0800687 int boolInt = 0;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700688 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700689 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500690 if (*intValue == 1)
691 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800692 boolInt = 1;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500693 }
694 else if (*intValue == 0)
695 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800696 boolInt = 0;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500697 }
698 else
699 {
700 return -ERANGE;
701 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700702 }
703 else if (b != nullptr)
704 {
Matt Spinlera2f02632019-01-18 10:15:35 -0600705 boolInt = *b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700706 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700707 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700708 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700709 boolInt = boost::istarts_with(*stringValue, "t") ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700710 }
711 else
712 {
713 return -1;
714 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700715 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700716 if (r < 0)
717 {
718 return r;
719 }
720 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700721 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700722 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700723 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700724 {
725 return -1;
726 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500727 if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
728 (*intValue > std::numeric_limits<int16_t>::max()))
729 {
730 return -ERANGE;
731 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700732 int16_t n = static_cast<int16_t>(*intValue);
733 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700734 if (r < 0)
735 {
736 return r;
737 }
738 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700739 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700740 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700741 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700742 {
743 return -1;
744 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700745 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700746 if (r < 0)
747 {
748 return r;
749 }
750 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700751 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700752 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500753 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700754 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700755 {
756 return -1;
757 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000758 if (*uintValue > std::numeric_limits<uint8_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500759 {
760 return -ERANGE;
761 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700762 uint8_t y = static_cast<uint8_t>(*uintValue);
763 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700764 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700765 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700766 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500767 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700768 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700769 {
770 return -1;
771 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000772 if (*uintValue > std::numeric_limits<uint16_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500773 {
774 return -ERANGE;
775 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700776 uint16_t q = static_cast<uint16_t>(*uintValue);
777 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700778 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700779 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700780 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500781 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700782 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700783 {
784 return -1;
785 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000786 if (*uintValue > std::numeric_limits<uint32_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500787 {
788 return -ERANGE;
789 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700790 uint32_t u = static_cast<uint32_t>(*uintValue);
791 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700792 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700793 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700794 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500795 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700796 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700797 {
798 return -1;
799 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700800 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700801 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700802 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700803 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500804 if (doubleValue == nullptr)
805 {
806 return -1;
807 }
808 if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
809 (*doubleValue > std::numeric_limits<double>::max()))
810 {
811 return -ERANGE;
812 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700813 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700814 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700815 else if (argCode.starts_with("a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700816 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700817 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700818 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700819 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700820 if (r < 0)
821 {
822 return r;
823 }
824
Ed Tanous0dfeda62019-10-24 11:21:38 -0700825 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700826 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700827 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700828 if (r < 0)
829 {
830 return r;
831 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700832 }
833 sd_bus_message_close_container(m);
834 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700835 else if (argCode.starts_with("v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700836 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700837 std::string containedType = argCode.substr(1);
838 BMCWEB_LOG_DEBUG << "variant type: " << argCode
839 << " appending variant of type: " << containedType;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700840 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700841 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700842 if (r < 0)
843 {
844 return r;
845 }
846
Ed Tanous81ce6092020-12-17 16:54:55 +0000847 r = convertJsonToDbus(m, containedType, inputJson);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700848 if (r < 0)
849 {
850 return r;
851 }
852
853 r = sd_bus_message_close_container(m);
854 if (r < 0)
855 {
856 return r;
857 }
858 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700859 else if (argCode.starts_with("(") && argCode.ends_with(")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700860 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700861 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700862 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700863 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800864 if (r < 0)
865 {
866 return r;
867 }
868
Ed Tanous1abe55e2018-09-05 08:30:59 -0700869 nlohmann::json::const_iterator it = j->begin();
Ed Tanous81ce6092020-12-17 16:54:55 +0000870 for (const std::string& argCode2 : dbusArgSplit(argType))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700871 {
872 if (it == j->end())
873 {
874 return -1;
875 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000876 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700877 if (r < 0)
878 {
879 return r;
880 }
881 it++;
882 }
883 r = sd_bus_message_close_container(m);
884 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700885 else if (argCode.starts_with("{") && argCode.ends_with("}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700886 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700887 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700888 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700889 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800890 if (r < 0)
891 {
892 return r;
893 }
894
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700895 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700896 if (codes.size() != 2)
897 {
898 return -1;
899 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700900 const std::string& keyType = codes[0];
901 const std::string& valueType = codes[1];
Ed Tanous3174e4d2020-10-07 11:41:22 -0700902 for (const auto& it : j->items())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700903 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700904 r = convertJsonToDbus(m, keyType, it.key());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700905 if (r < 0)
906 {
907 return r;
908 }
909
Ed Tanous2c70f802020-09-28 14:29:23 -0700910 r = convertJsonToDbus(m, valueType, it.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700911 if (r < 0)
912 {
913 return r;
914 }
915 }
916 r = sd_bus_message_close_container(m);
917 }
918 else
919 {
920 return -2;
921 }
922 if (r < 0)
923 {
924 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700925 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700926
Ed Tanous1abe55e2018-09-05 08:30:59 -0700927 if (argTypes.size() > 1)
928 {
929 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700930 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700931 }
Matt Spinler127ea542019-01-14 11:04:28 -0600932
933 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700934}
935
Matt Spinlerd22a7132019-01-14 12:14:30 -0600936template <typename T>
Patrick Williams59d494e2022-07-22 19:26:55 -0500937int readMessageItem(const std::string& typeCode, sdbusplus::message_t& m,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500938 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600939{
940 T value;
941
942 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
943 if (r < 0)
944 {
945 BMCWEB_LOG_ERROR << "sd_bus_message_read_basic on type " << typeCode
946 << " failed!";
947 return r;
948 }
949
950 data = value;
951 return 0;
952}
953
Patrick Williams59d494e2022-07-22 19:26:55 -0500954int convertDBusToJSON(const std::string& returnType, sdbusplus::message_t& m,
955 nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600956
Ed Tanous23a21a12020-07-25 04:45:05 +0000957inline int readDictEntryFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -0500958 sdbusplus::message_t& m,
Ed Tanous23a21a12020-07-25 04:45:05 +0000959 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600960{
961 std::vector<std::string> types = dbusArgSplit(typeCode);
962 if (types.size() != 2)
963 {
964 BMCWEB_LOG_ERROR << "wrong number contained types in dictionary: "
965 << types.size();
966 return -1;
967 }
968
969 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
970 typeCode.c_str());
971 if (r < 0)
972 {
973 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container with rc " << r;
974 return r;
975 }
976
977 nlohmann::json key;
978 r = convertDBusToJSON(types[0], m, key);
979 if (r < 0)
980 {
981 return r;
982 }
983
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500984 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -0600985 if (keyPtr == nullptr)
986 {
987 // json doesn't support non-string keys. If we hit this condition,
988 // convert the result to a string so we can proceed
Ed Tanous71f52d92021-02-19 08:51:17 -0800989 key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500990 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -0700991 // in theory this can't fail now, but lets be paranoid about it
992 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -0600993 if (keyPtr == nullptr)
994 {
995 return -1;
996 }
997 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500998 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -0600999
1000 r = convertDBusToJSON(types[1], m, value);
1001 if (r < 0)
1002 {
1003 return r;
1004 }
1005
1006 r = sd_bus_message_exit_container(m.get());
1007 if (r < 0)
1008 {
1009 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1010 return r;
1011 }
1012
1013 return 0;
1014}
1015
Ed Tanous23a21a12020-07-25 04:45:05 +00001016inline int readArrayFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001017 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -06001018{
1019 if (typeCode.size() < 2)
1020 {
1021 BMCWEB_LOG_ERROR << "Type code " << typeCode
1022 << " too small for an array";
1023 return -1;
1024 }
1025
1026 std::string containedType = typeCode.substr(1);
1027
1028 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
1029 containedType.c_str());
1030 if (r < 0)
1031 {
1032 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1033 << r;
1034 return r;
1035 }
1036
Ed Tanous11ba3972022-07-11 09:50:41 -07001037 bool dict = containedType.starts_with("{") && containedType.ends_with("}");
Matt Spinler6df8f992019-01-14 12:47:47 -06001038
1039 if (dict)
1040 {
1041 // Remove the { }
1042 containedType = containedType.substr(1, containedType.size() - 2);
1043 data = nlohmann::json::object();
1044 }
1045 else
1046 {
1047 data = nlohmann::json::array();
1048 }
1049
1050 while (true)
1051 {
Ed Tanouse662eae2022-01-25 10:39:19 -08001052 r = sd_bus_message_at_end(m.get(), 0);
Matt Spinler6df8f992019-01-14 12:47:47 -06001053 if (r < 0)
1054 {
1055 BMCWEB_LOG_ERROR << "sd_bus_message_at_end failed";
1056 return r;
1057 }
1058
1059 if (r > 0)
1060 {
1061 break;
1062 }
1063
1064 // Dictionaries are only ever seen in an array
1065 if (dict)
1066 {
1067 r = readDictEntryFromMessage(containedType, m, data);
1068 if (r < 0)
1069 {
1070 return r;
1071 }
1072 }
1073 else
1074 {
1075 data.push_back(nlohmann::json());
1076
1077 r = convertDBusToJSON(containedType, m, data.back());
1078 if (r < 0)
1079 {
1080 return r;
1081 }
1082 }
1083 }
1084
1085 r = sd_bus_message_exit_container(m.get());
1086 if (r < 0)
1087 {
1088 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1089 return r;
1090 }
1091
1092 return 0;
1093}
1094
Ed Tanous23a21a12020-07-25 04:45:05 +00001095inline int readStructFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001096 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001097{
1098 if (typeCode.size() < 3)
1099 {
1100 BMCWEB_LOG_ERROR << "Type code " << typeCode
1101 << " too small for a struct";
1102 return -1;
1103 }
1104
1105 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1106 std::vector<std::string> types = dbusArgSplit(containedTypes);
1107
1108 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1109 containedTypes.c_str());
1110 if (r < 0)
1111 {
1112 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1113 << r;
1114 return r;
1115 }
1116
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001117 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001118 {
1119 data.push_back(nlohmann::json());
1120 r = convertDBusToJSON(type, m, data.back());
1121 if (r < 0)
1122 {
1123 return r;
1124 }
1125 }
1126
1127 r = sd_bus_message_exit_container(m.get());
1128 if (r < 0)
1129 {
1130 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1131 return r;
1132 }
1133 return 0;
1134}
1135
Patrick Williams59d494e2022-07-22 19:26:55 -05001136inline int readVariantFromMessage(sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001137{
Ed Tanous543f4402022-01-06 13:12:53 -08001138 const char* containerType = nullptr;
Ed Tanous99131cd2019-10-24 11:12:47 -07001139 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001140 if (r < 0)
1141 {
1142 BMCWEB_LOG_ERROR << "sd_bus_message_peek_type failed";
1143 return r;
1144 }
1145
1146 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1147 containerType);
1148 if (r < 0)
1149 {
1150 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1151 << r;
1152 return r;
1153 }
1154
1155 r = convertDBusToJSON(containerType, m, data);
1156 if (r < 0)
1157 {
1158 return r;
1159 }
1160
1161 r = sd_bus_message_exit_container(m.get());
1162 if (r < 0)
1163 {
1164 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed";
1165 return r;
1166 }
1167
1168 return 0;
1169}
1170
Ed Tanous23a21a12020-07-25 04:45:05 +00001171inline int convertDBusToJSON(const std::string& returnType,
Patrick Williams59d494e2022-07-22 19:26:55 -05001172 sdbusplus::message_t& m, nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001173{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001174 int r = 0;
1175 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1176
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001177 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001178 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001179 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001180 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001181 {
1182 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001183 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001184 }
1185
Ed Tanousd4d25792020-09-29 15:15:03 -07001186 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001187 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001188 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001189 if (r < 0)
1190 {
1191 return r;
1192 }
1193 }
1194 else if (typeCode == "b")
1195 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001196 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001197 if (r < 0)
1198 {
1199 return r;
1200 }
1201
Matt Spinlerf39420c2019-01-30 12:57:18 -06001202 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001203 }
1204 else if (typeCode == "u")
1205 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001206 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001207 if (r < 0)
1208 {
1209 return r;
1210 }
1211 }
1212 else if (typeCode == "i")
1213 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001214 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001215 if (r < 0)
1216 {
1217 return r;
1218 }
1219 }
1220 else if (typeCode == "x")
1221 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001222 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001223 if (r < 0)
1224 {
1225 return r;
1226 }
1227 }
1228 else if (typeCode == "t")
1229 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001230 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001231 if (r < 0)
1232 {
1233 return r;
1234 }
1235 }
1236 else if (typeCode == "n")
1237 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001238 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001239 if (r < 0)
1240 {
1241 return r;
1242 }
1243 }
1244 else if (typeCode == "q")
1245 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001246 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001247 if (r < 0)
1248 {
1249 return r;
1250 }
1251 }
1252 else if (typeCode == "y")
1253 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001254 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001255 if (r < 0)
1256 {
1257 return r;
1258 }
1259 }
1260 else if (typeCode == "d")
1261 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001262 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001263 if (r < 0)
1264 {
1265 return r;
1266 }
1267 }
1268 else if (typeCode == "h")
1269 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001270 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001271 if (r < 0)
1272 {
1273 return r;
1274 }
1275 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001276 else if (typeCode.starts_with("a"))
Matt Spinler6df8f992019-01-14 12:47:47 -06001277 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001278 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001279 if (r < 0)
1280 {
1281 return r;
1282 }
1283 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001284 else if (typeCode.starts_with("(") && typeCode.ends_with(")"))
Matt Spinler75c6c672019-01-14 13:01:46 -06001285 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001286 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001287 if (r < 0)
1288 {
1289 return r;
1290 }
1291 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001292 else if (typeCode.starts_with("v"))
Matt Spinler89c19702019-01-14 13:13:00 -06001293 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001294 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001295 if (r < 0)
1296 {
1297 return r;
1298 }
1299 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001300 else
1301 {
Matt Spinlerd22a7132019-01-14 12:14:30 -06001302 BMCWEB_LOG_ERROR << "Invalid D-Bus signature type " << typeCode;
1303 return -2;
1304 }
1305 }
1306
Matt Spinler16caaee2019-01-15 11:40:34 -06001307 return 0;
1308}
1309
Ed Tanousb5a76932020-09-29 16:16:58 -07001310inline void handleMethodResponse(
1311 const std::shared_ptr<InProgressActionData>& transaction,
Patrick Williams59d494e2022-07-22 19:26:55 -05001312 sdbusplus::message_t& m, const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001313{
Matt Spinler39a4e392019-01-15 11:53:13 -06001314 nlohmann::json data;
1315
1316 int r = convertDBusToJSON(returnType, m, data);
1317 if (r < 0)
1318 {
1319 transaction->outputFailed = true;
1320 return;
1321 }
1322
1323 if (data.is_null())
1324 {
1325 return;
1326 }
1327
1328 if (transaction->methodResponse.is_null())
1329 {
1330 transaction->methodResponse = std::move(data);
1331 return;
1332 }
1333
1334 // If they're both dictionaries or arrays, merge into one.
1335 // Otherwise, make the results an array with every result
1336 // an entry. Could also just fail in that case, but it
1337 // seems better to get the data back somehow.
1338
1339 if (transaction->methodResponse.is_object() && data.is_object())
1340 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001341 for (const auto& obj : data.items())
Matt Spinler39a4e392019-01-15 11:53:13 -06001342 {
1343 // Note: Will overwrite the data for a duplicate key
1344 transaction->methodResponse.emplace(obj.key(),
1345 std::move(obj.value()));
1346 }
1347 return;
1348 }
1349
1350 if (transaction->methodResponse.is_array() && data.is_array())
1351 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001352 for (auto& obj : data)
Matt Spinler39a4e392019-01-15 11:53:13 -06001353 {
1354 transaction->methodResponse.push_back(std::move(obj));
1355 }
1356 return;
1357 }
1358
1359 if (!transaction->convertedToArray)
1360 {
1361 // They are different types. May as well turn them into an array
1362 nlohmann::json j = std::move(transaction->methodResponse);
1363 transaction->methodResponse = nlohmann::json::array();
1364 transaction->methodResponse.push_back(std::move(j));
1365 transaction->methodResponse.push_back(std::move(data));
1366 transaction->convertedToArray = true;
1367 }
1368 else
1369 {
1370 transaction->methodResponse.push_back(std::move(data));
1371 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001372}
1373
Ed Tanousb5a76932020-09-29 16:16:58 -07001374inline void findActionOnInterface(
1375 const std::shared_ptr<InProgressActionData>& transaction,
1376 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001377{
1378 BMCWEB_LOG_DEBUG << "findActionOnInterface for connection "
1379 << connectionName;
1380 crow::connections::systemBus->async_method_call(
1381 [transaction, connectionName{std::string(connectionName)}](
1382 const boost::system::error_code ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001383 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001384 BMCWEB_LOG_DEBUG << "got xml:\n " << introspectXml;
1385 if (ec)
1386 {
1387 BMCWEB_LOG_ERROR
1388 << "Introspect call failed with error: " << ec.message()
1389 << " on process: " << connectionName << "\n";
1390 return;
1391 }
1392 tinyxml2::XMLDocument doc;
Matt Spinler318bd892019-01-15 09:59:20 -06001393
Ed Tanous002d39b2022-05-31 08:59:27 -07001394 doc.Parse(introspectXml.data(), introspectXml.size());
1395 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1396 if (pRoot == nullptr)
1397 {
1398 BMCWEB_LOG_ERROR << "XML document failed to parse "
1399 << connectionName << "\n";
1400 return;
1401 }
1402 tinyxml2::XMLElement* interfaceNode =
1403 pRoot->FirstChildElement("interface");
1404 while (interfaceNode != nullptr)
1405 {
1406 const char* thisInterfaceName = interfaceNode->Attribute("name");
1407 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001408 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001409 if (!transaction->interfaceName.empty() &&
1410 (transaction->interfaceName != thisInterfaceName))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001411 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001412 interfaceNode =
1413 interfaceNode->NextSiblingElement("interface");
1414 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001415 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001416
1417 tinyxml2::XMLElement* methodNode =
1418 interfaceNode->FirstChildElement("method");
1419 while (methodNode != nullptr)
1420 {
1421 const char* thisMethodName = methodNode->Attribute("name");
1422 BMCWEB_LOG_DEBUG << "Found method: " << thisMethodName;
1423 if (thisMethodName != nullptr &&
1424 thisMethodName == transaction->methodName)
1425 {
1426 BMCWEB_LOG_DEBUG << "Found method named "
1427 << thisMethodName << " on interface "
1428 << thisInterfaceName;
Patrick Williams59d494e2022-07-22 19:26:55 -05001429 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001430 crow::connections::systemBus->new_method_call(
1431 connectionName.c_str(),
1432 transaction->path.c_str(), thisInterfaceName,
1433 transaction->methodName.c_str());
1434
1435 tinyxml2::XMLElement* argumentNode =
1436 methodNode->FirstChildElement("arg");
1437
1438 std::string returnType;
1439
1440 // Find the output type
1441 while (argumentNode != nullptr)
1442 {
1443 const char* argDirection =
1444 argumentNode->Attribute("direction");
1445 const char* argType =
1446 argumentNode->Attribute("type");
1447 if (argDirection != nullptr && argType != nullptr &&
1448 std::string(argDirection) == "out")
1449 {
1450 returnType = argType;
1451 break;
1452 }
1453 argumentNode =
1454 argumentNode->NextSiblingElement("arg");
1455 }
1456
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001457 auto argIt = transaction->arguments.begin();
Ed Tanous002d39b2022-05-31 08:59:27 -07001458
1459 argumentNode = methodNode->FirstChildElement("arg");
1460
1461 while (argumentNode != nullptr)
1462 {
1463 const char* argDirection =
1464 argumentNode->Attribute("direction");
1465 const char* argType =
1466 argumentNode->Attribute("type");
1467 if (argDirection != nullptr && argType != nullptr &&
1468 std::string(argDirection) == "in")
1469 {
1470 if (argIt == transaction->arguments.end())
1471 {
1472 transaction->setErrorStatus(
1473 "Invalid method args");
1474 return;
1475 }
1476 if (convertJsonToDbus(m.get(),
1477 std::string(argType),
1478 *argIt) < 0)
1479 {
1480 transaction->setErrorStatus(
1481 "Invalid method arg type");
1482 return;
1483 }
1484
1485 argIt++;
1486 }
1487 argumentNode =
1488 argumentNode->NextSiblingElement("arg");
1489 }
1490
1491 crow::connections::systemBus->async_send(
1492 m,
1493 [transaction,
1494 returnType](boost::system::error_code ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05001495 sdbusplus::message_t& m2) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001496 if (ec2)
1497 {
1498 transaction->methodFailed = true;
1499 const sd_bus_error* e = m2.get_error();
1500
1501 if (e != nullptr)
1502 {
1503 setErrorResponse(
1504 transaction->res,
1505 boost::beast::http::status::bad_request,
1506 e->name, e->message);
1507 }
1508 else
1509 {
1510 setErrorResponse(
1511 transaction->res,
1512 boost::beast::http::status::bad_request,
1513 "Method call failed", methodFailedMsg);
1514 }
1515 return;
1516 }
1517 transaction->methodPassed = true;
1518
1519 handleMethodResponse(transaction, m2, returnType);
1520 });
1521 break;
1522 }
1523 methodNode = methodNode->NextSiblingElement("method");
1524 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001525 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001526 interfaceNode = interfaceNode->NextSiblingElement("interface");
1527 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001528 },
1529 connectionName, transaction->path,
1530 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001531}
1532
zhanghch058d1b46d2021-04-01 11:18:24 +08001533inline void handleAction(const crow::Request& req,
1534 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001535 const std::string& objectPath,
1536 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001537{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001538 BMCWEB_LOG_DEBUG << "handleAction on path: " << objectPath << " and method "
1539 << methodName;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001540 nlohmann::json requestDbusData =
1541 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001542
Ed Tanous1abe55e2018-09-05 08:30:59 -07001543 if (requestDbusData.is_discarded())
1544 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001545 setErrorResponse(asyncResp->res,
1546 boost::beast::http::status::bad_request, noJsonDesc,
1547 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001548 return;
1549 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001550 nlohmann::json::iterator data = requestDbusData.find("data");
1551 if (data == requestDbusData.end())
1552 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001553 setErrorResponse(asyncResp->res,
1554 boost::beast::http::status::bad_request, noJsonDesc,
1555 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001556 return;
1557 }
1558
1559 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001560 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001561 setErrorResponse(asyncResp->res,
1562 boost::beast::http::status::bad_request, noJsonDesc,
1563 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001564 return;
1565 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001566 auto transaction = std::make_shared<InProgressActionData>(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001567
1568 transaction->path = objectPath;
1569 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001570 transaction->arguments = std::move(*data);
George Liu2b731192023-01-11 16:27:13 +08001571 dbus::utility::getDbusObject(
1572 objectPath, {},
Ed Tanous1abe55e2018-09-05 08:30:59 -07001573 [transaction](
George Liu2b731192023-01-11 16:27:13 +08001574 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001575 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1576 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001577 if (ec || interfaceNames.empty())
1578 {
1579 BMCWEB_LOG_ERROR << "Can't find object";
1580 setErrorResponse(transaction->res,
1581 boost::beast::http::status::not_found,
1582 notFoundDesc, notFoundMsg);
1583 return;
1584 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001585
Ed Tanous002d39b2022-05-31 08:59:27 -07001586 BMCWEB_LOG_DEBUG << "GetObject returned " << interfaceNames.size()
1587 << " object(s)";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001588
Ed Tanous002d39b2022-05-31 08:59:27 -07001589 for (const std::pair<std::string, std::vector<std::string>>& object :
1590 interfaceNames)
1591 {
1592 findActionOnInterface(transaction, object.first);
1593 }
George Liu2b731192023-01-11 16:27:13 +08001594 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001595}
1596
zhanghch058d1b46d2021-04-01 11:18:24 +08001597inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1598 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001599{
1600 BMCWEB_LOG_DEBUG << "handleDelete on path: " << objectPath;
1601
George Liu2b731192023-01-11 16:27:13 +08001602 dbus::utility::getDbusObject(
1603 objectPath, {},
zhanghch058d1b46d2021-04-01 11:18:24 +08001604 [asyncResp, objectPath](
George Liu2b731192023-01-11 16:27:13 +08001605 const boost::system::error_code& ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001606 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1607 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001608 if (ec || interfaceNames.empty())
1609 {
1610 BMCWEB_LOG_ERROR << "Can't find object";
1611 setErrorResponse(asyncResp->res,
1612 boost::beast::http::status::method_not_allowed,
1613 methodNotAllowedDesc, methodNotAllowedMsg);
1614 return;
1615 }
Matt Spinlerde818812018-12-11 16:39:20 -06001616
Ed Tanous002d39b2022-05-31 08:59:27 -07001617 auto transaction =
1618 std::make_shared<InProgressActionData>(asyncResp->res);
1619 transaction->path = objectPath;
1620 transaction->methodName = "Delete";
1621 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
Matt Spinlerde818812018-12-11 16:39:20 -06001622
Ed Tanous002d39b2022-05-31 08:59:27 -07001623 for (const std::pair<std::string, std::vector<std::string>>& object :
1624 interfaceNames)
1625 {
1626 findActionOnInterface(transaction, object.first);
1627 }
George Liu2b731192023-01-11 16:27:13 +08001628 });
Matt Spinlerde818812018-12-11 16:39:20 -06001629}
1630
zhanghch058d1b46d2021-04-01 11:18:24 +08001631inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1632 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001633{
George Liu7a1dbc42022-12-07 16:03:22 +08001634 dbus::utility::getSubTreePaths(
1635 objectPath, depth, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001636 [asyncResp](
George Liu7a1dbc42022-12-07 16:03:22 +08001637 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001638 const dbus::utility::MapperGetSubTreePathsResponse& objectPaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001639 if (ec)
1640 {
1641 setErrorResponse(asyncResp->res,
1642 boost::beast::http::status::not_found,
1643 notFoundDesc, notFoundMsg);
1644 }
1645 else
1646 {
1647 asyncResp->res.jsonValue["status"] = "ok";
1648 asyncResp->res.jsonValue["message"] = "200 OK";
1649 asyncResp->res.jsonValue["data"] = objectPaths;
1650 }
George Liu7a1dbc42022-12-07 16:03:22 +08001651 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001652}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001653
zhanghch058d1b46d2021-04-01 11:18:24 +08001654inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1655 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001656{
Ed Tanous049a0512018-11-01 13:58:42 -07001657 BMCWEB_LOG_DEBUG << "Doing enumerate on " << objectPath;
Ed Tanous049a0512018-11-01 13:58:42 -07001658
Ed Tanous14766872022-03-15 10:44:42 -07001659 asyncResp->res.jsonValue["message"] = "200 OK";
1660 asyncResp->res.jsonValue["status"] = "ok";
1661 asyncResp->res.jsonValue["data"] = nlohmann::json::object();
Ed Tanous049a0512018-11-01 13:58:42 -07001662
Ed Tanous1abe55e2018-09-05 08:30:59 -07001663 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001664 [objectPath, asyncResp](
1665 const boost::system::error_code ec,
1666 const dbus::utility::MapperGetSubTreeResponse& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001667 auto transaction =
1668 std::make_shared<InProgressEnumerateData>(objectPath, asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001669
Ed Tanous002d39b2022-05-31 08:59:27 -07001670 transaction->subtree =
1671 std::make_shared<dbus::utility::MapperGetSubTreeResponse>(
1672 objectNames);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001673
Ed Tanous002d39b2022-05-31 08:59:27 -07001674 if (ec)
1675 {
1676 BMCWEB_LOG_ERROR << "GetSubTree failed on "
1677 << transaction->objectPath;
1678 setErrorResponse(transaction->asyncResp->res,
1679 boost::beast::http::status::not_found,
1680 notFoundDesc, notFoundMsg);
1681 return;
1682 }
Ed Tanous64530012018-02-06 17:08:16 -08001683
Ed Tanous002d39b2022-05-31 08:59:27 -07001684 // Add the data for the path passed in to the results
1685 // as if GetSubTree returned it, and continue on enumerating
1686 getObjectAndEnumerate(transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001687 },
1688 "xyz.openbmc_project.ObjectMapper",
1689 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -07001690 "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath, 0,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001691 std::array<const char*, 0>());
Ed Tanous64530012018-02-06 17:08:16 -08001692}
Ed Tanous911ac312017-08-15 09:37:42 -07001693
zhanghch058d1b46d2021-04-01 11:18:24 +08001694inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1695 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001696{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001697 BMCWEB_LOG_DEBUG << "handleGet: " << objectPath << " prop:" << destProperty;
1698 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001699 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001700
Ed Tanous1abe55e2018-09-05 08:30:59 -07001701 std::shared_ptr<std::string> path =
1702 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001703
George Liu2b731192023-01-11 16:27:13 +08001704 dbus::utility::getDbusObject(
1705 *path, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001706 [asyncResp, path,
George Liu2b731192023-01-11 16:27:13 +08001707 propertyName](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001708 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001709 if (ec || objectNames.empty())
1710 {
1711 setErrorResponse(asyncResp->res,
1712 boost::beast::http::status::not_found,
1713 notFoundDesc, notFoundMsg);
1714 return;
1715 }
1716 std::shared_ptr<nlohmann::json> response =
1717 std::make_shared<nlohmann::json>(nlohmann::json::object());
1718 // The mapper should never give us an empty interface names
1719 // list, but check anyway
1720 for (const std::pair<std::string, std::vector<std::string>>&
1721 connection : objectNames)
1722 {
1723 const std::vector<std::string>& interfaceNames = connection.second;
1724
1725 if (interfaceNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001726 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001727 setErrorResponse(asyncResp->res,
1728 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001729 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001730 return;
1731 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001732
1733 for (const std::string& interface : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001734 {
Patrick Williams59d494e2022-07-22 19:26:55 -05001735 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001736 crow::connections::systemBus->new_method_call(
1737 connection.first.c_str(), path->c_str(),
1738 "org.freedesktop.DBus.Properties", "GetAll");
1739 m.append(interface);
1740 crow::connections::systemBus->async_send(
1741 m, [asyncResp, response,
1742 propertyName](const boost::system::error_code ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05001743 sdbusplus::message_t& msg) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001744 if (ec2)
1745 {
1746 BMCWEB_LOG_ERROR << "Bad dbus request error: "
1747 << ec2;
1748 }
1749 else
1750 {
1751 nlohmann::json properties;
1752 int r = convertDBusToJSON("a{sv}", msg, properties);
1753 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001754 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001755 BMCWEB_LOG_ERROR << "convertDBusToJSON failed";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001756 }
1757 else
1758 {
Patrick Williams62bafc02022-09-08 17:35:35 -05001759 for (const auto& prop : properties.items())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001760 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001761 // if property name is empty, or
1762 // matches our search query, add it
1763 // to the response json
Ed Tanous1abe55e2018-09-05 08:30:59 -07001764
Ed Tanous002d39b2022-05-31 08:59:27 -07001765 if (propertyName->empty())
1766 {
1767 (*response)[prop.key()] =
1768 std::move(prop.value());
1769 }
1770 else if (prop.key() == *propertyName)
1771 {
1772 *response = std::move(prop.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001773 }
1774 }
1775 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001776 }
1777 if (response.use_count() == 1)
1778 {
1779 if (!propertyName->empty() && response->empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001780 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001781 setErrorResponse(
1782 asyncResp->res,
1783 boost::beast::http::status::not_found,
1784 propNotFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001785 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001786 else
1787 {
1788 asyncResp->res.jsonValue["status"] = "ok";
1789 asyncResp->res.jsonValue["message"] = "200 OK";
1790 asyncResp->res.jsonValue["data"] = *response;
1791 }
1792 }
1793 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001794 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001795 }
George Liu2b731192023-01-11 16:27:13 +08001796 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001797}
1798
Ed Tanous1abe55e2018-09-05 08:30:59 -07001799struct AsyncPutRequest
1800{
Ed Tanous4e23a442022-06-06 09:57:26 -07001801 explicit AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
zhanghch058d1b46d2021-04-01 11:18:24 +08001802 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001803 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001804 ~AsyncPutRequest()
1805 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001806 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001807 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001808 setErrorResponse(asyncResp->res,
1809 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001810 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001811 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001812 }
1813
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001814 AsyncPutRequest(const AsyncPutRequest&) = delete;
1815 AsyncPutRequest(AsyncPutRequest&&) = delete;
1816 AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1817 AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1818
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001819 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001820 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001821 setErrorResponse(asyncResp->res,
1822 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001823 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001824 }
1825
zhanghch058d1b46d2021-04-01 11:18:24 +08001826 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001827 std::string objectPath;
1828 std::string propertyName;
1829 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001830};
1831
zhanghch058d1b46d2021-04-01 11:18:24 +08001832inline void handlePut(const crow::Request& req,
1833 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001834 const std::string& objectPath,
1835 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001836{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001837 if (destProperty.empty())
1838 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001839 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001840 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001841 return;
1842 }
1843
Ed Tanous1abe55e2018-09-05 08:30:59 -07001844 nlohmann::json requestDbusData =
1845 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001846
Ed Tanous1abe55e2018-09-05 08:30:59 -07001847 if (requestDbusData.is_discarded())
1848 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001849 setErrorResponse(asyncResp->res,
1850 boost::beast::http::status::bad_request, noJsonDesc,
1851 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001852 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001853 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001854
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001855 auto propertyIt = requestDbusData.find("data");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001856 if (propertyIt == requestDbusData.end())
1857 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001858 setErrorResponse(asyncResp->res,
1859 boost::beast::http::status::bad_request, noJsonDesc,
1860 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001861 return;
1862 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001863 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001864 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001865 transaction->objectPath = objectPath;
1866 transaction->propertyName = destProperty;
1867 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001868
George Liu2b731192023-01-11 16:27:13 +08001869 dbus::utility::getDbusObject(
1870 transaction->objectPath, {},
1871 [transaction](const boost::system::error_code& ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001872 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001873 if (!ec2 && objectNames.empty())
1874 {
1875 setErrorResponse(transaction->asyncResp->res,
1876 boost::beast::http::status::not_found,
1877 propNotFoundDesc, notFoundMsg);
1878 return;
1879 }
Ed Tanous911ac312017-08-15 09:37:42 -07001880
Ed Tanous002d39b2022-05-31 08:59:27 -07001881 for (const std::pair<std::string, std::vector<std::string>>&
1882 connection : objectNames)
1883 {
1884 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001885
Ed Tanous002d39b2022-05-31 08:59:27 -07001886 crow::connections::systemBus->async_method_call(
1887 [connectionName{std::string(connectionName)},
1888 transaction](const boost::system::error_code ec3,
1889 const std::string& introspectXml) {
1890 if (ec3)
1891 {
1892 BMCWEB_LOG_ERROR << "Introspect call failed with error: "
1893 << ec3.message()
1894 << " on process: " << connectionName;
1895 transaction->setErrorStatus("Unexpected Error");
1896 return;
1897 }
1898 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001899
Ed Tanous002d39b2022-05-31 08:59:27 -07001900 doc.Parse(introspectXml.c_str());
1901 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1902 if (pRoot == nullptr)
1903 {
1904 BMCWEB_LOG_ERROR << "XML document failed to parse: "
1905 << introspectXml;
1906 transaction->setErrorStatus("Unexpected Error");
1907 return;
1908 }
1909 tinyxml2::XMLElement* ifaceNode =
1910 pRoot->FirstChildElement("interface");
1911 while (ifaceNode != nullptr)
1912 {
1913 const char* interfaceName = ifaceNode->Attribute("name");
1914 BMCWEB_LOG_DEBUG << "found interface " << interfaceName;
1915 tinyxml2::XMLElement* propNode =
1916 ifaceNode->FirstChildElement("property");
1917 while (propNode != nullptr)
1918 {
1919 const char* propertyName = propNode->Attribute("name");
1920 BMCWEB_LOG_DEBUG << "Found property " << propertyName;
1921 if (propertyName == transaction->propertyName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001922 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001923 const char* argType = propNode->Attribute("type");
1924 if (argType != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001925 {
Patrick Williams59d494e2022-07-22 19:26:55 -05001926 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001927 crow::connections::systemBus
1928 ->new_method_call(
1929 connectionName.c_str(),
1930 transaction->objectPath.c_str(),
1931 "org.freedesktop.DBus."
1932 "Properties",
1933 "Set");
1934 m.append(interfaceName,
1935 transaction->propertyName);
1936 int r = sd_bus_message_open_container(
1937 m.get(), SD_BUS_TYPE_VARIANT, argType);
1938 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001939 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001940 transaction->setErrorStatus(
1941 "Unexpected Error");
1942 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001943 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001944 r = convertJsonToDbus(
1945 m.get(), argType,
1946 transaction->propertyValue);
1947 if (r < 0)
1948 {
1949 if (r == -ERANGE)
1950 {
1951 transaction->setErrorStatus(
1952 "Provided property value "
1953 "is out of range for the "
1954 "property type");
1955 }
1956 else
1957 {
1958 transaction->setErrorStatus(
1959 "Invalid arg type");
1960 }
1961 return;
1962 }
1963 r = sd_bus_message_close_container(m.get());
1964 if (r < 0)
1965 {
1966 transaction->setErrorStatus(
1967 "Unexpected Error");
1968 return;
1969 }
1970 crow::connections::systemBus->async_send(
1971 m,
Patrick Williams59d494e2022-07-22 19:26:55 -05001972 [transaction](boost::system::error_code ec,
1973 sdbusplus::message_t& m2) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001974 BMCWEB_LOG_DEBUG << "sent";
1975 if (ec)
1976 {
1977 const sd_bus_error* e = m2.get_error();
1978 setErrorResponse(
1979 transaction->asyncResp->res,
1980 boost::beast::http::status::
1981 forbidden,
1982 (e) != nullptr
1983 ? e->name
1984 : ec.category().name(),
1985 (e) != nullptr ? e->message
1986 : ec.message());
1987 }
1988 else
1989 {
1990 transaction->asyncResp->res
1991 .jsonValue["status"] = "ok";
1992 transaction->asyncResp->res
1993 .jsonValue["message"] = "200 OK";
1994 transaction->asyncResp->res
1995 .jsonValue["data"] = nullptr;
1996 }
1997 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001998 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001999 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002000 propNode = propNode->NextSiblingElement("property");
2001 }
2002 ifaceNode = ifaceNode->NextSiblingElement("interface");
2003 }
2004 },
2005 connectionName, transaction->objectPath,
2006 "org.freedesktop.DBus.Introspectable", "Introspect");
2007 }
George Liu2b731192023-01-11 16:27:13 +08002008 });
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07002009}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002010
zhanghch058d1b46d2021-04-01 11:18:24 +08002011inline void handleDBusUrl(const crow::Request& req,
2012 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002013 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002014{
Ed Tanous049a0512018-11-01 13:58:42 -07002015
2016 // If accessing a single attribute, fill in and update objectPath,
2017 // otherwise leave destProperty blank
Ed Tanouse05aec52022-01-25 10:28:56 -08002018 std::string destProperty;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002019 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002020 size_t attrPosition = objectPath.find(attrSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002021 if (attrPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002022 {
2023 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2024 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002025 objectPath.resize(attrPosition);
Ed Tanous049a0512018-11-01 13:58:42 -07002026 }
2027
Ed Tanousb41187f2019-10-24 16:30:02 -07002028 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002029 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002030 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002031 size_t actionPosition = objectPath.find(actionSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002032 if (actionPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002033 {
2034 std::string postProperty =
2035 objectPath.substr((actionPosition + strlen(actionSeperator)),
2036 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002037 objectPath.resize(actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002038 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002039 return;
2040 }
2041 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002042 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002043 {
Ed Tanous11ba3972022-07-11 09:50:41 -07002044 if (objectPath.ends_with("/enumerate"))
Ed Tanous049a0512018-11-01 13:58:42 -07002045 {
2046 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2047 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002048 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002049 }
Ed Tanous11ba3972022-07-11 09:50:41 -07002050 else if (objectPath.ends_with("/list"))
Ed Tanous049a0512018-11-01 13:58:42 -07002051 {
2052 objectPath.erase(objectPath.end() - sizeof("list"),
2053 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002054 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002055 }
2056 else
2057 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002058 // Trim any trailing "/" at the end
Ed Tanous11ba3972022-07-11 09:50:41 -07002059 if (objectPath.ends_with("/"))
Ed Tanousf839dfe2018-11-12 11:11:15 -08002060 {
2061 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002062 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002063 }
2064 else
2065 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002066 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002067 }
Ed Tanous049a0512018-11-01 13:58:42 -07002068 }
2069 return;
2070 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002071 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002072 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002073 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002074 return;
2075 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002076 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002077 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002078 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002079 return;
2080 }
Ed Tanous049a0512018-11-01 13:58:42 -07002081
zhanghch058d1b46d2021-04-01 11:18:24 +08002082 setErrorResponse(asyncResp->res,
2083 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002084 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002085}
2086
Ed Tanous1656b292022-05-04 11:33:42 -07002087inline void
2088 handleBusSystemPost(const crow::Request& req,
2089 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2090 const std::string& processName,
2091 const std::string& requestedPath)
2092{
2093 std::vector<std::string> strs;
2094 boost::split(strs, requestedPath, boost::is_any_of("/"));
2095 std::string objectPath;
2096 std::string interfaceName;
2097 std::string methodName;
2098 auto it = strs.begin();
2099 if (it == strs.end())
2100 {
2101 objectPath = "/";
2102 }
2103 while (it != strs.end())
2104 {
2105 // Check if segment contains ".". If it does, it must be an
2106 // interface
2107 if (it->find(".") != std::string::npos)
2108 {
2109 break;
2110 // This check is necessary as the trailing slash gets
2111 // parsed as part of our <path> specifier above, which
2112 // causes the normal trailing backslash redirector to
2113 // fail.
2114 }
2115 if (!it->empty())
2116 {
2117 objectPath += "/" + *it;
2118 }
2119 it++;
2120 }
2121 if (it != strs.end())
2122 {
2123 interfaceName = *it;
2124 it++;
2125
2126 // after interface, we might have a method name
2127 if (it != strs.end())
2128 {
2129 methodName = *it;
2130 it++;
2131 }
2132 }
2133 if (it != strs.end())
2134 {
2135 // if there is more levels past the method name, something
2136 // went wrong, return not found
2137 asyncResp->res.result(boost::beast::http::status::not_found);
2138 return;
2139 }
2140 if (interfaceName.empty())
2141 {
2142 crow::connections::systemBus->async_method_call(
2143 [asyncResp, processName,
2144 objectPath](const boost::system::error_code ec,
2145 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002146 if (ec)
2147 {
2148 BMCWEB_LOG_ERROR
2149 << "Introspect call failed with error: " << ec.message()
2150 << " on process: " << processName << " path: " << objectPath
2151 << "\n";
2152 return;
2153 }
2154 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002155
Ed Tanous002d39b2022-05-31 08:59:27 -07002156 doc.Parse(introspectXml.c_str());
2157 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2158 if (pRoot == nullptr)
2159 {
2160 BMCWEB_LOG_ERROR << "XML document failed to parse "
2161 << processName << " " << objectPath << "\n";
2162 asyncResp->res.jsonValue["status"] = "XML parse error";
2163 asyncResp->res.result(
2164 boost::beast::http::status::internal_server_error);
2165 return;
2166 }
2167
2168 BMCWEB_LOG_DEBUG << introspectXml;
2169 asyncResp->res.jsonValue["status"] = "ok";
2170 asyncResp->res.jsonValue["bus_name"] = processName;
2171 asyncResp->res.jsonValue["object_path"] = objectPath;
2172
2173 nlohmann::json& interfacesArray =
2174 asyncResp->res.jsonValue["interfaces"];
2175 interfacesArray = nlohmann::json::array();
2176 tinyxml2::XMLElement* interface =
2177 pRoot->FirstChildElement("interface");
2178
2179 while (interface != nullptr)
2180 {
2181 const char* ifaceName = interface->Attribute("name");
2182 if (ifaceName != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002183 {
Ed Tanous8a592812022-06-04 09:06:59 -07002184 nlohmann::json::object_t interfaceObj;
2185 interfaceObj["name"] = ifaceName;
2186 interfacesArray.push_back(std::move(interfaceObj));
Ed Tanous1656b292022-05-04 11:33:42 -07002187 }
2188
Ed Tanous002d39b2022-05-31 08:59:27 -07002189 interface = interface->NextSiblingElement("interface");
2190 }
Ed Tanous1656b292022-05-04 11:33:42 -07002191 },
2192 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2193 "Introspect");
2194 }
2195 else if (methodName.empty())
2196 {
2197 crow::connections::systemBus->async_method_call(
2198 [asyncResp, processName, objectPath,
2199 interfaceName](const boost::system::error_code ec,
2200 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002201 if (ec)
2202 {
2203 BMCWEB_LOG_ERROR
2204 << "Introspect call failed with error: " << ec.message()
2205 << " on process: " << processName << " path: " << objectPath
2206 << "\n";
2207 return;
2208 }
2209 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002210
Ed Tanous002d39b2022-05-31 08:59:27 -07002211 doc.Parse(introspectXml.data(), introspectXml.size());
2212 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2213 if (pRoot == nullptr)
2214 {
2215 BMCWEB_LOG_ERROR << "XML document failed to parse "
2216 << processName << " " << objectPath << "\n";
2217 asyncResp->res.result(
2218 boost::beast::http::status::internal_server_error);
2219 return;
2220 }
2221
2222 asyncResp->res.jsonValue["status"] = "ok";
2223 asyncResp->res.jsonValue["bus_name"] = processName;
2224 asyncResp->res.jsonValue["interface"] = interfaceName;
2225 asyncResp->res.jsonValue["object_path"] = objectPath;
2226
2227 nlohmann::json& methodsArray = asyncResp->res.jsonValue["methods"];
2228 methodsArray = nlohmann::json::array();
2229
2230 nlohmann::json& signalsArray = asyncResp->res.jsonValue["signals"];
2231 signalsArray = nlohmann::json::array();
2232
2233 nlohmann::json& propertiesObj =
2234 asyncResp->res.jsonValue["properties"];
2235 propertiesObj = nlohmann::json::object();
2236
2237 // if we know we're the only call, build the
2238 // json directly
2239 tinyxml2::XMLElement* interface =
2240 pRoot->FirstChildElement("interface");
2241 while (interface != nullptr)
2242 {
2243 const char* ifaceName = interface->Attribute("name");
2244
2245 if (ifaceName != nullptr && ifaceName == interfaceName)
Ed Tanous1656b292022-05-04 11:33:42 -07002246 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002247 break;
Ed Tanous1656b292022-05-04 11:33:42 -07002248 }
Ed Tanous14766872022-03-15 10:44:42 -07002249
Ed Tanous002d39b2022-05-31 08:59:27 -07002250 interface = interface->NextSiblingElement("interface");
2251 }
2252 if (interface == nullptr)
2253 {
2254 // if we got to the end of the list and
2255 // never found a match, throw 404
2256 asyncResp->res.result(boost::beast::http::status::not_found);
2257 return;
2258 }
Ed Tanous1656b292022-05-04 11:33:42 -07002259
Ed Tanous002d39b2022-05-31 08:59:27 -07002260 tinyxml2::XMLElement* methods =
2261 interface->FirstChildElement("method");
2262 while (methods != nullptr)
2263 {
2264 nlohmann::json argsArray = nlohmann::json::array();
2265 tinyxml2::XMLElement* arg = methods->FirstChildElement("arg");
2266 while (arg != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002267 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002268 nlohmann::json thisArg;
2269 for (const char* fieldName : std::array<const char*, 3>{
2270 "name", "direction", "type"})
Ed Tanous1656b292022-05-04 11:33:42 -07002271 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002272 const char* fieldValue = arg->Attribute(fieldName);
2273 if (fieldValue != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002274 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002275 thisArg[fieldName] = fieldValue;
2276 }
2277 }
2278 argsArray.push_back(std::move(thisArg));
2279 arg = arg->NextSiblingElement("arg");
2280 }
2281
2282 const char* name = methods->Attribute("name");
2283 if (name != nullptr)
2284 {
2285 std::string uri;
2286 uri.reserve(14 + processName.size() + objectPath.size() +
2287 interfaceName.size() + strlen(name));
2288 uri += "/bus/system/";
2289 uri += processName;
2290 uri += objectPath;
2291 uri += "/";
2292 uri += interfaceName;
2293 uri += "/";
2294 uri += name;
2295
2296 nlohmann::json::object_t object;
2297 object["name"] = name;
2298 object["uri"] = std::move(uri);
2299 object["args"] = argsArray;
2300
2301 methodsArray.push_back(std::move(object));
2302 }
2303 methods = methods->NextSiblingElement("method");
2304 }
2305 tinyxml2::XMLElement* signals =
2306 interface->FirstChildElement("signal");
2307 while (signals != nullptr)
2308 {
2309 nlohmann::json argsArray = nlohmann::json::array();
2310
2311 tinyxml2::XMLElement* arg = signals->FirstChildElement("arg");
2312 while (arg != nullptr)
2313 {
2314 const char* name = arg->Attribute("name");
2315 const char* type = arg->Attribute("type");
2316 if (name != nullptr && type != nullptr)
2317 {
2318 argsArray.push_back({
2319 {"name", name},
2320 {"type", type},
2321 });
2322 }
2323 arg = arg->NextSiblingElement("arg");
2324 }
2325 const char* name = signals->Attribute("name");
2326 if (name != nullptr)
2327 {
2328 nlohmann::json::object_t object;
2329 object["name"] = name;
2330 object["args"] = argsArray;
2331 signalsArray.push_back(std::move(object));
2332 }
2333
2334 signals = signals->NextSiblingElement("signal");
2335 }
2336
2337 tinyxml2::XMLElement* property =
2338 interface->FirstChildElement("property");
2339 while (property != nullptr)
2340 {
2341 const char* name = property->Attribute("name");
2342 const char* type = property->Attribute("type");
2343 if (type != nullptr && name != nullptr)
2344 {
Patrick Williams59d494e2022-07-22 19:26:55 -05002345 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07002346 crow::connections::systemBus->new_method_call(
2347 processName.c_str(), objectPath.c_str(),
2348 "org.freedesktop."
2349 "DBus."
2350 "Properties",
2351 "Get");
2352 m.append(interfaceName, name);
2353 nlohmann::json& propertyItem = propertiesObj[name];
2354 crow::connections::systemBus->async_send(
2355 m, [&propertyItem,
Ed Tanous02cad962022-06-30 16:50:15 -07002356 asyncResp](const boost::system::error_code& e,
Patrick Williams59d494e2022-07-22 19:26:55 -05002357 sdbusplus::message_t& msg) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002358 if (e)
Ed Tanous1656b292022-05-04 11:33:42 -07002359 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002360 return;
Ed Tanous1656b292022-05-04 11:33:42 -07002361 }
Ed Tanous1656b292022-05-04 11:33:42 -07002362
Ed Tanous002d39b2022-05-31 08:59:27 -07002363 convertDBusToJSON("v", msg, propertyItem);
2364 });
Ed Tanous1656b292022-05-04 11:33:42 -07002365 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002366 property = property->NextSiblingElement("property");
2367 }
Ed Tanous1656b292022-05-04 11:33:42 -07002368 },
2369 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2370 "Introspect");
2371 }
2372 else
2373 {
2374 if (req.method() != boost::beast::http::verb::post)
2375 {
2376 asyncResp->res.result(boost::beast::http::status::not_found);
2377 return;
2378 }
2379
2380 nlohmann::json requestDbusData =
2381 nlohmann::json::parse(req.body, nullptr, false);
2382
2383 if (requestDbusData.is_discarded())
2384 {
2385 asyncResp->res.result(boost::beast::http::status::bad_request);
2386 return;
2387 }
2388 if (!requestDbusData.is_array())
2389 {
2390 asyncResp->res.result(boost::beast::http::status::bad_request);
2391 return;
2392 }
2393 auto transaction =
2394 std::make_shared<InProgressActionData>(asyncResp->res);
2395
2396 transaction->path = objectPath;
2397 transaction->methodName = methodName;
2398 transaction->arguments = std::move(requestDbusData);
2399
2400 findActionOnInterface(transaction, processName);
2401 }
2402}
2403
Ed Tanous23a21a12020-07-25 04:45:05 +00002404inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002405{
2406 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002407 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002408 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002409 [](const crow::Request&,
2410 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002411 nlohmann::json::array_t buses;
2412 nlohmann::json& bus = buses.emplace_back();
2413 bus["name"] = "system";
2414 asyncResp->res.jsonValue["busses"] = std::move(buses);
2415 asyncResp->res.jsonValue["status"] = "ok";
2416 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002417
2418 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002419 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002420 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002421 [](const crow::Request&,
2422 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002423 auto myCallback = [asyncResp](const boost::system::error_code ec,
zhanghch058d1b46d2021-04-01 11:18:24 +08002424 std::vector<std::string>& names) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002425 if (ec)
2426 {
2427 BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
2428 asyncResp->res.result(
2429 boost::beast::http::status::internal_server_error);
2430 }
2431 else
2432 {
2433 std::sort(names.begin(), names.end());
2434 asyncResp->res.jsonValue["status"] = "ok";
2435 auto& objectsSub = asyncResp->res.jsonValue["objects"];
Ed Tanous02cad962022-06-30 16:50:15 -07002436 for (const auto& name : names)
Ed Tanous002d39b2022-05-31 08:59:27 -07002437 {
2438 nlohmann::json::object_t object;
2439 object["name"] = name;
2440 objectsSub.push_back(std::move(object));
2441 }
2442 }
2443 };
2444 crow::connections::systemBus->async_method_call(
2445 std::move(myCallback), "org.freedesktop.DBus", "/",
2446 "org.freedesktop.DBus", "ListNames");
2447 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002448
2449 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002450 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002451 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002452 [](const crow::Request&,
2453 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002454 handleList(asyncResp, "/");
2455 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002456
2457 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002458 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002459 .methods(boost::beast::http::verb::get)(
2460 [](const crow::Request& req,
2461 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002462 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002463 std::string objectPath = "/xyz/" + path;
2464 handleDBusUrl(req, asyncResp, objectPath);
2465 });
zhanghch058d1b46d2021-04-01 11:18:24 +08002466
2467 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002468 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002469 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2470 boost::beast::http::verb::delete_)(
2471 [](const crow::Request& req,
2472 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2473 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002474 std::string objectPath = "/xyz/" + path;
2475 handleDBusUrl(req, asyncResp, objectPath);
2476 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002477
Ed Tanous049a0512018-11-01 13:58:42 -07002478 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002479 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002480 .methods(boost::beast::http::verb::get)(
2481 [](const crow::Request& req,
2482 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2483 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002484 std::string objectPath = "/org/" + path;
2485 handleDBusUrl(req, asyncResp, objectPath);
2486 });
Tanousf00032d2018-11-05 01:18:10 -03002487
2488 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002489 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002490 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2491 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002492 [](const crow::Request& req,
2493 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002494 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002495 std::string objectPath = "/org/" + path;
2496 handleDBusUrl(req, asyncResp, objectPath);
2497 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002498
Ed Tanous1abe55e2018-09-05 08:30:59 -07002499 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002500 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002501 .methods(boost::beast::http::verb::get)(
2502 [](const crow::Request&,
2503 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2504 const std::string& dumpId) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002505 if (!validateFilename(dumpId))
2506 {
2507 asyncResp->res.result(boost::beast::http::status::bad_request);
2508 return;
2509 }
2510 std::filesystem::path loc("/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002511
Ed Tanous002d39b2022-05-31 08:59:27 -07002512 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002513
Ed Tanous002d39b2022-05-31 08:59:27 -07002514 if (!std::filesystem::exists(loc) ||
2515 !std::filesystem::is_directory(loc))
2516 {
2517 BMCWEB_LOG_ERROR << loc.string() << "Not found";
2518 asyncResp->res.result(boost::beast::http::status::not_found);
2519 return;
2520 }
2521 std::filesystem::directory_iterator files(loc);
zhanghch058d1b46d2021-04-01 11:18:24 +08002522
Ed Tanous002d39b2022-05-31 08:59:27 -07002523 for (const auto& file : files)
2524 {
2525 std::ifstream readFile(file.path());
2526 if (!readFile.good())
2527 {
2528 continue;
2529 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002530
Ed Tanousd9f6c622022-03-17 09:12:17 -07002531 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07002532 "application/octet-stream");
zhanghch058d1b46d2021-04-01 11:18:24 +08002533
Ed Tanous002d39b2022-05-31 08:59:27 -07002534 // Assuming only one dump file will be present in the dump
2535 // id directory
2536 std::string dumpFileName = file.path().filename().string();
zhanghch058d1b46d2021-04-01 11:18:24 +08002537
Ed Tanous002d39b2022-05-31 08:59:27 -07002538 // Filename should be in alphanumeric, dot and underscore
2539 // Its based on phosphor-debug-collector application
2540 // dumpfile format
2541 std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
2542 if (!std::regex_match(dumpFileName, dumpFileRegex))
2543 {
2544 BMCWEB_LOG_ERROR << "Invalid dump filename " << dumpFileName;
zhanghch058d1b46d2021-04-01 11:18:24 +08002545 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002546 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07002547 }
2548 std::string contentDispositionParam =
2549 "attachment; filename=\"" + dumpFileName + "\"";
2550
Ed Tanousd9f6c622022-03-17 09:12:17 -07002551 asyncResp->res.addHeader(
2552 boost::beast::http::field::content_disposition,
2553 contentDispositionParam);
Ed Tanous002d39b2022-05-31 08:59:27 -07002554
2555 asyncResp->res.body() = {std::istreambuf_iterator<char>(readFile),
2556 std::istreambuf_iterator<char>()};
2557 return;
2558 }
2559 asyncResp->res.result(boost::beast::http::status::not_found);
2560 return;
2561 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002562
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002563 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002564 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002565
2566 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002567 [](const crow::Request&,
2568 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002569 const std::string& connection) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002570 introspectObjects(connection, "/", asyncResp);
2571 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002572
2573 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002574 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous1656b292022-05-04 11:33:42 -07002575 .methods(boost::beast::http::verb::get,
2576 boost::beast::http::verb::post)(handleBusSystemPost);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002577}
2578} // namespace openbmc_mapper
2579} // namespace crow