blob: 272776cd070ecc867e428efa9a768d2e5b1e0dd6 [file] [log] [blame]
James Feist5b4aa862018-08-16 14:07:01 -07001// Copyright (c) 2018 Intel Corporation
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
Ed Tanousb9b2e0b2018-09-13 13:47:50 -070014
James Feist5b4aa862018-08-16 14:07:01 -070015#pragma once
Ed Tanous911ac312017-08-15 09:37:42 -070016#include <tinyxml2.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -070017
Ed Tanous04e438c2020-10-03 08:06:26 -070018#include <app.hpp>
Ed Tanouse3cb5a32018-08-08 14:16:49 -070019#include <async_resp.hpp>
Ed Tanous1abe55e2018-09-05 08:30:59 -070020#include <boost/algorithm/string.hpp>
21#include <boost/container/flat_set.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -070022#include <dbus_singleton.hpp>
James Feist5b4aa862018-08-16 14:07:01 -070023#include <dbus_utility.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050024#include <sdbusplus/message/types.hpp>
25
James Feist4418c7f2019-04-15 11:09:15 -070026#include <filesystem>
Ed Tanousd4bb9bb2018-05-16 13:36:42 -070027#include <fstream>
Ramesh Iyyard9207042019-07-05 08:04:42 -050028#include <regex>
Ed Tanousb5a76932020-09-29 16:16:58 -070029#include <utility>
Ed Tanous911ac312017-08-15 09:37:42 -070030
Ed Tanous1abe55e2018-09-05 08:30:59 -070031namespace crow
32{
33namespace openbmc_mapper
34{
Ed Tanous23a21a12020-07-25 04:45:05 +000035const constexpr char* notFoundMsg = "404 Not Found";
36const constexpr char* badReqMsg = "400 Bad Request";
37const constexpr char* methodNotAllowedMsg = "405 Method Not Allowed";
38const constexpr char* forbiddenMsg = "403 Forbidden";
39const constexpr char* methodFailedMsg = "500 Method Call Failed";
40const constexpr char* methodOutputFailedMsg = "500 Method Output Error";
41const constexpr char* notFoundDesc =
Matt Spinler2ae60092018-12-06 10:35:36 -060042 "org.freedesktop.DBus.Error.FileNotFound: path or object not found";
Ed Tanous23a21a12020-07-25 04:45:05 +000043const constexpr char* propNotFoundDesc =
44 "The specified property cannot be found";
45const constexpr char* noJsonDesc = "No JSON object could be decoded";
46const constexpr char* methodNotFoundDesc =
47 "The specified method cannot be found";
48const constexpr char* methodNotAllowedDesc = "Method not allowed";
49const constexpr char* forbiddenPropDesc =
50 "The specified property cannot be created";
51const constexpr char* forbiddenResDesc =
52 "The specified resource cannot be created";
Matt Spinler2ae60092018-12-06 10:35:36 -060053
Josh Lehan482c45a2022-03-29 17:10:44 -070054inline bool validateFilename(const std::string& filename)
55{
56 std::regex validFilename(R"(^[\w\- ]+(\.?[\w\- ]*)$)");
57
58 return std::regex_match(filename, validFilename);
59}
60
Ed Tanous23a21a12020-07-25 04:45:05 +000061inline void setErrorResponse(crow::Response& res,
62 boost::beast::http::status result,
63 const std::string& desc,
64 const std::string_view msg)
Matt Spinler2ae60092018-12-06 10:35:36 -060065{
66 res.result(result);
Ed Tanous14766872022-03-15 10:44:42 -070067 res.jsonValue["data"]["description"] = desc;
68 res.jsonValue["message"] = msg;
69 res.jsonValue["status"] = "error";
Matt Spinler2ae60092018-12-06 10:35:36 -060070}
71
Ed Tanousb5a76932020-09-29 16:16:58 -070072inline void
73 introspectObjects(const std::string& processName,
74 const std::string& objectPath,
75 const std::shared_ptr<bmcweb::AsyncResp>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -070076{
Ed Tanouse3cb5a32018-08-08 14:16:49 -070077 if (transaction->res.jsonValue.is_null())
78 {
Ed Tanous14766872022-03-15 10:44:42 -070079 transaction->res.jsonValue["status"] = "ok";
80 transaction->res.jsonValue["bus_name"] = processName;
81 transaction->res.jsonValue["objects"] = nlohmann::json::array();
Ed Tanouse3cb5a32018-08-08 14:16:49 -070082 }
83
Ed Tanous1abe55e2018-09-05 08:30:59 -070084 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -070085 [transaction, processName{std::string(processName)},
86 objectPath{std::string(objectPath)}](
87 const boost::system::error_code ec,
Ed Tanous81ce6092020-12-17 16:54:55 +000088 const std::string& introspectXml) {
Ed Tanous1abe55e2018-09-05 08:30:59 -070089 if (ec)
90 {
91 BMCWEB_LOG_ERROR
92 << "Introspect call failed with error: " << ec.message()
93 << " on process: " << processName << " path: " << objectPath
94 << "\n";
Ed Tanouse3cb5a32018-08-08 14:16:49 -070095 return;
96 }
Ed Tanous14766872022-03-15 10:44:42 -070097 nlohmann::json::object_t object;
98 object["path"] = objectPath;
99
100 transaction->res.jsonValue["objects"].push_back(std::move(object));
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700101
102 tinyxml2::XMLDocument doc;
103
Ed Tanous81ce6092020-12-17 16:54:55 +0000104 doc.Parse(introspectXml.c_str());
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500105 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700106 if (pRoot == nullptr)
107 {
108 BMCWEB_LOG_ERROR << "XML document failed to parse "
109 << processName << " " << objectPath << "\n";
Ed Tanous911ac312017-08-15 09:37:42 -0700110 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700111 else
112 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500113 tinyxml2::XMLElement* node = pRoot->FirstChildElement("node");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700114 while (node != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700115 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500116 const char* childPath = node->Attribute("name");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700117 if (childPath != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700118 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700119 std::string newpath;
120 if (objectPath != "/")
121 {
122 newpath += objectPath;
123 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700124 newpath += std::string("/") + childPath;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700125 // introspect the subobjects as well
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700126 introspectObjects(processName, newpath, transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700127 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700128
129 node = node->NextSiblingElement("node");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700130 }
131 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700132 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700133 processName, objectPath, "org.freedesktop.DBus.Introspectable",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700134 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -0700135}
Ed Tanous64530012018-02-06 17:08:16 -0800136
Ed Tanous23a21a12020-07-25 04:45:05 +0000137inline void getPropertiesForEnumerate(
138 const std::string& objectPath, const std::string& service,
Ed Tanousb5a76932020-09-29 16:16:58 -0700139 const std::string& interface,
140 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600141{
142 BMCWEB_LOG_DEBUG << "getPropertiesForEnumerate " << objectPath << " "
143 << service << " " << interface;
144
145 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -0800146 [asyncResp, objectPath, service,
147 interface](const boost::system::error_code ec,
148 const dbus::utility::DBusPropertiesMap& propertiesList) {
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600149 if (ec)
150 {
151 BMCWEB_LOG_ERROR << "GetAll on path " << objectPath << " iface "
152 << interface << " service " << service
153 << " failed with code " << ec;
154 return;
155 }
156
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500157 nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
158 nlohmann::json& objectJson = dataJson[objectPath];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600159 if (objectJson.is_null())
160 {
161 objectJson = nlohmann::json::object();
162 }
163
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500164 for (const auto& [name, value] : propertiesList)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600165 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500166 nlohmann::json& propertyJson = objectJson[name];
Ed Tanousd1a64812021-12-13 12:14:05 -0800167 std::visit(
168 [&propertyJson](auto&& val) {
169 if constexpr (std::is_same_v<
170 std::decay_t<decltype(val)>,
171 sdbusplus::message::unix_fd>)
172 {
173 propertyJson = val.fd;
174 }
175 else
176 {
177
178 propertyJson = val;
179 }
180 },
181 value);
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600182 }
183 },
184 service, objectPath, "org.freedesktop.DBus.Properties", "GetAll",
185 interface);
186}
187
188// Find any results that weren't picked up by ObjectManagers, to be
189// called after all ObjectManagers are searched for and called.
Ed Tanous23a21a12020-07-25 04:45:05 +0000190inline void findRemainingObjectsForEnumerate(
Ed Tanousb5a76932020-09-29 16:16:58 -0700191 const std::string& objectPath,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800192 const std::shared_ptr<dbus::utility::MapperGetSubTreeResponse>& subtree,
Ed Tanousb5a76932020-09-29 16:16:58 -0700193 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600194{
195 BMCWEB_LOG_DEBUG << "findRemainingObjectsForEnumerate";
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500196 const nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600197
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500198 for (const auto& [path, interface_map] : *subtree)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600199 {
200 if (path == objectPath)
201 {
202 // An enumerate does not return the target path's properties
203 continue;
204 }
205 if (dataJson.find(path) == dataJson.end())
206 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500207 for (const auto& [service, interfaces] : interface_map)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600208 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500209 for (const auto& interface : interfaces)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600210 {
211 if (!boost::starts_with(interface, "org.freedesktop.DBus"))
212 {
213 getPropertiesForEnumerate(path, service, interface,
214 asyncResp);
215 }
216 }
217 }
218 }
219 }
220}
221
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600222struct InProgressEnumerateData
223{
zhanghch058d1b46d2021-04-01 11:18:24 +0800224 InProgressEnumerateData(
225 const std::string& objectPathIn,
226 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
Ed Tanous23a21a12020-07-25 04:45:05 +0000227 objectPath(objectPathIn),
zhanghch058d1b46d2021-04-01 11:18:24 +0800228 asyncResp(asyncRespIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500229 {}
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600230
231 ~InProgressEnumerateData()
232 {
Ed Tanous24b2fe82022-01-06 12:45:54 -0800233 try
234 {
235 findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
236 }
237 catch (...)
238 {
239 BMCWEB_LOG_CRITICAL
240 << "findRemainingObjectsForEnumerate threw exception";
241 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600242 }
243
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800244 InProgressEnumerateData(const InProgressEnumerateData&) = delete;
245 InProgressEnumerateData(InProgressEnumerateData&&) = delete;
246 InProgressEnumerateData& operator=(const InProgressEnumerateData&) = delete;
247 InProgressEnumerateData& operator=(InProgressEnumerateData&&) = delete;
248
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600249 const std::string objectPath;
Ed Tanousb9d36b42022-02-26 21:42:46 -0800250 std::shared_ptr<dbus::utility::MapperGetSubTreeResponse> subtree;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600251 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
252};
253
Ed Tanous23a21a12020-07-25 04:45:05 +0000254inline void getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000255 const std::string& objectName, const std::string& objectManagerPath,
256 const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700257 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700258{
Ed Tanous81ce6092020-12-17 16:54:55 +0000259 BMCWEB_LOG_DEBUG << "getManagedObjectsForEnumerate " << objectName
260 << " object_manager_path " << objectManagerPath
261 << " connection_name " << connectionName;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700262 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000263 [transaction, objectName,
264 connectionName](const boost::system::error_code ec,
265 const dbus::utility::ManagedObjectType& objects) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700266 if (ec)
267 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000268 BMCWEB_LOG_ERROR << "GetManagedObjects on path " << objectName
269 << " on connection " << connectionName
Ed Tanous049a0512018-11-01 13:58:42 -0700270 << " failed with code " << ec;
271 return;
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700272 }
Ed Tanous64530012018-02-06 17:08:16 -0800273
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500274 nlohmann::json& dataJson =
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600275 transaction->asyncResp->res.jsonValue["data"];
Ed Tanous049a0512018-11-01 13:58:42 -0700276
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500277 for (const auto& objectPath : objects)
Ed Tanous049a0512018-11-01 13:58:42 -0700278 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000279 if (boost::starts_with(objectPath.first.str, objectName))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700280 {
Ed Tanous049a0512018-11-01 13:58:42 -0700281 BMCWEB_LOG_DEBUG << "Reading object "
282 << objectPath.first.str;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500283 nlohmann::json& objectJson = dataJson[objectPath.first.str];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700284 if (objectJson.is_null())
285 {
286 objectJson = nlohmann::json::object();
287 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500288 for (const auto& interface : objectPath.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700289 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500290 for (const auto& property : interface.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700291 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500292 nlohmann::json& propertyJson =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700293 objectJson[property.first];
Ed Tanousd1a64812021-12-13 12:14:05 -0800294 std::visit(
295 [&propertyJson](auto&& val) {
296 if constexpr (
297 std::is_same_v<
298 std::decay_t<decltype(val)>,
299 sdbusplus::message::unix_fd>)
300 {
301 propertyJson = val.fd;
302 }
303 else
304 {
305
306 propertyJson = val;
307 }
308 },
309 property.second);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700310 }
311 }
312 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500313 for (const auto& interface : objectPath.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700314 {
315 if (interface.first == "org.freedesktop.DBus.ObjectManager")
316 {
317 getManagedObjectsForEnumerate(
318 objectPath.first.str, objectPath.first.str,
Ed Tanous81ce6092020-12-17 16:54:55 +0000319 connectionName, transaction);
Ed Tanous049a0512018-11-01 13:58:42 -0700320 }
321 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700322 }
323 },
Ed Tanous81ce6092020-12-17 16:54:55 +0000324 connectionName, objectManagerPath, "org.freedesktop.DBus.ObjectManager",
325 "GetManagedObjects");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700326}
327
Ed Tanous23a21a12020-07-25 04:45:05 +0000328inline void findObjectManagerPathForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000329 const std::string& objectName, const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700330 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700331{
Ed Tanous81ce6092020-12-17 16:54:55 +0000332 BMCWEB_LOG_DEBUG << "Finding objectmanager for path " << objectName
333 << " on connection:" << connectionName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700334 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000335 [transaction, objectName, connectionName](
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700336 const boost::system::error_code ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800337 const dbus::utility::MapperGetAncestorsResponse& objects) {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700338 if (ec)
339 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000340 BMCWEB_LOG_ERROR << "GetAncestors on path " << objectName
Ed Tanous049a0512018-11-01 13:58:42 -0700341 << " failed with code " << ec;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700342 return;
343 }
344
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500345 for (const auto& pathGroup : objects)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700346 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500347 for (const auto& connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700348 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000349 if (connectionGroup.first == connectionName)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700350 {
351 // Found the object manager path for this resource.
352 getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000353 objectName, pathGroup.first, connectionName,
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600354 transaction);
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700355 return;
356 }
357 }
358 }
359 },
360 "xyz.openbmc_project.ObjectMapper",
361 "/xyz/openbmc_project/object_mapper",
Ed Tanous81ce6092020-12-17 16:54:55 +0000362 "xyz.openbmc_project.ObjectMapper", "GetAncestors", objectName,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500363 std::array<const char*, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700364}
Ed Tanous64530012018-02-06 17:08:16 -0800365
Ed Tanous7c091622019-05-23 11:42:36 -0700366// Uses GetObject to add the object info about the target /enumerate path to
367// the results of GetSubTree, as GetSubTree will not return info for the
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600368// target path, and then continues on enumerating the rest of the tree.
Ed Tanousb5a76932020-09-29 16:16:58 -0700369inline void getObjectAndEnumerate(
370 const std::shared_ptr<InProgressEnumerateData>& transaction)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600371{
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600372 crow::connections::systemBus->async_method_call(
373 [transaction](const boost::system::error_code ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800374 const dbus::utility::MapperGetObject& objects) {
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600375 if (ec)
376 {
377 BMCWEB_LOG_ERROR << "GetObject for path "
378 << transaction->objectPath
379 << " failed with code " << ec;
380 return;
381 }
382
383 BMCWEB_LOG_DEBUG << "GetObject for " << transaction->objectPath
384 << " has " << objects.size() << " entries";
385 if (!objects.empty())
386 {
387 transaction->subtree->emplace_back(transaction->objectPath,
388 objects);
389 }
390
391 // Map indicating connection name, and the path where the object
392 // manager exists
393 boost::container::flat_map<std::string, std::string> connections;
394
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500395 for (const auto& object : *(transaction->subtree))
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600396 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500397 for (const auto& connection : object.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600398 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500399 std::string& objectManagerPath =
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600400 connections[connection.first];
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500401 for (const auto& interface : connection.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600402 {
403 BMCWEB_LOG_DEBUG << connection.first
404 << " has interface " << interface;
405 if (interface == "org.freedesktop.DBus.ObjectManager")
406 {
407 BMCWEB_LOG_DEBUG << "found object manager path "
408 << object.first;
409 objectManagerPath = object.first;
410 }
411 }
412 }
413 }
414 BMCWEB_LOG_DEBUG << "Got " << connections.size() << " connections";
415
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500416 for (const auto& connection : connections)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600417 {
Ed Tanous7c091622019-05-23 11:42:36 -0700418 // If we already know where the object manager is, we don't
419 // need to search for it, we can call directly in to
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600420 // getManagedObjects
421 if (!connection.second.empty())
422 {
423 getManagedObjectsForEnumerate(
424 transaction->objectPath, connection.second,
425 connection.first, transaction);
426 }
427 else
428 {
Ed Tanous7c091622019-05-23 11:42:36 -0700429 // otherwise we need to find the object manager path
430 // before we can continue
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600431 findObjectManagerPathForEnumerate(
432 transaction->objectPath, connection.first, transaction);
433 }
434 }
435 },
436 "xyz.openbmc_project.ObjectMapper",
437 "/xyz/openbmc_project/object_mapper",
438 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500439 transaction->objectPath, std::array<const char*, 0>());
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600440}
Ed Tanous64530012018-02-06 17:08:16 -0800441
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700442// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700443struct InProgressActionData
444{
Ed Tanous23a21a12020-07-25 04:45:05 +0000445 InProgressActionData(crow::Response& resIn) : res(resIn)
446 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700447 ~InProgressActionData()
448 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600449 // Methods could have been called across different owners
450 // and interfaces, where some calls failed and some passed.
451 //
452 // The rules for this are:
453 // * if no method was called - error
454 // * if a method failed and none passed - error
455 // (converse: if at least one method passed - OK)
456 // * for the method output:
457 // * if output processing didn't fail, return the data
458
459 // Only deal with method returns if nothing failed earlier
460 if (res.result() == boost::beast::http::status::ok)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700461 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600462 if (!methodPassed)
463 {
Matt Spinler06b1b632019-06-18 16:09:25 -0500464 if (!methodFailed)
Matt Spinler16caaee2019-01-15 11:40:34 -0600465 {
466 setErrorResponse(res, boost::beast::http::status::not_found,
467 methodNotFoundDesc, notFoundMsg);
468 }
469 }
470 else
471 {
472 if (outputFailed)
473 {
474 setErrorResponse(
475 res, boost::beast::http::status::internal_server_error,
476 "Method output failure", methodOutputFailedMsg);
477 }
478 else
479 {
Ed Tanous14766872022-03-15 10:44:42 -0700480 res.jsonValue["status"] = "ok";
481 res.jsonValue["message"] = "200 OK";
482 res.jsonValue["data"] = methodResponse;
Matt Spinler16caaee2019-01-15 11:40:34 -0600483 }
484 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700485 }
Matt Spinler16caaee2019-01-15 11:40:34 -0600486
Ed Tanous1abe55e2018-09-05 08:30:59 -0700487 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700488 }
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800489 InProgressActionData(const InProgressActionData&) = delete;
490 InProgressActionData(InProgressActionData&&) = delete;
491 InProgressActionData& operator=(const InProgressActionData&) = delete;
492 InProgressActionData& operator=(InProgressActionData&&) = delete;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700493
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500494 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700495 {
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600496 setErrorResponse(res, boost::beast::http::status::bad_request, desc,
497 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700498 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500499 crow::Response& res;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700500 std::string path;
501 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600502 std::string interfaceName;
Matt Spinler16caaee2019-01-15 11:40:34 -0600503 bool methodPassed = false;
504 bool methodFailed = false;
505 bool outputFailed = false;
Matt Spinler39a4e392019-01-15 11:53:13 -0600506 bool convertedToArray = false;
Matt Spinler16caaee2019-01-15 11:40:34 -0600507 nlohmann::json methodResponse;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700508 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700509};
510
Ed Tanous23a21a12020-07-25 04:45:05 +0000511inline std::vector<std::string> dbusArgSplit(const std::string& string)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700512{
513 std::vector<std::string> ret;
514 if (string.empty())
515 {
516 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700517 }
Ed Tanous0f0353b2019-10-24 11:37:51 -0700518 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700519 int containerDepth = 0;
520
521 for (std::string::const_iterator character = string.begin();
522 character != string.end(); character++)
523 {
524 ret.back() += *character;
525 switch (*character)
526 {
527 case ('a'):
528 break;
529 case ('('):
530 case ('{'):
531 containerDepth++;
532 break;
533 case ('}'):
534 case (')'):
535 containerDepth--;
536 if (containerDepth == 0)
537 {
538 if (character + 1 != string.end())
539 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700540 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700541 }
542 }
543 break;
544 default:
545 if (containerDepth == 0)
546 {
547 if (character + 1 != string.end())
548 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700549 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700550 }
551 }
552 break;
553 }
554 }
Matt Spinler4ae611d2019-01-11 15:37:06 -0600555
556 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700557}
558
Ed Tanous81ce6092020-12-17 16:54:55 +0000559inline int convertJsonToDbus(sd_bus_message* m, const std::string& argType,
560 const nlohmann::json& inputJson)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700561{
562 int r = 0;
Ed Tanous71f52d92021-02-19 08:51:17 -0800563 BMCWEB_LOG_DEBUG << "Converting "
564 << inputJson.dump(2, ' ', true,
565 nlohmann::json::error_handler_t::replace)
Ed Tanous81ce6092020-12-17 16:54:55 +0000566 << " to type: " << argType;
567 const std::vector<std::string> argTypes = dbusArgSplit(argType);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700568
Ed Tanous1abe55e2018-09-05 08:30:59 -0700569 // Assume a single object for now.
Ed Tanous81ce6092020-12-17 16:54:55 +0000570 const nlohmann::json* j = &inputJson;
571 nlohmann::json::const_iterator jIt = inputJson.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700572
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500573 for (const std::string& argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700574 {
575 // If we are decoding multiple objects, grab the pointer to the
576 // iterator, and increment it for the next loop
577 if (argTypes.size() > 1)
578 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000579 if (jIt == inputJson.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700580 {
581 return -2;
582 }
583 j = &*jIt;
584 jIt++;
585 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500586 const int64_t* intValue = j->get_ptr<const int64_t*>();
587 const std::string* stringValue = j->get_ptr<const std::string*>();
588 const double* doubleValue = j->get_ptr<const double*>();
589 const bool* b = j->get_ptr<const bool*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700590 int64_t v = 0;
591 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700592
Ed Tanous1abe55e2018-09-05 08:30:59 -0700593 // Do some basic type conversions that make sense. uint can be
594 // converted to int. int and uint can be converted to double
Ed Tanous66664f22019-10-11 13:05:49 -0700595 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700596 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500597 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700598 if (uintValue != nullptr)
599 {
600 v = static_cast<int64_t>(*uintValue);
601 intValue = &v;
602 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700603 }
Ed Tanous66664f22019-10-11 13:05:49 -0700604 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700605 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500606 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700607 if (uintValue != nullptr)
608 {
609 d = static_cast<double>(*uintValue);
610 doubleValue = &d;
611 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700612 }
Ed Tanous66664f22019-10-11 13:05:49 -0700613 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700614 {
Ed Tanous66664f22019-10-11 13:05:49 -0700615 if (intValue != nullptr)
616 {
617 d = static_cast<double>(*intValue);
618 doubleValue = &d;
619 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700620 }
621
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700622 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700623 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700624 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700625 {
626 return -1;
627 }
Ed Tanous271584a2019-07-09 16:24:22 -0700628 r = sd_bus_message_append_basic(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500629 m, argCode[0], static_cast<const void*>(stringValue->data()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700630 if (r < 0)
631 {
632 return r;
633 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700634 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700635 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700636 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700637 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700638 {
639 return -1;
640 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500641 if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
642 (*intValue > std::numeric_limits<int32_t>::max()))
643 {
644 return -ERANGE;
645 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700646 int32_t i = static_cast<int32_t>(*intValue);
647 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700648 if (r < 0)
649 {
650 return r;
651 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700652 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700653 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700654 {
655 // lots of ways bool could be represented here. Try them all
Ed Tanouse662eae2022-01-25 10:39:19 -0800656 int boolInt = 0;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700657 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700658 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500659 if (*intValue == 1)
660 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800661 boolInt = 1;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500662 }
663 else if (*intValue == 0)
664 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800665 boolInt = 0;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500666 }
667 else
668 {
669 return -ERANGE;
670 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700671 }
672 else if (b != nullptr)
673 {
Matt Spinlera2f02632019-01-18 10:15:35 -0600674 boolInt = *b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700675 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700676 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700677 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700678 boolInt = boost::istarts_with(*stringValue, "t") ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700679 }
680 else
681 {
682 return -1;
683 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700684 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700685 if (r < 0)
686 {
687 return r;
688 }
689 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700690 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700691 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700692 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700693 {
694 return -1;
695 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500696 if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
697 (*intValue > std::numeric_limits<int16_t>::max()))
698 {
699 return -ERANGE;
700 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700701 int16_t n = static_cast<int16_t>(*intValue);
702 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700703 if (r < 0)
704 {
705 return r;
706 }
707 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700708 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700709 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700710 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700711 {
712 return -1;
713 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700714 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700715 if (r < 0)
716 {
717 return r;
718 }
719 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700720 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700721 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500722 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700723 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700724 {
725 return -1;
726 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000727 if (*uintValue > std::numeric_limits<uint8_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500728 {
729 return -ERANGE;
730 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700731 uint8_t y = static_cast<uint8_t>(*uintValue);
732 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700733 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700734 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700735 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500736 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700737 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700738 {
739 return -1;
740 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000741 if (*uintValue > std::numeric_limits<uint16_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500742 {
743 return -ERANGE;
744 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700745 uint16_t q = static_cast<uint16_t>(*uintValue);
746 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700747 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700748 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700749 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500750 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700751 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700752 {
753 return -1;
754 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000755 if (*uintValue > std::numeric_limits<uint32_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500756 {
757 return -ERANGE;
758 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700759 uint32_t u = static_cast<uint32_t>(*uintValue);
760 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700761 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700762 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700763 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500764 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700765 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700766 {
767 return -1;
768 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700769 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700770 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700771 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700772 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500773 if (doubleValue == nullptr)
774 {
775 return -1;
776 }
777 if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
778 (*doubleValue > std::numeric_limits<double>::max()))
779 {
780 return -ERANGE;
781 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700782 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700783 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700784 else if (boost::starts_with(argCode, "a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700785 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700786 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700787 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700788 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700789 if (r < 0)
790 {
791 return r;
792 }
793
Ed Tanous0dfeda62019-10-24 11:21:38 -0700794 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700795 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700796 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700797 if (r < 0)
798 {
799 return r;
800 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700801 }
802 sd_bus_message_close_container(m);
803 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700804 else if (boost::starts_with(argCode, "v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700805 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700806 std::string containedType = argCode.substr(1);
807 BMCWEB_LOG_DEBUG << "variant type: " << argCode
808 << " appending variant of type: " << containedType;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700809 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700810 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700811 if (r < 0)
812 {
813 return r;
814 }
815
Ed Tanous81ce6092020-12-17 16:54:55 +0000816 r = convertJsonToDbus(m, containedType, inputJson);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700817 if (r < 0)
818 {
819 return r;
820 }
821
822 r = sd_bus_message_close_container(m);
823 if (r < 0)
824 {
825 return r;
826 }
827 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700828 else if (boost::starts_with(argCode, "(") &&
829 boost::ends_with(argCode, ")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700830 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700831 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700832 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700833 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800834 if (r < 0)
835 {
836 return r;
837 }
838
Ed Tanous1abe55e2018-09-05 08:30:59 -0700839 nlohmann::json::const_iterator it = j->begin();
Ed Tanous81ce6092020-12-17 16:54:55 +0000840 for (const std::string& argCode2 : dbusArgSplit(argType))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700841 {
842 if (it == j->end())
843 {
844 return -1;
845 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000846 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700847 if (r < 0)
848 {
849 return r;
850 }
851 it++;
852 }
853 r = sd_bus_message_close_container(m);
854 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700855 else if (boost::starts_with(argCode, "{") &&
856 boost::ends_with(argCode, "}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700857 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700858 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700859 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700860 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800861 if (r < 0)
862 {
863 return r;
864 }
865
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700866 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700867 if (codes.size() != 2)
868 {
869 return -1;
870 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700871 const std::string& keyType = codes[0];
872 const std::string& valueType = codes[1];
Ed Tanous3174e4d2020-10-07 11:41:22 -0700873 for (const auto& it : j->items())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700874 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700875 r = convertJsonToDbus(m, keyType, it.key());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700876 if (r < 0)
877 {
878 return r;
879 }
880
Ed Tanous2c70f802020-09-28 14:29:23 -0700881 r = convertJsonToDbus(m, valueType, it.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700882 if (r < 0)
883 {
884 return r;
885 }
886 }
887 r = sd_bus_message_close_container(m);
888 }
889 else
890 {
891 return -2;
892 }
893 if (r < 0)
894 {
895 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700896 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700897
Ed Tanous1abe55e2018-09-05 08:30:59 -0700898 if (argTypes.size() > 1)
899 {
900 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700901 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700902 }
Matt Spinler127ea542019-01-14 11:04:28 -0600903
904 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700905}
906
Matt Spinlerd22a7132019-01-14 12:14:30 -0600907template <typename T>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500908int readMessageItem(const std::string& typeCode, sdbusplus::message::message& m,
909 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600910{
911 T value;
912
913 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
914 if (r < 0)
915 {
916 BMCWEB_LOG_ERROR << "sd_bus_message_read_basic on type " << typeCode
917 << " failed!";
918 return r;
919 }
920
921 data = value;
922 return 0;
923}
924
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500925int convertDBusToJSON(const std::string& returnType,
926 sdbusplus::message::message& m, nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600927
Ed Tanous23a21a12020-07-25 04:45:05 +0000928inline int readDictEntryFromMessage(const std::string& typeCode,
929 sdbusplus::message::message& m,
930 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600931{
932 std::vector<std::string> types = dbusArgSplit(typeCode);
933 if (types.size() != 2)
934 {
935 BMCWEB_LOG_ERROR << "wrong number contained types in dictionary: "
936 << types.size();
937 return -1;
938 }
939
940 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
941 typeCode.c_str());
942 if (r < 0)
943 {
944 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container with rc " << r;
945 return r;
946 }
947
948 nlohmann::json key;
949 r = convertDBusToJSON(types[0], m, key);
950 if (r < 0)
951 {
952 return r;
953 }
954
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500955 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -0600956 if (keyPtr == nullptr)
957 {
958 // json doesn't support non-string keys. If we hit this condition,
959 // convert the result to a string so we can proceed
Ed Tanous71f52d92021-02-19 08:51:17 -0800960 key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500961 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -0700962 // in theory this can't fail now, but lets be paranoid about it
963 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -0600964 if (keyPtr == nullptr)
965 {
966 return -1;
967 }
968 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500969 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -0600970
971 r = convertDBusToJSON(types[1], m, value);
972 if (r < 0)
973 {
974 return r;
975 }
976
977 r = sd_bus_message_exit_container(m.get());
978 if (r < 0)
979 {
980 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
981 return r;
982 }
983
984 return 0;
985}
986
Ed Tanous23a21a12020-07-25 04:45:05 +0000987inline int readArrayFromMessage(const std::string& typeCode,
988 sdbusplus::message::message& m,
989 nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -0600990{
991 if (typeCode.size() < 2)
992 {
993 BMCWEB_LOG_ERROR << "Type code " << typeCode
994 << " too small for an array";
995 return -1;
996 }
997
998 std::string containedType = typeCode.substr(1);
999
1000 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
1001 containedType.c_str());
1002 if (r < 0)
1003 {
1004 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1005 << r;
1006 return r;
1007 }
1008
1009 bool dict = boost::starts_with(containedType, "{") &&
1010 boost::ends_with(containedType, "}");
1011
1012 if (dict)
1013 {
1014 // Remove the { }
1015 containedType = containedType.substr(1, containedType.size() - 2);
1016 data = nlohmann::json::object();
1017 }
1018 else
1019 {
1020 data = nlohmann::json::array();
1021 }
1022
1023 while (true)
1024 {
Ed Tanouse662eae2022-01-25 10:39:19 -08001025 r = sd_bus_message_at_end(m.get(), 0);
Matt Spinler6df8f992019-01-14 12:47:47 -06001026 if (r < 0)
1027 {
1028 BMCWEB_LOG_ERROR << "sd_bus_message_at_end failed";
1029 return r;
1030 }
1031
1032 if (r > 0)
1033 {
1034 break;
1035 }
1036
1037 // Dictionaries are only ever seen in an array
1038 if (dict)
1039 {
1040 r = readDictEntryFromMessage(containedType, m, data);
1041 if (r < 0)
1042 {
1043 return r;
1044 }
1045 }
1046 else
1047 {
1048 data.push_back(nlohmann::json());
1049
1050 r = convertDBusToJSON(containedType, m, data.back());
1051 if (r < 0)
1052 {
1053 return r;
1054 }
1055 }
1056 }
1057
1058 r = sd_bus_message_exit_container(m.get());
1059 if (r < 0)
1060 {
1061 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1062 return r;
1063 }
1064
1065 return 0;
1066}
1067
Ed Tanous23a21a12020-07-25 04:45:05 +00001068inline int readStructFromMessage(const std::string& typeCode,
1069 sdbusplus::message::message& m,
1070 nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001071{
1072 if (typeCode.size() < 3)
1073 {
1074 BMCWEB_LOG_ERROR << "Type code " << typeCode
1075 << " too small for a struct";
1076 return -1;
1077 }
1078
1079 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1080 std::vector<std::string> types = dbusArgSplit(containedTypes);
1081
1082 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1083 containedTypes.c_str());
1084 if (r < 0)
1085 {
1086 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1087 << r;
1088 return r;
1089 }
1090
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001091 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001092 {
1093 data.push_back(nlohmann::json());
1094 r = convertDBusToJSON(type, m, data.back());
1095 if (r < 0)
1096 {
1097 return r;
1098 }
1099 }
1100
1101 r = sd_bus_message_exit_container(m.get());
1102 if (r < 0)
1103 {
1104 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1105 return r;
1106 }
1107 return 0;
1108}
1109
Ed Tanous23a21a12020-07-25 04:45:05 +00001110inline int readVariantFromMessage(sdbusplus::message::message& m,
1111 nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001112{
Ed Tanous543f4402022-01-06 13:12:53 -08001113 const char* containerType = nullptr;
Ed Tanous99131cd2019-10-24 11:12:47 -07001114 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001115 if (r < 0)
1116 {
1117 BMCWEB_LOG_ERROR << "sd_bus_message_peek_type failed";
1118 return r;
1119 }
1120
1121 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1122 containerType);
1123 if (r < 0)
1124 {
1125 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1126 << r;
1127 return r;
1128 }
1129
1130 r = convertDBusToJSON(containerType, m, data);
1131 if (r < 0)
1132 {
1133 return r;
1134 }
1135
1136 r = sd_bus_message_exit_container(m.get());
1137 if (r < 0)
1138 {
1139 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed";
1140 return r;
1141 }
1142
1143 return 0;
1144}
1145
Ed Tanous23a21a12020-07-25 04:45:05 +00001146inline int convertDBusToJSON(const std::string& returnType,
1147 sdbusplus::message::message& m,
1148 nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001149{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001150 int r = 0;
1151 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1152
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001153 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001154 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001155 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001156 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001157 {
1158 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001159 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001160 }
1161
Ed Tanousd4d25792020-09-29 15:15:03 -07001162 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001163 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001164 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001165 if (r < 0)
1166 {
1167 return r;
1168 }
1169 }
1170 else if (typeCode == "b")
1171 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001172 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001173 if (r < 0)
1174 {
1175 return r;
1176 }
1177
Matt Spinlerf39420c2019-01-30 12:57:18 -06001178 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001179 }
1180 else if (typeCode == "u")
1181 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001182 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001183 if (r < 0)
1184 {
1185 return r;
1186 }
1187 }
1188 else if (typeCode == "i")
1189 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001190 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001191 if (r < 0)
1192 {
1193 return r;
1194 }
1195 }
1196 else if (typeCode == "x")
1197 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001198 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001199 if (r < 0)
1200 {
1201 return r;
1202 }
1203 }
1204 else if (typeCode == "t")
1205 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001206 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001207 if (r < 0)
1208 {
1209 return r;
1210 }
1211 }
1212 else if (typeCode == "n")
1213 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001214 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001215 if (r < 0)
1216 {
1217 return r;
1218 }
1219 }
1220 else if (typeCode == "q")
1221 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001222 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001223 if (r < 0)
1224 {
1225 return r;
1226 }
1227 }
1228 else if (typeCode == "y")
1229 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001230 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001231 if (r < 0)
1232 {
1233 return r;
1234 }
1235 }
1236 else if (typeCode == "d")
1237 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001238 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001239 if (r < 0)
1240 {
1241 return r;
1242 }
1243 }
1244 else if (typeCode == "h")
1245 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001246 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001247 if (r < 0)
1248 {
1249 return r;
1250 }
1251 }
Matt Spinler6df8f992019-01-14 12:47:47 -06001252 else if (boost::starts_with(typeCode, "a"))
1253 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001254 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001255 if (r < 0)
1256 {
1257 return r;
1258 }
1259 }
Matt Spinler75c6c672019-01-14 13:01:46 -06001260 else if (boost::starts_with(typeCode, "(") &&
1261 boost::ends_with(typeCode, ")"))
1262 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001263 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001264 if (r < 0)
1265 {
1266 return r;
1267 }
1268 }
Matt Spinler89c19702019-01-14 13:13:00 -06001269 else if (boost::starts_with(typeCode, "v"))
1270 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001271 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001272 if (r < 0)
1273 {
1274 return r;
1275 }
1276 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001277 else
1278 {
Matt Spinlerd22a7132019-01-14 12:14:30 -06001279 BMCWEB_LOG_ERROR << "Invalid D-Bus signature type " << typeCode;
1280 return -2;
1281 }
1282 }
1283
Matt Spinler16caaee2019-01-15 11:40:34 -06001284 return 0;
1285}
1286
Ed Tanousb5a76932020-09-29 16:16:58 -07001287inline void handleMethodResponse(
1288 const std::shared_ptr<InProgressActionData>& transaction,
1289 sdbusplus::message::message& m, const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001290{
Matt Spinler39a4e392019-01-15 11:53:13 -06001291 nlohmann::json data;
1292
1293 int r = convertDBusToJSON(returnType, m, data);
1294 if (r < 0)
1295 {
1296 transaction->outputFailed = true;
1297 return;
1298 }
1299
1300 if (data.is_null())
1301 {
1302 return;
1303 }
1304
1305 if (transaction->methodResponse.is_null())
1306 {
1307 transaction->methodResponse = std::move(data);
1308 return;
1309 }
1310
1311 // If they're both dictionaries or arrays, merge into one.
1312 // Otherwise, make the results an array with every result
1313 // an entry. Could also just fail in that case, but it
1314 // seems better to get the data back somehow.
1315
1316 if (transaction->methodResponse.is_object() && data.is_object())
1317 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001318 for (const auto& obj : data.items())
Matt Spinler39a4e392019-01-15 11:53:13 -06001319 {
1320 // Note: Will overwrite the data for a duplicate key
1321 transaction->methodResponse.emplace(obj.key(),
1322 std::move(obj.value()));
1323 }
1324 return;
1325 }
1326
1327 if (transaction->methodResponse.is_array() && data.is_array())
1328 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001329 for (auto& obj : data)
Matt Spinler39a4e392019-01-15 11:53:13 -06001330 {
1331 transaction->methodResponse.push_back(std::move(obj));
1332 }
1333 return;
1334 }
1335
1336 if (!transaction->convertedToArray)
1337 {
1338 // They are different types. May as well turn them into an array
1339 nlohmann::json j = std::move(transaction->methodResponse);
1340 transaction->methodResponse = nlohmann::json::array();
1341 transaction->methodResponse.push_back(std::move(j));
1342 transaction->methodResponse.push_back(std::move(data));
1343 transaction->convertedToArray = true;
1344 }
1345 else
1346 {
1347 transaction->methodResponse.push_back(std::move(data));
1348 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001349}
1350
Ed Tanousb5a76932020-09-29 16:16:58 -07001351inline void findActionOnInterface(
1352 const std::shared_ptr<InProgressActionData>& transaction,
1353 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001354{
1355 BMCWEB_LOG_DEBUG << "findActionOnInterface for connection "
1356 << connectionName;
1357 crow::connections::systemBus->async_method_call(
1358 [transaction, connectionName{std::string(connectionName)}](
1359 const boost::system::error_code ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001360 const std::string& introspectXml) {
1361 BMCWEB_LOG_DEBUG << "got xml:\n " << introspectXml;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001362 if (ec)
1363 {
1364 BMCWEB_LOG_ERROR
1365 << "Introspect call failed with error: " << ec.message()
1366 << " on process: " << connectionName << "\n";
Matt Spinler318bd892019-01-15 09:59:20 -06001367 return;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001368 }
Matt Spinler318bd892019-01-15 09:59:20 -06001369 tinyxml2::XMLDocument doc;
1370
Ed Tanous81ce6092020-12-17 16:54:55 +00001371 doc.Parse(introspectXml.data(), introspectXml.size());
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001372 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
Matt Spinler318bd892019-01-15 09:59:20 -06001373 if (pRoot == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001374 {
Matt Spinler318bd892019-01-15 09:59:20 -06001375 BMCWEB_LOG_ERROR << "XML document failed to parse "
1376 << connectionName << "\n";
1377 return;
1378 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001379 tinyxml2::XMLElement* interfaceNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001380 pRoot->FirstChildElement("interface");
1381 while (interfaceNode != nullptr)
1382 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001383 const char* thisInterfaceName =
Matt Spinler318bd892019-01-15 09:59:20 -06001384 interfaceNode->Attribute("name");
1385 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001386 {
Matt Spinler318bd892019-01-15 09:59:20 -06001387 if (!transaction->interfaceName.empty() &&
1388 (transaction->interfaceName != thisInterfaceName))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001389 {
Matt Spinler318bd892019-01-15 09:59:20 -06001390 interfaceNode =
1391 interfaceNode->NextSiblingElement("interface");
1392 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001393 }
Matt Spinler318bd892019-01-15 09:59:20 -06001394
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001395 tinyxml2::XMLElement* methodNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001396 interfaceNode->FirstChildElement("method");
1397 while (methodNode != nullptr)
1398 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001399 const char* thisMethodName =
Matt Spinler318bd892019-01-15 09:59:20 -06001400 methodNode->Attribute("name");
1401 BMCWEB_LOG_DEBUG << "Found method: " << thisMethodName;
1402 if (thisMethodName != nullptr &&
1403 thisMethodName == transaction->methodName)
1404 {
1405 BMCWEB_LOG_DEBUG
1406 << "Found method named " << thisMethodName
1407 << " on interface " << thisInterfaceName;
1408 sdbusplus::message::message m =
1409 crow::connections::systemBus->new_method_call(
1410 connectionName.c_str(),
1411 transaction->path.c_str(),
1412 thisInterfaceName,
1413 transaction->methodName.c_str());
1414
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001415 tinyxml2::XMLElement* argumentNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001416 methodNode->FirstChildElement("arg");
1417
Matt Spinler16caaee2019-01-15 11:40:34 -06001418 std::string returnType;
1419
1420 // Find the output type
1421 while (argumentNode != nullptr)
1422 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001423 const char* argDirection =
Matt Spinler16caaee2019-01-15 11:40:34 -06001424 argumentNode->Attribute("direction");
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001425 const char* argType =
Matt Spinler16caaee2019-01-15 11:40:34 -06001426 argumentNode->Attribute("type");
1427 if (argDirection != nullptr &&
1428 argType != nullptr &&
1429 std::string(argDirection) == "out")
1430 {
1431 returnType = argType;
1432 break;
1433 }
1434 argumentNode =
1435 argumentNode->NextSiblingElement("arg");
1436 }
1437
Matt Spinler318bd892019-01-15 09:59:20 -06001438 nlohmann::json::const_iterator argIt =
1439 transaction->arguments.begin();
1440
Matt Spinler16caaee2019-01-15 11:40:34 -06001441 argumentNode = methodNode->FirstChildElement("arg");
1442
Matt Spinler318bd892019-01-15 09:59:20 -06001443 while (argumentNode != nullptr)
1444 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001445 const char* argDirection =
Matt Spinler318bd892019-01-15 09:59:20 -06001446 argumentNode->Attribute("direction");
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001447 const char* argType =
Matt Spinler318bd892019-01-15 09:59:20 -06001448 argumentNode->Attribute("type");
1449 if (argDirection != nullptr &&
1450 argType != nullptr &&
1451 std::string(argDirection) == "in")
1452 {
1453 if (argIt == transaction->arguments.end())
1454 {
1455 transaction->setErrorStatus(
1456 "Invalid method args");
1457 return;
1458 }
1459 if (convertJsonToDbus(m.get(),
1460 std::string(argType),
1461 *argIt) < 0)
1462 {
1463 transaction->setErrorStatus(
1464 "Invalid method arg type");
1465 return;
1466 }
1467
1468 argIt++;
1469 }
1470 argumentNode =
1471 argumentNode->NextSiblingElement("arg");
1472 }
1473
1474 crow::connections::systemBus->async_send(
Matt Spinler16caaee2019-01-15 11:40:34 -06001475 m, [transaction, returnType](
Ed Tanous23a21a12020-07-25 04:45:05 +00001476 boost::system::error_code ec2,
1477 sdbusplus::message::message& m2) {
1478 if (ec2)
Matt Spinler318bd892019-01-15 09:59:20 -06001479 {
Matt Spinler16caaee2019-01-15 11:40:34 -06001480 transaction->methodFailed = true;
Ed Tanous23a21a12020-07-25 04:45:05 +00001481 const sd_bus_error* e = m2.get_error();
Matt Spinler06b1b632019-06-18 16:09:25 -05001482
Ed Tanouse662eae2022-01-25 10:39:19 -08001483 if (e != nullptr)
Matt Spinler06b1b632019-06-18 16:09:25 -05001484 {
1485 setErrorResponse(
1486 transaction->res,
1487 boost::beast::http::status::
1488 bad_request,
1489 e->name, e->message);
1490 }
1491 else
1492 {
1493 setErrorResponse(
1494 transaction->res,
1495 boost::beast::http::status::
1496 bad_request,
1497 "Method call failed",
1498 methodFailedMsg);
1499 }
Matt Spinler318bd892019-01-15 09:59:20 -06001500 return;
1501 }
Ed Tanous3174e4d2020-10-07 11:41:22 -07001502 transaction->methodPassed = true;
Matt Spinler16caaee2019-01-15 11:40:34 -06001503
Ed Tanous23a21a12020-07-25 04:45:05 +00001504 handleMethodResponse(transaction, m2,
Matt Spinler16caaee2019-01-15 11:40:34 -06001505 returnType);
Matt Spinler318bd892019-01-15 09:59:20 -06001506 });
1507 break;
1508 }
1509 methodNode = methodNode->NextSiblingElement("method");
1510 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001511 }
Matt Spinler318bd892019-01-15 09:59:20 -06001512 interfaceNode = interfaceNode->NextSiblingElement("interface");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001513 }
1514 },
1515 connectionName, transaction->path,
1516 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001517}
1518
zhanghch058d1b46d2021-04-01 11:18:24 +08001519inline void handleAction(const crow::Request& req,
1520 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001521 const std::string& objectPath,
1522 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001523{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001524 BMCWEB_LOG_DEBUG << "handleAction on path: " << objectPath << " and method "
1525 << methodName;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001526 nlohmann::json requestDbusData =
1527 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001528
Ed Tanous1abe55e2018-09-05 08:30:59 -07001529 if (requestDbusData.is_discarded())
1530 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001531 setErrorResponse(asyncResp->res,
1532 boost::beast::http::status::bad_request, noJsonDesc,
1533 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001534 return;
1535 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001536 nlohmann::json::iterator data = requestDbusData.find("data");
1537 if (data == requestDbusData.end())
1538 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001539 setErrorResponse(asyncResp->res,
1540 boost::beast::http::status::bad_request, noJsonDesc,
1541 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001542 return;
1543 }
1544
1545 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001546 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001547 setErrorResponse(asyncResp->res,
1548 boost::beast::http::status::bad_request, noJsonDesc,
1549 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001550 return;
1551 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001552 auto transaction = std::make_shared<InProgressActionData>(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001553
1554 transaction->path = objectPath;
1555 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001556 transaction->arguments = std::move(*data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001557 crow::connections::systemBus->async_method_call(
1558 [transaction](
1559 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001560 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1561 interfaceNames) {
Ed Tanous26f69762022-01-25 09:49:11 -08001562 if (ec || interfaceNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001563 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001564 BMCWEB_LOG_ERROR << "Can't find object";
Matt Spinler6db06242018-12-11 11:21:22 -06001565 setErrorResponse(transaction->res,
1566 boost::beast::http::status::not_found,
1567 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001568 return;
1569 }
1570
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001571 BMCWEB_LOG_DEBUG << "GetObject returned " << interfaceNames.size()
1572 << " object(s)";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001573
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001574 for (const std::pair<std::string, std::vector<std::string>>&
1575 object : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001576 {
1577 findActionOnInterface(transaction, object.first);
1578 }
1579 },
1580 "xyz.openbmc_project.ObjectMapper",
1581 "/xyz/openbmc_project/object_mapper",
1582 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
1583 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001584}
1585
zhanghch058d1b46d2021-04-01 11:18:24 +08001586inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1587 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001588{
1589 BMCWEB_LOG_DEBUG << "handleDelete on path: " << objectPath;
1590
1591 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +08001592 [asyncResp, objectPath](
Matt Spinlerde818812018-12-11 16:39:20 -06001593 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001594 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1595 interfaceNames) {
Ed Tanous26f69762022-01-25 09:49:11 -08001596 if (ec || interfaceNames.empty())
Matt Spinlerde818812018-12-11 16:39:20 -06001597 {
1598 BMCWEB_LOG_ERROR << "Can't find object";
zhanghch058d1b46d2021-04-01 11:18:24 +08001599 setErrorResponse(asyncResp->res,
Matt Spinler62d2e8b2019-01-22 13:45:51 -06001600 boost::beast::http::status::method_not_allowed,
1601 methodNotAllowedDesc, methodNotAllowedMsg);
Matt Spinlerde818812018-12-11 16:39:20 -06001602 return;
1603 }
1604
zhanghch058d1b46d2021-04-01 11:18:24 +08001605 auto transaction =
1606 std::make_shared<InProgressActionData>(asyncResp->res);
Matt Spinlerde818812018-12-11 16:39:20 -06001607 transaction->path = objectPath;
1608 transaction->methodName = "Delete";
1609 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
1610
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001611 for (const std::pair<std::string, std::vector<std::string>>&
1612 object : interfaceNames)
Matt Spinlerde818812018-12-11 16:39:20 -06001613 {
1614 findActionOnInterface(transaction, object.first);
1615 }
1616 },
1617 "xyz.openbmc_project.ObjectMapper",
1618 "/xyz/openbmc_project/object_mapper",
1619 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001620 std::array<const char*, 0>());
Matt Spinlerde818812018-12-11 16:39:20 -06001621}
1622
zhanghch058d1b46d2021-04-01 11:18:24 +08001623inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1624 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001625{
1626 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001627 [asyncResp](
1628 const boost::system::error_code ec,
1629 const dbus::utility::MapperGetSubTreePathsResponse& objectPaths) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001630 if (ec)
1631 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001632 setErrorResponse(asyncResp->res,
1633 boost::beast::http::status::not_found,
Matt Spinlerd6091dd2018-12-06 14:08:27 -06001634 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001635 }
1636 else
1637 {
Ed Tanous14766872022-03-15 10:44:42 -07001638 asyncResp->res.jsonValue["status"] = "ok";
1639 asyncResp->res.jsonValue["message"] = "200 OK";
1640 asyncResp->res.jsonValue["data"] = objectPaths;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001641 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001642 },
1643 "xyz.openbmc_project.ObjectMapper",
1644 "/xyz/openbmc_project/object_mapper",
1645 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", objectPath,
Ed Tanousf839dfe2018-11-12 11:11:15 -08001646 depth, std::array<std::string, 0>());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001647}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001648
zhanghch058d1b46d2021-04-01 11:18:24 +08001649inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1650 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001651{
Ed Tanous049a0512018-11-01 13:58:42 -07001652 BMCWEB_LOG_DEBUG << "Doing enumerate on " << objectPath;
Ed Tanous049a0512018-11-01 13:58:42 -07001653
Ed Tanous14766872022-03-15 10:44:42 -07001654 asyncResp->res.jsonValue["message"] = "200 OK";
1655 asyncResp->res.jsonValue["status"] = "ok";
1656 asyncResp->res.jsonValue["data"] = nlohmann::json::object();
Ed Tanous049a0512018-11-01 13:58:42 -07001657
Ed Tanous1abe55e2018-09-05 08:30:59 -07001658 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001659 [objectPath, asyncResp](
1660 const boost::system::error_code ec,
1661 const dbus::utility::MapperGetSubTreeResponse& objectNames) {
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001662 auto transaction = std::make_shared<InProgressEnumerateData>(
1663 objectPath, asyncResp);
1664
1665 transaction->subtree =
Ed Tanousb9d36b42022-02-26 21:42:46 -08001666 std::make_shared<dbus::utility::MapperGetSubTreeResponse>(
1667 objectNames);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001668
Ed Tanous1abe55e2018-09-05 08:30:59 -07001669 if (ec)
1670 {
Matt Spinler2ae60092018-12-06 10:35:36 -06001671 BMCWEB_LOG_ERROR << "GetSubTree failed on "
1672 << transaction->objectPath;
1673 setErrorResponse(transaction->asyncResp->res,
1674 boost::beast::http::status::not_found,
1675 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001676 return;
1677 }
Ed Tanous64530012018-02-06 17:08:16 -08001678
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001679 // Add the data for the path passed in to the results
1680 // as if GetSubTree returned it, and continue on enumerating
1681 getObjectAndEnumerate(transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001682 },
1683 "xyz.openbmc_project.ObjectMapper",
1684 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -07001685 "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath, 0,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001686 std::array<const char*, 0>());
Ed Tanous64530012018-02-06 17:08:16 -08001687}
Ed Tanous911ac312017-08-15 09:37:42 -07001688
zhanghch058d1b46d2021-04-01 11:18:24 +08001689inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1690 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001691{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001692 BMCWEB_LOG_DEBUG << "handleGet: " << objectPath << " prop:" << destProperty;
1693 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001694 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001695
Ed Tanous1abe55e2018-09-05 08:30:59 -07001696 std::shared_ptr<std::string> path =
1697 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001698
Ed Tanous1abe55e2018-09-05 08:30:59 -07001699 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001700 [asyncResp, path,
1701 propertyName](const boost::system::error_code ec,
1702 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous26f69762022-01-25 09:49:11 -08001703 if (ec || objectNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001704 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001705 setErrorResponse(asyncResp->res,
1706 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001707 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001708 return;
1709 }
1710 std::shared_ptr<nlohmann::json> response =
1711 std::make_shared<nlohmann::json>(nlohmann::json::object());
Ed Tanous7c091622019-05-23 11:42:36 -07001712 // The mapper should never give us an empty interface names
1713 // list, but check anyway
Ed Tanous23a21a12020-07-25 04:45:05 +00001714 for (const std::pair<std::string, std::vector<std::string>>&
Ed Tanous81ce6092020-12-17 16:54:55 +00001715 connection : objectNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001716 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001717 const std::vector<std::string>& interfaceNames =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001718 connection.second;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001719
Ed Tanous26f69762022-01-25 09:49:11 -08001720 if (interfaceNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001721 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001722 setErrorResponse(asyncResp->res,
1723 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001724 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001725 return;
1726 }
1727
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001728 for (const std::string& interface : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001729 {
Matt Spinlerfe7e97d2019-01-30 15:33:21 -06001730 sdbusplus::message::message m =
1731 crow::connections::systemBus->new_method_call(
1732 connection.first.c_str(), path->c_str(),
1733 "org.freedesktop.DBus.Properties", "GetAll");
1734 m.append(interface);
1735 crow::connections::systemBus->async_send(
zhanghch058d1b46d2021-04-01 11:18:24 +08001736 m, [asyncResp, response,
Ed Tanous23a21a12020-07-25 04:45:05 +00001737 propertyName](const boost::system::error_code ec2,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001738 sdbusplus::message::message& msg) {
Ed Tanous23a21a12020-07-25 04:45:05 +00001739 if (ec2)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001740 {
1741 BMCWEB_LOG_ERROR << "Bad dbus request error: "
Ed Tanous23a21a12020-07-25 04:45:05 +00001742 << ec2;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001743 }
1744 else
1745 {
Ed Tanous984a4c22021-06-02 13:38:26 -07001746 nlohmann::json properties;
1747 int r =
1748 convertDBusToJSON("a{sv}", msg, properties);
1749 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001750 {
Ed Tanous984a4c22021-06-02 13:38:26 -07001751 BMCWEB_LOG_ERROR
1752 << "convertDBusToJSON failed";
1753 }
1754 else
1755 {
1756 for (auto& prop : properties.items())
1757 {
1758 // if property name is empty, or
1759 // matches our search query, add it
1760 // to the response json
Ed Tanous1abe55e2018-09-05 08:30:59 -07001761
Ed Tanous984a4c22021-06-02 13:38:26 -07001762 if (propertyName->empty())
1763 {
1764 (*response)[prop.key()] =
1765 std::move(prop.value());
1766 }
1767 else if (prop.key() == *propertyName)
1768 {
1769 *response = std::move(prop.value());
1770 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001771 }
1772 }
1773 }
1774 if (response.use_count() == 1)
1775 {
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001776 if (!propertyName->empty() && response->empty())
1777 {
1778 setErrorResponse(
zhanghch058d1b46d2021-04-01 11:18:24 +08001779 asyncResp->res,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001780 boost::beast::http::status::not_found,
1781 propNotFoundDesc, notFoundMsg);
1782 }
1783 else
1784 {
Ed Tanous14766872022-03-15 10:44:42 -07001785 asyncResp->res.jsonValue["status"] = "ok";
1786 asyncResp->res.jsonValue["message"] =
1787 "200 OK";
1788 asyncResp->res.jsonValue["data"] =
1789 *response;
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001790 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001791 }
Matt Spinlerfe7e97d2019-01-30 15:33:21 -06001792 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001793 }
1794 }
1795 },
1796 "xyz.openbmc_project.ObjectMapper",
1797 "/xyz/openbmc_project/object_mapper",
1798 "xyz.openbmc_project.ObjectMapper", "GetObject", *path,
1799 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001800}
1801
Ed Tanous1abe55e2018-09-05 08:30:59 -07001802struct AsyncPutRequest
1803{
zhanghch058d1b46d2021-04-01 11:18:24 +08001804 AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
1805 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001806 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001807 ~AsyncPutRequest()
1808 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001809 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001810 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001811 setErrorResponse(asyncResp->res,
1812 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001813 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001814 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001815 }
1816
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001817 AsyncPutRequest(const AsyncPutRequest&) = delete;
1818 AsyncPutRequest(AsyncPutRequest&&) = delete;
1819 AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1820 AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1821
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001822 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001823 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001824 setErrorResponse(asyncResp->res,
1825 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001826 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001827 }
1828
zhanghch058d1b46d2021-04-01 11:18:24 +08001829 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001830 std::string objectPath;
1831 std::string propertyName;
1832 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001833};
1834
zhanghch058d1b46d2021-04-01 11:18:24 +08001835inline void handlePut(const crow::Request& req,
1836 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001837 const std::string& objectPath,
1838 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001839{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001840 if (destProperty.empty())
1841 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001842 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001843 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001844 return;
1845 }
1846
Ed Tanous1abe55e2018-09-05 08:30:59 -07001847 nlohmann::json requestDbusData =
1848 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001849
Ed Tanous1abe55e2018-09-05 08:30:59 -07001850 if (requestDbusData.is_discarded())
1851 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001852 setErrorResponse(asyncResp->res,
1853 boost::beast::http::status::bad_request, noJsonDesc,
1854 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001855 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001856 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001857
Ed Tanous1abe55e2018-09-05 08:30:59 -07001858 nlohmann::json::const_iterator propertyIt = requestDbusData.find("data");
1859 if (propertyIt == requestDbusData.end())
1860 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001861 setErrorResponse(asyncResp->res,
1862 boost::beast::http::status::bad_request, noJsonDesc,
1863 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001864 return;
1865 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001866 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001867 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001868 transaction->objectPath = objectPath;
1869 transaction->propertyName = destProperty;
1870 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001871
Ed Tanous1abe55e2018-09-05 08:30:59 -07001872 crow::connections::systemBus->async_method_call(
Ed Tanous23a21a12020-07-25 04:45:05 +00001873 [transaction](const boost::system::error_code ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001874 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous26f69762022-01-25 09:49:11 -08001875 if (!ec2 && objectNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001876 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001877 setErrorResponse(transaction->asyncResp->res,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001878 boost::beast::http::status::not_found,
1879 propNotFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001880 return;
1881 }
Ed Tanous911ac312017-08-15 09:37:42 -07001882
Ed Tanous23a21a12020-07-25 04:45:05 +00001883 for (const std::pair<std::string, std::vector<std::string>>&
Ed Tanous81ce6092020-12-17 16:54:55 +00001884 connection : objectNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001885 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001886 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001887
Ed Tanous1abe55e2018-09-05 08:30:59 -07001888 crow::connections::systemBus->async_method_call(
1889 [connectionName{std::string(connectionName)},
Ed Tanous23a21a12020-07-25 04:45:05 +00001890 transaction](const boost::system::error_code ec3,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001891 const std::string& introspectXml) {
Ed Tanous23a21a12020-07-25 04:45:05 +00001892 if (ec3)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001893 {
1894 BMCWEB_LOG_ERROR
1895 << "Introspect call failed with error: "
Ed Tanous23a21a12020-07-25 04:45:05 +00001896 << ec3.message()
Ed Tanous1abe55e2018-09-05 08:30:59 -07001897 << " on process: " << connectionName;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001898 transaction->setErrorStatus("Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001899 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001900 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001901 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001902
Ed Tanous1abe55e2018-09-05 08:30:59 -07001903 doc.Parse(introspectXml.c_str());
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001904 tinyxml2::XMLNode* pRoot =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001905 doc.FirstChildElement("node");
1906 if (pRoot == nullptr)
1907 {
1908 BMCWEB_LOG_ERROR << "XML document failed to parse: "
1909 << introspectXml;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001910 transaction->setErrorStatus("Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001911 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001912 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001913 tinyxml2::XMLElement* ifaceNode =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001914 pRoot->FirstChildElement("interface");
1915 while (ifaceNode != nullptr)
1916 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001917 const char* interfaceName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001918 ifaceNode->Attribute("name");
1919 BMCWEB_LOG_DEBUG << "found interface "
1920 << interfaceName;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001921 tinyxml2::XMLElement* propNode =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001922 ifaceNode->FirstChildElement("property");
1923 while (propNode != nullptr)
1924 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001925 const char* propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001926 propNode->Attribute("name");
1927 BMCWEB_LOG_DEBUG << "Found property "
1928 << propertyName;
1929 if (propertyName == transaction->propertyName)
1930 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001931 const char* argType =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001932 propNode->Attribute("type");
1933 if (argType != nullptr)
1934 {
1935 sdbusplus::message::message m =
1936 crow::connections::systemBus
1937 ->new_method_call(
1938 connectionName.c_str(),
1939 transaction->objectPath
1940 .c_str(),
1941 "org.freedesktop.DBus."
1942 "Properties",
1943 "Set");
1944 m.append(interfaceName,
1945 transaction->propertyName);
1946 int r = sd_bus_message_open_container(
1947 m.get(), SD_BUS_TYPE_VARIANT,
1948 argType);
1949 if (r < 0)
1950 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001951 transaction->setErrorStatus(
1952 "Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001953 return;
1954 }
1955 r = convertJsonToDbus(
1956 m.get(), argType,
1957 transaction->propertyValue);
1958 if (r < 0)
1959 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -05001960 if (r == -ERANGE)
1961 {
1962 transaction->setErrorStatus(
1963 "Provided property value "
1964 "is out of range for the "
1965 "property type");
1966 }
1967 else
1968 {
1969 transaction->setErrorStatus(
1970 "Invalid arg type");
1971 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001972 return;
1973 }
1974 r = sd_bus_message_close_container(
1975 m.get());
1976 if (r < 0)
1977 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001978 transaction->setErrorStatus(
1979 "Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001980 return;
1981 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001982 crow::connections::systemBus
1983 ->async_send(
1984 m,
1985 [transaction](
1986 boost::system::error_code
1987 ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001988 sdbusplus::message::message&
Ed Tanous23a21a12020-07-25 04:45:05 +00001989 m2) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001990 BMCWEB_LOG_DEBUG << "sent";
1991 if (ec)
1992 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001993 const sd_bus_error* e =
Ed Tanous23a21a12020-07-25 04:45:05 +00001994 m2.get_error();
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001995 setErrorResponse(
zhanghch058d1b46d2021-04-01 11:18:24 +08001996 transaction
1997 ->asyncResp
1998 ->res,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001999 boost::beast::http::
2000 status::
2001 forbidden,
Ed Tanouse662eae2022-01-25 10:39:19 -08002002 (e) != nullptr
2003 ? e->name
Matt Spinler06b1b632019-06-18 16:09:25 -05002004 : ec.category()
2005 .name(),
Ed Tanouse662eae2022-01-25 10:39:19 -08002006 (e) != nullptr
2007 ? e->message
Matt Spinler06b1b632019-06-18 16:09:25 -05002008 : ec.message());
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06002009 }
2010 else
2011 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002012 transaction->asyncResp
Ed Tanous14766872022-03-15 10:44:42 -07002013 ->res.jsonValue
2014 ["status"] =
2015 "ok";
2016 transaction->asyncResp
2017 ->res.jsonValue
2018 ["message"] =
2019 "200 OK";
2020 transaction->asyncResp
2021 ->res
2022 .jsonValue["data"] =
2023 nullptr;
Ed Tanous1abe55e2018-09-05 08:30:59 -07002024 }
2025 });
2026 }
2027 }
2028 propNode =
2029 propNode->NextSiblingElement("property");
2030 }
2031 ifaceNode =
2032 ifaceNode->NextSiblingElement("interface");
2033 }
2034 },
2035 connectionName, transaction->objectPath,
2036 "org.freedesktop.DBus.Introspectable", "Introspect");
2037 }
2038 },
2039 "xyz.openbmc_project.ObjectMapper",
2040 "/xyz/openbmc_project/object_mapper",
2041 "xyz.openbmc_project.ObjectMapper", "GetObject",
2042 transaction->objectPath, std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07002043}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002044
zhanghch058d1b46d2021-04-01 11:18:24 +08002045inline void handleDBusUrl(const crow::Request& req,
2046 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002047 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002048{
Ed Tanous049a0512018-11-01 13:58:42 -07002049
2050 // If accessing a single attribute, fill in and update objectPath,
2051 // otherwise leave destProperty blank
Ed Tanouse05aec52022-01-25 10:28:56 -08002052 std::string destProperty;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002053 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002054 size_t attrPosition = objectPath.find(attrSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002055 if (attrPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002056 {
2057 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2058 objectPath.length());
2059 objectPath = objectPath.substr(0, attrPosition);
2060 }
2061
Ed Tanousb41187f2019-10-24 16:30:02 -07002062 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002063 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002064 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002065 size_t actionPosition = objectPath.find(actionSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002066 if (actionPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002067 {
2068 std::string postProperty =
2069 objectPath.substr((actionPosition + strlen(actionSeperator)),
2070 objectPath.length());
2071 objectPath = objectPath.substr(0, actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002072 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002073 return;
2074 }
2075 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002076 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002077 {
2078 if (boost::ends_with(objectPath, "/enumerate"))
2079 {
2080 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2081 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002082 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002083 }
2084 else if (boost::ends_with(objectPath, "/list"))
2085 {
2086 objectPath.erase(objectPath.end() - sizeof("list"),
2087 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002088 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002089 }
2090 else
2091 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002092 // Trim any trailing "/" at the end
2093 if (boost::ends_with(objectPath, "/"))
2094 {
2095 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002096 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002097 }
2098 else
2099 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002100 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002101 }
Ed Tanous049a0512018-11-01 13:58:42 -07002102 }
2103 return;
2104 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002105 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002106 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002107 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002108 return;
2109 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002110 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002111 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002112 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002113 return;
2114 }
Ed Tanous049a0512018-11-01 13:58:42 -07002115
zhanghch058d1b46d2021-04-01 11:18:24 +08002116 setErrorResponse(asyncResp->res,
2117 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002118 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002119}
2120
Ed Tanous1656b292022-05-04 11:33:42 -07002121inline void
2122 handleBusSystemPost(const crow::Request& req,
2123 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2124 const std::string& processName,
2125 const std::string& requestedPath)
2126{
2127 std::vector<std::string> strs;
2128 boost::split(strs, requestedPath, boost::is_any_of("/"));
2129 std::string objectPath;
2130 std::string interfaceName;
2131 std::string methodName;
2132 auto it = strs.begin();
2133 if (it == strs.end())
2134 {
2135 objectPath = "/";
2136 }
2137 while (it != strs.end())
2138 {
2139 // Check if segment contains ".". If it does, it must be an
2140 // interface
2141 if (it->find(".") != std::string::npos)
2142 {
2143 break;
2144 // This check is necessary as the trailing slash gets
2145 // parsed as part of our <path> specifier above, which
2146 // causes the normal trailing backslash redirector to
2147 // fail.
2148 }
2149 if (!it->empty())
2150 {
2151 objectPath += "/" + *it;
2152 }
2153 it++;
2154 }
2155 if (it != strs.end())
2156 {
2157 interfaceName = *it;
2158 it++;
2159
2160 // after interface, we might have a method name
2161 if (it != strs.end())
2162 {
2163 methodName = *it;
2164 it++;
2165 }
2166 }
2167 if (it != strs.end())
2168 {
2169 // if there is more levels past the method name, something
2170 // went wrong, return not found
2171 asyncResp->res.result(boost::beast::http::status::not_found);
2172 return;
2173 }
2174 if (interfaceName.empty())
2175 {
2176 crow::connections::systemBus->async_method_call(
2177 [asyncResp, processName,
2178 objectPath](const boost::system::error_code ec,
2179 const std::string& introspectXml) {
2180 if (ec)
2181 {
2182 BMCWEB_LOG_ERROR
2183 << "Introspect call failed with error: " << ec.message()
2184 << " on process: " << processName
2185 << " path: " << objectPath << "\n";
2186 return;
2187 }
2188 tinyxml2::XMLDocument doc;
2189
2190 doc.Parse(introspectXml.c_str());
2191 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2192 if (pRoot == nullptr)
2193 {
2194 BMCWEB_LOG_ERROR << "XML document failed to parse "
2195 << processName << " " << objectPath
2196 << "\n";
Ed Tanous14766872022-03-15 10:44:42 -07002197 asyncResp->res.jsonValue["status"] = "XML parse error";
Ed Tanous1656b292022-05-04 11:33:42 -07002198 asyncResp->res.result(
2199 boost::beast::http::status::internal_server_error);
2200 return;
2201 }
2202
2203 BMCWEB_LOG_DEBUG << introspectXml;
Ed Tanous14766872022-03-15 10:44:42 -07002204 asyncResp->res.jsonValue["status"] = "ok";
2205 asyncResp->res.jsonValue["bus_name"] = processName;
2206 asyncResp->res.jsonValue["object_path"] = objectPath;
2207
Ed Tanous1656b292022-05-04 11:33:42 -07002208 nlohmann::json& interfacesArray =
2209 asyncResp->res.jsonValue["interfaces"];
2210 interfacesArray = nlohmann::json::array();
2211 tinyxml2::XMLElement* interface =
2212 pRoot->FirstChildElement("interface");
2213
2214 while (interface != nullptr)
2215 {
2216 const char* ifaceName = interface->Attribute("name");
2217 if (ifaceName != nullptr)
2218 {
Ed Tanous14766872022-03-15 10:44:42 -07002219 nlohmann::json::object_t interface;
2220 interface["name"] = ifaceName;
2221 interfacesArray.push_back(std::move(interface));
Ed Tanous1656b292022-05-04 11:33:42 -07002222 }
2223
2224 interface = interface->NextSiblingElement("interface");
2225 }
2226 },
2227 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2228 "Introspect");
2229 }
2230 else if (methodName.empty())
2231 {
2232 crow::connections::systemBus->async_method_call(
2233 [asyncResp, processName, objectPath,
2234 interfaceName](const boost::system::error_code ec,
2235 const std::string& introspectXml) {
2236 if (ec)
2237 {
2238 BMCWEB_LOG_ERROR
2239 << "Introspect call failed with error: " << ec.message()
2240 << " on process: " << processName
2241 << " path: " << objectPath << "\n";
2242 return;
2243 }
2244 tinyxml2::XMLDocument doc;
2245
2246 doc.Parse(introspectXml.data(), introspectXml.size());
2247 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2248 if (pRoot == nullptr)
2249 {
2250 BMCWEB_LOG_ERROR << "XML document failed to parse "
2251 << processName << " " << objectPath
2252 << "\n";
2253 asyncResp->res.result(
2254 boost::beast::http::status::internal_server_error);
2255 return;
2256 }
Ed Tanous14766872022-03-15 10:44:42 -07002257
2258 asyncResp->res.jsonValue["status"] = "ok";
2259 asyncResp->res.jsonValue["bus_name"] = processName;
2260 asyncResp->res.jsonValue["interface"] = interfaceName;
2261 asyncResp->res.jsonValue["object_path"] = objectPath;
Ed Tanous1656b292022-05-04 11:33:42 -07002262
2263 nlohmann::json& methodsArray =
2264 asyncResp->res.jsonValue["methods"];
2265 methodsArray = nlohmann::json::array();
2266
2267 nlohmann::json& signalsArray =
2268 asyncResp->res.jsonValue["signals"];
2269 signalsArray = nlohmann::json::array();
2270
2271 nlohmann::json& propertiesObj =
2272 asyncResp->res.jsonValue["properties"];
2273 propertiesObj = nlohmann::json::object();
2274
2275 // if we know we're the only call, build the
2276 // json directly
2277 tinyxml2::XMLElement* interface =
2278 pRoot->FirstChildElement("interface");
2279 while (interface != nullptr)
2280 {
2281 const char* ifaceName = interface->Attribute("name");
2282
2283 if (ifaceName != nullptr && ifaceName == interfaceName)
2284 {
2285 break;
2286 }
2287
2288 interface = interface->NextSiblingElement("interface");
2289 }
2290 if (interface == nullptr)
2291 {
2292 // if we got to the end of the list and
2293 // never found a match, throw 404
2294 asyncResp->res.result(
2295 boost::beast::http::status::not_found);
2296 return;
2297 }
2298
2299 tinyxml2::XMLElement* methods =
2300 interface->FirstChildElement("method");
2301 while (methods != nullptr)
2302 {
2303 nlohmann::json argsArray = nlohmann::json::array();
2304 tinyxml2::XMLElement* arg =
2305 methods->FirstChildElement("arg");
2306 while (arg != nullptr)
2307 {
2308 nlohmann::json thisArg;
2309 for (const char* fieldName : std::array<const char*, 3>{
2310 "name", "direction", "type"})
2311 {
2312 const char* fieldValue = arg->Attribute(fieldName);
2313 if (fieldValue != nullptr)
2314 {
2315 thisArg[fieldName] = fieldValue;
2316 }
2317 }
2318 argsArray.push_back(std::move(thisArg));
2319 arg = arg->NextSiblingElement("arg");
2320 }
2321
2322 const char* name = methods->Attribute("name");
2323 if (name != nullptr)
2324 {
2325 std::string uri;
2326 uri.reserve(14 + processName.size() +
2327 objectPath.size() + interfaceName.size() +
2328 strlen(name));
2329 uri += "/bus/system/";
2330 uri += processName;
2331 uri += objectPath;
2332 uri += "/";
2333 uri += interfaceName;
2334 uri += "/";
2335 uri += name;
Ed Tanous14766872022-03-15 10:44:42 -07002336
2337 nlohmann::json::object_t object;
2338 object["name"] = name;
2339 object["uri"] = std::move(uri);
2340 object["args"] = argsArray;
2341
2342 methodsArray.push_back(std::move(object));
Ed Tanous1656b292022-05-04 11:33:42 -07002343 }
2344 methods = methods->NextSiblingElement("method");
2345 }
2346 tinyxml2::XMLElement* signals =
2347 interface->FirstChildElement("signal");
2348 while (signals != nullptr)
2349 {
2350 nlohmann::json argsArray = nlohmann::json::array();
2351
2352 tinyxml2::XMLElement* arg =
2353 signals->FirstChildElement("arg");
2354 while (arg != nullptr)
2355 {
2356 const char* name = arg->Attribute("name");
2357 const char* type = arg->Attribute("type");
2358 if (name != nullptr && type != nullptr)
2359 {
2360 argsArray.push_back({
2361 {"name", name},
2362 {"type", type},
2363 });
2364 }
2365 arg = arg->NextSiblingElement("arg");
2366 }
2367 const char* name = signals->Attribute("name");
2368 if (name != nullptr)
2369 {
Ed Tanous14766872022-03-15 10:44:42 -07002370 nlohmann::json::object_t object;
2371 object["name"] = name;
2372 object["args"] = argsArray;
2373 signalsArray.push_back(std::move(object));
Ed Tanous1656b292022-05-04 11:33:42 -07002374 }
2375
2376 signals = signals->NextSiblingElement("signal");
2377 }
2378
2379 tinyxml2::XMLElement* property =
2380 interface->FirstChildElement("property");
2381 while (property != nullptr)
2382 {
2383 const char* name = property->Attribute("name");
2384 const char* type = property->Attribute("type");
2385 if (type != nullptr && name != nullptr)
2386 {
2387 sdbusplus::message::message m =
2388 crow::connections::systemBus->new_method_call(
2389 processName.c_str(), objectPath.c_str(),
2390 "org.freedesktop."
2391 "DBus."
2392 "Properties",
2393 "Get");
2394 m.append(interfaceName, name);
2395 nlohmann::json& propertyItem = propertiesObj[name];
2396 crow::connections::systemBus->async_send(
2397 m, [&propertyItem,
2398 asyncResp](boost::system::error_code& e,
2399 sdbusplus::message::message& msg) {
2400 if (e)
2401 {
2402 return;
2403 }
2404
2405 convertDBusToJSON("v", msg, propertyItem);
2406 });
2407 }
2408 property = property->NextSiblingElement("property");
2409 }
2410 },
2411 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2412 "Introspect");
2413 }
2414 else
2415 {
2416 if (req.method() != boost::beast::http::verb::post)
2417 {
2418 asyncResp->res.result(boost::beast::http::status::not_found);
2419 return;
2420 }
2421
2422 nlohmann::json requestDbusData =
2423 nlohmann::json::parse(req.body, nullptr, false);
2424
2425 if (requestDbusData.is_discarded())
2426 {
2427 asyncResp->res.result(boost::beast::http::status::bad_request);
2428 return;
2429 }
2430 if (!requestDbusData.is_array())
2431 {
2432 asyncResp->res.result(boost::beast::http::status::bad_request);
2433 return;
2434 }
2435 auto transaction =
2436 std::make_shared<InProgressActionData>(asyncResp->res);
2437
2438 transaction->path = objectPath;
2439 transaction->methodName = methodName;
2440 transaction->arguments = std::move(requestDbusData);
2441
2442 findActionOnInterface(transaction, processName);
2443 }
2444}
2445
Ed Tanous23a21a12020-07-25 04:45:05 +00002446inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002447{
2448 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002449 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002450 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002451 [](const crow::Request&,
2452 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous14766872022-03-15 10:44:42 -07002453 nlohmann::json::array_t buses;
2454 nlohmann::json& bus = buses.emplace_back();
2455 bus["name"] = "system";
2456 asyncResp->res.jsonValue["busses"] = std::move(buses);
2457 asyncResp->res.jsonValue["status"] = "ok";
Ed Tanous1abe55e2018-09-05 08:30:59 -07002458 });
2459
2460 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002461 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002462 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002463 [](const crow::Request&,
2464 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
P Dheeraj Srujan Kumar83fd8e12021-07-13 02:53:03 +05302465 auto myCallback = [asyncResp](
zhanghch058d1b46d2021-04-01 11:18:24 +08002466 const boost::system::error_code ec,
2467 std::vector<std::string>& names) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07002468 if (ec)
2469 {
2470 BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +08002471 asyncResp->res.result(
Ed Tanous1abe55e2018-09-05 08:30:59 -07002472 boost::beast::http::status::internal_server_error);
2473 }
2474 else
2475 {
2476 std::sort(names.begin(), names.end());
Ed Tanous14766872022-03-15 10:44:42 -07002477 asyncResp->res.jsonValue["status"] = "ok";
zhanghch058d1b46d2021-04-01 11:18:24 +08002478 auto& objectsSub = asyncResp->res.jsonValue["objects"];
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002479 for (auto& name : names)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002480 {
Ed Tanous14766872022-03-15 10:44:42 -07002481 nlohmann::json::object_t object;
2482 object["name"] = name;
2483 objectsSub.push_back(std::move(object));
Ed Tanous1abe55e2018-09-05 08:30:59 -07002484 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002485 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002486 };
2487 crow::connections::systemBus->async_method_call(
2488 std::move(myCallback), "org.freedesktop.DBus", "/",
2489 "org.freedesktop.DBus", "ListNames");
2490 });
2491
2492 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002493 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002494 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002495 [](const crow::Request&,
2496 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2497 handleList(asyncResp, "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07002498 });
2499
2500 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002501 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002502 .methods(boost::beast::http::verb::get)(
2503 [](const crow::Request& req,
2504 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002505 const std::string& path) {
Ed Tanous049a0512018-11-01 13:58:42 -07002506 std::string objectPath = "/xyz/" + path;
zhanghch058d1b46d2021-04-01 11:18:24 +08002507 handleDBusUrl(req, asyncResp, objectPath);
2508 });
2509
2510 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002511 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002512 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2513 boost::beast::http::verb::delete_)(
2514 [](const crow::Request& req,
2515 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2516 const std::string& path) {
2517 std::string objectPath = "/xyz/" + path;
2518 handleDBusUrl(req, asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002519 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002520
Ed Tanous049a0512018-11-01 13:58:42 -07002521 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002522 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002523 .methods(boost::beast::http::verb::get)(
2524 [](const crow::Request& req,
2525 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2526 const std::string& path) {
2527 std::string objectPath = "/org/" + path;
2528 handleDBusUrl(req, asyncResp, objectPath);
2529 });
Tanousf00032d2018-11-05 01:18:10 -03002530
2531 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002532 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002533 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2534 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002535 [](const crow::Request& req,
2536 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002537 const std::string& path) {
Ed Tanouse1281402019-04-03 07:07:10 -07002538 std::string objectPath = "/org/" + path;
zhanghch058d1b46d2021-04-01 11:18:24 +08002539 handleDBusUrl(req, asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002540 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002541
Ed Tanous1abe55e2018-09-05 08:30:59 -07002542 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002543 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002544 .methods(boost::beast::http::verb::get)(
2545 [](const crow::Request&,
2546 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2547 const std::string& dumpId) {
Josh Lehan482c45a2022-03-29 17:10:44 -07002548 if (!validateFilename(dumpId))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002549 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002550 asyncResp->res.result(
2551 boost::beast::http::status::bad_request);
Ramesh Iyyard9207042019-07-05 08:04:42 -05002552 return;
2553 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002554 std::filesystem::path loc(
2555 "/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002556
zhanghch058d1b46d2021-04-01 11:18:24 +08002557 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002558
zhanghch058d1b46d2021-04-01 11:18:24 +08002559 if (!std::filesystem::exists(loc) ||
2560 !std::filesystem::is_directory(loc))
2561 {
Ed Tanous8cc8ede2022-02-28 10:20:59 -08002562 BMCWEB_LOG_ERROR << loc.string() << "Not found";
zhanghch058d1b46d2021-04-01 11:18:24 +08002563 asyncResp->res.result(
2564 boost::beast::http::status::not_found);
2565 return;
2566 }
2567 std::filesystem::directory_iterator files(loc);
2568
Ed Tanous9eb808c2022-01-25 10:19:23 -08002569 for (const auto& file : files)
zhanghch058d1b46d2021-04-01 11:18:24 +08002570 {
2571 std::ifstream readFile(file.path());
2572 if (!readFile.good())
2573 {
2574 continue;
2575 }
2576
2577 asyncResp->res.addHeader("Content-Type",
2578 "application/octet-stream");
2579
2580 // Assuming only one dump file will be present in the dump
2581 // id directory
2582 std::string dumpFileName = file.path().filename().string();
2583
2584 // Filename should be in alphanumeric, dot and underscore
2585 // Its based on phosphor-debug-collector application
2586 // dumpfile format
2587 std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
2588 if (!std::regex_match(dumpFileName, dumpFileRegex))
2589 {
2590 BMCWEB_LOG_ERROR << "Invalid dump filename "
2591 << dumpFileName;
2592 asyncResp->res.result(
2593 boost::beast::http::status::not_found);
2594 return;
2595 }
2596 std::string contentDispositionParam =
2597 "attachment; filename=\"" + dumpFileName + "\"";
2598
2599 asyncResp->res.addHeader("Content-Disposition",
2600 contentDispositionParam);
2601
2602 asyncResp->res.body() = {
2603 std::istreambuf_iterator<char>(readFile),
2604 std::istreambuf_iterator<char>()};
2605 return;
2606 }
2607 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002608 return;
zhanghch058d1b46d2021-04-01 11:18:24 +08002609 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002610
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002611 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002612 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002613
2614 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002615 [](const crow::Request&,
2616 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002617 const std::string& connection) {
Nan Zhou72374eb2022-01-27 17:06:51 -08002618 introspectObjects(connection, "/", asyncResp);
Ed Tanousb41187f2019-10-24 16:30:02 -07002619 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002620
2621 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002622 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous1656b292022-05-04 11:33:42 -07002623 .methods(boost::beast::http::verb::get,
2624 boost::beast::http::verb::post)(handleBusSystemPost);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002625}
2626} // namespace openbmc_mapper
2627} // namespace crow