blob: 042f19395276fcc9a7a64f5193d013e3efaa988d [file] [log] [blame]
James Feist5b4aa862018-08-16 14:07:01 -07001// Copyright (c) 2018 Intel Corporation
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
Ed Tanousb9b2e0b2018-09-13 13:47:50 -070014
James Feist5b4aa862018-08-16 14:07:01 -070015#pragma once
Ed Tanous911ac312017-08-15 09:37:42 -070016#include <tinyxml2.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -070017
Ed Tanous04e438c2020-10-03 08:06:26 -070018#include <app.hpp>
Ed Tanouse3cb5a32018-08-08 14:16:49 -070019#include <async_resp.hpp>
Ed Tanous1abe55e2018-09-05 08:30:59 -070020#include <boost/algorithm/string.hpp>
21#include <boost/container/flat_set.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -070022#include <dbus_singleton.hpp>
James Feist5b4aa862018-08-16 14:07:01 -070023#include <dbus_utility.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050024#include <sdbusplus/message/types.hpp>
25
James Feist4418c7f2019-04-15 11:09:15 -070026#include <filesystem>
Ed Tanousd4bb9bb2018-05-16 13:36:42 -070027#include <fstream>
Ramesh Iyyard9207042019-07-05 08:04:42 -050028#include <regex>
Ed Tanousb5a76932020-09-29 16:16:58 -070029#include <utility>
Ed Tanous911ac312017-08-15 09:37:42 -070030
Ed Tanous1abe55e2018-09-05 08:30:59 -070031namespace crow
32{
33namespace openbmc_mapper
34{
Ed Tanous23a21a12020-07-25 04:45:05 +000035const constexpr char* notFoundMsg = "404 Not Found";
36const constexpr char* badReqMsg = "400 Bad Request";
37const constexpr char* methodNotAllowedMsg = "405 Method Not Allowed";
38const constexpr char* forbiddenMsg = "403 Forbidden";
39const constexpr char* methodFailedMsg = "500 Method Call Failed";
40const constexpr char* methodOutputFailedMsg = "500 Method Output Error";
41const constexpr char* notFoundDesc =
Matt Spinler2ae60092018-12-06 10:35:36 -060042 "org.freedesktop.DBus.Error.FileNotFound: path or object not found";
Ed Tanous23a21a12020-07-25 04:45:05 +000043const constexpr char* propNotFoundDesc =
44 "The specified property cannot be found";
45const constexpr char* noJsonDesc = "No JSON object could be decoded";
46const constexpr char* methodNotFoundDesc =
47 "The specified method cannot be found";
48const constexpr char* methodNotAllowedDesc = "Method not allowed";
49const constexpr char* forbiddenPropDesc =
50 "The specified property cannot be created";
51const constexpr char* forbiddenResDesc =
52 "The specified resource cannot be created";
Matt Spinler2ae60092018-12-06 10:35:36 -060053
Ed Tanous23a21a12020-07-25 04:45:05 +000054inline void setErrorResponse(crow::Response& res,
55 boost::beast::http::status result,
56 const std::string& desc,
57 const std::string_view msg)
Matt Spinler2ae60092018-12-06 10:35:36 -060058{
59 res.result(result);
60 res.jsonValue = {{"data", {{"description", desc}}},
61 {"message", msg},
62 {"status", "error"}};
63}
64
Ed Tanousb5a76932020-09-29 16:16:58 -070065inline void
66 introspectObjects(const std::string& processName,
67 const std::string& objectPath,
68 const std::shared_ptr<bmcweb::AsyncResp>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -070069{
Ed Tanouse3cb5a32018-08-08 14:16:49 -070070 if (transaction->res.jsonValue.is_null())
71 {
72 transaction->res.jsonValue = {{"status", "ok"},
73 {"bus_name", processName},
74 {"objects", nlohmann::json::array()}};
75 }
76
Ed Tanous1abe55e2018-09-05 08:30:59 -070077 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -070078 [transaction, processName{std::string(processName)},
79 objectPath{std::string(objectPath)}](
80 const boost::system::error_code ec,
Ed Tanous81ce6092020-12-17 16:54:55 +000081 const std::string& introspectXml) {
Ed Tanous1abe55e2018-09-05 08:30:59 -070082 if (ec)
83 {
84 BMCWEB_LOG_ERROR
85 << "Introspect call failed with error: " << ec.message()
86 << " on process: " << processName << " path: " << objectPath
87 << "\n";
Ed Tanouse3cb5a32018-08-08 14:16:49 -070088 return;
89 }
90 transaction->res.jsonValue["objects"].push_back(
91 {{"path", objectPath}});
92
93 tinyxml2::XMLDocument doc;
94
Ed Tanous81ce6092020-12-17 16:54:55 +000095 doc.Parse(introspectXml.c_str());
Gunnar Mills1214b7e2020-06-04 10:11:30 -050096 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
Ed Tanouse3cb5a32018-08-08 14:16:49 -070097 if (pRoot == nullptr)
98 {
99 BMCWEB_LOG_ERROR << "XML document failed to parse "
100 << processName << " " << objectPath << "\n";
Ed Tanous911ac312017-08-15 09:37:42 -0700101 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700102 else
103 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500104 tinyxml2::XMLElement* node = pRoot->FirstChildElement("node");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700105 while (node != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700106 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500107 const char* childPath = node->Attribute("name");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700108 if (childPath != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700109 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700110 std::string newpath;
111 if (objectPath != "/")
112 {
113 newpath += objectPath;
114 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700115 newpath += std::string("/") + childPath;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700116 // introspect the subobjects as well
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700117 introspectObjects(processName, newpath, transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700118 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700119
120 node = node->NextSiblingElement("node");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700121 }
122 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700124 processName, objectPath, "org.freedesktop.DBus.Introspectable",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700125 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -0700126}
Ed Tanous64530012018-02-06 17:08:16 -0800127
Ed Tanous23a21a12020-07-25 04:45:05 +0000128inline void getPropertiesForEnumerate(
129 const std::string& objectPath, const std::string& service,
Ed Tanousb5a76932020-09-29 16:16:58 -0700130 const std::string& interface,
131 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600132{
133 BMCWEB_LOG_DEBUG << "getPropertiesForEnumerate " << objectPath << " "
134 << service << " " << interface;
135
136 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -0800137 [asyncResp, objectPath, service,
138 interface](const boost::system::error_code ec,
139 const dbus::utility::DBusPropertiesMap& propertiesList) {
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600140 if (ec)
141 {
142 BMCWEB_LOG_ERROR << "GetAll on path " << objectPath << " iface "
143 << interface << " service " << service
144 << " failed with code " << ec;
145 return;
146 }
147
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500148 nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
149 nlohmann::json& objectJson = dataJson[objectPath];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600150 if (objectJson.is_null())
151 {
152 objectJson = nlohmann::json::object();
153 }
154
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500155 for (const auto& [name, value] : propertiesList)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600156 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500157 nlohmann::json& propertyJson = objectJson[name];
Ed Tanousd1a64812021-12-13 12:14:05 -0800158 std::visit(
159 [&propertyJson](auto&& val) {
160 if constexpr (std::is_same_v<
161 std::decay_t<decltype(val)>,
162 sdbusplus::message::unix_fd>)
163 {
164 propertyJson = val.fd;
165 }
166 else
167 {
168
169 propertyJson = val;
170 }
171 },
172 value);
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600173 }
174 },
175 service, objectPath, "org.freedesktop.DBus.Properties", "GetAll",
176 interface);
177}
178
179// Find any results that weren't picked up by ObjectManagers, to be
180// called after all ObjectManagers are searched for and called.
Ed Tanous23a21a12020-07-25 04:45:05 +0000181inline void findRemainingObjectsForEnumerate(
Ed Tanousb5a76932020-09-29 16:16:58 -0700182 const std::string& objectPath,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800183 const std::shared_ptr<dbus::utility::MapperGetSubTreeResponse>& subtree,
Ed Tanousb5a76932020-09-29 16:16:58 -0700184 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600185{
186 BMCWEB_LOG_DEBUG << "findRemainingObjectsForEnumerate";
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500187 const nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600188
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500189 for (const auto& [path, interface_map] : *subtree)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600190 {
191 if (path == objectPath)
192 {
193 // An enumerate does not return the target path's properties
194 continue;
195 }
196 if (dataJson.find(path) == dataJson.end())
197 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500198 for (const auto& [service, interfaces] : interface_map)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600199 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500200 for (const auto& interface : interfaces)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600201 {
202 if (!boost::starts_with(interface, "org.freedesktop.DBus"))
203 {
204 getPropertiesForEnumerate(path, service, interface,
205 asyncResp);
206 }
207 }
208 }
209 }
210 }
211}
212
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600213struct InProgressEnumerateData
214{
zhanghch058d1b46d2021-04-01 11:18:24 +0800215 InProgressEnumerateData(
216 const std::string& objectPathIn,
217 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
Ed Tanous23a21a12020-07-25 04:45:05 +0000218 objectPath(objectPathIn),
zhanghch058d1b46d2021-04-01 11:18:24 +0800219 asyncResp(asyncRespIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500220 {}
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600221
222 ~InProgressEnumerateData()
223 {
Ed Tanous24b2fe82022-01-06 12:45:54 -0800224 try
225 {
226 findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
227 }
228 catch (...)
229 {
230 BMCWEB_LOG_CRITICAL
231 << "findRemainingObjectsForEnumerate threw exception";
232 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600233 }
234
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800235 InProgressEnumerateData(const InProgressEnumerateData&) = delete;
236 InProgressEnumerateData(InProgressEnumerateData&&) = delete;
237 InProgressEnumerateData& operator=(const InProgressEnumerateData&) = delete;
238 InProgressEnumerateData& operator=(InProgressEnumerateData&&) = delete;
239
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600240 const std::string objectPath;
Ed Tanousb9d36b42022-02-26 21:42:46 -0800241 std::shared_ptr<dbus::utility::MapperGetSubTreeResponse> subtree;
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600242 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
243};
244
Ed Tanous23a21a12020-07-25 04:45:05 +0000245inline void getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000246 const std::string& objectName, const std::string& objectManagerPath,
247 const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700248 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700249{
Ed Tanous81ce6092020-12-17 16:54:55 +0000250 BMCWEB_LOG_DEBUG << "getManagedObjectsForEnumerate " << objectName
251 << " object_manager_path " << objectManagerPath
252 << " connection_name " << connectionName;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700253 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000254 [transaction, objectName,
255 connectionName](const boost::system::error_code ec,
256 const dbus::utility::ManagedObjectType& objects) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700257 if (ec)
258 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000259 BMCWEB_LOG_ERROR << "GetManagedObjects on path " << objectName
260 << " on connection " << connectionName
Ed Tanous049a0512018-11-01 13:58:42 -0700261 << " failed with code " << ec;
262 return;
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700263 }
Ed Tanous64530012018-02-06 17:08:16 -0800264
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500265 nlohmann::json& dataJson =
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600266 transaction->asyncResp->res.jsonValue["data"];
Ed Tanous049a0512018-11-01 13:58:42 -0700267
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500268 for (const auto& objectPath : objects)
Ed Tanous049a0512018-11-01 13:58:42 -0700269 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000270 if (boost::starts_with(objectPath.first.str, objectName))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700271 {
Ed Tanous049a0512018-11-01 13:58:42 -0700272 BMCWEB_LOG_DEBUG << "Reading object "
273 << objectPath.first.str;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500274 nlohmann::json& objectJson = dataJson[objectPath.first.str];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700275 if (objectJson.is_null())
276 {
277 objectJson = nlohmann::json::object();
278 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500279 for (const auto& interface : objectPath.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700280 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500281 for (const auto& property : interface.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700282 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500283 nlohmann::json& propertyJson =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700284 objectJson[property.first];
Ed Tanousd1a64812021-12-13 12:14:05 -0800285 std::visit(
286 [&propertyJson](auto&& val) {
287 if constexpr (
288 std::is_same_v<
289 std::decay_t<decltype(val)>,
290 sdbusplus::message::unix_fd>)
291 {
292 propertyJson = val.fd;
293 }
294 else
295 {
296
297 propertyJson = val;
298 }
299 },
300 property.second);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700301 }
302 }
303 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500304 for (const auto& interface : objectPath.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700305 {
306 if (interface.first == "org.freedesktop.DBus.ObjectManager")
307 {
308 getManagedObjectsForEnumerate(
309 objectPath.first.str, objectPath.first.str,
Ed Tanous81ce6092020-12-17 16:54:55 +0000310 connectionName, transaction);
Ed Tanous049a0512018-11-01 13:58:42 -0700311 }
312 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700313 }
314 },
Ed Tanous81ce6092020-12-17 16:54:55 +0000315 connectionName, objectManagerPath, "org.freedesktop.DBus.ObjectManager",
316 "GetManagedObjects");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700317}
318
Ed Tanous23a21a12020-07-25 04:45:05 +0000319inline void findObjectManagerPathForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000320 const std::string& objectName, const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700321 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700322{
Ed Tanous81ce6092020-12-17 16:54:55 +0000323 BMCWEB_LOG_DEBUG << "Finding objectmanager for path " << objectName
324 << " on connection:" << connectionName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700325 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000326 [transaction, objectName, connectionName](
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700327 const boost::system::error_code ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800328 const dbus::utility::MapperGetAncestorsResponse& objects) {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700329 if (ec)
330 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000331 BMCWEB_LOG_ERROR << "GetAncestors on path " << objectName
Ed Tanous049a0512018-11-01 13:58:42 -0700332 << " failed with code " << ec;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700333 return;
334 }
335
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500336 for (const auto& pathGroup : objects)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700337 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500338 for (const auto& connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700339 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000340 if (connectionGroup.first == connectionName)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700341 {
342 // Found the object manager path for this resource.
343 getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000344 objectName, pathGroup.first, connectionName,
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600345 transaction);
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700346 return;
347 }
348 }
349 }
350 },
351 "xyz.openbmc_project.ObjectMapper",
352 "/xyz/openbmc_project/object_mapper",
Ed Tanous81ce6092020-12-17 16:54:55 +0000353 "xyz.openbmc_project.ObjectMapper", "GetAncestors", objectName,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500354 std::array<const char*, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700355}
Ed Tanous64530012018-02-06 17:08:16 -0800356
Ed Tanous7c091622019-05-23 11:42:36 -0700357// Uses GetObject to add the object info about the target /enumerate path to
358// the results of GetSubTree, as GetSubTree will not return info for the
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600359// target path, and then continues on enumerating the rest of the tree.
Ed Tanousb5a76932020-09-29 16:16:58 -0700360inline void getObjectAndEnumerate(
361 const std::shared_ptr<InProgressEnumerateData>& transaction)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600362{
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600363 crow::connections::systemBus->async_method_call(
364 [transaction](const boost::system::error_code ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800365 const dbus::utility::MapperGetObject& objects) {
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600366 if (ec)
367 {
368 BMCWEB_LOG_ERROR << "GetObject for path "
369 << transaction->objectPath
370 << " failed with code " << ec;
371 return;
372 }
373
374 BMCWEB_LOG_DEBUG << "GetObject for " << transaction->objectPath
375 << " has " << objects.size() << " entries";
376 if (!objects.empty())
377 {
378 transaction->subtree->emplace_back(transaction->objectPath,
379 objects);
380 }
381
382 // Map indicating connection name, and the path where the object
383 // manager exists
384 boost::container::flat_map<std::string, std::string> connections;
385
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500386 for (const auto& object : *(transaction->subtree))
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600387 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500388 for (const auto& connection : object.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600389 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500390 std::string& objectManagerPath =
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600391 connections[connection.first];
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500392 for (const auto& interface : connection.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600393 {
394 BMCWEB_LOG_DEBUG << connection.first
395 << " has interface " << interface;
396 if (interface == "org.freedesktop.DBus.ObjectManager")
397 {
398 BMCWEB_LOG_DEBUG << "found object manager path "
399 << object.first;
400 objectManagerPath = object.first;
401 }
402 }
403 }
404 }
405 BMCWEB_LOG_DEBUG << "Got " << connections.size() << " connections";
406
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500407 for (const auto& connection : connections)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600408 {
Ed Tanous7c091622019-05-23 11:42:36 -0700409 // If we already know where the object manager is, we don't
410 // need to search for it, we can call directly in to
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600411 // getManagedObjects
412 if (!connection.second.empty())
413 {
414 getManagedObjectsForEnumerate(
415 transaction->objectPath, connection.second,
416 connection.first, transaction);
417 }
418 else
419 {
Ed Tanous7c091622019-05-23 11:42:36 -0700420 // otherwise we need to find the object manager path
421 // before we can continue
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600422 findObjectManagerPathForEnumerate(
423 transaction->objectPath, connection.first, transaction);
424 }
425 }
426 },
427 "xyz.openbmc_project.ObjectMapper",
428 "/xyz/openbmc_project/object_mapper",
429 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500430 transaction->objectPath, std::array<const char*, 0>());
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600431}
Ed Tanous64530012018-02-06 17:08:16 -0800432
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700433// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700434struct InProgressActionData
435{
Ed Tanous23a21a12020-07-25 04:45:05 +0000436 InProgressActionData(crow::Response& resIn) : res(resIn)
437 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700438 ~InProgressActionData()
439 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600440 // Methods could have been called across different owners
441 // and interfaces, where some calls failed and some passed.
442 //
443 // The rules for this are:
444 // * if no method was called - error
445 // * if a method failed and none passed - error
446 // (converse: if at least one method passed - OK)
447 // * for the method output:
448 // * if output processing didn't fail, return the data
449
450 // Only deal with method returns if nothing failed earlier
451 if (res.result() == boost::beast::http::status::ok)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700452 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600453 if (!methodPassed)
454 {
Matt Spinler06b1b632019-06-18 16:09:25 -0500455 if (!methodFailed)
Matt Spinler16caaee2019-01-15 11:40:34 -0600456 {
457 setErrorResponse(res, boost::beast::http::status::not_found,
458 methodNotFoundDesc, notFoundMsg);
459 }
460 }
461 else
462 {
463 if (outputFailed)
464 {
465 setErrorResponse(
466 res, boost::beast::http::status::internal_server_error,
467 "Method output failure", methodOutputFailedMsg);
468 }
469 else
470 {
471 res.jsonValue = {{"status", "ok"},
472 {"message", "200 OK"},
473 {"data", methodResponse}};
474 }
475 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700476 }
Matt Spinler16caaee2019-01-15 11:40:34 -0600477
Ed Tanous1abe55e2018-09-05 08:30:59 -0700478 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700479 }
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800480 InProgressActionData(const InProgressActionData&) = delete;
481 InProgressActionData(InProgressActionData&&) = delete;
482 InProgressActionData& operator=(const InProgressActionData&) = delete;
483 InProgressActionData& operator=(InProgressActionData&&) = delete;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700484
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500485 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700486 {
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600487 setErrorResponse(res, boost::beast::http::status::bad_request, desc,
488 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700489 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500490 crow::Response& res;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700491 std::string path;
492 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600493 std::string interfaceName;
Matt Spinler16caaee2019-01-15 11:40:34 -0600494 bool methodPassed = false;
495 bool methodFailed = false;
496 bool outputFailed = false;
Matt Spinler39a4e392019-01-15 11:53:13 -0600497 bool convertedToArray = false;
Matt Spinler16caaee2019-01-15 11:40:34 -0600498 nlohmann::json methodResponse;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700499 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700500};
501
Ed Tanous23a21a12020-07-25 04:45:05 +0000502inline std::vector<std::string> dbusArgSplit(const std::string& string)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700503{
504 std::vector<std::string> ret;
505 if (string.empty())
506 {
507 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700508 }
Ed Tanous0f0353b2019-10-24 11:37:51 -0700509 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700510 int containerDepth = 0;
511
512 for (std::string::const_iterator character = string.begin();
513 character != string.end(); character++)
514 {
515 ret.back() += *character;
516 switch (*character)
517 {
518 case ('a'):
519 break;
520 case ('('):
521 case ('{'):
522 containerDepth++;
523 break;
524 case ('}'):
525 case (')'):
526 containerDepth--;
527 if (containerDepth == 0)
528 {
529 if (character + 1 != string.end())
530 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700531 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700532 }
533 }
534 break;
535 default:
536 if (containerDepth == 0)
537 {
538 if (character + 1 != string.end())
539 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700540 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700541 }
542 }
543 break;
544 }
545 }
Matt Spinler4ae611d2019-01-11 15:37:06 -0600546
547 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700548}
549
Ed Tanous81ce6092020-12-17 16:54:55 +0000550inline int convertJsonToDbus(sd_bus_message* m, const std::string& argType,
551 const nlohmann::json& inputJson)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700552{
553 int r = 0;
Ed Tanous71f52d92021-02-19 08:51:17 -0800554 BMCWEB_LOG_DEBUG << "Converting "
555 << inputJson.dump(2, ' ', true,
556 nlohmann::json::error_handler_t::replace)
Ed Tanous81ce6092020-12-17 16:54:55 +0000557 << " to type: " << argType;
558 const std::vector<std::string> argTypes = dbusArgSplit(argType);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700559
Ed Tanous1abe55e2018-09-05 08:30:59 -0700560 // Assume a single object for now.
Ed Tanous81ce6092020-12-17 16:54:55 +0000561 const nlohmann::json* j = &inputJson;
562 nlohmann::json::const_iterator jIt = inputJson.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700563
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500564 for (const std::string& argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700565 {
566 // If we are decoding multiple objects, grab the pointer to the
567 // iterator, and increment it for the next loop
568 if (argTypes.size() > 1)
569 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000570 if (jIt == inputJson.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700571 {
572 return -2;
573 }
574 j = &*jIt;
575 jIt++;
576 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500577 const int64_t* intValue = j->get_ptr<const int64_t*>();
578 const std::string* stringValue = j->get_ptr<const std::string*>();
579 const double* doubleValue = j->get_ptr<const double*>();
580 const bool* b = j->get_ptr<const bool*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700581 int64_t v = 0;
582 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700583
Ed Tanous1abe55e2018-09-05 08:30:59 -0700584 // Do some basic type conversions that make sense. uint can be
585 // converted to int. int and uint can be converted to double
Ed Tanous66664f22019-10-11 13:05:49 -0700586 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700587 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500588 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700589 if (uintValue != nullptr)
590 {
591 v = static_cast<int64_t>(*uintValue);
592 intValue = &v;
593 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700594 }
Ed Tanous66664f22019-10-11 13:05:49 -0700595 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700596 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500597 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700598 if (uintValue != nullptr)
599 {
600 d = static_cast<double>(*uintValue);
601 doubleValue = &d;
602 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700603 }
Ed Tanous66664f22019-10-11 13:05:49 -0700604 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700605 {
Ed Tanous66664f22019-10-11 13:05:49 -0700606 if (intValue != nullptr)
607 {
608 d = static_cast<double>(*intValue);
609 doubleValue = &d;
610 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700611 }
612
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700613 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700614 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700615 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700616 {
617 return -1;
618 }
Ed Tanous271584a2019-07-09 16:24:22 -0700619 r = sd_bus_message_append_basic(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500620 m, argCode[0], static_cast<const void*>(stringValue->data()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700621 if (r < 0)
622 {
623 return r;
624 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700625 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700626 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700627 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700628 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700629 {
630 return -1;
631 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500632 if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
633 (*intValue > std::numeric_limits<int32_t>::max()))
634 {
635 return -ERANGE;
636 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700637 int32_t i = static_cast<int32_t>(*intValue);
638 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700639 if (r < 0)
640 {
641 return r;
642 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700643 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700644 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700645 {
646 // lots of ways bool could be represented here. Try them all
Ed Tanouse662eae2022-01-25 10:39:19 -0800647 int boolInt = 0;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700648 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700649 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500650 if (*intValue == 1)
651 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800652 boolInt = 1;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500653 }
654 else if (*intValue == 0)
655 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800656 boolInt = 0;
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500657 }
658 else
659 {
660 return -ERANGE;
661 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700662 }
663 else if (b != nullptr)
664 {
Matt Spinlera2f02632019-01-18 10:15:35 -0600665 boolInt = *b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700666 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700667 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700668 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700669 boolInt = boost::istarts_with(*stringValue, "t") ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700670 }
671 else
672 {
673 return -1;
674 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700675 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700676 if (r < 0)
677 {
678 return r;
679 }
680 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700681 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700682 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700683 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700684 {
685 return -1;
686 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500687 if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
688 (*intValue > std::numeric_limits<int16_t>::max()))
689 {
690 return -ERANGE;
691 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700692 int16_t n = static_cast<int16_t>(*intValue);
693 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700694 if (r < 0)
695 {
696 return r;
697 }
698 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700699 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700700 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700701 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700702 {
703 return -1;
704 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700705 r = sd_bus_message_append_basic(m, argCode[0], intValue);
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 == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700712 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500713 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700714 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700715 {
716 return -1;
717 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000718 if (*uintValue > std::numeric_limits<uint8_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500719 {
720 return -ERANGE;
721 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700722 uint8_t y = static_cast<uint8_t>(*uintValue);
723 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700724 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700725 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700726 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500727 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700728 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700729 {
730 return -1;
731 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000732 if (*uintValue > std::numeric_limits<uint16_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500733 {
734 return -ERANGE;
735 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700736 uint16_t q = static_cast<uint16_t>(*uintValue);
737 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700738 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700739 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700740 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500741 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700742 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700743 {
744 return -1;
745 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000746 if (*uintValue > std::numeric_limits<uint32_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500747 {
748 return -ERANGE;
749 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700750 uint32_t u = static_cast<uint32_t>(*uintValue);
751 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700752 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700753 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700754 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500755 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700756 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700757 {
758 return -1;
759 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700760 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700761 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700762 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700763 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500764 if (doubleValue == nullptr)
765 {
766 return -1;
767 }
768 if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
769 (*doubleValue > std::numeric_limits<double>::max()))
770 {
771 return -ERANGE;
772 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700773 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700774 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700775 else if (boost::starts_with(argCode, "a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700776 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700777 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700778 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700779 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700780 if (r < 0)
781 {
782 return r;
783 }
784
Ed Tanous0dfeda62019-10-24 11:21:38 -0700785 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700786 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700787 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700788 if (r < 0)
789 {
790 return r;
791 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700792 }
793 sd_bus_message_close_container(m);
794 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700795 else if (boost::starts_with(argCode, "v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700796 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700797 std::string containedType = argCode.substr(1);
798 BMCWEB_LOG_DEBUG << "variant type: " << argCode
799 << " appending variant of type: " << containedType;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700800 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700801 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700802 if (r < 0)
803 {
804 return r;
805 }
806
Ed Tanous81ce6092020-12-17 16:54:55 +0000807 r = convertJsonToDbus(m, containedType, inputJson);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700808 if (r < 0)
809 {
810 return r;
811 }
812
813 r = sd_bus_message_close_container(m);
814 if (r < 0)
815 {
816 return r;
817 }
818 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700819 else if (boost::starts_with(argCode, "(") &&
820 boost::ends_with(argCode, ")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700821 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700822 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700823 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700824 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800825 if (r < 0)
826 {
827 return r;
828 }
829
Ed Tanous1abe55e2018-09-05 08:30:59 -0700830 nlohmann::json::const_iterator it = j->begin();
Ed Tanous81ce6092020-12-17 16:54:55 +0000831 for (const std::string& argCode2 : dbusArgSplit(argType))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700832 {
833 if (it == j->end())
834 {
835 return -1;
836 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000837 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700838 if (r < 0)
839 {
840 return r;
841 }
842 it++;
843 }
844 r = sd_bus_message_close_container(m);
845 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700846 else if (boost::starts_with(argCode, "{") &&
847 boost::ends_with(argCode, "}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700848 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700849 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700850 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700851 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800852 if (r < 0)
853 {
854 return r;
855 }
856
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700857 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700858 if (codes.size() != 2)
859 {
860 return -1;
861 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700862 const std::string& keyType = codes[0];
863 const std::string& valueType = codes[1];
Ed Tanous3174e4d2020-10-07 11:41:22 -0700864 for (const auto& it : j->items())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700865 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700866 r = convertJsonToDbus(m, keyType, it.key());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700867 if (r < 0)
868 {
869 return r;
870 }
871
Ed Tanous2c70f802020-09-28 14:29:23 -0700872 r = convertJsonToDbus(m, valueType, it.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700873 if (r < 0)
874 {
875 return r;
876 }
877 }
878 r = sd_bus_message_close_container(m);
879 }
880 else
881 {
882 return -2;
883 }
884 if (r < 0)
885 {
886 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700887 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700888
Ed Tanous1abe55e2018-09-05 08:30:59 -0700889 if (argTypes.size() > 1)
890 {
891 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700892 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700893 }
Matt Spinler127ea542019-01-14 11:04:28 -0600894
895 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700896}
897
Matt Spinlerd22a7132019-01-14 12:14:30 -0600898template <typename T>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500899int readMessageItem(const std::string& typeCode, sdbusplus::message::message& m,
900 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600901{
902 T value;
903
904 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
905 if (r < 0)
906 {
907 BMCWEB_LOG_ERROR << "sd_bus_message_read_basic on type " << typeCode
908 << " failed!";
909 return r;
910 }
911
912 data = value;
913 return 0;
914}
915
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500916int convertDBusToJSON(const std::string& returnType,
917 sdbusplus::message::message& m, nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600918
Ed Tanous23a21a12020-07-25 04:45:05 +0000919inline int readDictEntryFromMessage(const std::string& typeCode,
920 sdbusplus::message::message& m,
921 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600922{
923 std::vector<std::string> types = dbusArgSplit(typeCode);
924 if (types.size() != 2)
925 {
926 BMCWEB_LOG_ERROR << "wrong number contained types in dictionary: "
927 << types.size();
928 return -1;
929 }
930
931 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
932 typeCode.c_str());
933 if (r < 0)
934 {
935 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container with rc " << r;
936 return r;
937 }
938
939 nlohmann::json key;
940 r = convertDBusToJSON(types[0], m, key);
941 if (r < 0)
942 {
943 return r;
944 }
945
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500946 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -0600947 if (keyPtr == nullptr)
948 {
949 // json doesn't support non-string keys. If we hit this condition,
950 // convert the result to a string so we can proceed
Ed Tanous71f52d92021-02-19 08:51:17 -0800951 key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500952 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -0700953 // in theory this can't fail now, but lets be paranoid about it
954 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -0600955 if (keyPtr == nullptr)
956 {
957 return -1;
958 }
959 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500960 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -0600961
962 r = convertDBusToJSON(types[1], m, value);
963 if (r < 0)
964 {
965 return r;
966 }
967
968 r = sd_bus_message_exit_container(m.get());
969 if (r < 0)
970 {
971 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
972 return r;
973 }
974
975 return 0;
976}
977
Ed Tanous23a21a12020-07-25 04:45:05 +0000978inline int readArrayFromMessage(const std::string& typeCode,
979 sdbusplus::message::message& m,
980 nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -0600981{
982 if (typeCode.size() < 2)
983 {
984 BMCWEB_LOG_ERROR << "Type code " << typeCode
985 << " too small for an array";
986 return -1;
987 }
988
989 std::string containedType = typeCode.substr(1);
990
991 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
992 containedType.c_str());
993 if (r < 0)
994 {
995 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
996 << r;
997 return r;
998 }
999
1000 bool dict = boost::starts_with(containedType, "{") &&
1001 boost::ends_with(containedType, "}");
1002
1003 if (dict)
1004 {
1005 // Remove the { }
1006 containedType = containedType.substr(1, containedType.size() - 2);
1007 data = nlohmann::json::object();
1008 }
1009 else
1010 {
1011 data = nlohmann::json::array();
1012 }
1013
1014 while (true)
1015 {
Ed Tanouse662eae2022-01-25 10:39:19 -08001016 r = sd_bus_message_at_end(m.get(), 0);
Matt Spinler6df8f992019-01-14 12:47:47 -06001017 if (r < 0)
1018 {
1019 BMCWEB_LOG_ERROR << "sd_bus_message_at_end failed";
1020 return r;
1021 }
1022
1023 if (r > 0)
1024 {
1025 break;
1026 }
1027
1028 // Dictionaries are only ever seen in an array
1029 if (dict)
1030 {
1031 r = readDictEntryFromMessage(containedType, m, data);
1032 if (r < 0)
1033 {
1034 return r;
1035 }
1036 }
1037 else
1038 {
1039 data.push_back(nlohmann::json());
1040
1041 r = convertDBusToJSON(containedType, m, data.back());
1042 if (r < 0)
1043 {
1044 return r;
1045 }
1046 }
1047 }
1048
1049 r = sd_bus_message_exit_container(m.get());
1050 if (r < 0)
1051 {
1052 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1053 return r;
1054 }
1055
1056 return 0;
1057}
1058
Ed Tanous23a21a12020-07-25 04:45:05 +00001059inline int readStructFromMessage(const std::string& typeCode,
1060 sdbusplus::message::message& m,
1061 nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001062{
1063 if (typeCode.size() < 3)
1064 {
1065 BMCWEB_LOG_ERROR << "Type code " << typeCode
1066 << " too small for a struct";
1067 return -1;
1068 }
1069
1070 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1071 std::vector<std::string> types = dbusArgSplit(containedTypes);
1072
1073 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1074 containedTypes.c_str());
1075 if (r < 0)
1076 {
1077 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1078 << r;
1079 return r;
1080 }
1081
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001082 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001083 {
1084 data.push_back(nlohmann::json());
1085 r = convertDBusToJSON(type, m, data.back());
1086 if (r < 0)
1087 {
1088 return r;
1089 }
1090 }
1091
1092 r = sd_bus_message_exit_container(m.get());
1093 if (r < 0)
1094 {
1095 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1096 return r;
1097 }
1098 return 0;
1099}
1100
Ed Tanous23a21a12020-07-25 04:45:05 +00001101inline int readVariantFromMessage(sdbusplus::message::message& m,
1102 nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001103{
Ed Tanous543f4402022-01-06 13:12:53 -08001104 const char* containerType = nullptr;
Ed Tanous99131cd2019-10-24 11:12:47 -07001105 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001106 if (r < 0)
1107 {
1108 BMCWEB_LOG_ERROR << "sd_bus_message_peek_type failed";
1109 return r;
1110 }
1111
1112 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1113 containerType);
1114 if (r < 0)
1115 {
1116 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1117 << r;
1118 return r;
1119 }
1120
1121 r = convertDBusToJSON(containerType, m, data);
1122 if (r < 0)
1123 {
1124 return r;
1125 }
1126
1127 r = sd_bus_message_exit_container(m.get());
1128 if (r < 0)
1129 {
1130 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed";
1131 return r;
1132 }
1133
1134 return 0;
1135}
1136
Ed Tanous23a21a12020-07-25 04:45:05 +00001137inline int convertDBusToJSON(const std::string& returnType,
1138 sdbusplus::message::message& m,
1139 nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001140{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001141 int r = 0;
1142 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1143
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001144 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001145 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001146 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001147 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001148 {
1149 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001150 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001151 }
1152
Ed Tanousd4d25792020-09-29 15:15:03 -07001153 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001154 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001155 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001156 if (r < 0)
1157 {
1158 return r;
1159 }
1160 }
1161 else if (typeCode == "b")
1162 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001163 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001164 if (r < 0)
1165 {
1166 return r;
1167 }
1168
Matt Spinlerf39420c2019-01-30 12:57:18 -06001169 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001170 }
1171 else if (typeCode == "u")
1172 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001173 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001174 if (r < 0)
1175 {
1176 return r;
1177 }
1178 }
1179 else if (typeCode == "i")
1180 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001181 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001182 if (r < 0)
1183 {
1184 return r;
1185 }
1186 }
1187 else if (typeCode == "x")
1188 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001189 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001190 if (r < 0)
1191 {
1192 return r;
1193 }
1194 }
1195 else if (typeCode == "t")
1196 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001197 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001198 if (r < 0)
1199 {
1200 return r;
1201 }
1202 }
1203 else if (typeCode == "n")
1204 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001205 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001206 if (r < 0)
1207 {
1208 return r;
1209 }
1210 }
1211 else if (typeCode == "q")
1212 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001213 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001214 if (r < 0)
1215 {
1216 return r;
1217 }
1218 }
1219 else if (typeCode == "y")
1220 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001221 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001222 if (r < 0)
1223 {
1224 return r;
1225 }
1226 }
1227 else if (typeCode == "d")
1228 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001229 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001230 if (r < 0)
1231 {
1232 return r;
1233 }
1234 }
1235 else if (typeCode == "h")
1236 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001237 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001238 if (r < 0)
1239 {
1240 return r;
1241 }
1242 }
Matt Spinler6df8f992019-01-14 12:47:47 -06001243 else if (boost::starts_with(typeCode, "a"))
1244 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001245 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001246 if (r < 0)
1247 {
1248 return r;
1249 }
1250 }
Matt Spinler75c6c672019-01-14 13:01:46 -06001251 else if (boost::starts_with(typeCode, "(") &&
1252 boost::ends_with(typeCode, ")"))
1253 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001254 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001255 if (r < 0)
1256 {
1257 return r;
1258 }
1259 }
Matt Spinler89c19702019-01-14 13:13:00 -06001260 else if (boost::starts_with(typeCode, "v"))
1261 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001262 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001263 if (r < 0)
1264 {
1265 return r;
1266 }
1267 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001268 else
1269 {
Matt Spinlerd22a7132019-01-14 12:14:30 -06001270 BMCWEB_LOG_ERROR << "Invalid D-Bus signature type " << typeCode;
1271 return -2;
1272 }
1273 }
1274
Matt Spinler16caaee2019-01-15 11:40:34 -06001275 return 0;
1276}
1277
Ed Tanousb5a76932020-09-29 16:16:58 -07001278inline void handleMethodResponse(
1279 const std::shared_ptr<InProgressActionData>& transaction,
1280 sdbusplus::message::message& m, const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001281{
Matt Spinler39a4e392019-01-15 11:53:13 -06001282 nlohmann::json data;
1283
1284 int r = convertDBusToJSON(returnType, m, data);
1285 if (r < 0)
1286 {
1287 transaction->outputFailed = true;
1288 return;
1289 }
1290
1291 if (data.is_null())
1292 {
1293 return;
1294 }
1295
1296 if (transaction->methodResponse.is_null())
1297 {
1298 transaction->methodResponse = std::move(data);
1299 return;
1300 }
1301
1302 // If they're both dictionaries or arrays, merge into one.
1303 // Otherwise, make the results an array with every result
1304 // an entry. Could also just fail in that case, but it
1305 // seems better to get the data back somehow.
1306
1307 if (transaction->methodResponse.is_object() && data.is_object())
1308 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001309 for (const auto& obj : data.items())
Matt Spinler39a4e392019-01-15 11:53:13 -06001310 {
1311 // Note: Will overwrite the data for a duplicate key
1312 transaction->methodResponse.emplace(obj.key(),
1313 std::move(obj.value()));
1314 }
1315 return;
1316 }
1317
1318 if (transaction->methodResponse.is_array() && data.is_array())
1319 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001320 for (auto& obj : data)
Matt Spinler39a4e392019-01-15 11:53:13 -06001321 {
1322 transaction->methodResponse.push_back(std::move(obj));
1323 }
1324 return;
1325 }
1326
1327 if (!transaction->convertedToArray)
1328 {
1329 // They are different types. May as well turn them into an array
1330 nlohmann::json j = std::move(transaction->methodResponse);
1331 transaction->methodResponse = nlohmann::json::array();
1332 transaction->methodResponse.push_back(std::move(j));
1333 transaction->methodResponse.push_back(std::move(data));
1334 transaction->convertedToArray = true;
1335 }
1336 else
1337 {
1338 transaction->methodResponse.push_back(std::move(data));
1339 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001340}
1341
Ed Tanousb5a76932020-09-29 16:16:58 -07001342inline void findActionOnInterface(
1343 const std::shared_ptr<InProgressActionData>& transaction,
1344 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001345{
1346 BMCWEB_LOG_DEBUG << "findActionOnInterface for connection "
1347 << connectionName;
1348 crow::connections::systemBus->async_method_call(
1349 [transaction, connectionName{std::string(connectionName)}](
1350 const boost::system::error_code ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001351 const std::string& introspectXml) {
1352 BMCWEB_LOG_DEBUG << "got xml:\n " << introspectXml;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001353 if (ec)
1354 {
1355 BMCWEB_LOG_ERROR
1356 << "Introspect call failed with error: " << ec.message()
1357 << " on process: " << connectionName << "\n";
Matt Spinler318bd892019-01-15 09:59:20 -06001358 return;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001359 }
Matt Spinler318bd892019-01-15 09:59:20 -06001360 tinyxml2::XMLDocument doc;
1361
Ed Tanous81ce6092020-12-17 16:54:55 +00001362 doc.Parse(introspectXml.data(), introspectXml.size());
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001363 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
Matt Spinler318bd892019-01-15 09:59:20 -06001364 if (pRoot == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001365 {
Matt Spinler318bd892019-01-15 09:59:20 -06001366 BMCWEB_LOG_ERROR << "XML document failed to parse "
1367 << connectionName << "\n";
1368 return;
1369 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001370 tinyxml2::XMLElement* interfaceNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001371 pRoot->FirstChildElement("interface");
1372 while (interfaceNode != nullptr)
1373 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001374 const char* thisInterfaceName =
Matt Spinler318bd892019-01-15 09:59:20 -06001375 interfaceNode->Attribute("name");
1376 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001377 {
Matt Spinler318bd892019-01-15 09:59:20 -06001378 if (!transaction->interfaceName.empty() &&
1379 (transaction->interfaceName != thisInterfaceName))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001380 {
Matt Spinler318bd892019-01-15 09:59:20 -06001381 interfaceNode =
1382 interfaceNode->NextSiblingElement("interface");
1383 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001384 }
Matt Spinler318bd892019-01-15 09:59:20 -06001385
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001386 tinyxml2::XMLElement* methodNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001387 interfaceNode->FirstChildElement("method");
1388 while (methodNode != nullptr)
1389 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001390 const char* thisMethodName =
Matt Spinler318bd892019-01-15 09:59:20 -06001391 methodNode->Attribute("name");
1392 BMCWEB_LOG_DEBUG << "Found method: " << thisMethodName;
1393 if (thisMethodName != nullptr &&
1394 thisMethodName == transaction->methodName)
1395 {
1396 BMCWEB_LOG_DEBUG
1397 << "Found method named " << thisMethodName
1398 << " on interface " << thisInterfaceName;
1399 sdbusplus::message::message m =
1400 crow::connections::systemBus->new_method_call(
1401 connectionName.c_str(),
1402 transaction->path.c_str(),
1403 thisInterfaceName,
1404 transaction->methodName.c_str());
1405
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001406 tinyxml2::XMLElement* argumentNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001407 methodNode->FirstChildElement("arg");
1408
Matt Spinler16caaee2019-01-15 11:40:34 -06001409 std::string returnType;
1410
1411 // Find the output type
1412 while (argumentNode != nullptr)
1413 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001414 const char* argDirection =
Matt Spinler16caaee2019-01-15 11:40:34 -06001415 argumentNode->Attribute("direction");
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001416 const char* argType =
Matt Spinler16caaee2019-01-15 11:40:34 -06001417 argumentNode->Attribute("type");
1418 if (argDirection != nullptr &&
1419 argType != nullptr &&
1420 std::string(argDirection) == "out")
1421 {
1422 returnType = argType;
1423 break;
1424 }
1425 argumentNode =
1426 argumentNode->NextSiblingElement("arg");
1427 }
1428
Matt Spinler318bd892019-01-15 09:59:20 -06001429 nlohmann::json::const_iterator argIt =
1430 transaction->arguments.begin();
1431
Matt Spinler16caaee2019-01-15 11:40:34 -06001432 argumentNode = methodNode->FirstChildElement("arg");
1433
Matt Spinler318bd892019-01-15 09:59:20 -06001434 while (argumentNode != nullptr)
1435 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001436 const char* argDirection =
Matt Spinler318bd892019-01-15 09:59:20 -06001437 argumentNode->Attribute("direction");
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001438 const char* argType =
Matt Spinler318bd892019-01-15 09:59:20 -06001439 argumentNode->Attribute("type");
1440 if (argDirection != nullptr &&
1441 argType != nullptr &&
1442 std::string(argDirection) == "in")
1443 {
1444 if (argIt == transaction->arguments.end())
1445 {
1446 transaction->setErrorStatus(
1447 "Invalid method args");
1448 return;
1449 }
1450 if (convertJsonToDbus(m.get(),
1451 std::string(argType),
1452 *argIt) < 0)
1453 {
1454 transaction->setErrorStatus(
1455 "Invalid method arg type");
1456 return;
1457 }
1458
1459 argIt++;
1460 }
1461 argumentNode =
1462 argumentNode->NextSiblingElement("arg");
1463 }
1464
1465 crow::connections::systemBus->async_send(
Matt Spinler16caaee2019-01-15 11:40:34 -06001466 m, [transaction, returnType](
Ed Tanous23a21a12020-07-25 04:45:05 +00001467 boost::system::error_code ec2,
1468 sdbusplus::message::message& m2) {
1469 if (ec2)
Matt Spinler318bd892019-01-15 09:59:20 -06001470 {
Matt Spinler16caaee2019-01-15 11:40:34 -06001471 transaction->methodFailed = true;
Ed Tanous23a21a12020-07-25 04:45:05 +00001472 const sd_bus_error* e = m2.get_error();
Matt Spinler06b1b632019-06-18 16:09:25 -05001473
Ed Tanouse662eae2022-01-25 10:39:19 -08001474 if (e != nullptr)
Matt Spinler06b1b632019-06-18 16:09:25 -05001475 {
1476 setErrorResponse(
1477 transaction->res,
1478 boost::beast::http::status::
1479 bad_request,
1480 e->name, e->message);
1481 }
1482 else
1483 {
1484 setErrorResponse(
1485 transaction->res,
1486 boost::beast::http::status::
1487 bad_request,
1488 "Method call failed",
1489 methodFailedMsg);
1490 }
Matt Spinler318bd892019-01-15 09:59:20 -06001491 return;
1492 }
Ed Tanous3174e4d2020-10-07 11:41:22 -07001493 transaction->methodPassed = true;
Matt Spinler16caaee2019-01-15 11:40:34 -06001494
Ed Tanous23a21a12020-07-25 04:45:05 +00001495 handleMethodResponse(transaction, m2,
Matt Spinler16caaee2019-01-15 11:40:34 -06001496 returnType);
Matt Spinler318bd892019-01-15 09:59:20 -06001497 });
1498 break;
1499 }
1500 methodNode = methodNode->NextSiblingElement("method");
1501 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001502 }
Matt Spinler318bd892019-01-15 09:59:20 -06001503 interfaceNode = interfaceNode->NextSiblingElement("interface");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001504 }
1505 },
1506 connectionName, transaction->path,
1507 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001508}
1509
zhanghch058d1b46d2021-04-01 11:18:24 +08001510inline void handleAction(const crow::Request& req,
1511 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001512 const std::string& objectPath,
1513 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001514{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001515 BMCWEB_LOG_DEBUG << "handleAction on path: " << objectPath << " and method "
1516 << methodName;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001517 nlohmann::json requestDbusData =
1518 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001519
Ed Tanous1abe55e2018-09-05 08:30:59 -07001520 if (requestDbusData.is_discarded())
1521 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001522 setErrorResponse(asyncResp->res,
1523 boost::beast::http::status::bad_request, noJsonDesc,
1524 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001525 return;
1526 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001527 nlohmann::json::iterator data = requestDbusData.find("data");
1528 if (data == requestDbusData.end())
1529 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001530 setErrorResponse(asyncResp->res,
1531 boost::beast::http::status::bad_request, noJsonDesc,
1532 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001533 return;
1534 }
1535
1536 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001537 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001538 setErrorResponse(asyncResp->res,
1539 boost::beast::http::status::bad_request, noJsonDesc,
1540 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001541 return;
1542 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001543 auto transaction = std::make_shared<InProgressActionData>(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001544
1545 transaction->path = objectPath;
1546 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001547 transaction->arguments = std::move(*data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001548 crow::connections::systemBus->async_method_call(
1549 [transaction](
1550 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001551 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1552 interfaceNames) {
Ed Tanous26f69762022-01-25 09:49:11 -08001553 if (ec || interfaceNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001554 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001555 BMCWEB_LOG_ERROR << "Can't find object";
Matt Spinler6db06242018-12-11 11:21:22 -06001556 setErrorResponse(transaction->res,
1557 boost::beast::http::status::not_found,
1558 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001559 return;
1560 }
1561
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001562 BMCWEB_LOG_DEBUG << "GetObject returned " << interfaceNames.size()
1563 << " object(s)";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001564
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001565 for (const std::pair<std::string, std::vector<std::string>>&
1566 object : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001567 {
1568 findActionOnInterface(transaction, object.first);
1569 }
1570 },
1571 "xyz.openbmc_project.ObjectMapper",
1572 "/xyz/openbmc_project/object_mapper",
1573 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
1574 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001575}
1576
zhanghch058d1b46d2021-04-01 11:18:24 +08001577inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1578 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001579{
1580 BMCWEB_LOG_DEBUG << "handleDelete on path: " << objectPath;
1581
1582 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +08001583 [asyncResp, objectPath](
Matt Spinlerde818812018-12-11 16:39:20 -06001584 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001585 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1586 interfaceNames) {
Ed Tanous26f69762022-01-25 09:49:11 -08001587 if (ec || interfaceNames.empty())
Matt Spinlerde818812018-12-11 16:39:20 -06001588 {
1589 BMCWEB_LOG_ERROR << "Can't find object";
zhanghch058d1b46d2021-04-01 11:18:24 +08001590 setErrorResponse(asyncResp->res,
Matt Spinler62d2e8b2019-01-22 13:45:51 -06001591 boost::beast::http::status::method_not_allowed,
1592 methodNotAllowedDesc, methodNotAllowedMsg);
Matt Spinlerde818812018-12-11 16:39:20 -06001593 return;
1594 }
1595
zhanghch058d1b46d2021-04-01 11:18:24 +08001596 auto transaction =
1597 std::make_shared<InProgressActionData>(asyncResp->res);
Matt Spinlerde818812018-12-11 16:39:20 -06001598 transaction->path = objectPath;
1599 transaction->methodName = "Delete";
1600 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
1601
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001602 for (const std::pair<std::string, std::vector<std::string>>&
1603 object : interfaceNames)
Matt Spinlerde818812018-12-11 16:39:20 -06001604 {
1605 findActionOnInterface(transaction, object.first);
1606 }
1607 },
1608 "xyz.openbmc_project.ObjectMapper",
1609 "/xyz/openbmc_project/object_mapper",
1610 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001611 std::array<const char*, 0>());
Matt Spinlerde818812018-12-11 16:39:20 -06001612}
1613
zhanghch058d1b46d2021-04-01 11:18:24 +08001614inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1615 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001616{
1617 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001618 [asyncResp](
1619 const boost::system::error_code ec,
1620 const dbus::utility::MapperGetSubTreePathsResponse& objectPaths) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001621 if (ec)
1622 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001623 setErrorResponse(asyncResp->res,
1624 boost::beast::http::status::not_found,
Matt Spinlerd6091dd2018-12-06 14:08:27 -06001625 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001626 }
1627 else
1628 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001629 asyncResp->res.jsonValue = {{"status", "ok"},
1630 {"message", "200 OK"},
Ed Tanous914e2d52022-01-07 11:38:34 -08001631 {"data", objectPaths}};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001632 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001633 },
1634 "xyz.openbmc_project.ObjectMapper",
1635 "/xyz/openbmc_project/object_mapper",
1636 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", objectPath,
Ed Tanousf839dfe2018-11-12 11:11:15 -08001637 depth, std::array<std::string, 0>());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001638}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001639
zhanghch058d1b46d2021-04-01 11:18:24 +08001640inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1641 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001642{
Ed Tanous049a0512018-11-01 13:58:42 -07001643 BMCWEB_LOG_DEBUG << "Doing enumerate on " << objectPath;
Ed Tanous049a0512018-11-01 13:58:42 -07001644
1645 asyncResp->res.jsonValue = {{"message", "200 OK"},
1646 {"status", "ok"},
1647 {"data", nlohmann::json::object()}};
1648
Ed Tanous1abe55e2018-09-05 08:30:59 -07001649 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001650 [objectPath, asyncResp](
1651 const boost::system::error_code ec,
1652 const dbus::utility::MapperGetSubTreeResponse& objectNames) {
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001653 auto transaction = std::make_shared<InProgressEnumerateData>(
1654 objectPath, asyncResp);
1655
1656 transaction->subtree =
Ed Tanousb9d36b42022-02-26 21:42:46 -08001657 std::make_shared<dbus::utility::MapperGetSubTreeResponse>(
1658 objectNames);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001659
Ed Tanous1abe55e2018-09-05 08:30:59 -07001660 if (ec)
1661 {
Matt Spinler2ae60092018-12-06 10:35:36 -06001662 BMCWEB_LOG_ERROR << "GetSubTree failed on "
1663 << transaction->objectPath;
1664 setErrorResponse(transaction->asyncResp->res,
1665 boost::beast::http::status::not_found,
1666 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001667 return;
1668 }
Ed Tanous64530012018-02-06 17:08:16 -08001669
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001670 // Add the data for the path passed in to the results
1671 // as if GetSubTree returned it, and continue on enumerating
1672 getObjectAndEnumerate(transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001673 },
1674 "xyz.openbmc_project.ObjectMapper",
1675 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -07001676 "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath, 0,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001677 std::array<const char*, 0>());
Ed Tanous64530012018-02-06 17:08:16 -08001678}
Ed Tanous911ac312017-08-15 09:37:42 -07001679
zhanghch058d1b46d2021-04-01 11:18:24 +08001680inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1681 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001682{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001683 BMCWEB_LOG_DEBUG << "handleGet: " << objectPath << " prop:" << destProperty;
1684 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001685 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001686
Ed Tanous1abe55e2018-09-05 08:30:59 -07001687 std::shared_ptr<std::string> path =
1688 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001689
Ed Tanous1abe55e2018-09-05 08:30:59 -07001690 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001691 [asyncResp, path,
1692 propertyName](const boost::system::error_code ec,
1693 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous26f69762022-01-25 09:49:11 -08001694 if (ec || objectNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001695 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001696 setErrorResponse(asyncResp->res,
1697 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001698 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001699 return;
1700 }
1701 std::shared_ptr<nlohmann::json> response =
1702 std::make_shared<nlohmann::json>(nlohmann::json::object());
Ed Tanous7c091622019-05-23 11:42:36 -07001703 // The mapper should never give us an empty interface names
1704 // list, but check anyway
Ed Tanous23a21a12020-07-25 04:45:05 +00001705 for (const std::pair<std::string, std::vector<std::string>>&
Ed Tanous81ce6092020-12-17 16:54:55 +00001706 connection : objectNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001707 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001708 const std::vector<std::string>& interfaceNames =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001709 connection.second;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001710
Ed Tanous26f69762022-01-25 09:49:11 -08001711 if (interfaceNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001712 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001713 setErrorResponse(asyncResp->res,
1714 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001715 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001716 return;
1717 }
1718
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001719 for (const std::string& interface : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001720 {
Matt Spinlerfe7e97d2019-01-30 15:33:21 -06001721 sdbusplus::message::message m =
1722 crow::connections::systemBus->new_method_call(
1723 connection.first.c_str(), path->c_str(),
1724 "org.freedesktop.DBus.Properties", "GetAll");
1725 m.append(interface);
1726 crow::connections::systemBus->async_send(
zhanghch058d1b46d2021-04-01 11:18:24 +08001727 m, [asyncResp, response,
Ed Tanous23a21a12020-07-25 04:45:05 +00001728 propertyName](const boost::system::error_code ec2,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001729 sdbusplus::message::message& msg) {
Ed Tanous23a21a12020-07-25 04:45:05 +00001730 if (ec2)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001731 {
1732 BMCWEB_LOG_ERROR << "Bad dbus request error: "
Ed Tanous23a21a12020-07-25 04:45:05 +00001733 << ec2;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001734 }
1735 else
1736 {
Ed Tanous984a4c22021-06-02 13:38:26 -07001737 nlohmann::json properties;
1738 int r =
1739 convertDBusToJSON("a{sv}", msg, properties);
1740 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001741 {
Ed Tanous984a4c22021-06-02 13:38:26 -07001742 BMCWEB_LOG_ERROR
1743 << "convertDBusToJSON failed";
1744 }
1745 else
1746 {
1747 for (auto& prop : properties.items())
1748 {
1749 // if property name is empty, or
1750 // matches our search query, add it
1751 // to the response json
Ed Tanous1abe55e2018-09-05 08:30:59 -07001752
Ed Tanous984a4c22021-06-02 13:38:26 -07001753 if (propertyName->empty())
1754 {
1755 (*response)[prop.key()] =
1756 std::move(prop.value());
1757 }
1758 else if (prop.key() == *propertyName)
1759 {
1760 *response = std::move(prop.value());
1761 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001762 }
1763 }
1764 }
1765 if (response.use_count() == 1)
1766 {
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001767 if (!propertyName->empty() && response->empty())
1768 {
1769 setErrorResponse(
zhanghch058d1b46d2021-04-01 11:18:24 +08001770 asyncResp->res,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001771 boost::beast::http::status::not_found,
1772 propNotFoundDesc, notFoundMsg);
1773 }
1774 else
1775 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001776 asyncResp->res.jsonValue = {
1777 {"status", "ok"},
1778 {"message", "200 OK"},
1779 {"data", *response}};
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001780 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001781 }
Matt Spinlerfe7e97d2019-01-30 15:33:21 -06001782 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001783 }
1784 }
1785 },
1786 "xyz.openbmc_project.ObjectMapper",
1787 "/xyz/openbmc_project/object_mapper",
1788 "xyz.openbmc_project.ObjectMapper", "GetObject", *path,
1789 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001790}
1791
Ed Tanous1abe55e2018-09-05 08:30:59 -07001792struct AsyncPutRequest
1793{
zhanghch058d1b46d2021-04-01 11:18:24 +08001794 AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
1795 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001796 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001797 ~AsyncPutRequest()
1798 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001799 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001800 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001801 setErrorResponse(asyncResp->res,
1802 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001803 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001804 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001805 }
1806
Ed Tanousecd6a3a2022-01-07 09:18:40 -08001807 AsyncPutRequest(const AsyncPutRequest&) = delete;
1808 AsyncPutRequest(AsyncPutRequest&&) = delete;
1809 AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1810 AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1811
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001812 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001813 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001814 setErrorResponse(asyncResp->res,
1815 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001816 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001817 }
1818
zhanghch058d1b46d2021-04-01 11:18:24 +08001819 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001820 std::string objectPath;
1821 std::string propertyName;
1822 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001823};
1824
zhanghch058d1b46d2021-04-01 11:18:24 +08001825inline void handlePut(const crow::Request& req,
1826 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001827 const std::string& objectPath,
1828 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001829{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001830 if (destProperty.empty())
1831 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001832 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001833 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001834 return;
1835 }
1836
Ed Tanous1abe55e2018-09-05 08:30:59 -07001837 nlohmann::json requestDbusData =
1838 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001839
Ed Tanous1abe55e2018-09-05 08:30:59 -07001840 if (requestDbusData.is_discarded())
1841 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001842 setErrorResponse(asyncResp->res,
1843 boost::beast::http::status::bad_request, noJsonDesc,
1844 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001845 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001846 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001847
Ed Tanous1abe55e2018-09-05 08:30:59 -07001848 nlohmann::json::const_iterator propertyIt = requestDbusData.find("data");
1849 if (propertyIt == requestDbusData.end())
1850 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001851 setErrorResponse(asyncResp->res,
1852 boost::beast::http::status::bad_request, noJsonDesc,
1853 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001854 return;
1855 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001856 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001857 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001858 transaction->objectPath = objectPath;
1859 transaction->propertyName = destProperty;
1860 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001861
Ed Tanous1abe55e2018-09-05 08:30:59 -07001862 crow::connections::systemBus->async_method_call(
Ed Tanous23a21a12020-07-25 04:45:05 +00001863 [transaction](const boost::system::error_code ec2,
Ed Tanousb9d36b42022-02-26 21:42:46 -08001864 const dbus::utility::MapperGetObject& objectNames) {
Ed Tanous26f69762022-01-25 09:49:11 -08001865 if (!ec2 && objectNames.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001866 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001867 setErrorResponse(transaction->asyncResp->res,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001868 boost::beast::http::status::not_found,
1869 propNotFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001870 return;
1871 }
Ed Tanous911ac312017-08-15 09:37:42 -07001872
Ed Tanous23a21a12020-07-25 04:45:05 +00001873 for (const std::pair<std::string, std::vector<std::string>>&
Ed Tanous81ce6092020-12-17 16:54:55 +00001874 connection : objectNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001875 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001876 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001877
Ed Tanous1abe55e2018-09-05 08:30:59 -07001878 crow::connections::systemBus->async_method_call(
1879 [connectionName{std::string(connectionName)},
Ed Tanous23a21a12020-07-25 04:45:05 +00001880 transaction](const boost::system::error_code ec3,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001881 const std::string& introspectXml) {
Ed Tanous23a21a12020-07-25 04:45:05 +00001882 if (ec3)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001883 {
1884 BMCWEB_LOG_ERROR
1885 << "Introspect call failed with error: "
Ed Tanous23a21a12020-07-25 04:45:05 +00001886 << ec3.message()
Ed Tanous1abe55e2018-09-05 08:30:59 -07001887 << " on process: " << connectionName;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001888 transaction->setErrorStatus("Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001889 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001890 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001891 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001892
Ed Tanous1abe55e2018-09-05 08:30:59 -07001893 doc.Parse(introspectXml.c_str());
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001894 tinyxml2::XMLNode* pRoot =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001895 doc.FirstChildElement("node");
1896 if (pRoot == nullptr)
1897 {
1898 BMCWEB_LOG_ERROR << "XML document failed to parse: "
1899 << introspectXml;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001900 transaction->setErrorStatus("Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001901 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001902 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001903 tinyxml2::XMLElement* ifaceNode =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001904 pRoot->FirstChildElement("interface");
1905 while (ifaceNode != nullptr)
1906 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001907 const char* interfaceName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001908 ifaceNode->Attribute("name");
1909 BMCWEB_LOG_DEBUG << "found interface "
1910 << interfaceName;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001911 tinyxml2::XMLElement* propNode =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001912 ifaceNode->FirstChildElement("property");
1913 while (propNode != nullptr)
1914 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001915 const char* propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001916 propNode->Attribute("name");
1917 BMCWEB_LOG_DEBUG << "Found property "
1918 << propertyName;
1919 if (propertyName == transaction->propertyName)
1920 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001921 const char* argType =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001922 propNode->Attribute("type");
1923 if (argType != nullptr)
1924 {
1925 sdbusplus::message::message m =
1926 crow::connections::systemBus
1927 ->new_method_call(
1928 connectionName.c_str(),
1929 transaction->objectPath
1930 .c_str(),
1931 "org.freedesktop.DBus."
1932 "Properties",
1933 "Set");
1934 m.append(interfaceName,
1935 transaction->propertyName);
1936 int r = sd_bus_message_open_container(
1937 m.get(), SD_BUS_TYPE_VARIANT,
1938 argType);
1939 if (r < 0)
1940 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001941 transaction->setErrorStatus(
1942 "Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001943 return;
1944 }
1945 r = convertJsonToDbus(
1946 m.get(), argType,
1947 transaction->propertyValue);
1948 if (r < 0)
1949 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -05001950 if (r == -ERANGE)
1951 {
1952 transaction->setErrorStatus(
1953 "Provided property value "
1954 "is out of range for the "
1955 "property type");
1956 }
1957 else
1958 {
1959 transaction->setErrorStatus(
1960 "Invalid arg type");
1961 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001962 return;
1963 }
1964 r = sd_bus_message_close_container(
1965 m.get());
1966 if (r < 0)
1967 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001968 transaction->setErrorStatus(
1969 "Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001970 return;
1971 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001972 crow::connections::systemBus
1973 ->async_send(
1974 m,
1975 [transaction](
1976 boost::system::error_code
1977 ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001978 sdbusplus::message::message&
Ed Tanous23a21a12020-07-25 04:45:05 +00001979 m2) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001980 BMCWEB_LOG_DEBUG << "sent";
1981 if (ec)
1982 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001983 const sd_bus_error* e =
Ed Tanous23a21a12020-07-25 04:45:05 +00001984 m2.get_error();
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001985 setErrorResponse(
zhanghch058d1b46d2021-04-01 11:18:24 +08001986 transaction
1987 ->asyncResp
1988 ->res,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001989 boost::beast::http::
1990 status::
1991 forbidden,
Ed Tanouse662eae2022-01-25 10:39:19 -08001992 (e) != nullptr
1993 ? e->name
Matt Spinler06b1b632019-06-18 16:09:25 -05001994 : ec.category()
1995 .name(),
Ed Tanouse662eae2022-01-25 10:39:19 -08001996 (e) != nullptr
1997 ? e->message
Matt Spinler06b1b632019-06-18 16:09:25 -05001998 : ec.message());
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001999 }
2000 else
2001 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002002 transaction->asyncResp
2003 ->res.jsonValue = {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06002004 {"status", "ok"},
2005 {"message",
2006 "200 OK"},
2007 {"data", nullptr}};
Ed Tanous1abe55e2018-09-05 08:30:59 -07002008 }
2009 });
2010 }
2011 }
2012 propNode =
2013 propNode->NextSiblingElement("property");
2014 }
2015 ifaceNode =
2016 ifaceNode->NextSiblingElement("interface");
2017 }
2018 },
2019 connectionName, transaction->objectPath,
2020 "org.freedesktop.DBus.Introspectable", "Introspect");
2021 }
2022 },
2023 "xyz.openbmc_project.ObjectMapper",
2024 "/xyz/openbmc_project/object_mapper",
2025 "xyz.openbmc_project.ObjectMapper", "GetObject",
2026 transaction->objectPath, std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07002027}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002028
zhanghch058d1b46d2021-04-01 11:18:24 +08002029inline void handleDBusUrl(const crow::Request& req,
2030 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002031 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002032{
Ed Tanous049a0512018-11-01 13:58:42 -07002033
2034 // If accessing a single attribute, fill in and update objectPath,
2035 // otherwise leave destProperty blank
Ed Tanouse05aec52022-01-25 10:28:56 -08002036 std::string destProperty;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002037 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002038 size_t attrPosition = objectPath.find(attrSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002039 if (attrPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002040 {
2041 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2042 objectPath.length());
2043 objectPath = objectPath.substr(0, attrPosition);
2044 }
2045
Ed Tanousb41187f2019-10-24 16:30:02 -07002046 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002047 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002048 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002049 size_t actionPosition = objectPath.find(actionSeperator);
Ed Tanous71d5d8d2022-01-25 11:04:33 -08002050 if (actionPosition != std::string::npos)
Ed Tanous049a0512018-11-01 13:58:42 -07002051 {
2052 std::string postProperty =
2053 objectPath.substr((actionPosition + strlen(actionSeperator)),
2054 objectPath.length());
2055 objectPath = objectPath.substr(0, actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002056 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002057 return;
2058 }
2059 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002060 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002061 {
2062 if (boost::ends_with(objectPath, "/enumerate"))
2063 {
2064 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2065 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002066 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002067 }
2068 else if (boost::ends_with(objectPath, "/list"))
2069 {
2070 objectPath.erase(objectPath.end() - sizeof("list"),
2071 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002072 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002073 }
2074 else
2075 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002076 // Trim any trailing "/" at the end
2077 if (boost::ends_with(objectPath, "/"))
2078 {
2079 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002080 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002081 }
2082 else
2083 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002084 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002085 }
Ed Tanous049a0512018-11-01 13:58:42 -07002086 }
2087 return;
2088 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002089 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002090 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002091 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002092 return;
2093 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002094 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002095 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002096 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002097 return;
2098 }
Ed Tanous049a0512018-11-01 13:58:42 -07002099
zhanghch058d1b46d2021-04-01 11:18:24 +08002100 setErrorResponse(asyncResp->res,
2101 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002102 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002103}
2104
Ed Tanous23a21a12020-07-25 04:45:05 +00002105inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002106{
2107 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002108 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002109 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002110 [](const crow::Request&,
2111 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2112 asyncResp->res.jsonValue = {{"buses", {{{"name", "system"}}}},
2113 {"status", "ok"}};
Ed Tanous1abe55e2018-09-05 08:30:59 -07002114 });
2115
2116 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002117 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002118 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002119 [](const crow::Request&,
2120 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
P Dheeraj Srujan Kumar83fd8e12021-07-13 02:53:03 +05302121 auto myCallback = [asyncResp](
zhanghch058d1b46d2021-04-01 11:18:24 +08002122 const boost::system::error_code ec,
2123 std::vector<std::string>& names) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07002124 if (ec)
2125 {
2126 BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +08002127 asyncResp->res.result(
Ed Tanous1abe55e2018-09-05 08:30:59 -07002128 boost::beast::http::status::internal_server_error);
2129 }
2130 else
2131 {
2132 std::sort(names.begin(), names.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002133 asyncResp->res.jsonValue = {{"status", "ok"}};
2134 auto& objectsSub = asyncResp->res.jsonValue["objects"];
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002135 for (auto& name : names)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002136 {
2137 objectsSub.push_back({{"name", name}});
2138 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002139 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002140 };
2141 crow::connections::systemBus->async_method_call(
2142 std::move(myCallback), "org.freedesktop.DBus", "/",
2143 "org.freedesktop.DBus", "ListNames");
2144 });
2145
2146 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002147 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002148 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002149 [](const crow::Request&,
2150 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2151 handleList(asyncResp, "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07002152 });
2153
2154 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002155 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002156 .methods(boost::beast::http::verb::get)(
2157 [](const crow::Request& req,
2158 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002159 const std::string& path) {
Ed Tanous049a0512018-11-01 13:58:42 -07002160 std::string objectPath = "/xyz/" + path;
zhanghch058d1b46d2021-04-01 11:18:24 +08002161 handleDBusUrl(req, asyncResp, objectPath);
2162 });
2163
2164 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002165 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002166 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2167 boost::beast::http::verb::delete_)(
2168 [](const crow::Request& req,
2169 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2170 const std::string& path) {
2171 std::string objectPath = "/xyz/" + path;
2172 handleDBusUrl(req, asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002173 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002174
Ed Tanous049a0512018-11-01 13:58:42 -07002175 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002176 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002177 .methods(boost::beast::http::verb::get)(
2178 [](const crow::Request& req,
2179 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2180 const std::string& path) {
2181 std::string objectPath = "/org/" + path;
2182 handleDBusUrl(req, asyncResp, objectPath);
2183 });
Tanousf00032d2018-11-05 01:18:10 -03002184
2185 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002186 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002187 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2188 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002189 [](const crow::Request& req,
2190 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002191 const std::string& path) {
Ed Tanouse1281402019-04-03 07:07:10 -07002192 std::string objectPath = "/org/" + path;
zhanghch058d1b46d2021-04-01 11:18:24 +08002193 handleDBusUrl(req, asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002194 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002195
Ed Tanous1abe55e2018-09-05 08:30:59 -07002196 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002197 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002198 .methods(boost::beast::http::verb::get)(
2199 [](const crow::Request&,
2200 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2201 const std::string& dumpId) {
2202 std::regex validFilename(R"(^[\w\- ]+(\.?[\w\- ]*)$)");
2203 if (!std::regex_match(dumpId, validFilename))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002204 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002205 asyncResp->res.result(
2206 boost::beast::http::status::bad_request);
Ramesh Iyyard9207042019-07-05 08:04:42 -05002207 return;
2208 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002209 std::filesystem::path loc(
2210 "/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002211
zhanghch058d1b46d2021-04-01 11:18:24 +08002212 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002213
zhanghch058d1b46d2021-04-01 11:18:24 +08002214 if (!std::filesystem::exists(loc) ||
2215 !std::filesystem::is_directory(loc))
2216 {
Ed Tanous8cc8ede2022-02-28 10:20:59 -08002217 BMCWEB_LOG_ERROR << loc.string() << "Not found";
zhanghch058d1b46d2021-04-01 11:18:24 +08002218 asyncResp->res.result(
2219 boost::beast::http::status::not_found);
2220 return;
2221 }
2222 std::filesystem::directory_iterator files(loc);
2223
Ed Tanous9eb808c2022-01-25 10:19:23 -08002224 for (const auto& file : files)
zhanghch058d1b46d2021-04-01 11:18:24 +08002225 {
2226 std::ifstream readFile(file.path());
2227 if (!readFile.good())
2228 {
2229 continue;
2230 }
2231
2232 asyncResp->res.addHeader("Content-Type",
2233 "application/octet-stream");
2234
2235 // Assuming only one dump file will be present in the dump
2236 // id directory
2237 std::string dumpFileName = file.path().filename().string();
2238
2239 // Filename should be in alphanumeric, dot and underscore
2240 // Its based on phosphor-debug-collector application
2241 // dumpfile format
2242 std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
2243 if (!std::regex_match(dumpFileName, dumpFileRegex))
2244 {
2245 BMCWEB_LOG_ERROR << "Invalid dump filename "
2246 << dumpFileName;
2247 asyncResp->res.result(
2248 boost::beast::http::status::not_found);
2249 return;
2250 }
2251 std::string contentDispositionParam =
2252 "attachment; filename=\"" + dumpFileName + "\"";
2253
2254 asyncResp->res.addHeader("Content-Disposition",
2255 contentDispositionParam);
2256
2257 asyncResp->res.body() = {
2258 std::istreambuf_iterator<char>(readFile),
2259 std::istreambuf_iterator<char>()};
2260 return;
2261 }
2262 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002263 return;
zhanghch058d1b46d2021-04-01 11:18:24 +08002264 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002265
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002266 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002267 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002268
2269 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002270 [](const crow::Request&,
2271 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002272 const std::string& connection) {
Nan Zhou72374eb2022-01-27 17:06:51 -08002273 introspectObjects(connection, "/", asyncResp);
Ed Tanousb41187f2019-10-24 16:30:02 -07002274 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002275
2276 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002277 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002278 .methods(boost::beast::http::verb::get, boost::beast::http::verb::post)(
2279 [](const crow::Request& req,
2280 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2281 const std::string& processName,
2282 const std::string& requestedPath) {
2283 std::vector<std::string> strs;
2284 boost::split(strs, requestedPath, boost::is_any_of("/"));
2285 std::string objectPath;
2286 std::string interfaceName;
2287 std::string methodName;
2288 auto it = strs.begin();
2289 if (it == strs.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -07002290 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002291 objectPath = "/";
Ed Tanous1abe55e2018-09-05 08:30:59 -07002292 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002293 while (it != strs.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -07002294 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002295 // Check if segment contains ".". If it does, it must be an
2296 // interface
2297 if (it->find(".") != std::string::npos)
2298 {
2299 break;
2300 // This check is necessary as the trailing slash gets
2301 // parsed as part of our <path> specifier above, which
2302 // causes the normal trailing backslash redirector to
2303 // fail.
2304 }
2305 if (!it->empty())
2306 {
2307 objectPath += "/" + *it;
2308 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002309 it++;
2310 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002311 if (it != strs.end())
2312 {
2313 interfaceName = *it;
2314 it++;
Ed Tanous7c091622019-05-23 11:42:36 -07002315
zhanghch058d1b46d2021-04-01 11:18:24 +08002316 // after interface, we might have a method name
2317 if (it != strs.end())
2318 {
2319 methodName = *it;
2320 it++;
2321 }
2322 }
2323 if (it != strs.end())
2324 {
2325 // if there is more levels past the method name, something
2326 // went wrong, return not found
2327 asyncResp->res.result(
2328 boost::beast::http::status::not_found);
2329 return;
2330 }
2331 if (interfaceName.empty())
2332 {
2333 crow::connections::systemBus->async_method_call(
2334 [asyncResp, processName,
2335 objectPath](const boost::system::error_code ec,
2336 const std::string& introspectXml) {
2337 if (ec)
2338 {
2339 BMCWEB_LOG_ERROR
2340 << "Introspect call failed with error: "
2341 << ec.message()
2342 << " on process: " << processName
2343 << " path: " << objectPath << "\n";
2344 return;
2345 }
2346 tinyxml2::XMLDocument doc;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002347
zhanghch058d1b46d2021-04-01 11:18:24 +08002348 doc.Parse(introspectXml.c_str());
2349 tinyxml2::XMLNode* pRoot =
2350 doc.FirstChildElement("node");
2351 if (pRoot == nullptr)
2352 {
2353 BMCWEB_LOG_ERROR
2354 << "XML document failed to parse "
2355 << processName << " " << objectPath << "\n";
2356 asyncResp->res.jsonValue = {
2357 {"status", "XML parse error"}};
2358 asyncResp->res.result(
2359 boost::beast::http::status::
2360 internal_server_error);
2361 return;
2362 }
2363
2364 BMCWEB_LOG_DEBUG << introspectXml;
Ed Tanous7c091622019-05-23 11:42:36 -07002365 asyncResp->res.jsonValue = {
zhanghch058d1b46d2021-04-01 11:18:24 +08002366 {"status", "ok"},
2367 {"bus_name", processName},
2368 {"object_path", objectPath}};
2369 nlohmann::json& interfacesArray =
2370 asyncResp->res.jsonValue["interfaces"];
2371 interfacesArray = nlohmann::json::array();
2372 tinyxml2::XMLElement* interface =
2373 pRoot->FirstChildElement("interface");
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002374
zhanghch058d1b46d2021-04-01 11:18:24 +08002375 while (interface != nullptr)
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002376 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002377 const char* ifaceName =
2378 interface->Attribute("name");
2379 if (ifaceName != nullptr)
Ed Tanous7c091622019-05-23 11:42:36 -07002380 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002381 interfacesArray.push_back(
2382 {{"name", ifaceName}});
2383 }
2384
2385 interface =
2386 interface->NextSiblingElement("interface");
2387 }
2388 },
2389 processName, objectPath,
2390 "org.freedesktop.DBus.Introspectable", "Introspect");
2391 }
2392 else if (methodName.empty())
2393 {
2394 crow::connections::systemBus->async_method_call(
2395 [asyncResp, processName, objectPath,
2396 interfaceName](const boost::system::error_code ec,
2397 const std::string& introspectXml) {
2398 if (ec)
2399 {
2400 BMCWEB_LOG_ERROR
2401 << "Introspect call failed with error: "
2402 << ec.message()
2403 << " on process: " << processName
2404 << " path: " << objectPath << "\n";
2405 return;
2406 }
2407 tinyxml2::XMLDocument doc;
2408
2409 doc.Parse(introspectXml.data(),
2410 introspectXml.size());
2411 tinyxml2::XMLNode* pRoot =
2412 doc.FirstChildElement("node");
2413 if (pRoot == nullptr)
2414 {
2415 BMCWEB_LOG_ERROR
2416 << "XML document failed to parse "
2417 << processName << " " << objectPath << "\n";
2418 asyncResp->res.result(
2419 boost::beast::http::status::
2420 internal_server_error);
2421 return;
2422 }
2423 asyncResp->res.jsonValue = {
2424 {"status", "ok"},
2425 {"bus_name", processName},
2426 {"interface", interfaceName},
2427 {"object_path", objectPath}};
2428
2429 nlohmann::json& methodsArray =
2430 asyncResp->res.jsonValue["methods"];
2431 methodsArray = nlohmann::json::array();
2432
2433 nlohmann::json& signalsArray =
2434 asyncResp->res.jsonValue["signals"];
2435 signalsArray = nlohmann::json::array();
2436
2437 nlohmann::json& propertiesObj =
2438 asyncResp->res.jsonValue["properties"];
2439 propertiesObj = nlohmann::json::object();
2440
2441 // if we know we're the only call, build the
2442 // json directly
2443 tinyxml2::XMLElement* interface =
2444 pRoot->FirstChildElement("interface");
2445 while (interface != nullptr)
2446 {
2447 const char* ifaceName =
2448 interface->Attribute("name");
2449
2450 if (ifaceName != nullptr &&
2451 ifaceName == interfaceName)
2452 {
2453 break;
2454 }
2455
2456 interface =
2457 interface->NextSiblingElement("interface");
2458 }
2459 if (interface == nullptr)
2460 {
2461 // if we got to the end of the list and
2462 // never found a match, throw 404
2463 asyncResp->res.result(
2464 boost::beast::http::status::not_found);
2465 return;
2466 }
2467
2468 tinyxml2::XMLElement* methods =
2469 interface->FirstChildElement("method");
2470 while (methods != nullptr)
2471 {
2472 nlohmann::json argsArray =
2473 nlohmann::json::array();
2474 tinyxml2::XMLElement* arg =
2475 methods->FirstChildElement("arg");
2476 while (arg != nullptr)
2477 {
2478 nlohmann::json thisArg;
2479 for (const char* fieldName :
2480 std::array<const char*, 3>{
2481 "name", "direction", "type"})
Ed Tanous7c091622019-05-23 11:42:36 -07002482 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002483 const char* fieldValue =
2484 arg->Attribute(fieldName);
2485 if (fieldValue != nullptr)
Ed Tanous7c091622019-05-23 11:42:36 -07002486 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002487 thisArg[fieldName] = fieldValue;
Ed Tanous7c091622019-05-23 11:42:36 -07002488 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002489 }
2490 argsArray.push_back(std::move(thisArg));
2491 arg = arg->NextSiblingElement("arg");
2492 }
Ed Tanous7c091622019-05-23 11:42:36 -07002493
zhanghch058d1b46d2021-04-01 11:18:24 +08002494 const char* name = methods->Attribute("name");
2495 if (name != nullptr)
2496 {
2497 std::string uri;
2498 uri.reserve(14 + processName.size() +
2499 objectPath.size() +
2500 interfaceName.size() +
2501 strlen(name));
2502 uri += "/bus/system/";
2503 uri += processName;
2504 uri += objectPath;
2505 uri += "/";
2506 uri += interfaceName;
2507 uri += "/";
2508 uri += name;
2509 methodsArray.push_back(
2510 {{"name", name},
2511 {"uri", std::move(uri)},
2512 {"args", argsArray}});
2513 }
2514 methods = methods->NextSiblingElement("method");
Ed Tanous7c091622019-05-23 11:42:36 -07002515 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002516 tinyxml2::XMLElement* signals =
2517 interface->FirstChildElement("signal");
2518 while (signals != nullptr)
2519 {
2520 nlohmann::json argsArray =
2521 nlohmann::json::array();
2522
2523 tinyxml2::XMLElement* arg =
2524 signals->FirstChildElement("arg");
2525 while (arg != nullptr)
2526 {
2527 const char* name = arg->Attribute("name");
2528 const char* type = arg->Attribute("type");
2529 if (name != nullptr && type != nullptr)
2530 {
2531 argsArray.push_back({
2532 {"name", name},
2533 {"type", type},
2534 });
2535 }
2536 arg = arg->NextSiblingElement("arg");
2537 }
2538 const char* name = signals->Attribute("name");
2539 if (name != nullptr)
2540 {
2541 signalsArray.push_back(
2542 {{"name", name}, {"args", argsArray}});
2543 }
2544
2545 signals = signals->NextSiblingElement("signal");
2546 }
2547
2548 tinyxml2::XMLElement* property =
2549 interface->FirstChildElement("property");
2550 while (property != nullptr)
2551 {
2552 const char* name = property->Attribute("name");
2553 const char* type = property->Attribute("type");
2554 if (type != nullptr && name != nullptr)
2555 {
2556 sdbusplus::message::message m =
2557 crow::connections::systemBus
2558 ->new_method_call(
2559 processName.c_str(),
2560 objectPath.c_str(),
2561 "org.freedesktop."
2562 "DBus."
2563 "Properties",
2564 "Get");
2565 m.append(interfaceName, name);
2566 nlohmann::json& propertyItem =
2567 propertiesObj[name];
2568 crow::connections::systemBus->async_send(
2569 m,
2570 [&propertyItem, asyncResp](
2571 boost::system::error_code& e,
2572 sdbusplus::message::message& msg) {
2573 if (e)
2574 {
2575 return;
2576 }
2577
2578 convertDBusToJSON("v", msg,
2579 propertyItem);
2580 });
2581 }
2582 property =
2583 property->NextSiblingElement("property");
2584 }
2585 },
2586 processName, objectPath,
2587 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002588 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002589 else
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002590 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002591 if (req.method() != boost::beast::http::verb::post)
2592 {
2593 asyncResp->res.result(
2594 boost::beast::http::status::not_found);
2595 return;
2596 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002597
zhanghch058d1b46d2021-04-01 11:18:24 +08002598 nlohmann::json requestDbusData =
2599 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002600
zhanghch058d1b46d2021-04-01 11:18:24 +08002601 if (requestDbusData.is_discarded())
2602 {
2603 asyncResp->res.result(
2604 boost::beast::http::status::bad_request);
2605 return;
2606 }
2607 if (!requestDbusData.is_array())
2608 {
2609 asyncResp->res.result(
2610 boost::beast::http::status::bad_request);
2611 return;
2612 }
2613 auto transaction =
2614 std::make_shared<InProgressActionData>(asyncResp->res);
2615
2616 transaction->path = objectPath;
2617 transaction->methodName = methodName;
2618 transaction->arguments = std::move(requestDbusData);
2619
2620 findActionOnInterface(transaction, processName);
2621 }
2622 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002623}
2624} // namespace openbmc_mapper
2625} // namespace crow