blob: c7dbb27c4eb648aed720fa3df3254bac2cc934df [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
George Liu7a1dbc42022-12-07 16:03:22 +080016#include "dbus_utility.hpp"
Nan Zhoud5c80ad2022-07-11 01:16:31 +000017#include "http_request.hpp"
18#include "http_response.hpp"
19#include "logging.hpp"
20#include "routing.hpp"
21
22#include <systemd/sd-bus-protocol.h>
23#include <systemd/sd-bus.h>
Ed Tanous911ac312017-08-15 09:37:42 -070024#include <tinyxml2.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -070025
Ed Tanous04e438c2020-10-03 08:06:26 -070026#include <app.hpp>
Ed Tanouse3cb5a32018-08-08 14:16:49 -070027#include <async_resp.hpp>
Ed Tanous11ba3972022-07-11 09:50:41 -070028#include <boost/algorithm/string/classification.hpp>
29#include <boost/algorithm/string/predicate.hpp>
30#include <boost/algorithm/string/split.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000031#include <boost/beast/http/status.hpp>
32#include <boost/beast/http/verb.hpp>
33#include <boost/container/flat_map.hpp>
34#include <boost/container/vector.hpp>
35#include <boost/iterator/iterator_facade.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -070036#include <dbus_singleton.hpp>
James Feist5b4aa862018-08-16 14:07:01 -070037#include <dbus_utility.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000038#include <nlohmann/json.hpp>
39#include <sdbusplus/asio/connection.hpp>
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +020040#include <sdbusplus/asio/property.hpp>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000041#include <sdbusplus/exception.hpp>
42#include <sdbusplus/message.hpp>
43#include <sdbusplus/message/native_types.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050044
Nan Zhoud5c80ad2022-07-11 01:16:31 +000045#include <algorithm>
46#include <array>
47#include <cerrno>
48#include <cstdint>
49#include <cstring>
James Feist4418c7f2019-04-15 11:09:15 -070050#include <filesystem>
Ed Tanousd4bb9bb2018-05-16 13:36:42 -070051#include <fstream>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000052#include <functional>
53#include <initializer_list>
54#include <iterator>
55#include <limits>
56#include <map>
57#include <memory>
Ramesh Iyyard9207042019-07-05 08:04:42 -050058#include <regex>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000059#include <string>
60#include <string_view>
61#include <type_traits>
Ed Tanousb5a76932020-09-29 16:16:58 -070062#include <utility>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000063#include <variant>
64#include <vector>
65
66// IWYU pragma: no_include <boost/algorithm/string/detail/classification.hpp>
67// IWYU pragma: no_include <boost/system/detail/error_code.hpp>
68// IWYU pragma: no_include <boost/system/detail/error_category.hpp>
69// IWYU pragma: no_include <errno.h>
70// IWYU pragma: no_include <string.h>
71// IWYU pragma: no_include <ext/alloc_traits.h>
72// IWYU pragma: no_include <exception>
73// IWYU pragma: no_include <boost/type_index/type_index_facade.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -070074
Ed Tanous1abe55e2018-09-05 08:30:59 -070075namespace crow
76{
77namespace openbmc_mapper
78{
Ed Tanous23a21a12020-07-25 04:45:05 +000079const constexpr char* notFoundMsg = "404 Not Found";
80const constexpr char* badReqMsg = "400 Bad Request";
81const constexpr char* methodNotAllowedMsg = "405 Method Not Allowed";
82const constexpr char* forbiddenMsg = "403 Forbidden";
83const constexpr char* methodFailedMsg = "500 Method Call Failed";
84const constexpr char* methodOutputFailedMsg = "500 Method Output Error";
85const constexpr char* notFoundDesc =
Matt Spinler2ae60092018-12-06 10:35:36 -060086 "org.freedesktop.DBus.Error.FileNotFound: path or object not found";
Ed Tanous23a21a12020-07-25 04:45:05 +000087const constexpr char* propNotFoundDesc =
88 "The specified property cannot be found";
89const constexpr char* noJsonDesc = "No JSON object could be decoded";
90const constexpr char* methodNotFoundDesc =
91 "The specified method cannot be found";
92const constexpr char* methodNotAllowedDesc = "Method not allowed";
93const constexpr char* forbiddenPropDesc =
94 "The specified property cannot be created";
95const constexpr char* forbiddenResDesc =
96 "The specified resource cannot be created";
Matt Spinler2ae60092018-12-06 10:35:36 -060097
Josh Lehan482c45a2022-03-29 17:10:44 -070098inline bool validateFilename(const std::string& filename)
99{
100 std::regex validFilename(R"(^[\w\- ]+(\.?[\w\- ]*)$)");
101
102 return std::regex_match(filename, validFilename);
103}
104
Ed Tanous23a21a12020-07-25 04:45:05 +0000105inline void setErrorResponse(crow::Response& res,
106 boost::beast::http::status result,
107 const std::string& desc,
108 const std::string_view msg)
Matt Spinler2ae60092018-12-06 10:35:36 -0600109{
110 res.result(result);
Ed Tanous14766872022-03-15 10:44:42 -0700111 res.jsonValue["data"]["description"] = desc;
112 res.jsonValue["message"] = msg;
113 res.jsonValue["status"] = "error";
Matt Spinler2ae60092018-12-06 10:35:36 -0600114}
115
Ed Tanousb5a76932020-09-29 16:16:58 -0700116inline void
117 introspectObjects(const std::string& processName,
118 const std::string& objectPath,
119 const std::shared_ptr<bmcweb::AsyncResp>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700120{
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700121 if (transaction->res.jsonValue.is_null())
122 {
Ed Tanous14766872022-03-15 10:44:42 -0700123 transaction->res.jsonValue["status"] = "ok";
124 transaction->res.jsonValue["bus_name"] = processName;
125 transaction->res.jsonValue["objects"] = nlohmann::json::array();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700126 }
127
Ed Tanous1abe55e2018-09-05 08:30:59 -0700128 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700129 [transaction, processName{std::string(processName)},
130 objectPath{std::string(objectPath)}](
131 const boost::system::error_code ec,
Ed Tanous81ce6092020-12-17 16:54:55 +0000132 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700133 if (ec)
134 {
135 BMCWEB_LOG_ERROR
136 << "Introspect call failed with error: " << ec.message()
137 << " on process: " << processName << " path: " << objectPath
138 << "\n";
139 return;
140 }
141 nlohmann::json::object_t object;
142 object["path"] = objectPath;
Ed Tanous14766872022-03-15 10:44:42 -0700143
Ed Tanous002d39b2022-05-31 08:59:27 -0700144 transaction->res.jsonValue["objects"].push_back(std::move(object));
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700145
Ed Tanous002d39b2022-05-31 08:59:27 -0700146 tinyxml2::XMLDocument doc;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700147
Ed Tanous002d39b2022-05-31 08:59:27 -0700148 doc.Parse(introspectXml.c_str());
149 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
150 if (pRoot == nullptr)
151 {
152 BMCWEB_LOG_ERROR << "XML document failed to parse " << processName
153 << " " << objectPath << "\n";
154 }
155 else
156 {
157 tinyxml2::XMLElement* node = pRoot->FirstChildElement("node");
158 while (node != nullptr)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700159 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700160 const char* childPath = node->Attribute("name");
161 if (childPath != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700162 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700163 std::string newpath;
164 if (objectPath != "/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700165 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700166 newpath += objectPath;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700167 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700168 newpath += std::string("/") + childPath;
169 // introspect the subobjects as well
170 introspectObjects(processName, newpath, transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700171 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700172
173 node = node->NextSiblingElement("node");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700174 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700175 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700176 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700177 processName, objectPath, "org.freedesktop.DBus.Introspectable",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700178 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -0700179}
Ed Tanous64530012018-02-06 17:08:16 -0800180
Ed Tanous23a21a12020-07-25 04:45:05 +0000181inline void getPropertiesForEnumerate(
182 const std::string& objectPath, const std::string& service,
Ed Tanousb5a76932020-09-29 16:16:58 -0700183 const std::string& interface,
184 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600185{
186 BMCWEB_LOG_DEBUG << "getPropertiesForEnumerate " << objectPath << " "
187 << service << " " << interface;
188
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +0200189 sdbusplus::asio::getAllProperties(
190 *crow::connections::systemBus, service, objectPath, interface,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800191 [asyncResp, objectPath, service,
192 interface](const boost::system::error_code ec,
193 const dbus::utility::DBusPropertiesMap& propertiesList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700194 if (ec)
195 {
196 BMCWEB_LOG_ERROR << "GetAll on path " << objectPath << " iface "
197 << interface << " service " << service
198 << " failed with code " << ec;
199 return;
200 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600201
Ed Tanous002d39b2022-05-31 08:59:27 -0700202 nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
203 nlohmann::json& objectJson = dataJson[objectPath];
204 if (objectJson.is_null())
205 {
206 objectJson = nlohmann::json::object();
207 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600208
Ed Tanous002d39b2022-05-31 08:59:27 -0700209 for (const auto& [name, value] : propertiesList)
210 {
211 nlohmann::json& propertyJson = objectJson[name];
212 std::visit(
213 [&propertyJson](auto&& val) {
214 if constexpr (std::is_same_v<std::decay_t<decltype(val)>,
215 sdbusplus::message::unix_fd>)
216 {
217 propertyJson = val.fd;
218 }
219 else
220 {
Ed Tanousd1a64812021-12-13 12:14:05 -0800221
Ed Tanous002d39b2022-05-31 08:59:27 -0700222 propertyJson = val;
223 }
224 },
225 value);
226 }
Krzysztof Grobelnyc1343bf2022-08-31 13:15:26 +0200227 });
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600228}
229
230// Find any results that weren't picked up by ObjectManagers, to be
231// called after all ObjectManagers are searched for and called.
Ed Tanous23a21a12020-07-25 04:45:05 +0000232inline void findRemainingObjectsForEnumerate(
Ed Tanousb5a76932020-09-29 16:16:58 -0700233 const std::string& objectPath,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800234 const std::shared_ptr<dbus::utility::MapperGetSubTreeResponse>& subtree,
Ed Tanousb5a76932020-09-29 16:16:58 -0700235 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600236{
237 BMCWEB_LOG_DEBUG << "findRemainingObjectsForEnumerate";
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500238 const nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600239
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500240 for (const auto& [path, interface_map] : *subtree)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600241 {
242 if (path == objectPath)
243 {
244 // An enumerate does not return the target path's properties
245 continue;
246 }
247 if (dataJson.find(path) == dataJson.end())
248 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500249 for (const auto& [service, interfaces] : interface_map)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600250 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500251 for (const auto& interface : interfaces)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600252 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700253 if (!interface.starts_with("org.freedesktop.DBus"))
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600254 {
255 getPropertiesForEnumerate(path, service, interface,
256 asyncResp);
257 }
258 }
259 }
260 }
261 }
262}
263
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600264struct InProgressEnumerateData
265{
zhanghch058d1b46d2021-04-01 11:18:24 +0800266 InProgressEnumerateData(
267 const std::string& objectPathIn,
268 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
Ed Tanous23a21a12020-07-25 04:45:05 +0000269 objectPath(objectPathIn),
zhanghch058d1b46d2021-04-01 11:18:24 +0800270 asyncResp(asyncRespIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500271 {}
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600272
273 ~InProgressEnumerateData()
274 {
Ed Tanous24b2fe82022-01-06 12:45:54 -0800275 try
276 {
277 findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
278 }
279 catch (...)
280 {
281 BMCWEB_LOG_CRITICAL
282 << "findRemainingObjectsForEnumerate threw exception";
283 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600284 }
285
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800286 InProgressEnumerateData(const InProgressEnumerateData&) = delete;
287 InProgressEnumerateData(InProgressEnumerateData&&) = delete;
288 InProgressEnumerateData& operator=(const InProgressEnumerateData&) = delete;
289 InProgressEnumerateData& operator=(InProgressEnumerateData&&) = delete;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600290 const std::string objectPath;
Ed Tanousb9d36b42022-02-26 21:42:46 -0800291 std::shared_ptr<dbus::utility::MapperGetSubTreeResponse> subtree;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600292 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
293};
294
Ed Tanous23a21a12020-07-25 04:45:05 +0000295inline void getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000296 const std::string& objectName, const std::string& objectManagerPath,
297 const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700298 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700299{
Ed Tanous81ce6092020-12-17 16:54:55 +0000300 BMCWEB_LOG_DEBUG << "getManagedObjectsForEnumerate " << objectName
301 << " object_manager_path " << objectManagerPath
302 << " connection_name " << connectionName;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700303 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000304 [transaction, objectName,
305 connectionName](const boost::system::error_code ec,
306 const dbus::utility::ManagedObjectType& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700307 if (ec)
308 {
309 BMCWEB_LOG_ERROR << "GetManagedObjects on path " << objectName
310 << " on connection " << connectionName
311 << " failed with code " << ec;
312 return;
313 }
Ed Tanous64530012018-02-06 17:08:16 -0800314
Ed Tanous002d39b2022-05-31 08:59:27 -0700315 nlohmann::json& dataJson =
316 transaction->asyncResp->res.jsonValue["data"];
Ed Tanous049a0512018-11-01 13:58:42 -0700317
Ed Tanous002d39b2022-05-31 08:59:27 -0700318 for (const auto& objectPath : objects)
319 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700320 if (objectPath.first.str.starts_with(objectName))
Ed Tanous049a0512018-11-01 13:58:42 -0700321 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700322 BMCWEB_LOG_DEBUG << "Reading object " << objectPath.first.str;
323 nlohmann::json& objectJson = dataJson[objectPath.first.str];
324 if (objectJson.is_null())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700325 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700326 objectJson = nlohmann::json::object();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700327 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500328 for (const auto& interface : objectPath.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700329 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700330 for (const auto& property : interface.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700331 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700332 nlohmann::json& propertyJson =
333 objectJson[property.first];
334 std::visit(
335 [&propertyJson](auto&& val) {
336 if constexpr (std::is_same_v<
337 std::decay_t<decltype(val)>,
338 sdbusplus::message::unix_fd>)
339 {
340 propertyJson = val.fd;
341 }
342 else
343 {
344
345 propertyJson = val;
346 }
347 },
348 property.second);
Ed Tanous049a0512018-11-01 13:58:42 -0700349 }
350 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700351 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700352 for (const auto& interface : objectPath.second)
353 {
354 if (interface.first == "org.freedesktop.DBus.ObjectManager")
355 {
356 getManagedObjectsForEnumerate(objectPath.first.str,
357 objectPath.first.str,
358 connectionName, transaction);
359 }
360 }
361 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700362 },
Ed Tanous81ce6092020-12-17 16:54:55 +0000363 connectionName, objectManagerPath, "org.freedesktop.DBus.ObjectManager",
364 "GetManagedObjects");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700365}
366
Ed Tanous23a21a12020-07-25 04:45:05 +0000367inline void findObjectManagerPathForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000368 const std::string& objectName, const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700369 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700370{
Ed Tanous81ce6092020-12-17 16:54:55 +0000371 BMCWEB_LOG_DEBUG << "Finding objectmanager for path " << objectName
372 << " on connection:" << connectionName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700373 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000374 [transaction, objectName, connectionName](
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700375 const boost::system::error_code ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800376 const dbus::utility::MapperGetAncestorsResponse& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700377 if (ec)
378 {
379 BMCWEB_LOG_ERROR << "GetAncestors on path " << objectName
380 << " failed with code " << ec;
381 return;
382 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700383
Ed Tanous002d39b2022-05-31 08:59:27 -0700384 for (const auto& pathGroup : objects)
385 {
386 for (const auto& connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700387 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700388 if (connectionGroup.first == connectionName)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700389 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700390 // Found the object manager path for this resource.
391 getManagedObjectsForEnumerate(objectName, pathGroup.first,
392 connectionName, transaction);
393 return;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700394 }
395 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700396 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700397 },
398 "xyz.openbmc_project.ObjectMapper",
399 "/xyz/openbmc_project/object_mapper",
Ed Tanous81ce6092020-12-17 16:54:55 +0000400 "xyz.openbmc_project.ObjectMapper", "GetAncestors", objectName,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500401 std::array<const char*, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700402}
Ed Tanous64530012018-02-06 17:08:16 -0800403
Ed Tanous7c091622019-05-23 11:42:36 -0700404// Uses GetObject to add the object info about the target /enumerate path to
405// the results of GetSubTree, as GetSubTree will not return info for the
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600406// target path, and then continues on enumerating the rest of the tree.
Ed Tanousb5a76932020-09-29 16:16:58 -0700407inline void getObjectAndEnumerate(
408 const std::shared_ptr<InProgressEnumerateData>& transaction)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600409{
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600410 crow::connections::systemBus->async_method_call(
411 [transaction](const boost::system::error_code ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800412 const dbus::utility::MapperGetObject& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700413 if (ec)
414 {
415 BMCWEB_LOG_ERROR << "GetObject for path " << transaction->objectPath
416 << " failed with code " << ec;
417 return;
418 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600419
Ed Tanous002d39b2022-05-31 08:59:27 -0700420 BMCWEB_LOG_DEBUG << "GetObject for " << transaction->objectPath
421 << " has " << objects.size() << " entries";
422 if (!objects.empty())
423 {
424 transaction->subtree->emplace_back(transaction->objectPath,
425 objects);
426 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600427
Ed Tanous002d39b2022-05-31 08:59:27 -0700428 // Map indicating connection name, and the path where the object
429 // manager exists
430 boost::container::flat_map<std::string, std::string> connections;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600431
Ed Tanous002d39b2022-05-31 08:59:27 -0700432 for (const auto& object : *(transaction->subtree))
433 {
434 for (const auto& connection : object.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600435 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700436 for (const auto& interface : connection.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600437 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700438 BMCWEB_LOG_DEBUG << connection.first << " has interface "
439 << interface;
440 if (interface == "org.freedesktop.DBus.ObjectManager")
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600441 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700442 BMCWEB_LOG_DEBUG << "found object manager path "
443 << object.first;
Ed Tanousf8fe53e2022-06-30 15:55:45 -0700444 connections[connection.first] = object.first;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600445 }
446 }
447 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700448 }
449 BMCWEB_LOG_DEBUG << "Got " << connections.size() << " connections";
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600450
Ed Tanous002d39b2022-05-31 08:59:27 -0700451 for (const auto& connection : connections)
452 {
453 // If we already know where the object manager is, we don't
454 // need to search for it, we can call directly in to
455 // getManagedObjects
456 if (!connection.second.empty())
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600457 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700458 getManagedObjectsForEnumerate(transaction->objectPath,
459 connection.second,
460 connection.first, transaction);
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600461 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700462 else
463 {
464 // otherwise we need to find the object manager path
465 // before we can continue
466 findObjectManagerPathForEnumerate(
467 transaction->objectPath, connection.first, transaction);
468 }
469 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600470 },
471 "xyz.openbmc_project.ObjectMapper",
472 "/xyz/openbmc_project/object_mapper",
473 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500474 transaction->objectPath, std::array<const char*, 0>());
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600475}
Ed Tanous64530012018-02-06 17:08:16 -0800476
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700477// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700478struct InProgressActionData
479{
Ed Tanous4e23a442022-06-06 09:57:26 -0700480 explicit InProgressActionData(crow::Response& resIn) : res(resIn)
Ed Tanous23a21a12020-07-25 04:45:05 +0000481 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700482 ~InProgressActionData()
483 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600484 // Methods could have been called across different owners
485 // and interfaces, where some calls failed and some passed.
486 //
487 // The rules for this are:
488 // * if no method was called - error
489 // * if a method failed and none passed - error
490 // (converse: if at least one method passed - OK)
491 // * for the method output:
492 // * if output processing didn't fail, return the data
493
494 // Only deal with method returns if nothing failed earlier
495 if (res.result() == boost::beast::http::status::ok)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700496 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600497 if (!methodPassed)
498 {
Matt Spinler06b1b632019-06-18 16:09:25 -0500499 if (!methodFailed)
Matt Spinler16caaee2019-01-15 11:40:34 -0600500 {
501 setErrorResponse(res, boost::beast::http::status::not_found,
502 methodNotFoundDesc, notFoundMsg);
503 }
504 }
505 else
506 {
507 if (outputFailed)
508 {
509 setErrorResponse(
510 res, boost::beast::http::status::internal_server_error,
511 "Method output failure", methodOutputFailedMsg);
512 }
513 else
514 {
Ed Tanous14766872022-03-15 10:44:42 -0700515 res.jsonValue["status"] = "ok";
516 res.jsonValue["message"] = "200 OK";
517 res.jsonValue["data"] = methodResponse;
Matt Spinler16caaee2019-01-15 11:40:34 -0600518 }
519 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700520 }
Matt Spinler16caaee2019-01-15 11:40:34 -0600521
Ed Tanous1abe55e2018-09-05 08:30:59 -0700522 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700523 }
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800524 InProgressActionData(const InProgressActionData&) = delete;
525 InProgressActionData(InProgressActionData&&) = delete;
526 InProgressActionData& operator=(const InProgressActionData&) = delete;
527 InProgressActionData& operator=(InProgressActionData&&) = delete;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700528
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500529 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700530 {
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600531 setErrorResponse(res, boost::beast::http::status::bad_request, desc,
532 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700533 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500534 crow::Response& res;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700535 std::string path;
536 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600537 std::string interfaceName;
Matt Spinler16caaee2019-01-15 11:40:34 -0600538 bool methodPassed = false;
539 bool methodFailed = false;
540 bool outputFailed = false;
Matt Spinler39a4e392019-01-15 11:53:13 -0600541 bool convertedToArray = false;
Matt Spinler16caaee2019-01-15 11:40:34 -0600542 nlohmann::json methodResponse;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700543 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700544};
545
Ed Tanous23a21a12020-07-25 04:45:05 +0000546inline std::vector<std::string> dbusArgSplit(const std::string& string)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700547{
548 std::vector<std::string> ret;
549 if (string.empty())
550 {
551 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700552 }
Ed Tanous0f0353b2019-10-24 11:37:51 -0700553 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700554 int containerDepth = 0;
555
556 for (std::string::const_iterator character = string.begin();
557 character != string.end(); character++)
558 {
559 ret.back() += *character;
560 switch (*character)
561 {
562 case ('a'):
563 break;
564 case ('('):
565 case ('{'):
566 containerDepth++;
567 break;
568 case ('}'):
569 case (')'):
570 containerDepth--;
571 if (containerDepth == 0)
572 {
573 if (character + 1 != string.end())
574 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700575 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700576 }
577 }
578 break;
579 default:
580 if (containerDepth == 0)
581 {
582 if (character + 1 != string.end())
583 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700584 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700585 }
586 }
587 break;
588 }
589 }
Matt Spinler4ae611d2019-01-11 15:37:06 -0600590
591 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700592}
593
Ed Tanous81ce6092020-12-17 16:54:55 +0000594inline int convertJsonToDbus(sd_bus_message* m, const std::string& argType,
595 const nlohmann::json& inputJson)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700596{
597 int r = 0;
Ed Tanous71f52d92021-02-19 08:51:17 -0800598 BMCWEB_LOG_DEBUG << "Converting "
599 << inputJson.dump(2, ' ', true,
600 nlohmann::json::error_handler_t::replace)
Ed Tanous81ce6092020-12-17 16:54:55 +0000601 << " to type: " << argType;
602 const std::vector<std::string> argTypes = dbusArgSplit(argType);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700603
Ed Tanous1abe55e2018-09-05 08:30:59 -0700604 // Assume a single object for now.
Ed Tanous81ce6092020-12-17 16:54:55 +0000605 const nlohmann::json* j = &inputJson;
606 nlohmann::json::const_iterator jIt = inputJson.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700607
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500608 for (const std::string& argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700609 {
610 // If we are decoding multiple objects, grab the pointer to the
611 // iterator, and increment it for the next loop
612 if (argTypes.size() > 1)
613 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000614 if (jIt == inputJson.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700615 {
616 return -2;
617 }
618 j = &*jIt;
619 jIt++;
620 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500621 const int64_t* intValue = j->get_ptr<const int64_t*>();
622 const std::string* stringValue = j->get_ptr<const std::string*>();
623 const double* doubleValue = j->get_ptr<const double*>();
624 const bool* b = j->get_ptr<const bool*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700625 int64_t v = 0;
626 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700627
Ed Tanous1abe55e2018-09-05 08:30:59 -0700628 // Do some basic type conversions that make sense. uint can be
629 // converted to int. int and uint can be converted to double
Ed Tanous66664f22019-10-11 13:05:49 -0700630 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700631 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500632 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700633 if (uintValue != nullptr)
634 {
635 v = static_cast<int64_t>(*uintValue);
636 intValue = &v;
637 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700638 }
Ed Tanous66664f22019-10-11 13:05:49 -0700639 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700640 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500641 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700642 if (uintValue != nullptr)
643 {
644 d = static_cast<double>(*uintValue);
645 doubleValue = &d;
646 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700647 }
Ed Tanous66664f22019-10-11 13:05:49 -0700648 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700649 {
Ed Tanous66664f22019-10-11 13:05:49 -0700650 if (intValue != nullptr)
651 {
652 d = static_cast<double>(*intValue);
653 doubleValue = &d;
654 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700655 }
656
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700657 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700658 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700659 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700660 {
661 return -1;
662 }
Ed Tanous271584a2019-07-09 16:24:22 -0700663 r = sd_bus_message_append_basic(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500664 m, argCode[0], static_cast<const void*>(stringValue->data()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700665 if (r < 0)
666 {
667 return r;
668 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700669 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700670 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700671 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700672 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700673 {
674 return -1;
675 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500676 if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
677 (*intValue > std::numeric_limits<int32_t>::max()))
678 {
679 return -ERANGE;
680 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700681 int32_t i = static_cast<int32_t>(*intValue);
682 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700683 if (r < 0)
684 {
685 return r;
686 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700687 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700688 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700689 {
690 // lots of ways bool could be represented here. Try them all
Ed Tanouse662eae2022-01-25 10:39:19 -0800691 int boolInt = 0;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700692 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700693 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500694 if (*intValue == 1)
695 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800696 boolInt = 1;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500697 }
698 else if (*intValue == 0)
699 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800700 boolInt = 0;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500701 }
702 else
703 {
704 return -ERANGE;
705 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700706 }
707 else if (b != nullptr)
708 {
Matt Spinlera2f02632019-01-18 10:15:35 -0600709 boolInt = *b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700710 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700711 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700712 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700713 boolInt = boost::istarts_with(*stringValue, "t") ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700714 }
715 else
716 {
717 return -1;
718 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700719 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700720 if (r < 0)
721 {
722 return r;
723 }
724 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700725 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700726 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700727 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700728 {
729 return -1;
730 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500731 if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
732 (*intValue > std::numeric_limits<int16_t>::max()))
733 {
734 return -ERANGE;
735 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700736 int16_t n = static_cast<int16_t>(*intValue);
737 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700738 if (r < 0)
739 {
740 return r;
741 }
742 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700743 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700744 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700745 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700746 {
747 return -1;
748 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700749 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700750 if (r < 0)
751 {
752 return r;
753 }
754 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700755 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700756 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500757 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700758 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700759 {
760 return -1;
761 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000762 if (*uintValue > std::numeric_limits<uint8_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500763 {
764 return -ERANGE;
765 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700766 uint8_t y = static_cast<uint8_t>(*uintValue);
767 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700768 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700769 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700770 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500771 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700772 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700773 {
774 return -1;
775 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000776 if (*uintValue > std::numeric_limits<uint16_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500777 {
778 return -ERANGE;
779 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700780 uint16_t q = static_cast<uint16_t>(*uintValue);
781 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700782 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700783 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700784 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500785 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700786 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700787 {
788 return -1;
789 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000790 if (*uintValue > std::numeric_limits<uint32_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500791 {
792 return -ERANGE;
793 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700794 uint32_t u = static_cast<uint32_t>(*uintValue);
795 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700796 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700797 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700798 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500799 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700800 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700801 {
802 return -1;
803 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700804 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700805 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700806 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700807 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500808 if (doubleValue == nullptr)
809 {
810 return -1;
811 }
812 if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
813 (*doubleValue > std::numeric_limits<double>::max()))
814 {
815 return -ERANGE;
816 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700817 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700818 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700819 else if (argCode.starts_with("a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700820 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700821 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700822 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700823 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700824 if (r < 0)
825 {
826 return r;
827 }
828
Ed Tanous0dfeda62019-10-24 11:21:38 -0700829 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700830 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700831 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700832 if (r < 0)
833 {
834 return r;
835 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700836 }
837 sd_bus_message_close_container(m);
838 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700839 else if (argCode.starts_with("v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700840 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700841 std::string containedType = argCode.substr(1);
842 BMCWEB_LOG_DEBUG << "variant type: " << argCode
843 << " appending variant of type: " << containedType;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700844 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700845 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700846 if (r < 0)
847 {
848 return r;
849 }
850
Ed Tanous81ce6092020-12-17 16:54:55 +0000851 r = convertJsonToDbus(m, containedType, inputJson);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700852 if (r < 0)
853 {
854 return r;
855 }
856
857 r = sd_bus_message_close_container(m);
858 if (r < 0)
859 {
860 return r;
861 }
862 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700863 else if (argCode.starts_with("(") && argCode.ends_with(")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700864 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700865 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700866 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700867 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800868 if (r < 0)
869 {
870 return r;
871 }
872
Ed Tanous1abe55e2018-09-05 08:30:59 -0700873 nlohmann::json::const_iterator it = j->begin();
Ed Tanous81ce6092020-12-17 16:54:55 +0000874 for (const std::string& argCode2 : dbusArgSplit(argType))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700875 {
876 if (it == j->end())
877 {
878 return -1;
879 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000880 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700881 if (r < 0)
882 {
883 return r;
884 }
885 it++;
886 }
887 r = sd_bus_message_close_container(m);
888 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700889 else if (argCode.starts_with("{") && argCode.ends_with("}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700890 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700891 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700892 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700893 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800894 if (r < 0)
895 {
896 return r;
897 }
898
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700899 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700900 if (codes.size() != 2)
901 {
902 return -1;
903 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700904 const std::string& keyType = codes[0];
905 const std::string& valueType = codes[1];
Ed Tanous3174e4d2020-10-07 11:41:22 -0700906 for (const auto& it : j->items())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700907 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700908 r = convertJsonToDbus(m, keyType, it.key());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700909 if (r < 0)
910 {
911 return r;
912 }
913
Ed Tanous2c70f802020-09-28 14:29:23 -0700914 r = convertJsonToDbus(m, valueType, it.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700915 if (r < 0)
916 {
917 return r;
918 }
919 }
920 r = sd_bus_message_close_container(m);
921 }
922 else
923 {
924 return -2;
925 }
926 if (r < 0)
927 {
928 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700929 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700930
Ed Tanous1abe55e2018-09-05 08:30:59 -0700931 if (argTypes.size() > 1)
932 {
933 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700934 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700935 }
Matt Spinler127ea542019-01-14 11:04:28 -0600936
937 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700938}
939
Matt Spinlerd22a7132019-01-14 12:14:30 -0600940template <typename T>
Patrick Williams59d494e2022-07-22 19:26:55 -0500941int readMessageItem(const std::string& typeCode, sdbusplus::message_t& m,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500942 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600943{
944 T value;
945
946 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
947 if (r < 0)
948 {
949 BMCWEB_LOG_ERROR << "sd_bus_message_read_basic on type " << typeCode
950 << " failed!";
951 return r;
952 }
953
954 data = value;
955 return 0;
956}
957
Patrick Williams59d494e2022-07-22 19:26:55 -0500958int convertDBusToJSON(const std::string& returnType, sdbusplus::message_t& m,
959 nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600960
Ed Tanous23a21a12020-07-25 04:45:05 +0000961inline int readDictEntryFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -0500962 sdbusplus::message_t& m,
Ed Tanous23a21a12020-07-25 04:45:05 +0000963 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600964{
965 std::vector<std::string> types = dbusArgSplit(typeCode);
966 if (types.size() != 2)
967 {
968 BMCWEB_LOG_ERROR << "wrong number contained types in dictionary: "
969 << types.size();
970 return -1;
971 }
972
973 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
974 typeCode.c_str());
975 if (r < 0)
976 {
977 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container with rc " << r;
978 return r;
979 }
980
981 nlohmann::json key;
982 r = convertDBusToJSON(types[0], m, key);
983 if (r < 0)
984 {
985 return r;
986 }
987
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500988 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -0600989 if (keyPtr == nullptr)
990 {
991 // json doesn't support non-string keys. If we hit this condition,
992 // convert the result to a string so we can proceed
Ed Tanous71f52d92021-02-19 08:51:17 -0800993 key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500994 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -0700995 // in theory this can't fail now, but lets be paranoid about it
996 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -0600997 if (keyPtr == nullptr)
998 {
999 return -1;
1000 }
1001 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001002 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -06001003
1004 r = convertDBusToJSON(types[1], m, value);
1005 if (r < 0)
1006 {
1007 return r;
1008 }
1009
1010 r = sd_bus_message_exit_container(m.get());
1011 if (r < 0)
1012 {
1013 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1014 return r;
1015 }
1016
1017 return 0;
1018}
1019
Ed Tanous23a21a12020-07-25 04:45:05 +00001020inline int readArrayFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001021 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -06001022{
1023 if (typeCode.size() < 2)
1024 {
1025 BMCWEB_LOG_ERROR << "Type code " << typeCode
1026 << " too small for an array";
1027 return -1;
1028 }
1029
1030 std::string containedType = typeCode.substr(1);
1031
1032 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
1033 containedType.c_str());
1034 if (r < 0)
1035 {
1036 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1037 << r;
1038 return r;
1039 }
1040
Ed Tanous11ba3972022-07-11 09:50:41 -07001041 bool dict = containedType.starts_with("{") && containedType.ends_with("}");
Matt Spinler6df8f992019-01-14 12:47:47 -06001042
1043 if (dict)
1044 {
1045 // Remove the { }
1046 containedType = containedType.substr(1, containedType.size() - 2);
1047 data = nlohmann::json::object();
1048 }
1049 else
1050 {
1051 data = nlohmann::json::array();
1052 }
1053
1054 while (true)
1055 {
Ed Tanouse662eae2022-01-25 10:39:19 -08001056 r = sd_bus_message_at_end(m.get(), 0);
Matt Spinler6df8f992019-01-14 12:47:47 -06001057 if (r < 0)
1058 {
1059 BMCWEB_LOG_ERROR << "sd_bus_message_at_end failed";
1060 return r;
1061 }
1062
1063 if (r > 0)
1064 {
1065 break;
1066 }
1067
1068 // Dictionaries are only ever seen in an array
1069 if (dict)
1070 {
1071 r = readDictEntryFromMessage(containedType, m, data);
1072 if (r < 0)
1073 {
1074 return r;
1075 }
1076 }
1077 else
1078 {
1079 data.push_back(nlohmann::json());
1080
1081 r = convertDBusToJSON(containedType, m, data.back());
1082 if (r < 0)
1083 {
1084 return r;
1085 }
1086 }
1087 }
1088
1089 r = sd_bus_message_exit_container(m.get());
1090 if (r < 0)
1091 {
1092 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1093 return r;
1094 }
1095
1096 return 0;
1097}
1098
Ed Tanous23a21a12020-07-25 04:45:05 +00001099inline int readStructFromMessage(const std::string& typeCode,
Patrick Williams59d494e2022-07-22 19:26:55 -05001100 sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001101{
1102 if (typeCode.size() < 3)
1103 {
1104 BMCWEB_LOG_ERROR << "Type code " << typeCode
1105 << " too small for a struct";
1106 return -1;
1107 }
1108
1109 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1110 std::vector<std::string> types = dbusArgSplit(containedTypes);
1111
1112 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1113 containedTypes.c_str());
1114 if (r < 0)
1115 {
1116 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1117 << r;
1118 return r;
1119 }
1120
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001121 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001122 {
1123 data.push_back(nlohmann::json());
1124 r = convertDBusToJSON(type, m, data.back());
1125 if (r < 0)
1126 {
1127 return r;
1128 }
1129 }
1130
1131 r = sd_bus_message_exit_container(m.get());
1132 if (r < 0)
1133 {
1134 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1135 return r;
1136 }
1137 return 0;
1138}
1139
Patrick Williams59d494e2022-07-22 19:26:55 -05001140inline int readVariantFromMessage(sdbusplus::message_t& m, nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001141{
Ed Tanous543f4402022-01-06 13:12:53 -08001142 const char* containerType = nullptr;
Ed Tanous99131cd2019-10-24 11:12:47 -07001143 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001144 if (r < 0)
1145 {
1146 BMCWEB_LOG_ERROR << "sd_bus_message_peek_type failed";
1147 return r;
1148 }
1149
1150 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1151 containerType);
1152 if (r < 0)
1153 {
1154 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1155 << r;
1156 return r;
1157 }
1158
1159 r = convertDBusToJSON(containerType, m, data);
1160 if (r < 0)
1161 {
1162 return r;
1163 }
1164
1165 r = sd_bus_message_exit_container(m.get());
1166 if (r < 0)
1167 {
1168 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed";
1169 return r;
1170 }
1171
1172 return 0;
1173}
1174
Ed Tanous23a21a12020-07-25 04:45:05 +00001175inline int convertDBusToJSON(const std::string& returnType,
Patrick Williams59d494e2022-07-22 19:26:55 -05001176 sdbusplus::message_t& m, nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001177{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001178 int r = 0;
1179 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1180
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001181 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001182 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001183 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001184 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001185 {
1186 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001187 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001188 }
1189
Ed Tanousd4d25792020-09-29 15:15:03 -07001190 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001191 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001192 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001193 if (r < 0)
1194 {
1195 return r;
1196 }
1197 }
1198 else if (typeCode == "b")
1199 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001200 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001201 if (r < 0)
1202 {
1203 return r;
1204 }
1205
Matt Spinlerf39420c2019-01-30 12:57:18 -06001206 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001207 }
1208 else if (typeCode == "u")
1209 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001210 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001211 if (r < 0)
1212 {
1213 return r;
1214 }
1215 }
1216 else if (typeCode == "i")
1217 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001218 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001219 if (r < 0)
1220 {
1221 return r;
1222 }
1223 }
1224 else if (typeCode == "x")
1225 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001226 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001227 if (r < 0)
1228 {
1229 return r;
1230 }
1231 }
1232 else if (typeCode == "t")
1233 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001234 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001235 if (r < 0)
1236 {
1237 return r;
1238 }
1239 }
1240 else if (typeCode == "n")
1241 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001242 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001243 if (r < 0)
1244 {
1245 return r;
1246 }
1247 }
1248 else if (typeCode == "q")
1249 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001250 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001251 if (r < 0)
1252 {
1253 return r;
1254 }
1255 }
1256 else if (typeCode == "y")
1257 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001258 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001259 if (r < 0)
1260 {
1261 return r;
1262 }
1263 }
1264 else if (typeCode == "d")
1265 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001266 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001267 if (r < 0)
1268 {
1269 return r;
1270 }
1271 }
1272 else if (typeCode == "h")
1273 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001274 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001275 if (r < 0)
1276 {
1277 return r;
1278 }
1279 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001280 else if (typeCode.starts_with("a"))
Matt Spinler6df8f992019-01-14 12:47:47 -06001281 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001282 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001283 if (r < 0)
1284 {
1285 return r;
1286 }
1287 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001288 else if (typeCode.starts_with("(") && typeCode.ends_with(")"))
Matt Spinler75c6c672019-01-14 13:01:46 -06001289 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001290 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001291 if (r < 0)
1292 {
1293 return r;
1294 }
1295 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001296 else if (typeCode.starts_with("v"))
Matt Spinler89c19702019-01-14 13:13:00 -06001297 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001298 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001299 if (r < 0)
1300 {
1301 return r;
1302 }
1303 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001304 else
1305 {
Matt Spinlerd22a7132019-01-14 12:14:30 -06001306 BMCWEB_LOG_ERROR << "Invalid D-Bus signature type " << typeCode;
1307 return -2;
1308 }
1309 }
1310
Matt Spinler16caaee2019-01-15 11:40:34 -06001311 return 0;
1312}
1313
Ed Tanousb5a76932020-09-29 16:16:58 -07001314inline void handleMethodResponse(
1315 const std::shared_ptr<InProgressActionData>& transaction,
Patrick Williams59d494e2022-07-22 19:26:55 -05001316 sdbusplus::message_t& m, const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001317{
Matt Spinler39a4e392019-01-15 11:53:13 -06001318 nlohmann::json data;
1319
1320 int r = convertDBusToJSON(returnType, m, data);
1321 if (r < 0)
1322 {
1323 transaction->outputFailed = true;
1324 return;
1325 }
1326
1327 if (data.is_null())
1328 {
1329 return;
1330 }
1331
1332 if (transaction->methodResponse.is_null())
1333 {
1334 transaction->methodResponse = std::move(data);
1335 return;
1336 }
1337
1338 // If they're both dictionaries or arrays, merge into one.
1339 // Otherwise, make the results an array with every result
1340 // an entry. Could also just fail in that case, but it
1341 // seems better to get the data back somehow.
1342
1343 if (transaction->methodResponse.is_object() && data.is_object())
1344 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001345 for (const auto& obj : data.items())
Matt Spinler39a4e392019-01-15 11:53:13 -06001346 {
1347 // Note: Will overwrite the data for a duplicate key
1348 transaction->methodResponse.emplace(obj.key(),
1349 std::move(obj.value()));
1350 }
1351 return;
1352 }
1353
1354 if (transaction->methodResponse.is_array() && data.is_array())
1355 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001356 for (auto& obj : data)
Matt Spinler39a4e392019-01-15 11:53:13 -06001357 {
1358 transaction->methodResponse.push_back(std::move(obj));
1359 }
1360 return;
1361 }
1362
1363 if (!transaction->convertedToArray)
1364 {
1365 // They are different types. May as well turn them into an array
1366 nlohmann::json j = std::move(transaction->methodResponse);
1367 transaction->methodResponse = nlohmann::json::array();
1368 transaction->methodResponse.push_back(std::move(j));
1369 transaction->methodResponse.push_back(std::move(data));
1370 transaction->convertedToArray = true;
1371 }
1372 else
1373 {
1374 transaction->methodResponse.push_back(std::move(data));
1375 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001376}
1377
Ed Tanousb5a76932020-09-29 16:16:58 -07001378inline void findActionOnInterface(
1379 const std::shared_ptr<InProgressActionData>& transaction,
1380 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001381{
1382 BMCWEB_LOG_DEBUG << "findActionOnInterface for connection "
1383 << connectionName;
1384 crow::connections::systemBus->async_method_call(
1385 [transaction, connectionName{std::string(connectionName)}](
1386 const boost::system::error_code ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001387 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001388 BMCWEB_LOG_DEBUG << "got xml:\n " << introspectXml;
1389 if (ec)
1390 {
1391 BMCWEB_LOG_ERROR
1392 << "Introspect call failed with error: " << ec.message()
1393 << " on process: " << connectionName << "\n";
1394 return;
1395 }
1396 tinyxml2::XMLDocument doc;
Matt Spinler318bd892019-01-15 09:59:20 -06001397
Ed Tanous002d39b2022-05-31 08:59:27 -07001398 doc.Parse(introspectXml.data(), introspectXml.size());
1399 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1400 if (pRoot == nullptr)
1401 {
1402 BMCWEB_LOG_ERROR << "XML document failed to parse "
1403 << connectionName << "\n";
1404 return;
1405 }
1406 tinyxml2::XMLElement* interfaceNode =
1407 pRoot->FirstChildElement("interface");
1408 while (interfaceNode != nullptr)
1409 {
1410 const char* thisInterfaceName = interfaceNode->Attribute("name");
1411 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001412 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001413 if (!transaction->interfaceName.empty() &&
1414 (transaction->interfaceName != thisInterfaceName))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001415 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001416 interfaceNode =
1417 interfaceNode->NextSiblingElement("interface");
1418 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001419 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001420
1421 tinyxml2::XMLElement* methodNode =
1422 interfaceNode->FirstChildElement("method");
1423 while (methodNode != nullptr)
1424 {
1425 const char* thisMethodName = methodNode->Attribute("name");
1426 BMCWEB_LOG_DEBUG << "Found method: " << thisMethodName;
1427 if (thisMethodName != nullptr &&
1428 thisMethodName == transaction->methodName)
1429 {
1430 BMCWEB_LOG_DEBUG << "Found method named "
1431 << thisMethodName << " on interface "
1432 << thisInterfaceName;
Patrick Williams59d494e2022-07-22 19:26:55 -05001433 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001434 crow::connections::systemBus->new_method_call(
1435 connectionName.c_str(),
1436 transaction->path.c_str(), thisInterfaceName,
1437 transaction->methodName.c_str());
1438
1439 tinyxml2::XMLElement* argumentNode =
1440 methodNode->FirstChildElement("arg");
1441
1442 std::string returnType;
1443
1444 // Find the output type
1445 while (argumentNode != nullptr)
1446 {
1447 const char* argDirection =
1448 argumentNode->Attribute("direction");
1449 const char* argType =
1450 argumentNode->Attribute("type");
1451 if (argDirection != nullptr && argType != nullptr &&
1452 std::string(argDirection) == "out")
1453 {
1454 returnType = argType;
1455 break;
1456 }
1457 argumentNode =
1458 argumentNode->NextSiblingElement("arg");
1459 }
1460
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001461 auto argIt = transaction->arguments.begin();
Ed Tanous002d39b2022-05-31 08:59:27 -07001462
1463 argumentNode = methodNode->FirstChildElement("arg");
1464
1465 while (argumentNode != nullptr)
1466 {
1467 const char* argDirection =
1468 argumentNode->Attribute("direction");
1469 const char* argType =
1470 argumentNode->Attribute("type");
1471 if (argDirection != nullptr && argType != nullptr &&
1472 std::string(argDirection) == "in")
1473 {
1474 if (argIt == transaction->arguments.end())
1475 {
1476 transaction->setErrorStatus(
1477 "Invalid method args");
1478 return;
1479 }
1480 if (convertJsonToDbus(m.get(),
1481 std::string(argType),
1482 *argIt) < 0)
1483 {
1484 transaction->setErrorStatus(
1485 "Invalid method arg type");
1486 return;
1487 }
1488
1489 argIt++;
1490 }
1491 argumentNode =
1492 argumentNode->NextSiblingElement("arg");
1493 }
1494
1495 crow::connections::systemBus->async_send(
1496 m,
1497 [transaction,
1498 returnType](boost::system::error_code ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05001499 sdbusplus::message_t& m2) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001500 if (ec2)
1501 {
1502 transaction->methodFailed = true;
1503 const sd_bus_error* e = m2.get_error();
1504
1505 if (e != nullptr)
1506 {
1507 setErrorResponse(
1508 transaction->res,
1509 boost::beast::http::status::bad_request,
1510 e->name, e->message);
1511 }
1512 else
1513 {
1514 setErrorResponse(
1515 transaction->res,
1516 boost::beast::http::status::bad_request,
1517 "Method call failed", methodFailedMsg);
1518 }
1519 return;
1520 }
1521 transaction->methodPassed = true;
1522
1523 handleMethodResponse(transaction, m2, returnType);
1524 });
1525 break;
1526 }
1527 methodNode = methodNode->NextSiblingElement("method");
1528 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001529 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001530 interfaceNode = interfaceNode->NextSiblingElement("interface");
1531 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001532 },
1533 connectionName, transaction->path,
1534 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001535}
1536
zhanghch058d1b46d2021-04-01 11:18:24 +08001537inline void handleAction(const crow::Request& req,
1538 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001539 const std::string& objectPath,
1540 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001541{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001542 BMCWEB_LOG_DEBUG << "handleAction on path: " << objectPath << " and method "
1543 << methodName;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001544 nlohmann::json requestDbusData =
1545 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001546
Ed Tanous1abe55e2018-09-05 08:30:59 -07001547 if (requestDbusData.is_discarded())
1548 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001549 setErrorResponse(asyncResp->res,
1550 boost::beast::http::status::bad_request, noJsonDesc,
1551 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001552 return;
1553 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001554 nlohmann::json::iterator data = requestDbusData.find("data");
1555 if (data == requestDbusData.end())
1556 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001557 setErrorResponse(asyncResp->res,
1558 boost::beast::http::status::bad_request, noJsonDesc,
1559 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001560 return;
1561 }
1562
1563 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001564 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001565 setErrorResponse(asyncResp->res,
1566 boost::beast::http::status::bad_request, noJsonDesc,
1567 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001568 return;
1569 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001570 auto transaction = std::make_shared<InProgressActionData>(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001571
1572 transaction->path = objectPath;
1573 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001574 transaction->arguments = std::move(*data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001575 crow::connections::systemBus->async_method_call(
1576 [transaction](
1577 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001578 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1579 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001580 if (ec || interfaceNames.empty())
1581 {
1582 BMCWEB_LOG_ERROR << "Can't find object";
1583 setErrorResponse(transaction->res,
1584 boost::beast::http::status::not_found,
1585 notFoundDesc, notFoundMsg);
1586 return;
1587 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001588
Ed Tanous002d39b2022-05-31 08:59:27 -07001589 BMCWEB_LOG_DEBUG << "GetObject returned " << interfaceNames.size()
1590 << " object(s)";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001591
Ed Tanous002d39b2022-05-31 08:59:27 -07001592 for (const std::pair<std::string, std::vector<std::string>>& object :
1593 interfaceNames)
1594 {
1595 findActionOnInterface(transaction, object.first);
1596 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001597 },
1598 "xyz.openbmc_project.ObjectMapper",
1599 "/xyz/openbmc_project/object_mapper",
1600 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
1601 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001602}
1603
zhanghch058d1b46d2021-04-01 11:18:24 +08001604inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1605 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001606{
1607 BMCWEB_LOG_DEBUG << "handleDelete on path: " << objectPath;
1608
1609 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +08001610 [asyncResp, objectPath](
Matt Spinlerde818812018-12-11 16:39:20 -06001611 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001612 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1613 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001614 if (ec || interfaceNames.empty())
1615 {
1616 BMCWEB_LOG_ERROR << "Can't find object";
1617 setErrorResponse(asyncResp->res,
1618 boost::beast::http::status::method_not_allowed,
1619 methodNotAllowedDesc, methodNotAllowedMsg);
1620 return;
1621 }
Matt Spinlerde818812018-12-11 16:39:20 -06001622
Ed Tanous002d39b2022-05-31 08:59:27 -07001623 auto transaction =
1624 std::make_shared<InProgressActionData>(asyncResp->res);
1625 transaction->path = objectPath;
1626 transaction->methodName = "Delete";
1627 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
Matt Spinlerde818812018-12-11 16:39:20 -06001628
Ed Tanous002d39b2022-05-31 08:59:27 -07001629 for (const std::pair<std::string, std::vector<std::string>>& object :
1630 interfaceNames)
1631 {
1632 findActionOnInterface(transaction, object.first);
1633 }
Matt Spinlerde818812018-12-11 16:39:20 -06001634 },
1635 "xyz.openbmc_project.ObjectMapper",
1636 "/xyz/openbmc_project/object_mapper",
1637 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001638 std::array<const char*, 0>());
Matt Spinlerde818812018-12-11 16:39:20 -06001639}
1640
zhanghch058d1b46d2021-04-01 11:18:24 +08001641inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1642 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001643{
George Liu7a1dbc42022-12-07 16:03:22 +08001644 dbus::utility::getSubTreePaths(
1645 objectPath, depth, {},
Ed Tanousb9d36b42022-02-26 21:42:46 -08001646 [asyncResp](
George Liu7a1dbc42022-12-07 16:03:22 +08001647 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001648 const dbus::utility::MapperGetSubTreePathsResponse& objectPaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001649 if (ec)
1650 {
1651 setErrorResponse(asyncResp->res,
1652 boost::beast::http::status::not_found,
1653 notFoundDesc, notFoundMsg);
1654 }
1655 else
1656 {
1657 asyncResp->res.jsonValue["status"] = "ok";
1658 asyncResp->res.jsonValue["message"] = "200 OK";
1659 asyncResp->res.jsonValue["data"] = objectPaths;
1660 }
George Liu7a1dbc42022-12-07 16:03:22 +08001661 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001662}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001663
zhanghch058d1b46d2021-04-01 11:18:24 +08001664inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1665 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001666{
Ed Tanous049a0512018-11-01 13:58:42 -07001667 BMCWEB_LOG_DEBUG << "Doing enumerate on " << objectPath;
Ed Tanous049a0512018-11-01 13:58:42 -07001668
Ed Tanous14766872022-03-15 10:44:42 -07001669 asyncResp->res.jsonValue["message"] = "200 OK";
1670 asyncResp->res.jsonValue["status"] = "ok";
1671 asyncResp->res.jsonValue["data"] = nlohmann::json::object();
Ed Tanous049a0512018-11-01 13:58:42 -07001672
Ed Tanous1abe55e2018-09-05 08:30:59 -07001673 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001674 [objectPath, asyncResp](
1675 const boost::system::error_code ec,
1676 const dbus::utility::MapperGetSubTreeResponse& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001677 auto transaction =
1678 std::make_shared<InProgressEnumerateData>(objectPath, asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001679
Ed Tanous002d39b2022-05-31 08:59:27 -07001680 transaction->subtree =
1681 std::make_shared<dbus::utility::MapperGetSubTreeResponse>(
1682 objectNames);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001683
Ed Tanous002d39b2022-05-31 08:59:27 -07001684 if (ec)
1685 {
1686 BMCWEB_LOG_ERROR << "GetSubTree failed on "
1687 << transaction->objectPath;
1688 setErrorResponse(transaction->asyncResp->res,
1689 boost::beast::http::status::not_found,
1690 notFoundDesc, notFoundMsg);
1691 return;
1692 }
Ed Tanous64530012018-02-06 17:08:16 -08001693
Ed Tanous002d39b2022-05-31 08:59:27 -07001694 // Add the data for the path passed in to the results
1695 // as if GetSubTree returned it, and continue on enumerating
1696 getObjectAndEnumerate(transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001697 },
1698 "xyz.openbmc_project.ObjectMapper",
1699 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -07001700 "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath, 0,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001701 std::array<const char*, 0>());
Ed Tanous64530012018-02-06 17:08:16 -08001702}
Ed Tanous911ac312017-08-15 09:37:42 -07001703
zhanghch058d1b46d2021-04-01 11:18:24 +08001704inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1705 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001706{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001707 BMCWEB_LOG_DEBUG << "handleGet: " << objectPath << " prop:" << destProperty;
1708 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001709 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001710
Ed Tanous1abe55e2018-09-05 08:30:59 -07001711 std::shared_ptr<std::string> path =
1712 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001713
Ed Tanous1abe55e2018-09-05 08:30:59 -07001714 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001715 [asyncResp, path,
1716 propertyName](const boost::system::error_code ec,
1717 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001718 if (ec || objectNames.empty())
1719 {
1720 setErrorResponse(asyncResp->res,
1721 boost::beast::http::status::not_found,
1722 notFoundDesc, notFoundMsg);
1723 return;
1724 }
1725 std::shared_ptr<nlohmann::json> response =
1726 std::make_shared<nlohmann::json>(nlohmann::json::object());
1727 // The mapper should never give us an empty interface names
1728 // list, but check anyway
1729 for (const std::pair<std::string, std::vector<std::string>>&
1730 connection : objectNames)
1731 {
1732 const std::vector<std::string>& interfaceNames = connection.second;
1733
1734 if (interfaceNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001735 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001736 setErrorResponse(asyncResp->res,
1737 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001738 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001739 return;
1740 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001741
1742 for (const std::string& interface : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001743 {
Patrick Williams59d494e2022-07-22 19:26:55 -05001744 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001745 crow::connections::systemBus->new_method_call(
1746 connection.first.c_str(), path->c_str(),
1747 "org.freedesktop.DBus.Properties", "GetAll");
1748 m.append(interface);
1749 crow::connections::systemBus->async_send(
1750 m, [asyncResp, response,
1751 propertyName](const boost::system::error_code ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05001752 sdbusplus::message_t& msg) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001753 if (ec2)
1754 {
1755 BMCWEB_LOG_ERROR << "Bad dbus request error: "
1756 << ec2;
1757 }
1758 else
1759 {
1760 nlohmann::json properties;
1761 int r = convertDBusToJSON("a{sv}", msg, properties);
1762 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001763 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001764 BMCWEB_LOG_ERROR << "convertDBusToJSON failed";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001765 }
1766 else
1767 {
Patrick Williams62bafc02022-09-08 17:35:35 -05001768 for (const auto& prop : properties.items())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001769 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001770 // if property name is empty, or
1771 // matches our search query, add it
1772 // to the response json
Ed Tanous1abe55e2018-09-05 08:30:59 -07001773
Ed Tanous002d39b2022-05-31 08:59:27 -07001774 if (propertyName->empty())
1775 {
1776 (*response)[prop.key()] =
1777 std::move(prop.value());
1778 }
1779 else if (prop.key() == *propertyName)
1780 {
1781 *response = std::move(prop.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001782 }
1783 }
1784 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001785 }
1786 if (response.use_count() == 1)
1787 {
1788 if (!propertyName->empty() && response->empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001789 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001790 setErrorResponse(
1791 asyncResp->res,
1792 boost::beast::http::status::not_found,
1793 propNotFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001794 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001795 else
1796 {
1797 asyncResp->res.jsonValue["status"] = "ok";
1798 asyncResp->res.jsonValue["message"] = "200 OK";
1799 asyncResp->res.jsonValue["data"] = *response;
1800 }
1801 }
1802 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001803 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001804 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001805 },
1806 "xyz.openbmc_project.ObjectMapper",
1807 "/xyz/openbmc_project/object_mapper",
1808 "xyz.openbmc_project.ObjectMapper", "GetObject", *path,
1809 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001810}
1811
Ed Tanous1abe55e2018-09-05 08:30:59 -07001812struct AsyncPutRequest
1813{
Ed Tanous4e23a442022-06-06 09:57:26 -07001814 explicit AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
zhanghch058d1b46d2021-04-01 11:18:24 +08001815 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001816 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001817 ~AsyncPutRequest()
1818 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001819 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001820 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001821 setErrorResponse(asyncResp->res,
1822 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001823 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001824 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001825 }
1826
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001827 AsyncPutRequest(const AsyncPutRequest&) = delete;
1828 AsyncPutRequest(AsyncPutRequest&&) = delete;
1829 AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1830 AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1831
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001832 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001833 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001834 setErrorResponse(asyncResp->res,
1835 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001836 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001837 }
1838
zhanghch058d1b46d2021-04-01 11:18:24 +08001839 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001840 std::string objectPath;
1841 std::string propertyName;
1842 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001843};
1844
zhanghch058d1b46d2021-04-01 11:18:24 +08001845inline void handlePut(const crow::Request& req,
1846 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001847 const std::string& objectPath,
1848 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001849{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001850 if (destProperty.empty())
1851 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001852 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001853 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001854 return;
1855 }
1856
Ed Tanous1abe55e2018-09-05 08:30:59 -07001857 nlohmann::json requestDbusData =
1858 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001859
Ed Tanous1abe55e2018-09-05 08:30:59 -07001860 if (requestDbusData.is_discarded())
1861 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001862 setErrorResponse(asyncResp->res,
1863 boost::beast::http::status::bad_request, noJsonDesc,
1864 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001865 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001866 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001867
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001868 auto propertyIt = requestDbusData.find("data");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001869 if (propertyIt == requestDbusData.end())
1870 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001871 setErrorResponse(asyncResp->res,
1872 boost::beast::http::status::bad_request, noJsonDesc,
1873 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001874 return;
1875 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001876 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001877 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001878 transaction->objectPath = objectPath;
1879 transaction->propertyName = destProperty;
1880 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001881
Ed Tanous1abe55e2018-09-05 08:30:59 -07001882 crow::connections::systemBus->async_method_call(
Ed Tanous23a21a12020-07-25 04:45:05 +00001883 [transaction](const boost::system::error_code ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001884 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001885 if (!ec2 && objectNames.empty())
1886 {
1887 setErrorResponse(transaction->asyncResp->res,
1888 boost::beast::http::status::not_found,
1889 propNotFoundDesc, notFoundMsg);
1890 return;
1891 }
Ed Tanous911ac312017-08-15 09:37:42 -07001892
Ed Tanous002d39b2022-05-31 08:59:27 -07001893 for (const std::pair<std::string, std::vector<std::string>>&
1894 connection : objectNames)
1895 {
1896 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001897
Ed Tanous002d39b2022-05-31 08:59:27 -07001898 crow::connections::systemBus->async_method_call(
1899 [connectionName{std::string(connectionName)},
1900 transaction](const boost::system::error_code ec3,
1901 const std::string& introspectXml) {
1902 if (ec3)
1903 {
1904 BMCWEB_LOG_ERROR << "Introspect call failed with error: "
1905 << ec3.message()
1906 << " on process: " << connectionName;
1907 transaction->setErrorStatus("Unexpected Error");
1908 return;
1909 }
1910 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001911
Ed Tanous002d39b2022-05-31 08:59:27 -07001912 doc.Parse(introspectXml.c_str());
1913 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1914 if (pRoot == nullptr)
1915 {
1916 BMCWEB_LOG_ERROR << "XML document failed to parse: "
1917 << introspectXml;
1918 transaction->setErrorStatus("Unexpected Error");
1919 return;
1920 }
1921 tinyxml2::XMLElement* ifaceNode =
1922 pRoot->FirstChildElement("interface");
1923 while (ifaceNode != nullptr)
1924 {
1925 const char* interfaceName = ifaceNode->Attribute("name");
1926 BMCWEB_LOG_DEBUG << "found interface " << interfaceName;
1927 tinyxml2::XMLElement* propNode =
1928 ifaceNode->FirstChildElement("property");
1929 while (propNode != nullptr)
1930 {
1931 const char* propertyName = propNode->Attribute("name");
1932 BMCWEB_LOG_DEBUG << "Found property " << propertyName;
1933 if (propertyName == transaction->propertyName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001934 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001935 const char* argType = propNode->Attribute("type");
1936 if (argType != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001937 {
Patrick Williams59d494e2022-07-22 19:26:55 -05001938 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07001939 crow::connections::systemBus
1940 ->new_method_call(
1941 connectionName.c_str(),
1942 transaction->objectPath.c_str(),
1943 "org.freedesktop.DBus."
1944 "Properties",
1945 "Set");
1946 m.append(interfaceName,
1947 transaction->propertyName);
1948 int r = sd_bus_message_open_container(
1949 m.get(), SD_BUS_TYPE_VARIANT, argType);
1950 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001951 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001952 transaction->setErrorStatus(
1953 "Unexpected Error");
1954 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001955 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001956 r = convertJsonToDbus(
1957 m.get(), argType,
1958 transaction->propertyValue);
1959 if (r < 0)
1960 {
1961 if (r == -ERANGE)
1962 {
1963 transaction->setErrorStatus(
1964 "Provided property value "
1965 "is out of range for the "
1966 "property type");
1967 }
1968 else
1969 {
1970 transaction->setErrorStatus(
1971 "Invalid arg type");
1972 }
1973 return;
1974 }
1975 r = sd_bus_message_close_container(m.get());
1976 if (r < 0)
1977 {
1978 transaction->setErrorStatus(
1979 "Unexpected Error");
1980 return;
1981 }
1982 crow::connections::systemBus->async_send(
1983 m,
Patrick Williams59d494e2022-07-22 19:26:55 -05001984 [transaction](boost::system::error_code ec,
1985 sdbusplus::message_t& m2) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001986 BMCWEB_LOG_DEBUG << "sent";
1987 if (ec)
1988 {
1989 const sd_bus_error* e = m2.get_error();
1990 setErrorResponse(
1991 transaction->asyncResp->res,
1992 boost::beast::http::status::
1993 forbidden,
1994 (e) != nullptr
1995 ? e->name
1996 : ec.category().name(),
1997 (e) != nullptr ? e->message
1998 : ec.message());
1999 }
2000 else
2001 {
2002 transaction->asyncResp->res
2003 .jsonValue["status"] = "ok";
2004 transaction->asyncResp->res
2005 .jsonValue["message"] = "200 OK";
2006 transaction->asyncResp->res
2007 .jsonValue["data"] = nullptr;
2008 }
2009 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002010 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002011 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002012 propNode = propNode->NextSiblingElement("property");
2013 }
2014 ifaceNode = ifaceNode->NextSiblingElement("interface");
2015 }
2016 },
2017 connectionName, transaction->objectPath,
2018 "org.freedesktop.DBus.Introspectable", "Introspect");
2019 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002020 },
2021 "xyz.openbmc_project.ObjectMapper",
2022 "/xyz/openbmc_project/object_mapper",
2023 "xyz.openbmc_project.ObjectMapper", "GetObject",
2024 transaction->objectPath, std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07002025}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002026
zhanghch058d1b46d2021-04-01 11:18:24 +08002027inline void handleDBusUrl(const crow::Request& req,
2028 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002029 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002030{
Ed Tanous049a0512018-11-01 13:58:42 -07002031
2032 // If accessing a single attribute, fill in and update objectPath,
2033 // otherwise leave destProperty blank
Ed Tanouse05aec52022-01-25 10:28:56 -08002034 std::string destProperty;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002035 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002036 size_t attrPosition = objectPath.find(attrSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002037 if (attrPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002038 {
2039 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2040 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002041 objectPath.resize(attrPosition);
Ed Tanous049a0512018-11-01 13:58:42 -07002042 }
2043
Ed Tanousb41187f2019-10-24 16:30:02 -07002044 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002045 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002046 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002047 size_t actionPosition = objectPath.find(actionSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002048 if (actionPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002049 {
2050 std::string postProperty =
2051 objectPath.substr((actionPosition + strlen(actionSeperator)),
2052 objectPath.length());
Ed Tanous7f57f192022-12-20 09:53:40 -08002053 objectPath.resize(actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002054 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002055 return;
2056 }
2057 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002058 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002059 {
Ed Tanous11ba3972022-07-11 09:50:41 -07002060 if (objectPath.ends_with("/enumerate"))
Ed Tanous049a0512018-11-01 13:58:42 -07002061 {
2062 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2063 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002064 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002065 }
Ed Tanous11ba3972022-07-11 09:50:41 -07002066 else if (objectPath.ends_with("/list"))
Ed Tanous049a0512018-11-01 13:58:42 -07002067 {
2068 objectPath.erase(objectPath.end() - sizeof("list"),
2069 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002070 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002071 }
2072 else
2073 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002074 // Trim any trailing "/" at the end
Ed Tanous11ba3972022-07-11 09:50:41 -07002075 if (objectPath.ends_with("/"))
Ed Tanousf839dfe2018-11-12 11:11:15 -08002076 {
2077 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002078 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002079 }
2080 else
2081 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002082 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002083 }
Ed Tanous049a0512018-11-01 13:58:42 -07002084 }
2085 return;
2086 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002087 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002088 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002089 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002090 return;
2091 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002092 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002093 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002094 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002095 return;
2096 }
Ed Tanous049a0512018-11-01 13:58:42 -07002097
zhanghch058d1b46d2021-04-01 11:18:24 +08002098 setErrorResponse(asyncResp->res,
2099 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002100 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002101}
2102
Ed Tanous1656b292022-05-04 11:33:42 -07002103inline void
2104 handleBusSystemPost(const crow::Request& req,
2105 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2106 const std::string& processName,
2107 const std::string& requestedPath)
2108{
2109 std::vector<std::string> strs;
2110 boost::split(strs, requestedPath, boost::is_any_of("/"));
2111 std::string objectPath;
2112 std::string interfaceName;
2113 std::string methodName;
2114 auto it = strs.begin();
2115 if (it == strs.end())
2116 {
2117 objectPath = "/";
2118 }
2119 while (it != strs.end())
2120 {
2121 // Check if segment contains ".". If it does, it must be an
2122 // interface
2123 if (it->find(".") != std::string::npos)
2124 {
2125 break;
2126 // This check is necessary as the trailing slash gets
2127 // parsed as part of our <path> specifier above, which
2128 // causes the normal trailing backslash redirector to
2129 // fail.
2130 }
2131 if (!it->empty())
2132 {
2133 objectPath += "/" + *it;
2134 }
2135 it++;
2136 }
2137 if (it != strs.end())
2138 {
2139 interfaceName = *it;
2140 it++;
2141
2142 // after interface, we might have a method name
2143 if (it != strs.end())
2144 {
2145 methodName = *it;
2146 it++;
2147 }
2148 }
2149 if (it != strs.end())
2150 {
2151 // if there is more levels past the method name, something
2152 // went wrong, return not found
2153 asyncResp->res.result(boost::beast::http::status::not_found);
2154 return;
2155 }
2156 if (interfaceName.empty())
2157 {
2158 crow::connections::systemBus->async_method_call(
2159 [asyncResp, processName,
2160 objectPath](const boost::system::error_code ec,
2161 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002162 if (ec)
2163 {
2164 BMCWEB_LOG_ERROR
2165 << "Introspect call failed with error: " << ec.message()
2166 << " on process: " << processName << " path: " << objectPath
2167 << "\n";
2168 return;
2169 }
2170 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002171
Ed Tanous002d39b2022-05-31 08:59:27 -07002172 doc.Parse(introspectXml.c_str());
2173 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2174 if (pRoot == nullptr)
2175 {
2176 BMCWEB_LOG_ERROR << "XML document failed to parse "
2177 << processName << " " << objectPath << "\n";
2178 asyncResp->res.jsonValue["status"] = "XML parse error";
2179 asyncResp->res.result(
2180 boost::beast::http::status::internal_server_error);
2181 return;
2182 }
2183
2184 BMCWEB_LOG_DEBUG << introspectXml;
2185 asyncResp->res.jsonValue["status"] = "ok";
2186 asyncResp->res.jsonValue["bus_name"] = processName;
2187 asyncResp->res.jsonValue["object_path"] = objectPath;
2188
2189 nlohmann::json& interfacesArray =
2190 asyncResp->res.jsonValue["interfaces"];
2191 interfacesArray = nlohmann::json::array();
2192 tinyxml2::XMLElement* interface =
2193 pRoot->FirstChildElement("interface");
2194
2195 while (interface != nullptr)
2196 {
2197 const char* ifaceName = interface->Attribute("name");
2198 if (ifaceName != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002199 {
Ed Tanous8a592812022-06-04 09:06:59 -07002200 nlohmann::json::object_t interfaceObj;
2201 interfaceObj["name"] = ifaceName;
2202 interfacesArray.push_back(std::move(interfaceObj));
Ed Tanous1656b292022-05-04 11:33:42 -07002203 }
2204
Ed Tanous002d39b2022-05-31 08:59:27 -07002205 interface = interface->NextSiblingElement("interface");
2206 }
Ed Tanous1656b292022-05-04 11:33:42 -07002207 },
2208 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2209 "Introspect");
2210 }
2211 else if (methodName.empty())
2212 {
2213 crow::connections::systemBus->async_method_call(
2214 [asyncResp, processName, objectPath,
2215 interfaceName](const boost::system::error_code ec,
2216 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002217 if (ec)
2218 {
2219 BMCWEB_LOG_ERROR
2220 << "Introspect call failed with error: " << ec.message()
2221 << " on process: " << processName << " path: " << objectPath
2222 << "\n";
2223 return;
2224 }
2225 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002226
Ed Tanous002d39b2022-05-31 08:59:27 -07002227 doc.Parse(introspectXml.data(), introspectXml.size());
2228 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2229 if (pRoot == nullptr)
2230 {
2231 BMCWEB_LOG_ERROR << "XML document failed to parse "
2232 << processName << " " << objectPath << "\n";
2233 asyncResp->res.result(
2234 boost::beast::http::status::internal_server_error);
2235 return;
2236 }
2237
2238 asyncResp->res.jsonValue["status"] = "ok";
2239 asyncResp->res.jsonValue["bus_name"] = processName;
2240 asyncResp->res.jsonValue["interface"] = interfaceName;
2241 asyncResp->res.jsonValue["object_path"] = objectPath;
2242
2243 nlohmann::json& methodsArray = asyncResp->res.jsonValue["methods"];
2244 methodsArray = nlohmann::json::array();
2245
2246 nlohmann::json& signalsArray = asyncResp->res.jsonValue["signals"];
2247 signalsArray = nlohmann::json::array();
2248
2249 nlohmann::json& propertiesObj =
2250 asyncResp->res.jsonValue["properties"];
2251 propertiesObj = nlohmann::json::object();
2252
2253 // if we know we're the only call, build the
2254 // json directly
2255 tinyxml2::XMLElement* interface =
2256 pRoot->FirstChildElement("interface");
2257 while (interface != nullptr)
2258 {
2259 const char* ifaceName = interface->Attribute("name");
2260
2261 if (ifaceName != nullptr && ifaceName == interfaceName)
Ed Tanous1656b292022-05-04 11:33:42 -07002262 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002263 break;
Ed Tanous1656b292022-05-04 11:33:42 -07002264 }
Ed Tanous14766872022-03-15 10:44:42 -07002265
Ed Tanous002d39b2022-05-31 08:59:27 -07002266 interface = interface->NextSiblingElement("interface");
2267 }
2268 if (interface == nullptr)
2269 {
2270 // if we got to the end of the list and
2271 // never found a match, throw 404
2272 asyncResp->res.result(boost::beast::http::status::not_found);
2273 return;
2274 }
Ed Tanous1656b292022-05-04 11:33:42 -07002275
Ed Tanous002d39b2022-05-31 08:59:27 -07002276 tinyxml2::XMLElement* methods =
2277 interface->FirstChildElement("method");
2278 while (methods != nullptr)
2279 {
2280 nlohmann::json argsArray = nlohmann::json::array();
2281 tinyxml2::XMLElement* arg = methods->FirstChildElement("arg");
2282 while (arg != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002283 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002284 nlohmann::json thisArg;
2285 for (const char* fieldName : std::array<const char*, 3>{
2286 "name", "direction", "type"})
Ed Tanous1656b292022-05-04 11:33:42 -07002287 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002288 const char* fieldValue = arg->Attribute(fieldName);
2289 if (fieldValue != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002290 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002291 thisArg[fieldName] = fieldValue;
2292 }
2293 }
2294 argsArray.push_back(std::move(thisArg));
2295 arg = arg->NextSiblingElement("arg");
2296 }
2297
2298 const char* name = methods->Attribute("name");
2299 if (name != nullptr)
2300 {
2301 std::string uri;
2302 uri.reserve(14 + processName.size() + objectPath.size() +
2303 interfaceName.size() + strlen(name));
2304 uri += "/bus/system/";
2305 uri += processName;
2306 uri += objectPath;
2307 uri += "/";
2308 uri += interfaceName;
2309 uri += "/";
2310 uri += name;
2311
2312 nlohmann::json::object_t object;
2313 object["name"] = name;
2314 object["uri"] = std::move(uri);
2315 object["args"] = argsArray;
2316
2317 methodsArray.push_back(std::move(object));
2318 }
2319 methods = methods->NextSiblingElement("method");
2320 }
2321 tinyxml2::XMLElement* signals =
2322 interface->FirstChildElement("signal");
2323 while (signals != nullptr)
2324 {
2325 nlohmann::json argsArray = nlohmann::json::array();
2326
2327 tinyxml2::XMLElement* arg = signals->FirstChildElement("arg");
2328 while (arg != nullptr)
2329 {
2330 const char* name = arg->Attribute("name");
2331 const char* type = arg->Attribute("type");
2332 if (name != nullptr && type != nullptr)
2333 {
2334 argsArray.push_back({
2335 {"name", name},
2336 {"type", type},
2337 });
2338 }
2339 arg = arg->NextSiblingElement("arg");
2340 }
2341 const char* name = signals->Attribute("name");
2342 if (name != nullptr)
2343 {
2344 nlohmann::json::object_t object;
2345 object["name"] = name;
2346 object["args"] = argsArray;
2347 signalsArray.push_back(std::move(object));
2348 }
2349
2350 signals = signals->NextSiblingElement("signal");
2351 }
2352
2353 tinyxml2::XMLElement* property =
2354 interface->FirstChildElement("property");
2355 while (property != nullptr)
2356 {
2357 const char* name = property->Attribute("name");
2358 const char* type = property->Attribute("type");
2359 if (type != nullptr && name != nullptr)
2360 {
Patrick Williams59d494e2022-07-22 19:26:55 -05002361 sdbusplus::message_t m =
Ed Tanous002d39b2022-05-31 08:59:27 -07002362 crow::connections::systemBus->new_method_call(
2363 processName.c_str(), objectPath.c_str(),
2364 "org.freedesktop."
2365 "DBus."
2366 "Properties",
2367 "Get");
2368 m.append(interfaceName, name);
2369 nlohmann::json& propertyItem = propertiesObj[name];
2370 crow::connections::systemBus->async_send(
2371 m, [&propertyItem,
Ed Tanous02cad962022-06-30 16:50:15 -07002372 asyncResp](const boost::system::error_code& e,
Patrick Williams59d494e2022-07-22 19:26:55 -05002373 sdbusplus::message_t& msg) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002374 if (e)
Ed Tanous1656b292022-05-04 11:33:42 -07002375 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002376 return;
Ed Tanous1656b292022-05-04 11:33:42 -07002377 }
Ed Tanous1656b292022-05-04 11:33:42 -07002378
Ed Tanous002d39b2022-05-31 08:59:27 -07002379 convertDBusToJSON("v", msg, propertyItem);
2380 });
Ed Tanous1656b292022-05-04 11:33:42 -07002381 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002382 property = property->NextSiblingElement("property");
2383 }
Ed Tanous1656b292022-05-04 11:33:42 -07002384 },
2385 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2386 "Introspect");
2387 }
2388 else
2389 {
2390 if (req.method() != boost::beast::http::verb::post)
2391 {
2392 asyncResp->res.result(boost::beast::http::status::not_found);
2393 return;
2394 }
2395
2396 nlohmann::json requestDbusData =
2397 nlohmann::json::parse(req.body, nullptr, false);
2398
2399 if (requestDbusData.is_discarded())
2400 {
2401 asyncResp->res.result(boost::beast::http::status::bad_request);
2402 return;
2403 }
2404 if (!requestDbusData.is_array())
2405 {
2406 asyncResp->res.result(boost::beast::http::status::bad_request);
2407 return;
2408 }
2409 auto transaction =
2410 std::make_shared<InProgressActionData>(asyncResp->res);
2411
2412 transaction->path = objectPath;
2413 transaction->methodName = methodName;
2414 transaction->arguments = std::move(requestDbusData);
2415
2416 findActionOnInterface(transaction, processName);
2417 }
2418}
2419
Ed Tanous23a21a12020-07-25 04:45:05 +00002420inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002421{
2422 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002423 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002424 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002425 [](const crow::Request&,
2426 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002427 nlohmann::json::array_t buses;
2428 nlohmann::json& bus = buses.emplace_back();
2429 bus["name"] = "system";
2430 asyncResp->res.jsonValue["busses"] = std::move(buses);
2431 asyncResp->res.jsonValue["status"] = "ok";
2432 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002433
2434 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002435 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002436 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002437 [](const crow::Request&,
2438 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002439 auto myCallback = [asyncResp](const boost::system::error_code ec,
zhanghch058d1b46d2021-04-01 11:18:24 +08002440 std::vector<std::string>& names) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002441 if (ec)
2442 {
2443 BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
2444 asyncResp->res.result(
2445 boost::beast::http::status::internal_server_error);
2446 }
2447 else
2448 {
2449 std::sort(names.begin(), names.end());
2450 asyncResp->res.jsonValue["status"] = "ok";
2451 auto& objectsSub = asyncResp->res.jsonValue["objects"];
Ed Tanous02cad962022-06-30 16:50:15 -07002452 for (const auto& name : names)
Ed Tanous002d39b2022-05-31 08:59:27 -07002453 {
2454 nlohmann::json::object_t object;
2455 object["name"] = name;
2456 objectsSub.push_back(std::move(object));
2457 }
2458 }
2459 };
2460 crow::connections::systemBus->async_method_call(
2461 std::move(myCallback), "org.freedesktop.DBus", "/",
2462 "org.freedesktop.DBus", "ListNames");
2463 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002464
2465 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002466 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002467 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002468 [](const crow::Request&,
2469 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002470 handleList(asyncResp, "/");
2471 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002472
2473 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002474 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002475 .methods(boost::beast::http::verb::get)(
2476 [](const crow::Request& req,
2477 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002478 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002479 std::string objectPath = "/xyz/" + path;
2480 handleDBusUrl(req, asyncResp, objectPath);
2481 });
zhanghch058d1b46d2021-04-01 11:18:24 +08002482
2483 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002484 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002485 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2486 boost::beast::http::verb::delete_)(
2487 [](const crow::Request& req,
2488 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2489 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002490 std::string objectPath = "/xyz/" + path;
2491 handleDBusUrl(req, asyncResp, objectPath);
2492 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002493
Ed Tanous049a0512018-11-01 13:58:42 -07002494 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002495 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002496 .methods(boost::beast::http::verb::get)(
2497 [](const crow::Request& req,
2498 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2499 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002500 std::string objectPath = "/org/" + path;
2501 handleDBusUrl(req, asyncResp, objectPath);
2502 });
Tanousf00032d2018-11-05 01:18:10 -03002503
2504 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002505 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002506 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2507 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002508 [](const crow::Request& req,
2509 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002510 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002511 std::string objectPath = "/org/" + path;
2512 handleDBusUrl(req, asyncResp, objectPath);
2513 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002514
Ed Tanous1abe55e2018-09-05 08:30:59 -07002515 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002516 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002517 .methods(boost::beast::http::verb::get)(
2518 [](const crow::Request&,
2519 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2520 const std::string& dumpId) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002521 if (!validateFilename(dumpId))
2522 {
2523 asyncResp->res.result(boost::beast::http::status::bad_request);
2524 return;
2525 }
2526 std::filesystem::path loc("/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002527
Ed Tanous002d39b2022-05-31 08:59:27 -07002528 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002529
Ed Tanous002d39b2022-05-31 08:59:27 -07002530 if (!std::filesystem::exists(loc) ||
2531 !std::filesystem::is_directory(loc))
2532 {
2533 BMCWEB_LOG_ERROR << loc.string() << "Not found";
2534 asyncResp->res.result(boost::beast::http::status::not_found);
2535 return;
2536 }
2537 std::filesystem::directory_iterator files(loc);
zhanghch058d1b46d2021-04-01 11:18:24 +08002538
Ed Tanous002d39b2022-05-31 08:59:27 -07002539 for (const auto& file : files)
2540 {
2541 std::ifstream readFile(file.path());
2542 if (!readFile.good())
2543 {
2544 continue;
2545 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002546
Ed Tanousd9f6c622022-03-17 09:12:17 -07002547 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07002548 "application/octet-stream");
zhanghch058d1b46d2021-04-01 11:18:24 +08002549
Ed Tanous002d39b2022-05-31 08:59:27 -07002550 // Assuming only one dump file will be present in the dump
2551 // id directory
2552 std::string dumpFileName = file.path().filename().string();
zhanghch058d1b46d2021-04-01 11:18:24 +08002553
Ed Tanous002d39b2022-05-31 08:59:27 -07002554 // Filename should be in alphanumeric, dot and underscore
2555 // Its based on phosphor-debug-collector application
2556 // dumpfile format
2557 std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
2558 if (!std::regex_match(dumpFileName, dumpFileRegex))
2559 {
2560 BMCWEB_LOG_ERROR << "Invalid dump filename " << dumpFileName;
zhanghch058d1b46d2021-04-01 11:18:24 +08002561 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002562 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07002563 }
2564 std::string contentDispositionParam =
2565 "attachment; filename=\"" + dumpFileName + "\"";
2566
Ed Tanousd9f6c622022-03-17 09:12:17 -07002567 asyncResp->res.addHeader(
2568 boost::beast::http::field::content_disposition,
2569 contentDispositionParam);
Ed Tanous002d39b2022-05-31 08:59:27 -07002570
2571 asyncResp->res.body() = {std::istreambuf_iterator<char>(readFile),
2572 std::istreambuf_iterator<char>()};
2573 return;
2574 }
2575 asyncResp->res.result(boost::beast::http::status::not_found);
2576 return;
2577 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002578
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002579 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002580 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002581
2582 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002583 [](const crow::Request&,
2584 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002585 const std::string& connection) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002586 introspectObjects(connection, "/", asyncResp);
2587 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002588
2589 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002590 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous1656b292022-05-04 11:33:42 -07002591 .methods(boost::beast::http::verb::get,
2592 boost::beast::http::verb::post)(handleBusSystemPost);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002593}
2594} // namespace openbmc_mapper
2595} // namespace crow