blob: cb5d727a25bb8f43ea058addda793d366411c04f [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 Tanouse662eae2022-01-25 10:39:19 -0800659 int boolInt = 0;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700660 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700661 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500662 if (*intValue == 1)
663 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800664 boolInt = 1;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500665 }
666 else if (*intValue == 0)
667 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800668 boolInt = 0;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500669 }
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 {
Ed Tanouse662eae2022-01-25 10:39:19 -08001028 r = sd_bus_message_at_end(m.get(), 0);
Matt Spinler6df8f992019-01-14 12:47:47 -06001029 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
Ed Tanouse662eae2022-01-25 10:39:19 -08001486 if (e != nullptr)
Matt Spinler06b1b632019-06-18 16:09:25 -05001487 {
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,
Ed Tanouse662eae2022-01-25 10:39:19 -08002005 (e) != nullptr
2006 ? e->name
Matt Spinler06b1b632019-06-18 16:09:25 -05002007 : ec.category()
2008 .name(),
Ed Tanouse662eae2022-01-25 10:39:19 -08002009 (e) != nullptr
2010 ? e->message
Matt Spinler06b1b632019-06-18 16:09:25 -05002011 : ec.message());
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06002012 }
2013 else
2014 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002015 transaction->asyncResp
2016 ->res.jsonValue = {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06002017 {"status", "ok"},
2018 {"message",
2019 "200 OK"},
2020 {"data", nullptr}};
Ed Tanous1abe55e2018-09-05 08:30:59 -07002021 }
2022 });
2023 }
2024 }
2025 propNode =
2026 propNode->NextSiblingElement("property");
2027 }
2028 ifaceNode =
2029 ifaceNode->NextSiblingElement("interface");
2030 }
2031 },
2032 connectionName, transaction->objectPath,
2033 "org.freedesktop.DBus.Introspectable", "Introspect");
2034 }
2035 },
2036 "xyz.openbmc_project.ObjectMapper",
2037 "/xyz/openbmc_project/object_mapper",
2038 "xyz.openbmc_project.ObjectMapper", "GetObject",
2039 transaction->objectPath, std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07002040}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002041
zhanghch058d1b46d2021-04-01 11:18:24 +08002042inline void handleDBusUrl(const crow::Request& req,
2043 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002044 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002045{
Ed Tanous049a0512018-11-01 13:58:42 -07002046
2047 // If accessing a single attribute, fill in and update objectPath,
2048 // otherwise leave destProperty blank
Ed Tanouse05aec52022-01-25 10:28:56 -08002049 std::string destProperty;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002050 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002051 size_t attrPosition = objectPath.find(attrSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002052 if (attrPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002053 {
2054 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2055 objectPath.length());
2056 objectPath = objectPath.substr(0, attrPosition);
2057 }
2058
Ed Tanousb41187f2019-10-24 16:30:02 -07002059 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002060 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002061 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002062 size_t actionPosition = objectPath.find(actionSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002063 if (actionPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002064 {
2065 std::string postProperty =
2066 objectPath.substr((actionPosition + strlen(actionSeperator)),
2067 objectPath.length());
2068 objectPath = objectPath.substr(0, actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002069 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002070 return;
2071 }
2072 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002073 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002074 {
2075 if (boost::ends_with(objectPath, "/enumerate"))
2076 {
2077 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2078 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002079 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002080 }
2081 else if (boost::ends_with(objectPath, "/list"))
2082 {
2083 objectPath.erase(objectPath.end() - sizeof("list"),
2084 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002085 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002086 }
2087 else
2088 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002089 // Trim any trailing "/" at the end
2090 if (boost::ends_with(objectPath, "/"))
2091 {
2092 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002093 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002094 }
2095 else
2096 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002097 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002098 }
Ed Tanous049a0512018-11-01 13:58:42 -07002099 }
2100 return;
2101 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002102 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002103 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002104 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002105 return;
2106 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002107 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002108 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002109 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002110 return;
2111 }
Ed Tanous049a0512018-11-01 13:58:42 -07002112
zhanghch058d1b46d2021-04-01 11:18:24 +08002113 setErrorResponse(asyncResp->res,
2114 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002115 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002116}
2117
Ed Tanous23a21a12020-07-25 04:45:05 +00002118inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002119{
2120 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002121 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002122 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002123 [](const crow::Request&,
2124 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2125 asyncResp->res.jsonValue = {{"buses", {{{"name", "system"}}}},
2126 {"status", "ok"}};
Ed Tanous1abe55e2018-09-05 08:30:59 -07002127 });
2128
2129 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002130 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002131 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002132 [](const crow::Request&,
2133 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
P Dheeraj Srujan Kumar83fd8e12021-07-13 02:53:03 +05302134 auto myCallback = [asyncResp](
zhanghch058d1b46d2021-04-01 11:18:24 +08002135 const boost::system::error_code ec,
2136 std::vector<std::string>& names) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07002137 if (ec)
2138 {
2139 BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +08002140 asyncResp->res.result(
Ed Tanous1abe55e2018-09-05 08:30:59 -07002141 boost::beast::http::status::internal_server_error);
2142 }
2143 else
2144 {
2145 std::sort(names.begin(), names.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002146 asyncResp->res.jsonValue = {{"status", "ok"}};
2147 auto& objectsSub = asyncResp->res.jsonValue["objects"];
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002148 for (auto& name : names)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002149 {
2150 objectsSub.push_back({{"name", name}});
2151 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002152 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002153 };
2154 crow::connections::systemBus->async_method_call(
2155 std::move(myCallback), "org.freedesktop.DBus", "/",
2156 "org.freedesktop.DBus", "ListNames");
2157 });
2158
2159 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002160 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002161 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002162 [](const crow::Request&,
2163 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2164 handleList(asyncResp, "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07002165 });
2166
2167 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002168 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002169 .methods(boost::beast::http::verb::get)(
2170 [](const crow::Request& req,
2171 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002172 const std::string& path) {
Ed Tanous049a0512018-11-01 13:58:42 -07002173 std::string objectPath = "/xyz/" + path;
zhanghch058d1b46d2021-04-01 11:18:24 +08002174 handleDBusUrl(req, asyncResp, objectPath);
2175 });
2176
2177 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002178 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002179 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2180 boost::beast::http::verb::delete_)(
2181 [](const crow::Request& req,
2182 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2183 const std::string& path) {
2184 std::string objectPath = "/xyz/" + path;
2185 handleDBusUrl(req, asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002186 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002187
Ed Tanous049a0512018-11-01 13:58:42 -07002188 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002189 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002190 .methods(boost::beast::http::verb::get)(
2191 [](const crow::Request& req,
2192 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2193 const std::string& path) {
2194 std::string objectPath = "/org/" + path;
2195 handleDBusUrl(req, asyncResp, objectPath);
2196 });
Tanousf00032d2018-11-05 01:18:10 -03002197
2198 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002199 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002200 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2201 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002202 [](const crow::Request& req,
2203 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002204 const std::string& path) {
Ed Tanouse1281402019-04-03 07:07:10 -07002205 std::string objectPath = "/org/" + path;
zhanghch058d1b46d2021-04-01 11:18:24 +08002206 handleDBusUrl(req, asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002207 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002208
Ed Tanous1abe55e2018-09-05 08:30:59 -07002209 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002210 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002211 .methods(boost::beast::http::verb::get)(
2212 [](const crow::Request&,
2213 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2214 const std::string& dumpId) {
2215 std::regex validFilename(R"(^[\w\- ]+(\.?[\w\- ]*)$)");
2216 if (!std::regex_match(dumpId, validFilename))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002217 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002218 asyncResp->res.result(
2219 boost::beast::http::status::bad_request);
Ramesh Iyyard9207042019-07-05 08:04:42 -05002220 return;
2221 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002222 std::filesystem::path loc(
2223 "/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002224
zhanghch058d1b46d2021-04-01 11:18:24 +08002225 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002226
zhanghch058d1b46d2021-04-01 11:18:24 +08002227 if (!std::filesystem::exists(loc) ||
2228 !std::filesystem::is_directory(loc))
2229 {
2230 BMCWEB_LOG_ERROR << loc << "Not found";
2231 asyncResp->res.result(
2232 boost::beast::http::status::not_found);
2233 return;
2234 }
2235 std::filesystem::directory_iterator files(loc);
2236
Ed Tanous9eb808c2022-01-25 10:19:23 -08002237 for (const auto& file : files)
zhanghch058d1b46d2021-04-01 11:18:24 +08002238 {
2239 std::ifstream readFile(file.path());
2240 if (!readFile.good())
2241 {
2242 continue;
2243 }
2244
2245 asyncResp->res.addHeader("Content-Type",
2246 "application/octet-stream");
2247
2248 // Assuming only one dump file will be present in the dump
2249 // id directory
2250 std::string dumpFileName = file.path().filename().string();
2251
2252 // Filename should be in alphanumeric, dot and underscore
2253 // Its based on phosphor-debug-collector application
2254 // dumpfile format
2255 std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
2256 if (!std::regex_match(dumpFileName, dumpFileRegex))
2257 {
2258 BMCWEB_LOG_ERROR << "Invalid dump filename "
2259 << dumpFileName;
2260 asyncResp->res.result(
2261 boost::beast::http::status::not_found);
2262 return;
2263 }
2264 std::string contentDispositionParam =
2265 "attachment; filename=\"" + dumpFileName + "\"";
2266
2267 asyncResp->res.addHeader("Content-Disposition",
2268 contentDispositionParam);
2269
2270 asyncResp->res.body() = {
2271 std::istreambuf_iterator<char>(readFile),
2272 std::istreambuf_iterator<char>()};
2273 return;
2274 }
2275 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002276 return;
zhanghch058d1b46d2021-04-01 11:18:24 +08002277 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002278
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002279 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002280 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002281
2282 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002283 [](const crow::Request&,
2284 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002285 const std::string& connection) {
Gunnar Mills9062d472021-11-16 11:37:47 -06002286 introspectObjects(
2287 connection, "/",
2288 std::make_shared<bmcweb::AsyncResp>(asyncResp->res));
Ed Tanousb41187f2019-10-24 16:30:02 -07002289 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002290
2291 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002292 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002293 .methods(boost::beast::http::verb::get, boost::beast::http::verb::post)(
2294 [](const crow::Request& req,
2295 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2296 const std::string& processName,
2297 const std::string& requestedPath) {
2298 std::vector<std::string> strs;
2299 boost::split(strs, requestedPath, boost::is_any_of("/"));
2300 std::string objectPath;
2301 std::string interfaceName;
2302 std::string methodName;
2303 auto it = strs.begin();
2304 if (it == strs.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -07002305 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002306 objectPath = "/";
Ed Tanous1abe55e2018-09-05 08:30:59 -07002307 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002308 while (it != strs.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -07002309 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002310 // Check if segment contains ".". If it does, it must be an
2311 // interface
2312 if (it->find(".") != std::string::npos)
2313 {
2314 break;
2315 // This check is necessary as the trailing slash gets
2316 // parsed as part of our <path> specifier above, which
2317 // causes the normal trailing backslash redirector to
2318 // fail.
2319 }
2320 if (!it->empty())
2321 {
2322 objectPath += "/" + *it;
2323 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002324 it++;
2325 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002326 if (it != strs.end())
2327 {
2328 interfaceName = *it;
2329 it++;
Ed Tanous7c091622019-05-23 11:42:36 -07002330
zhanghch058d1b46d2021-04-01 11:18:24 +08002331 // after interface, we might have a method name
2332 if (it != strs.end())
2333 {
2334 methodName = *it;
2335 it++;
2336 }
2337 }
2338 if (it != strs.end())
2339 {
2340 // if there is more levels past the method name, something
2341 // went wrong, return not found
2342 asyncResp->res.result(
2343 boost::beast::http::status::not_found);
2344 return;
2345 }
2346 if (interfaceName.empty())
2347 {
2348 crow::connections::systemBus->async_method_call(
2349 [asyncResp, processName,
2350 objectPath](const boost::system::error_code ec,
2351 const std::string& introspectXml) {
2352 if (ec)
2353 {
2354 BMCWEB_LOG_ERROR
2355 << "Introspect call failed with error: "
2356 << ec.message()
2357 << " on process: " << processName
2358 << " path: " << objectPath << "\n";
2359 return;
2360 }
2361 tinyxml2::XMLDocument doc;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002362
zhanghch058d1b46d2021-04-01 11:18:24 +08002363 doc.Parse(introspectXml.c_str());
2364 tinyxml2::XMLNode* pRoot =
2365 doc.FirstChildElement("node");
2366 if (pRoot == nullptr)
2367 {
2368 BMCWEB_LOG_ERROR
2369 << "XML document failed to parse "
2370 << processName << " " << objectPath << "\n";
2371 asyncResp->res.jsonValue = {
2372 {"status", "XML parse error"}};
2373 asyncResp->res.result(
2374 boost::beast::http::status::
2375 internal_server_error);
2376 return;
2377 }
2378
2379 BMCWEB_LOG_DEBUG << introspectXml;
Ed Tanous7c091622019-05-23 11:42:36 -07002380 asyncResp->res.jsonValue = {
zhanghch058d1b46d2021-04-01 11:18:24 +08002381 {"status", "ok"},
2382 {"bus_name", processName},
2383 {"object_path", objectPath}};
2384 nlohmann::json& interfacesArray =
2385 asyncResp->res.jsonValue["interfaces"];
2386 interfacesArray = nlohmann::json::array();
2387 tinyxml2::XMLElement* interface =
2388 pRoot->FirstChildElement("interface");
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002389
zhanghch058d1b46d2021-04-01 11:18:24 +08002390 while (interface != nullptr)
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002391 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002392 const char* ifaceName =
2393 interface->Attribute("name");
2394 if (ifaceName != nullptr)
Ed Tanous7c091622019-05-23 11:42:36 -07002395 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002396 interfacesArray.push_back(
2397 {{"name", ifaceName}});
2398 }
2399
2400 interface =
2401 interface->NextSiblingElement("interface");
2402 }
2403 },
2404 processName, objectPath,
2405 "org.freedesktop.DBus.Introspectable", "Introspect");
2406 }
2407 else if (methodName.empty())
2408 {
2409 crow::connections::systemBus->async_method_call(
2410 [asyncResp, processName, objectPath,
2411 interfaceName](const boost::system::error_code ec,
2412 const std::string& introspectXml) {
2413 if (ec)
2414 {
2415 BMCWEB_LOG_ERROR
2416 << "Introspect call failed with error: "
2417 << ec.message()
2418 << " on process: " << processName
2419 << " path: " << objectPath << "\n";
2420 return;
2421 }
2422 tinyxml2::XMLDocument doc;
2423
2424 doc.Parse(introspectXml.data(),
2425 introspectXml.size());
2426 tinyxml2::XMLNode* pRoot =
2427 doc.FirstChildElement("node");
2428 if (pRoot == nullptr)
2429 {
2430 BMCWEB_LOG_ERROR
2431 << "XML document failed to parse "
2432 << processName << " " << objectPath << "\n";
2433 asyncResp->res.result(
2434 boost::beast::http::status::
2435 internal_server_error);
2436 return;
2437 }
2438 asyncResp->res.jsonValue = {
2439 {"status", "ok"},
2440 {"bus_name", processName},
2441 {"interface", interfaceName},
2442 {"object_path", objectPath}};
2443
2444 nlohmann::json& methodsArray =
2445 asyncResp->res.jsonValue["methods"];
2446 methodsArray = nlohmann::json::array();
2447
2448 nlohmann::json& signalsArray =
2449 asyncResp->res.jsonValue["signals"];
2450 signalsArray = nlohmann::json::array();
2451
2452 nlohmann::json& propertiesObj =
2453 asyncResp->res.jsonValue["properties"];
2454 propertiesObj = nlohmann::json::object();
2455
2456 // if we know we're the only call, build the
2457 // json directly
2458 tinyxml2::XMLElement* interface =
2459 pRoot->FirstChildElement("interface");
2460 while (interface != nullptr)
2461 {
2462 const char* ifaceName =
2463 interface->Attribute("name");
2464
2465 if (ifaceName != nullptr &&
2466 ifaceName == interfaceName)
2467 {
2468 break;
2469 }
2470
2471 interface =
2472 interface->NextSiblingElement("interface");
2473 }
2474 if (interface == nullptr)
2475 {
2476 // if we got to the end of the list and
2477 // never found a match, throw 404
2478 asyncResp->res.result(
2479 boost::beast::http::status::not_found);
2480 return;
2481 }
2482
2483 tinyxml2::XMLElement* methods =
2484 interface->FirstChildElement("method");
2485 while (methods != nullptr)
2486 {
2487 nlohmann::json argsArray =
2488 nlohmann::json::array();
2489 tinyxml2::XMLElement* arg =
2490 methods->FirstChildElement("arg");
2491 while (arg != nullptr)
2492 {
2493 nlohmann::json thisArg;
2494 for (const char* fieldName :
2495 std::array<const char*, 3>{
2496 "name", "direction", "type"})
Ed Tanous7c091622019-05-23 11:42:36 -07002497 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002498 const char* fieldValue =
2499 arg->Attribute(fieldName);
2500 if (fieldValue != nullptr)
Ed Tanous7c091622019-05-23 11:42:36 -07002501 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002502 thisArg[fieldName] = fieldValue;
Ed Tanous7c091622019-05-23 11:42:36 -07002503 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002504 }
2505 argsArray.push_back(std::move(thisArg));
2506 arg = arg->NextSiblingElement("arg");
2507 }
Ed Tanous7c091622019-05-23 11:42:36 -07002508
zhanghch058d1b46d2021-04-01 11:18:24 +08002509 const char* name = methods->Attribute("name");
2510 if (name != nullptr)
2511 {
2512 std::string uri;
2513 uri.reserve(14 + processName.size() +
2514 objectPath.size() +
2515 interfaceName.size() +
2516 strlen(name));
2517 uri += "/bus/system/";
2518 uri += processName;
2519 uri += objectPath;
2520 uri += "/";
2521 uri += interfaceName;
2522 uri += "/";
2523 uri += name;
2524 methodsArray.push_back(
2525 {{"name", name},
2526 {"uri", std::move(uri)},
2527 {"args", argsArray}});
2528 }
2529 methods = methods->NextSiblingElement("method");
Ed Tanous7c091622019-05-23 11:42:36 -07002530 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002531 tinyxml2::XMLElement* signals =
2532 interface->FirstChildElement("signal");
2533 while (signals != nullptr)
2534 {
2535 nlohmann::json argsArray =
2536 nlohmann::json::array();
2537
2538 tinyxml2::XMLElement* arg =
2539 signals->FirstChildElement("arg");
2540 while (arg != nullptr)
2541 {
2542 const char* name = arg->Attribute("name");
2543 const char* type = arg->Attribute("type");
2544 if (name != nullptr && type != nullptr)
2545 {
2546 argsArray.push_back({
2547 {"name", name},
2548 {"type", type},
2549 });
2550 }
2551 arg = arg->NextSiblingElement("arg");
2552 }
2553 const char* name = signals->Attribute("name");
2554 if (name != nullptr)
2555 {
2556 signalsArray.push_back(
2557 {{"name", name}, {"args", argsArray}});
2558 }
2559
2560 signals = signals->NextSiblingElement("signal");
2561 }
2562
2563 tinyxml2::XMLElement* property =
2564 interface->FirstChildElement("property");
2565 while (property != nullptr)
2566 {
2567 const char* name = property->Attribute("name");
2568 const char* type = property->Attribute("type");
2569 if (type != nullptr && name != nullptr)
2570 {
2571 sdbusplus::message::message m =
2572 crow::connections::systemBus
2573 ->new_method_call(
2574 processName.c_str(),
2575 objectPath.c_str(),
2576 "org.freedesktop."
2577 "DBus."
2578 "Properties",
2579 "Get");
2580 m.append(interfaceName, name);
2581 nlohmann::json& propertyItem =
2582 propertiesObj[name];
2583 crow::connections::systemBus->async_send(
2584 m,
2585 [&propertyItem, asyncResp](
2586 boost::system::error_code& e,
2587 sdbusplus::message::message& msg) {
2588 if (e)
2589 {
2590 return;
2591 }
2592
2593 convertDBusToJSON("v", msg,
2594 propertyItem);
2595 });
2596 }
2597 property =
2598 property->NextSiblingElement("property");
2599 }
2600 },
2601 processName, objectPath,
2602 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002603 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002604 else
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002605 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002606 if (req.method() != boost::beast::http::verb::post)
2607 {
2608 asyncResp->res.result(
2609 boost::beast::http::status::not_found);
2610 return;
2611 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002612
zhanghch058d1b46d2021-04-01 11:18:24 +08002613 nlohmann::json requestDbusData =
2614 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002615
zhanghch058d1b46d2021-04-01 11:18:24 +08002616 if (requestDbusData.is_discarded())
2617 {
2618 asyncResp->res.result(
2619 boost::beast::http::status::bad_request);
2620 return;
2621 }
2622 if (!requestDbusData.is_array())
2623 {
2624 asyncResp->res.result(
2625 boost::beast::http::status::bad_request);
2626 return;
2627 }
2628 auto transaction =
2629 std::make_shared<InProgressActionData>(asyncResp->res);
2630
2631 transaction->path = objectPath;
2632 transaction->methodName = methodName;
2633 transaction->arguments = std::move(requestDbusData);
2634
2635 findActionOnInterface(transaction, processName);
2636 }
2637 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002638}
2639} // namespace openbmc_mapper
2640} // namespace crow