blob: 0e2af700f6e0c70a31db3ff449b4a661372ca68a [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 Tanous002d39b2022-05-31 08:59:27 -070089 if (ec)
90 {
91 BMCWEB_LOG_ERROR
92 << "Introspect call failed with error: " << ec.message()
93 << " on process: " << processName << " path: " << objectPath
94 << "\n";
95 return;
96 }
97 nlohmann::json::object_t object;
98 object["path"] = objectPath;
Ed Tanous14766872022-03-15 10:44:42 -070099
Ed Tanous002d39b2022-05-31 08:59:27 -0700100 transaction->res.jsonValue["objects"].push_back(std::move(object));
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700101
Ed Tanous002d39b2022-05-31 08:59:27 -0700102 tinyxml2::XMLDocument doc;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700103
Ed Tanous002d39b2022-05-31 08:59:27 -0700104 doc.Parse(introspectXml.c_str());
105 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
106 if (pRoot == nullptr)
107 {
108 BMCWEB_LOG_ERROR << "XML document failed to parse " << processName
109 << " " << objectPath << "\n";
110 }
111 else
112 {
113 tinyxml2::XMLElement* node = pRoot->FirstChildElement("node");
114 while (node != nullptr)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700115 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700116 const char* childPath = node->Attribute("name");
117 if (childPath != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700118 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700119 std::string newpath;
120 if (objectPath != "/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700121 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700122 newpath += objectPath;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700124 newpath += std::string("/") + childPath;
125 // introspect the subobjects as well
126 introspectObjects(processName, newpath, transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700127 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700128
129 node = node->NextSiblingElement("node");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700130 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700131 }
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) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700149 if (ec)
150 {
151 BMCWEB_LOG_ERROR << "GetAll on path " << objectPath << " iface "
152 << interface << " service " << service
153 << " failed with code " << ec;
154 return;
155 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600156
Ed Tanous002d39b2022-05-31 08:59:27 -0700157 nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
158 nlohmann::json& objectJson = dataJson[objectPath];
159 if (objectJson.is_null())
160 {
161 objectJson = nlohmann::json::object();
162 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600163
Ed Tanous002d39b2022-05-31 08:59:27 -0700164 for (const auto& [name, value] : propertiesList)
165 {
166 nlohmann::json& propertyJson = objectJson[name];
167 std::visit(
168 [&propertyJson](auto&& val) {
169 if constexpr (std::is_same_v<std::decay_t<decltype(val)>,
170 sdbusplus::message::unix_fd>)
171 {
172 propertyJson = val.fd;
173 }
174 else
175 {
Ed Tanousd1a64812021-12-13 12:14:05 -0800176
Ed Tanous002d39b2022-05-31 08:59:27 -0700177 propertyJson = val;
178 }
179 },
180 value);
181 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600182 },
183 service, objectPath, "org.freedesktop.DBus.Properties", "GetAll",
184 interface);
185}
186
187// Find any results that weren't picked up by ObjectManagers, to be
188// called after all ObjectManagers are searched for and called.
Ed Tanous23a21a12020-07-25 04:45:05 +0000189inline void findRemainingObjectsForEnumerate(
Ed Tanousb5a76932020-09-29 16:16:58 -0700190 const std::string& objectPath,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800191 const std::shared_ptr<dbus::utility::MapperGetSubTreeResponse>& subtree,
Ed Tanousb5a76932020-09-29 16:16:58 -0700192 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600193{
194 BMCWEB_LOG_DEBUG << "findRemainingObjectsForEnumerate";
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500195 const nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600196
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500197 for (const auto& [path, interface_map] : *subtree)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600198 {
199 if (path == objectPath)
200 {
201 // An enumerate does not return the target path's properties
202 continue;
203 }
204 if (dataJson.find(path) == dataJson.end())
205 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500206 for (const auto& [service, interfaces] : interface_map)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600207 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500208 for (const auto& interface : interfaces)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600209 {
210 if (!boost::starts_with(interface, "org.freedesktop.DBus"))
211 {
212 getPropertiesForEnumerate(path, service, interface,
213 asyncResp);
214 }
215 }
216 }
217 }
218 }
219}
220
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600221struct InProgressEnumerateData
222{
zhanghch058d1b46d2021-04-01 11:18:24 +0800223 InProgressEnumerateData(
224 const std::string& objectPathIn,
225 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
Ed Tanous23a21a12020-07-25 04:45:05 +0000226 objectPath(objectPathIn),
zhanghch058d1b46d2021-04-01 11:18:24 +0800227 asyncResp(asyncRespIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500228 {}
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600229
230 ~InProgressEnumerateData()
231 {
Ed Tanous24b2fe82022-01-06 12:45:54 -0800232 try
233 {
234 findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
235 }
236 catch (...)
237 {
238 BMCWEB_LOG_CRITICAL
239 << "findRemainingObjectsForEnumerate threw exception";
240 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600241 }
242
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800243 InProgressEnumerateData(const InProgressEnumerateData&) = delete;
244 InProgressEnumerateData(InProgressEnumerateData&&) = delete;
245 InProgressEnumerateData& operator=(const InProgressEnumerateData&) = delete;
246 InProgressEnumerateData& operator=(InProgressEnumerateData&&) = delete;
247
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600248 const std::string objectPath;
Ed Tanousb9d36b42022-02-26 21:42:46 -0800249 std::shared_ptr<dbus::utility::MapperGetSubTreeResponse> subtree;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600250 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
251};
252
Ed Tanous23a21a12020-07-25 04:45:05 +0000253inline void getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000254 const std::string& objectName, const std::string& objectManagerPath,
255 const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700256 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700257{
Ed Tanous81ce6092020-12-17 16:54:55 +0000258 BMCWEB_LOG_DEBUG << "getManagedObjectsForEnumerate " << objectName
259 << " object_manager_path " << objectManagerPath
260 << " connection_name " << connectionName;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700261 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000262 [transaction, objectName,
263 connectionName](const boost::system::error_code ec,
264 const dbus::utility::ManagedObjectType& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700265 if (ec)
266 {
267 BMCWEB_LOG_ERROR << "GetManagedObjects on path " << objectName
268 << " on connection " << connectionName
269 << " failed with code " << ec;
270 return;
271 }
Ed Tanous64530012018-02-06 17:08:16 -0800272
Ed Tanous002d39b2022-05-31 08:59:27 -0700273 nlohmann::json& dataJson =
274 transaction->asyncResp->res.jsonValue["data"];
Ed Tanous049a0512018-11-01 13:58:42 -0700275
Ed Tanous002d39b2022-05-31 08:59:27 -0700276 for (const auto& objectPath : objects)
277 {
278 if (boost::starts_with(objectPath.first.str, objectName))
Ed Tanous049a0512018-11-01 13:58:42 -0700279 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700280 BMCWEB_LOG_DEBUG << "Reading object " << objectPath.first.str;
281 nlohmann::json& objectJson = dataJson[objectPath.first.str];
282 if (objectJson.is_null())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700283 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700284 objectJson = nlohmann::json::object();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700285 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500286 for (const auto& interface : objectPath.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700287 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700288 for (const auto& property : interface.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700289 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700290 nlohmann::json& propertyJson =
291 objectJson[property.first];
292 std::visit(
293 [&propertyJson](auto&& val) {
294 if constexpr (std::is_same_v<
295 std::decay_t<decltype(val)>,
296 sdbusplus::message::unix_fd>)
297 {
298 propertyJson = val.fd;
299 }
300 else
301 {
302
303 propertyJson = val;
304 }
305 },
306 property.second);
Ed Tanous049a0512018-11-01 13:58:42 -0700307 }
308 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700309 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700310 for (const auto& interface : objectPath.second)
311 {
312 if (interface.first == "org.freedesktop.DBus.ObjectManager")
313 {
314 getManagedObjectsForEnumerate(objectPath.first.str,
315 objectPath.first.str,
316 connectionName, transaction);
317 }
318 }
319 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700320 },
Ed Tanous81ce6092020-12-17 16:54:55 +0000321 connectionName, objectManagerPath, "org.freedesktop.DBus.ObjectManager",
322 "GetManagedObjects");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700323}
324
Ed Tanous23a21a12020-07-25 04:45:05 +0000325inline void findObjectManagerPathForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000326 const std::string& objectName, const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700327 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700328{
Ed Tanous81ce6092020-12-17 16:54:55 +0000329 BMCWEB_LOG_DEBUG << "Finding objectmanager for path " << objectName
330 << " on connection:" << connectionName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700331 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000332 [transaction, objectName, connectionName](
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700333 const boost::system::error_code ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800334 const dbus::utility::MapperGetAncestorsResponse& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700335 if (ec)
336 {
337 BMCWEB_LOG_ERROR << "GetAncestors on path " << objectName
338 << " failed with code " << ec;
339 return;
340 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700341
Ed Tanous002d39b2022-05-31 08:59:27 -0700342 for (const auto& pathGroup : objects)
343 {
344 for (const auto& connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700345 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700346 if (connectionGroup.first == connectionName)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700347 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700348 // Found the object manager path for this resource.
349 getManagedObjectsForEnumerate(objectName, pathGroup.first,
350 connectionName, transaction);
351 return;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700352 }
353 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700354 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700355 },
356 "xyz.openbmc_project.ObjectMapper",
357 "/xyz/openbmc_project/object_mapper",
Ed Tanous81ce6092020-12-17 16:54:55 +0000358 "xyz.openbmc_project.ObjectMapper", "GetAncestors", objectName,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500359 std::array<const char*, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700360}
Ed Tanous64530012018-02-06 17:08:16 -0800361
Ed Tanous7c091622019-05-23 11:42:36 -0700362// Uses GetObject to add the object info about the target /enumerate path to
363// the results of GetSubTree, as GetSubTree will not return info for the
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600364// target path, and then continues on enumerating the rest of the tree.
Ed Tanousb5a76932020-09-29 16:16:58 -0700365inline void getObjectAndEnumerate(
366 const std::shared_ptr<InProgressEnumerateData>& transaction)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600367{
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600368 crow::connections::systemBus->async_method_call(
369 [transaction](const boost::system::error_code ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800370 const dbus::utility::MapperGetObject& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700371 if (ec)
372 {
373 BMCWEB_LOG_ERROR << "GetObject for path " << transaction->objectPath
374 << " failed with code " << ec;
375 return;
376 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600377
Ed Tanous002d39b2022-05-31 08:59:27 -0700378 BMCWEB_LOG_DEBUG << "GetObject for " << transaction->objectPath
379 << " has " << objects.size() << " entries";
380 if (!objects.empty())
381 {
382 transaction->subtree->emplace_back(transaction->objectPath,
383 objects);
384 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600385
Ed Tanous002d39b2022-05-31 08:59:27 -0700386 // Map indicating connection name, and the path where the object
387 // manager exists
388 boost::container::flat_map<std::string, std::string> connections;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600389
Ed Tanous002d39b2022-05-31 08:59:27 -0700390 for (const auto& object : *(transaction->subtree))
391 {
392 for (const auto& connection : object.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600393 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700394 std::string& objectManagerPath = connections[connection.first];
395 for (const auto& interface : connection.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600396 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700397 BMCWEB_LOG_DEBUG << connection.first << " has interface "
398 << interface;
399 if (interface == "org.freedesktop.DBus.ObjectManager")
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600400 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700401 BMCWEB_LOG_DEBUG << "found object manager path "
402 << object.first;
403 objectManagerPath = object.first;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600404 }
405 }
406 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700407 }
408 BMCWEB_LOG_DEBUG << "Got " << connections.size() << " connections";
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600409
Ed Tanous002d39b2022-05-31 08:59:27 -0700410 for (const auto& connection : connections)
411 {
412 // If we already know where the object manager is, we don't
413 // need to search for it, we can call directly in to
414 // getManagedObjects
415 if (!connection.second.empty())
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600416 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700417 getManagedObjectsForEnumerate(transaction->objectPath,
418 connection.second,
419 connection.first, transaction);
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600420 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700421 else
422 {
423 // otherwise we need to find the object manager path
424 // before we can continue
425 findObjectManagerPathForEnumerate(
426 transaction->objectPath, connection.first, transaction);
427 }
428 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600429 },
430 "xyz.openbmc_project.ObjectMapper",
431 "/xyz/openbmc_project/object_mapper",
432 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500433 transaction->objectPath, std::array<const char*, 0>());
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600434}
Ed Tanous64530012018-02-06 17:08:16 -0800435
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700436// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700437struct InProgressActionData
438{
Ed Tanous4e23a442022-06-06 09:57:26 -0700439 explicit InProgressActionData(crow::Response& resIn) : res(resIn)
Ed Tanous23a21a12020-07-25 04:45:05 +0000440 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700441 ~InProgressActionData()
442 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600443 // Methods could have been called across different owners
444 // and interfaces, where some calls failed and some passed.
445 //
446 // The rules for this are:
447 // * if no method was called - error
448 // * if a method failed and none passed - error
449 // (converse: if at least one method passed - OK)
450 // * for the method output:
451 // * if output processing didn't fail, return the data
452
453 // Only deal with method returns if nothing failed earlier
454 if (res.result() == boost::beast::http::status::ok)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700455 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600456 if (!methodPassed)
457 {
Matt Spinler06b1b632019-06-18 16:09:25 -0500458 if (!methodFailed)
Matt Spinler16caaee2019-01-15 11:40:34 -0600459 {
460 setErrorResponse(res, boost::beast::http::status::not_found,
461 methodNotFoundDesc, notFoundMsg);
462 }
463 }
464 else
465 {
466 if (outputFailed)
467 {
468 setErrorResponse(
469 res, boost::beast::http::status::internal_server_error,
470 "Method output failure", methodOutputFailedMsg);
471 }
472 else
473 {
Ed Tanous14766872022-03-15 10:44:42 -0700474 res.jsonValue["status"] = "ok";
475 res.jsonValue["message"] = "200 OK";
476 res.jsonValue["data"] = methodResponse;
Matt Spinler16caaee2019-01-15 11:40:34 -0600477 }
478 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700479 }
Matt Spinler16caaee2019-01-15 11:40:34 -0600480
Ed Tanous1abe55e2018-09-05 08:30:59 -0700481 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700482 }
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800483 InProgressActionData(const InProgressActionData&) = delete;
484 InProgressActionData(InProgressActionData&&) = delete;
485 InProgressActionData& operator=(const InProgressActionData&) = delete;
486 InProgressActionData& operator=(InProgressActionData&&) = delete;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700487
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500488 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700489 {
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600490 setErrorResponse(res, boost::beast::http::status::bad_request, desc,
491 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700492 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500493 crow::Response& res;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700494 std::string path;
495 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600496 std::string interfaceName;
Matt Spinler16caaee2019-01-15 11:40:34 -0600497 bool methodPassed = false;
498 bool methodFailed = false;
499 bool outputFailed = false;
Matt Spinler39a4e392019-01-15 11:53:13 -0600500 bool convertedToArray = false;
Matt Spinler16caaee2019-01-15 11:40:34 -0600501 nlohmann::json methodResponse;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700502 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700503};
504
Ed Tanous23a21a12020-07-25 04:45:05 +0000505inline std::vector<std::string> dbusArgSplit(const std::string& string)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700506{
507 std::vector<std::string> ret;
508 if (string.empty())
509 {
510 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700511 }
Ed Tanous0f0353b2019-10-24 11:37:51 -0700512 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700513 int containerDepth = 0;
514
515 for (std::string::const_iterator character = string.begin();
516 character != string.end(); character++)
517 {
518 ret.back() += *character;
519 switch (*character)
520 {
521 case ('a'):
522 break;
523 case ('('):
524 case ('{'):
525 containerDepth++;
526 break;
527 case ('}'):
528 case (')'):
529 containerDepth--;
530 if (containerDepth == 0)
531 {
532 if (character + 1 != string.end())
533 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700534 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700535 }
536 }
537 break;
538 default:
539 if (containerDepth == 0)
540 {
541 if (character + 1 != string.end())
542 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700543 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700544 }
545 }
546 break;
547 }
548 }
Matt Spinler4ae611d2019-01-11 15:37:06 -0600549
550 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700551}
552
Ed Tanous81ce6092020-12-17 16:54:55 +0000553inline int convertJsonToDbus(sd_bus_message* m, const std::string& argType,
554 const nlohmann::json& inputJson)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700555{
556 int r = 0;
Ed Tanous71f52d92021-02-19 08:51:17 -0800557 BMCWEB_LOG_DEBUG << "Converting "
558 << inputJson.dump(2, ' ', true,
559 nlohmann::json::error_handler_t::replace)
Ed Tanous81ce6092020-12-17 16:54:55 +0000560 << " to type: " << argType;
561 const std::vector<std::string> argTypes = dbusArgSplit(argType);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700562
Ed Tanous1abe55e2018-09-05 08:30:59 -0700563 // Assume a single object for now.
Ed Tanous81ce6092020-12-17 16:54:55 +0000564 const nlohmann::json* j = &inputJson;
565 nlohmann::json::const_iterator jIt = inputJson.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700566
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500567 for (const std::string& argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700568 {
569 // If we are decoding multiple objects, grab the pointer to the
570 // iterator, and increment it for the next loop
571 if (argTypes.size() > 1)
572 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000573 if (jIt == inputJson.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700574 {
575 return -2;
576 }
577 j = &*jIt;
578 jIt++;
579 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500580 const int64_t* intValue = j->get_ptr<const int64_t*>();
581 const std::string* stringValue = j->get_ptr<const std::string*>();
582 const double* doubleValue = j->get_ptr<const double*>();
583 const bool* b = j->get_ptr<const bool*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700584 int64_t v = 0;
585 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700586
Ed Tanous1abe55e2018-09-05 08:30:59 -0700587 // Do some basic type conversions that make sense. uint can be
588 // converted to int. int and uint can be converted to double
Ed Tanous66664f22019-10-11 13:05:49 -0700589 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700590 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500591 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700592 if (uintValue != nullptr)
593 {
594 v = static_cast<int64_t>(*uintValue);
595 intValue = &v;
596 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700597 }
Ed Tanous66664f22019-10-11 13:05:49 -0700598 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700599 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500600 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700601 if (uintValue != nullptr)
602 {
603 d = static_cast<double>(*uintValue);
604 doubleValue = &d;
605 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700606 }
Ed Tanous66664f22019-10-11 13:05:49 -0700607 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700608 {
Ed Tanous66664f22019-10-11 13:05:49 -0700609 if (intValue != nullptr)
610 {
611 d = static_cast<double>(*intValue);
612 doubleValue = &d;
613 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700614 }
615
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700616 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700617 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700618 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700619 {
620 return -1;
621 }
Ed Tanous271584a2019-07-09 16:24:22 -0700622 r = sd_bus_message_append_basic(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500623 m, argCode[0], static_cast<const void*>(stringValue->data()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700624 if (r < 0)
625 {
626 return r;
627 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700628 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700629 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700630 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700631 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700632 {
633 return -1;
634 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500635 if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
636 (*intValue > std::numeric_limits<int32_t>::max()))
637 {
638 return -ERANGE;
639 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700640 int32_t i = static_cast<int32_t>(*intValue);
641 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700642 if (r < 0)
643 {
644 return r;
645 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700646 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700647 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700648 {
649 // lots of ways bool could be represented here. Try them all
Ed Tanouse662eae2022-01-25 10:39:19 -0800650 int boolInt = 0;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700651 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700652 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500653 if (*intValue == 1)
654 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800655 boolInt = 1;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500656 }
657 else if (*intValue == 0)
658 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800659 boolInt = 0;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500660 }
661 else
662 {
663 return -ERANGE;
664 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700665 }
666 else if (b != nullptr)
667 {
Matt Spinlera2f02632019-01-18 10:15:35 -0600668 boolInt = *b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700669 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700670 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700671 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700672 boolInt = boost::istarts_with(*stringValue, "t") ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700673 }
674 else
675 {
676 return -1;
677 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700678 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700679 if (r < 0)
680 {
681 return r;
682 }
683 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700684 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700685 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700686 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700687 {
688 return -1;
689 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500690 if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
691 (*intValue > std::numeric_limits<int16_t>::max()))
692 {
693 return -ERANGE;
694 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700695 int16_t n = static_cast<int16_t>(*intValue);
696 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700697 if (r < 0)
698 {
699 return r;
700 }
701 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700702 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700703 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700704 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700705 {
706 return -1;
707 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700708 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700709 if (r < 0)
710 {
711 return r;
712 }
713 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700714 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700715 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500716 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700717 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700718 {
719 return -1;
720 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000721 if (*uintValue > std::numeric_limits<uint8_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500722 {
723 return -ERANGE;
724 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700725 uint8_t y = static_cast<uint8_t>(*uintValue);
726 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700727 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700728 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700729 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500730 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700731 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700732 {
733 return -1;
734 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000735 if (*uintValue > std::numeric_limits<uint16_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500736 {
737 return -ERANGE;
738 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700739 uint16_t q = static_cast<uint16_t>(*uintValue);
740 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700741 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700742 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700743 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500744 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700745 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700746 {
747 return -1;
748 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000749 if (*uintValue > std::numeric_limits<uint32_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500750 {
751 return -ERANGE;
752 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700753 uint32_t u = static_cast<uint32_t>(*uintValue);
754 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700755 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700756 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700757 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500758 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700759 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700760 {
761 return -1;
762 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700763 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700764 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700765 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700766 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500767 if (doubleValue == nullptr)
768 {
769 return -1;
770 }
771 if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
772 (*doubleValue > std::numeric_limits<double>::max()))
773 {
774 return -ERANGE;
775 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700776 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700777 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700778 else if (boost::starts_with(argCode, "a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700779 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700780 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700781 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700782 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700783 if (r < 0)
784 {
785 return r;
786 }
787
Ed Tanous0dfeda62019-10-24 11:21:38 -0700788 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700789 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700790 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700791 if (r < 0)
792 {
793 return r;
794 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700795 }
796 sd_bus_message_close_container(m);
797 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700798 else if (boost::starts_with(argCode, "v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700799 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700800 std::string containedType = argCode.substr(1);
801 BMCWEB_LOG_DEBUG << "variant type: " << argCode
802 << " appending variant of type: " << containedType;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700803 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700804 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700805 if (r < 0)
806 {
807 return r;
808 }
809
Ed Tanous81ce6092020-12-17 16:54:55 +0000810 r = convertJsonToDbus(m, containedType, inputJson);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700811 if (r < 0)
812 {
813 return r;
814 }
815
816 r = sd_bus_message_close_container(m);
817 if (r < 0)
818 {
819 return r;
820 }
821 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700822 else if (boost::starts_with(argCode, "(") &&
823 boost::ends_with(argCode, ")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700824 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700825 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700826 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700827 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800828 if (r < 0)
829 {
830 return r;
831 }
832
Ed Tanous1abe55e2018-09-05 08:30:59 -0700833 nlohmann::json::const_iterator it = j->begin();
Ed Tanous81ce6092020-12-17 16:54:55 +0000834 for (const std::string& argCode2 : dbusArgSplit(argType))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700835 {
836 if (it == j->end())
837 {
838 return -1;
839 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000840 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700841 if (r < 0)
842 {
843 return r;
844 }
845 it++;
846 }
847 r = sd_bus_message_close_container(m);
848 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700849 else if (boost::starts_with(argCode, "{") &&
850 boost::ends_with(argCode, "}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700851 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700852 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700853 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700854 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800855 if (r < 0)
856 {
857 return r;
858 }
859
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700860 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700861 if (codes.size() != 2)
862 {
863 return -1;
864 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700865 const std::string& keyType = codes[0];
866 const std::string& valueType = codes[1];
Ed Tanous3174e4d2020-10-07 11:41:22 -0700867 for (const auto& it : j->items())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700868 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700869 r = convertJsonToDbus(m, keyType, it.key());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700870 if (r < 0)
871 {
872 return r;
873 }
874
Ed Tanous2c70f802020-09-28 14:29:23 -0700875 r = convertJsonToDbus(m, valueType, it.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700876 if (r < 0)
877 {
878 return r;
879 }
880 }
881 r = sd_bus_message_close_container(m);
882 }
883 else
884 {
885 return -2;
886 }
887 if (r < 0)
888 {
889 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700890 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700891
Ed Tanous1abe55e2018-09-05 08:30:59 -0700892 if (argTypes.size() > 1)
893 {
894 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700895 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700896 }
Matt Spinler127ea542019-01-14 11:04:28 -0600897
898 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700899}
900
Matt Spinlerd22a7132019-01-14 12:14:30 -0600901template <typename T>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500902int readMessageItem(const std::string& typeCode, sdbusplus::message::message& m,
903 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600904{
905 T value;
906
907 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
908 if (r < 0)
909 {
910 BMCWEB_LOG_ERROR << "sd_bus_message_read_basic on type " << typeCode
911 << " failed!";
912 return r;
913 }
914
915 data = value;
916 return 0;
917}
918
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500919int convertDBusToJSON(const std::string& returnType,
920 sdbusplus::message::message& m, nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600921
Ed Tanous23a21a12020-07-25 04:45:05 +0000922inline int readDictEntryFromMessage(const std::string& typeCode,
923 sdbusplus::message::message& m,
924 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600925{
926 std::vector<std::string> types = dbusArgSplit(typeCode);
927 if (types.size() != 2)
928 {
929 BMCWEB_LOG_ERROR << "wrong number contained types in dictionary: "
930 << types.size();
931 return -1;
932 }
933
934 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
935 typeCode.c_str());
936 if (r < 0)
937 {
938 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container with rc " << r;
939 return r;
940 }
941
942 nlohmann::json key;
943 r = convertDBusToJSON(types[0], m, key);
944 if (r < 0)
945 {
946 return r;
947 }
948
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500949 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -0600950 if (keyPtr == nullptr)
951 {
952 // json doesn't support non-string keys. If we hit this condition,
953 // convert the result to a string so we can proceed
Ed Tanous71f52d92021-02-19 08:51:17 -0800954 key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500955 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -0700956 // in theory this can't fail now, but lets be paranoid about it
957 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -0600958 if (keyPtr == nullptr)
959 {
960 return -1;
961 }
962 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500963 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -0600964
965 r = convertDBusToJSON(types[1], m, value);
966 if (r < 0)
967 {
968 return r;
969 }
970
971 r = sd_bus_message_exit_container(m.get());
972 if (r < 0)
973 {
974 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
975 return r;
976 }
977
978 return 0;
979}
980
Ed Tanous23a21a12020-07-25 04:45:05 +0000981inline int readArrayFromMessage(const std::string& typeCode,
982 sdbusplus::message::message& m,
983 nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -0600984{
985 if (typeCode.size() < 2)
986 {
987 BMCWEB_LOG_ERROR << "Type code " << typeCode
988 << " too small for an array";
989 return -1;
990 }
991
992 std::string containedType = typeCode.substr(1);
993
994 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
995 containedType.c_str());
996 if (r < 0)
997 {
998 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
999 << r;
1000 return r;
1001 }
1002
1003 bool dict = boost::starts_with(containedType, "{") &&
1004 boost::ends_with(containedType, "}");
1005
1006 if (dict)
1007 {
1008 // Remove the { }
1009 containedType = containedType.substr(1, containedType.size() - 2);
1010 data = nlohmann::json::object();
1011 }
1012 else
1013 {
1014 data = nlohmann::json::array();
1015 }
1016
1017 while (true)
1018 {
Ed Tanouse662eae2022-01-25 10:39:19 -08001019 r = sd_bus_message_at_end(m.get(), 0);
Matt Spinler6df8f992019-01-14 12:47:47 -06001020 if (r < 0)
1021 {
1022 BMCWEB_LOG_ERROR << "sd_bus_message_at_end failed";
1023 return r;
1024 }
1025
1026 if (r > 0)
1027 {
1028 break;
1029 }
1030
1031 // Dictionaries are only ever seen in an array
1032 if (dict)
1033 {
1034 r = readDictEntryFromMessage(containedType, m, data);
1035 if (r < 0)
1036 {
1037 return r;
1038 }
1039 }
1040 else
1041 {
1042 data.push_back(nlohmann::json());
1043
1044 r = convertDBusToJSON(containedType, m, data.back());
1045 if (r < 0)
1046 {
1047 return r;
1048 }
1049 }
1050 }
1051
1052 r = sd_bus_message_exit_container(m.get());
1053 if (r < 0)
1054 {
1055 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1056 return r;
1057 }
1058
1059 return 0;
1060}
1061
Ed Tanous23a21a12020-07-25 04:45:05 +00001062inline int readStructFromMessage(const std::string& typeCode,
1063 sdbusplus::message::message& m,
1064 nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001065{
1066 if (typeCode.size() < 3)
1067 {
1068 BMCWEB_LOG_ERROR << "Type code " << typeCode
1069 << " too small for a struct";
1070 return -1;
1071 }
1072
1073 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1074 std::vector<std::string> types = dbusArgSplit(containedTypes);
1075
1076 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1077 containedTypes.c_str());
1078 if (r < 0)
1079 {
1080 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1081 << r;
1082 return r;
1083 }
1084
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001085 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001086 {
1087 data.push_back(nlohmann::json());
1088 r = convertDBusToJSON(type, m, data.back());
1089 if (r < 0)
1090 {
1091 return r;
1092 }
1093 }
1094
1095 r = sd_bus_message_exit_container(m.get());
1096 if (r < 0)
1097 {
1098 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1099 return r;
1100 }
1101 return 0;
1102}
1103
Ed Tanous23a21a12020-07-25 04:45:05 +00001104inline int readVariantFromMessage(sdbusplus::message::message& m,
1105 nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001106{
Ed Tanous543f4402022-01-06 13:12:53 -08001107 const char* containerType = nullptr;
Ed Tanous99131cd2019-10-24 11:12:47 -07001108 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001109 if (r < 0)
1110 {
1111 BMCWEB_LOG_ERROR << "sd_bus_message_peek_type failed";
1112 return r;
1113 }
1114
1115 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1116 containerType);
1117 if (r < 0)
1118 {
1119 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1120 << r;
1121 return r;
1122 }
1123
1124 r = convertDBusToJSON(containerType, m, data);
1125 if (r < 0)
1126 {
1127 return r;
1128 }
1129
1130 r = sd_bus_message_exit_container(m.get());
1131 if (r < 0)
1132 {
1133 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed";
1134 return r;
1135 }
1136
1137 return 0;
1138}
1139
Ed Tanous23a21a12020-07-25 04:45:05 +00001140inline int convertDBusToJSON(const std::string& returnType,
1141 sdbusplus::message::message& m,
1142 nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001143{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001144 int r = 0;
1145 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1146
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001147 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001148 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001149 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001150 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001151 {
1152 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001153 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001154 }
1155
Ed Tanousd4d25792020-09-29 15:15:03 -07001156 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001157 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001158 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001159 if (r < 0)
1160 {
1161 return r;
1162 }
1163 }
1164 else if (typeCode == "b")
1165 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001166 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001167 if (r < 0)
1168 {
1169 return r;
1170 }
1171
Matt Spinlerf39420c2019-01-30 12:57:18 -06001172 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001173 }
1174 else if (typeCode == "u")
1175 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001176 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001177 if (r < 0)
1178 {
1179 return r;
1180 }
1181 }
1182 else if (typeCode == "i")
1183 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001184 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001185 if (r < 0)
1186 {
1187 return r;
1188 }
1189 }
1190 else if (typeCode == "x")
1191 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001192 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001193 if (r < 0)
1194 {
1195 return r;
1196 }
1197 }
1198 else if (typeCode == "t")
1199 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001200 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001201 if (r < 0)
1202 {
1203 return r;
1204 }
1205 }
1206 else if (typeCode == "n")
1207 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001208 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001209 if (r < 0)
1210 {
1211 return r;
1212 }
1213 }
1214 else if (typeCode == "q")
1215 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001216 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001217 if (r < 0)
1218 {
1219 return r;
1220 }
1221 }
1222 else if (typeCode == "y")
1223 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001224 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001225 if (r < 0)
1226 {
1227 return r;
1228 }
1229 }
1230 else if (typeCode == "d")
1231 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001232 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001233 if (r < 0)
1234 {
1235 return r;
1236 }
1237 }
1238 else if (typeCode == "h")
1239 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001240 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001241 if (r < 0)
1242 {
1243 return r;
1244 }
1245 }
Matt Spinler6df8f992019-01-14 12:47:47 -06001246 else if (boost::starts_with(typeCode, "a"))
1247 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001248 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001249 if (r < 0)
1250 {
1251 return r;
1252 }
1253 }
Matt Spinler75c6c672019-01-14 13:01:46 -06001254 else if (boost::starts_with(typeCode, "(") &&
1255 boost::ends_with(typeCode, ")"))
1256 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001257 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001258 if (r < 0)
1259 {
1260 return r;
1261 }
1262 }
Matt Spinler89c19702019-01-14 13:13:00 -06001263 else if (boost::starts_with(typeCode, "v"))
1264 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001265 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001266 if (r < 0)
1267 {
1268 return r;
1269 }
1270 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001271 else
1272 {
Matt Spinlerd22a7132019-01-14 12:14:30 -06001273 BMCWEB_LOG_ERROR << "Invalid D-Bus signature type " << typeCode;
1274 return -2;
1275 }
1276 }
1277
Matt Spinler16caaee2019-01-15 11:40:34 -06001278 return 0;
1279}
1280
Ed Tanousb5a76932020-09-29 16:16:58 -07001281inline void handleMethodResponse(
1282 const std::shared_ptr<InProgressActionData>& transaction,
1283 sdbusplus::message::message& m, const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001284{
Matt Spinler39a4e392019-01-15 11:53:13 -06001285 nlohmann::json data;
1286
1287 int r = convertDBusToJSON(returnType, m, data);
1288 if (r < 0)
1289 {
1290 transaction->outputFailed = true;
1291 return;
1292 }
1293
1294 if (data.is_null())
1295 {
1296 return;
1297 }
1298
1299 if (transaction->methodResponse.is_null())
1300 {
1301 transaction->methodResponse = std::move(data);
1302 return;
1303 }
1304
1305 // If they're both dictionaries or arrays, merge into one.
1306 // Otherwise, make the results an array with every result
1307 // an entry. Could also just fail in that case, but it
1308 // seems better to get the data back somehow.
1309
1310 if (transaction->methodResponse.is_object() && data.is_object())
1311 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001312 for (const auto& obj : data.items())
Matt Spinler39a4e392019-01-15 11:53:13 -06001313 {
1314 // Note: Will overwrite the data for a duplicate key
1315 transaction->methodResponse.emplace(obj.key(),
1316 std::move(obj.value()));
1317 }
1318 return;
1319 }
1320
1321 if (transaction->methodResponse.is_array() && data.is_array())
1322 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001323 for (auto& obj : data)
Matt Spinler39a4e392019-01-15 11:53:13 -06001324 {
1325 transaction->methodResponse.push_back(std::move(obj));
1326 }
1327 return;
1328 }
1329
1330 if (!transaction->convertedToArray)
1331 {
1332 // They are different types. May as well turn them into an array
1333 nlohmann::json j = std::move(transaction->methodResponse);
1334 transaction->methodResponse = nlohmann::json::array();
1335 transaction->methodResponse.push_back(std::move(j));
1336 transaction->methodResponse.push_back(std::move(data));
1337 transaction->convertedToArray = true;
1338 }
1339 else
1340 {
1341 transaction->methodResponse.push_back(std::move(data));
1342 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001343}
1344
Ed Tanousb5a76932020-09-29 16:16:58 -07001345inline void findActionOnInterface(
1346 const std::shared_ptr<InProgressActionData>& transaction,
1347 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001348{
1349 BMCWEB_LOG_DEBUG << "findActionOnInterface for connection "
1350 << connectionName;
1351 crow::connections::systemBus->async_method_call(
1352 [transaction, connectionName{std::string(connectionName)}](
1353 const boost::system::error_code ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001354 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001355 BMCWEB_LOG_DEBUG << "got xml:\n " << introspectXml;
1356 if (ec)
1357 {
1358 BMCWEB_LOG_ERROR
1359 << "Introspect call failed with error: " << ec.message()
1360 << " on process: " << connectionName << "\n";
1361 return;
1362 }
1363 tinyxml2::XMLDocument doc;
Matt Spinler318bd892019-01-15 09:59:20 -06001364
Ed Tanous002d39b2022-05-31 08:59:27 -07001365 doc.Parse(introspectXml.data(), introspectXml.size());
1366 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1367 if (pRoot == nullptr)
1368 {
1369 BMCWEB_LOG_ERROR << "XML document failed to parse "
1370 << connectionName << "\n";
1371 return;
1372 }
1373 tinyxml2::XMLElement* interfaceNode =
1374 pRoot->FirstChildElement("interface");
1375 while (interfaceNode != nullptr)
1376 {
1377 const char* thisInterfaceName = interfaceNode->Attribute("name");
1378 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001379 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001380 if (!transaction->interfaceName.empty() &&
1381 (transaction->interfaceName != thisInterfaceName))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001382 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001383 interfaceNode =
1384 interfaceNode->NextSiblingElement("interface");
1385 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001386 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001387
1388 tinyxml2::XMLElement* methodNode =
1389 interfaceNode->FirstChildElement("method");
1390 while (methodNode != nullptr)
1391 {
1392 const char* thisMethodName = methodNode->Attribute("name");
1393 BMCWEB_LOG_DEBUG << "Found method: " << thisMethodName;
1394 if (thisMethodName != nullptr &&
1395 thisMethodName == transaction->methodName)
1396 {
1397 BMCWEB_LOG_DEBUG << "Found method named "
1398 << thisMethodName << " on interface "
1399 << thisInterfaceName;
1400 sdbusplus::message::message m =
1401 crow::connections::systemBus->new_method_call(
1402 connectionName.c_str(),
1403 transaction->path.c_str(), thisInterfaceName,
1404 transaction->methodName.c_str());
1405
1406 tinyxml2::XMLElement* argumentNode =
1407 methodNode->FirstChildElement("arg");
1408
1409 std::string returnType;
1410
1411 // Find the output type
1412 while (argumentNode != nullptr)
1413 {
1414 const char* argDirection =
1415 argumentNode->Attribute("direction");
1416 const char* argType =
1417 argumentNode->Attribute("type");
1418 if (argDirection != nullptr && argType != nullptr &&
1419 std::string(argDirection) == "out")
1420 {
1421 returnType = argType;
1422 break;
1423 }
1424 argumentNode =
1425 argumentNode->NextSiblingElement("arg");
1426 }
1427
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001428 auto argIt = transaction->arguments.begin();
Ed Tanous002d39b2022-05-31 08:59:27 -07001429
1430 argumentNode = methodNode->FirstChildElement("arg");
1431
1432 while (argumentNode != nullptr)
1433 {
1434 const char* argDirection =
1435 argumentNode->Attribute("direction");
1436 const char* argType =
1437 argumentNode->Attribute("type");
1438 if (argDirection != nullptr && argType != nullptr &&
1439 std::string(argDirection) == "in")
1440 {
1441 if (argIt == transaction->arguments.end())
1442 {
1443 transaction->setErrorStatus(
1444 "Invalid method args");
1445 return;
1446 }
1447 if (convertJsonToDbus(m.get(),
1448 std::string(argType),
1449 *argIt) < 0)
1450 {
1451 transaction->setErrorStatus(
1452 "Invalid method arg type");
1453 return;
1454 }
1455
1456 argIt++;
1457 }
1458 argumentNode =
1459 argumentNode->NextSiblingElement("arg");
1460 }
1461
1462 crow::connections::systemBus->async_send(
1463 m,
1464 [transaction,
1465 returnType](boost::system::error_code ec2,
1466 sdbusplus::message::message& m2) {
1467 if (ec2)
1468 {
1469 transaction->methodFailed = true;
1470 const sd_bus_error* e = m2.get_error();
1471
1472 if (e != nullptr)
1473 {
1474 setErrorResponse(
1475 transaction->res,
1476 boost::beast::http::status::bad_request,
1477 e->name, e->message);
1478 }
1479 else
1480 {
1481 setErrorResponse(
1482 transaction->res,
1483 boost::beast::http::status::bad_request,
1484 "Method call failed", methodFailedMsg);
1485 }
1486 return;
1487 }
1488 transaction->methodPassed = true;
1489
1490 handleMethodResponse(transaction, m2, returnType);
1491 });
1492 break;
1493 }
1494 methodNode = methodNode->NextSiblingElement("method");
1495 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001496 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001497 interfaceNode = interfaceNode->NextSiblingElement("interface");
1498 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001499 },
1500 connectionName, transaction->path,
1501 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001502}
1503
zhanghch058d1b46d2021-04-01 11:18:24 +08001504inline void handleAction(const crow::Request& req,
1505 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001506 const std::string& objectPath,
1507 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001508{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001509 BMCWEB_LOG_DEBUG << "handleAction on path: " << objectPath << " and method "
1510 << methodName;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001511 nlohmann::json requestDbusData =
1512 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001513
Ed Tanous1abe55e2018-09-05 08:30:59 -07001514 if (requestDbusData.is_discarded())
1515 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001516 setErrorResponse(asyncResp->res,
1517 boost::beast::http::status::bad_request, noJsonDesc,
1518 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001519 return;
1520 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001521 nlohmann::json::iterator data = requestDbusData.find("data");
1522 if (data == requestDbusData.end())
1523 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001524 setErrorResponse(asyncResp->res,
1525 boost::beast::http::status::bad_request, noJsonDesc,
1526 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001527 return;
1528 }
1529
1530 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001531 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001532 setErrorResponse(asyncResp->res,
1533 boost::beast::http::status::bad_request, noJsonDesc,
1534 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001535 return;
1536 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001537 auto transaction = std::make_shared<InProgressActionData>(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001538
1539 transaction->path = objectPath;
1540 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001541 transaction->arguments = std::move(*data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001542 crow::connections::systemBus->async_method_call(
1543 [transaction](
1544 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001545 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1546 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001547 if (ec || interfaceNames.empty())
1548 {
1549 BMCWEB_LOG_ERROR << "Can't find object";
1550 setErrorResponse(transaction->res,
1551 boost::beast::http::status::not_found,
1552 notFoundDesc, notFoundMsg);
1553 return;
1554 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001555
Ed Tanous002d39b2022-05-31 08:59:27 -07001556 BMCWEB_LOG_DEBUG << "GetObject returned " << interfaceNames.size()
1557 << " object(s)";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001558
Ed Tanous002d39b2022-05-31 08:59:27 -07001559 for (const std::pair<std::string, std::vector<std::string>>& object :
1560 interfaceNames)
1561 {
1562 findActionOnInterface(transaction, object.first);
1563 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001564 },
1565 "xyz.openbmc_project.ObjectMapper",
1566 "/xyz/openbmc_project/object_mapper",
1567 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
1568 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001569}
1570
zhanghch058d1b46d2021-04-01 11:18:24 +08001571inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1572 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001573{
1574 BMCWEB_LOG_DEBUG << "handleDelete on path: " << objectPath;
1575
1576 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +08001577 [asyncResp, objectPath](
Matt Spinlerde818812018-12-11 16:39:20 -06001578 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001579 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1580 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001581 if (ec || interfaceNames.empty())
1582 {
1583 BMCWEB_LOG_ERROR << "Can't find object";
1584 setErrorResponse(asyncResp->res,
1585 boost::beast::http::status::method_not_allowed,
1586 methodNotAllowedDesc, methodNotAllowedMsg);
1587 return;
1588 }
Matt Spinlerde818812018-12-11 16:39:20 -06001589
Ed Tanous002d39b2022-05-31 08:59:27 -07001590 auto transaction =
1591 std::make_shared<InProgressActionData>(asyncResp->res);
1592 transaction->path = objectPath;
1593 transaction->methodName = "Delete";
1594 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
Matt Spinlerde818812018-12-11 16:39:20 -06001595
Ed Tanous002d39b2022-05-31 08:59:27 -07001596 for (const std::pair<std::string, std::vector<std::string>>& object :
1597 interfaceNames)
1598 {
1599 findActionOnInterface(transaction, object.first);
1600 }
Matt Spinlerde818812018-12-11 16:39:20 -06001601 },
1602 "xyz.openbmc_project.ObjectMapper",
1603 "/xyz/openbmc_project/object_mapper",
1604 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001605 std::array<const char*, 0>());
Matt Spinlerde818812018-12-11 16:39:20 -06001606}
1607
zhanghch058d1b46d2021-04-01 11:18:24 +08001608inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1609 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001610{
1611 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001612 [asyncResp](
1613 const boost::system::error_code ec,
1614 const dbus::utility::MapperGetSubTreePathsResponse& objectPaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001615 if (ec)
1616 {
1617 setErrorResponse(asyncResp->res,
1618 boost::beast::http::status::not_found,
1619 notFoundDesc, notFoundMsg);
1620 }
1621 else
1622 {
1623 asyncResp->res.jsonValue["status"] = "ok";
1624 asyncResp->res.jsonValue["message"] = "200 OK";
1625 asyncResp->res.jsonValue["data"] = objectPaths;
1626 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001627 },
1628 "xyz.openbmc_project.ObjectMapper",
1629 "/xyz/openbmc_project/object_mapper",
1630 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", objectPath,
Ed Tanousf839dfe2018-11-12 11:11:15 -08001631 depth, std::array<std::string, 0>());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001632}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001633
zhanghch058d1b46d2021-04-01 11:18:24 +08001634inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1635 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001636{
Ed Tanous049a0512018-11-01 13:58:42 -07001637 BMCWEB_LOG_DEBUG << "Doing enumerate on " << objectPath;
Ed Tanous049a0512018-11-01 13:58:42 -07001638
Ed Tanous14766872022-03-15 10:44:42 -07001639 asyncResp->res.jsonValue["message"] = "200 OK";
1640 asyncResp->res.jsonValue["status"] = "ok";
1641 asyncResp->res.jsonValue["data"] = nlohmann::json::object();
Ed Tanous049a0512018-11-01 13:58:42 -07001642
Ed Tanous1abe55e2018-09-05 08:30:59 -07001643 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001644 [objectPath, asyncResp](
1645 const boost::system::error_code ec,
1646 const dbus::utility::MapperGetSubTreeResponse& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001647 auto transaction =
1648 std::make_shared<InProgressEnumerateData>(objectPath, asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001649
Ed Tanous002d39b2022-05-31 08:59:27 -07001650 transaction->subtree =
1651 std::make_shared<dbus::utility::MapperGetSubTreeResponse>(
1652 objectNames);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001653
Ed Tanous002d39b2022-05-31 08:59:27 -07001654 if (ec)
1655 {
1656 BMCWEB_LOG_ERROR << "GetSubTree failed on "
1657 << transaction->objectPath;
1658 setErrorResponse(transaction->asyncResp->res,
1659 boost::beast::http::status::not_found,
1660 notFoundDesc, notFoundMsg);
1661 return;
1662 }
Ed Tanous64530012018-02-06 17:08:16 -08001663
Ed Tanous002d39b2022-05-31 08:59:27 -07001664 // Add the data for the path passed in to the results
1665 // as if GetSubTree returned it, and continue on enumerating
1666 getObjectAndEnumerate(transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001667 },
1668 "xyz.openbmc_project.ObjectMapper",
1669 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -07001670 "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath, 0,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001671 std::array<const char*, 0>());
Ed Tanous64530012018-02-06 17:08:16 -08001672}
Ed Tanous911ac312017-08-15 09:37:42 -07001673
zhanghch058d1b46d2021-04-01 11:18:24 +08001674inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1675 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001676{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001677 BMCWEB_LOG_DEBUG << "handleGet: " << objectPath << " prop:" << destProperty;
1678 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001679 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001680
Ed Tanous1abe55e2018-09-05 08:30:59 -07001681 std::shared_ptr<std::string> path =
1682 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001683
Ed Tanous1abe55e2018-09-05 08:30:59 -07001684 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001685 [asyncResp, path,
1686 propertyName](const boost::system::error_code ec,
1687 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001688 if (ec || objectNames.empty())
1689 {
1690 setErrorResponse(asyncResp->res,
1691 boost::beast::http::status::not_found,
1692 notFoundDesc, notFoundMsg);
1693 return;
1694 }
1695 std::shared_ptr<nlohmann::json> response =
1696 std::make_shared<nlohmann::json>(nlohmann::json::object());
1697 // The mapper should never give us an empty interface names
1698 // list, but check anyway
1699 for (const std::pair<std::string, std::vector<std::string>>&
1700 connection : objectNames)
1701 {
1702 const std::vector<std::string>& interfaceNames = connection.second;
1703
1704 if (interfaceNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001705 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001706 setErrorResponse(asyncResp->res,
1707 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001708 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001709 return;
1710 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001711
1712 for (const std::string& interface : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001713 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001714 sdbusplus::message::message m =
1715 crow::connections::systemBus->new_method_call(
1716 connection.first.c_str(), path->c_str(),
1717 "org.freedesktop.DBus.Properties", "GetAll");
1718 m.append(interface);
1719 crow::connections::systemBus->async_send(
1720 m, [asyncResp, response,
1721 propertyName](const boost::system::error_code ec2,
1722 sdbusplus::message::message& msg) {
1723 if (ec2)
1724 {
1725 BMCWEB_LOG_ERROR << "Bad dbus request error: "
1726 << ec2;
1727 }
1728 else
1729 {
1730 nlohmann::json properties;
1731 int r = convertDBusToJSON("a{sv}", msg, properties);
1732 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001733 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001734 BMCWEB_LOG_ERROR << "convertDBusToJSON failed";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001735 }
1736 else
1737 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001738 for (auto& prop : properties.items())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001739 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001740 // if property name is empty, or
1741 // matches our search query, add it
1742 // to the response json
Ed Tanous1abe55e2018-09-05 08:30:59 -07001743
Ed Tanous002d39b2022-05-31 08:59:27 -07001744 if (propertyName->empty())
1745 {
1746 (*response)[prop.key()] =
1747 std::move(prop.value());
1748 }
1749 else if (prop.key() == *propertyName)
1750 {
1751 *response = std::move(prop.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001752 }
1753 }
1754 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001755 }
1756 if (response.use_count() == 1)
1757 {
1758 if (!propertyName->empty() && response->empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001759 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001760 setErrorResponse(
1761 asyncResp->res,
1762 boost::beast::http::status::not_found,
1763 propNotFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001764 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001765 else
1766 {
1767 asyncResp->res.jsonValue["status"] = "ok";
1768 asyncResp->res.jsonValue["message"] = "200 OK";
1769 asyncResp->res.jsonValue["data"] = *response;
1770 }
1771 }
1772 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001773 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001774 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001775 },
1776 "xyz.openbmc_project.ObjectMapper",
1777 "/xyz/openbmc_project/object_mapper",
1778 "xyz.openbmc_project.ObjectMapper", "GetObject", *path,
1779 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001780}
1781
Ed Tanous1abe55e2018-09-05 08:30:59 -07001782struct AsyncPutRequest
1783{
Ed Tanous4e23a442022-06-06 09:57:26 -07001784 explicit AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
zhanghch058d1b46d2021-04-01 11:18:24 +08001785 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001786 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001787 ~AsyncPutRequest()
1788 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001789 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001790 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001791 setErrorResponse(asyncResp->res,
1792 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001793 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001794 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001795 }
1796
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001797 AsyncPutRequest(const AsyncPutRequest&) = delete;
1798 AsyncPutRequest(AsyncPutRequest&&) = delete;
1799 AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1800 AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1801
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001802 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001803 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001804 setErrorResponse(asyncResp->res,
1805 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001806 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001807 }
1808
zhanghch058d1b46d2021-04-01 11:18:24 +08001809 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001810 std::string objectPath;
1811 std::string propertyName;
1812 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001813};
1814
zhanghch058d1b46d2021-04-01 11:18:24 +08001815inline void handlePut(const crow::Request& req,
1816 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001817 const std::string& objectPath,
1818 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001819{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001820 if (destProperty.empty())
1821 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001822 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001823 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001824 return;
1825 }
1826
Ed Tanous1abe55e2018-09-05 08:30:59 -07001827 nlohmann::json requestDbusData =
1828 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001829
Ed Tanous1abe55e2018-09-05 08:30:59 -07001830 if (requestDbusData.is_discarded())
1831 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001832 setErrorResponse(asyncResp->res,
1833 boost::beast::http::status::bad_request, noJsonDesc,
1834 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001835 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001836 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001837
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001838 auto propertyIt = requestDbusData.find("data");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001839 if (propertyIt == requestDbusData.end())
1840 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001841 setErrorResponse(asyncResp->res,
1842 boost::beast::http::status::bad_request, noJsonDesc,
1843 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001844 return;
1845 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001846 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001847 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001848 transaction->objectPath = objectPath;
1849 transaction->propertyName = destProperty;
1850 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001851
Ed Tanous1abe55e2018-09-05 08:30:59 -07001852 crow::connections::systemBus->async_method_call(
Ed Tanous23a21a12020-07-25 04:45:05 +00001853 [transaction](const boost::system::error_code ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001854 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001855 if (!ec2 && objectNames.empty())
1856 {
1857 setErrorResponse(transaction->asyncResp->res,
1858 boost::beast::http::status::not_found,
1859 propNotFoundDesc, notFoundMsg);
1860 return;
1861 }
Ed Tanous911ac312017-08-15 09:37:42 -07001862
Ed Tanous002d39b2022-05-31 08:59:27 -07001863 for (const std::pair<std::string, std::vector<std::string>>&
1864 connection : objectNames)
1865 {
1866 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001867
Ed Tanous002d39b2022-05-31 08:59:27 -07001868 crow::connections::systemBus->async_method_call(
1869 [connectionName{std::string(connectionName)},
1870 transaction](const boost::system::error_code ec3,
1871 const std::string& introspectXml) {
1872 if (ec3)
1873 {
1874 BMCWEB_LOG_ERROR << "Introspect call failed with error: "
1875 << ec3.message()
1876 << " on process: " << connectionName;
1877 transaction->setErrorStatus("Unexpected Error");
1878 return;
1879 }
1880 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001881
Ed Tanous002d39b2022-05-31 08:59:27 -07001882 doc.Parse(introspectXml.c_str());
1883 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1884 if (pRoot == nullptr)
1885 {
1886 BMCWEB_LOG_ERROR << "XML document failed to parse: "
1887 << introspectXml;
1888 transaction->setErrorStatus("Unexpected Error");
1889 return;
1890 }
1891 tinyxml2::XMLElement* ifaceNode =
1892 pRoot->FirstChildElement("interface");
1893 while (ifaceNode != nullptr)
1894 {
1895 const char* interfaceName = ifaceNode->Attribute("name");
1896 BMCWEB_LOG_DEBUG << "found interface " << interfaceName;
1897 tinyxml2::XMLElement* propNode =
1898 ifaceNode->FirstChildElement("property");
1899 while (propNode != nullptr)
1900 {
1901 const char* propertyName = propNode->Attribute("name");
1902 BMCWEB_LOG_DEBUG << "Found property " << propertyName;
1903 if (propertyName == transaction->propertyName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001904 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001905 const char* argType = propNode->Attribute("type");
1906 if (argType != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001907 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001908 sdbusplus::message::message m =
1909 crow::connections::systemBus
1910 ->new_method_call(
1911 connectionName.c_str(),
1912 transaction->objectPath.c_str(),
1913 "org.freedesktop.DBus."
1914 "Properties",
1915 "Set");
1916 m.append(interfaceName,
1917 transaction->propertyName);
1918 int r = sd_bus_message_open_container(
1919 m.get(), SD_BUS_TYPE_VARIANT, argType);
1920 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001921 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001922 transaction->setErrorStatus(
1923 "Unexpected Error");
1924 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001925 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001926 r = convertJsonToDbus(
1927 m.get(), argType,
1928 transaction->propertyValue);
1929 if (r < 0)
1930 {
1931 if (r == -ERANGE)
1932 {
1933 transaction->setErrorStatus(
1934 "Provided property value "
1935 "is out of range for the "
1936 "property type");
1937 }
1938 else
1939 {
1940 transaction->setErrorStatus(
1941 "Invalid arg type");
1942 }
1943 return;
1944 }
1945 r = sd_bus_message_close_container(m.get());
1946 if (r < 0)
1947 {
1948 transaction->setErrorStatus(
1949 "Unexpected Error");
1950 return;
1951 }
1952 crow::connections::systemBus->async_send(
1953 m,
1954 [transaction](
1955 boost::system::error_code ec,
1956 sdbusplus::message::message& m2) {
1957 BMCWEB_LOG_DEBUG << "sent";
1958 if (ec)
1959 {
1960 const sd_bus_error* e = m2.get_error();
1961 setErrorResponse(
1962 transaction->asyncResp->res,
1963 boost::beast::http::status::
1964 forbidden,
1965 (e) != nullptr
1966 ? e->name
1967 : ec.category().name(),
1968 (e) != nullptr ? e->message
1969 : ec.message());
1970 }
1971 else
1972 {
1973 transaction->asyncResp->res
1974 .jsonValue["status"] = "ok";
1975 transaction->asyncResp->res
1976 .jsonValue["message"] = "200 OK";
1977 transaction->asyncResp->res
1978 .jsonValue["data"] = nullptr;
1979 }
1980 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001981 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001982 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001983 propNode = propNode->NextSiblingElement("property");
1984 }
1985 ifaceNode = ifaceNode->NextSiblingElement("interface");
1986 }
1987 },
1988 connectionName, transaction->objectPath,
1989 "org.freedesktop.DBus.Introspectable", "Introspect");
1990 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001991 },
1992 "xyz.openbmc_project.ObjectMapper",
1993 "/xyz/openbmc_project/object_mapper",
1994 "xyz.openbmc_project.ObjectMapper", "GetObject",
1995 transaction->objectPath, std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001996}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001997
zhanghch058d1b46d2021-04-01 11:18:24 +08001998inline void handleDBusUrl(const crow::Request& req,
1999 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002000 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002001{
Ed Tanous049a0512018-11-01 13:58:42 -07002002
2003 // If accessing a single attribute, fill in and update objectPath,
2004 // otherwise leave destProperty blank
Ed Tanouse05aec52022-01-25 10:28:56 -08002005 std::string destProperty;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002006 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002007 size_t attrPosition = objectPath.find(attrSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002008 if (attrPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002009 {
2010 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2011 objectPath.length());
2012 objectPath = objectPath.substr(0, attrPosition);
2013 }
2014
Ed Tanousb41187f2019-10-24 16:30:02 -07002015 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002016 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002017 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002018 size_t actionPosition = objectPath.find(actionSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002019 if (actionPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002020 {
2021 std::string postProperty =
2022 objectPath.substr((actionPosition + strlen(actionSeperator)),
2023 objectPath.length());
2024 objectPath = objectPath.substr(0, actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002025 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002026 return;
2027 }
2028 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002029 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002030 {
2031 if (boost::ends_with(objectPath, "/enumerate"))
2032 {
2033 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2034 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002035 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002036 }
2037 else if (boost::ends_with(objectPath, "/list"))
2038 {
2039 objectPath.erase(objectPath.end() - sizeof("list"),
2040 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002041 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002042 }
2043 else
2044 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002045 // Trim any trailing "/" at the end
2046 if (boost::ends_with(objectPath, "/"))
2047 {
2048 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002049 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002050 }
2051 else
2052 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002053 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002054 }
Ed Tanous049a0512018-11-01 13:58:42 -07002055 }
2056 return;
2057 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002058 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002059 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002060 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002061 return;
2062 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002063 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002064 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002065 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002066 return;
2067 }
Ed Tanous049a0512018-11-01 13:58:42 -07002068
zhanghch058d1b46d2021-04-01 11:18:24 +08002069 setErrorResponse(asyncResp->res,
2070 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002071 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002072}
2073
Ed Tanous1656b292022-05-04 11:33:42 -07002074inline void
2075 handleBusSystemPost(const crow::Request& req,
2076 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2077 const std::string& processName,
2078 const std::string& requestedPath)
2079{
2080 std::vector<std::string> strs;
2081 boost::split(strs, requestedPath, boost::is_any_of("/"));
2082 std::string objectPath;
2083 std::string interfaceName;
2084 std::string methodName;
2085 auto it = strs.begin();
2086 if (it == strs.end())
2087 {
2088 objectPath = "/";
2089 }
2090 while (it != strs.end())
2091 {
2092 // Check if segment contains ".". If it does, it must be an
2093 // interface
2094 if (it->find(".") != std::string::npos)
2095 {
2096 break;
2097 // This check is necessary as the trailing slash gets
2098 // parsed as part of our <path> specifier above, which
2099 // causes the normal trailing backslash redirector to
2100 // fail.
2101 }
2102 if (!it->empty())
2103 {
2104 objectPath += "/" + *it;
2105 }
2106 it++;
2107 }
2108 if (it != strs.end())
2109 {
2110 interfaceName = *it;
2111 it++;
2112
2113 // after interface, we might have a method name
2114 if (it != strs.end())
2115 {
2116 methodName = *it;
2117 it++;
2118 }
2119 }
2120 if (it != strs.end())
2121 {
2122 // if there is more levels past the method name, something
2123 // went wrong, return not found
2124 asyncResp->res.result(boost::beast::http::status::not_found);
2125 return;
2126 }
2127 if (interfaceName.empty())
2128 {
2129 crow::connections::systemBus->async_method_call(
2130 [asyncResp, processName,
2131 objectPath](const boost::system::error_code ec,
2132 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002133 if (ec)
2134 {
2135 BMCWEB_LOG_ERROR
2136 << "Introspect call failed with error: " << ec.message()
2137 << " on process: " << processName << " path: " << objectPath
2138 << "\n";
2139 return;
2140 }
2141 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002142
Ed Tanous002d39b2022-05-31 08:59:27 -07002143 doc.Parse(introspectXml.c_str());
2144 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2145 if (pRoot == nullptr)
2146 {
2147 BMCWEB_LOG_ERROR << "XML document failed to parse "
2148 << processName << " " << objectPath << "\n";
2149 asyncResp->res.jsonValue["status"] = "XML parse error";
2150 asyncResp->res.result(
2151 boost::beast::http::status::internal_server_error);
2152 return;
2153 }
2154
2155 BMCWEB_LOG_DEBUG << introspectXml;
2156 asyncResp->res.jsonValue["status"] = "ok";
2157 asyncResp->res.jsonValue["bus_name"] = processName;
2158 asyncResp->res.jsonValue["object_path"] = objectPath;
2159
2160 nlohmann::json& interfacesArray =
2161 asyncResp->res.jsonValue["interfaces"];
2162 interfacesArray = nlohmann::json::array();
2163 tinyxml2::XMLElement* interface =
2164 pRoot->FirstChildElement("interface");
2165
2166 while (interface != nullptr)
2167 {
2168 const char* ifaceName = interface->Attribute("name");
2169 if (ifaceName != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002170 {
Ed Tanous8a592812022-06-04 09:06:59 -07002171 nlohmann::json::object_t interfaceObj;
2172 interfaceObj["name"] = ifaceName;
2173 interfacesArray.push_back(std::move(interfaceObj));
Ed Tanous1656b292022-05-04 11:33:42 -07002174 }
2175
Ed Tanous002d39b2022-05-31 08:59:27 -07002176 interface = interface->NextSiblingElement("interface");
2177 }
Ed Tanous1656b292022-05-04 11:33:42 -07002178 },
2179 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2180 "Introspect");
2181 }
2182 else if (methodName.empty())
2183 {
2184 crow::connections::systemBus->async_method_call(
2185 [asyncResp, processName, objectPath,
2186 interfaceName](const boost::system::error_code ec,
2187 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002188 if (ec)
2189 {
2190 BMCWEB_LOG_ERROR
2191 << "Introspect call failed with error: " << ec.message()
2192 << " on process: " << processName << " path: " << objectPath
2193 << "\n";
2194 return;
2195 }
2196 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002197
Ed Tanous002d39b2022-05-31 08:59:27 -07002198 doc.Parse(introspectXml.data(), introspectXml.size());
2199 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2200 if (pRoot == nullptr)
2201 {
2202 BMCWEB_LOG_ERROR << "XML document failed to parse "
2203 << processName << " " << objectPath << "\n";
2204 asyncResp->res.result(
2205 boost::beast::http::status::internal_server_error);
2206 return;
2207 }
2208
2209 asyncResp->res.jsonValue["status"] = "ok";
2210 asyncResp->res.jsonValue["bus_name"] = processName;
2211 asyncResp->res.jsonValue["interface"] = interfaceName;
2212 asyncResp->res.jsonValue["object_path"] = objectPath;
2213
2214 nlohmann::json& methodsArray = asyncResp->res.jsonValue["methods"];
2215 methodsArray = nlohmann::json::array();
2216
2217 nlohmann::json& signalsArray = asyncResp->res.jsonValue["signals"];
2218 signalsArray = nlohmann::json::array();
2219
2220 nlohmann::json& propertiesObj =
2221 asyncResp->res.jsonValue["properties"];
2222 propertiesObj = nlohmann::json::object();
2223
2224 // if we know we're the only call, build the
2225 // json directly
2226 tinyxml2::XMLElement* interface =
2227 pRoot->FirstChildElement("interface");
2228 while (interface != nullptr)
2229 {
2230 const char* ifaceName = interface->Attribute("name");
2231
2232 if (ifaceName != nullptr && ifaceName == interfaceName)
Ed Tanous1656b292022-05-04 11:33:42 -07002233 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002234 break;
Ed Tanous1656b292022-05-04 11:33:42 -07002235 }
Ed Tanous14766872022-03-15 10:44:42 -07002236
Ed Tanous002d39b2022-05-31 08:59:27 -07002237 interface = interface->NextSiblingElement("interface");
2238 }
2239 if (interface == nullptr)
2240 {
2241 // if we got to the end of the list and
2242 // never found a match, throw 404
2243 asyncResp->res.result(boost::beast::http::status::not_found);
2244 return;
2245 }
Ed Tanous1656b292022-05-04 11:33:42 -07002246
Ed Tanous002d39b2022-05-31 08:59:27 -07002247 tinyxml2::XMLElement* methods =
2248 interface->FirstChildElement("method");
2249 while (methods != nullptr)
2250 {
2251 nlohmann::json argsArray = nlohmann::json::array();
2252 tinyxml2::XMLElement* arg = methods->FirstChildElement("arg");
2253 while (arg != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002254 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002255 nlohmann::json thisArg;
2256 for (const char* fieldName : std::array<const char*, 3>{
2257 "name", "direction", "type"})
Ed Tanous1656b292022-05-04 11:33:42 -07002258 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002259 const char* fieldValue = arg->Attribute(fieldName);
2260 if (fieldValue != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002261 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002262 thisArg[fieldName] = fieldValue;
2263 }
2264 }
2265 argsArray.push_back(std::move(thisArg));
2266 arg = arg->NextSiblingElement("arg");
2267 }
2268
2269 const char* name = methods->Attribute("name");
2270 if (name != nullptr)
2271 {
2272 std::string uri;
2273 uri.reserve(14 + processName.size() + objectPath.size() +
2274 interfaceName.size() + strlen(name));
2275 uri += "/bus/system/";
2276 uri += processName;
2277 uri += objectPath;
2278 uri += "/";
2279 uri += interfaceName;
2280 uri += "/";
2281 uri += name;
2282
2283 nlohmann::json::object_t object;
2284 object["name"] = name;
2285 object["uri"] = std::move(uri);
2286 object["args"] = argsArray;
2287
2288 methodsArray.push_back(std::move(object));
2289 }
2290 methods = methods->NextSiblingElement("method");
2291 }
2292 tinyxml2::XMLElement* signals =
2293 interface->FirstChildElement("signal");
2294 while (signals != nullptr)
2295 {
2296 nlohmann::json argsArray = nlohmann::json::array();
2297
2298 tinyxml2::XMLElement* arg = signals->FirstChildElement("arg");
2299 while (arg != nullptr)
2300 {
2301 const char* name = arg->Attribute("name");
2302 const char* type = arg->Attribute("type");
2303 if (name != nullptr && type != nullptr)
2304 {
2305 argsArray.push_back({
2306 {"name", name},
2307 {"type", type},
2308 });
2309 }
2310 arg = arg->NextSiblingElement("arg");
2311 }
2312 const char* name = signals->Attribute("name");
2313 if (name != nullptr)
2314 {
2315 nlohmann::json::object_t object;
2316 object["name"] = name;
2317 object["args"] = argsArray;
2318 signalsArray.push_back(std::move(object));
2319 }
2320
2321 signals = signals->NextSiblingElement("signal");
2322 }
2323
2324 tinyxml2::XMLElement* property =
2325 interface->FirstChildElement("property");
2326 while (property != nullptr)
2327 {
2328 const char* name = property->Attribute("name");
2329 const char* type = property->Attribute("type");
2330 if (type != nullptr && name != nullptr)
2331 {
2332 sdbusplus::message::message m =
2333 crow::connections::systemBus->new_method_call(
2334 processName.c_str(), objectPath.c_str(),
2335 "org.freedesktop."
2336 "DBus."
2337 "Properties",
2338 "Get");
2339 m.append(interfaceName, name);
2340 nlohmann::json& propertyItem = propertiesObj[name];
2341 crow::connections::systemBus->async_send(
2342 m, [&propertyItem,
2343 asyncResp](boost::system::error_code& e,
2344 sdbusplus::message::message& msg) {
2345 if (e)
Ed Tanous1656b292022-05-04 11:33:42 -07002346 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002347 return;
Ed Tanous1656b292022-05-04 11:33:42 -07002348 }
Ed Tanous1656b292022-05-04 11:33:42 -07002349
Ed Tanous002d39b2022-05-31 08:59:27 -07002350 convertDBusToJSON("v", msg, propertyItem);
2351 });
Ed Tanous1656b292022-05-04 11:33:42 -07002352 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002353 property = property->NextSiblingElement("property");
2354 }
Ed Tanous1656b292022-05-04 11:33:42 -07002355 },
2356 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2357 "Introspect");
2358 }
2359 else
2360 {
2361 if (req.method() != boost::beast::http::verb::post)
2362 {
2363 asyncResp->res.result(boost::beast::http::status::not_found);
2364 return;
2365 }
2366
2367 nlohmann::json requestDbusData =
2368 nlohmann::json::parse(req.body, nullptr, false);
2369
2370 if (requestDbusData.is_discarded())
2371 {
2372 asyncResp->res.result(boost::beast::http::status::bad_request);
2373 return;
2374 }
2375 if (!requestDbusData.is_array())
2376 {
2377 asyncResp->res.result(boost::beast::http::status::bad_request);
2378 return;
2379 }
2380 auto transaction =
2381 std::make_shared<InProgressActionData>(asyncResp->res);
2382
2383 transaction->path = objectPath;
2384 transaction->methodName = methodName;
2385 transaction->arguments = std::move(requestDbusData);
2386
2387 findActionOnInterface(transaction, processName);
2388 }
2389}
2390
Ed Tanous23a21a12020-07-25 04:45:05 +00002391inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002392{
2393 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002394 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002395 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002396 [](const crow::Request&,
2397 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002398 nlohmann::json::array_t buses;
2399 nlohmann::json& bus = buses.emplace_back();
2400 bus["name"] = "system";
2401 asyncResp->res.jsonValue["busses"] = std::move(buses);
2402 asyncResp->res.jsonValue["status"] = "ok";
2403 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002404
2405 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002406 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002407 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002408 [](const crow::Request&,
2409 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002410 auto myCallback = [asyncResp](const boost::system::error_code ec,
zhanghch058d1b46d2021-04-01 11:18:24 +08002411 std::vector<std::string>& names) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002412 if (ec)
2413 {
2414 BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
2415 asyncResp->res.result(
2416 boost::beast::http::status::internal_server_error);
2417 }
2418 else
2419 {
2420 std::sort(names.begin(), names.end());
2421 asyncResp->res.jsonValue["status"] = "ok";
2422 auto& objectsSub = asyncResp->res.jsonValue["objects"];
2423 for (auto& name : names)
2424 {
2425 nlohmann::json::object_t object;
2426 object["name"] = name;
2427 objectsSub.push_back(std::move(object));
2428 }
2429 }
2430 };
2431 crow::connections::systemBus->async_method_call(
2432 std::move(myCallback), "org.freedesktop.DBus", "/",
2433 "org.freedesktop.DBus", "ListNames");
2434 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002435
2436 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002437 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002438 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002439 [](const crow::Request&,
2440 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002441 handleList(asyncResp, "/");
2442 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002443
2444 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002445 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002446 .methods(boost::beast::http::verb::get)(
2447 [](const crow::Request& req,
2448 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002449 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002450 std::string objectPath = "/xyz/" + path;
2451 handleDBusUrl(req, asyncResp, objectPath);
2452 });
zhanghch058d1b46d2021-04-01 11:18:24 +08002453
2454 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002455 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002456 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2457 boost::beast::http::verb::delete_)(
2458 [](const crow::Request& req,
2459 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2460 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002461 std::string objectPath = "/xyz/" + path;
2462 handleDBusUrl(req, asyncResp, objectPath);
2463 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002464
Ed Tanous049a0512018-11-01 13:58:42 -07002465 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002466 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002467 .methods(boost::beast::http::verb::get)(
2468 [](const crow::Request& req,
2469 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2470 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002471 std::string objectPath = "/org/" + path;
2472 handleDBusUrl(req, asyncResp, objectPath);
2473 });
Tanousf00032d2018-11-05 01:18:10 -03002474
2475 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002476 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002477 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2478 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002479 [](const crow::Request& req,
2480 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002481 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002482 std::string objectPath = "/org/" + path;
2483 handleDBusUrl(req, asyncResp, objectPath);
2484 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002485
Ed Tanous1abe55e2018-09-05 08:30:59 -07002486 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002487 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002488 .methods(boost::beast::http::verb::get)(
2489 [](const crow::Request&,
2490 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2491 const std::string& dumpId) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002492 if (!validateFilename(dumpId))
2493 {
2494 asyncResp->res.result(boost::beast::http::status::bad_request);
2495 return;
2496 }
2497 std::filesystem::path loc("/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002498
Ed Tanous002d39b2022-05-31 08:59:27 -07002499 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002500
Ed Tanous002d39b2022-05-31 08:59:27 -07002501 if (!std::filesystem::exists(loc) ||
2502 !std::filesystem::is_directory(loc))
2503 {
2504 BMCWEB_LOG_ERROR << loc.string() << "Not found";
2505 asyncResp->res.result(boost::beast::http::status::not_found);
2506 return;
2507 }
2508 std::filesystem::directory_iterator files(loc);
zhanghch058d1b46d2021-04-01 11:18:24 +08002509
Ed Tanous002d39b2022-05-31 08:59:27 -07002510 for (const auto& file : files)
2511 {
2512 std::ifstream readFile(file.path());
2513 if (!readFile.good())
2514 {
2515 continue;
2516 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002517
Ed Tanous002d39b2022-05-31 08:59:27 -07002518 asyncResp->res.addHeader("Content-Type",
2519 "application/octet-stream");
zhanghch058d1b46d2021-04-01 11:18:24 +08002520
Ed Tanous002d39b2022-05-31 08:59:27 -07002521 // Assuming only one dump file will be present in the dump
2522 // id directory
2523 std::string dumpFileName = file.path().filename().string();
zhanghch058d1b46d2021-04-01 11:18:24 +08002524
Ed Tanous002d39b2022-05-31 08:59:27 -07002525 // Filename should be in alphanumeric, dot and underscore
2526 // Its based on phosphor-debug-collector application
2527 // dumpfile format
2528 std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
2529 if (!std::regex_match(dumpFileName, dumpFileRegex))
2530 {
2531 BMCWEB_LOG_ERROR << "Invalid dump filename " << dumpFileName;
zhanghch058d1b46d2021-04-01 11:18:24 +08002532 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002533 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07002534 }
2535 std::string contentDispositionParam =
2536 "attachment; filename=\"" + dumpFileName + "\"";
2537
2538 asyncResp->res.addHeader("Content-Disposition",
2539 contentDispositionParam);
2540
2541 asyncResp->res.body() = {std::istreambuf_iterator<char>(readFile),
2542 std::istreambuf_iterator<char>()};
2543 return;
2544 }
2545 asyncResp->res.result(boost::beast::http::status::not_found);
2546 return;
2547 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002548
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002549 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002550 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002551
2552 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002553 [](const crow::Request&,
2554 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002555 const std::string& connection) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002556 introspectObjects(connection, "/", asyncResp);
2557 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002558
2559 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002560 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous1656b292022-05-04 11:33:42 -07002561 .methods(boost::beast::http::verb::get,
2562 boost::beast::http::verb::post)(handleBusSystemPost);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002563}
2564} // namespace openbmc_mapper
2565} // namespace crow