blob: 9e79e60ccd78066e1b888175912f6c5bd74686ad [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 Tanous23a21a12020-07-25 04:45:05 +0000439 InProgressActionData(crow::Response& resIn) : res(resIn)
440 {}
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
1428 nlohmann::json::const_iterator argIt =
1429 transaction->arguments.begin();
1430
1431 argumentNode = methodNode->FirstChildElement("arg");
1432
1433 while (argumentNode != nullptr)
1434 {
1435 const char* argDirection =
1436 argumentNode->Attribute("direction");
1437 const char* argType =
1438 argumentNode->Attribute("type");
1439 if (argDirection != nullptr && argType != nullptr &&
1440 std::string(argDirection) == "in")
1441 {
1442 if (argIt == transaction->arguments.end())
1443 {
1444 transaction->setErrorStatus(
1445 "Invalid method args");
1446 return;
1447 }
1448 if (convertJsonToDbus(m.get(),
1449 std::string(argType),
1450 *argIt) < 0)
1451 {
1452 transaction->setErrorStatus(
1453 "Invalid method arg type");
1454 return;
1455 }
1456
1457 argIt++;
1458 }
1459 argumentNode =
1460 argumentNode->NextSiblingElement("arg");
1461 }
1462
1463 crow::connections::systemBus->async_send(
1464 m,
1465 [transaction,
1466 returnType](boost::system::error_code ec2,
1467 sdbusplus::message::message& m2) {
1468 if (ec2)
1469 {
1470 transaction->methodFailed = true;
1471 const sd_bus_error* e = m2.get_error();
1472
1473 if (e != nullptr)
1474 {
1475 setErrorResponse(
1476 transaction->res,
1477 boost::beast::http::status::bad_request,
1478 e->name, e->message);
1479 }
1480 else
1481 {
1482 setErrorResponse(
1483 transaction->res,
1484 boost::beast::http::status::bad_request,
1485 "Method call failed", methodFailedMsg);
1486 }
1487 return;
1488 }
1489 transaction->methodPassed = true;
1490
1491 handleMethodResponse(transaction, m2, returnType);
1492 });
1493 break;
1494 }
1495 methodNode = methodNode->NextSiblingElement("method");
1496 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001497 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001498 interfaceNode = interfaceNode->NextSiblingElement("interface");
1499 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001500 },
1501 connectionName, transaction->path,
1502 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001503}
1504
zhanghch058d1b46d2021-04-01 11:18:24 +08001505inline void handleAction(const crow::Request& req,
1506 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001507 const std::string& objectPath,
1508 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001509{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001510 BMCWEB_LOG_DEBUG << "handleAction on path: " << objectPath << " and method "
1511 << methodName;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001512 nlohmann::json requestDbusData =
1513 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001514
Ed Tanous1abe55e2018-09-05 08:30:59 -07001515 if (requestDbusData.is_discarded())
1516 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001517 setErrorResponse(asyncResp->res,
1518 boost::beast::http::status::bad_request, noJsonDesc,
1519 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001520 return;
1521 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001522 nlohmann::json::iterator data = requestDbusData.find("data");
1523 if (data == requestDbusData.end())
1524 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001525 setErrorResponse(asyncResp->res,
1526 boost::beast::http::status::bad_request, noJsonDesc,
1527 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001528 return;
1529 }
1530
1531 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001532 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001533 setErrorResponse(asyncResp->res,
1534 boost::beast::http::status::bad_request, noJsonDesc,
1535 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001536 return;
1537 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001538 auto transaction = std::make_shared<InProgressActionData>(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001539
1540 transaction->path = objectPath;
1541 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001542 transaction->arguments = std::move(*data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001543 crow::connections::systemBus->async_method_call(
1544 [transaction](
1545 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001546 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1547 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001548 if (ec || interfaceNames.empty())
1549 {
1550 BMCWEB_LOG_ERROR << "Can't find object";
1551 setErrorResponse(transaction->res,
1552 boost::beast::http::status::not_found,
1553 notFoundDesc, notFoundMsg);
1554 return;
1555 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001556
Ed Tanous002d39b2022-05-31 08:59:27 -07001557 BMCWEB_LOG_DEBUG << "GetObject returned " << interfaceNames.size()
1558 << " object(s)";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001559
Ed Tanous002d39b2022-05-31 08:59:27 -07001560 for (const std::pair<std::string, std::vector<std::string>>& object :
1561 interfaceNames)
1562 {
1563 findActionOnInterface(transaction, object.first);
1564 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001565 },
1566 "xyz.openbmc_project.ObjectMapper",
1567 "/xyz/openbmc_project/object_mapper",
1568 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
1569 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001570}
1571
zhanghch058d1b46d2021-04-01 11:18:24 +08001572inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1573 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001574{
1575 BMCWEB_LOG_DEBUG << "handleDelete on path: " << objectPath;
1576
1577 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +08001578 [asyncResp, objectPath](
Matt Spinlerde818812018-12-11 16:39:20 -06001579 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001580 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1581 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001582 if (ec || interfaceNames.empty())
1583 {
1584 BMCWEB_LOG_ERROR << "Can't find object";
1585 setErrorResponse(asyncResp->res,
1586 boost::beast::http::status::method_not_allowed,
1587 methodNotAllowedDesc, methodNotAllowedMsg);
1588 return;
1589 }
Matt Spinlerde818812018-12-11 16:39:20 -06001590
Ed Tanous002d39b2022-05-31 08:59:27 -07001591 auto transaction =
1592 std::make_shared<InProgressActionData>(asyncResp->res);
1593 transaction->path = objectPath;
1594 transaction->methodName = "Delete";
1595 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
Matt Spinlerde818812018-12-11 16:39:20 -06001596
Ed Tanous002d39b2022-05-31 08:59:27 -07001597 for (const std::pair<std::string, std::vector<std::string>>& object :
1598 interfaceNames)
1599 {
1600 findActionOnInterface(transaction, object.first);
1601 }
Matt Spinlerde818812018-12-11 16:39:20 -06001602 },
1603 "xyz.openbmc_project.ObjectMapper",
1604 "/xyz/openbmc_project/object_mapper",
1605 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001606 std::array<const char*, 0>());
Matt Spinlerde818812018-12-11 16:39:20 -06001607}
1608
zhanghch058d1b46d2021-04-01 11:18:24 +08001609inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1610 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001611{
1612 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001613 [asyncResp](
1614 const boost::system::error_code ec,
1615 const dbus::utility::MapperGetSubTreePathsResponse& objectPaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001616 if (ec)
1617 {
1618 setErrorResponse(asyncResp->res,
1619 boost::beast::http::status::not_found,
1620 notFoundDesc, notFoundMsg);
1621 }
1622 else
1623 {
1624 asyncResp->res.jsonValue["status"] = "ok";
1625 asyncResp->res.jsonValue["message"] = "200 OK";
1626 asyncResp->res.jsonValue["data"] = objectPaths;
1627 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001628 },
1629 "xyz.openbmc_project.ObjectMapper",
1630 "/xyz/openbmc_project/object_mapper",
1631 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", objectPath,
Ed Tanousf839dfe2018-11-12 11:11:15 -08001632 depth, std::array<std::string, 0>());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001633}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001634
zhanghch058d1b46d2021-04-01 11:18:24 +08001635inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1636 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001637{
Ed Tanous049a0512018-11-01 13:58:42 -07001638 BMCWEB_LOG_DEBUG << "Doing enumerate on " << objectPath;
Ed Tanous049a0512018-11-01 13:58:42 -07001639
Ed Tanous14766872022-03-15 10:44:42 -07001640 asyncResp->res.jsonValue["message"] = "200 OK";
1641 asyncResp->res.jsonValue["status"] = "ok";
1642 asyncResp->res.jsonValue["data"] = nlohmann::json::object();
Ed Tanous049a0512018-11-01 13:58:42 -07001643
Ed Tanous1abe55e2018-09-05 08:30:59 -07001644 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001645 [objectPath, asyncResp](
1646 const boost::system::error_code ec,
1647 const dbus::utility::MapperGetSubTreeResponse& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001648 auto transaction =
1649 std::make_shared<InProgressEnumerateData>(objectPath, asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001650
Ed Tanous002d39b2022-05-31 08:59:27 -07001651 transaction->subtree =
1652 std::make_shared<dbus::utility::MapperGetSubTreeResponse>(
1653 objectNames);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001654
Ed Tanous002d39b2022-05-31 08:59:27 -07001655 if (ec)
1656 {
1657 BMCWEB_LOG_ERROR << "GetSubTree failed on "
1658 << transaction->objectPath;
1659 setErrorResponse(transaction->asyncResp->res,
1660 boost::beast::http::status::not_found,
1661 notFoundDesc, notFoundMsg);
1662 return;
1663 }
Ed Tanous64530012018-02-06 17:08:16 -08001664
Ed Tanous002d39b2022-05-31 08:59:27 -07001665 // Add the data for the path passed in to the results
1666 // as if GetSubTree returned it, and continue on enumerating
1667 getObjectAndEnumerate(transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001668 },
1669 "xyz.openbmc_project.ObjectMapper",
1670 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -07001671 "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath, 0,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001672 std::array<const char*, 0>());
Ed Tanous64530012018-02-06 17:08:16 -08001673}
Ed Tanous911ac312017-08-15 09:37:42 -07001674
zhanghch058d1b46d2021-04-01 11:18:24 +08001675inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1676 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001677{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001678 BMCWEB_LOG_DEBUG << "handleGet: " << objectPath << " prop:" << destProperty;
1679 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001680 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001681
Ed Tanous1abe55e2018-09-05 08:30:59 -07001682 std::shared_ptr<std::string> path =
1683 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001684
Ed Tanous1abe55e2018-09-05 08:30:59 -07001685 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001686 [asyncResp, path,
1687 propertyName](const boost::system::error_code ec,
1688 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001689 if (ec || objectNames.empty())
1690 {
1691 setErrorResponse(asyncResp->res,
1692 boost::beast::http::status::not_found,
1693 notFoundDesc, notFoundMsg);
1694 return;
1695 }
1696 std::shared_ptr<nlohmann::json> response =
1697 std::make_shared<nlohmann::json>(nlohmann::json::object());
1698 // The mapper should never give us an empty interface names
1699 // list, but check anyway
1700 for (const std::pair<std::string, std::vector<std::string>>&
1701 connection : objectNames)
1702 {
1703 const std::vector<std::string>& interfaceNames = connection.second;
1704
1705 if (interfaceNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001706 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001707 setErrorResponse(asyncResp->res,
1708 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001709 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001710 return;
1711 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001712
1713 for (const std::string& interface : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001714 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001715 sdbusplus::message::message m =
1716 crow::connections::systemBus->new_method_call(
1717 connection.first.c_str(), path->c_str(),
1718 "org.freedesktop.DBus.Properties", "GetAll");
1719 m.append(interface);
1720 crow::connections::systemBus->async_send(
1721 m, [asyncResp, response,
1722 propertyName](const boost::system::error_code ec2,
1723 sdbusplus::message::message& msg) {
1724 if (ec2)
1725 {
1726 BMCWEB_LOG_ERROR << "Bad dbus request error: "
1727 << ec2;
1728 }
1729 else
1730 {
1731 nlohmann::json properties;
1732 int r = convertDBusToJSON("a{sv}", msg, properties);
1733 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001734 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001735 BMCWEB_LOG_ERROR << "convertDBusToJSON failed";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001736 }
1737 else
1738 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001739 for (auto& prop : properties.items())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001740 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001741 // if property name is empty, or
1742 // matches our search query, add it
1743 // to the response json
Ed Tanous1abe55e2018-09-05 08:30:59 -07001744
Ed Tanous002d39b2022-05-31 08:59:27 -07001745 if (propertyName->empty())
1746 {
1747 (*response)[prop.key()] =
1748 std::move(prop.value());
1749 }
1750 else if (prop.key() == *propertyName)
1751 {
1752 *response = std::move(prop.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001753 }
1754 }
1755 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001756 }
1757 if (response.use_count() == 1)
1758 {
1759 if (!propertyName->empty() && response->empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001760 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001761 setErrorResponse(
1762 asyncResp->res,
1763 boost::beast::http::status::not_found,
1764 propNotFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001765 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001766 else
1767 {
1768 asyncResp->res.jsonValue["status"] = "ok";
1769 asyncResp->res.jsonValue["message"] = "200 OK";
1770 asyncResp->res.jsonValue["data"] = *response;
1771 }
1772 }
1773 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001774 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001775 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001776 },
1777 "xyz.openbmc_project.ObjectMapper",
1778 "/xyz/openbmc_project/object_mapper",
1779 "xyz.openbmc_project.ObjectMapper", "GetObject", *path,
1780 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001781}
1782
Ed Tanous1abe55e2018-09-05 08:30:59 -07001783struct AsyncPutRequest
1784{
zhanghch058d1b46d2021-04-01 11:18:24 +08001785 AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
1786 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001787 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001788 ~AsyncPutRequest()
1789 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001790 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001791 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001792 setErrorResponse(asyncResp->res,
1793 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001794 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001795 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001796 }
1797
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001798 AsyncPutRequest(const AsyncPutRequest&) = delete;
1799 AsyncPutRequest(AsyncPutRequest&&) = delete;
1800 AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1801 AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1802
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001803 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001804 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001805 setErrorResponse(asyncResp->res,
1806 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001807 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001808 }
1809
zhanghch058d1b46d2021-04-01 11:18:24 +08001810 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001811 std::string objectPath;
1812 std::string propertyName;
1813 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001814};
1815
zhanghch058d1b46d2021-04-01 11:18:24 +08001816inline void handlePut(const crow::Request& req,
1817 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001818 const std::string& objectPath,
1819 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001820{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001821 if (destProperty.empty())
1822 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001823 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001824 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001825 return;
1826 }
1827
Ed Tanous1abe55e2018-09-05 08:30:59 -07001828 nlohmann::json requestDbusData =
1829 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001830
Ed Tanous1abe55e2018-09-05 08:30:59 -07001831 if (requestDbusData.is_discarded())
1832 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001833 setErrorResponse(asyncResp->res,
1834 boost::beast::http::status::bad_request, noJsonDesc,
1835 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001836 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001837 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001838
Ed Tanous1abe55e2018-09-05 08:30:59 -07001839 nlohmann::json::const_iterator propertyIt = requestDbusData.find("data");
1840 if (propertyIt == requestDbusData.end())
1841 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001842 setErrorResponse(asyncResp->res,
1843 boost::beast::http::status::bad_request, noJsonDesc,
1844 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001845 return;
1846 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001847 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001848 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001849 transaction->objectPath = objectPath;
1850 transaction->propertyName = destProperty;
1851 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001852
Ed Tanous1abe55e2018-09-05 08:30:59 -07001853 crow::connections::systemBus->async_method_call(
Ed Tanous23a21a12020-07-25 04:45:05 +00001854 [transaction](const boost::system::error_code ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001855 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001856 if (!ec2 && objectNames.empty())
1857 {
1858 setErrorResponse(transaction->asyncResp->res,
1859 boost::beast::http::status::not_found,
1860 propNotFoundDesc, notFoundMsg);
1861 return;
1862 }
Ed Tanous911ac312017-08-15 09:37:42 -07001863
Ed Tanous002d39b2022-05-31 08:59:27 -07001864 for (const std::pair<std::string, std::vector<std::string>>&
1865 connection : objectNames)
1866 {
1867 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001868
Ed Tanous002d39b2022-05-31 08:59:27 -07001869 crow::connections::systemBus->async_method_call(
1870 [connectionName{std::string(connectionName)},
1871 transaction](const boost::system::error_code ec3,
1872 const std::string& introspectXml) {
1873 if (ec3)
1874 {
1875 BMCWEB_LOG_ERROR << "Introspect call failed with error: "
1876 << ec3.message()
1877 << " on process: " << connectionName;
1878 transaction->setErrorStatus("Unexpected Error");
1879 return;
1880 }
1881 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001882
Ed Tanous002d39b2022-05-31 08:59:27 -07001883 doc.Parse(introspectXml.c_str());
1884 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1885 if (pRoot == nullptr)
1886 {
1887 BMCWEB_LOG_ERROR << "XML document failed to parse: "
1888 << introspectXml;
1889 transaction->setErrorStatus("Unexpected Error");
1890 return;
1891 }
1892 tinyxml2::XMLElement* ifaceNode =
1893 pRoot->FirstChildElement("interface");
1894 while (ifaceNode != nullptr)
1895 {
1896 const char* interfaceName = ifaceNode->Attribute("name");
1897 BMCWEB_LOG_DEBUG << "found interface " << interfaceName;
1898 tinyxml2::XMLElement* propNode =
1899 ifaceNode->FirstChildElement("property");
1900 while (propNode != nullptr)
1901 {
1902 const char* propertyName = propNode->Attribute("name");
1903 BMCWEB_LOG_DEBUG << "Found property " << propertyName;
1904 if (propertyName == transaction->propertyName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001905 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001906 const char* argType = propNode->Attribute("type");
1907 if (argType != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001908 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001909 sdbusplus::message::message m =
1910 crow::connections::systemBus
1911 ->new_method_call(
1912 connectionName.c_str(),
1913 transaction->objectPath.c_str(),
1914 "org.freedesktop.DBus."
1915 "Properties",
1916 "Set");
1917 m.append(interfaceName,
1918 transaction->propertyName);
1919 int r = sd_bus_message_open_container(
1920 m.get(), SD_BUS_TYPE_VARIANT, argType);
1921 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001922 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001923 transaction->setErrorStatus(
1924 "Unexpected Error");
1925 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001926 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001927 r = convertJsonToDbus(
1928 m.get(), argType,
1929 transaction->propertyValue);
1930 if (r < 0)
1931 {
1932 if (r == -ERANGE)
1933 {
1934 transaction->setErrorStatus(
1935 "Provided property value "
1936 "is out of range for the "
1937 "property type");
1938 }
1939 else
1940 {
1941 transaction->setErrorStatus(
1942 "Invalid arg type");
1943 }
1944 return;
1945 }
1946 r = sd_bus_message_close_container(m.get());
1947 if (r < 0)
1948 {
1949 transaction->setErrorStatus(
1950 "Unexpected Error");
1951 return;
1952 }
1953 crow::connections::systemBus->async_send(
1954 m,
1955 [transaction](
1956 boost::system::error_code ec,
1957 sdbusplus::message::message& m2) {
1958 BMCWEB_LOG_DEBUG << "sent";
1959 if (ec)
1960 {
1961 const sd_bus_error* e = m2.get_error();
1962 setErrorResponse(
1963 transaction->asyncResp->res,
1964 boost::beast::http::status::
1965 forbidden,
1966 (e) != nullptr
1967 ? e->name
1968 : ec.category().name(),
1969 (e) != nullptr ? e->message
1970 : ec.message());
1971 }
1972 else
1973 {
1974 transaction->asyncResp->res
1975 .jsonValue["status"] = "ok";
1976 transaction->asyncResp->res
1977 .jsonValue["message"] = "200 OK";
1978 transaction->asyncResp->res
1979 .jsonValue["data"] = nullptr;
1980 }
1981 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001982 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001983 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001984 propNode = propNode->NextSiblingElement("property");
1985 }
1986 ifaceNode = ifaceNode->NextSiblingElement("interface");
1987 }
1988 },
1989 connectionName, transaction->objectPath,
1990 "org.freedesktop.DBus.Introspectable", "Introspect");
1991 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001992 },
1993 "xyz.openbmc_project.ObjectMapper",
1994 "/xyz/openbmc_project/object_mapper",
1995 "xyz.openbmc_project.ObjectMapper", "GetObject",
1996 transaction->objectPath, std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001997}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001998
zhanghch058d1b46d2021-04-01 11:18:24 +08001999inline void handleDBusUrl(const crow::Request& req,
2000 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002001 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002002{
Ed Tanous049a0512018-11-01 13:58:42 -07002003
2004 // If accessing a single attribute, fill in and update objectPath,
2005 // otherwise leave destProperty blank
Ed Tanouse05aec52022-01-25 10:28:56 -08002006 std::string destProperty;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002007 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002008 size_t attrPosition = objectPath.find(attrSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002009 if (attrPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002010 {
2011 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2012 objectPath.length());
2013 objectPath = objectPath.substr(0, attrPosition);
2014 }
2015
Ed Tanousb41187f2019-10-24 16:30:02 -07002016 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002017 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002018 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002019 size_t actionPosition = objectPath.find(actionSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002020 if (actionPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002021 {
2022 std::string postProperty =
2023 objectPath.substr((actionPosition + strlen(actionSeperator)),
2024 objectPath.length());
2025 objectPath = objectPath.substr(0, actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002026 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002027 return;
2028 }
2029 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002030 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002031 {
2032 if (boost::ends_with(objectPath, "/enumerate"))
2033 {
2034 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2035 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002036 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002037 }
2038 else if (boost::ends_with(objectPath, "/list"))
2039 {
2040 objectPath.erase(objectPath.end() - sizeof("list"),
2041 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002042 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002043 }
2044 else
2045 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002046 // Trim any trailing "/" at the end
2047 if (boost::ends_with(objectPath, "/"))
2048 {
2049 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002050 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002051 }
2052 else
2053 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002054 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002055 }
Ed Tanous049a0512018-11-01 13:58:42 -07002056 }
2057 return;
2058 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002059 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002060 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002061 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002062 return;
2063 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002064 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002065 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002066 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002067 return;
2068 }
Ed Tanous049a0512018-11-01 13:58:42 -07002069
zhanghch058d1b46d2021-04-01 11:18:24 +08002070 setErrorResponse(asyncResp->res,
2071 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002072 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002073}
2074
Ed Tanous1656b292022-05-04 11:33:42 -07002075inline void
2076 handleBusSystemPost(const crow::Request& req,
2077 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2078 const std::string& processName,
2079 const std::string& requestedPath)
2080{
2081 std::vector<std::string> strs;
2082 boost::split(strs, requestedPath, boost::is_any_of("/"));
2083 std::string objectPath;
2084 std::string interfaceName;
2085 std::string methodName;
2086 auto it = strs.begin();
2087 if (it == strs.end())
2088 {
2089 objectPath = "/";
2090 }
2091 while (it != strs.end())
2092 {
2093 // Check if segment contains ".". If it does, it must be an
2094 // interface
2095 if (it->find(".") != std::string::npos)
2096 {
2097 break;
2098 // This check is necessary as the trailing slash gets
2099 // parsed as part of our <path> specifier above, which
2100 // causes the normal trailing backslash redirector to
2101 // fail.
2102 }
2103 if (!it->empty())
2104 {
2105 objectPath += "/" + *it;
2106 }
2107 it++;
2108 }
2109 if (it != strs.end())
2110 {
2111 interfaceName = *it;
2112 it++;
2113
2114 // after interface, we might have a method name
2115 if (it != strs.end())
2116 {
2117 methodName = *it;
2118 it++;
2119 }
2120 }
2121 if (it != strs.end())
2122 {
2123 // if there is more levels past the method name, something
2124 // went wrong, return not found
2125 asyncResp->res.result(boost::beast::http::status::not_found);
2126 return;
2127 }
2128 if (interfaceName.empty())
2129 {
2130 crow::connections::systemBus->async_method_call(
2131 [asyncResp, processName,
2132 objectPath](const boost::system::error_code ec,
2133 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002134 if (ec)
2135 {
2136 BMCWEB_LOG_ERROR
2137 << "Introspect call failed with error: " << ec.message()
2138 << " on process: " << processName << " path: " << objectPath
2139 << "\n";
2140 return;
2141 }
2142 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002143
Ed Tanous002d39b2022-05-31 08:59:27 -07002144 doc.Parse(introspectXml.c_str());
2145 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2146 if (pRoot == nullptr)
2147 {
2148 BMCWEB_LOG_ERROR << "XML document failed to parse "
2149 << processName << " " << objectPath << "\n";
2150 asyncResp->res.jsonValue["status"] = "XML parse error";
2151 asyncResp->res.result(
2152 boost::beast::http::status::internal_server_error);
2153 return;
2154 }
2155
2156 BMCWEB_LOG_DEBUG << introspectXml;
2157 asyncResp->res.jsonValue["status"] = "ok";
2158 asyncResp->res.jsonValue["bus_name"] = processName;
2159 asyncResp->res.jsonValue["object_path"] = objectPath;
2160
2161 nlohmann::json& interfacesArray =
2162 asyncResp->res.jsonValue["interfaces"];
2163 interfacesArray = nlohmann::json::array();
2164 tinyxml2::XMLElement* interface =
2165 pRoot->FirstChildElement("interface");
2166
2167 while (interface != nullptr)
2168 {
2169 const char* ifaceName = interface->Attribute("name");
2170 if (ifaceName != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002171 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002172 nlohmann::json::object_t interface;
2173 interface["name"] = ifaceName;
2174 interfacesArray.push_back(std::move(interface));
Ed Tanous1656b292022-05-04 11:33:42 -07002175 }
2176
Ed Tanous002d39b2022-05-31 08:59:27 -07002177 interface = interface->NextSiblingElement("interface");
2178 }
Ed Tanous1656b292022-05-04 11:33:42 -07002179 },
2180 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2181 "Introspect");
2182 }
2183 else if (methodName.empty())
2184 {
2185 crow::connections::systemBus->async_method_call(
2186 [asyncResp, processName, objectPath,
2187 interfaceName](const boost::system::error_code ec,
2188 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002189 if (ec)
2190 {
2191 BMCWEB_LOG_ERROR
2192 << "Introspect call failed with error: " << ec.message()
2193 << " on process: " << processName << " path: " << objectPath
2194 << "\n";
2195 return;
2196 }
2197 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002198
Ed Tanous002d39b2022-05-31 08:59:27 -07002199 doc.Parse(introspectXml.data(), introspectXml.size());
2200 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2201 if (pRoot == nullptr)
2202 {
2203 BMCWEB_LOG_ERROR << "XML document failed to parse "
2204 << processName << " " << objectPath << "\n";
2205 asyncResp->res.result(
2206 boost::beast::http::status::internal_server_error);
2207 return;
2208 }
2209
2210 asyncResp->res.jsonValue["status"] = "ok";
2211 asyncResp->res.jsonValue["bus_name"] = processName;
2212 asyncResp->res.jsonValue["interface"] = interfaceName;
2213 asyncResp->res.jsonValue["object_path"] = objectPath;
2214
2215 nlohmann::json& methodsArray = asyncResp->res.jsonValue["methods"];
2216 methodsArray = nlohmann::json::array();
2217
2218 nlohmann::json& signalsArray = asyncResp->res.jsonValue["signals"];
2219 signalsArray = nlohmann::json::array();
2220
2221 nlohmann::json& propertiesObj =
2222 asyncResp->res.jsonValue["properties"];
2223 propertiesObj = nlohmann::json::object();
2224
2225 // if we know we're the only call, build the
2226 // json directly
2227 tinyxml2::XMLElement* interface =
2228 pRoot->FirstChildElement("interface");
2229 while (interface != nullptr)
2230 {
2231 const char* ifaceName = interface->Attribute("name");
2232
2233 if (ifaceName != nullptr && ifaceName == interfaceName)
Ed Tanous1656b292022-05-04 11:33:42 -07002234 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002235 break;
Ed Tanous1656b292022-05-04 11:33:42 -07002236 }
Ed Tanous14766872022-03-15 10:44:42 -07002237
Ed Tanous002d39b2022-05-31 08:59:27 -07002238 interface = interface->NextSiblingElement("interface");
2239 }
2240 if (interface == nullptr)
2241 {
2242 // if we got to the end of the list and
2243 // never found a match, throw 404
2244 asyncResp->res.result(boost::beast::http::status::not_found);
2245 return;
2246 }
Ed Tanous1656b292022-05-04 11:33:42 -07002247
Ed Tanous002d39b2022-05-31 08:59:27 -07002248 tinyxml2::XMLElement* methods =
2249 interface->FirstChildElement("method");
2250 while (methods != nullptr)
2251 {
2252 nlohmann::json argsArray = nlohmann::json::array();
2253 tinyxml2::XMLElement* arg = methods->FirstChildElement("arg");
2254 while (arg != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002255 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002256 nlohmann::json thisArg;
2257 for (const char* fieldName : std::array<const char*, 3>{
2258 "name", "direction", "type"})
Ed Tanous1656b292022-05-04 11:33:42 -07002259 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002260 const char* fieldValue = arg->Attribute(fieldName);
2261 if (fieldValue != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002262 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002263 thisArg[fieldName] = fieldValue;
2264 }
2265 }
2266 argsArray.push_back(std::move(thisArg));
2267 arg = arg->NextSiblingElement("arg");
2268 }
2269
2270 const char* name = methods->Attribute("name");
2271 if (name != nullptr)
2272 {
2273 std::string uri;
2274 uri.reserve(14 + processName.size() + objectPath.size() +
2275 interfaceName.size() + strlen(name));
2276 uri += "/bus/system/";
2277 uri += processName;
2278 uri += objectPath;
2279 uri += "/";
2280 uri += interfaceName;
2281 uri += "/";
2282 uri += name;
2283
2284 nlohmann::json::object_t object;
2285 object["name"] = name;
2286 object["uri"] = std::move(uri);
2287 object["args"] = argsArray;
2288
2289 methodsArray.push_back(std::move(object));
2290 }
2291 methods = methods->NextSiblingElement("method");
2292 }
2293 tinyxml2::XMLElement* signals =
2294 interface->FirstChildElement("signal");
2295 while (signals != nullptr)
2296 {
2297 nlohmann::json argsArray = nlohmann::json::array();
2298
2299 tinyxml2::XMLElement* arg = signals->FirstChildElement("arg");
2300 while (arg != nullptr)
2301 {
2302 const char* name = arg->Attribute("name");
2303 const char* type = arg->Attribute("type");
2304 if (name != nullptr && type != nullptr)
2305 {
2306 argsArray.push_back({
2307 {"name", name},
2308 {"type", type},
2309 });
2310 }
2311 arg = arg->NextSiblingElement("arg");
2312 }
2313 const char* name = signals->Attribute("name");
2314 if (name != nullptr)
2315 {
2316 nlohmann::json::object_t object;
2317 object["name"] = name;
2318 object["args"] = argsArray;
2319 signalsArray.push_back(std::move(object));
2320 }
2321
2322 signals = signals->NextSiblingElement("signal");
2323 }
2324
2325 tinyxml2::XMLElement* property =
2326 interface->FirstChildElement("property");
2327 while (property != nullptr)
2328 {
2329 const char* name = property->Attribute("name");
2330 const char* type = property->Attribute("type");
2331 if (type != nullptr && name != nullptr)
2332 {
2333 sdbusplus::message::message m =
2334 crow::connections::systemBus->new_method_call(
2335 processName.c_str(), objectPath.c_str(),
2336 "org.freedesktop."
2337 "DBus."
2338 "Properties",
2339 "Get");
2340 m.append(interfaceName, name);
2341 nlohmann::json& propertyItem = propertiesObj[name];
2342 crow::connections::systemBus->async_send(
2343 m, [&propertyItem,
2344 asyncResp](boost::system::error_code& e,
2345 sdbusplus::message::message& msg) {
2346 if (e)
Ed Tanous1656b292022-05-04 11:33:42 -07002347 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002348 return;
Ed Tanous1656b292022-05-04 11:33:42 -07002349 }
Ed Tanous1656b292022-05-04 11:33:42 -07002350
Ed Tanous002d39b2022-05-31 08:59:27 -07002351 convertDBusToJSON("v", msg, propertyItem);
2352 });
Ed Tanous1656b292022-05-04 11:33:42 -07002353 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002354 property = property->NextSiblingElement("property");
2355 }
Ed Tanous1656b292022-05-04 11:33:42 -07002356 },
2357 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2358 "Introspect");
2359 }
2360 else
2361 {
2362 if (req.method() != boost::beast::http::verb::post)
2363 {
2364 asyncResp->res.result(boost::beast::http::status::not_found);
2365 return;
2366 }
2367
2368 nlohmann::json requestDbusData =
2369 nlohmann::json::parse(req.body, nullptr, false);
2370
2371 if (requestDbusData.is_discarded())
2372 {
2373 asyncResp->res.result(boost::beast::http::status::bad_request);
2374 return;
2375 }
2376 if (!requestDbusData.is_array())
2377 {
2378 asyncResp->res.result(boost::beast::http::status::bad_request);
2379 return;
2380 }
2381 auto transaction =
2382 std::make_shared<InProgressActionData>(asyncResp->res);
2383
2384 transaction->path = objectPath;
2385 transaction->methodName = methodName;
2386 transaction->arguments = std::move(requestDbusData);
2387
2388 findActionOnInterface(transaction, processName);
2389 }
2390}
2391
Ed Tanous23a21a12020-07-25 04:45:05 +00002392inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002393{
2394 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002395 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002396 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002397 [](const crow::Request&,
2398 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002399 nlohmann::json::array_t buses;
2400 nlohmann::json& bus = buses.emplace_back();
2401 bus["name"] = "system";
2402 asyncResp->res.jsonValue["busses"] = std::move(buses);
2403 asyncResp->res.jsonValue["status"] = "ok";
2404 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002405
2406 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002407 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002408 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002409 [](const crow::Request&,
2410 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002411 auto myCallback = [asyncResp](const boost::system::error_code ec,
zhanghch058d1b46d2021-04-01 11:18:24 +08002412 std::vector<std::string>& names) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002413 if (ec)
2414 {
2415 BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
2416 asyncResp->res.result(
2417 boost::beast::http::status::internal_server_error);
2418 }
2419 else
2420 {
2421 std::sort(names.begin(), names.end());
2422 asyncResp->res.jsonValue["status"] = "ok";
2423 auto& objectsSub = asyncResp->res.jsonValue["objects"];
2424 for (auto& name : names)
2425 {
2426 nlohmann::json::object_t object;
2427 object["name"] = name;
2428 objectsSub.push_back(std::move(object));
2429 }
2430 }
2431 };
2432 crow::connections::systemBus->async_method_call(
2433 std::move(myCallback), "org.freedesktop.DBus", "/",
2434 "org.freedesktop.DBus", "ListNames");
2435 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002436
2437 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002438 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002439 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002440 [](const crow::Request&,
2441 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002442 handleList(asyncResp, "/");
2443 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002444
2445 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002446 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002447 .methods(boost::beast::http::verb::get)(
2448 [](const crow::Request& req,
2449 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002450 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002451 std::string objectPath = "/xyz/" + path;
2452 handleDBusUrl(req, asyncResp, objectPath);
2453 });
zhanghch058d1b46d2021-04-01 11:18:24 +08002454
2455 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002456 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002457 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2458 boost::beast::http::verb::delete_)(
2459 [](const crow::Request& req,
2460 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2461 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002462 std::string objectPath = "/xyz/" + path;
2463 handleDBusUrl(req, asyncResp, objectPath);
2464 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002465
Ed Tanous049a0512018-11-01 13:58:42 -07002466 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002467 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002468 .methods(boost::beast::http::verb::get)(
2469 [](const crow::Request& req,
2470 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2471 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002472 std::string objectPath = "/org/" + path;
2473 handleDBusUrl(req, asyncResp, objectPath);
2474 });
Tanousf00032d2018-11-05 01:18:10 -03002475
2476 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002477 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002478 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2479 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002480 [](const crow::Request& req,
2481 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002482 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002483 std::string objectPath = "/org/" + path;
2484 handleDBusUrl(req, asyncResp, objectPath);
2485 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002486
Ed Tanous1abe55e2018-09-05 08:30:59 -07002487 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002488 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002489 .methods(boost::beast::http::verb::get)(
2490 [](const crow::Request&,
2491 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2492 const std::string& dumpId) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002493 if (!validateFilename(dumpId))
2494 {
2495 asyncResp->res.result(boost::beast::http::status::bad_request);
2496 return;
2497 }
2498 std::filesystem::path loc("/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002499
Ed Tanous002d39b2022-05-31 08:59:27 -07002500 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002501
Ed Tanous002d39b2022-05-31 08:59:27 -07002502 if (!std::filesystem::exists(loc) ||
2503 !std::filesystem::is_directory(loc))
2504 {
2505 BMCWEB_LOG_ERROR << loc.string() << "Not found";
2506 asyncResp->res.result(boost::beast::http::status::not_found);
2507 return;
2508 }
2509 std::filesystem::directory_iterator files(loc);
zhanghch058d1b46d2021-04-01 11:18:24 +08002510
Ed Tanous002d39b2022-05-31 08:59:27 -07002511 for (const auto& file : files)
2512 {
2513 std::ifstream readFile(file.path());
2514 if (!readFile.good())
2515 {
2516 continue;
2517 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002518
Ed Tanous002d39b2022-05-31 08:59:27 -07002519 asyncResp->res.addHeader("Content-Type",
2520 "application/octet-stream");
zhanghch058d1b46d2021-04-01 11:18:24 +08002521
Ed Tanous002d39b2022-05-31 08:59:27 -07002522 // Assuming only one dump file will be present in the dump
2523 // id directory
2524 std::string dumpFileName = file.path().filename().string();
zhanghch058d1b46d2021-04-01 11:18:24 +08002525
Ed Tanous002d39b2022-05-31 08:59:27 -07002526 // Filename should be in alphanumeric, dot and underscore
2527 // Its based on phosphor-debug-collector application
2528 // dumpfile format
2529 std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
2530 if (!std::regex_match(dumpFileName, dumpFileRegex))
2531 {
2532 BMCWEB_LOG_ERROR << "Invalid dump filename " << dumpFileName;
zhanghch058d1b46d2021-04-01 11:18:24 +08002533 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002534 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07002535 }
2536 std::string contentDispositionParam =
2537 "attachment; filename=\"" + dumpFileName + "\"";
2538
2539 asyncResp->res.addHeader("Content-Disposition",
2540 contentDispositionParam);
2541
2542 asyncResp->res.body() = {std::istreambuf_iterator<char>(readFile),
2543 std::istreambuf_iterator<char>()};
2544 return;
2545 }
2546 asyncResp->res.result(boost::beast::http::status::not_found);
2547 return;
2548 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002549
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002550 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002551 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002552
2553 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002554 [](const crow::Request&,
2555 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002556 const std::string& connection) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002557 introspectObjects(connection, "/", asyncResp);
2558 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002559
2560 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002561 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous1656b292022-05-04 11:33:42 -07002562 .methods(boost::beast::http::verb::get,
2563 boost::beast::http::verb::post)(handleBusSystemPost);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002564}
2565} // namespace openbmc_mapper
2566} // namespace crow