blob: 0e3e070ccd3fa4278b9d69e465c52441ddc19493 [file] [log] [blame]
James Feist5b4aa862018-08-16 14:07:01 -07001// Copyright (c) 2018 Intel Corporation
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
Ed Tanousb9b2e0b2018-09-13 13:47:50 -070014
James Feist5b4aa862018-08-16 14:07:01 -070015#pragma once
Nan Zhoud5c80ad2022-07-11 01:16:31 +000016#include "http_request.hpp"
17#include "http_response.hpp"
18#include "logging.hpp"
19#include "routing.hpp"
20
21#include <systemd/sd-bus-protocol.h>
22#include <systemd/sd-bus.h>
Ed Tanous911ac312017-08-15 09:37:42 -070023#include <tinyxml2.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -070024
Ed Tanous04e438c2020-10-03 08:06:26 -070025#include <app.hpp>
Ed Tanouse3cb5a32018-08-08 14:16:49 -070026#include <async_resp.hpp>
Ed Tanous11ba3972022-07-11 09:50:41 -070027#include <boost/algorithm/string/classification.hpp>
28#include <boost/algorithm/string/predicate.hpp>
29#include <boost/algorithm/string/split.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000030#include <boost/beast/http/status.hpp>
31#include <boost/beast/http/verb.hpp>
32#include <boost/container/flat_map.hpp>
33#include <boost/container/vector.hpp>
34#include <boost/iterator/iterator_facade.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -070035#include <dbus_singleton.hpp>
James Feist5b4aa862018-08-16 14:07:01 -070036#include <dbus_utility.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000037#include <nlohmann/json.hpp>
38#include <sdbusplus/asio/connection.hpp>
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{
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600409 crow::connections::systemBus->async_method_call(
410 [transaction](const boost::system::error_code ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800411 const dbus::utility::MapperGetObject& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700412 if (ec)
413 {
414 BMCWEB_LOG_ERROR << "GetObject for path " << transaction->objectPath
415 << " failed with code " << ec;
416 return;
417 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600418
Ed Tanous002d39b2022-05-31 08:59:27 -0700419 BMCWEB_LOG_DEBUG << "GetObject for " << transaction->objectPath
420 << " has " << objects.size() << " entries";
421 if (!objects.empty())
422 {
423 transaction->subtree->emplace_back(transaction->objectPath,
424 objects);
425 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600426
Ed Tanous002d39b2022-05-31 08:59:27 -0700427 // Map indicating connection name, and the path where the object
428 // manager exists
429 boost::container::flat_map<std::string, std::string> connections;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600430
Ed Tanous002d39b2022-05-31 08:59:27 -0700431 for (const auto& object : *(transaction->subtree))
432 {
433 for (const auto& connection : object.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600434 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700435 for (const auto& interface : connection.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600436 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700437 BMCWEB_LOG_DEBUG << connection.first << " has interface "
438 << interface;
439 if (interface == "org.freedesktop.DBus.ObjectManager")
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600440 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700441 BMCWEB_LOG_DEBUG << "found object manager path "
442 << object.first;
Ed Tanousf8fe53e2022-06-30 15:55:45 -0700443 connections[connection.first] = object.first;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600444 }
445 }
446 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700447 }
448 BMCWEB_LOG_DEBUG << "Got " << connections.size() << " connections";
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600449
Ed Tanous002d39b2022-05-31 08:59:27 -0700450 for (const auto& connection : connections)
451 {
452 // If we already know where the object manager is, we don't
453 // need to search for it, we can call directly in to
454 // getManagedObjects
455 if (!connection.second.empty())
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600456 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700457 getManagedObjectsForEnumerate(transaction->objectPath,
458 connection.second,
459 connection.first, transaction);
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600460 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700461 else
462 {
463 // otherwise we need to find the object manager path
464 // before we can continue
465 findObjectManagerPathForEnumerate(
466 transaction->objectPath, connection.first, transaction);
467 }
468 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600469 },
470 "xyz.openbmc_project.ObjectMapper",
471 "/xyz/openbmc_project/object_mapper",
472 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500473 transaction->objectPath, std::array<const char*, 0>());
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600474}
Ed Tanous64530012018-02-06 17:08:16 -0800475
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700476// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700477struct InProgressActionData
478{
Ed Tanous4e23a442022-06-06 09:57:26 -0700479 explicit InProgressActionData(crow::Response& resIn) : res(resIn)
Ed Tanous23a21a12020-07-25 04:45:05 +0000480 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700481 ~InProgressActionData()
482 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600483 // Methods could have been called across different owners
484 // and interfaces, where some calls failed and some passed.
485 //
486 // The rules for this are:
487 // * if no method was called - error
488 // * if a method failed and none passed - error
489 // (converse: if at least one method passed - OK)
490 // * for the method output:
491 // * if output processing didn't fail, return the data
492
493 // Only deal with method returns if nothing failed earlier
494 if (res.result() == boost::beast::http::status::ok)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700495 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600496 if (!methodPassed)
497 {
Matt Spinler06b1b632019-06-18 16:09:25 -0500498 if (!methodFailed)
Matt Spinler16caaee2019-01-15 11:40:34 -0600499 {
500 setErrorResponse(res, boost::beast::http::status::not_found,
501 methodNotFoundDesc, notFoundMsg);
502 }
503 }
504 else
505 {
506 if (outputFailed)
507 {
508 setErrorResponse(
509 res, boost::beast::http::status::internal_server_error,
510 "Method output failure", methodOutputFailedMsg);
511 }
512 else
513 {
Ed Tanous14766872022-03-15 10:44:42 -0700514 res.jsonValue["status"] = "ok";
515 res.jsonValue["message"] = "200 OK";
516 res.jsonValue["data"] = methodResponse;
Matt Spinler16caaee2019-01-15 11:40:34 -0600517 }
518 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700519 }
Matt Spinler16caaee2019-01-15 11:40:34 -0600520
Ed Tanous1abe55e2018-09-05 08:30:59 -0700521 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700522 }
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800523 InProgressActionData(const InProgressActionData&) = delete;
524 InProgressActionData(InProgressActionData&&) = delete;
525 InProgressActionData& operator=(const InProgressActionData&) = delete;
526 InProgressActionData& operator=(InProgressActionData&&) = delete;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700527
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500528 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700529 {
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600530 setErrorResponse(res, boost::beast::http::status::bad_request, desc,
531 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700532 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500533 crow::Response& res;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700534 std::string path;
535 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600536 std::string interfaceName;
Matt Spinler16caaee2019-01-15 11:40:34 -0600537 bool methodPassed = false;
538 bool methodFailed = false;
539 bool outputFailed = false;
Matt Spinler39a4e392019-01-15 11:53:13 -0600540 bool convertedToArray = false;
Matt Spinler16caaee2019-01-15 11:40:34 -0600541 nlohmann::json methodResponse;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700542 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700543};
544
Ed Tanous23a21a12020-07-25 04:45:05 +0000545inline std::vector<std::string> dbusArgSplit(const std::string& string)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700546{
547 std::vector<std::string> ret;
548 if (string.empty())
549 {
550 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700551 }
Ed Tanous0f0353b2019-10-24 11:37:51 -0700552 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700553 int containerDepth = 0;
554
555 for (std::string::const_iterator character = string.begin();
556 character != string.end(); character++)
557 {
558 ret.back() += *character;
559 switch (*character)
560 {
561 case ('a'):
562 break;
563 case ('('):
564 case ('{'):
565 containerDepth++;
566 break;
567 case ('}'):
568 case (')'):
569 containerDepth--;
570 if (containerDepth == 0)
571 {
572 if (character + 1 != string.end())
573 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700574 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700575 }
576 }
577 break;
578 default:
579 if (containerDepth == 0)
580 {
581 if (character + 1 != string.end())
582 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700583 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700584 }
585 }
586 break;
587 }
588 }
Matt Spinler4ae611d2019-01-11 15:37:06 -0600589
590 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700591}
592
Ed Tanous81ce6092020-12-17 16:54:55 +0000593inline int convertJsonToDbus(sd_bus_message* m, const std::string& argType,
594 const nlohmann::json& inputJson)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700595{
596 int r = 0;
Ed Tanous71f52d92021-02-19 08:51:17 -0800597 BMCWEB_LOG_DEBUG << "Converting "
598 << inputJson.dump(2, ' ', true,
599 nlohmann::json::error_handler_t::replace)
Ed Tanous81ce6092020-12-17 16:54:55 +0000600 << " to type: " << argType;
601 const std::vector<std::string> argTypes = dbusArgSplit(argType);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700602
Ed Tanous1abe55e2018-09-05 08:30:59 -0700603 // Assume a single object for now.
Ed Tanous81ce6092020-12-17 16:54:55 +0000604 const nlohmann::json* j = &inputJson;
605 nlohmann::json::const_iterator jIt = inputJson.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700606
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500607 for (const std::string& argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700608 {
609 // If we are decoding multiple objects, grab the pointer to the
610 // iterator, and increment it for the next loop
611 if (argTypes.size() > 1)
612 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000613 if (jIt == inputJson.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700614 {
615 return -2;
616 }
617 j = &*jIt;
618 jIt++;
619 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500620 const int64_t* intValue = j->get_ptr<const int64_t*>();
621 const std::string* stringValue = j->get_ptr<const std::string*>();
622 const double* doubleValue = j->get_ptr<const double*>();
623 const bool* b = j->get_ptr<const bool*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700624 int64_t v = 0;
625 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700626
Ed Tanous1abe55e2018-09-05 08:30:59 -0700627 // Do some basic type conversions that make sense. uint can be
628 // converted to int. int and uint can be converted to double
Ed Tanous66664f22019-10-11 13:05:49 -0700629 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700630 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500631 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700632 if (uintValue != nullptr)
633 {
634 v = static_cast<int64_t>(*uintValue);
635 intValue = &v;
636 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700637 }
Ed Tanous66664f22019-10-11 13:05:49 -0700638 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700639 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500640 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700641 if (uintValue != nullptr)
642 {
643 d = static_cast<double>(*uintValue);
644 doubleValue = &d;
645 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700646 }
Ed Tanous66664f22019-10-11 13:05:49 -0700647 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700648 {
Ed Tanous66664f22019-10-11 13:05:49 -0700649 if (intValue != nullptr)
650 {
651 d = static_cast<double>(*intValue);
652 doubleValue = &d;
653 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700654 }
655
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700656 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700657 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700658 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700659 {
660 return -1;
661 }
Ed Tanous271584a2019-07-09 16:24:22 -0700662 r = sd_bus_message_append_basic(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500663 m, argCode[0], static_cast<const void*>(stringValue->data()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700664 if (r < 0)
665 {
666 return r;
667 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700668 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700669 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700670 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700671 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700672 {
673 return -1;
674 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500675 if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
676 (*intValue > std::numeric_limits<int32_t>::max()))
677 {
678 return -ERANGE;
679 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700680 int32_t i = static_cast<int32_t>(*intValue);
681 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700682 if (r < 0)
683 {
684 return r;
685 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700686 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700687 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700688 {
689 // lots of ways bool could be represented here. Try them all
Ed Tanouse662eae2022-01-25 10:39:19 -0800690 int boolInt = 0;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700691 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700692 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500693 if (*intValue == 1)
694 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800695 boolInt = 1;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500696 }
697 else if (*intValue == 0)
698 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800699 boolInt = 0;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500700 }
701 else
702 {
703 return -ERANGE;
704 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700705 }
706 else if (b != nullptr)
707 {
Matt Spinlera2f02632019-01-18 10:15:35 -0600708 boolInt = *b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700709 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700710 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700711 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700712 boolInt = boost::istarts_with(*stringValue, "t") ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700713 }
714 else
715 {
716 return -1;
717 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700718 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700719 if (r < 0)
720 {
721 return r;
722 }
723 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700724 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700725 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700726 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700727 {
728 return -1;
729 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500730 if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
731 (*intValue > std::numeric_limits<int16_t>::max()))
732 {
733 return -ERANGE;
734 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700735 int16_t n = static_cast<int16_t>(*intValue);
736 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700737 if (r < 0)
738 {
739 return r;
740 }
741 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700742 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700743 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700744 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700745 {
746 return -1;
747 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700748 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700749 if (r < 0)
750 {
751 return r;
752 }
753 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700754 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700755 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500756 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700757 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700758 {
759 return -1;
760 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000761 if (*uintValue > std::numeric_limits<uint8_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500762 {
763 return -ERANGE;
764 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700765 uint8_t y = static_cast<uint8_t>(*uintValue);
766 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700767 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700768 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700769 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500770 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700771 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700772 {
773 return -1;
774 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000775 if (*uintValue > std::numeric_limits<uint16_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500776 {
777 return -ERANGE;
778 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700779 uint16_t q = static_cast<uint16_t>(*uintValue);
780 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700781 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700782 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700783 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500784 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700785 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700786 {
787 return -1;
788 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000789 if (*uintValue > std::numeric_limits<uint32_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500790 {
791 return -ERANGE;
792 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700793 uint32_t u = static_cast<uint32_t>(*uintValue);
794 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700795 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700796 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700797 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500798 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700799 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700800 {
801 return -1;
802 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700803 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700804 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700805 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700806 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500807 if (doubleValue == nullptr)
808 {
809 return -1;
810 }
811 if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
812 (*doubleValue > std::numeric_limits<double>::max()))
813 {
814 return -ERANGE;
815 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700816 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700817 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700818 else if (argCode.starts_with("a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700819 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700820 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700821 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700822 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700823 if (r < 0)
824 {
825 return r;
826 }
827
Ed Tanous0dfeda62019-10-24 11:21:38 -0700828 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700829 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700830 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700831 if (r < 0)
832 {
833 return r;
834 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700835 }
836 sd_bus_message_close_container(m);
837 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700838 else if (argCode.starts_with("v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700839 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700840 std::string containedType = argCode.substr(1);
841 BMCWEB_LOG_DEBUG << "variant type: " << argCode
842 << " appending variant of type: " << containedType;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700843 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700844 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700845 if (r < 0)
846 {
847 return r;
848 }
849
Ed Tanous81ce6092020-12-17 16:54:55 +0000850 r = convertJsonToDbus(m, containedType, inputJson);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700851 if (r < 0)
852 {
853 return r;
854 }
855
856 r = sd_bus_message_close_container(m);
857 if (r < 0)
858 {
859 return r;
860 }
861 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700862 else if (argCode.starts_with("(") && argCode.ends_with(")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700863 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700864 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700865 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700866 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800867 if (r < 0)
868 {
869 return r;
870 }
871
Ed Tanous1abe55e2018-09-05 08:30:59 -0700872 nlohmann::json::const_iterator it = j->begin();
Ed Tanous81ce6092020-12-17 16:54:55 +0000873 for (const std::string& argCode2 : dbusArgSplit(argType))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700874 {
875 if (it == j->end())
876 {
877 return -1;
878 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000879 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700880 if (r < 0)
881 {
882 return r;
883 }
884 it++;
885 }
886 r = sd_bus_message_close_container(m);
887 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700888 else if (argCode.starts_with("{") && argCode.ends_with("}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700889 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700890 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700891 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700892 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800893 if (r < 0)
894 {
895 return r;
896 }
897
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700898 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700899 if (codes.size() != 2)
900 {
901 return -1;
902 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700903 const std::string& keyType = codes[0];
904 const std::string& valueType = codes[1];
Ed Tanous3174e4d2020-10-07 11:41:22 -0700905 for (const auto& it : j->items())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700906 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700907 r = convertJsonToDbus(m, keyType, it.key());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700908 if (r < 0)
909 {
910 return r;
911 }
912
Ed Tanous2c70f802020-09-28 14:29:23 -0700913 r = convertJsonToDbus(m, valueType, it.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700914 if (r < 0)
915 {
916 return r;
917 }
918 }
919 r = sd_bus_message_close_container(m);
920 }
921 else
922 {
923 return -2;
924 }
925 if (r < 0)
926 {
927 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700928 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700929
Ed Tanous1abe55e2018-09-05 08:30:59 -0700930 if (argTypes.size() > 1)
931 {
932 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700933 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700934 }
Matt Spinler127ea542019-01-14 11:04:28 -0600935
936 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700937}
938
Matt Spinlerd22a7132019-01-14 12:14:30 -0600939template <typename T>
Patrick Williams59d494e2022-07-22 19:26:55 -0500940int readMessageItem(const std::string& typeCode, sdbusplus::message_t& m,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500941 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600942{
943 T value;
944
945 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
946 if (r < 0)
947 {
948 BMCWEB_LOG_ERROR << "sd_bus_message_read_basic on type " << typeCode
949 << " failed!";
950 return r;
951 }
952
953 data = value;
954 return 0;
955}
956
Patrick Williams59d494e2022-07-22 19:26:55 -0500957int convertDBusToJSON(const std::string& returnType, sdbusplus::message_t& m,
958 nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600959
Ed Tanous23a21a12020-07-25 04:45:05 +0000960inline int readDictEntryFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -0500961 sdbusplus::message_t& m,
Ed Tanous23a21a12020-07-25 04:45:05 +0000962 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600963{
964 std::vector<std::string> types = dbusArgSplit(typeCode);
965 if (types.size() != 2)
966 {
967 BMCWEB_LOG_ERROR << "wrong number contained types in dictionary: "
968 << types.size();
969 return -1;
970 }
971
972 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
973 typeCode.c_str());
974 if (r < 0)
975 {
976 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container with rc " << r;
977 return r;
978 }
979
980 nlohmann::json key;
981 r = convertDBusToJSON(types[0], m, key);
982 if (r < 0)
983 {
984 return r;
985 }
986
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500987 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -0600988 if (keyPtr == nullptr)
989 {
990 // json doesn't support non-string keys. If we hit this condition,
991 // convert the result to a string so we can proceed
Ed Tanous71f52d92021-02-19 08:51:17 -0800992 key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500993 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -0700994 // in theory this can't fail now, but lets be paranoid about it
995 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -0600996 if (keyPtr == nullptr)
997 {
998 return -1;
999 }
1000 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001001 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -06001002
1003 r = convertDBusToJSON(types[1], m, value);
1004 if (r < 0)
1005 {
1006 return r;
1007 }
1008
1009 r = sd_bus_message_exit_container(m.get());
1010 if (r < 0)
1011 {
1012 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1013 return r;
1014 }
1015
1016 return 0;
1017}
1018
Ed Tanous23a21a12020-07-25 04:45:05 +00001019inline int readArrayFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001020 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -06001021{
1022 if (typeCode.size() < 2)
1023 {
1024 BMCWEB_LOG_ERROR << "Type code " << typeCode
1025 << " too small for an array";
1026 return -1;
1027 }
1028
1029 std::string containedType = typeCode.substr(1);
1030
1031 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
1032 containedType.c_str());
1033 if (r < 0)
1034 {
1035 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1036 << r;
1037 return r;
1038 }
1039
Ed Tanous11ba3972022-07-11 09:50:41 -07001040 bool dict = containedType.starts_with("{") && containedType.ends_with("}");
Matt Spinler6df8f992019-01-14 12:47:47 -06001041
1042 if (dict)
1043 {
1044 // Remove the { }
1045 containedType = containedType.substr(1, containedType.size() - 2);
1046 data = nlohmann::json::object();
1047 }
1048 else
1049 {
1050 data = nlohmann::json::array();
1051 }
1052
1053 while (true)
1054 {
Ed Tanouse662eae2022-01-25 10:39:19 -08001055 r = sd_bus_message_at_end(m.get(), 0);
Matt Spinler6df8f992019-01-14 12:47:47 -06001056 if (r < 0)
1057 {
1058 BMCWEB_LOG_ERROR << "sd_bus_message_at_end failed";
1059 return r;
1060 }
1061
1062 if (r > 0)
1063 {
1064 break;
1065 }
1066
1067 // Dictionaries are only ever seen in an array
1068 if (dict)
1069 {
1070 r = readDictEntryFromMessage(containedType, m, data);
1071 if (r < 0)
1072 {
1073 return r;
1074 }
1075 }
1076 else
1077 {
1078 data.push_back(nlohmann::json());
1079
1080 r = convertDBusToJSON(containedType, m, data.back());
1081 if (r < 0)
1082 {
1083 return r;
1084 }
1085 }
1086 }
1087
1088 r = sd_bus_message_exit_container(m.get());
1089 if (r < 0)
1090 {
1091 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1092 return r;
1093 }
1094
1095 return 0;
1096}
1097
Ed Tanous23a21a12020-07-25 04:45:05 +00001098inline int readStructFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001099 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001100{
1101 if (typeCode.size() < 3)
1102 {
1103 BMCWEB_LOG_ERROR << "Type code " << typeCode
1104 << " too small for a struct";
1105 return -1;
1106 }
1107
1108 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1109 std::vector<std::string> types = dbusArgSplit(containedTypes);
1110
1111 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1112 containedTypes.c_str());
1113 if (r < 0)
1114 {
1115 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1116 << r;
1117 return r;
1118 }
1119
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001120 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001121 {
1122 data.push_back(nlohmann::json());
1123 r = convertDBusToJSON(type, m, data.back());
1124 if (r < 0)
1125 {
1126 return r;
1127 }
1128 }
1129
1130 r = sd_bus_message_exit_container(m.get());
1131 if (r < 0)
1132 {
1133 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1134 return r;
1135 }
1136 return 0;
1137}
1138
Patrick Williams59d494e2022-07-22 19:26:55 -05001139inline int readVariantFromMessage(sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001140{
Ed Tanous543f4402022-01-06 13:12:53 -08001141 const char* containerType = nullptr;
Ed Tanous99131cd2019-10-24 11:12:47 -07001142 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001143 if (r < 0)
1144 {
1145 BMCWEB_LOG_ERROR << "sd_bus_message_peek_type failed";
1146 return r;
1147 }
1148
1149 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1150 containerType);
1151 if (r < 0)
1152 {
1153 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1154 << r;
1155 return r;
1156 }
1157
1158 r = convertDBusToJSON(containerType, m, data);
1159 if (r < 0)
1160 {
1161 return r;
1162 }
1163
1164 r = sd_bus_message_exit_container(m.get());
1165 if (r < 0)
1166 {
1167 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed";
1168 return r;
1169 }
1170
1171 return 0;
1172}
1173
Ed Tanous23a21a12020-07-25 04:45:05 +00001174inline int convertDBusToJSON(const std::string& returnType,
Patrick Williams59d494e2022-07-22 19:26:55 -05001175 sdbusplus::message_t& m, nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001176{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001177 int r = 0;
1178 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1179
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001180 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001181 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001182 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001183 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001184 {
1185 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001186 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001187 }
1188
Ed Tanousd4d25792020-09-29 15:15:03 -07001189 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001190 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001191 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001192 if (r < 0)
1193 {
1194 return r;
1195 }
1196 }
1197 else if (typeCode == "b")
1198 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001199 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001200 if (r < 0)
1201 {
1202 return r;
1203 }
1204
Matt Spinlerf39420c2019-01-30 12:57:18 -06001205 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001206 }
1207 else if (typeCode == "u")
1208 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001209 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001210 if (r < 0)
1211 {
1212 return r;
1213 }
1214 }
1215 else if (typeCode == "i")
1216 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001217 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001218 if (r < 0)
1219 {
1220 return r;
1221 }
1222 }
1223 else if (typeCode == "x")
1224 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001225 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001226 if (r < 0)
1227 {
1228 return r;
1229 }
1230 }
1231 else if (typeCode == "t")
1232 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001233 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001234 if (r < 0)
1235 {
1236 return r;
1237 }
1238 }
1239 else if (typeCode == "n")
1240 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001241 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001242 if (r < 0)
1243 {
1244 return r;
1245 }
1246 }
1247 else if (typeCode == "q")
1248 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001249 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001250 if (r < 0)
1251 {
1252 return r;
1253 }
1254 }
1255 else if (typeCode == "y")
1256 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001257 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001258 if (r < 0)
1259 {
1260 return r;
1261 }
1262 }
1263 else if (typeCode == "d")
1264 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001265 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001266 if (r < 0)
1267 {
1268 return r;
1269 }
1270 }
1271 else if (typeCode == "h")
1272 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001273 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001274 if (r < 0)
1275 {
1276 return r;
1277 }
1278 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001279 else if (typeCode.starts_with("a"))
Matt Spinler6df8f992019-01-14 12:47:47 -06001280 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001281 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001282 if (r < 0)
1283 {
1284 return r;
1285 }
1286 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001287 else if (typeCode.starts_with("(") && typeCode.ends_with(")"))
Matt Spinler75c6c672019-01-14 13:01:46 -06001288 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001289 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001290 if (r < 0)
1291 {
1292 return r;
1293 }
1294 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001295 else if (typeCode.starts_with("v"))
Matt Spinler89c19702019-01-14 13:13:00 -06001296 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001297 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001298 if (r < 0)
1299 {
1300 return r;
1301 }
1302 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001303 else
1304 {
Matt Spinlerd22a7132019-01-14 12:14:30 -06001305 BMCWEB_LOG_ERROR << "Invalid D-Bus signature type " << typeCode;
1306 return -2;
1307 }
1308 }
1309
Matt Spinler16caaee2019-01-15 11:40:34 -06001310 return 0;
1311}
1312
Ed Tanousb5a76932020-09-29 16:16:58 -07001313inline void handleMethodResponse(
1314 const std::shared_ptr<InProgressActionData>& transaction,
Patrick Williams59d494e2022-07-22 19:26:55 -05001315 sdbusplus::message_t& m, const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001316{
Matt Spinler39a4e392019-01-15 11:53:13 -06001317 nlohmann::json data;
1318
1319 int r = convertDBusToJSON(returnType, m, data);
1320 if (r < 0)
1321 {
1322 transaction->outputFailed = true;
1323 return;
1324 }
1325
1326 if (data.is_null())
1327 {
1328 return;
1329 }
1330
1331 if (transaction->methodResponse.is_null())
1332 {
1333 transaction->methodResponse = std::move(data);
1334 return;
1335 }
1336
1337 // If they're both dictionaries or arrays, merge into one.
1338 // Otherwise, make the results an array with every result
1339 // an entry. Could also just fail in that case, but it
1340 // seems better to get the data back somehow.
1341
1342 if (transaction->methodResponse.is_object() && data.is_object())
1343 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001344 for (const auto& obj : data.items())
Matt Spinler39a4e392019-01-15 11:53:13 -06001345 {
1346 // Note: Will overwrite the data for a duplicate key
1347 transaction->methodResponse.emplace(obj.key(),
1348 std::move(obj.value()));
1349 }
1350 return;
1351 }
1352
1353 if (transaction->methodResponse.is_array() && data.is_array())
1354 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001355 for (auto& obj : data)
Matt Spinler39a4e392019-01-15 11:53:13 -06001356 {
1357 transaction->methodResponse.push_back(std::move(obj));
1358 }
1359 return;
1360 }
1361
1362 if (!transaction->convertedToArray)
1363 {
1364 // They are different types. May as well turn them into an array
1365 nlohmann::json j = std::move(transaction->methodResponse);
1366 transaction->methodResponse = nlohmann::json::array();
1367 transaction->methodResponse.push_back(std::move(j));
1368 transaction->methodResponse.push_back(std::move(data));
1369 transaction->convertedToArray = true;
1370 }
1371 else
1372 {
1373 transaction->methodResponse.push_back(std::move(data));
1374 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001375}
1376
Ed Tanousb5a76932020-09-29 16:16:58 -07001377inline void findActionOnInterface(
1378 const std::shared_ptr<InProgressActionData>& transaction,
1379 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001380{
1381 BMCWEB_LOG_DEBUG << "findActionOnInterface for connection "
1382 << connectionName;
1383 crow::connections::systemBus->async_method_call(
1384 [transaction, connectionName{std::string(connectionName)}](
1385 const boost::system::error_code ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001386 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001387 BMCWEB_LOG_DEBUG << "got xml:\n " << introspectXml;
1388 if (ec)
1389 {
1390 BMCWEB_LOG_ERROR
1391 << "Introspect call failed with error: " << ec.message()
1392 << " on process: " << connectionName << "\n";
1393 return;
1394 }
1395 tinyxml2::XMLDocument doc;
Matt Spinler318bd892019-01-15 09:59:20 -06001396
Ed Tanous002d39b2022-05-31 08:59:27 -07001397 doc.Parse(introspectXml.data(), introspectXml.size());
1398 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1399 if (pRoot == nullptr)
1400 {
1401 BMCWEB_LOG_ERROR << "XML document failed to parse "
1402 << connectionName << "\n";
1403 return;
1404 }
1405 tinyxml2::XMLElement* interfaceNode =
1406 pRoot->FirstChildElement("interface");
1407 while (interfaceNode != nullptr)
1408 {
1409 const char* thisInterfaceName = interfaceNode->Attribute("name");
1410 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001411 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001412 if (!transaction->interfaceName.empty() &&
1413 (transaction->interfaceName != thisInterfaceName))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001414 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001415 interfaceNode =
1416 interfaceNode->NextSiblingElement("interface");
1417 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001418 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001419
1420 tinyxml2::XMLElement* methodNode =
1421 interfaceNode->FirstChildElement("method");
1422 while (methodNode != nullptr)
1423 {
1424 const char* thisMethodName = methodNode->Attribute("name");
1425 BMCWEB_LOG_DEBUG << "Found method: " << thisMethodName;
1426 if (thisMethodName != nullptr &&
1427 thisMethodName == transaction->methodName)
1428 {
1429 BMCWEB_LOG_DEBUG << "Found method named "
1430 << thisMethodName << " on interface "
1431 << thisInterfaceName;
Patrick Williams59d494e2022-07-22 19:26:55 -05001432 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001433 crow::connections::systemBus->new_method_call(
1434 connectionName.c_str(),
1435 transaction->path.c_str(), thisInterfaceName,
1436 transaction->methodName.c_str());
1437
1438 tinyxml2::XMLElement* argumentNode =
1439 methodNode->FirstChildElement("arg");
1440
1441 std::string returnType;
1442
1443 // Find the output type
1444 while (argumentNode != nullptr)
1445 {
1446 const char* argDirection =
1447 argumentNode->Attribute("direction");
1448 const char* argType =
1449 argumentNode->Attribute("type");
1450 if (argDirection != nullptr && argType != nullptr &&
1451 std::string(argDirection) == "out")
1452 {
1453 returnType = argType;
1454 break;
1455 }
1456 argumentNode =
1457 argumentNode->NextSiblingElement("arg");
1458 }
1459
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001460 auto argIt = transaction->arguments.begin();
Ed Tanous002d39b2022-05-31 08:59:27 -07001461
1462 argumentNode = methodNode->FirstChildElement("arg");
1463
1464 while (argumentNode != nullptr)
1465 {
1466 const char* argDirection =
1467 argumentNode->Attribute("direction");
1468 const char* argType =
1469 argumentNode->Attribute("type");
1470 if (argDirection != nullptr && argType != nullptr &&
1471 std::string(argDirection) == "in")
1472 {
1473 if (argIt == transaction->arguments.end())
1474 {
1475 transaction->setErrorStatus(
1476 "Invalid method args");
1477 return;
1478 }
1479 if (convertJsonToDbus(m.get(),
1480 std::string(argType),
1481 *argIt) < 0)
1482 {
1483 transaction->setErrorStatus(
1484 "Invalid method arg type");
1485 return;
1486 }
1487
1488 argIt++;
1489 }
1490 argumentNode =
1491 argumentNode->NextSiblingElement("arg");
1492 }
1493
1494 crow::connections::systemBus->async_send(
1495 m,
1496 [transaction,
1497 returnType](boost::system::error_code ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05001498 sdbusplus::message_t& m2) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001499 if (ec2)
1500 {
1501 transaction->methodFailed = true;
1502 const sd_bus_error* e = m2.get_error();
1503
1504 if (e != nullptr)
1505 {
1506 setErrorResponse(
1507 transaction->res,
1508 boost::beast::http::status::bad_request,
1509 e->name, e->message);
1510 }
1511 else
1512 {
1513 setErrorResponse(
1514 transaction->res,
1515 boost::beast::http::status::bad_request,
1516 "Method call failed", methodFailedMsg);
1517 }
1518 return;
1519 }
1520 transaction->methodPassed = true;
1521
1522 handleMethodResponse(transaction, m2, returnType);
1523 });
1524 break;
1525 }
1526 methodNode = methodNode->NextSiblingElement("method");
1527 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001528 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001529 interfaceNode = interfaceNode->NextSiblingElement("interface");
1530 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001531 },
1532 connectionName, transaction->path,
1533 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001534}
1535
zhanghch058d1b46d2021-04-01 11:18:24 +08001536inline void handleAction(const crow::Request& req,
1537 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001538 const std::string& objectPath,
1539 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001540{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001541 BMCWEB_LOG_DEBUG << "handleAction on path: " << objectPath << " and method "
1542 << methodName;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001543 nlohmann::json requestDbusData =
1544 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001545
Ed Tanous1abe55e2018-09-05 08:30:59 -07001546 if (requestDbusData.is_discarded())
1547 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001548 setErrorResponse(asyncResp->res,
1549 boost::beast::http::status::bad_request, noJsonDesc,
1550 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001551 return;
1552 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001553 nlohmann::json::iterator data = requestDbusData.find("data");
1554 if (data == requestDbusData.end())
1555 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001556 setErrorResponse(asyncResp->res,
1557 boost::beast::http::status::bad_request, noJsonDesc,
1558 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001559 return;
1560 }
1561
1562 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001563 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001564 setErrorResponse(asyncResp->res,
1565 boost::beast::http::status::bad_request, noJsonDesc,
1566 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001567 return;
1568 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001569 auto transaction = std::make_shared<InProgressActionData>(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001570
1571 transaction->path = objectPath;
1572 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001573 transaction->arguments = std::move(*data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001574 crow::connections::systemBus->async_method_call(
1575 [transaction](
1576 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001577 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1578 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001579 if (ec || interfaceNames.empty())
1580 {
1581 BMCWEB_LOG_ERROR << "Can't find object";
1582 setErrorResponse(transaction->res,
1583 boost::beast::http::status::not_found,
1584 notFoundDesc, notFoundMsg);
1585 return;
1586 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001587
Ed Tanous002d39b2022-05-31 08:59:27 -07001588 BMCWEB_LOG_DEBUG << "GetObject returned " << interfaceNames.size()
1589 << " object(s)";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001590
Ed Tanous002d39b2022-05-31 08:59:27 -07001591 for (const std::pair<std::string, std::vector<std::string>>& object :
1592 interfaceNames)
1593 {
1594 findActionOnInterface(transaction, object.first);
1595 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001596 },
1597 "xyz.openbmc_project.ObjectMapper",
1598 "/xyz/openbmc_project/object_mapper",
1599 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
1600 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001601}
1602
zhanghch058d1b46d2021-04-01 11:18:24 +08001603inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1604 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001605{
1606 BMCWEB_LOG_DEBUG << "handleDelete on path: " << objectPath;
1607
1608 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +08001609 [asyncResp, objectPath](
Matt Spinlerde818812018-12-11 16:39:20 -06001610 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001611 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1612 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001613 if (ec || interfaceNames.empty())
1614 {
1615 BMCWEB_LOG_ERROR << "Can't find object";
1616 setErrorResponse(asyncResp->res,
1617 boost::beast::http::status::method_not_allowed,
1618 methodNotAllowedDesc, methodNotAllowedMsg);
1619 return;
1620 }
Matt Spinlerde818812018-12-11 16:39:20 -06001621
Ed Tanous002d39b2022-05-31 08:59:27 -07001622 auto transaction =
1623 std::make_shared<InProgressActionData>(asyncResp->res);
1624 transaction->path = objectPath;
1625 transaction->methodName = "Delete";
1626 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
Matt Spinlerde818812018-12-11 16:39:20 -06001627
Ed Tanous002d39b2022-05-31 08:59:27 -07001628 for (const std::pair<std::string, std::vector<std::string>>& object :
1629 interfaceNames)
1630 {
1631 findActionOnInterface(transaction, object.first);
1632 }
Matt Spinlerde818812018-12-11 16:39:20 -06001633 },
1634 "xyz.openbmc_project.ObjectMapper",
1635 "/xyz/openbmc_project/object_mapper",
1636 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001637 std::array<const char*, 0>());
Matt Spinlerde818812018-12-11 16:39:20 -06001638}
1639
zhanghch058d1b46d2021-04-01 11:18:24 +08001640inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1641 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001642{
1643 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001644 [asyncResp](
1645 const boost::system::error_code ec,
1646 const dbus::utility::MapperGetSubTreePathsResponse& objectPaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001647 if (ec)
1648 {
1649 setErrorResponse(asyncResp->res,
1650 boost::beast::http::status::not_found,
1651 notFoundDesc, notFoundMsg);
1652 }
1653 else
1654 {
1655 asyncResp->res.jsonValue["status"] = "ok";
1656 asyncResp->res.jsonValue["message"] = "200 OK";
1657 asyncResp->res.jsonValue["data"] = objectPaths;
1658 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001659 },
1660 "xyz.openbmc_project.ObjectMapper",
1661 "/xyz/openbmc_project/object_mapper",
1662 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", objectPath,
Ed Tanousf839dfe2018-11-12 11:11:15 -08001663 depth, std::array<std::string, 0>());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001664}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001665
zhanghch058d1b46d2021-04-01 11:18:24 +08001666inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1667 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001668{
Ed Tanous049a0512018-11-01 13:58:42 -07001669 BMCWEB_LOG_DEBUG << "Doing enumerate on " << objectPath;
Ed Tanous049a0512018-11-01 13:58:42 -07001670
Ed Tanous14766872022-03-15 10:44:42 -07001671 asyncResp->res.jsonValue["message"] = "200 OK";
1672 asyncResp->res.jsonValue["status"] = "ok";
1673 asyncResp->res.jsonValue["data"] = nlohmann::json::object();
Ed Tanous049a0512018-11-01 13:58:42 -07001674
Ed Tanous1abe55e2018-09-05 08:30:59 -07001675 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001676 [objectPath, asyncResp](
1677 const boost::system::error_code ec,
1678 const dbus::utility::MapperGetSubTreeResponse& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001679 auto transaction =
1680 std::make_shared<InProgressEnumerateData>(objectPath, asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001681
Ed Tanous002d39b2022-05-31 08:59:27 -07001682 transaction->subtree =
1683 std::make_shared<dbus::utility::MapperGetSubTreeResponse>(
1684 objectNames);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001685
Ed Tanous002d39b2022-05-31 08:59:27 -07001686 if (ec)
1687 {
1688 BMCWEB_LOG_ERROR << "GetSubTree failed on "
1689 << transaction->objectPath;
1690 setErrorResponse(transaction->asyncResp->res,
1691 boost::beast::http::status::not_found,
1692 notFoundDesc, notFoundMsg);
1693 return;
1694 }
Ed Tanous64530012018-02-06 17:08:16 -08001695
Ed Tanous002d39b2022-05-31 08:59:27 -07001696 // Add the data for the path passed in to the results
1697 // as if GetSubTree returned it, and continue on enumerating
1698 getObjectAndEnumerate(transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001699 },
1700 "xyz.openbmc_project.ObjectMapper",
1701 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -07001702 "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath, 0,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001703 std::array<const char*, 0>());
Ed Tanous64530012018-02-06 17:08:16 -08001704}
Ed Tanous911ac312017-08-15 09:37:42 -07001705
zhanghch058d1b46d2021-04-01 11:18:24 +08001706inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1707 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001708{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001709 BMCWEB_LOG_DEBUG << "handleGet: " << objectPath << " prop:" << destProperty;
1710 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001711 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001712
Ed Tanous1abe55e2018-09-05 08:30:59 -07001713 std::shared_ptr<std::string> path =
1714 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001715
Ed Tanous1abe55e2018-09-05 08:30:59 -07001716 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001717 [asyncResp, path,
1718 propertyName](const boost::system::error_code ec,
1719 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001720 if (ec || objectNames.empty())
1721 {
1722 setErrorResponse(asyncResp->res,
1723 boost::beast::http::status::not_found,
1724 notFoundDesc, notFoundMsg);
1725 return;
1726 }
1727 std::shared_ptr<nlohmann::json> response =
1728 std::make_shared<nlohmann::json>(nlohmann::json::object());
1729 // The mapper should never give us an empty interface names
1730 // list, but check anyway
1731 for (const std::pair<std::string, std::vector<std::string>>&
1732 connection : objectNames)
1733 {
1734 const std::vector<std::string>& interfaceNames = connection.second;
1735
1736 if (interfaceNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001737 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001738 setErrorResponse(asyncResp->res,
1739 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001740 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001741 return;
1742 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001743
1744 for (const std::string& interface : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001745 {
Patrick Williams59d494e2022-07-22 19:26:55 -05001746 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001747 crow::connections::systemBus->new_method_call(
1748 connection.first.c_str(), path->c_str(),
1749 "org.freedesktop.DBus.Properties", "GetAll");
1750 m.append(interface);
1751 crow::connections::systemBus->async_send(
1752 m, [asyncResp, response,
1753 propertyName](const boost::system::error_code ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05001754 sdbusplus::message_t& msg) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001755 if (ec2)
1756 {
1757 BMCWEB_LOG_ERROR << "Bad dbus request error: "
1758 << ec2;
1759 }
1760 else
1761 {
1762 nlohmann::json properties;
1763 int r = convertDBusToJSON("a{sv}", msg, properties);
1764 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001765 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001766 BMCWEB_LOG_ERROR << "convertDBusToJSON failed";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001767 }
1768 else
1769 {
Patrick Williams62bafc02022-09-08 17:35:35 -05001770 for (const auto& prop : properties.items())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001771 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001772 // if property name is empty, or
1773 // matches our search query, add it
1774 // to the response json
Ed Tanous1abe55e2018-09-05 08:30:59 -07001775
Ed Tanous002d39b2022-05-31 08:59:27 -07001776 if (propertyName->empty())
1777 {
1778 (*response)[prop.key()] =
1779 std::move(prop.value());
1780 }
1781 else if (prop.key() == *propertyName)
1782 {
1783 *response = std::move(prop.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001784 }
1785 }
1786 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001787 }
1788 if (response.use_count() == 1)
1789 {
1790 if (!propertyName->empty() && response->empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001791 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001792 setErrorResponse(
1793 asyncResp->res,
1794 boost::beast::http::status::not_found,
1795 propNotFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001796 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001797 else
1798 {
1799 asyncResp->res.jsonValue["status"] = "ok";
1800 asyncResp->res.jsonValue["message"] = "200 OK";
1801 asyncResp->res.jsonValue["data"] = *response;
1802 }
1803 }
1804 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001805 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001806 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001807 },
1808 "xyz.openbmc_project.ObjectMapper",
1809 "/xyz/openbmc_project/object_mapper",
1810 "xyz.openbmc_project.ObjectMapper", "GetObject", *path,
1811 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001812}
1813
Ed Tanous1abe55e2018-09-05 08:30:59 -07001814struct AsyncPutRequest
1815{
Ed Tanous4e23a442022-06-06 09:57:26 -07001816 explicit AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
zhanghch058d1b46d2021-04-01 11:18:24 +08001817 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001818 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001819 ~AsyncPutRequest()
1820 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001821 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001822 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001823 setErrorResponse(asyncResp->res,
1824 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001825 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001826 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001827 }
1828
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001829 AsyncPutRequest(const AsyncPutRequest&) = delete;
1830 AsyncPutRequest(AsyncPutRequest&&) = delete;
1831 AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1832 AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1833
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001834 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001835 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001836 setErrorResponse(asyncResp->res,
1837 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001838 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001839 }
1840
zhanghch058d1b46d2021-04-01 11:18:24 +08001841 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001842 std::string objectPath;
1843 std::string propertyName;
1844 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001845};
1846
zhanghch058d1b46d2021-04-01 11:18:24 +08001847inline void handlePut(const crow::Request& req,
1848 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001849 const std::string& objectPath,
1850 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001851{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001852 if (destProperty.empty())
1853 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001854 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001855 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001856 return;
1857 }
1858
Ed Tanous1abe55e2018-09-05 08:30:59 -07001859 nlohmann::json requestDbusData =
1860 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001861
Ed Tanous1abe55e2018-09-05 08:30:59 -07001862 if (requestDbusData.is_discarded())
1863 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001864 setErrorResponse(asyncResp->res,
1865 boost::beast::http::status::bad_request, noJsonDesc,
1866 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001867 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001868 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001869
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001870 auto propertyIt = requestDbusData.find("data");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001871 if (propertyIt == requestDbusData.end())
1872 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001873 setErrorResponse(asyncResp->res,
1874 boost::beast::http::status::bad_request, noJsonDesc,
1875 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001876 return;
1877 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001878 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001879 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001880 transaction->objectPath = objectPath;
1881 transaction->propertyName = destProperty;
1882 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001883
Ed Tanous1abe55e2018-09-05 08:30:59 -07001884 crow::connections::systemBus->async_method_call(
Ed Tanous23a21a12020-07-25 04:45:05 +00001885 [transaction](const boost::system::error_code ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001886 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001887 if (!ec2 && objectNames.empty())
1888 {
1889 setErrorResponse(transaction->asyncResp->res,
1890 boost::beast::http::status::not_found,
1891 propNotFoundDesc, notFoundMsg);
1892 return;
1893 }
Ed Tanous911ac312017-08-15 09:37:42 -07001894
Ed Tanous002d39b2022-05-31 08:59:27 -07001895 for (const std::pair<std::string, std::vector<std::string>>&
1896 connection : objectNames)
1897 {
1898 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001899
Ed Tanous002d39b2022-05-31 08:59:27 -07001900 crow::connections::systemBus->async_method_call(
1901 [connectionName{std::string(connectionName)},
1902 transaction](const boost::system::error_code ec3,
1903 const std::string& introspectXml) {
1904 if (ec3)
1905 {
1906 BMCWEB_LOG_ERROR << "Introspect call failed with error: "
1907 << ec3.message()
1908 << " on process: " << connectionName;
1909 transaction->setErrorStatus("Unexpected Error");
1910 return;
1911 }
1912 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001913
Ed Tanous002d39b2022-05-31 08:59:27 -07001914 doc.Parse(introspectXml.c_str());
1915 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1916 if (pRoot == nullptr)
1917 {
1918 BMCWEB_LOG_ERROR << "XML document failed to parse: "
1919 << introspectXml;
1920 transaction->setErrorStatus("Unexpected Error");
1921 return;
1922 }
1923 tinyxml2::XMLElement* ifaceNode =
1924 pRoot->FirstChildElement("interface");
1925 while (ifaceNode != nullptr)
1926 {
1927 const char* interfaceName = ifaceNode->Attribute("name");
1928 BMCWEB_LOG_DEBUG << "found interface " << interfaceName;
1929 tinyxml2::XMLElement* propNode =
1930 ifaceNode->FirstChildElement("property");
1931 while (propNode != nullptr)
1932 {
1933 const char* propertyName = propNode->Attribute("name");
1934 BMCWEB_LOG_DEBUG << "Found property " << propertyName;
1935 if (propertyName == transaction->propertyName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001936 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001937 const char* argType = propNode->Attribute("type");
1938 if (argType != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001939 {
Patrick Williams59d494e2022-07-22 19:26:55 -05001940 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001941 crow::connections::systemBus
1942 ->new_method_call(
1943 connectionName.c_str(),
1944 transaction->objectPath.c_str(),
1945 "org.freedesktop.DBus."
1946 "Properties",
1947 "Set");
1948 m.append(interfaceName,
1949 transaction->propertyName);
1950 int r = sd_bus_message_open_container(
1951 m.get(), SD_BUS_TYPE_VARIANT, argType);
1952 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001953 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001954 transaction->setErrorStatus(
1955 "Unexpected Error");
1956 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001957 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001958 r = convertJsonToDbus(
1959 m.get(), argType,
1960 transaction->propertyValue);
1961 if (r < 0)
1962 {
1963 if (r == -ERANGE)
1964 {
1965 transaction->setErrorStatus(
1966 "Provided property value "
1967 "is out of range for the "
1968 "property type");
1969 }
1970 else
1971 {
1972 transaction->setErrorStatus(
1973 "Invalid arg type");
1974 }
1975 return;
1976 }
1977 r = sd_bus_message_close_container(m.get());
1978 if (r < 0)
1979 {
1980 transaction->setErrorStatus(
1981 "Unexpected Error");
1982 return;
1983 }
1984 crow::connections::systemBus->async_send(
1985 m,
Patrick Williams59d494e2022-07-22 19:26:55 -05001986 [transaction](boost::system::error_code ec,
1987 sdbusplus::message_t& m2) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001988 BMCWEB_LOG_DEBUG << "sent";
1989 if (ec)
1990 {
1991 const sd_bus_error* e = m2.get_error();
1992 setErrorResponse(
1993 transaction->asyncResp->res,
1994 boost::beast::http::status::
1995 forbidden,
1996 (e) != nullptr
1997 ? e->name
1998 : ec.category().name(),
1999 (e) != nullptr ? e->message
2000 : ec.message());
2001 }
2002 else
2003 {
2004 transaction->asyncResp->res
2005 .jsonValue["status"] = "ok";
2006 transaction->asyncResp->res
2007 .jsonValue["message"] = "200 OK";
2008 transaction->asyncResp->res
2009 .jsonValue["data"] = nullptr;
2010 }
2011 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002012 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002013 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002014 propNode = propNode->NextSiblingElement("property");
2015 }
2016 ifaceNode = ifaceNode->NextSiblingElement("interface");
2017 }
2018 },
2019 connectionName, transaction->objectPath,
2020 "org.freedesktop.DBus.Introspectable", "Introspect");
2021 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002022 },
2023 "xyz.openbmc_project.ObjectMapper",
2024 "/xyz/openbmc_project/object_mapper",
2025 "xyz.openbmc_project.ObjectMapper", "GetObject",
2026 transaction->objectPath, std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07002027}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002028
zhanghch058d1b46d2021-04-01 11:18:24 +08002029inline void handleDBusUrl(const crow::Request& req,
2030 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002031 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002032{
Ed Tanous049a0512018-11-01 13:58:42 -07002033
2034 // If accessing a single attribute, fill in and update objectPath,
2035 // otherwise leave destProperty blank
Ed Tanouse05aec52022-01-25 10:28:56 -08002036 std::string destProperty;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002037 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002038 size_t attrPosition = objectPath.find(attrSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002039 if (attrPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002040 {
2041 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2042 objectPath.length());
2043 objectPath = objectPath.substr(0, attrPosition);
2044 }
2045
Ed Tanousb41187f2019-10-24 16:30:02 -07002046 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002047 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002048 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002049 size_t actionPosition = objectPath.find(actionSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002050 if (actionPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002051 {
2052 std::string postProperty =
2053 objectPath.substr((actionPosition + strlen(actionSeperator)),
2054 objectPath.length());
2055 objectPath = objectPath.substr(0, actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002056 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002057 return;
2058 }
2059 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002060 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002061 {
Ed Tanous11ba3972022-07-11 09:50:41 -07002062 if (objectPath.ends_with("/enumerate"))
Ed Tanous049a0512018-11-01 13:58:42 -07002063 {
2064 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2065 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002066 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002067 }
Ed Tanous11ba3972022-07-11 09:50:41 -07002068 else if (objectPath.ends_with("/list"))
Ed Tanous049a0512018-11-01 13:58:42 -07002069 {
2070 objectPath.erase(objectPath.end() - sizeof("list"),
2071 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002072 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002073 }
2074 else
2075 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002076 // Trim any trailing "/" at the end
Ed Tanous11ba3972022-07-11 09:50:41 -07002077 if (objectPath.ends_with("/"))
Ed Tanousf839dfe2018-11-12 11:11:15 -08002078 {
2079 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002080 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002081 }
2082 else
2083 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002084 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002085 }
Ed Tanous049a0512018-11-01 13:58:42 -07002086 }
2087 return;
2088 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002089 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002090 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002091 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002092 return;
2093 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002094 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002095 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002096 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002097 return;
2098 }
Ed Tanous049a0512018-11-01 13:58:42 -07002099
zhanghch058d1b46d2021-04-01 11:18:24 +08002100 setErrorResponse(asyncResp->res,
2101 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002102 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002103}
2104
Ed Tanous1656b292022-05-04 11:33:42 -07002105inline void
2106 handleBusSystemPost(const crow::Request& req,
2107 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2108 const std::string& processName,
2109 const std::string& requestedPath)
2110{
2111 std::vector<std::string> strs;
2112 boost::split(strs, requestedPath, boost::is_any_of("/"));
2113 std::string objectPath;
2114 std::string interfaceName;
2115 std::string methodName;
2116 auto it = strs.begin();
2117 if (it == strs.end())
2118 {
2119 objectPath = "/";
2120 }
2121 while (it != strs.end())
2122 {
2123 // Check if segment contains ".". If it does, it must be an
2124 // interface
2125 if (it->find(".") != std::string::npos)
2126 {
2127 break;
2128 // This check is necessary as the trailing slash gets
2129 // parsed as part of our <path> specifier above, which
2130 // causes the normal trailing backslash redirector to
2131 // fail.
2132 }
2133 if (!it->empty())
2134 {
2135 objectPath += "/" + *it;
2136 }
2137 it++;
2138 }
2139 if (it != strs.end())
2140 {
2141 interfaceName = *it;
2142 it++;
2143
2144 // after interface, we might have a method name
2145 if (it != strs.end())
2146 {
2147 methodName = *it;
2148 it++;
2149 }
2150 }
2151 if (it != strs.end())
2152 {
2153 // if there is more levels past the method name, something
2154 // went wrong, return not found
2155 asyncResp->res.result(boost::beast::http::status::not_found);
2156 return;
2157 }
2158 if (interfaceName.empty())
2159 {
2160 crow::connections::systemBus->async_method_call(
2161 [asyncResp, processName,
2162 objectPath](const boost::system::error_code ec,
2163 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002164 if (ec)
2165 {
2166 BMCWEB_LOG_ERROR
2167 << "Introspect call failed with error: " << ec.message()
2168 << " on process: " << processName << " path: " << objectPath
2169 << "\n";
2170 return;
2171 }
2172 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002173
Ed Tanous002d39b2022-05-31 08:59:27 -07002174 doc.Parse(introspectXml.c_str());
2175 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2176 if (pRoot == nullptr)
2177 {
2178 BMCWEB_LOG_ERROR << "XML document failed to parse "
2179 << processName << " " << objectPath << "\n";
2180 asyncResp->res.jsonValue["status"] = "XML parse error";
2181 asyncResp->res.result(
2182 boost::beast::http::status::internal_server_error);
2183 return;
2184 }
2185
2186 BMCWEB_LOG_DEBUG << introspectXml;
2187 asyncResp->res.jsonValue["status"] = "ok";
2188 asyncResp->res.jsonValue["bus_name"] = processName;
2189 asyncResp->res.jsonValue["object_path"] = objectPath;
2190
2191 nlohmann::json& interfacesArray =
2192 asyncResp->res.jsonValue["interfaces"];
2193 interfacesArray = nlohmann::json::array();
2194 tinyxml2::XMLElement* interface =
2195 pRoot->FirstChildElement("interface");
2196
2197 while (interface != nullptr)
2198 {
2199 const char* ifaceName = interface->Attribute("name");
2200 if (ifaceName != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002201 {
Ed Tanous8a592812022-06-04 09:06:59 -07002202 nlohmann::json::object_t interfaceObj;
2203 interfaceObj["name"] = ifaceName;
2204 interfacesArray.push_back(std::move(interfaceObj));
Ed Tanous1656b292022-05-04 11:33:42 -07002205 }
2206
Ed Tanous002d39b2022-05-31 08:59:27 -07002207 interface = interface->NextSiblingElement("interface");
2208 }
Ed Tanous1656b292022-05-04 11:33:42 -07002209 },
2210 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2211 "Introspect");
2212 }
2213 else if (methodName.empty())
2214 {
2215 crow::connections::systemBus->async_method_call(
2216 [asyncResp, processName, objectPath,
2217 interfaceName](const boost::system::error_code ec,
2218 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002219 if (ec)
2220 {
2221 BMCWEB_LOG_ERROR
2222 << "Introspect call failed with error: " << ec.message()
2223 << " on process: " << processName << " path: " << objectPath
2224 << "\n";
2225 return;
2226 }
2227 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002228
Ed Tanous002d39b2022-05-31 08:59:27 -07002229 doc.Parse(introspectXml.data(), introspectXml.size());
2230 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2231 if (pRoot == nullptr)
2232 {
2233 BMCWEB_LOG_ERROR << "XML document failed to parse "
2234 << processName << " " << objectPath << "\n";
2235 asyncResp->res.result(
2236 boost::beast::http::status::internal_server_error);
2237 return;
2238 }
2239
2240 asyncResp->res.jsonValue["status"] = "ok";
2241 asyncResp->res.jsonValue["bus_name"] = processName;
2242 asyncResp->res.jsonValue["interface"] = interfaceName;
2243 asyncResp->res.jsonValue["object_path"] = objectPath;
2244
2245 nlohmann::json& methodsArray = asyncResp->res.jsonValue["methods"];
2246 methodsArray = nlohmann::json::array();
2247
2248 nlohmann::json& signalsArray = asyncResp->res.jsonValue["signals"];
2249 signalsArray = nlohmann::json::array();
2250
2251 nlohmann::json& propertiesObj =
2252 asyncResp->res.jsonValue["properties"];
2253 propertiesObj = nlohmann::json::object();
2254
2255 // if we know we're the only call, build the
2256 // json directly
2257 tinyxml2::XMLElement* interface =
2258 pRoot->FirstChildElement("interface");
2259 while (interface != nullptr)
2260 {
2261 const char* ifaceName = interface->Attribute("name");
2262
2263 if (ifaceName != nullptr && ifaceName == interfaceName)
Ed Tanous1656b292022-05-04 11:33:42 -07002264 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002265 break;
Ed Tanous1656b292022-05-04 11:33:42 -07002266 }
Ed Tanous14766872022-03-15 10:44:42 -07002267
Ed Tanous002d39b2022-05-31 08:59:27 -07002268 interface = interface->NextSiblingElement("interface");
2269 }
2270 if (interface == nullptr)
2271 {
2272 // if we got to the end of the list and
2273 // never found a match, throw 404
2274 asyncResp->res.result(boost::beast::http::status::not_found);
2275 return;
2276 }
Ed Tanous1656b292022-05-04 11:33:42 -07002277
Ed Tanous002d39b2022-05-31 08:59:27 -07002278 tinyxml2::XMLElement* methods =
2279 interface->FirstChildElement("method");
2280 while (methods != nullptr)
2281 {
2282 nlohmann::json argsArray = nlohmann::json::array();
2283 tinyxml2::XMLElement* arg = methods->FirstChildElement("arg");
2284 while (arg != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002285 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002286 nlohmann::json thisArg;
2287 for (const char* fieldName : std::array<const char*, 3>{
2288 "name", "direction", "type"})
Ed Tanous1656b292022-05-04 11:33:42 -07002289 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002290 const char* fieldValue = arg->Attribute(fieldName);
2291 if (fieldValue != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002292 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002293 thisArg[fieldName] = fieldValue;
2294 }
2295 }
2296 argsArray.push_back(std::move(thisArg));
2297 arg = arg->NextSiblingElement("arg");
2298 }
2299
2300 const char* name = methods->Attribute("name");
2301 if (name != nullptr)
2302 {
2303 std::string uri;
2304 uri.reserve(14 + processName.size() + objectPath.size() +
2305 interfaceName.size() + strlen(name));
2306 uri += "/bus/system/";
2307 uri += processName;
2308 uri += objectPath;
2309 uri += "/";
2310 uri += interfaceName;
2311 uri += "/";
2312 uri += name;
2313
2314 nlohmann::json::object_t object;
2315 object["name"] = name;
2316 object["uri"] = std::move(uri);
2317 object["args"] = argsArray;
2318
2319 methodsArray.push_back(std::move(object));
2320 }
2321 methods = methods->NextSiblingElement("method");
2322 }
2323 tinyxml2::XMLElement* signals =
2324 interface->FirstChildElement("signal");
2325 while (signals != nullptr)
2326 {
2327 nlohmann::json argsArray = nlohmann::json::array();
2328
2329 tinyxml2::XMLElement* arg = signals->FirstChildElement("arg");
2330 while (arg != nullptr)
2331 {
2332 const char* name = arg->Attribute("name");
2333 const char* type = arg->Attribute("type");
2334 if (name != nullptr && type != nullptr)
2335 {
2336 argsArray.push_back({
2337 {"name", name},
2338 {"type", type},
2339 });
2340 }
2341 arg = arg->NextSiblingElement("arg");
2342 }
2343 const char* name = signals->Attribute("name");
2344 if (name != nullptr)
2345 {
2346 nlohmann::json::object_t object;
2347 object["name"] = name;
2348 object["args"] = argsArray;
2349 signalsArray.push_back(std::move(object));
2350 }
2351
2352 signals = signals->NextSiblingElement("signal");
2353 }
2354
2355 tinyxml2::XMLElement* property =
2356 interface->FirstChildElement("property");
2357 while (property != nullptr)
2358 {
2359 const char* name = property->Attribute("name");
2360 const char* type = property->Attribute("type");
2361 if (type != nullptr && name != nullptr)
2362 {
Patrick Williams59d494e2022-07-22 19:26:55 -05002363 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07002364 crow::connections::systemBus->new_method_call(
2365 processName.c_str(), objectPath.c_str(),
2366 "org.freedesktop."
2367 "DBus."
2368 "Properties",
2369 "Get");
2370 m.append(interfaceName, name);
2371 nlohmann::json& propertyItem = propertiesObj[name];
2372 crow::connections::systemBus->async_send(
2373 m, [&propertyItem,
Ed Tanous02cad962022-06-30 16:50:15 -07002374 asyncResp](const boost::system::error_code& e,
Patrick Williams59d494e2022-07-22 19:26:55 -05002375 sdbusplus::message_t& msg) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002376 if (e)
Ed Tanous1656b292022-05-04 11:33:42 -07002377 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002378 return;
Ed Tanous1656b292022-05-04 11:33:42 -07002379 }
Ed Tanous1656b292022-05-04 11:33:42 -07002380
Ed Tanous002d39b2022-05-31 08:59:27 -07002381 convertDBusToJSON("v", msg, propertyItem);
2382 });
Ed Tanous1656b292022-05-04 11:33:42 -07002383 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002384 property = property->NextSiblingElement("property");
2385 }
Ed Tanous1656b292022-05-04 11:33:42 -07002386 },
2387 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2388 "Introspect");
2389 }
2390 else
2391 {
2392 if (req.method() != boost::beast::http::verb::post)
2393 {
2394 asyncResp->res.result(boost::beast::http::status::not_found);
2395 return;
2396 }
2397
2398 nlohmann::json requestDbusData =
2399 nlohmann::json::parse(req.body, nullptr, false);
2400
2401 if (requestDbusData.is_discarded())
2402 {
2403 asyncResp->res.result(boost::beast::http::status::bad_request);
2404 return;
2405 }
2406 if (!requestDbusData.is_array())
2407 {
2408 asyncResp->res.result(boost::beast::http::status::bad_request);
2409 return;
2410 }
2411 auto transaction =
2412 std::make_shared<InProgressActionData>(asyncResp->res);
2413
2414 transaction->path = objectPath;
2415 transaction->methodName = methodName;
2416 transaction->arguments = std::move(requestDbusData);
2417
2418 findActionOnInterface(transaction, processName);
2419 }
2420}
2421
Ed Tanous23a21a12020-07-25 04:45:05 +00002422inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002423{
2424 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002425 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002426 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002427 [](const crow::Request&,
2428 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002429 nlohmann::json::array_t buses;
2430 nlohmann::json& bus = buses.emplace_back();
2431 bus["name"] = "system";
2432 asyncResp->res.jsonValue["busses"] = std::move(buses);
2433 asyncResp->res.jsonValue["status"] = "ok";
2434 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002435
2436 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002437 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002438 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002439 [](const crow::Request&,
2440 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002441 auto myCallback = [asyncResp](const boost::system::error_code ec,
zhanghch058d1b46d2021-04-01 11:18:24 +08002442 std::vector<std::string>& names) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002443 if (ec)
2444 {
2445 BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
2446 asyncResp->res.result(
2447 boost::beast::http::status::internal_server_error);
2448 }
2449 else
2450 {
2451 std::sort(names.begin(), names.end());
2452 asyncResp->res.jsonValue["status"] = "ok";
2453 auto& objectsSub = asyncResp->res.jsonValue["objects"];
Ed Tanous02cad962022-06-30 16:50:15 -07002454 for (const auto& name : names)
Ed Tanous002d39b2022-05-31 08:59:27 -07002455 {
2456 nlohmann::json::object_t object;
2457 object["name"] = name;
2458 objectsSub.push_back(std::move(object));
2459 }
2460 }
2461 };
2462 crow::connections::systemBus->async_method_call(
2463 std::move(myCallback), "org.freedesktop.DBus", "/",
2464 "org.freedesktop.DBus", "ListNames");
2465 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002466
2467 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002468 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002469 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002470 [](const crow::Request&,
2471 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002472 handleList(asyncResp, "/");
2473 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002474
2475 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002476 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002477 .methods(boost::beast::http::verb::get)(
2478 [](const crow::Request& req,
2479 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002480 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002481 std::string objectPath = "/xyz/" + path;
2482 handleDBusUrl(req, asyncResp, objectPath);
2483 });
zhanghch058d1b46d2021-04-01 11:18:24 +08002484
2485 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002486 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002487 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2488 boost::beast::http::verb::delete_)(
2489 [](const crow::Request& req,
2490 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2491 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002492 std::string objectPath = "/xyz/" + path;
2493 handleDBusUrl(req, asyncResp, objectPath);
2494 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002495
Ed Tanous049a0512018-11-01 13:58:42 -07002496 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002497 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002498 .methods(boost::beast::http::verb::get)(
2499 [](const crow::Request& req,
2500 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2501 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002502 std::string objectPath = "/org/" + path;
2503 handleDBusUrl(req, asyncResp, objectPath);
2504 });
Tanousf00032d2018-11-05 01:18:10 -03002505
2506 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002507 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002508 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2509 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002510 [](const crow::Request& req,
2511 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002512 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002513 std::string objectPath = "/org/" + path;
2514 handleDBusUrl(req, asyncResp, objectPath);
2515 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002516
Ed Tanous1abe55e2018-09-05 08:30:59 -07002517 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002518 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002519 .methods(boost::beast::http::verb::get)(
2520 [](const crow::Request&,
2521 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2522 const std::string& dumpId) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002523 if (!validateFilename(dumpId))
2524 {
2525 asyncResp->res.result(boost::beast::http::status::bad_request);
2526 return;
2527 }
2528 std::filesystem::path loc("/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002529
Ed Tanous002d39b2022-05-31 08:59:27 -07002530 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002531
Ed Tanous002d39b2022-05-31 08:59:27 -07002532 if (!std::filesystem::exists(loc) ||
2533 !std::filesystem::is_directory(loc))
2534 {
2535 BMCWEB_LOG_ERROR << loc.string() << "Not found";
2536 asyncResp->res.result(boost::beast::http::status::not_found);
2537 return;
2538 }
2539 std::filesystem::directory_iterator files(loc);
zhanghch058d1b46d2021-04-01 11:18:24 +08002540
Ed Tanous002d39b2022-05-31 08:59:27 -07002541 for (const auto& file : files)
2542 {
2543 std::ifstream readFile(file.path());
2544 if (!readFile.good())
2545 {
2546 continue;
2547 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002548
Ed Tanousd9f6c622022-03-17 09:12:17 -07002549 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07002550 "application/octet-stream");
zhanghch058d1b46d2021-04-01 11:18:24 +08002551
Ed Tanous002d39b2022-05-31 08:59:27 -07002552 // Assuming only one dump file will be present in the dump
2553 // id directory
2554 std::string dumpFileName = file.path().filename().string();
zhanghch058d1b46d2021-04-01 11:18:24 +08002555
Ed Tanous002d39b2022-05-31 08:59:27 -07002556 // Filename should be in alphanumeric, dot and underscore
2557 // Its based on phosphor-debug-collector application
2558 // dumpfile format
2559 std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
2560 if (!std::regex_match(dumpFileName, dumpFileRegex))
2561 {
2562 BMCWEB_LOG_ERROR << "Invalid dump filename " << dumpFileName;
zhanghch058d1b46d2021-04-01 11:18:24 +08002563 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002564 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07002565 }
2566 std::string contentDispositionParam =
2567 "attachment; filename=\"" + dumpFileName + "\"";
2568
Ed Tanousd9f6c622022-03-17 09:12:17 -07002569 asyncResp->res.addHeader(
2570 boost::beast::http::field::content_disposition,
2571 contentDispositionParam);
Ed Tanous002d39b2022-05-31 08:59:27 -07002572
2573 asyncResp->res.body() = {std::istreambuf_iterator<char>(readFile),
2574 std::istreambuf_iterator<char>()};
2575 return;
2576 }
2577 asyncResp->res.result(boost::beast::http::status::not_found);
2578 return;
2579 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002580
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002581 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002582 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002583
2584 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002585 [](const crow::Request&,
2586 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002587 const std::string& connection) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002588 introspectObjects(connection, "/", asyncResp);
2589 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002590
2591 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002592 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous1656b292022-05-04 11:33:42 -07002593 .methods(boost::beast::http::verb::get,
2594 boost::beast::http::verb::post)(handleBusSystemPost);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002595}
2596} // namespace openbmc_mapper
2597} // namespace crow