blob: cf07f76f33369b5aa1aee7a5208eedbd523ac5bb [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 Tanous11ba3972022-07-11 09:50:41 -070020#include <boost/algorithm/string/classification.hpp>
21#include <boost/algorithm/string/predicate.hpp>
22#include <boost/algorithm/string/split.hpp>
Ed Tanous1abe55e2018-09-05 08:30:59 -070023#include <boost/container/flat_set.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -070024#include <dbus_singleton.hpp>
James Feist5b4aa862018-08-16 14:07:01 -070025#include <dbus_utility.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050026#include <sdbusplus/message/types.hpp>
27
James Feist4418c7f2019-04-15 11:09:15 -070028#include <filesystem>
Ed Tanousd4bb9bb2018-05-16 13:36:42 -070029#include <fstream>
Ramesh Iyyard9207042019-07-05 08:04:42 -050030#include <regex>
Ed Tanousb5a76932020-09-29 16:16:58 -070031#include <utility>
Ed Tanous911ac312017-08-15 09:37:42 -070032
Ed Tanous1abe55e2018-09-05 08:30:59 -070033namespace crow
34{
35namespace openbmc_mapper
36{
Ed Tanous23a21a12020-07-25 04:45:05 +000037const constexpr char* notFoundMsg = "404 Not Found";
38const constexpr char* badReqMsg = "400 Bad Request";
39const constexpr char* methodNotAllowedMsg = "405 Method Not Allowed";
40const constexpr char* forbiddenMsg = "403 Forbidden";
41const constexpr char* methodFailedMsg = "500 Method Call Failed";
42const constexpr char* methodOutputFailedMsg = "500 Method Output Error";
43const constexpr char* notFoundDesc =
Matt Spinler2ae60092018-12-06 10:35:36 -060044 "org.freedesktop.DBus.Error.FileNotFound: path or object not found";
Ed Tanous23a21a12020-07-25 04:45:05 +000045const constexpr char* propNotFoundDesc =
46 "The specified property cannot be found";
47const constexpr char* noJsonDesc = "No JSON object could be decoded";
48const constexpr char* methodNotFoundDesc =
49 "The specified method cannot be found";
50const constexpr char* methodNotAllowedDesc = "Method not allowed";
51const constexpr char* forbiddenPropDesc =
52 "The specified property cannot be created";
53const constexpr char* forbiddenResDesc =
54 "The specified resource cannot be created";
Matt Spinler2ae60092018-12-06 10:35:36 -060055
Josh Lehan482c45a2022-03-29 17:10:44 -070056inline bool validateFilename(const std::string& filename)
57{
58 std::regex validFilename(R"(^[\w\- ]+(\.?[\w\- ]*)$)");
59
60 return std::regex_match(filename, validFilename);
61}
62
Ed Tanous23a21a12020-07-25 04:45:05 +000063inline void setErrorResponse(crow::Response& res,
64 boost::beast::http::status result,
65 const std::string& desc,
66 const std::string_view msg)
Matt Spinler2ae60092018-12-06 10:35:36 -060067{
68 res.result(result);
Ed Tanous14766872022-03-15 10:44:42 -070069 res.jsonValue["data"]["description"] = desc;
70 res.jsonValue["message"] = msg;
71 res.jsonValue["status"] = "error";
Matt Spinler2ae60092018-12-06 10:35:36 -060072}
73
Ed Tanousb5a76932020-09-29 16:16:58 -070074inline void
75 introspectObjects(const std::string& processName,
76 const std::string& objectPath,
77 const std::shared_ptr<bmcweb::AsyncResp>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -070078{
Ed Tanouse3cb5a32018-08-08 14:16:49 -070079 if (transaction->res.jsonValue.is_null())
80 {
Ed Tanous14766872022-03-15 10:44:42 -070081 transaction->res.jsonValue["status"] = "ok";
82 transaction->res.jsonValue["bus_name"] = processName;
83 transaction->res.jsonValue["objects"] = nlohmann::json::array();
Ed Tanouse3cb5a32018-08-08 14:16:49 -070084 }
85
Ed Tanous1abe55e2018-09-05 08:30:59 -070086 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -070087 [transaction, processName{std::string(processName)},
88 objectPath{std::string(objectPath)}](
89 const boost::system::error_code ec,
Ed Tanous81ce6092020-12-17 16:54:55 +000090 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -070091 if (ec)
92 {
93 BMCWEB_LOG_ERROR
94 << "Introspect call failed with error: " << ec.message()
95 << " on process: " << processName << " path: " << objectPath
96 << "\n";
97 return;
98 }
99 nlohmann::json::object_t object;
100 object["path"] = objectPath;
Ed Tanous14766872022-03-15 10:44:42 -0700101
Ed Tanous002d39b2022-05-31 08:59:27 -0700102 transaction->res.jsonValue["objects"].push_back(std::move(object));
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700103
Ed Tanous002d39b2022-05-31 08:59:27 -0700104 tinyxml2::XMLDocument doc;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700105
Ed Tanous002d39b2022-05-31 08:59:27 -0700106 doc.Parse(introspectXml.c_str());
107 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
108 if (pRoot == nullptr)
109 {
110 BMCWEB_LOG_ERROR << "XML document failed to parse " << processName
111 << " " << objectPath << "\n";
112 }
113 else
114 {
115 tinyxml2::XMLElement* node = pRoot->FirstChildElement("node");
116 while (node != nullptr)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700117 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700118 const char* childPath = node->Attribute("name");
119 if (childPath != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700120 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700121 std::string newpath;
122 if (objectPath != "/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700124 newpath += objectPath;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700125 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700126 newpath += std::string("/") + childPath;
127 // introspect the subobjects as well
128 introspectObjects(processName, newpath, transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700129 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700130
131 node = node->NextSiblingElement("node");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700132 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700133 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700134 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700135 processName, objectPath, "org.freedesktop.DBus.Introspectable",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700136 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -0700137}
Ed Tanous64530012018-02-06 17:08:16 -0800138
Ed Tanous23a21a12020-07-25 04:45:05 +0000139inline void getPropertiesForEnumerate(
140 const std::string& objectPath, const std::string& service,
Ed Tanousb5a76932020-09-29 16:16:58 -0700141 const std::string& interface,
142 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600143{
144 BMCWEB_LOG_DEBUG << "getPropertiesForEnumerate " << objectPath << " "
145 << service << " " << interface;
146
147 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -0800148 [asyncResp, objectPath, service,
149 interface](const boost::system::error_code ec,
150 const dbus::utility::DBusPropertiesMap& propertiesList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700151 if (ec)
152 {
153 BMCWEB_LOG_ERROR << "GetAll on path " << objectPath << " iface "
154 << interface << " service " << service
155 << " failed with code " << ec;
156 return;
157 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600158
Ed Tanous002d39b2022-05-31 08:59:27 -0700159 nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
160 nlohmann::json& objectJson = dataJson[objectPath];
161 if (objectJson.is_null())
162 {
163 objectJson = nlohmann::json::object();
164 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600165
Ed Tanous002d39b2022-05-31 08:59:27 -0700166 for (const auto& [name, value] : propertiesList)
167 {
168 nlohmann::json& propertyJson = objectJson[name];
169 std::visit(
170 [&propertyJson](auto&& val) {
171 if constexpr (std::is_same_v<std::decay_t<decltype(val)>,
172 sdbusplus::message::unix_fd>)
173 {
174 propertyJson = val.fd;
175 }
176 else
177 {
Ed Tanousd1a64812021-12-13 12:14:05 -0800178
Ed Tanous002d39b2022-05-31 08:59:27 -0700179 propertyJson = val;
180 }
181 },
182 value);
183 }
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600184 },
185 service, objectPath, "org.freedesktop.DBus.Properties", "GetAll",
186 interface);
187}
188
189// Find any results that weren't picked up by ObjectManagers, to be
190// called after all ObjectManagers are searched for and called.
Ed Tanous23a21a12020-07-25 04:45:05 +0000191inline void findRemainingObjectsForEnumerate(
Ed Tanousb5a76932020-09-29 16:16:58 -0700192 const std::string& objectPath,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800193 const std::shared_ptr<dbus::utility::MapperGetSubTreeResponse>& subtree,
Ed Tanousb5a76932020-09-29 16:16:58 -0700194 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600195{
196 BMCWEB_LOG_DEBUG << "findRemainingObjectsForEnumerate";
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500197 const nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600198
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500199 for (const auto& [path, interface_map] : *subtree)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600200 {
201 if (path == objectPath)
202 {
203 // An enumerate does not return the target path's properties
204 continue;
205 }
206 if (dataJson.find(path) == dataJson.end())
207 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500208 for (const auto& [service, interfaces] : interface_map)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600209 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500210 for (const auto& interface : interfaces)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600211 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700212 if (!interface.starts_with("org.freedesktop.DBus"))
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600213 {
214 getPropertiesForEnumerate(path, service, interface,
215 asyncResp);
216 }
217 }
218 }
219 }
220 }
221}
222
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600223struct InProgressEnumerateData
224{
zhanghch058d1b46d2021-04-01 11:18:24 +0800225 InProgressEnumerateData(
226 const std::string& objectPathIn,
227 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
Ed Tanous23a21a12020-07-25 04:45:05 +0000228 objectPath(objectPathIn),
zhanghch058d1b46d2021-04-01 11:18:24 +0800229 asyncResp(asyncRespIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500230 {}
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600231
232 ~InProgressEnumerateData()
233 {
Ed Tanous24b2fe82022-01-06 12:45:54 -0800234 try
235 {
236 findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
237 }
238 catch (...)
239 {
240 BMCWEB_LOG_CRITICAL
241 << "findRemainingObjectsForEnumerate threw exception";
242 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600243 }
244
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800245 InProgressEnumerateData(const InProgressEnumerateData&) = delete;
246 InProgressEnumerateData(InProgressEnumerateData&&) = delete;
247 InProgressEnumerateData& operator=(const InProgressEnumerateData&) = delete;
248 InProgressEnumerateData& operator=(InProgressEnumerateData&&) = delete;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600249 const std::string objectPath;
Ed Tanousb9d36b42022-02-26 21:42:46 -0800250 std::shared_ptr<dbus::utility::MapperGetSubTreeResponse> subtree;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600251 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
252};
253
Ed Tanous23a21a12020-07-25 04:45:05 +0000254inline void getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000255 const std::string& objectName, const std::string& objectManagerPath,
256 const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700257 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700258{
Ed Tanous81ce6092020-12-17 16:54:55 +0000259 BMCWEB_LOG_DEBUG << "getManagedObjectsForEnumerate " << objectName
260 << " object_manager_path " << objectManagerPath
261 << " connection_name " << connectionName;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700262 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000263 [transaction, objectName,
264 connectionName](const boost::system::error_code ec,
265 const dbus::utility::ManagedObjectType& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700266 if (ec)
267 {
268 BMCWEB_LOG_ERROR << "GetManagedObjects on path " << objectName
269 << " on connection " << connectionName
270 << " failed with code " << ec;
271 return;
272 }
Ed Tanous64530012018-02-06 17:08:16 -0800273
Ed Tanous002d39b2022-05-31 08:59:27 -0700274 nlohmann::json& dataJson =
275 transaction->asyncResp->res.jsonValue["data"];
Ed Tanous049a0512018-11-01 13:58:42 -0700276
Ed Tanous002d39b2022-05-31 08:59:27 -0700277 for (const auto& objectPath : objects)
278 {
Ed Tanous11ba3972022-07-11 09:50:41 -0700279 if (objectPath.first.str.starts_with(objectName))
Ed Tanous049a0512018-11-01 13:58:42 -0700280 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700281 BMCWEB_LOG_DEBUG << "Reading object " << objectPath.first.str;
282 nlohmann::json& objectJson = dataJson[objectPath.first.str];
283 if (objectJson.is_null())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700284 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700285 objectJson = nlohmann::json::object();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700286 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500287 for (const auto& interface : objectPath.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700288 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700289 for (const auto& property : interface.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700290 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700291 nlohmann::json& propertyJson =
292 objectJson[property.first];
293 std::visit(
294 [&propertyJson](auto&& val) {
295 if constexpr (std::is_same_v<
296 std::decay_t<decltype(val)>,
297 sdbusplus::message::unix_fd>)
298 {
299 propertyJson = val.fd;
300 }
301 else
302 {
303
304 propertyJson = val;
305 }
306 },
307 property.second);
Ed Tanous049a0512018-11-01 13:58:42 -0700308 }
309 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700310 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700311 for (const auto& interface : objectPath.second)
312 {
313 if (interface.first == "org.freedesktop.DBus.ObjectManager")
314 {
315 getManagedObjectsForEnumerate(objectPath.first.str,
316 objectPath.first.str,
317 connectionName, transaction);
318 }
319 }
320 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700321 },
Ed Tanous81ce6092020-12-17 16:54:55 +0000322 connectionName, objectManagerPath, "org.freedesktop.DBus.ObjectManager",
323 "GetManagedObjects");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700324}
325
Ed Tanous23a21a12020-07-25 04:45:05 +0000326inline void findObjectManagerPathForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000327 const std::string& objectName, const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700328 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700329{
Ed Tanous81ce6092020-12-17 16:54:55 +0000330 BMCWEB_LOG_DEBUG << "Finding objectmanager for path " << objectName
331 << " on connection:" << connectionName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700332 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000333 [transaction, objectName, connectionName](
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700334 const boost::system::error_code ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800335 const dbus::utility::MapperGetAncestorsResponse& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700336 if (ec)
337 {
338 BMCWEB_LOG_ERROR << "GetAncestors on path " << objectName
339 << " failed with code " << ec;
340 return;
341 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700342
Ed Tanous002d39b2022-05-31 08:59:27 -0700343 for (const auto& pathGroup : objects)
344 {
345 for (const auto& connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700346 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700347 if (connectionGroup.first == connectionName)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700348 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700349 // Found the object manager path for this resource.
350 getManagedObjectsForEnumerate(objectName, pathGroup.first,
351 connectionName, transaction);
352 return;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700353 }
354 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700355 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700356 },
357 "xyz.openbmc_project.ObjectMapper",
358 "/xyz/openbmc_project/object_mapper",
Ed Tanous81ce6092020-12-17 16:54:55 +0000359 "xyz.openbmc_project.ObjectMapper", "GetAncestors", objectName,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500360 std::array<const char*, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700361}
Ed Tanous64530012018-02-06 17:08:16 -0800362
Ed Tanous7c091622019-05-23 11:42:36 -0700363// Uses GetObject to add the object info about the target /enumerate path to
364// the results of GetSubTree, as GetSubTree will not return info for the
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600365// target path, and then continues on enumerating the rest of the tree.
Ed Tanousb5a76932020-09-29 16:16:58 -0700366inline void getObjectAndEnumerate(
367 const std::shared_ptr<InProgressEnumerateData>& transaction)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600368{
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600369 crow::connections::systemBus->async_method_call(
370 [transaction](const boost::system::error_code ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800371 const dbus::utility::MapperGetObject& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700372 if (ec)
373 {
374 BMCWEB_LOG_ERROR << "GetObject for path " << transaction->objectPath
375 << " failed with code " << ec;
376 return;
377 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600378
Ed Tanous002d39b2022-05-31 08:59:27 -0700379 BMCWEB_LOG_DEBUG << "GetObject for " << transaction->objectPath
380 << " has " << objects.size() << " entries";
381 if (!objects.empty())
382 {
383 transaction->subtree->emplace_back(transaction->objectPath,
384 objects);
385 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600386
Ed Tanous002d39b2022-05-31 08:59:27 -0700387 // Map indicating connection name, and the path where the object
388 // manager exists
389 boost::container::flat_map<std::string, std::string> connections;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600390
Ed Tanous002d39b2022-05-31 08:59:27 -0700391 for (const auto& object : *(transaction->subtree))
392 {
393 for (const auto& connection : object.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600394 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700395 std::string& objectManagerPath = connections[connection.first];
396 for (const auto& interface : connection.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600397 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700398 BMCWEB_LOG_DEBUG << connection.first << " has interface "
399 << interface;
400 if (interface == "org.freedesktop.DBus.ObjectManager")
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600401 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700402 BMCWEB_LOG_DEBUG << "found object manager path "
403 << object.first;
404 objectManagerPath = object.first;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600405 }
406 }
407 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700408 }
409 BMCWEB_LOG_DEBUG << "Got " << connections.size() << " connections";
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600410
Ed Tanous002d39b2022-05-31 08:59:27 -0700411 for (const auto& connection : connections)
412 {
413 // If we already know where the object manager is, we don't
414 // need to search for it, we can call directly in to
415 // getManagedObjects
416 if (!connection.second.empty())
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600417 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700418 getManagedObjectsForEnumerate(transaction->objectPath,
419 connection.second,
420 connection.first, transaction);
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600421 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700422 else
423 {
424 // otherwise we need to find the object manager path
425 // before we can continue
426 findObjectManagerPathForEnumerate(
427 transaction->objectPath, connection.first, transaction);
428 }
429 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600430 },
431 "xyz.openbmc_project.ObjectMapper",
432 "/xyz/openbmc_project/object_mapper",
433 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500434 transaction->objectPath, std::array<const char*, 0>());
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600435}
Ed Tanous64530012018-02-06 17:08:16 -0800436
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700437// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700438struct InProgressActionData
439{
Ed Tanous4e23a442022-06-06 09:57:26 -0700440 explicit InProgressActionData(crow::Response& resIn) : res(resIn)
Ed Tanous23a21a12020-07-25 04:45:05 +0000441 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700442 ~InProgressActionData()
443 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600444 // Methods could have been called across different owners
445 // and interfaces, where some calls failed and some passed.
446 //
447 // The rules for this are:
448 // * if no method was called - error
449 // * if a method failed and none passed - error
450 // (converse: if at least one method passed - OK)
451 // * for the method output:
452 // * if output processing didn't fail, return the data
453
454 // Only deal with method returns if nothing failed earlier
455 if (res.result() == boost::beast::http::status::ok)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700456 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600457 if (!methodPassed)
458 {
Matt Spinler06b1b632019-06-18 16:09:25 -0500459 if (!methodFailed)
Matt Spinler16caaee2019-01-15 11:40:34 -0600460 {
461 setErrorResponse(res, boost::beast::http::status::not_found,
462 methodNotFoundDesc, notFoundMsg);
463 }
464 }
465 else
466 {
467 if (outputFailed)
468 {
469 setErrorResponse(
470 res, boost::beast::http::status::internal_server_error,
471 "Method output failure", methodOutputFailedMsg);
472 }
473 else
474 {
Ed Tanous14766872022-03-15 10:44:42 -0700475 res.jsonValue["status"] = "ok";
476 res.jsonValue["message"] = "200 OK";
477 res.jsonValue["data"] = methodResponse;
Matt Spinler16caaee2019-01-15 11:40:34 -0600478 }
479 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700480 }
Matt Spinler16caaee2019-01-15 11:40:34 -0600481
Ed Tanous1abe55e2018-09-05 08:30:59 -0700482 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700483 }
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800484 InProgressActionData(const InProgressActionData&) = delete;
485 InProgressActionData(InProgressActionData&&) = delete;
486 InProgressActionData& operator=(const InProgressActionData&) = delete;
487 InProgressActionData& operator=(InProgressActionData&&) = delete;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700488
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500489 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700490 {
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600491 setErrorResponse(res, boost::beast::http::status::bad_request, desc,
492 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700493 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500494 crow::Response& res;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700495 std::string path;
496 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600497 std::string interfaceName;
Matt Spinler16caaee2019-01-15 11:40:34 -0600498 bool methodPassed = false;
499 bool methodFailed = false;
500 bool outputFailed = false;
Matt Spinler39a4e392019-01-15 11:53:13 -0600501 bool convertedToArray = false;
Matt Spinler16caaee2019-01-15 11:40:34 -0600502 nlohmann::json methodResponse;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700503 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700504};
505
Ed Tanous23a21a12020-07-25 04:45:05 +0000506inline std::vector<std::string> dbusArgSplit(const std::string& string)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700507{
508 std::vector<std::string> ret;
509 if (string.empty())
510 {
511 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700512 }
Ed Tanous0f0353b2019-10-24 11:37:51 -0700513 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700514 int containerDepth = 0;
515
516 for (std::string::const_iterator character = string.begin();
517 character != string.end(); character++)
518 {
519 ret.back() += *character;
520 switch (*character)
521 {
522 case ('a'):
523 break;
524 case ('('):
525 case ('{'):
526 containerDepth++;
527 break;
528 case ('}'):
529 case (')'):
530 containerDepth--;
531 if (containerDepth == 0)
532 {
533 if (character + 1 != string.end())
534 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700535 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700536 }
537 }
538 break;
539 default:
540 if (containerDepth == 0)
541 {
542 if (character + 1 != string.end())
543 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700544 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700545 }
546 }
547 break;
548 }
549 }
Matt Spinler4ae611d2019-01-11 15:37:06 -0600550
551 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700552}
553
Ed Tanous81ce6092020-12-17 16:54:55 +0000554inline int convertJsonToDbus(sd_bus_message* m, const std::string& argType,
555 const nlohmann::json& inputJson)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700556{
557 int r = 0;
Ed Tanous71f52d92021-02-19 08:51:17 -0800558 BMCWEB_LOG_DEBUG << "Converting "
559 << inputJson.dump(2, ' ', true,
560 nlohmann::json::error_handler_t::replace)
Ed Tanous81ce6092020-12-17 16:54:55 +0000561 << " to type: " << argType;
562 const std::vector<std::string> argTypes = dbusArgSplit(argType);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700563
Ed Tanous1abe55e2018-09-05 08:30:59 -0700564 // Assume a single object for now.
Ed Tanous81ce6092020-12-17 16:54:55 +0000565 const nlohmann::json* j = &inputJson;
566 nlohmann::json::const_iterator jIt = inputJson.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700567
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500568 for (const std::string& argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700569 {
570 // If we are decoding multiple objects, grab the pointer to the
571 // iterator, and increment it for the next loop
572 if (argTypes.size() > 1)
573 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000574 if (jIt == inputJson.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700575 {
576 return -2;
577 }
578 j = &*jIt;
579 jIt++;
580 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500581 const int64_t* intValue = j->get_ptr<const int64_t*>();
582 const std::string* stringValue = j->get_ptr<const std::string*>();
583 const double* doubleValue = j->get_ptr<const double*>();
584 const bool* b = j->get_ptr<const bool*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700585 int64_t v = 0;
586 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700587
Ed Tanous1abe55e2018-09-05 08:30:59 -0700588 // Do some basic type conversions that make sense. uint can be
589 // converted to int. int and uint can be converted to double
Ed Tanous66664f22019-10-11 13:05:49 -0700590 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700591 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500592 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700593 if (uintValue != nullptr)
594 {
595 v = static_cast<int64_t>(*uintValue);
596 intValue = &v;
597 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700598 }
Ed Tanous66664f22019-10-11 13:05:49 -0700599 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700600 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500601 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700602 if (uintValue != nullptr)
603 {
604 d = static_cast<double>(*uintValue);
605 doubleValue = &d;
606 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700607 }
Ed Tanous66664f22019-10-11 13:05:49 -0700608 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700609 {
Ed Tanous66664f22019-10-11 13:05:49 -0700610 if (intValue != nullptr)
611 {
612 d = static_cast<double>(*intValue);
613 doubleValue = &d;
614 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700615 }
616
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700617 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700618 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700619 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700620 {
621 return -1;
622 }
Ed Tanous271584a2019-07-09 16:24:22 -0700623 r = sd_bus_message_append_basic(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500624 m, argCode[0], static_cast<const void*>(stringValue->data()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700625 if (r < 0)
626 {
627 return r;
628 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700629 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700630 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700631 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700632 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700633 {
634 return -1;
635 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500636 if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
637 (*intValue > std::numeric_limits<int32_t>::max()))
638 {
639 return -ERANGE;
640 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700641 int32_t i = static_cast<int32_t>(*intValue);
642 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700643 if (r < 0)
644 {
645 return r;
646 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700647 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700648 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700649 {
650 // lots of ways bool could be represented here. Try them all
Ed Tanouse662eae2022-01-25 10:39:19 -0800651 int boolInt = 0;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700652 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700653 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500654 if (*intValue == 1)
655 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800656 boolInt = 1;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500657 }
658 else if (*intValue == 0)
659 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800660 boolInt = 0;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500661 }
662 else
663 {
664 return -ERANGE;
665 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700666 }
667 else if (b != nullptr)
668 {
Matt Spinlera2f02632019-01-18 10:15:35 -0600669 boolInt = *b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700670 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700671 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700672 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700673 boolInt = boost::istarts_with(*stringValue, "t") ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700674 }
675 else
676 {
677 return -1;
678 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700679 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700680 if (r < 0)
681 {
682 return r;
683 }
684 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700685 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700686 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700687 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700688 {
689 return -1;
690 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500691 if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
692 (*intValue > std::numeric_limits<int16_t>::max()))
693 {
694 return -ERANGE;
695 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700696 int16_t n = static_cast<int16_t>(*intValue);
697 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700698 if (r < 0)
699 {
700 return r;
701 }
702 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700703 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700704 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700705 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700706 {
707 return -1;
708 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700709 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700710 if (r < 0)
711 {
712 return r;
713 }
714 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700715 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700716 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500717 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700718 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700719 {
720 return -1;
721 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000722 if (*uintValue > std::numeric_limits<uint8_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500723 {
724 return -ERANGE;
725 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700726 uint8_t y = static_cast<uint8_t>(*uintValue);
727 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700728 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700729 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700730 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500731 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700732 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700733 {
734 return -1;
735 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000736 if (*uintValue > std::numeric_limits<uint16_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500737 {
738 return -ERANGE;
739 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700740 uint16_t q = static_cast<uint16_t>(*uintValue);
741 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700742 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700743 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700744 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500745 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700746 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700747 {
748 return -1;
749 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000750 if (*uintValue > std::numeric_limits<uint32_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500751 {
752 return -ERANGE;
753 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700754 uint32_t u = static_cast<uint32_t>(*uintValue);
755 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700756 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700757 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700758 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500759 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700760 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700761 {
762 return -1;
763 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700764 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700765 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700766 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700767 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500768 if (doubleValue == nullptr)
769 {
770 return -1;
771 }
772 if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
773 (*doubleValue > std::numeric_limits<double>::max()))
774 {
775 return -ERANGE;
776 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700777 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700778 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700779 else if (argCode.starts_with("a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700780 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700781 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700782 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700783 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700784 if (r < 0)
785 {
786 return r;
787 }
788
Ed Tanous0dfeda62019-10-24 11:21:38 -0700789 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700790 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700791 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700792 if (r < 0)
793 {
794 return r;
795 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700796 }
797 sd_bus_message_close_container(m);
798 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700799 else if (argCode.starts_with("v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700800 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700801 std::string containedType = argCode.substr(1);
802 BMCWEB_LOG_DEBUG << "variant type: " << argCode
803 << " appending variant of type: " << containedType;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700804 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700805 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700806 if (r < 0)
807 {
808 return r;
809 }
810
Ed Tanous81ce6092020-12-17 16:54:55 +0000811 r = convertJsonToDbus(m, containedType, inputJson);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700812 if (r < 0)
813 {
814 return r;
815 }
816
817 r = sd_bus_message_close_container(m);
818 if (r < 0)
819 {
820 return r;
821 }
822 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700823 else if (argCode.starts_with("(") && argCode.ends_with(")"))
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 Tanous11ba3972022-07-11 09:50:41 -0700849 else if (argCode.starts_with("{") && argCode.ends_with("}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700850 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700851 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700852 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700853 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800854 if (r < 0)
855 {
856 return r;
857 }
858
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700859 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700860 if (codes.size() != 2)
861 {
862 return -1;
863 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700864 const std::string& keyType = codes[0];
865 const std::string& valueType = codes[1];
Ed Tanous3174e4d2020-10-07 11:41:22 -0700866 for (const auto& it : j->items())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700867 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700868 r = convertJsonToDbus(m, keyType, it.key());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700869 if (r < 0)
870 {
871 return r;
872 }
873
Ed Tanous2c70f802020-09-28 14:29:23 -0700874 r = convertJsonToDbus(m, valueType, it.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700875 if (r < 0)
876 {
877 return r;
878 }
879 }
880 r = sd_bus_message_close_container(m);
881 }
882 else
883 {
884 return -2;
885 }
886 if (r < 0)
887 {
888 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700889 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700890
Ed Tanous1abe55e2018-09-05 08:30:59 -0700891 if (argTypes.size() > 1)
892 {
893 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700894 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700895 }
Matt Spinler127ea542019-01-14 11:04:28 -0600896
897 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700898}
899
Matt Spinlerd22a7132019-01-14 12:14:30 -0600900template <typename T>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500901int readMessageItem(const std::string& typeCode, sdbusplus::message::message& m,
902 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600903{
904 T value;
905
906 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
907 if (r < 0)
908 {
909 BMCWEB_LOG_ERROR << "sd_bus_message_read_basic on type " << typeCode
910 << " failed!";
911 return r;
912 }
913
914 data = value;
915 return 0;
916}
917
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500918int convertDBusToJSON(const std::string& returnType,
919 sdbusplus::message::message& m, nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600920
Ed Tanous23a21a12020-07-25 04:45:05 +0000921inline int readDictEntryFromMessage(const std::string& typeCode,
922 sdbusplus::message::message& m,
923 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600924{
925 std::vector<std::string> types = dbusArgSplit(typeCode);
926 if (types.size() != 2)
927 {
928 BMCWEB_LOG_ERROR << "wrong number contained types in dictionary: "
929 << types.size();
930 return -1;
931 }
932
933 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
934 typeCode.c_str());
935 if (r < 0)
936 {
937 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container with rc " << r;
938 return r;
939 }
940
941 nlohmann::json key;
942 r = convertDBusToJSON(types[0], m, key);
943 if (r < 0)
944 {
945 return r;
946 }
947
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500948 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -0600949 if (keyPtr == nullptr)
950 {
951 // json doesn't support non-string keys. If we hit this condition,
952 // convert the result to a string so we can proceed
Ed Tanous71f52d92021-02-19 08:51:17 -0800953 key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500954 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -0700955 // in theory this can't fail now, but lets be paranoid about it
956 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -0600957 if (keyPtr == nullptr)
958 {
959 return -1;
960 }
961 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500962 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -0600963
964 r = convertDBusToJSON(types[1], m, value);
965 if (r < 0)
966 {
967 return r;
968 }
969
970 r = sd_bus_message_exit_container(m.get());
971 if (r < 0)
972 {
973 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
974 return r;
975 }
976
977 return 0;
978}
979
Ed Tanous23a21a12020-07-25 04:45:05 +0000980inline int readArrayFromMessage(const std::string& typeCode,
981 sdbusplus::message::message& m,
982 nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -0600983{
984 if (typeCode.size() < 2)
985 {
986 BMCWEB_LOG_ERROR << "Type code " << typeCode
987 << " too small for an array";
988 return -1;
989 }
990
991 std::string containedType = typeCode.substr(1);
992
993 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
994 containedType.c_str());
995 if (r < 0)
996 {
997 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
998 << r;
999 return r;
1000 }
1001
Ed Tanous11ba3972022-07-11 09:50:41 -07001002 bool dict = containedType.starts_with("{") && containedType.ends_with("}");
Matt Spinler6df8f992019-01-14 12:47:47 -06001003
1004 if (dict)
1005 {
1006 // Remove the { }
1007 containedType = containedType.substr(1, containedType.size() - 2);
1008 data = nlohmann::json::object();
1009 }
1010 else
1011 {
1012 data = nlohmann::json::array();
1013 }
1014
1015 while (true)
1016 {
Ed Tanouse662eae2022-01-25 10:39:19 -08001017 r = sd_bus_message_at_end(m.get(), 0);
Matt Spinler6df8f992019-01-14 12:47:47 -06001018 if (r < 0)
1019 {
1020 BMCWEB_LOG_ERROR << "sd_bus_message_at_end failed";
1021 return r;
1022 }
1023
1024 if (r > 0)
1025 {
1026 break;
1027 }
1028
1029 // Dictionaries are only ever seen in an array
1030 if (dict)
1031 {
1032 r = readDictEntryFromMessage(containedType, m, data);
1033 if (r < 0)
1034 {
1035 return r;
1036 }
1037 }
1038 else
1039 {
1040 data.push_back(nlohmann::json());
1041
1042 r = convertDBusToJSON(containedType, m, data.back());
1043 if (r < 0)
1044 {
1045 return r;
1046 }
1047 }
1048 }
1049
1050 r = sd_bus_message_exit_container(m.get());
1051 if (r < 0)
1052 {
1053 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1054 return r;
1055 }
1056
1057 return 0;
1058}
1059
Ed Tanous23a21a12020-07-25 04:45:05 +00001060inline int readStructFromMessage(const std::string& typeCode,
1061 sdbusplus::message::message& m,
1062 nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001063{
1064 if (typeCode.size() < 3)
1065 {
1066 BMCWEB_LOG_ERROR << "Type code " << typeCode
1067 << " too small for a struct";
1068 return -1;
1069 }
1070
1071 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1072 std::vector<std::string> types = dbusArgSplit(containedTypes);
1073
1074 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1075 containedTypes.c_str());
1076 if (r < 0)
1077 {
1078 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1079 << r;
1080 return r;
1081 }
1082
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001083 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001084 {
1085 data.push_back(nlohmann::json());
1086 r = convertDBusToJSON(type, m, data.back());
1087 if (r < 0)
1088 {
1089 return r;
1090 }
1091 }
1092
1093 r = sd_bus_message_exit_container(m.get());
1094 if (r < 0)
1095 {
1096 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1097 return r;
1098 }
1099 return 0;
1100}
1101
Ed Tanous23a21a12020-07-25 04:45:05 +00001102inline int readVariantFromMessage(sdbusplus::message::message& m,
1103 nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001104{
Ed Tanous543f4402022-01-06 13:12:53 -08001105 const char* containerType = nullptr;
Ed Tanous99131cd2019-10-24 11:12:47 -07001106 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001107 if (r < 0)
1108 {
1109 BMCWEB_LOG_ERROR << "sd_bus_message_peek_type failed";
1110 return r;
1111 }
1112
1113 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1114 containerType);
1115 if (r < 0)
1116 {
1117 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1118 << r;
1119 return r;
1120 }
1121
1122 r = convertDBusToJSON(containerType, m, data);
1123 if (r < 0)
1124 {
1125 return r;
1126 }
1127
1128 r = sd_bus_message_exit_container(m.get());
1129 if (r < 0)
1130 {
1131 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed";
1132 return r;
1133 }
1134
1135 return 0;
1136}
1137
Ed Tanous23a21a12020-07-25 04:45:05 +00001138inline int convertDBusToJSON(const std::string& returnType,
1139 sdbusplus::message::message& m,
1140 nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001141{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001142 int r = 0;
1143 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1144
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001145 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001146 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001147 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001148 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001149 {
1150 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001151 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001152 }
1153
Ed Tanousd4d25792020-09-29 15:15:03 -07001154 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001155 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001156 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001157 if (r < 0)
1158 {
1159 return r;
1160 }
1161 }
1162 else if (typeCode == "b")
1163 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001164 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001165 if (r < 0)
1166 {
1167 return r;
1168 }
1169
Matt Spinlerf39420c2019-01-30 12:57:18 -06001170 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001171 }
1172 else if (typeCode == "u")
1173 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001174 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001175 if (r < 0)
1176 {
1177 return r;
1178 }
1179 }
1180 else if (typeCode == "i")
1181 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001182 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001183 if (r < 0)
1184 {
1185 return r;
1186 }
1187 }
1188 else if (typeCode == "x")
1189 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001190 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001191 if (r < 0)
1192 {
1193 return r;
1194 }
1195 }
1196 else if (typeCode == "t")
1197 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001198 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001199 if (r < 0)
1200 {
1201 return r;
1202 }
1203 }
1204 else if (typeCode == "n")
1205 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001206 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001207 if (r < 0)
1208 {
1209 return r;
1210 }
1211 }
1212 else if (typeCode == "q")
1213 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001214 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001215 if (r < 0)
1216 {
1217 return r;
1218 }
1219 }
1220 else if (typeCode == "y")
1221 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001222 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001223 if (r < 0)
1224 {
1225 return r;
1226 }
1227 }
1228 else if (typeCode == "d")
1229 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001230 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001231 if (r < 0)
1232 {
1233 return r;
1234 }
1235 }
1236 else if (typeCode == "h")
1237 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001238 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001239 if (r < 0)
1240 {
1241 return r;
1242 }
1243 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001244 else if (typeCode.starts_with("a"))
Matt Spinler6df8f992019-01-14 12:47:47 -06001245 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001246 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001247 if (r < 0)
1248 {
1249 return r;
1250 }
1251 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001252 else if (typeCode.starts_with("(") && typeCode.ends_with(")"))
Matt Spinler75c6c672019-01-14 13:01:46 -06001253 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001254 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001255 if (r < 0)
1256 {
1257 return r;
1258 }
1259 }
Ed Tanous11ba3972022-07-11 09:50:41 -07001260 else if (typeCode.starts_with("v"))
Matt Spinler89c19702019-01-14 13:13:00 -06001261 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001262 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001263 if (r < 0)
1264 {
1265 return r;
1266 }
1267 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001268 else
1269 {
Matt Spinlerd22a7132019-01-14 12:14:30 -06001270 BMCWEB_LOG_ERROR << "Invalid D-Bus signature type " << typeCode;
1271 return -2;
1272 }
1273 }
1274
Matt Spinler16caaee2019-01-15 11:40:34 -06001275 return 0;
1276}
1277
Ed Tanousb5a76932020-09-29 16:16:58 -07001278inline void handleMethodResponse(
1279 const std::shared_ptr<InProgressActionData>& transaction,
1280 sdbusplus::message::message& m, const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001281{
Matt Spinler39a4e392019-01-15 11:53:13 -06001282 nlohmann::json data;
1283
1284 int r = convertDBusToJSON(returnType, m, data);
1285 if (r < 0)
1286 {
1287 transaction->outputFailed = true;
1288 return;
1289 }
1290
1291 if (data.is_null())
1292 {
1293 return;
1294 }
1295
1296 if (transaction->methodResponse.is_null())
1297 {
1298 transaction->methodResponse = std::move(data);
1299 return;
1300 }
1301
1302 // If they're both dictionaries or arrays, merge into one.
1303 // Otherwise, make the results an array with every result
1304 // an entry. Could also just fail in that case, but it
1305 // seems better to get the data back somehow.
1306
1307 if (transaction->methodResponse.is_object() && data.is_object())
1308 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001309 for (const auto& obj : data.items())
Matt Spinler39a4e392019-01-15 11:53:13 -06001310 {
1311 // Note: Will overwrite the data for a duplicate key
1312 transaction->methodResponse.emplace(obj.key(),
1313 std::move(obj.value()));
1314 }
1315 return;
1316 }
1317
1318 if (transaction->methodResponse.is_array() && data.is_array())
1319 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001320 for (auto& obj : data)
Matt Spinler39a4e392019-01-15 11:53:13 -06001321 {
1322 transaction->methodResponse.push_back(std::move(obj));
1323 }
1324 return;
1325 }
1326
1327 if (!transaction->convertedToArray)
1328 {
1329 // They are different types. May as well turn them into an array
1330 nlohmann::json j = std::move(transaction->methodResponse);
1331 transaction->methodResponse = nlohmann::json::array();
1332 transaction->methodResponse.push_back(std::move(j));
1333 transaction->methodResponse.push_back(std::move(data));
1334 transaction->convertedToArray = true;
1335 }
1336 else
1337 {
1338 transaction->methodResponse.push_back(std::move(data));
1339 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001340}
1341
Ed Tanousb5a76932020-09-29 16:16:58 -07001342inline void findActionOnInterface(
1343 const std::shared_ptr<InProgressActionData>& transaction,
1344 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001345{
1346 BMCWEB_LOG_DEBUG << "findActionOnInterface for connection "
1347 << connectionName;
1348 crow::connections::systemBus->async_method_call(
1349 [transaction, connectionName{std::string(connectionName)}](
1350 const boost::system::error_code ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001351 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001352 BMCWEB_LOG_DEBUG << "got xml:\n " << introspectXml;
1353 if (ec)
1354 {
1355 BMCWEB_LOG_ERROR
1356 << "Introspect call failed with error: " << ec.message()
1357 << " on process: " << connectionName << "\n";
1358 return;
1359 }
1360 tinyxml2::XMLDocument doc;
Matt Spinler318bd892019-01-15 09:59:20 -06001361
Ed Tanous002d39b2022-05-31 08:59:27 -07001362 doc.Parse(introspectXml.data(), introspectXml.size());
1363 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1364 if (pRoot == nullptr)
1365 {
1366 BMCWEB_LOG_ERROR << "XML document failed to parse "
1367 << connectionName << "\n";
1368 return;
1369 }
1370 tinyxml2::XMLElement* interfaceNode =
1371 pRoot->FirstChildElement("interface");
1372 while (interfaceNode != nullptr)
1373 {
1374 const char* thisInterfaceName = interfaceNode->Attribute("name");
1375 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001376 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001377 if (!transaction->interfaceName.empty() &&
1378 (transaction->interfaceName != thisInterfaceName))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001379 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001380 interfaceNode =
1381 interfaceNode->NextSiblingElement("interface");
1382 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001383 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001384
1385 tinyxml2::XMLElement* methodNode =
1386 interfaceNode->FirstChildElement("method");
1387 while (methodNode != nullptr)
1388 {
1389 const char* thisMethodName = methodNode->Attribute("name");
1390 BMCWEB_LOG_DEBUG << "Found method: " << thisMethodName;
1391 if (thisMethodName != nullptr &&
1392 thisMethodName == transaction->methodName)
1393 {
1394 BMCWEB_LOG_DEBUG << "Found method named "
1395 << thisMethodName << " on interface "
1396 << thisInterfaceName;
1397 sdbusplus::message::message m =
1398 crow::connections::systemBus->new_method_call(
1399 connectionName.c_str(),
1400 transaction->path.c_str(), thisInterfaceName,
1401 transaction->methodName.c_str());
1402
1403 tinyxml2::XMLElement* argumentNode =
1404 methodNode->FirstChildElement("arg");
1405
1406 std::string returnType;
1407
1408 // Find the output type
1409 while (argumentNode != nullptr)
1410 {
1411 const char* argDirection =
1412 argumentNode->Attribute("direction");
1413 const char* argType =
1414 argumentNode->Attribute("type");
1415 if (argDirection != nullptr && argType != nullptr &&
1416 std::string(argDirection) == "out")
1417 {
1418 returnType = argType;
1419 break;
1420 }
1421 argumentNode =
1422 argumentNode->NextSiblingElement("arg");
1423 }
1424
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001425 auto argIt = transaction->arguments.begin();
Ed Tanous002d39b2022-05-31 08:59:27 -07001426
1427 argumentNode = methodNode->FirstChildElement("arg");
1428
1429 while (argumentNode != nullptr)
1430 {
1431 const char* argDirection =
1432 argumentNode->Attribute("direction");
1433 const char* argType =
1434 argumentNode->Attribute("type");
1435 if (argDirection != nullptr && argType != nullptr &&
1436 std::string(argDirection) == "in")
1437 {
1438 if (argIt == transaction->arguments.end())
1439 {
1440 transaction->setErrorStatus(
1441 "Invalid method args");
1442 return;
1443 }
1444 if (convertJsonToDbus(m.get(),
1445 std::string(argType),
1446 *argIt) < 0)
1447 {
1448 transaction->setErrorStatus(
1449 "Invalid method arg type");
1450 return;
1451 }
1452
1453 argIt++;
1454 }
1455 argumentNode =
1456 argumentNode->NextSiblingElement("arg");
1457 }
1458
1459 crow::connections::systemBus->async_send(
1460 m,
1461 [transaction,
1462 returnType](boost::system::error_code ec2,
1463 sdbusplus::message::message& m2) {
1464 if (ec2)
1465 {
1466 transaction->methodFailed = true;
1467 const sd_bus_error* e = m2.get_error();
1468
1469 if (e != nullptr)
1470 {
1471 setErrorResponse(
1472 transaction->res,
1473 boost::beast::http::status::bad_request,
1474 e->name, e->message);
1475 }
1476 else
1477 {
1478 setErrorResponse(
1479 transaction->res,
1480 boost::beast::http::status::bad_request,
1481 "Method call failed", methodFailedMsg);
1482 }
1483 return;
1484 }
1485 transaction->methodPassed = true;
1486
1487 handleMethodResponse(transaction, m2, returnType);
1488 });
1489 break;
1490 }
1491 methodNode = methodNode->NextSiblingElement("method");
1492 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001493 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001494 interfaceNode = interfaceNode->NextSiblingElement("interface");
1495 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001496 },
1497 connectionName, transaction->path,
1498 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001499}
1500
zhanghch058d1b46d2021-04-01 11:18:24 +08001501inline void handleAction(const crow::Request& req,
1502 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001503 const std::string& objectPath,
1504 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001505{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001506 BMCWEB_LOG_DEBUG << "handleAction on path: " << objectPath << " and method "
1507 << methodName;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001508 nlohmann::json requestDbusData =
1509 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001510
Ed Tanous1abe55e2018-09-05 08:30:59 -07001511 if (requestDbusData.is_discarded())
1512 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001513 setErrorResponse(asyncResp->res,
1514 boost::beast::http::status::bad_request, noJsonDesc,
1515 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001516 return;
1517 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001518 nlohmann::json::iterator data = requestDbusData.find("data");
1519 if (data == requestDbusData.end())
1520 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001521 setErrorResponse(asyncResp->res,
1522 boost::beast::http::status::bad_request, noJsonDesc,
1523 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001524 return;
1525 }
1526
1527 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001528 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001529 setErrorResponse(asyncResp->res,
1530 boost::beast::http::status::bad_request, noJsonDesc,
1531 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001532 return;
1533 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001534 auto transaction = std::make_shared<InProgressActionData>(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001535
1536 transaction->path = objectPath;
1537 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001538 transaction->arguments = std::move(*data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001539 crow::connections::systemBus->async_method_call(
1540 [transaction](
1541 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001542 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1543 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001544 if (ec || interfaceNames.empty())
1545 {
1546 BMCWEB_LOG_ERROR << "Can't find object";
1547 setErrorResponse(transaction->res,
1548 boost::beast::http::status::not_found,
1549 notFoundDesc, notFoundMsg);
1550 return;
1551 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001552
Ed Tanous002d39b2022-05-31 08:59:27 -07001553 BMCWEB_LOG_DEBUG << "GetObject returned " << interfaceNames.size()
1554 << " object(s)";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001555
Ed Tanous002d39b2022-05-31 08:59:27 -07001556 for (const std::pair<std::string, std::vector<std::string>>& object :
1557 interfaceNames)
1558 {
1559 findActionOnInterface(transaction, object.first);
1560 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001561 },
1562 "xyz.openbmc_project.ObjectMapper",
1563 "/xyz/openbmc_project/object_mapper",
1564 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
1565 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001566}
1567
zhanghch058d1b46d2021-04-01 11:18:24 +08001568inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1569 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001570{
1571 BMCWEB_LOG_DEBUG << "handleDelete on path: " << objectPath;
1572
1573 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +08001574 [asyncResp, objectPath](
Matt Spinlerde818812018-12-11 16:39:20 -06001575 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001576 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1577 interfaceNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001578 if (ec || interfaceNames.empty())
1579 {
1580 BMCWEB_LOG_ERROR << "Can't find object";
1581 setErrorResponse(asyncResp->res,
1582 boost::beast::http::status::method_not_allowed,
1583 methodNotAllowedDesc, methodNotAllowedMsg);
1584 return;
1585 }
Matt Spinlerde818812018-12-11 16:39:20 -06001586
Ed Tanous002d39b2022-05-31 08:59:27 -07001587 auto transaction =
1588 std::make_shared<InProgressActionData>(asyncResp->res);
1589 transaction->path = objectPath;
1590 transaction->methodName = "Delete";
1591 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
Matt Spinlerde818812018-12-11 16:39:20 -06001592
Ed Tanous002d39b2022-05-31 08:59:27 -07001593 for (const std::pair<std::string, std::vector<std::string>>& object :
1594 interfaceNames)
1595 {
1596 findActionOnInterface(transaction, object.first);
1597 }
Matt Spinlerde818812018-12-11 16:39:20 -06001598 },
1599 "xyz.openbmc_project.ObjectMapper",
1600 "/xyz/openbmc_project/object_mapper",
1601 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001602 std::array<const char*, 0>());
Matt Spinlerde818812018-12-11 16:39:20 -06001603}
1604
zhanghch058d1b46d2021-04-01 11:18:24 +08001605inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1606 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001607{
1608 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001609 [asyncResp](
1610 const boost::system::error_code ec,
1611 const dbus::utility::MapperGetSubTreePathsResponse& objectPaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001612 if (ec)
1613 {
1614 setErrorResponse(asyncResp->res,
1615 boost::beast::http::status::not_found,
1616 notFoundDesc, notFoundMsg);
1617 }
1618 else
1619 {
1620 asyncResp->res.jsonValue["status"] = "ok";
1621 asyncResp->res.jsonValue["message"] = "200 OK";
1622 asyncResp->res.jsonValue["data"] = objectPaths;
1623 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001624 },
1625 "xyz.openbmc_project.ObjectMapper",
1626 "/xyz/openbmc_project/object_mapper",
1627 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", objectPath,
Ed Tanousf839dfe2018-11-12 11:11:15 -08001628 depth, std::array<std::string, 0>());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001629}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001630
zhanghch058d1b46d2021-04-01 11:18:24 +08001631inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1632 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001633{
Ed Tanous049a0512018-11-01 13:58:42 -07001634 BMCWEB_LOG_DEBUG << "Doing enumerate on " << objectPath;
Ed Tanous049a0512018-11-01 13:58:42 -07001635
Ed Tanous14766872022-03-15 10:44:42 -07001636 asyncResp->res.jsonValue["message"] = "200 OK";
1637 asyncResp->res.jsonValue["status"] = "ok";
1638 asyncResp->res.jsonValue["data"] = nlohmann::json::object();
Ed Tanous049a0512018-11-01 13:58:42 -07001639
Ed Tanous1abe55e2018-09-05 08:30:59 -07001640 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001641 [objectPath, asyncResp](
1642 const boost::system::error_code ec,
1643 const dbus::utility::MapperGetSubTreeResponse& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001644 auto transaction =
1645 std::make_shared<InProgressEnumerateData>(objectPath, asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001646
Ed Tanous002d39b2022-05-31 08:59:27 -07001647 transaction->subtree =
1648 std::make_shared<dbus::utility::MapperGetSubTreeResponse>(
1649 objectNames);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001650
Ed Tanous002d39b2022-05-31 08:59:27 -07001651 if (ec)
1652 {
1653 BMCWEB_LOG_ERROR << "GetSubTree failed on "
1654 << transaction->objectPath;
1655 setErrorResponse(transaction->asyncResp->res,
1656 boost::beast::http::status::not_found,
1657 notFoundDesc, notFoundMsg);
1658 return;
1659 }
Ed Tanous64530012018-02-06 17:08:16 -08001660
Ed Tanous002d39b2022-05-31 08:59:27 -07001661 // Add the data for the path passed in to the results
1662 // as if GetSubTree returned it, and continue on enumerating
1663 getObjectAndEnumerate(transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001664 },
1665 "xyz.openbmc_project.ObjectMapper",
1666 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -07001667 "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath, 0,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001668 std::array<const char*, 0>());
Ed Tanous64530012018-02-06 17:08:16 -08001669}
Ed Tanous911ac312017-08-15 09:37:42 -07001670
zhanghch058d1b46d2021-04-01 11:18:24 +08001671inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1672 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001673{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001674 BMCWEB_LOG_DEBUG << "handleGet: " << objectPath << " prop:" << destProperty;
1675 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001676 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001677
Ed Tanous1abe55e2018-09-05 08:30:59 -07001678 std::shared_ptr<std::string> path =
1679 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001680
Ed Tanous1abe55e2018-09-05 08:30:59 -07001681 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001682 [asyncResp, path,
1683 propertyName](const boost::system::error_code ec,
1684 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001685 if (ec || objectNames.empty())
1686 {
1687 setErrorResponse(asyncResp->res,
1688 boost::beast::http::status::not_found,
1689 notFoundDesc, notFoundMsg);
1690 return;
1691 }
1692 std::shared_ptr<nlohmann::json> response =
1693 std::make_shared<nlohmann::json>(nlohmann::json::object());
1694 // The mapper should never give us an empty interface names
1695 // list, but check anyway
1696 for (const std::pair<std::string, std::vector<std::string>>&
1697 connection : objectNames)
1698 {
1699 const std::vector<std::string>& interfaceNames = connection.second;
1700
1701 if (interfaceNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001702 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001703 setErrorResponse(asyncResp->res,
1704 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001705 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001706 return;
1707 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001708
1709 for (const std::string& interface : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001710 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001711 sdbusplus::message::message m =
1712 crow::connections::systemBus->new_method_call(
1713 connection.first.c_str(), path->c_str(),
1714 "org.freedesktop.DBus.Properties", "GetAll");
1715 m.append(interface);
1716 crow::connections::systemBus->async_send(
1717 m, [asyncResp, response,
1718 propertyName](const boost::system::error_code ec2,
1719 sdbusplus::message::message& msg) {
1720 if (ec2)
1721 {
1722 BMCWEB_LOG_ERROR << "Bad dbus request error: "
1723 << ec2;
1724 }
1725 else
1726 {
1727 nlohmann::json properties;
1728 int r = convertDBusToJSON("a{sv}", msg, properties);
1729 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001730 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001731 BMCWEB_LOG_ERROR << "convertDBusToJSON failed";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001732 }
1733 else
1734 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001735 for (auto& prop : properties.items())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001736 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001737 // if property name is empty, or
1738 // matches our search query, add it
1739 // to the response json
Ed Tanous1abe55e2018-09-05 08:30:59 -07001740
Ed Tanous002d39b2022-05-31 08:59:27 -07001741 if (propertyName->empty())
1742 {
1743 (*response)[prop.key()] =
1744 std::move(prop.value());
1745 }
1746 else if (prop.key() == *propertyName)
1747 {
1748 *response = std::move(prop.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001749 }
1750 }
1751 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001752 }
1753 if (response.use_count() == 1)
1754 {
1755 if (!propertyName->empty() && response->empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001756 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001757 setErrorResponse(
1758 asyncResp->res,
1759 boost::beast::http::status::not_found,
1760 propNotFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001761 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001762 else
1763 {
1764 asyncResp->res.jsonValue["status"] = "ok";
1765 asyncResp->res.jsonValue["message"] = "200 OK";
1766 asyncResp->res.jsonValue["data"] = *response;
1767 }
1768 }
1769 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001770 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001771 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001772 },
1773 "xyz.openbmc_project.ObjectMapper",
1774 "/xyz/openbmc_project/object_mapper",
1775 "xyz.openbmc_project.ObjectMapper", "GetObject", *path,
1776 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001777}
1778
Ed Tanous1abe55e2018-09-05 08:30:59 -07001779struct AsyncPutRequest
1780{
Ed Tanous4e23a442022-06-06 09:57:26 -07001781 explicit AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
zhanghch058d1b46d2021-04-01 11:18:24 +08001782 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001783 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001784 ~AsyncPutRequest()
1785 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001786 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001787 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001788 setErrorResponse(asyncResp->res,
1789 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001790 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001791 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001792 }
1793
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001794 AsyncPutRequest(const AsyncPutRequest&) = delete;
1795 AsyncPutRequest(AsyncPutRequest&&) = delete;
1796 AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1797 AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1798
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001799 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001800 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001801 setErrorResponse(asyncResp->res,
1802 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001803 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001804 }
1805
zhanghch058d1b46d2021-04-01 11:18:24 +08001806 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001807 std::string objectPath;
1808 std::string propertyName;
1809 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001810};
1811
zhanghch058d1b46d2021-04-01 11:18:24 +08001812inline void handlePut(const crow::Request& req,
1813 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001814 const std::string& objectPath,
1815 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001816{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001817 if (destProperty.empty())
1818 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001819 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001820 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001821 return;
1822 }
1823
Ed Tanous1abe55e2018-09-05 08:30:59 -07001824 nlohmann::json requestDbusData =
1825 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001826
Ed Tanous1abe55e2018-09-05 08:30:59 -07001827 if (requestDbusData.is_discarded())
1828 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001829 setErrorResponse(asyncResp->res,
1830 boost::beast::http::status::bad_request, noJsonDesc,
1831 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001832 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001833 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001834
Nan Zhoub2ec0ce2022-06-02 23:57:38 +00001835 auto propertyIt = requestDbusData.find("data");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001836 if (propertyIt == requestDbusData.end())
1837 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001838 setErrorResponse(asyncResp->res,
1839 boost::beast::http::status::bad_request, noJsonDesc,
1840 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001841 return;
1842 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001843 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001844 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001845 transaction->objectPath = objectPath;
1846 transaction->propertyName = destProperty;
1847 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001848
Ed Tanous1abe55e2018-09-05 08:30:59 -07001849 crow::connections::systemBus->async_method_call(
Ed Tanous23a21a12020-07-25 04:45:05 +00001850 [transaction](const boost::system::error_code ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001851 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001852 if (!ec2 && objectNames.empty())
1853 {
1854 setErrorResponse(transaction->asyncResp->res,
1855 boost::beast::http::status::not_found,
1856 propNotFoundDesc, notFoundMsg);
1857 return;
1858 }
Ed Tanous911ac312017-08-15 09:37:42 -07001859
Ed Tanous002d39b2022-05-31 08:59:27 -07001860 for (const std::pair<std::string, std::vector<std::string>>&
1861 connection : objectNames)
1862 {
1863 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001864
Ed Tanous002d39b2022-05-31 08:59:27 -07001865 crow::connections::systemBus->async_method_call(
1866 [connectionName{std::string(connectionName)},
1867 transaction](const boost::system::error_code ec3,
1868 const std::string& introspectXml) {
1869 if (ec3)
1870 {
1871 BMCWEB_LOG_ERROR << "Introspect call failed with error: "
1872 << ec3.message()
1873 << " on process: " << connectionName;
1874 transaction->setErrorStatus("Unexpected Error");
1875 return;
1876 }
1877 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001878
Ed Tanous002d39b2022-05-31 08:59:27 -07001879 doc.Parse(introspectXml.c_str());
1880 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1881 if (pRoot == nullptr)
1882 {
1883 BMCWEB_LOG_ERROR << "XML document failed to parse: "
1884 << introspectXml;
1885 transaction->setErrorStatus("Unexpected Error");
1886 return;
1887 }
1888 tinyxml2::XMLElement* ifaceNode =
1889 pRoot->FirstChildElement("interface");
1890 while (ifaceNode != nullptr)
1891 {
1892 const char* interfaceName = ifaceNode->Attribute("name");
1893 BMCWEB_LOG_DEBUG << "found interface " << interfaceName;
1894 tinyxml2::XMLElement* propNode =
1895 ifaceNode->FirstChildElement("property");
1896 while (propNode != nullptr)
1897 {
1898 const char* propertyName = propNode->Attribute("name");
1899 BMCWEB_LOG_DEBUG << "Found property " << propertyName;
1900 if (propertyName == transaction->propertyName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001901 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001902 const char* argType = propNode->Attribute("type");
1903 if (argType != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001904 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001905 sdbusplus::message::message m =
1906 crow::connections::systemBus
1907 ->new_method_call(
1908 connectionName.c_str(),
1909 transaction->objectPath.c_str(),
1910 "org.freedesktop.DBus."
1911 "Properties",
1912 "Set");
1913 m.append(interfaceName,
1914 transaction->propertyName);
1915 int r = sd_bus_message_open_container(
1916 m.get(), SD_BUS_TYPE_VARIANT, argType);
1917 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001918 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001919 transaction->setErrorStatus(
1920 "Unexpected Error");
1921 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001922 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001923 r = convertJsonToDbus(
1924 m.get(), argType,
1925 transaction->propertyValue);
1926 if (r < 0)
1927 {
1928 if (r == -ERANGE)
1929 {
1930 transaction->setErrorStatus(
1931 "Provided property value "
1932 "is out of range for the "
1933 "property type");
1934 }
1935 else
1936 {
1937 transaction->setErrorStatus(
1938 "Invalid arg type");
1939 }
1940 return;
1941 }
1942 r = sd_bus_message_close_container(m.get());
1943 if (r < 0)
1944 {
1945 transaction->setErrorStatus(
1946 "Unexpected Error");
1947 return;
1948 }
1949 crow::connections::systemBus->async_send(
1950 m,
1951 [transaction](
1952 boost::system::error_code ec,
1953 sdbusplus::message::message& m2) {
1954 BMCWEB_LOG_DEBUG << "sent";
1955 if (ec)
1956 {
1957 const sd_bus_error* e = m2.get_error();
1958 setErrorResponse(
1959 transaction->asyncResp->res,
1960 boost::beast::http::status::
1961 forbidden,
1962 (e) != nullptr
1963 ? e->name
1964 : ec.category().name(),
1965 (e) != nullptr ? e->message
1966 : ec.message());
1967 }
1968 else
1969 {
1970 transaction->asyncResp->res
1971 .jsonValue["status"] = "ok";
1972 transaction->asyncResp->res
1973 .jsonValue["message"] = "200 OK";
1974 transaction->asyncResp->res
1975 .jsonValue["data"] = nullptr;
1976 }
1977 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001978 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001979 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001980 propNode = propNode->NextSiblingElement("property");
1981 }
1982 ifaceNode = ifaceNode->NextSiblingElement("interface");
1983 }
1984 },
1985 connectionName, transaction->objectPath,
1986 "org.freedesktop.DBus.Introspectable", "Introspect");
1987 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001988 },
1989 "xyz.openbmc_project.ObjectMapper",
1990 "/xyz/openbmc_project/object_mapper",
1991 "xyz.openbmc_project.ObjectMapper", "GetObject",
1992 transaction->objectPath, std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001993}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001994
zhanghch058d1b46d2021-04-01 11:18:24 +08001995inline void handleDBusUrl(const crow::Request& req,
1996 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001997 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07001998{
Ed Tanous049a0512018-11-01 13:58:42 -07001999
2000 // If accessing a single attribute, fill in and update objectPath,
2001 // otherwise leave destProperty blank
Ed Tanouse05aec52022-01-25 10:28:56 -08002002 std::string destProperty;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002003 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002004 size_t attrPosition = objectPath.find(attrSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002005 if (attrPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002006 {
2007 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2008 objectPath.length());
2009 objectPath = objectPath.substr(0, attrPosition);
2010 }
2011
Ed Tanousb41187f2019-10-24 16:30:02 -07002012 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002013 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002014 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002015 size_t actionPosition = objectPath.find(actionSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002016 if (actionPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002017 {
2018 std::string postProperty =
2019 objectPath.substr((actionPosition + strlen(actionSeperator)),
2020 objectPath.length());
2021 objectPath = objectPath.substr(0, actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002022 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002023 return;
2024 }
2025 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002026 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002027 {
Ed Tanous11ba3972022-07-11 09:50:41 -07002028 if (objectPath.ends_with("/enumerate"))
Ed Tanous049a0512018-11-01 13:58:42 -07002029 {
2030 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2031 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002032 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002033 }
Ed Tanous11ba3972022-07-11 09:50:41 -07002034 else if (objectPath.ends_with("/list"))
Ed Tanous049a0512018-11-01 13:58:42 -07002035 {
2036 objectPath.erase(objectPath.end() - sizeof("list"),
2037 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002038 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002039 }
2040 else
2041 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002042 // Trim any trailing "/" at the end
Ed Tanous11ba3972022-07-11 09:50:41 -07002043 if (objectPath.ends_with("/"))
Ed Tanousf839dfe2018-11-12 11:11:15 -08002044 {
2045 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002046 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002047 }
2048 else
2049 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002050 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002051 }
Ed Tanous049a0512018-11-01 13:58:42 -07002052 }
2053 return;
2054 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002055 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002056 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002057 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002058 return;
2059 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002060 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002061 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002062 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002063 return;
2064 }
Ed Tanous049a0512018-11-01 13:58:42 -07002065
zhanghch058d1b46d2021-04-01 11:18:24 +08002066 setErrorResponse(asyncResp->res,
2067 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002068 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002069}
2070
Ed Tanous1656b292022-05-04 11:33:42 -07002071inline void
2072 handleBusSystemPost(const crow::Request& req,
2073 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2074 const std::string& processName,
2075 const std::string& requestedPath)
2076{
2077 std::vector<std::string> strs;
2078 boost::split(strs, requestedPath, boost::is_any_of("/"));
2079 std::string objectPath;
2080 std::string interfaceName;
2081 std::string methodName;
2082 auto it = strs.begin();
2083 if (it == strs.end())
2084 {
2085 objectPath = "/";
2086 }
2087 while (it != strs.end())
2088 {
2089 // Check if segment contains ".". If it does, it must be an
2090 // interface
2091 if (it->find(".") != std::string::npos)
2092 {
2093 break;
2094 // This check is necessary as the trailing slash gets
2095 // parsed as part of our <path> specifier above, which
2096 // causes the normal trailing backslash redirector to
2097 // fail.
2098 }
2099 if (!it->empty())
2100 {
2101 objectPath += "/" + *it;
2102 }
2103 it++;
2104 }
2105 if (it != strs.end())
2106 {
2107 interfaceName = *it;
2108 it++;
2109
2110 // after interface, we might have a method name
2111 if (it != strs.end())
2112 {
2113 methodName = *it;
2114 it++;
2115 }
2116 }
2117 if (it != strs.end())
2118 {
2119 // if there is more levels past the method name, something
2120 // went wrong, return not found
2121 asyncResp->res.result(boost::beast::http::status::not_found);
2122 return;
2123 }
2124 if (interfaceName.empty())
2125 {
2126 crow::connections::systemBus->async_method_call(
2127 [asyncResp, processName,
2128 objectPath](const boost::system::error_code ec,
2129 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002130 if (ec)
2131 {
2132 BMCWEB_LOG_ERROR
2133 << "Introspect call failed with error: " << ec.message()
2134 << " on process: " << processName << " path: " << objectPath
2135 << "\n";
2136 return;
2137 }
2138 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002139
Ed Tanous002d39b2022-05-31 08:59:27 -07002140 doc.Parse(introspectXml.c_str());
2141 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2142 if (pRoot == nullptr)
2143 {
2144 BMCWEB_LOG_ERROR << "XML document failed to parse "
2145 << processName << " " << objectPath << "\n";
2146 asyncResp->res.jsonValue["status"] = "XML parse error";
2147 asyncResp->res.result(
2148 boost::beast::http::status::internal_server_error);
2149 return;
2150 }
2151
2152 BMCWEB_LOG_DEBUG << introspectXml;
2153 asyncResp->res.jsonValue["status"] = "ok";
2154 asyncResp->res.jsonValue["bus_name"] = processName;
2155 asyncResp->res.jsonValue["object_path"] = objectPath;
2156
2157 nlohmann::json& interfacesArray =
2158 asyncResp->res.jsonValue["interfaces"];
2159 interfacesArray = nlohmann::json::array();
2160 tinyxml2::XMLElement* interface =
2161 pRoot->FirstChildElement("interface");
2162
2163 while (interface != nullptr)
2164 {
2165 const char* ifaceName = interface->Attribute("name");
2166 if (ifaceName != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002167 {
Ed Tanous8a592812022-06-04 09:06:59 -07002168 nlohmann::json::object_t interfaceObj;
2169 interfaceObj["name"] = ifaceName;
2170 interfacesArray.push_back(std::move(interfaceObj));
Ed Tanous1656b292022-05-04 11:33:42 -07002171 }
2172
Ed Tanous002d39b2022-05-31 08:59:27 -07002173 interface = interface->NextSiblingElement("interface");
2174 }
Ed Tanous1656b292022-05-04 11:33:42 -07002175 },
2176 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2177 "Introspect");
2178 }
2179 else if (methodName.empty())
2180 {
2181 crow::connections::systemBus->async_method_call(
2182 [asyncResp, processName, objectPath,
2183 interfaceName](const boost::system::error_code ec,
2184 const std::string& introspectXml) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002185 if (ec)
2186 {
2187 BMCWEB_LOG_ERROR
2188 << "Introspect call failed with error: " << ec.message()
2189 << " on process: " << processName << " path: " << objectPath
2190 << "\n";
2191 return;
2192 }
2193 tinyxml2::XMLDocument doc;
Ed Tanous1656b292022-05-04 11:33:42 -07002194
Ed Tanous002d39b2022-05-31 08:59:27 -07002195 doc.Parse(introspectXml.data(), introspectXml.size());
2196 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
2197 if (pRoot == nullptr)
2198 {
2199 BMCWEB_LOG_ERROR << "XML document failed to parse "
2200 << processName << " " << objectPath << "\n";
2201 asyncResp->res.result(
2202 boost::beast::http::status::internal_server_error);
2203 return;
2204 }
2205
2206 asyncResp->res.jsonValue["status"] = "ok";
2207 asyncResp->res.jsonValue["bus_name"] = processName;
2208 asyncResp->res.jsonValue["interface"] = interfaceName;
2209 asyncResp->res.jsonValue["object_path"] = objectPath;
2210
2211 nlohmann::json& methodsArray = asyncResp->res.jsonValue["methods"];
2212 methodsArray = nlohmann::json::array();
2213
2214 nlohmann::json& signalsArray = asyncResp->res.jsonValue["signals"];
2215 signalsArray = nlohmann::json::array();
2216
2217 nlohmann::json& propertiesObj =
2218 asyncResp->res.jsonValue["properties"];
2219 propertiesObj = nlohmann::json::object();
2220
2221 // if we know we're the only call, build the
2222 // json directly
2223 tinyxml2::XMLElement* interface =
2224 pRoot->FirstChildElement("interface");
2225 while (interface != nullptr)
2226 {
2227 const char* ifaceName = interface->Attribute("name");
2228
2229 if (ifaceName != nullptr && ifaceName == interfaceName)
Ed Tanous1656b292022-05-04 11:33:42 -07002230 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002231 break;
Ed Tanous1656b292022-05-04 11:33:42 -07002232 }
Ed Tanous14766872022-03-15 10:44:42 -07002233
Ed Tanous002d39b2022-05-31 08:59:27 -07002234 interface = interface->NextSiblingElement("interface");
2235 }
2236 if (interface == nullptr)
2237 {
2238 // if we got to the end of the list and
2239 // never found a match, throw 404
2240 asyncResp->res.result(boost::beast::http::status::not_found);
2241 return;
2242 }
Ed Tanous1656b292022-05-04 11:33:42 -07002243
Ed Tanous002d39b2022-05-31 08:59:27 -07002244 tinyxml2::XMLElement* methods =
2245 interface->FirstChildElement("method");
2246 while (methods != nullptr)
2247 {
2248 nlohmann::json argsArray = nlohmann::json::array();
2249 tinyxml2::XMLElement* arg = methods->FirstChildElement("arg");
2250 while (arg != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002251 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002252 nlohmann::json thisArg;
2253 for (const char* fieldName : std::array<const char*, 3>{
2254 "name", "direction", "type"})
Ed Tanous1656b292022-05-04 11:33:42 -07002255 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002256 const char* fieldValue = arg->Attribute(fieldName);
2257 if (fieldValue != nullptr)
Ed Tanous1656b292022-05-04 11:33:42 -07002258 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002259 thisArg[fieldName] = fieldValue;
2260 }
2261 }
2262 argsArray.push_back(std::move(thisArg));
2263 arg = arg->NextSiblingElement("arg");
2264 }
2265
2266 const char* name = methods->Attribute("name");
2267 if (name != nullptr)
2268 {
2269 std::string uri;
2270 uri.reserve(14 + processName.size() + objectPath.size() +
2271 interfaceName.size() + strlen(name));
2272 uri += "/bus/system/";
2273 uri += processName;
2274 uri += objectPath;
2275 uri += "/";
2276 uri += interfaceName;
2277 uri += "/";
2278 uri += name;
2279
2280 nlohmann::json::object_t object;
2281 object["name"] = name;
2282 object["uri"] = std::move(uri);
2283 object["args"] = argsArray;
2284
2285 methodsArray.push_back(std::move(object));
2286 }
2287 methods = methods->NextSiblingElement("method");
2288 }
2289 tinyxml2::XMLElement* signals =
2290 interface->FirstChildElement("signal");
2291 while (signals != nullptr)
2292 {
2293 nlohmann::json argsArray = nlohmann::json::array();
2294
2295 tinyxml2::XMLElement* arg = signals->FirstChildElement("arg");
2296 while (arg != nullptr)
2297 {
2298 const char* name = arg->Attribute("name");
2299 const char* type = arg->Attribute("type");
2300 if (name != nullptr && type != nullptr)
2301 {
2302 argsArray.push_back({
2303 {"name", name},
2304 {"type", type},
2305 });
2306 }
2307 arg = arg->NextSiblingElement("arg");
2308 }
2309 const char* name = signals->Attribute("name");
2310 if (name != nullptr)
2311 {
2312 nlohmann::json::object_t object;
2313 object["name"] = name;
2314 object["args"] = argsArray;
2315 signalsArray.push_back(std::move(object));
2316 }
2317
2318 signals = signals->NextSiblingElement("signal");
2319 }
2320
2321 tinyxml2::XMLElement* property =
2322 interface->FirstChildElement("property");
2323 while (property != nullptr)
2324 {
2325 const char* name = property->Attribute("name");
2326 const char* type = property->Attribute("type");
2327 if (type != nullptr && name != nullptr)
2328 {
2329 sdbusplus::message::message m =
2330 crow::connections::systemBus->new_method_call(
2331 processName.c_str(), objectPath.c_str(),
2332 "org.freedesktop."
2333 "DBus."
2334 "Properties",
2335 "Get");
2336 m.append(interfaceName, name);
2337 nlohmann::json& propertyItem = propertiesObj[name];
2338 crow::connections::systemBus->async_send(
2339 m, [&propertyItem,
Ed Tanous02cad962022-06-30 16:50:15 -07002340 asyncResp](const boost::system::error_code& e,
Ed Tanous002d39b2022-05-31 08:59:27 -07002341 sdbusplus::message::message& msg) {
2342 if (e)
Ed Tanous1656b292022-05-04 11:33:42 -07002343 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002344 return;
Ed Tanous1656b292022-05-04 11:33:42 -07002345 }
Ed Tanous1656b292022-05-04 11:33:42 -07002346
Ed Tanous002d39b2022-05-31 08:59:27 -07002347 convertDBusToJSON("v", msg, propertyItem);
2348 });
Ed Tanous1656b292022-05-04 11:33:42 -07002349 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002350 property = property->NextSiblingElement("property");
2351 }
Ed Tanous1656b292022-05-04 11:33:42 -07002352 },
2353 processName, objectPath, "org.freedesktop.DBus.Introspectable",
2354 "Introspect");
2355 }
2356 else
2357 {
2358 if (req.method() != boost::beast::http::verb::post)
2359 {
2360 asyncResp->res.result(boost::beast::http::status::not_found);
2361 return;
2362 }
2363
2364 nlohmann::json requestDbusData =
2365 nlohmann::json::parse(req.body, nullptr, false);
2366
2367 if (requestDbusData.is_discarded())
2368 {
2369 asyncResp->res.result(boost::beast::http::status::bad_request);
2370 return;
2371 }
2372 if (!requestDbusData.is_array())
2373 {
2374 asyncResp->res.result(boost::beast::http::status::bad_request);
2375 return;
2376 }
2377 auto transaction =
2378 std::make_shared<InProgressActionData>(asyncResp->res);
2379
2380 transaction->path = objectPath;
2381 transaction->methodName = methodName;
2382 transaction->arguments = std::move(requestDbusData);
2383
2384 findActionOnInterface(transaction, processName);
2385 }
2386}
2387
Ed Tanous23a21a12020-07-25 04:45:05 +00002388inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002389{
2390 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002391 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002392 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002393 [](const crow::Request&,
2394 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002395 nlohmann::json::array_t buses;
2396 nlohmann::json& bus = buses.emplace_back();
2397 bus["name"] = "system";
2398 asyncResp->res.jsonValue["busses"] = std::move(buses);
2399 asyncResp->res.jsonValue["status"] = "ok";
2400 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002401
2402 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002403 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002404 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002405 [](const crow::Request&,
2406 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002407 auto myCallback = [asyncResp](const boost::system::error_code ec,
zhanghch058d1b46d2021-04-01 11:18:24 +08002408 std::vector<std::string>& names) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002409 if (ec)
2410 {
2411 BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
2412 asyncResp->res.result(
2413 boost::beast::http::status::internal_server_error);
2414 }
2415 else
2416 {
2417 std::sort(names.begin(), names.end());
2418 asyncResp->res.jsonValue["status"] = "ok";
2419 auto& objectsSub = asyncResp->res.jsonValue["objects"];
Ed Tanous02cad962022-06-30 16:50:15 -07002420 for (const auto& name : names)
Ed Tanous002d39b2022-05-31 08:59:27 -07002421 {
2422 nlohmann::json::object_t object;
2423 object["name"] = name;
2424 objectsSub.push_back(std::move(object));
2425 }
2426 }
2427 };
2428 crow::connections::systemBus->async_method_call(
2429 std::move(myCallback), "org.freedesktop.DBus", "/",
2430 "org.freedesktop.DBus", "ListNames");
2431 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002432
2433 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002434 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002435 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002436 [](const crow::Request&,
2437 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002438 handleList(asyncResp, "/");
2439 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002440
2441 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002442 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002443 .methods(boost::beast::http::verb::get)(
2444 [](const crow::Request& req,
2445 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002446 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002447 std::string objectPath = "/xyz/" + path;
2448 handleDBusUrl(req, asyncResp, objectPath);
2449 });
zhanghch058d1b46d2021-04-01 11:18:24 +08002450
2451 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002452 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002453 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2454 boost::beast::http::verb::delete_)(
2455 [](const crow::Request& req,
2456 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2457 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002458 std::string objectPath = "/xyz/" + path;
2459 handleDBusUrl(req, asyncResp, objectPath);
2460 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002461
Ed Tanous049a0512018-11-01 13:58:42 -07002462 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002463 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002464 .methods(boost::beast::http::verb::get)(
2465 [](const crow::Request& req,
2466 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2467 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002468 std::string objectPath = "/org/" + path;
2469 handleDBusUrl(req, asyncResp, objectPath);
2470 });
Tanousf00032d2018-11-05 01:18:10 -03002471
2472 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002473 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002474 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2475 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002476 [](const crow::Request& req,
2477 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002478 const std::string& path) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002479 std::string objectPath = "/org/" + path;
2480 handleDBusUrl(req, asyncResp, objectPath);
2481 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002482
Ed Tanous1abe55e2018-09-05 08:30:59 -07002483 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002484 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002485 .methods(boost::beast::http::verb::get)(
2486 [](const crow::Request&,
2487 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2488 const std::string& dumpId) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002489 if (!validateFilename(dumpId))
2490 {
2491 asyncResp->res.result(boost::beast::http::status::bad_request);
2492 return;
2493 }
2494 std::filesystem::path loc("/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002495
Ed Tanous002d39b2022-05-31 08:59:27 -07002496 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002497
Ed Tanous002d39b2022-05-31 08:59:27 -07002498 if (!std::filesystem::exists(loc) ||
2499 !std::filesystem::is_directory(loc))
2500 {
2501 BMCWEB_LOG_ERROR << loc.string() << "Not found";
2502 asyncResp->res.result(boost::beast::http::status::not_found);
2503 return;
2504 }
2505 std::filesystem::directory_iterator files(loc);
zhanghch058d1b46d2021-04-01 11:18:24 +08002506
Ed Tanous002d39b2022-05-31 08:59:27 -07002507 for (const auto& file : files)
2508 {
2509 std::ifstream readFile(file.path());
2510 if (!readFile.good())
2511 {
2512 continue;
2513 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002514
Ed Tanous002d39b2022-05-31 08:59:27 -07002515 asyncResp->res.addHeader("Content-Type",
2516 "application/octet-stream");
zhanghch058d1b46d2021-04-01 11:18:24 +08002517
Ed Tanous002d39b2022-05-31 08:59:27 -07002518 // Assuming only one dump file will be present in the dump
2519 // id directory
2520 std::string dumpFileName = file.path().filename().string();
zhanghch058d1b46d2021-04-01 11:18:24 +08002521
Ed Tanous002d39b2022-05-31 08:59:27 -07002522 // Filename should be in alphanumeric, dot and underscore
2523 // Its based on phosphor-debug-collector application
2524 // dumpfile format
2525 std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
2526 if (!std::regex_match(dumpFileName, dumpFileRegex))
2527 {
2528 BMCWEB_LOG_ERROR << "Invalid dump filename " << dumpFileName;
zhanghch058d1b46d2021-04-01 11:18:24 +08002529 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002530 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07002531 }
2532 std::string contentDispositionParam =
2533 "attachment; filename=\"" + dumpFileName + "\"";
2534
2535 asyncResp->res.addHeader("Content-Disposition",
2536 contentDispositionParam);
2537
2538 asyncResp->res.body() = {std::istreambuf_iterator<char>(readFile),
2539 std::istreambuf_iterator<char>()};
2540 return;
2541 }
2542 asyncResp->res.result(boost::beast::http::status::not_found);
2543 return;
2544 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002545
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002546 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002547 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002548
2549 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002550 [](const crow::Request&,
2551 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002552 const std::string& connection) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002553 introspectObjects(connection, "/", asyncResp);
2554 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002555
2556 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002557 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous1656b292022-05-04 11:33:42 -07002558 .methods(boost::beast::http::verb::get,
2559 boost::beast::http::verb::post)(handleBusSystemPost);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002560}
2561} // namespace openbmc_mapper
2562} // namespace crow