blob: 6861571073d3ca17232f8e2bcd3e41dbfeb1b02a [file] [log] [blame]
James Feist5b4aa862018-08-16 14:07:01 -07001// Copyright (c) 2018 Intel Corporation
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
Ed Tanousb9b2e0b2018-09-13 13:47:50 -070014
James Feist5b4aa862018-08-16 14:07:01 -070015#pragma once
Ed Tanous911ac312017-08-15 09:37:42 -070016#include <tinyxml2.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -070017
Ed Tanous04e438c2020-10-03 08:06:26 -070018#include <app.hpp>
Ed Tanouse3cb5a32018-08-08 14:16:49 -070019#include <async_resp.hpp>
Ed Tanous1abe55e2018-09-05 08:30:59 -070020#include <boost/algorithm/string.hpp>
21#include <boost/container/flat_set.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -070022#include <dbus_singleton.hpp>
James Feist5b4aa862018-08-16 14:07:01 -070023#include <dbus_utility.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050024#include <sdbusplus/message/types.hpp>
25
James Feist4418c7f2019-04-15 11:09:15 -070026#include <filesystem>
Ed Tanousd4bb9bb2018-05-16 13:36:42 -070027#include <fstream>
Ramesh Iyyard9207042019-07-05 08:04:42 -050028#include <regex>
Ed Tanousb5a76932020-09-29 16:16:58 -070029#include <utility>
Ed Tanous911ac312017-08-15 09:37:42 -070030
Ed Tanous1abe55e2018-09-05 08:30:59 -070031namespace crow
32{
33namespace openbmc_mapper
34{
Ed Tanousba9f9a62017-10-11 16:40:35 -070035
Matt Spinler3ae4ba72018-12-05 14:01:22 -060036using GetSubTreeType = std::vector<
37 std::pair<std::string,
38 std::vector<std::pair<std::string, std::vector<std::string>>>>>;
39
Ed Tanous23a21a12020-07-25 04:45:05 +000040const constexpr char* notFoundMsg = "404 Not Found";
41const constexpr char* badReqMsg = "400 Bad Request";
42const constexpr char* methodNotAllowedMsg = "405 Method Not Allowed";
43const constexpr char* forbiddenMsg = "403 Forbidden";
44const constexpr char* methodFailedMsg = "500 Method Call Failed";
45const constexpr char* methodOutputFailedMsg = "500 Method Output Error";
46const constexpr char* notFoundDesc =
Matt Spinler2ae60092018-12-06 10:35:36 -060047 "org.freedesktop.DBus.Error.FileNotFound: path or object not found";
Ed Tanous23a21a12020-07-25 04:45:05 +000048const constexpr char* propNotFoundDesc =
49 "The specified property cannot be found";
50const constexpr char* noJsonDesc = "No JSON object could be decoded";
51const constexpr char* methodNotFoundDesc =
52 "The specified method cannot be found";
53const constexpr char* methodNotAllowedDesc = "Method not allowed";
54const constexpr char* forbiddenPropDesc =
55 "The specified property cannot be created";
56const constexpr char* forbiddenResDesc =
57 "The specified resource cannot be created";
Matt Spinler2ae60092018-12-06 10:35:36 -060058
Ed Tanous23a21a12020-07-25 04:45:05 +000059inline void setErrorResponse(crow::Response& res,
60 boost::beast::http::status result,
61 const std::string& desc,
62 const std::string_view msg)
Matt Spinler2ae60092018-12-06 10:35:36 -060063{
64 res.result(result);
65 res.jsonValue = {{"data", {{"description", desc}}},
66 {"message", msg},
67 {"status", "error"}};
68}
69
Ed Tanousb5a76932020-09-29 16:16:58 -070070inline void
71 introspectObjects(const std::string& processName,
72 const std::string& objectPath,
73 const std::shared_ptr<bmcweb::AsyncResp>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -070074{
Ed Tanouse3cb5a32018-08-08 14:16:49 -070075 if (transaction->res.jsonValue.is_null())
76 {
77 transaction->res.jsonValue = {{"status", "ok"},
78 {"bus_name", processName},
79 {"objects", nlohmann::json::array()}};
80 }
81
Ed Tanous1abe55e2018-09-05 08:30:59 -070082 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -070083 [transaction, processName{std::string(processName)},
84 objectPath{std::string(objectPath)}](
85 const boost::system::error_code ec,
Ed Tanous81ce6092020-12-17 16:54:55 +000086 const std::string& introspectXml) {
Ed Tanous1abe55e2018-09-05 08:30:59 -070087 if (ec)
88 {
89 BMCWEB_LOG_ERROR
90 << "Introspect call failed with error: " << ec.message()
91 << " on process: " << processName << " path: " << objectPath
92 << "\n";
Ed Tanouse3cb5a32018-08-08 14:16:49 -070093 return;
94 }
95 transaction->res.jsonValue["objects"].push_back(
96 {{"path", objectPath}});
97
98 tinyxml2::XMLDocument doc;
99
Ed Tanous81ce6092020-12-17 16:54:55 +0000100 doc.Parse(introspectXml.c_str());
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500101 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700102 if (pRoot == nullptr)
103 {
104 BMCWEB_LOG_ERROR << "XML document failed to parse "
105 << processName << " " << objectPath << "\n";
Ed Tanous911ac312017-08-15 09:37:42 -0700106 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700107 else
108 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500109 tinyxml2::XMLElement* node = pRoot->FirstChildElement("node");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700110 while (node != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700111 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500112 const char* childPath = node->Attribute("name");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700113 if (childPath != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700114 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700115 std::string newpath;
116 if (objectPath != "/")
117 {
118 newpath += objectPath;
119 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700120 newpath += std::string("/") + childPath;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700121 // introspect the subobjects as well
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700122 introspectObjects(processName, newpath, transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700124
125 node = node->NextSiblingElement("node");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700126 }
127 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700128 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700129 processName, objectPath, "org.freedesktop.DBus.Introspectable",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700130 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -0700131}
Ed Tanous64530012018-02-06 17:08:16 -0800132
Ed Tanous23a21a12020-07-25 04:45:05 +0000133inline void getPropertiesForEnumerate(
134 const std::string& objectPath, const std::string& service,
Ed Tanousb5a76932020-09-29 16:16:58 -0700135 const std::string& interface,
136 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600137{
138 BMCWEB_LOG_DEBUG << "getPropertiesForEnumerate " << objectPath << " "
139 << service << " " << interface;
140
141 crow::connections::systemBus->async_method_call(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500142 [asyncResp, objectPath, service, interface](
143 const boost::system::error_code ec,
144 const std::vector<std::pair<
145 std::string, dbus::utility::DbusVariantType>>& propertiesList) {
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600146 if (ec)
147 {
148 BMCWEB_LOG_ERROR << "GetAll on path " << objectPath << " iface "
149 << interface << " service " << service
150 << " failed with code " << ec;
151 return;
152 }
153
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500154 nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
155 nlohmann::json& objectJson = dataJson[objectPath];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600156 if (objectJson.is_null())
157 {
158 objectJson = nlohmann::json::object();
159 }
160
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500161 for (const auto& [name, value] : propertiesList)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600162 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500163 nlohmann::json& propertyJson = objectJson[name];
Ed Tanousd1a64812021-12-13 12:14:05 -0800164 std::visit(
165 [&propertyJson](auto&& val) {
166 if constexpr (std::is_same_v<
167 std::decay_t<decltype(val)>,
168 sdbusplus::message::unix_fd>)
169 {
170 propertyJson = val.fd;
171 }
172 else
173 {
174
175 propertyJson = val;
176 }
177 },
178 value);
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600179 }
180 },
181 service, objectPath, "org.freedesktop.DBus.Properties", "GetAll",
182 interface);
183}
184
185// Find any results that weren't picked up by ObjectManagers, to be
186// called after all ObjectManagers are searched for and called.
Ed Tanous23a21a12020-07-25 04:45:05 +0000187inline void findRemainingObjectsForEnumerate(
Ed Tanousb5a76932020-09-29 16:16:58 -0700188 const std::string& objectPath,
189 const std::shared_ptr<GetSubTreeType>& subtree,
190 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600191{
192 BMCWEB_LOG_DEBUG << "findRemainingObjectsForEnumerate";
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500193 const nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600194
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500195 for (const auto& [path, interface_map] : *subtree)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600196 {
197 if (path == objectPath)
198 {
199 // An enumerate does not return the target path's properties
200 continue;
201 }
202 if (dataJson.find(path) == dataJson.end())
203 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500204 for (const auto& [service, interfaces] : interface_map)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600205 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500206 for (const auto& interface : interfaces)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600207 {
208 if (!boost::starts_with(interface, "org.freedesktop.DBus"))
209 {
210 getPropertiesForEnumerate(path, service, interface,
211 asyncResp);
212 }
213 }
214 }
215 }
216 }
217}
218
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600219struct InProgressEnumerateData
220{
zhanghch058d1b46d2021-04-01 11:18:24 +0800221 InProgressEnumerateData(
222 const std::string& objectPathIn,
223 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
Ed Tanous23a21a12020-07-25 04:45:05 +0000224 objectPath(objectPathIn),
zhanghch058d1b46d2021-04-01 11:18:24 +0800225 asyncResp(asyncRespIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500226 {}
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600227
228 ~InProgressEnumerateData()
229 {
Ed Tanous24b2fe82022-01-06 12:45:54 -0800230 try
231 {
232 findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
233 }
234 catch (...)
235 {
236 BMCWEB_LOG_CRITICAL
237 << "findRemainingObjectsForEnumerate threw exception";
238 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600239 }
240
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800241 InProgressEnumerateData(const InProgressEnumerateData&) = delete;
242 InProgressEnumerateData(InProgressEnumerateData&&) = delete;
243 InProgressEnumerateData& operator=(const InProgressEnumerateData&) = delete;
244 InProgressEnumerateData& operator=(InProgressEnumerateData&&) = delete;
245
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600246 const std::string objectPath;
247 std::shared_ptr<GetSubTreeType> subtree;
248 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
249};
250
Ed Tanous23a21a12020-07-25 04:45:05 +0000251inline void getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000252 const std::string& objectName, const std::string& objectManagerPath,
253 const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700254 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700255{
Ed Tanous81ce6092020-12-17 16:54:55 +0000256 BMCWEB_LOG_DEBUG << "getManagedObjectsForEnumerate " << objectName
257 << " object_manager_path " << objectManagerPath
258 << " connection_name " << connectionName;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700259 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000260 [transaction, objectName,
261 connectionName](const boost::system::error_code ec,
262 const dbus::utility::ManagedObjectType& objects) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700263 if (ec)
264 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000265 BMCWEB_LOG_ERROR << "GetManagedObjects on path " << objectName
266 << " on connection " << connectionName
Ed Tanous049a0512018-11-01 13:58:42 -0700267 << " failed with code " << ec;
268 return;
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700269 }
Ed Tanous64530012018-02-06 17:08:16 -0800270
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500271 nlohmann::json& dataJson =
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600272 transaction->asyncResp->res.jsonValue["data"];
Ed Tanous049a0512018-11-01 13:58:42 -0700273
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500274 for (const auto& objectPath : objects)
Ed Tanous049a0512018-11-01 13:58:42 -0700275 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000276 if (boost::starts_with(objectPath.first.str, objectName))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700277 {
Ed Tanous049a0512018-11-01 13:58:42 -0700278 BMCWEB_LOG_DEBUG << "Reading object "
279 << objectPath.first.str;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500280 nlohmann::json& objectJson = dataJson[objectPath.first.str];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700281 if (objectJson.is_null())
282 {
283 objectJson = nlohmann::json::object();
284 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500285 for (const auto& interface : objectPath.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700286 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500287 for (const auto& property : interface.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700288 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500289 nlohmann::json& propertyJson =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700290 objectJson[property.first];
Ed Tanousd1a64812021-12-13 12:14:05 -0800291 std::visit(
292 [&propertyJson](auto&& val) {
293 if constexpr (
294 std::is_same_v<
295 std::decay_t<decltype(val)>,
296 sdbusplus::message::unix_fd>)
297 {
298 propertyJson = val.fd;
299 }
300 else
301 {
302
303 propertyJson = val;
304 }
305 },
306 property.second);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700307 }
308 }
309 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500310 for (const auto& interface : objectPath.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700311 {
312 if (interface.first == "org.freedesktop.DBus.ObjectManager")
313 {
314 getManagedObjectsForEnumerate(
315 objectPath.first.str, objectPath.first.str,
Ed Tanous81ce6092020-12-17 16:54:55 +0000316 connectionName, transaction);
Ed Tanous049a0512018-11-01 13:58:42 -0700317 }
318 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700319 }
320 },
Ed Tanous81ce6092020-12-17 16:54:55 +0000321 connectionName, objectManagerPath, "org.freedesktop.DBus.ObjectManager",
322 "GetManagedObjects");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700323}
324
Ed Tanous23a21a12020-07-25 04:45:05 +0000325inline void findObjectManagerPathForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000326 const std::string& objectName, const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700327 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700328{
Ed Tanous81ce6092020-12-17 16:54:55 +0000329 BMCWEB_LOG_DEBUG << "Finding objectmanager for path " << objectName
330 << " on connection:" << connectionName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700331 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000332 [transaction, objectName, connectionName](
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700333 const boost::system::error_code ec,
334 const boost::container::flat_map<
335 std::string, boost::container::flat_map<
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500336 std::string, std::vector<std::string>>>&
337 objects) {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700338 if (ec)
339 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000340 BMCWEB_LOG_ERROR << "GetAncestors on path " << objectName
Ed Tanous049a0512018-11-01 13:58:42 -0700341 << " failed with code " << ec;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700342 return;
343 }
344
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500345 for (const auto& pathGroup : objects)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700346 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500347 for (const auto& connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700348 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000349 if (connectionGroup.first == connectionName)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700350 {
351 // Found the object manager path for this resource.
352 getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000353 objectName, pathGroup.first, connectionName,
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600354 transaction);
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700355 return;
356 }
357 }
358 }
359 },
360 "xyz.openbmc_project.ObjectMapper",
361 "/xyz/openbmc_project/object_mapper",
Ed Tanous81ce6092020-12-17 16:54:55 +0000362 "xyz.openbmc_project.ObjectMapper", "GetAncestors", objectName,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500363 std::array<const char*, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700364}
Ed Tanous64530012018-02-06 17:08:16 -0800365
Ed Tanous7c091622019-05-23 11:42:36 -0700366// Uses GetObject to add the object info about the target /enumerate path to
367// the results of GetSubTree, as GetSubTree will not return info for the
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600368// target path, and then continues on enumerating the rest of the tree.
Ed Tanousb5a76932020-09-29 16:16:58 -0700369inline void getObjectAndEnumerate(
370 const std::shared_ptr<InProgressEnumerateData>& transaction)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600371{
372 using GetObjectType =
373 std::vector<std::pair<std::string, std::vector<std::string>>>;
374
375 crow::connections::systemBus->async_method_call(
376 [transaction](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500377 const GetObjectType& objects) {
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600378 if (ec)
379 {
380 BMCWEB_LOG_ERROR << "GetObject for path "
381 << transaction->objectPath
382 << " failed with code " << ec;
383 return;
384 }
385
386 BMCWEB_LOG_DEBUG << "GetObject for " << transaction->objectPath
387 << " has " << objects.size() << " entries";
388 if (!objects.empty())
389 {
390 transaction->subtree->emplace_back(transaction->objectPath,
391 objects);
392 }
393
394 // Map indicating connection name, and the path where the object
395 // manager exists
396 boost::container::flat_map<std::string, std::string> connections;
397
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500398 for (const auto& object : *(transaction->subtree))
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600399 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500400 for (const auto& connection : object.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600401 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500402 std::string& objectManagerPath =
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600403 connections[connection.first];
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500404 for (const auto& interface : connection.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600405 {
406 BMCWEB_LOG_DEBUG << connection.first
407 << " has interface " << interface;
408 if (interface == "org.freedesktop.DBus.ObjectManager")
409 {
410 BMCWEB_LOG_DEBUG << "found object manager path "
411 << object.first;
412 objectManagerPath = object.first;
413 }
414 }
415 }
416 }
417 BMCWEB_LOG_DEBUG << "Got " << connections.size() << " connections";
418
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500419 for (const auto& connection : connections)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600420 {
Ed Tanous7c091622019-05-23 11:42:36 -0700421 // If we already know where the object manager is, we don't
422 // need to search for it, we can call directly in to
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600423 // getManagedObjects
424 if (!connection.second.empty())
425 {
426 getManagedObjectsForEnumerate(
427 transaction->objectPath, connection.second,
428 connection.first, transaction);
429 }
430 else
431 {
Ed Tanous7c091622019-05-23 11:42:36 -0700432 // otherwise we need to find the object manager path
433 // before we can continue
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600434 findObjectManagerPathForEnumerate(
435 transaction->objectPath, connection.first, transaction);
436 }
437 }
438 },
439 "xyz.openbmc_project.ObjectMapper",
440 "/xyz/openbmc_project/object_mapper",
441 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500442 transaction->objectPath, std::array<const char*, 0>());
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600443}
Ed Tanous64530012018-02-06 17:08:16 -0800444
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700445// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700446struct InProgressActionData
447{
Ed Tanous23a21a12020-07-25 04:45:05 +0000448 InProgressActionData(crow::Response& resIn) : res(resIn)
449 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700450 ~InProgressActionData()
451 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600452 // Methods could have been called across different owners
453 // and interfaces, where some calls failed and some passed.
454 //
455 // The rules for this are:
456 // * if no method was called - error
457 // * if a method failed and none passed - error
458 // (converse: if at least one method passed - OK)
459 // * for the method output:
460 // * if output processing didn't fail, return the data
461
462 // Only deal with method returns if nothing failed earlier
463 if (res.result() == boost::beast::http::status::ok)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700464 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600465 if (!methodPassed)
466 {
Matt Spinler06b1b632019-06-18 16:09:25 -0500467 if (!methodFailed)
Matt Spinler16caaee2019-01-15 11:40:34 -0600468 {
469 setErrorResponse(res, boost::beast::http::status::not_found,
470 methodNotFoundDesc, notFoundMsg);
471 }
472 }
473 else
474 {
475 if (outputFailed)
476 {
477 setErrorResponse(
478 res, boost::beast::http::status::internal_server_error,
479 "Method output failure", methodOutputFailedMsg);
480 }
481 else
482 {
483 res.jsonValue = {{"status", "ok"},
484 {"message", "200 OK"},
485 {"data", methodResponse}};
486 }
487 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700488 }
Matt Spinler16caaee2019-01-15 11:40:34 -0600489
Ed Tanous1abe55e2018-09-05 08:30:59 -0700490 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700491 }
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800492 InProgressActionData(const InProgressActionData&) = delete;
493 InProgressActionData(InProgressActionData&&) = delete;
494 InProgressActionData& operator=(const InProgressActionData&) = delete;
495 InProgressActionData& operator=(InProgressActionData&&) = delete;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700496
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500497 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700498 {
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600499 setErrorResponse(res, boost::beast::http::status::bad_request, desc,
500 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700501 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500502 crow::Response& res;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700503 std::string path;
504 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600505 std::string interfaceName;
Matt Spinler16caaee2019-01-15 11:40:34 -0600506 bool methodPassed = false;
507 bool methodFailed = false;
508 bool outputFailed = false;
Matt Spinler39a4e392019-01-15 11:53:13 -0600509 bool convertedToArray = false;
Matt Spinler16caaee2019-01-15 11:40:34 -0600510 nlohmann::json methodResponse;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700511 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700512};
513
Ed Tanous23a21a12020-07-25 04:45:05 +0000514inline std::vector<std::string> dbusArgSplit(const std::string& string)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700515{
516 std::vector<std::string> ret;
517 if (string.empty())
518 {
519 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700520 }
Ed Tanous0f0353b2019-10-24 11:37:51 -0700521 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700522 int containerDepth = 0;
523
524 for (std::string::const_iterator character = string.begin();
525 character != string.end(); character++)
526 {
527 ret.back() += *character;
528 switch (*character)
529 {
530 case ('a'):
531 break;
532 case ('('):
533 case ('{'):
534 containerDepth++;
535 break;
536 case ('}'):
537 case (')'):
538 containerDepth--;
539 if (containerDepth == 0)
540 {
541 if (character + 1 != string.end())
542 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700543 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700544 }
545 }
546 break;
547 default:
548 if (containerDepth == 0)
549 {
550 if (character + 1 != string.end())
551 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700552 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700553 }
554 }
555 break;
556 }
557 }
Matt Spinler4ae611d2019-01-11 15:37:06 -0600558
559 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700560}
561
Ed Tanous81ce6092020-12-17 16:54:55 +0000562inline int convertJsonToDbus(sd_bus_message* m, const std::string& argType,
563 const nlohmann::json& inputJson)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700564{
565 int r = 0;
Ed Tanous71f52d92021-02-19 08:51:17 -0800566 BMCWEB_LOG_DEBUG << "Converting "
567 << inputJson.dump(2, ' ', true,
568 nlohmann::json::error_handler_t::replace)
Ed Tanous81ce6092020-12-17 16:54:55 +0000569 << " to type: " << argType;
570 const std::vector<std::string> argTypes = dbusArgSplit(argType);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700571
Ed Tanous1abe55e2018-09-05 08:30:59 -0700572 // Assume a single object for now.
Ed Tanous81ce6092020-12-17 16:54:55 +0000573 const nlohmann::json* j = &inputJson;
574 nlohmann::json::const_iterator jIt = inputJson.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700575
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500576 for (const std::string& argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700577 {
578 // If we are decoding multiple objects, grab the pointer to the
579 // iterator, and increment it for the next loop
580 if (argTypes.size() > 1)
581 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000582 if (jIt == inputJson.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700583 {
584 return -2;
585 }
586 j = &*jIt;
587 jIt++;
588 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500589 const int64_t* intValue = j->get_ptr<const int64_t*>();
590 const std::string* stringValue = j->get_ptr<const std::string*>();
591 const double* doubleValue = j->get_ptr<const double*>();
592 const bool* b = j->get_ptr<const bool*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700593 int64_t v = 0;
594 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700595
Ed Tanous1abe55e2018-09-05 08:30:59 -0700596 // Do some basic type conversions that make sense. uint can be
597 // converted to int. int and uint can be converted to double
Ed Tanous66664f22019-10-11 13:05:49 -0700598 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700599 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500600 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700601 if (uintValue != nullptr)
602 {
603 v = static_cast<int64_t>(*uintValue);
604 intValue = &v;
605 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700606 }
Ed Tanous66664f22019-10-11 13:05:49 -0700607 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700608 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500609 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700610 if (uintValue != nullptr)
611 {
612 d = static_cast<double>(*uintValue);
613 doubleValue = &d;
614 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700615 }
Ed Tanous66664f22019-10-11 13:05:49 -0700616 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700617 {
Ed Tanous66664f22019-10-11 13:05:49 -0700618 if (intValue != nullptr)
619 {
620 d = static_cast<double>(*intValue);
621 doubleValue = &d;
622 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700623 }
624
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700625 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700626 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700627 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700628 {
629 return -1;
630 }
Ed Tanous271584a2019-07-09 16:24:22 -0700631 r = sd_bus_message_append_basic(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500632 m, argCode[0], static_cast<const void*>(stringValue->data()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700633 if (r < 0)
634 {
635 return r;
636 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700637 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700638 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700639 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700640 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700641 {
642 return -1;
643 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500644 if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
645 (*intValue > std::numeric_limits<int32_t>::max()))
646 {
647 return -ERANGE;
648 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700649 int32_t i = static_cast<int32_t>(*intValue);
650 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700651 if (r < 0)
652 {
653 return r;
654 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700655 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700656 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700657 {
658 // lots of ways bool could be represented here. Try them all
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700659 int boolInt = false;
660 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700661 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500662 if (*intValue == 1)
663 {
664 boolInt = true;
665 }
666 else if (*intValue == 0)
667 {
668 boolInt = false;
669 }
670 else
671 {
672 return -ERANGE;
673 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700674 }
675 else if (b != nullptr)
676 {
Matt Spinlera2f02632019-01-18 10:15:35 -0600677 boolInt = *b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700678 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700679 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700680 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700681 boolInt = boost::istarts_with(*stringValue, "t") ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700682 }
683 else
684 {
685 return -1;
686 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700687 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700688 if (r < 0)
689 {
690 return r;
691 }
692 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700693 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700694 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700695 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700696 {
697 return -1;
698 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500699 if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
700 (*intValue > std::numeric_limits<int16_t>::max()))
701 {
702 return -ERANGE;
703 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700704 int16_t n = static_cast<int16_t>(*intValue);
705 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700706 if (r < 0)
707 {
708 return r;
709 }
710 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700711 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700712 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700713 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700714 {
715 return -1;
716 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700717 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700718 if (r < 0)
719 {
720 return r;
721 }
722 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700723 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700724 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500725 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700726 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700727 {
728 return -1;
729 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000730 if (*uintValue > std::numeric_limits<uint8_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500731 {
732 return -ERANGE;
733 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700734 uint8_t y = static_cast<uint8_t>(*uintValue);
735 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700736 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700737 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700738 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500739 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700740 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700741 {
742 return -1;
743 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000744 if (*uintValue > std::numeric_limits<uint16_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500745 {
746 return -ERANGE;
747 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700748 uint16_t q = static_cast<uint16_t>(*uintValue);
749 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700750 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700751 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700752 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500753 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700754 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700755 {
756 return -1;
757 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000758 if (*uintValue > std::numeric_limits<uint32_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500759 {
760 return -ERANGE;
761 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700762 uint32_t u = static_cast<uint32_t>(*uintValue);
763 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700764 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700765 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700766 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500767 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700768 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700769 {
770 return -1;
771 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700772 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700773 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700774 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700775 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500776 if (doubleValue == nullptr)
777 {
778 return -1;
779 }
780 if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
781 (*doubleValue > std::numeric_limits<double>::max()))
782 {
783 return -ERANGE;
784 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700785 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700786 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700787 else if (boost::starts_with(argCode, "a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700788 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700789 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700790 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700791 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700792 if (r < 0)
793 {
794 return r;
795 }
796
Ed Tanous0dfeda62019-10-24 11:21:38 -0700797 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700798 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700799 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700800 if (r < 0)
801 {
802 return r;
803 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700804 }
805 sd_bus_message_close_container(m);
806 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700807 else if (boost::starts_with(argCode, "v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700808 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700809 std::string containedType = argCode.substr(1);
810 BMCWEB_LOG_DEBUG << "variant type: " << argCode
811 << " appending variant of type: " << containedType;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700812 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700813 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700814 if (r < 0)
815 {
816 return r;
817 }
818
Ed Tanous81ce6092020-12-17 16:54:55 +0000819 r = convertJsonToDbus(m, containedType, inputJson);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700820 if (r < 0)
821 {
822 return r;
823 }
824
825 r = sd_bus_message_close_container(m);
826 if (r < 0)
827 {
828 return r;
829 }
830 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700831 else if (boost::starts_with(argCode, "(") &&
832 boost::ends_with(argCode, ")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700833 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700834 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700835 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700836 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800837 if (r < 0)
838 {
839 return r;
840 }
841
Ed Tanous1abe55e2018-09-05 08:30:59 -0700842 nlohmann::json::const_iterator it = j->begin();
Ed Tanous81ce6092020-12-17 16:54:55 +0000843 for (const std::string& argCode2 : dbusArgSplit(argType))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700844 {
845 if (it == j->end())
846 {
847 return -1;
848 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000849 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700850 if (r < 0)
851 {
852 return r;
853 }
854 it++;
855 }
856 r = sd_bus_message_close_container(m);
857 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700858 else if (boost::starts_with(argCode, "{") &&
859 boost::ends_with(argCode, "}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700860 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700861 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700862 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700863 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800864 if (r < 0)
865 {
866 return r;
867 }
868
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700869 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700870 if (codes.size() != 2)
871 {
872 return -1;
873 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700874 const std::string& keyType = codes[0];
875 const std::string& valueType = codes[1];
Ed Tanous3174e4d2020-10-07 11:41:22 -0700876 for (const auto& it : j->items())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700877 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700878 r = convertJsonToDbus(m, keyType, it.key());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700879 if (r < 0)
880 {
881 return r;
882 }
883
Ed Tanous2c70f802020-09-28 14:29:23 -0700884 r = convertJsonToDbus(m, valueType, it.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700885 if (r < 0)
886 {
887 return r;
888 }
889 }
890 r = sd_bus_message_close_container(m);
891 }
892 else
893 {
894 return -2;
895 }
896 if (r < 0)
897 {
898 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700899 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700900
Ed Tanous1abe55e2018-09-05 08:30:59 -0700901 if (argTypes.size() > 1)
902 {
903 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700904 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700905 }
Matt Spinler127ea542019-01-14 11:04:28 -0600906
907 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700908}
909
Matt Spinlerd22a7132019-01-14 12:14:30 -0600910template <typename T>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500911int readMessageItem(const std::string& typeCode, sdbusplus::message::message& m,
912 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600913{
914 T value;
915
916 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
917 if (r < 0)
918 {
919 BMCWEB_LOG_ERROR << "sd_bus_message_read_basic on type " << typeCode
920 << " failed!";
921 return r;
922 }
923
924 data = value;
925 return 0;
926}
927
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500928int convertDBusToJSON(const std::string& returnType,
929 sdbusplus::message::message& m, nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600930
Ed Tanous23a21a12020-07-25 04:45:05 +0000931inline int readDictEntryFromMessage(const std::string& typeCode,
932 sdbusplus::message::message& m,
933 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600934{
935 std::vector<std::string> types = dbusArgSplit(typeCode);
936 if (types.size() != 2)
937 {
938 BMCWEB_LOG_ERROR << "wrong number contained types in dictionary: "
939 << types.size();
940 return -1;
941 }
942
943 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
944 typeCode.c_str());
945 if (r < 0)
946 {
947 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container with rc " << r;
948 return r;
949 }
950
951 nlohmann::json key;
952 r = convertDBusToJSON(types[0], m, key);
953 if (r < 0)
954 {
955 return r;
956 }
957
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500958 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -0600959 if (keyPtr == nullptr)
960 {
961 // json doesn't support non-string keys. If we hit this condition,
962 // convert the result to a string so we can proceed
Ed Tanous71f52d92021-02-19 08:51:17 -0800963 key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500964 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -0700965 // in theory this can't fail now, but lets be paranoid about it
966 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -0600967 if (keyPtr == nullptr)
968 {
969 return -1;
970 }
971 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500972 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -0600973
974 r = convertDBusToJSON(types[1], m, value);
975 if (r < 0)
976 {
977 return r;
978 }
979
980 r = sd_bus_message_exit_container(m.get());
981 if (r < 0)
982 {
983 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
984 return r;
985 }
986
987 return 0;
988}
989
Ed Tanous23a21a12020-07-25 04:45:05 +0000990inline int readArrayFromMessage(const std::string& typeCode,
991 sdbusplus::message::message& m,
992 nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -0600993{
994 if (typeCode.size() < 2)
995 {
996 BMCWEB_LOG_ERROR << "Type code " << typeCode
997 << " too small for an array";
998 return -1;
999 }
1000
1001 std::string containedType = typeCode.substr(1);
1002
1003 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
1004 containedType.c_str());
1005 if (r < 0)
1006 {
1007 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1008 << r;
1009 return r;
1010 }
1011
1012 bool dict = boost::starts_with(containedType, "{") &&
1013 boost::ends_with(containedType, "}");
1014
1015 if (dict)
1016 {
1017 // Remove the { }
1018 containedType = containedType.substr(1, containedType.size() - 2);
1019 data = nlohmann::json::object();
1020 }
1021 else
1022 {
1023 data = nlohmann::json::array();
1024 }
1025
1026 while (true)
1027 {
1028 r = sd_bus_message_at_end(m.get(), false);
1029 if (r < 0)
1030 {
1031 BMCWEB_LOG_ERROR << "sd_bus_message_at_end failed";
1032 return r;
1033 }
1034
1035 if (r > 0)
1036 {
1037 break;
1038 }
1039
1040 // Dictionaries are only ever seen in an array
1041 if (dict)
1042 {
1043 r = readDictEntryFromMessage(containedType, m, data);
1044 if (r < 0)
1045 {
1046 return r;
1047 }
1048 }
1049 else
1050 {
1051 data.push_back(nlohmann::json());
1052
1053 r = convertDBusToJSON(containedType, m, data.back());
1054 if (r < 0)
1055 {
1056 return r;
1057 }
1058 }
1059 }
1060
1061 r = sd_bus_message_exit_container(m.get());
1062 if (r < 0)
1063 {
1064 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1065 return r;
1066 }
1067
1068 return 0;
1069}
1070
Ed Tanous23a21a12020-07-25 04:45:05 +00001071inline int readStructFromMessage(const std::string& typeCode,
1072 sdbusplus::message::message& m,
1073 nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001074{
1075 if (typeCode.size() < 3)
1076 {
1077 BMCWEB_LOG_ERROR << "Type code " << typeCode
1078 << " too small for a struct";
1079 return -1;
1080 }
1081
1082 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1083 std::vector<std::string> types = dbusArgSplit(containedTypes);
1084
1085 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1086 containedTypes.c_str());
1087 if (r < 0)
1088 {
1089 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1090 << r;
1091 return r;
1092 }
1093
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001094 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001095 {
1096 data.push_back(nlohmann::json());
1097 r = convertDBusToJSON(type, m, data.back());
1098 if (r < 0)
1099 {
1100 return r;
1101 }
1102 }
1103
1104 r = sd_bus_message_exit_container(m.get());
1105 if (r < 0)
1106 {
1107 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1108 return r;
1109 }
1110 return 0;
1111}
1112
Ed Tanous23a21a12020-07-25 04:45:05 +00001113inline int readVariantFromMessage(sdbusplus::message::message& m,
1114 nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001115{
Ed Tanous543f4402022-01-06 13:12:53 -08001116 const char* containerType = nullptr;
Ed Tanous99131cd2019-10-24 11:12:47 -07001117 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001118 if (r < 0)
1119 {
1120 BMCWEB_LOG_ERROR << "sd_bus_message_peek_type failed";
1121 return r;
1122 }
1123
1124 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1125 containerType);
1126 if (r < 0)
1127 {
1128 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1129 << r;
1130 return r;
1131 }
1132
1133 r = convertDBusToJSON(containerType, m, data);
1134 if (r < 0)
1135 {
1136 return r;
1137 }
1138
1139 r = sd_bus_message_exit_container(m.get());
1140 if (r < 0)
1141 {
1142 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed";
1143 return r;
1144 }
1145
1146 return 0;
1147}
1148
Ed Tanous23a21a12020-07-25 04:45:05 +00001149inline int convertDBusToJSON(const std::string& returnType,
1150 sdbusplus::message::message& m,
1151 nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001152{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001153 int r = 0;
1154 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1155
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001156 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001157 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001158 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001159 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001160 {
1161 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001162 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001163 }
1164
Ed Tanousd4d25792020-09-29 15:15:03 -07001165 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001166 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001167 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001168 if (r < 0)
1169 {
1170 return r;
1171 }
1172 }
1173 else if (typeCode == "b")
1174 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001175 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001176 if (r < 0)
1177 {
1178 return r;
1179 }
1180
Matt Spinlerf39420c2019-01-30 12:57:18 -06001181 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001182 }
1183 else if (typeCode == "u")
1184 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001185 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001186 if (r < 0)
1187 {
1188 return r;
1189 }
1190 }
1191 else if (typeCode == "i")
1192 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001193 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001194 if (r < 0)
1195 {
1196 return r;
1197 }
1198 }
1199 else if (typeCode == "x")
1200 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001201 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001202 if (r < 0)
1203 {
1204 return r;
1205 }
1206 }
1207 else if (typeCode == "t")
1208 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001209 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001210 if (r < 0)
1211 {
1212 return r;
1213 }
1214 }
1215 else if (typeCode == "n")
1216 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001217 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001218 if (r < 0)
1219 {
1220 return r;
1221 }
1222 }
1223 else if (typeCode == "q")
1224 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001225 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001226 if (r < 0)
1227 {
1228 return r;
1229 }
1230 }
1231 else if (typeCode == "y")
1232 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001233 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001234 if (r < 0)
1235 {
1236 return r;
1237 }
1238 }
1239 else if (typeCode == "d")
1240 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001241 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001242 if (r < 0)
1243 {
1244 return r;
1245 }
1246 }
1247 else if (typeCode == "h")
1248 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001249 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001250 if (r < 0)
1251 {
1252 return r;
1253 }
1254 }
Matt Spinler6df8f992019-01-14 12:47:47 -06001255 else if (boost::starts_with(typeCode, "a"))
1256 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001257 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001258 if (r < 0)
1259 {
1260 return r;
1261 }
1262 }
Matt Spinler75c6c672019-01-14 13:01:46 -06001263 else if (boost::starts_with(typeCode, "(") &&
1264 boost::ends_with(typeCode, ")"))
1265 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001266 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001267 if (r < 0)
1268 {
1269 return r;
1270 }
1271 }
Matt Spinler89c19702019-01-14 13:13:00 -06001272 else if (boost::starts_with(typeCode, "v"))
1273 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001274 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001275 if (r < 0)
1276 {
1277 return r;
1278 }
1279 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001280 else
1281 {
Matt Spinlerd22a7132019-01-14 12:14:30 -06001282 BMCWEB_LOG_ERROR << "Invalid D-Bus signature type " << typeCode;
1283 return -2;
1284 }
1285 }
1286
Matt Spinler16caaee2019-01-15 11:40:34 -06001287 return 0;
1288}
1289
Ed Tanousb5a76932020-09-29 16:16:58 -07001290inline void handleMethodResponse(
1291 const std::shared_ptr<InProgressActionData>& transaction,
1292 sdbusplus::message::message& m, const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001293{
Matt Spinler39a4e392019-01-15 11:53:13 -06001294 nlohmann::json data;
1295
1296 int r = convertDBusToJSON(returnType, m, data);
1297 if (r < 0)
1298 {
1299 transaction->outputFailed = true;
1300 return;
1301 }
1302
1303 if (data.is_null())
1304 {
1305 return;
1306 }
1307
1308 if (transaction->methodResponse.is_null())
1309 {
1310 transaction->methodResponse = std::move(data);
1311 return;
1312 }
1313
1314 // If they're both dictionaries or arrays, merge into one.
1315 // Otherwise, make the results an array with every result
1316 // an entry. Could also just fail in that case, but it
1317 // seems better to get the data back somehow.
1318
1319 if (transaction->methodResponse.is_object() && data.is_object())
1320 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001321 for (const auto& obj : data.items())
Matt Spinler39a4e392019-01-15 11:53:13 -06001322 {
1323 // Note: Will overwrite the data for a duplicate key
1324 transaction->methodResponse.emplace(obj.key(),
1325 std::move(obj.value()));
1326 }
1327 return;
1328 }
1329
1330 if (transaction->methodResponse.is_array() && data.is_array())
1331 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001332 for (auto& obj : data)
Matt Spinler39a4e392019-01-15 11:53:13 -06001333 {
1334 transaction->methodResponse.push_back(std::move(obj));
1335 }
1336 return;
1337 }
1338
1339 if (!transaction->convertedToArray)
1340 {
1341 // They are different types. May as well turn them into an array
1342 nlohmann::json j = std::move(transaction->methodResponse);
1343 transaction->methodResponse = nlohmann::json::array();
1344 transaction->methodResponse.push_back(std::move(j));
1345 transaction->methodResponse.push_back(std::move(data));
1346 transaction->convertedToArray = true;
1347 }
1348 else
1349 {
1350 transaction->methodResponse.push_back(std::move(data));
1351 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001352}
1353
Ed Tanousb5a76932020-09-29 16:16:58 -07001354inline void findActionOnInterface(
1355 const std::shared_ptr<InProgressActionData>& transaction,
1356 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001357{
1358 BMCWEB_LOG_DEBUG << "findActionOnInterface for connection "
1359 << connectionName;
1360 crow::connections::systemBus->async_method_call(
1361 [transaction, connectionName{std::string(connectionName)}](
1362 const boost::system::error_code ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001363 const std::string& introspectXml) {
1364 BMCWEB_LOG_DEBUG << "got xml:\n " << introspectXml;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001365 if (ec)
1366 {
1367 BMCWEB_LOG_ERROR
1368 << "Introspect call failed with error: " << ec.message()
1369 << " on process: " << connectionName << "\n";
Matt Spinler318bd892019-01-15 09:59:20 -06001370 return;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001371 }
Matt Spinler318bd892019-01-15 09:59:20 -06001372 tinyxml2::XMLDocument doc;
1373
Ed Tanous81ce6092020-12-17 16:54:55 +00001374 doc.Parse(introspectXml.data(), introspectXml.size());
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001375 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
Matt Spinler318bd892019-01-15 09:59:20 -06001376 if (pRoot == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001377 {
Matt Spinler318bd892019-01-15 09:59:20 -06001378 BMCWEB_LOG_ERROR << "XML document failed to parse "
1379 << connectionName << "\n";
1380 return;
1381 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001382 tinyxml2::XMLElement* interfaceNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001383 pRoot->FirstChildElement("interface");
1384 while (interfaceNode != nullptr)
1385 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001386 const char* thisInterfaceName =
Matt Spinler318bd892019-01-15 09:59:20 -06001387 interfaceNode->Attribute("name");
1388 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001389 {
Matt Spinler318bd892019-01-15 09:59:20 -06001390 if (!transaction->interfaceName.empty() &&
1391 (transaction->interfaceName != thisInterfaceName))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001392 {
Matt Spinler318bd892019-01-15 09:59:20 -06001393 interfaceNode =
1394 interfaceNode->NextSiblingElement("interface");
1395 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001396 }
Matt Spinler318bd892019-01-15 09:59:20 -06001397
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001398 tinyxml2::XMLElement* methodNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001399 interfaceNode->FirstChildElement("method");
1400 while (methodNode != nullptr)
1401 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001402 const char* thisMethodName =
Matt Spinler318bd892019-01-15 09:59:20 -06001403 methodNode->Attribute("name");
1404 BMCWEB_LOG_DEBUG << "Found method: " << thisMethodName;
1405 if (thisMethodName != nullptr &&
1406 thisMethodName == transaction->methodName)
1407 {
1408 BMCWEB_LOG_DEBUG
1409 << "Found method named " << thisMethodName
1410 << " on interface " << thisInterfaceName;
1411 sdbusplus::message::message m =
1412 crow::connections::systemBus->new_method_call(
1413 connectionName.c_str(),
1414 transaction->path.c_str(),
1415 thisInterfaceName,
1416 transaction->methodName.c_str());
1417
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001418 tinyxml2::XMLElement* argumentNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001419 methodNode->FirstChildElement("arg");
1420
Matt Spinler16caaee2019-01-15 11:40:34 -06001421 std::string returnType;
1422
1423 // Find the output type
1424 while (argumentNode != nullptr)
1425 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001426 const char* argDirection =
Matt Spinler16caaee2019-01-15 11:40:34 -06001427 argumentNode->Attribute("direction");
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001428 const char* argType =
Matt Spinler16caaee2019-01-15 11:40:34 -06001429 argumentNode->Attribute("type");
1430 if (argDirection != nullptr &&
1431 argType != nullptr &&
1432 std::string(argDirection) == "out")
1433 {
1434 returnType = argType;
1435 break;
1436 }
1437 argumentNode =
1438 argumentNode->NextSiblingElement("arg");
1439 }
1440
Matt Spinler318bd892019-01-15 09:59:20 -06001441 nlohmann::json::const_iterator argIt =
1442 transaction->arguments.begin();
1443
Matt Spinler16caaee2019-01-15 11:40:34 -06001444 argumentNode = methodNode->FirstChildElement("arg");
1445
Matt Spinler318bd892019-01-15 09:59:20 -06001446 while (argumentNode != nullptr)
1447 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001448 const char* argDirection =
Matt Spinler318bd892019-01-15 09:59:20 -06001449 argumentNode->Attribute("direction");
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001450 const char* argType =
Matt Spinler318bd892019-01-15 09:59:20 -06001451 argumentNode->Attribute("type");
1452 if (argDirection != nullptr &&
1453 argType != nullptr &&
1454 std::string(argDirection) == "in")
1455 {
1456 if (argIt == transaction->arguments.end())
1457 {
1458 transaction->setErrorStatus(
1459 "Invalid method args");
1460 return;
1461 }
1462 if (convertJsonToDbus(m.get(),
1463 std::string(argType),
1464 *argIt) < 0)
1465 {
1466 transaction->setErrorStatus(
1467 "Invalid method arg type");
1468 return;
1469 }
1470
1471 argIt++;
1472 }
1473 argumentNode =
1474 argumentNode->NextSiblingElement("arg");
1475 }
1476
1477 crow::connections::systemBus->async_send(
Matt Spinler16caaee2019-01-15 11:40:34 -06001478 m, [transaction, returnType](
Ed Tanous23a21a12020-07-25 04:45:05 +00001479 boost::system::error_code ec2,
1480 sdbusplus::message::message& m2) {
1481 if (ec2)
Matt Spinler318bd892019-01-15 09:59:20 -06001482 {
Matt Spinler16caaee2019-01-15 11:40:34 -06001483 transaction->methodFailed = true;
Ed Tanous23a21a12020-07-25 04:45:05 +00001484 const sd_bus_error* e = m2.get_error();
Matt Spinler06b1b632019-06-18 16:09:25 -05001485
1486 if (e)
1487 {
1488 setErrorResponse(
1489 transaction->res,
1490 boost::beast::http::status::
1491 bad_request,
1492 e->name, e->message);
1493 }
1494 else
1495 {
1496 setErrorResponse(
1497 transaction->res,
1498 boost::beast::http::status::
1499 bad_request,
1500 "Method call failed",
1501 methodFailedMsg);
1502 }
Matt Spinler318bd892019-01-15 09:59:20 -06001503 return;
1504 }
Ed Tanous3174e4d2020-10-07 11:41:22 -07001505 transaction->methodPassed = true;
Matt Spinler16caaee2019-01-15 11:40:34 -06001506
Ed Tanous23a21a12020-07-25 04:45:05 +00001507 handleMethodResponse(transaction, m2,
Matt Spinler16caaee2019-01-15 11:40:34 -06001508 returnType);
Matt Spinler318bd892019-01-15 09:59:20 -06001509 });
1510 break;
1511 }
1512 methodNode = methodNode->NextSiblingElement("method");
1513 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001514 }
Matt Spinler318bd892019-01-15 09:59:20 -06001515 interfaceNode = interfaceNode->NextSiblingElement("interface");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001516 }
1517 },
1518 connectionName, transaction->path,
1519 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001520}
1521
zhanghch058d1b46d2021-04-01 11:18:24 +08001522inline void handleAction(const crow::Request& req,
1523 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001524 const std::string& objectPath,
1525 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001526{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001527 BMCWEB_LOG_DEBUG << "handleAction on path: " << objectPath << " and method "
1528 << methodName;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001529 nlohmann::json requestDbusData =
1530 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001531
Ed Tanous1abe55e2018-09-05 08:30:59 -07001532 if (requestDbusData.is_discarded())
1533 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001534 setErrorResponse(asyncResp->res,
1535 boost::beast::http::status::bad_request, noJsonDesc,
1536 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001537 return;
1538 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001539 nlohmann::json::iterator data = requestDbusData.find("data");
1540 if (data == requestDbusData.end())
1541 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001542 setErrorResponse(asyncResp->res,
1543 boost::beast::http::status::bad_request, noJsonDesc,
1544 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001545 return;
1546 }
1547
1548 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001549 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001550 setErrorResponse(asyncResp->res,
1551 boost::beast::http::status::bad_request, noJsonDesc,
1552 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001553 return;
1554 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001555 auto transaction = std::make_shared<InProgressActionData>(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001556
1557 transaction->path = objectPath;
1558 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001559 transaction->arguments = std::move(*data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001560 crow::connections::systemBus->async_method_call(
1561 [transaction](
1562 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001563 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1564 interfaceNames) {
Ed Tanous26f69762022-01-25 09:49:11 -08001565 if (ec || interfaceNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001566 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001567 BMCWEB_LOG_ERROR << "Can't find object";
Matt Spinler6db06242018-12-11 11:21:22 -06001568 setErrorResponse(transaction->res,
1569 boost::beast::http::status::not_found,
1570 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001571 return;
1572 }
1573
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001574 BMCWEB_LOG_DEBUG << "GetObject returned " << interfaceNames.size()
1575 << " object(s)";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001576
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001577 for (const std::pair<std::string, std::vector<std::string>>&
1578 object : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001579 {
1580 findActionOnInterface(transaction, object.first);
1581 }
1582 },
1583 "xyz.openbmc_project.ObjectMapper",
1584 "/xyz/openbmc_project/object_mapper",
1585 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
1586 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001587}
1588
zhanghch058d1b46d2021-04-01 11:18:24 +08001589inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1590 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001591{
1592 BMCWEB_LOG_DEBUG << "handleDelete on path: " << objectPath;
1593
1594 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +08001595 [asyncResp, objectPath](
Matt Spinlerde818812018-12-11 16:39:20 -06001596 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001597 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1598 interfaceNames) {
Ed Tanous26f69762022-01-25 09:49:11 -08001599 if (ec || interfaceNames.empty())
Matt Spinlerde818812018-12-11 16:39:20 -06001600 {
1601 BMCWEB_LOG_ERROR << "Can't find object";
zhanghch058d1b46d2021-04-01 11:18:24 +08001602 setErrorResponse(asyncResp->res,
Matt Spinler62d2e8b2019-01-22 13:45:51 -06001603 boost::beast::http::status::method_not_allowed,
1604 methodNotAllowedDesc, methodNotAllowedMsg);
Matt Spinlerde818812018-12-11 16:39:20 -06001605 return;
1606 }
1607
zhanghch058d1b46d2021-04-01 11:18:24 +08001608 auto transaction =
1609 std::make_shared<InProgressActionData>(asyncResp->res);
Matt Spinlerde818812018-12-11 16:39:20 -06001610 transaction->path = objectPath;
1611 transaction->methodName = "Delete";
1612 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
1613
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001614 for (const std::pair<std::string, std::vector<std::string>>&
1615 object : interfaceNames)
Matt Spinlerde818812018-12-11 16:39:20 -06001616 {
1617 findActionOnInterface(transaction, object.first);
1618 }
1619 },
1620 "xyz.openbmc_project.ObjectMapper",
1621 "/xyz/openbmc_project/object_mapper",
1622 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001623 std::array<const char*, 0>());
Matt Spinlerde818812018-12-11 16:39:20 -06001624}
1625
zhanghch058d1b46d2021-04-01 11:18:24 +08001626inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1627 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001628{
1629 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +08001630 [asyncResp](const boost::system::error_code ec,
Ed Tanous914e2d52022-01-07 11:38:34 -08001631 const std::vector<std::string>& objectPaths) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001632 if (ec)
1633 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001634 setErrorResponse(asyncResp->res,
1635 boost::beast::http::status::not_found,
Matt Spinlerd6091dd2018-12-06 14:08:27 -06001636 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001637 }
1638 else
1639 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001640 asyncResp->res.jsonValue = {{"status", "ok"},
1641 {"message", "200 OK"},
Ed Tanous914e2d52022-01-07 11:38:34 -08001642 {"data", objectPaths}};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001643 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001644 },
1645 "xyz.openbmc_project.ObjectMapper",
1646 "/xyz/openbmc_project/object_mapper",
1647 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", objectPath,
Ed Tanousf839dfe2018-11-12 11:11:15 -08001648 depth, std::array<std::string, 0>());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001649}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001650
zhanghch058d1b46d2021-04-01 11:18:24 +08001651inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1652 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001653{
Ed Tanous049a0512018-11-01 13:58:42 -07001654 BMCWEB_LOG_DEBUG << "Doing enumerate on " << objectPath;
Ed Tanous049a0512018-11-01 13:58:42 -07001655
1656 asyncResp->res.jsonValue = {{"message", "200 OK"},
1657 {"status", "ok"},
1658 {"data", nlohmann::json::object()}};
1659
Ed Tanous1abe55e2018-09-05 08:30:59 -07001660 crow::connections::systemBus->async_method_call(
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001661 [objectPath, asyncResp](const boost::system::error_code ec,
Ed Tanous914e2d52022-01-07 11:38:34 -08001662 const GetSubTreeType& objectNames) {
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001663 auto transaction = std::make_shared<InProgressEnumerateData>(
1664 objectPath, asyncResp);
1665
1666 transaction->subtree =
Ed Tanous914e2d52022-01-07 11:38:34 -08001667 std::make_shared<GetSubTreeType>(objectNames);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001668
Ed Tanous1abe55e2018-09-05 08:30:59 -07001669 if (ec)
1670 {
Matt Spinler2ae60092018-12-06 10:35:36 -06001671 BMCWEB_LOG_ERROR << "GetSubTree failed on "
1672 << transaction->objectPath;
1673 setErrorResponse(transaction->asyncResp->res,
1674 boost::beast::http::status::not_found,
1675 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001676 return;
1677 }
Ed Tanous64530012018-02-06 17:08:16 -08001678
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001679 // Add the data for the path passed in to the results
1680 // as if GetSubTree returned it, and continue on enumerating
1681 getObjectAndEnumerate(transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001682 },
1683 "xyz.openbmc_project.ObjectMapper",
1684 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -07001685 "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath, 0,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001686 std::array<const char*, 0>());
Ed Tanous64530012018-02-06 17:08:16 -08001687}
Ed Tanous911ac312017-08-15 09:37:42 -07001688
zhanghch058d1b46d2021-04-01 11:18:24 +08001689inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1690 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001691{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001692 BMCWEB_LOG_DEBUG << "handleGet: " << objectPath << " prop:" << destProperty;
1693 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001694 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001695
Ed Tanous1abe55e2018-09-05 08:30:59 -07001696 std::shared_ptr<std::string> path =
1697 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001698
Ed Tanous1abe55e2018-09-05 08:30:59 -07001699 using GetObjectType =
1700 std::vector<std::pair<std::string, std::vector<std::string>>>;
1701 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +08001702 [asyncResp, path, propertyName](const boost::system::error_code ec,
1703 const GetObjectType& objectNames) {
Ed Tanous26f69762022-01-25 09:49:11 -08001704 if (ec || objectNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001705 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001706 setErrorResponse(asyncResp->res,
1707 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001708 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001709 return;
1710 }
1711 std::shared_ptr<nlohmann::json> response =
1712 std::make_shared<nlohmann::json>(nlohmann::json::object());
Ed Tanous7c091622019-05-23 11:42:36 -07001713 // The mapper should never give us an empty interface names
1714 // list, but check anyway
Ed Tanous23a21a12020-07-25 04:45:05 +00001715 for (const std::pair<std::string, std::vector<std::string>>&
Ed Tanous81ce6092020-12-17 16:54:55 +00001716 connection : objectNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001717 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001718 const std::vector<std::string>& interfaceNames =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001719 connection.second;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001720
Ed Tanous26f69762022-01-25 09:49:11 -08001721 if (interfaceNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001722 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001723 setErrorResponse(asyncResp->res,
1724 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001725 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001726 return;
1727 }
1728
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001729 for (const std::string& interface : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001730 {
Matt Spinlerfe7e97d2019-01-30 15:33:21 -06001731 sdbusplus::message::message m =
1732 crow::connections::systemBus->new_method_call(
1733 connection.first.c_str(), path->c_str(),
1734 "org.freedesktop.DBus.Properties", "GetAll");
1735 m.append(interface);
1736 crow::connections::systemBus->async_send(
zhanghch058d1b46d2021-04-01 11:18:24 +08001737 m, [asyncResp, response,
Ed Tanous23a21a12020-07-25 04:45:05 +00001738 propertyName](const boost::system::error_code ec2,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001739 sdbusplus::message::message& msg) {
Ed Tanous23a21a12020-07-25 04:45:05 +00001740 if (ec2)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001741 {
1742 BMCWEB_LOG_ERROR << "Bad dbus request error: "
Ed Tanous23a21a12020-07-25 04:45:05 +00001743 << ec2;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001744 }
1745 else
1746 {
Ed Tanous984a4c22021-06-02 13:38:26 -07001747 nlohmann::json properties;
1748 int r =
1749 convertDBusToJSON("a{sv}", msg, properties);
1750 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001751 {
Ed Tanous984a4c22021-06-02 13:38:26 -07001752 BMCWEB_LOG_ERROR
1753 << "convertDBusToJSON failed";
1754 }
1755 else
1756 {
1757 for (auto& prop : properties.items())
1758 {
1759 // if property name is empty, or
1760 // matches our search query, add it
1761 // to the response json
Ed Tanous1abe55e2018-09-05 08:30:59 -07001762
Ed Tanous984a4c22021-06-02 13:38:26 -07001763 if (propertyName->empty())
1764 {
1765 (*response)[prop.key()] =
1766 std::move(prop.value());
1767 }
1768 else if (prop.key() == *propertyName)
1769 {
1770 *response = std::move(prop.value());
1771 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001772 }
1773 }
1774 }
1775 if (response.use_count() == 1)
1776 {
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001777 if (!propertyName->empty() && response->empty())
1778 {
1779 setErrorResponse(
zhanghch058d1b46d2021-04-01 11:18:24 +08001780 asyncResp->res,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001781 boost::beast::http::status::not_found,
1782 propNotFoundDesc, notFoundMsg);
1783 }
1784 else
1785 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001786 asyncResp->res.jsonValue = {
1787 {"status", "ok"},
1788 {"message", "200 OK"},
1789 {"data", *response}};
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001790 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001791 }
Matt Spinlerfe7e97d2019-01-30 15:33:21 -06001792 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001793 }
1794 }
1795 },
1796 "xyz.openbmc_project.ObjectMapper",
1797 "/xyz/openbmc_project/object_mapper",
1798 "xyz.openbmc_project.ObjectMapper", "GetObject", *path,
1799 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001800}
1801
Ed Tanous1abe55e2018-09-05 08:30:59 -07001802struct AsyncPutRequest
1803{
zhanghch058d1b46d2021-04-01 11:18:24 +08001804 AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
1805 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001806 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001807 ~AsyncPutRequest()
1808 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001809 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001810 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001811 setErrorResponse(asyncResp->res,
1812 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001813 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001814 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001815 }
1816
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001817 AsyncPutRequest(const AsyncPutRequest&) = delete;
1818 AsyncPutRequest(AsyncPutRequest&&) = delete;
1819 AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1820 AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1821
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001822 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001823 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001824 setErrorResponse(asyncResp->res,
1825 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001826 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001827 }
1828
zhanghch058d1b46d2021-04-01 11:18:24 +08001829 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001830 std::string objectPath;
1831 std::string propertyName;
1832 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001833};
1834
zhanghch058d1b46d2021-04-01 11:18:24 +08001835inline void handlePut(const crow::Request& req,
1836 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001837 const std::string& objectPath,
1838 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001839{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001840 if (destProperty.empty())
1841 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001842 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001843 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001844 return;
1845 }
1846
Ed Tanous1abe55e2018-09-05 08:30:59 -07001847 nlohmann::json requestDbusData =
1848 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001849
Ed Tanous1abe55e2018-09-05 08:30:59 -07001850 if (requestDbusData.is_discarded())
1851 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001852 setErrorResponse(asyncResp->res,
1853 boost::beast::http::status::bad_request, noJsonDesc,
1854 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001855 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001856 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001857
Ed Tanous1abe55e2018-09-05 08:30:59 -07001858 nlohmann::json::const_iterator propertyIt = requestDbusData.find("data");
1859 if (propertyIt == requestDbusData.end())
1860 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001861 setErrorResponse(asyncResp->res,
1862 boost::beast::http::status::bad_request, noJsonDesc,
1863 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001864 return;
1865 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001866 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001867 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001868 transaction->objectPath = objectPath;
1869 transaction->propertyName = destProperty;
1870 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001871
Ed Tanous1abe55e2018-09-05 08:30:59 -07001872 using GetObjectType =
1873 std::vector<std::pair<std::string, std::vector<std::string>>>;
Ed Tanous911ac312017-08-15 09:37:42 -07001874
Ed Tanous1abe55e2018-09-05 08:30:59 -07001875 crow::connections::systemBus->async_method_call(
Ed Tanous23a21a12020-07-25 04:45:05 +00001876 [transaction](const boost::system::error_code ec2,
Ed Tanous81ce6092020-12-17 16:54:55 +00001877 const GetObjectType& objectNames) {
Ed Tanous26f69762022-01-25 09:49:11 -08001878 if (!ec2 && objectNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001879 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001880 setErrorResponse(transaction->asyncResp->res,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001881 boost::beast::http::status::not_found,
1882 propNotFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001883 return;
1884 }
Ed Tanous911ac312017-08-15 09:37:42 -07001885
Ed Tanous23a21a12020-07-25 04:45:05 +00001886 for (const std::pair<std::string, std::vector<std::string>>&
Ed Tanous81ce6092020-12-17 16:54:55 +00001887 connection : objectNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001888 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001889 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001890
Ed Tanous1abe55e2018-09-05 08:30:59 -07001891 crow::connections::systemBus->async_method_call(
1892 [connectionName{std::string(connectionName)},
Ed Tanous23a21a12020-07-25 04:45:05 +00001893 transaction](const boost::system::error_code ec3,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001894 const std::string& introspectXml) {
Ed Tanous23a21a12020-07-25 04:45:05 +00001895 if (ec3)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001896 {
1897 BMCWEB_LOG_ERROR
1898 << "Introspect call failed with error: "
Ed Tanous23a21a12020-07-25 04:45:05 +00001899 << ec3.message()
Ed Tanous1abe55e2018-09-05 08:30:59 -07001900 << " on process: " << connectionName;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001901 transaction->setErrorStatus("Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001902 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001903 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001904 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001905
Ed Tanous1abe55e2018-09-05 08:30:59 -07001906 doc.Parse(introspectXml.c_str());
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001907 tinyxml2::XMLNode* pRoot =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001908 doc.FirstChildElement("node");
1909 if (pRoot == nullptr)
1910 {
1911 BMCWEB_LOG_ERROR << "XML document failed to parse: "
1912 << introspectXml;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001913 transaction->setErrorStatus("Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001914 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001915 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001916 tinyxml2::XMLElement* ifaceNode =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001917 pRoot->FirstChildElement("interface");
1918 while (ifaceNode != nullptr)
1919 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001920 const char* interfaceName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001921 ifaceNode->Attribute("name");
1922 BMCWEB_LOG_DEBUG << "found interface "
1923 << interfaceName;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001924 tinyxml2::XMLElement* propNode =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001925 ifaceNode->FirstChildElement("property");
1926 while (propNode != nullptr)
1927 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001928 const char* propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001929 propNode->Attribute("name");
1930 BMCWEB_LOG_DEBUG << "Found property "
1931 << propertyName;
1932 if (propertyName == transaction->propertyName)
1933 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001934 const char* argType =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001935 propNode->Attribute("type");
1936 if (argType != nullptr)
1937 {
1938 sdbusplus::message::message m =
1939 crow::connections::systemBus
1940 ->new_method_call(
1941 connectionName.c_str(),
1942 transaction->objectPath
1943 .c_str(),
1944 "org.freedesktop.DBus."
1945 "Properties",
1946 "Set");
1947 m.append(interfaceName,
1948 transaction->propertyName);
1949 int r = sd_bus_message_open_container(
1950 m.get(), SD_BUS_TYPE_VARIANT,
1951 argType);
1952 if (r < 0)
1953 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001954 transaction->setErrorStatus(
1955 "Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001956 return;
1957 }
1958 r = convertJsonToDbus(
1959 m.get(), argType,
1960 transaction->propertyValue);
1961 if (r < 0)
1962 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -05001963 if (r == -ERANGE)
1964 {
1965 transaction->setErrorStatus(
1966 "Provided property value "
1967 "is out of range for the "
1968 "property type");
1969 }
1970 else
1971 {
1972 transaction->setErrorStatus(
1973 "Invalid arg type");
1974 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001975 return;
1976 }
1977 r = sd_bus_message_close_container(
1978 m.get());
1979 if (r < 0)
1980 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001981 transaction->setErrorStatus(
1982 "Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001983 return;
1984 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001985 crow::connections::systemBus
1986 ->async_send(
1987 m,
1988 [transaction](
1989 boost::system::error_code
1990 ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001991 sdbusplus::message::message&
Ed Tanous23a21a12020-07-25 04:45:05 +00001992 m2) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001993 BMCWEB_LOG_DEBUG << "sent";
1994 if (ec)
1995 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001996 const sd_bus_error* e =
Ed Tanous23a21a12020-07-25 04:45:05 +00001997 m2.get_error();
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001998 setErrorResponse(
zhanghch058d1b46d2021-04-01 11:18:24 +08001999 transaction
2000 ->asyncResp
2001 ->res,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06002002 boost::beast::http::
2003 status::
2004 forbidden,
Matt Spinler06b1b632019-06-18 16:09:25 -05002005 (e) ? e->name
2006 : ec.category()
2007 .name(),
2008 (e) ? e->message
2009 : ec.message());
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06002010 }
2011 else
2012 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002013 transaction->asyncResp
2014 ->res.jsonValue = {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06002015 {"status", "ok"},
2016 {"message",
2017 "200 OK"},
2018 {"data", nullptr}};
Ed Tanous1abe55e2018-09-05 08:30:59 -07002019 }
2020 });
2021 }
2022 }
2023 propNode =
2024 propNode->NextSiblingElement("property");
2025 }
2026 ifaceNode =
2027 ifaceNode->NextSiblingElement("interface");
2028 }
2029 },
2030 connectionName, transaction->objectPath,
2031 "org.freedesktop.DBus.Introspectable", "Introspect");
2032 }
2033 },
2034 "xyz.openbmc_project.ObjectMapper",
2035 "/xyz/openbmc_project/object_mapper",
2036 "xyz.openbmc_project.ObjectMapper", "GetObject",
2037 transaction->objectPath, std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07002038}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002039
zhanghch058d1b46d2021-04-01 11:18:24 +08002040inline void handleDBusUrl(const crow::Request& req,
2041 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002042 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002043{
Ed Tanous049a0512018-11-01 13:58:42 -07002044
2045 // If accessing a single attribute, fill in and update objectPath,
2046 // otherwise leave destProperty blank
Ed Tanouse05aec52022-01-25 10:28:56 -08002047 std::string destProperty;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002048 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002049 size_t attrPosition = objectPath.find(attrSeperator);
2050 if (attrPosition != objectPath.npos)
2051 {
2052 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2053 objectPath.length());
2054 objectPath = objectPath.substr(0, attrPosition);
2055 }
2056
Ed Tanousb41187f2019-10-24 16:30:02 -07002057 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002058 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002059 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002060 size_t actionPosition = objectPath.find(actionSeperator);
2061 if (actionPosition != objectPath.npos)
2062 {
2063 std::string postProperty =
2064 objectPath.substr((actionPosition + strlen(actionSeperator)),
2065 objectPath.length());
2066 objectPath = objectPath.substr(0, actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002067 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002068 return;
2069 }
2070 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002071 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002072 {
2073 if (boost::ends_with(objectPath, "/enumerate"))
2074 {
2075 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2076 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002077 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002078 }
2079 else if (boost::ends_with(objectPath, "/list"))
2080 {
2081 objectPath.erase(objectPath.end() - sizeof("list"),
2082 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002083 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002084 }
2085 else
2086 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002087 // Trim any trailing "/" at the end
2088 if (boost::ends_with(objectPath, "/"))
2089 {
2090 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002091 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002092 }
2093 else
2094 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002095 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002096 }
Ed Tanous049a0512018-11-01 13:58:42 -07002097 }
2098 return;
2099 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002100 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002101 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002102 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002103 return;
2104 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002105 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002106 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002107 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002108 return;
2109 }
Ed Tanous049a0512018-11-01 13:58:42 -07002110
zhanghch058d1b46d2021-04-01 11:18:24 +08002111 setErrorResponse(asyncResp->res,
2112 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002113 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002114}
2115
Ed Tanous23a21a12020-07-25 04:45:05 +00002116inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002117{
2118 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002119 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002120 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002121 [](const crow::Request&,
2122 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2123 asyncResp->res.jsonValue = {{"buses", {{{"name", "system"}}}},
2124 {"status", "ok"}};
Ed Tanous1abe55e2018-09-05 08:30:59 -07002125 });
2126
2127 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002128 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002129 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002130 [](const crow::Request&,
2131 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
P Dheeraj Srujan Kumar83fd8e12021-07-13 02:53:03 +05302132 auto myCallback = [asyncResp](
zhanghch058d1b46d2021-04-01 11:18:24 +08002133 const boost::system::error_code ec,
2134 std::vector<std::string>& names) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07002135 if (ec)
2136 {
2137 BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +08002138 asyncResp->res.result(
Ed Tanous1abe55e2018-09-05 08:30:59 -07002139 boost::beast::http::status::internal_server_error);
2140 }
2141 else
2142 {
2143 std::sort(names.begin(), names.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002144 asyncResp->res.jsonValue = {{"status", "ok"}};
2145 auto& objectsSub = asyncResp->res.jsonValue["objects"];
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002146 for (auto& name : names)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002147 {
2148 objectsSub.push_back({{"name", name}});
2149 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002150 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002151 };
2152 crow::connections::systemBus->async_method_call(
2153 std::move(myCallback), "org.freedesktop.DBus", "/",
2154 "org.freedesktop.DBus", "ListNames");
2155 });
2156
2157 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002158 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002159 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002160 [](const crow::Request&,
2161 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2162 handleList(asyncResp, "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07002163 });
2164
2165 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002166 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002167 .methods(boost::beast::http::verb::get)(
2168 [](const crow::Request& req,
2169 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002170 const std::string& path) {
Ed Tanous049a0512018-11-01 13:58:42 -07002171 std::string objectPath = "/xyz/" + path;
zhanghch058d1b46d2021-04-01 11:18:24 +08002172 handleDBusUrl(req, asyncResp, objectPath);
2173 });
2174
2175 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002176 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002177 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2178 boost::beast::http::verb::delete_)(
2179 [](const crow::Request& req,
2180 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2181 const std::string& path) {
2182 std::string objectPath = "/xyz/" + path;
2183 handleDBusUrl(req, asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002184 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002185
Ed Tanous049a0512018-11-01 13:58:42 -07002186 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002187 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002188 .methods(boost::beast::http::verb::get)(
2189 [](const crow::Request& req,
2190 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2191 const std::string& path) {
2192 std::string objectPath = "/org/" + path;
2193 handleDBusUrl(req, asyncResp, objectPath);
2194 });
Tanousf00032d2018-11-05 01:18:10 -03002195
2196 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002197 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002198 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2199 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002200 [](const crow::Request& req,
2201 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002202 const std::string& path) {
Ed Tanouse1281402019-04-03 07:07:10 -07002203 std::string objectPath = "/org/" + path;
zhanghch058d1b46d2021-04-01 11:18:24 +08002204 handleDBusUrl(req, asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002205 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002206
Ed Tanous1abe55e2018-09-05 08:30:59 -07002207 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002208 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002209 .methods(boost::beast::http::verb::get)(
2210 [](const crow::Request&,
2211 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2212 const std::string& dumpId) {
2213 std::regex validFilename(R"(^[\w\- ]+(\.?[\w\- ]*)$)");
2214 if (!std::regex_match(dumpId, validFilename))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002215 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002216 asyncResp->res.result(
2217 boost::beast::http::status::bad_request);
Ramesh Iyyard9207042019-07-05 08:04:42 -05002218 return;
2219 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002220 std::filesystem::path loc(
2221 "/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002222
zhanghch058d1b46d2021-04-01 11:18:24 +08002223 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002224
zhanghch058d1b46d2021-04-01 11:18:24 +08002225 if (!std::filesystem::exists(loc) ||
2226 !std::filesystem::is_directory(loc))
2227 {
2228 BMCWEB_LOG_ERROR << loc << "Not found";
2229 asyncResp->res.result(
2230 boost::beast::http::status::not_found);
2231 return;
2232 }
2233 std::filesystem::directory_iterator files(loc);
2234
Ed Tanous9eb808c2022-01-25 10:19:23 -08002235 for (const auto& file : files)
zhanghch058d1b46d2021-04-01 11:18:24 +08002236 {
2237 std::ifstream readFile(file.path());
2238 if (!readFile.good())
2239 {
2240 continue;
2241 }
2242
2243 asyncResp->res.addHeader("Content-Type",
2244 "application/octet-stream");
2245
2246 // Assuming only one dump file will be present in the dump
2247 // id directory
2248 std::string dumpFileName = file.path().filename().string();
2249
2250 // Filename should be in alphanumeric, dot and underscore
2251 // Its based on phosphor-debug-collector application
2252 // dumpfile format
2253 std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
2254 if (!std::regex_match(dumpFileName, dumpFileRegex))
2255 {
2256 BMCWEB_LOG_ERROR << "Invalid dump filename "
2257 << dumpFileName;
2258 asyncResp->res.result(
2259 boost::beast::http::status::not_found);
2260 return;
2261 }
2262 std::string contentDispositionParam =
2263 "attachment; filename=\"" + dumpFileName + "\"";
2264
2265 asyncResp->res.addHeader("Content-Disposition",
2266 contentDispositionParam);
2267
2268 asyncResp->res.body() = {
2269 std::istreambuf_iterator<char>(readFile),
2270 std::istreambuf_iterator<char>()};
2271 return;
2272 }
2273 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002274 return;
zhanghch058d1b46d2021-04-01 11:18:24 +08002275 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002276
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002277 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002278 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002279
2280 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002281 [](const crow::Request&,
2282 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002283 const std::string& connection) {
Gunnar Mills9062d472021-11-16 11:37:47 -06002284 introspectObjects(
2285 connection, "/",
2286 std::make_shared<bmcweb::AsyncResp>(asyncResp->res));
Ed Tanousb41187f2019-10-24 16:30:02 -07002287 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002288
2289 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002290 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002291 .methods(boost::beast::http::verb::get, boost::beast::http::verb::post)(
2292 [](const crow::Request& req,
2293 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2294 const std::string& processName,
2295 const std::string& requestedPath) {
2296 std::vector<std::string> strs;
2297 boost::split(strs, requestedPath, boost::is_any_of("/"));
2298 std::string objectPath;
2299 std::string interfaceName;
2300 std::string methodName;
2301 auto it = strs.begin();
2302 if (it == strs.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -07002303 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002304 objectPath = "/";
Ed Tanous1abe55e2018-09-05 08:30:59 -07002305 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002306 while (it != strs.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -07002307 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002308 // Check if segment contains ".". If it does, it must be an
2309 // interface
2310 if (it->find(".") != std::string::npos)
2311 {
2312 break;
2313 // This check is necessary as the trailing slash gets
2314 // parsed as part of our <path> specifier above, which
2315 // causes the normal trailing backslash redirector to
2316 // fail.
2317 }
2318 if (!it->empty())
2319 {
2320 objectPath += "/" + *it;
2321 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002322 it++;
2323 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002324 if (it != strs.end())
2325 {
2326 interfaceName = *it;
2327 it++;
Ed Tanous7c091622019-05-23 11:42:36 -07002328
zhanghch058d1b46d2021-04-01 11:18:24 +08002329 // after interface, we might have a method name
2330 if (it != strs.end())
2331 {
2332 methodName = *it;
2333 it++;
2334 }
2335 }
2336 if (it != strs.end())
2337 {
2338 // if there is more levels past the method name, something
2339 // went wrong, return not found
2340 asyncResp->res.result(
2341 boost::beast::http::status::not_found);
2342 return;
2343 }
2344 if (interfaceName.empty())
2345 {
2346 crow::connections::systemBus->async_method_call(
2347 [asyncResp, processName,
2348 objectPath](const boost::system::error_code ec,
2349 const std::string& introspectXml) {
2350 if (ec)
2351 {
2352 BMCWEB_LOG_ERROR
2353 << "Introspect call failed with error: "
2354 << ec.message()
2355 << " on process: " << processName
2356 << " path: " << objectPath << "\n";
2357 return;
2358 }
2359 tinyxml2::XMLDocument doc;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002360
zhanghch058d1b46d2021-04-01 11:18:24 +08002361 doc.Parse(introspectXml.c_str());
2362 tinyxml2::XMLNode* pRoot =
2363 doc.FirstChildElement("node");
2364 if (pRoot == nullptr)
2365 {
2366 BMCWEB_LOG_ERROR
2367 << "XML document failed to parse "
2368 << processName << " " << objectPath << "\n";
2369 asyncResp->res.jsonValue = {
2370 {"status", "XML parse error"}};
2371 asyncResp->res.result(
2372 boost::beast::http::status::
2373 internal_server_error);
2374 return;
2375 }
2376
2377 BMCWEB_LOG_DEBUG << introspectXml;
Ed Tanous7c091622019-05-23 11:42:36 -07002378 asyncResp->res.jsonValue = {
zhanghch058d1b46d2021-04-01 11:18:24 +08002379 {"status", "ok"},
2380 {"bus_name", processName},
2381 {"object_path", objectPath}};
2382 nlohmann::json& interfacesArray =
2383 asyncResp->res.jsonValue["interfaces"];
2384 interfacesArray = nlohmann::json::array();
2385 tinyxml2::XMLElement* interface =
2386 pRoot->FirstChildElement("interface");
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002387
zhanghch058d1b46d2021-04-01 11:18:24 +08002388 while (interface != nullptr)
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002389 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002390 const char* ifaceName =
2391 interface->Attribute("name");
2392 if (ifaceName != nullptr)
Ed Tanous7c091622019-05-23 11:42:36 -07002393 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002394 interfacesArray.push_back(
2395 {{"name", ifaceName}});
2396 }
2397
2398 interface =
2399 interface->NextSiblingElement("interface");
2400 }
2401 },
2402 processName, objectPath,
2403 "org.freedesktop.DBus.Introspectable", "Introspect");
2404 }
2405 else if (methodName.empty())
2406 {
2407 crow::connections::systemBus->async_method_call(
2408 [asyncResp, processName, objectPath,
2409 interfaceName](const boost::system::error_code ec,
2410 const std::string& introspectXml) {
2411 if (ec)
2412 {
2413 BMCWEB_LOG_ERROR
2414 << "Introspect call failed with error: "
2415 << ec.message()
2416 << " on process: " << processName
2417 << " path: " << objectPath << "\n";
2418 return;
2419 }
2420 tinyxml2::XMLDocument doc;
2421
2422 doc.Parse(introspectXml.data(),
2423 introspectXml.size());
2424 tinyxml2::XMLNode* pRoot =
2425 doc.FirstChildElement("node");
2426 if (pRoot == nullptr)
2427 {
2428 BMCWEB_LOG_ERROR
2429 << "XML document failed to parse "
2430 << processName << " " << objectPath << "\n";
2431 asyncResp->res.result(
2432 boost::beast::http::status::
2433 internal_server_error);
2434 return;
2435 }
2436 asyncResp->res.jsonValue = {
2437 {"status", "ok"},
2438 {"bus_name", processName},
2439 {"interface", interfaceName},
2440 {"object_path", objectPath}};
2441
2442 nlohmann::json& methodsArray =
2443 asyncResp->res.jsonValue["methods"];
2444 methodsArray = nlohmann::json::array();
2445
2446 nlohmann::json& signalsArray =
2447 asyncResp->res.jsonValue["signals"];
2448 signalsArray = nlohmann::json::array();
2449
2450 nlohmann::json& propertiesObj =
2451 asyncResp->res.jsonValue["properties"];
2452 propertiesObj = nlohmann::json::object();
2453
2454 // if we know we're the only call, build the
2455 // json directly
2456 tinyxml2::XMLElement* interface =
2457 pRoot->FirstChildElement("interface");
2458 while (interface != nullptr)
2459 {
2460 const char* ifaceName =
2461 interface->Attribute("name");
2462
2463 if (ifaceName != nullptr &&
2464 ifaceName == interfaceName)
2465 {
2466 break;
2467 }
2468
2469 interface =
2470 interface->NextSiblingElement("interface");
2471 }
2472 if (interface == nullptr)
2473 {
2474 // if we got to the end of the list and
2475 // never found a match, throw 404
2476 asyncResp->res.result(
2477 boost::beast::http::status::not_found);
2478 return;
2479 }
2480
2481 tinyxml2::XMLElement* methods =
2482 interface->FirstChildElement("method");
2483 while (methods != nullptr)
2484 {
2485 nlohmann::json argsArray =
2486 nlohmann::json::array();
2487 tinyxml2::XMLElement* arg =
2488 methods->FirstChildElement("arg");
2489 while (arg != nullptr)
2490 {
2491 nlohmann::json thisArg;
2492 for (const char* fieldName :
2493 std::array<const char*, 3>{
2494 "name", "direction", "type"})
Ed Tanous7c091622019-05-23 11:42:36 -07002495 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002496 const char* fieldValue =
2497 arg->Attribute(fieldName);
2498 if (fieldValue != nullptr)
Ed Tanous7c091622019-05-23 11:42:36 -07002499 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002500 thisArg[fieldName] = fieldValue;
Ed Tanous7c091622019-05-23 11:42:36 -07002501 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002502 }
2503 argsArray.push_back(std::move(thisArg));
2504 arg = arg->NextSiblingElement("arg");
2505 }
Ed Tanous7c091622019-05-23 11:42:36 -07002506
zhanghch058d1b46d2021-04-01 11:18:24 +08002507 const char* name = methods->Attribute("name");
2508 if (name != nullptr)
2509 {
2510 std::string uri;
2511 uri.reserve(14 + processName.size() +
2512 objectPath.size() +
2513 interfaceName.size() +
2514 strlen(name));
2515 uri += "/bus/system/";
2516 uri += processName;
2517 uri += objectPath;
2518 uri += "/";
2519 uri += interfaceName;
2520 uri += "/";
2521 uri += name;
2522 methodsArray.push_back(
2523 {{"name", name},
2524 {"uri", std::move(uri)},
2525 {"args", argsArray}});
2526 }
2527 methods = methods->NextSiblingElement("method");
Ed Tanous7c091622019-05-23 11:42:36 -07002528 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002529 tinyxml2::XMLElement* signals =
2530 interface->FirstChildElement("signal");
2531 while (signals != nullptr)
2532 {
2533 nlohmann::json argsArray =
2534 nlohmann::json::array();
2535
2536 tinyxml2::XMLElement* arg =
2537 signals->FirstChildElement("arg");
2538 while (arg != nullptr)
2539 {
2540 const char* name = arg->Attribute("name");
2541 const char* type = arg->Attribute("type");
2542 if (name != nullptr && type != nullptr)
2543 {
2544 argsArray.push_back({
2545 {"name", name},
2546 {"type", type},
2547 });
2548 }
2549 arg = arg->NextSiblingElement("arg");
2550 }
2551 const char* name = signals->Attribute("name");
2552 if (name != nullptr)
2553 {
2554 signalsArray.push_back(
2555 {{"name", name}, {"args", argsArray}});
2556 }
2557
2558 signals = signals->NextSiblingElement("signal");
2559 }
2560
2561 tinyxml2::XMLElement* property =
2562 interface->FirstChildElement("property");
2563 while (property != nullptr)
2564 {
2565 const char* name = property->Attribute("name");
2566 const char* type = property->Attribute("type");
2567 if (type != nullptr && name != nullptr)
2568 {
2569 sdbusplus::message::message m =
2570 crow::connections::systemBus
2571 ->new_method_call(
2572 processName.c_str(),
2573 objectPath.c_str(),
2574 "org.freedesktop."
2575 "DBus."
2576 "Properties",
2577 "Get");
2578 m.append(interfaceName, name);
2579 nlohmann::json& propertyItem =
2580 propertiesObj[name];
2581 crow::connections::systemBus->async_send(
2582 m,
2583 [&propertyItem, asyncResp](
2584 boost::system::error_code& e,
2585 sdbusplus::message::message& msg) {
2586 if (e)
2587 {
2588 return;
2589 }
2590
2591 convertDBusToJSON("v", msg,
2592 propertyItem);
2593 });
2594 }
2595 property =
2596 property->NextSiblingElement("property");
2597 }
2598 },
2599 processName, objectPath,
2600 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002601 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002602 else
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002603 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002604 if (req.method() != boost::beast::http::verb::post)
2605 {
2606 asyncResp->res.result(
2607 boost::beast::http::status::not_found);
2608 return;
2609 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002610
zhanghch058d1b46d2021-04-01 11:18:24 +08002611 nlohmann::json requestDbusData =
2612 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002613
zhanghch058d1b46d2021-04-01 11:18:24 +08002614 if (requestDbusData.is_discarded())
2615 {
2616 asyncResp->res.result(
2617 boost::beast::http::status::bad_request);
2618 return;
2619 }
2620 if (!requestDbusData.is_array())
2621 {
2622 asyncResp->res.result(
2623 boost::beast::http::status::bad_request);
2624 return;
2625 }
2626 auto transaction =
2627 std::make_shared<InProgressActionData>(asyncResp->res);
2628
2629 transaction->path = objectPath;
2630 transaction->methodName = methodName;
2631 transaction->arguments = std::move(requestDbusData);
2632
2633 findActionOnInterface(transaction, processName);
2634 }
2635 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002636}
2637} // namespace openbmc_mapper
2638} // namespace crow