blob: e970de5da356df9a2ad60baeced1cf2d663682cb [file] [log] [blame]
James Feist5b4aa862018-08-16 14:07:01 -07001// Copyright (c) 2018 Intel Corporation
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
Ed Tanousb9b2e0b2018-09-13 13:47:50 -070014
James Feist5b4aa862018-08-16 14:07:01 -070015#pragma once
Ed Tanous911ac312017-08-15 09:37:42 -070016#include <tinyxml2.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -070017
Ed Tanous04e438c2020-10-03 08:06:26 -070018#include <app.hpp>
Ed Tanouse3cb5a32018-08-08 14:16:49 -070019#include <async_resp.hpp>
Ed Tanous1abe55e2018-09-05 08:30:59 -070020#include <boost/algorithm/string.hpp>
21#include <boost/container/flat_set.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -070022#include <dbus_singleton.hpp>
James Feist5b4aa862018-08-16 14:07:01 -070023#include <dbus_utility.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050024#include <sdbusplus/message/types.hpp>
25
James Feist4418c7f2019-04-15 11:09:15 -070026#include <filesystem>
Ed Tanousd4bb9bb2018-05-16 13:36:42 -070027#include <fstream>
Ramesh Iyyard9207042019-07-05 08:04:42 -050028#include <regex>
Ed Tanousb5a76932020-09-29 16:16:58 -070029#include <utility>
Ed Tanous911ac312017-08-15 09:37:42 -070030
Ed Tanous1abe55e2018-09-05 08:30:59 -070031namespace crow
32{
33namespace openbmc_mapper
34{
Ed Tanousba9f9a62017-10-11 16:40:35 -070035
Matt Spinler3ae4ba72018-12-05 14:01:22 -060036using GetSubTreeType = std::vector<
37 std::pair<std::string,
38 std::vector<std::pair<std::string, std::vector<std::string>>>>>;
39
Ed Tanous23a21a12020-07-25 04:45:05 +000040const constexpr char* notFoundMsg = "404 Not Found";
41const constexpr char* badReqMsg = "400 Bad Request";
42const constexpr char* methodNotAllowedMsg = "405 Method Not Allowed";
43const constexpr char* forbiddenMsg = "403 Forbidden";
44const constexpr char* methodFailedMsg = "500 Method Call Failed";
45const constexpr char* methodOutputFailedMsg = "500 Method Output Error";
46const constexpr char* notFoundDesc =
Matt Spinler2ae60092018-12-06 10:35:36 -060047 "org.freedesktop.DBus.Error.FileNotFound: path or object not found";
Ed Tanous23a21a12020-07-25 04:45:05 +000048const constexpr char* propNotFoundDesc =
49 "The specified property cannot be found";
50const constexpr char* noJsonDesc = "No JSON object could be decoded";
51const constexpr char* methodNotFoundDesc =
52 "The specified method cannot be found";
53const constexpr char* methodNotAllowedDesc = "Method not allowed";
54const constexpr char* forbiddenPropDesc =
55 "The specified property cannot be created";
56const constexpr char* forbiddenResDesc =
57 "The specified resource cannot be created";
Matt Spinler2ae60092018-12-06 10:35:36 -060058
Ed Tanous23a21a12020-07-25 04:45:05 +000059inline void setErrorResponse(crow::Response& res,
60 boost::beast::http::status result,
61 const std::string& desc,
62 const std::string_view msg)
Matt Spinler2ae60092018-12-06 10:35:36 -060063{
64 res.result(result);
65 res.jsonValue = {{"data", {{"description", desc}}},
66 {"message", msg},
67 {"status", "error"}};
68}
69
Ed Tanousb5a76932020-09-29 16:16:58 -070070inline void
71 introspectObjects(const std::string& processName,
72 const std::string& objectPath,
73 const std::shared_ptr<bmcweb::AsyncResp>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -070074{
Ed Tanouse3cb5a32018-08-08 14:16:49 -070075 if (transaction->res.jsonValue.is_null())
76 {
77 transaction->res.jsonValue = {{"status", "ok"},
78 {"bus_name", processName},
79 {"objects", nlohmann::json::array()}};
80 }
81
Ed Tanous1abe55e2018-09-05 08:30:59 -070082 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -070083 [transaction, processName{std::string(processName)},
84 objectPath{std::string(objectPath)}](
85 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -050086 const std::string& introspect_xml) {
Ed Tanous1abe55e2018-09-05 08:30:59 -070087 if (ec)
88 {
89 BMCWEB_LOG_ERROR
90 << "Introspect call failed with error: " << ec.message()
91 << " on process: " << processName << " path: " << objectPath
92 << "\n";
Ed Tanouse3cb5a32018-08-08 14:16:49 -070093 return;
94 }
95 transaction->res.jsonValue["objects"].push_back(
96 {{"path", objectPath}});
97
98 tinyxml2::XMLDocument doc;
99
100 doc.Parse(introspect_xml.c_str());
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500101 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700102 if (pRoot == nullptr)
103 {
104 BMCWEB_LOG_ERROR << "XML document failed to parse "
105 << processName << " " << objectPath << "\n";
Ed Tanous911ac312017-08-15 09:37:42 -0700106 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700107 else
108 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500109 tinyxml2::XMLElement* node = pRoot->FirstChildElement("node");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700110 while (node != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700111 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500112 const char* childPath = node->Attribute("name");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700113 if (childPath != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700114 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700115 std::string newpath;
116 if (objectPath != "/")
117 {
118 newpath += objectPath;
119 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700120 newpath += std::string("/") + childPath;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700121 // introspect the subobjects as well
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700122 introspectObjects(processName, newpath, transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700124
125 node = node->NextSiblingElement("node");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700126 }
127 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700128 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700129 processName, objectPath, "org.freedesktop.DBus.Introspectable",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700130 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -0700131}
Ed Tanous64530012018-02-06 17:08:16 -0800132
Ed Tanous23a21a12020-07-25 04:45:05 +0000133inline void getPropertiesForEnumerate(
134 const std::string& objectPath, const std::string& service,
Ed Tanousb5a76932020-09-29 16:16:58 -0700135 const std::string& interface,
136 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600137{
138 BMCWEB_LOG_DEBUG << "getPropertiesForEnumerate " << objectPath << " "
139 << service << " " << interface;
140
141 crow::connections::systemBus->async_method_call(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500142 [asyncResp, objectPath, service, interface](
143 const boost::system::error_code ec,
144 const std::vector<std::pair<
145 std::string, dbus::utility::DbusVariantType>>& propertiesList) {
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600146 if (ec)
147 {
148 BMCWEB_LOG_ERROR << "GetAll on path " << objectPath << " iface "
149 << interface << " service " << service
150 << " failed with code " << ec;
151 return;
152 }
153
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500154 nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
155 nlohmann::json& objectJson = dataJson[objectPath];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600156 if (objectJson.is_null())
157 {
158 objectJson = nlohmann::json::object();
159 }
160
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500161 for (const auto& [name, value] : propertiesList)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600162 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500163 nlohmann::json& propertyJson = objectJson[name];
164 std::visit([&propertyJson](auto&& val) { propertyJson = val; },
Ed Tanousabf2add2019-01-22 16:40:12 -0800165 value);
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600166 }
167 },
168 service, objectPath, "org.freedesktop.DBus.Properties", "GetAll",
169 interface);
170}
171
172// Find any results that weren't picked up by ObjectManagers, to be
173// called after all ObjectManagers are searched for and called.
Ed Tanous23a21a12020-07-25 04:45:05 +0000174inline void findRemainingObjectsForEnumerate(
Ed Tanousb5a76932020-09-29 16:16:58 -0700175 const std::string& objectPath,
176 const std::shared_ptr<GetSubTreeType>& subtree,
177 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600178{
179 BMCWEB_LOG_DEBUG << "findRemainingObjectsForEnumerate";
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500180 const nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600181
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500182 for (const auto& [path, interface_map] : *subtree)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600183 {
184 if (path == objectPath)
185 {
186 // An enumerate does not return the target path's properties
187 continue;
188 }
189 if (dataJson.find(path) == dataJson.end())
190 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500191 for (const auto& [service, interfaces] : interface_map)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600192 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500193 for (const auto& interface : interfaces)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600194 {
195 if (!boost::starts_with(interface, "org.freedesktop.DBus"))
196 {
197 getPropertiesForEnumerate(path, service, interface,
198 asyncResp);
199 }
200 }
201 }
202 }
203 }
204}
205
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600206struct InProgressEnumerateData
207{
Ed Tanous23a21a12020-07-25 04:45:05 +0000208 InProgressEnumerateData(const std::string& objectPathIn,
209 std::shared_ptr<bmcweb::AsyncResp> asyncRespIn) :
210 objectPath(objectPathIn),
Ed Tanousb5a76932020-09-29 16:16:58 -0700211 asyncResp(std::move(asyncRespIn))
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500212 {}
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600213
214 ~InProgressEnumerateData()
215 {
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600216 findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600217 }
218
219 const std::string objectPath;
220 std::shared_ptr<GetSubTreeType> subtree;
221 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
222};
223
Ed Tanous23a21a12020-07-25 04:45:05 +0000224inline void getManagedObjectsForEnumerate(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500225 const std::string& object_name, const std::string& object_manager_path,
226 const std::string& connection_name,
Ed Tanousb5a76932020-09-29 16:16:58 -0700227 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700228{
Ed Tanous049a0512018-11-01 13:58:42 -0700229 BMCWEB_LOG_DEBUG << "getManagedObjectsForEnumerate " << object_name
230 << " object_manager_path " << object_manager_path
231 << " connection_name " << connection_name;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700232 crow::connections::systemBus->async_method_call(
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600233 [transaction, object_name,
Ed Tanous049a0512018-11-01 13:58:42 -0700234 connection_name](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500235 const dbus::utility::ManagedObjectType& objects) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700236 if (ec)
237 {
Ed Tanous049a0512018-11-01 13:58:42 -0700238 BMCWEB_LOG_ERROR << "GetManagedObjects on path " << object_name
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600239 << " on connection " << connection_name
Ed Tanous049a0512018-11-01 13:58:42 -0700240 << " failed with code " << ec;
241 return;
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700242 }
Ed Tanous64530012018-02-06 17:08:16 -0800243
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500244 nlohmann::json& dataJson =
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600245 transaction->asyncResp->res.jsonValue["data"];
Ed Tanous049a0512018-11-01 13:58:42 -0700246
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500247 for (const auto& objectPath : objects)
Ed Tanous049a0512018-11-01 13:58:42 -0700248 {
249 if (boost::starts_with(objectPath.first.str, object_name))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700250 {
Ed Tanous049a0512018-11-01 13:58:42 -0700251 BMCWEB_LOG_DEBUG << "Reading object "
252 << objectPath.first.str;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500253 nlohmann::json& objectJson = dataJson[objectPath.first.str];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700254 if (objectJson.is_null())
255 {
256 objectJson = nlohmann::json::object();
257 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500258 for (const auto& interface : objectPath.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700259 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500260 for (const auto& property : interface.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700261 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500262 nlohmann::json& propertyJson =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700263 objectJson[property.first];
Ed Tanousabf2add2019-01-22 16:40:12 -0800264 std::visit([&propertyJson](
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500265 auto&& val) { propertyJson = val; },
Ed Tanousabf2add2019-01-22 16:40:12 -0800266 property.second);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700267 }
268 }
269 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500270 for (const auto& interface : objectPath.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700271 {
272 if (interface.first == "org.freedesktop.DBus.ObjectManager")
273 {
274 getManagedObjectsForEnumerate(
275 objectPath.first.str, objectPath.first.str,
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600276 connection_name, transaction);
Ed Tanous049a0512018-11-01 13:58:42 -0700277 }
278 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700279 }
280 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700281 connection_name, object_manager_path,
282 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
283}
284
Ed Tanous23a21a12020-07-25 04:45:05 +0000285inline void findObjectManagerPathForEnumerate(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500286 const std::string& object_name, const std::string& connection_name,
Ed Tanousb5a76932020-09-29 16:16:58 -0700287 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700288{
Ed Tanous049a0512018-11-01 13:58:42 -0700289 BMCWEB_LOG_DEBUG << "Finding objectmanager for path " << object_name
290 << " on connection:" << connection_name;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700291 crow::connections::systemBus->async_method_call(
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600292 [transaction, object_name, connection_name](
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700293 const boost::system::error_code ec,
294 const boost::container::flat_map<
295 std::string, boost::container::flat_map<
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500296 std::string, std::vector<std::string>>>&
297 objects) {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700298 if (ec)
299 {
Ed Tanous049a0512018-11-01 13:58:42 -0700300 BMCWEB_LOG_ERROR << "GetAncestors on path " << object_name
301 << " failed with code " << ec;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700302 return;
303 }
304
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500305 for (const auto& pathGroup : objects)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700306 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500307 for (const auto& connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700308 {
309 if (connectionGroup.first == connection_name)
310 {
311 // Found the object manager path for this resource.
312 getManagedObjectsForEnumerate(
Ed Tanous049a0512018-11-01 13:58:42 -0700313 object_name, pathGroup.first, connection_name,
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600314 transaction);
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700315 return;
316 }
317 }
318 }
319 },
320 "xyz.openbmc_project.ObjectMapper",
321 "/xyz/openbmc_project/object_mapper",
322 "xyz.openbmc_project.ObjectMapper", "GetAncestors", object_name,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500323 std::array<const char*, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700324}
Ed Tanous64530012018-02-06 17:08:16 -0800325
Ed Tanous7c091622019-05-23 11:42:36 -0700326// Uses GetObject to add the object info about the target /enumerate path to
327// the results of GetSubTree, as GetSubTree will not return info for the
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600328// target path, and then continues on enumerating the rest of the tree.
Ed Tanousb5a76932020-09-29 16:16:58 -0700329inline void getObjectAndEnumerate(
330 const std::shared_ptr<InProgressEnumerateData>& transaction)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600331{
332 using GetObjectType =
333 std::vector<std::pair<std::string, std::vector<std::string>>>;
334
335 crow::connections::systemBus->async_method_call(
336 [transaction](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500337 const GetObjectType& objects) {
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600338 if (ec)
339 {
340 BMCWEB_LOG_ERROR << "GetObject for path "
341 << transaction->objectPath
342 << " failed with code " << ec;
343 return;
344 }
345
346 BMCWEB_LOG_DEBUG << "GetObject for " << transaction->objectPath
347 << " has " << objects.size() << " entries";
348 if (!objects.empty())
349 {
350 transaction->subtree->emplace_back(transaction->objectPath,
351 objects);
352 }
353
354 // Map indicating connection name, and the path where the object
355 // manager exists
356 boost::container::flat_map<std::string, std::string> connections;
357
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500358 for (const auto& object : *(transaction->subtree))
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600359 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500360 for (const auto& connection : object.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600361 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500362 std::string& objectManagerPath =
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600363 connections[connection.first];
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500364 for (const auto& interface : connection.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600365 {
366 BMCWEB_LOG_DEBUG << connection.first
367 << " has interface " << interface;
368 if (interface == "org.freedesktop.DBus.ObjectManager")
369 {
370 BMCWEB_LOG_DEBUG << "found object manager path "
371 << object.first;
372 objectManagerPath = object.first;
373 }
374 }
375 }
376 }
377 BMCWEB_LOG_DEBUG << "Got " << connections.size() << " connections";
378
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500379 for (const auto& connection : connections)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600380 {
Ed Tanous7c091622019-05-23 11:42:36 -0700381 // If we already know where the object manager is, we don't
382 // need to search for it, we can call directly in to
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600383 // getManagedObjects
384 if (!connection.second.empty())
385 {
386 getManagedObjectsForEnumerate(
387 transaction->objectPath, connection.second,
388 connection.first, transaction);
389 }
390 else
391 {
Ed Tanous7c091622019-05-23 11:42:36 -0700392 // otherwise we need to find the object manager path
393 // before we can continue
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600394 findObjectManagerPathForEnumerate(
395 transaction->objectPath, connection.first, transaction);
396 }
397 }
398 },
399 "xyz.openbmc_project.ObjectMapper",
400 "/xyz/openbmc_project/object_mapper",
401 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500402 transaction->objectPath, std::array<const char*, 0>());
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600403}
Ed Tanous64530012018-02-06 17:08:16 -0800404
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700405// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700406struct InProgressActionData
407{
Ed Tanous23a21a12020-07-25 04:45:05 +0000408 InProgressActionData(crow::Response& resIn) : res(resIn)
409 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700410 ~InProgressActionData()
411 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600412 // Methods could have been called across different owners
413 // and interfaces, where some calls failed and some passed.
414 //
415 // The rules for this are:
416 // * if no method was called - error
417 // * if a method failed and none passed - error
418 // (converse: if at least one method passed - OK)
419 // * for the method output:
420 // * if output processing didn't fail, return the data
421
422 // Only deal with method returns if nothing failed earlier
423 if (res.result() == boost::beast::http::status::ok)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700424 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600425 if (!methodPassed)
426 {
Matt Spinler06b1b632019-06-18 16:09:25 -0500427 if (!methodFailed)
Matt Spinler16caaee2019-01-15 11:40:34 -0600428 {
429 setErrorResponse(res, boost::beast::http::status::not_found,
430 methodNotFoundDesc, notFoundMsg);
431 }
432 }
433 else
434 {
435 if (outputFailed)
436 {
437 setErrorResponse(
438 res, boost::beast::http::status::internal_server_error,
439 "Method output failure", methodOutputFailedMsg);
440 }
441 else
442 {
443 res.jsonValue = {{"status", "ok"},
444 {"message", "200 OK"},
445 {"data", methodResponse}};
446 }
447 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700448 }
Matt Spinler16caaee2019-01-15 11:40:34 -0600449
Ed Tanous1abe55e2018-09-05 08:30:59 -0700450 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700451 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700452
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500453 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700454 {
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600455 setErrorResponse(res, boost::beast::http::status::bad_request, desc,
456 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700457 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500458 crow::Response& res;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700459 std::string path;
460 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600461 std::string interfaceName;
Matt Spinler16caaee2019-01-15 11:40:34 -0600462 bool methodPassed = false;
463 bool methodFailed = false;
464 bool outputFailed = false;
Matt Spinler39a4e392019-01-15 11:53:13 -0600465 bool convertedToArray = false;
Matt Spinler16caaee2019-01-15 11:40:34 -0600466 nlohmann::json methodResponse;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700467 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700468};
469
Ed Tanous23a21a12020-07-25 04:45:05 +0000470inline std::vector<std::string> dbusArgSplit(const std::string& string)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700471{
472 std::vector<std::string> ret;
473 if (string.empty())
474 {
475 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700476 }
Ed Tanous0f0353b2019-10-24 11:37:51 -0700477 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700478 int containerDepth = 0;
479
480 for (std::string::const_iterator character = string.begin();
481 character != string.end(); character++)
482 {
483 ret.back() += *character;
484 switch (*character)
485 {
486 case ('a'):
487 break;
488 case ('('):
489 case ('{'):
490 containerDepth++;
491 break;
492 case ('}'):
493 case (')'):
494 containerDepth--;
495 if (containerDepth == 0)
496 {
497 if (character + 1 != string.end())
498 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700499 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700500 }
501 }
502 break;
503 default:
504 if (containerDepth == 0)
505 {
506 if (character + 1 != string.end())
507 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700508 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700509 }
510 }
511 break;
512 }
513 }
Matt Spinler4ae611d2019-01-11 15:37:06 -0600514
515 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700516}
517
Ed Tanous23a21a12020-07-25 04:45:05 +0000518inline int convertJsonToDbus(sd_bus_message* m, const std::string& arg_type,
519 const nlohmann::json& input_json)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700520{
521 int r = 0;
522 BMCWEB_LOG_DEBUG << "Converting " << input_json.dump()
523 << " to type: " << arg_type;
524 const std::vector<std::string> argTypes = dbusArgSplit(arg_type);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700525
Ed Tanous1abe55e2018-09-05 08:30:59 -0700526 // Assume a single object for now.
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500527 const nlohmann::json* j = &input_json;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700528 nlohmann::json::const_iterator jIt = input_json.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700529
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500530 for (const std::string& argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700531 {
532 // If we are decoding multiple objects, grab the pointer to the
533 // iterator, and increment it for the next loop
534 if (argTypes.size() > 1)
535 {
536 if (jIt == input_json.end())
537 {
538 return -2;
539 }
540 j = &*jIt;
541 jIt++;
542 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500543 const int64_t* intValue = j->get_ptr<const int64_t*>();
544 const std::string* stringValue = j->get_ptr<const std::string*>();
545 const double* doubleValue = j->get_ptr<const double*>();
546 const bool* b = j->get_ptr<const bool*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700547 int64_t v = 0;
548 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700549
Ed Tanous1abe55e2018-09-05 08:30:59 -0700550 // Do some basic type conversions that make sense. uint can be
551 // converted to int. int and uint can be converted to double
Ed Tanous66664f22019-10-11 13:05:49 -0700552 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700553 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500554 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700555 if (uintValue != nullptr)
556 {
557 v = static_cast<int64_t>(*uintValue);
558 intValue = &v;
559 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700560 }
Ed Tanous66664f22019-10-11 13:05:49 -0700561 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700562 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500563 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700564 if (uintValue != nullptr)
565 {
566 d = static_cast<double>(*uintValue);
567 doubleValue = &d;
568 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700569 }
Ed Tanous66664f22019-10-11 13:05:49 -0700570 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700571 {
Ed Tanous66664f22019-10-11 13:05:49 -0700572 if (intValue != nullptr)
573 {
574 d = static_cast<double>(*intValue);
575 doubleValue = &d;
576 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700577 }
578
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700579 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700580 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700581 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700582 {
583 return -1;
584 }
Ed Tanous271584a2019-07-09 16:24:22 -0700585 r = sd_bus_message_append_basic(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500586 m, argCode[0], static_cast<const void*>(stringValue->data()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700587 if (r < 0)
588 {
589 return r;
590 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700591 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700592 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700593 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700594 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700595 {
596 return -1;
597 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500598 if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
599 (*intValue > std::numeric_limits<int32_t>::max()))
600 {
601 return -ERANGE;
602 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700603 int32_t i = static_cast<int32_t>(*intValue);
604 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700605 if (r < 0)
606 {
607 return r;
608 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700609 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700610 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700611 {
612 // lots of ways bool could be represented here. Try them all
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700613 int boolInt = false;
614 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700615 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500616 if (*intValue == 1)
617 {
618 boolInt = true;
619 }
620 else if (*intValue == 0)
621 {
622 boolInt = false;
623 }
624 else
625 {
626 return -ERANGE;
627 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700628 }
629 else if (b != nullptr)
630 {
Matt Spinlera2f02632019-01-18 10:15:35 -0600631 boolInt = *b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700632 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700633 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700634 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700635 boolInt = boost::istarts_with(*stringValue, "t") ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700636 }
637 else
638 {
639 return -1;
640 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700641 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700642 if (r < 0)
643 {
644 return r;
645 }
646 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700647 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700648 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700649 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700650 {
651 return -1;
652 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500653 if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
654 (*intValue > std::numeric_limits<int16_t>::max()))
655 {
656 return -ERANGE;
657 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700658 int16_t n = static_cast<int16_t>(*intValue);
659 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700660 if (r < 0)
661 {
662 return r;
663 }
664 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700665 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700666 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700667 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700668 {
669 return -1;
670 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700671 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700672 if (r < 0)
673 {
674 return r;
675 }
676 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700677 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700678 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500679 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700680 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700681 {
682 return -1;
683 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000684 if (*uintValue > std::numeric_limits<uint8_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500685 {
686 return -ERANGE;
687 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700688 uint8_t y = static_cast<uint8_t>(*uintValue);
689 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700690 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700691 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700692 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500693 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700694 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700695 {
696 return -1;
697 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000698 if (*uintValue > std::numeric_limits<uint16_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500699 {
700 return -ERANGE;
701 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700702 uint16_t q = static_cast<uint16_t>(*uintValue);
703 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700704 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700705 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700706 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500707 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700708 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700709 {
710 return -1;
711 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000712 if (*uintValue > std::numeric_limits<uint32_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500713 {
714 return -ERANGE;
715 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700716 uint32_t u = static_cast<uint32_t>(*uintValue);
717 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700718 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700719 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700720 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500721 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700722 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700723 {
724 return -1;
725 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700726 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700727 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700728 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700729 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500730 if (doubleValue == nullptr)
731 {
732 return -1;
733 }
734 if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
735 (*doubleValue > std::numeric_limits<double>::max()))
736 {
737 return -ERANGE;
738 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700739 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700740 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700741 else if (boost::starts_with(argCode, "a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700742 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700743 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700744 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700745 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700746 if (r < 0)
747 {
748 return r;
749 }
750
Ed Tanous0dfeda62019-10-24 11:21:38 -0700751 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700752 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700753 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700754 if (r < 0)
755 {
756 return r;
757 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700758 }
759 sd_bus_message_close_container(m);
760 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700761 else if (boost::starts_with(argCode, "v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700762 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700763 std::string containedType = argCode.substr(1);
764 BMCWEB_LOG_DEBUG << "variant type: " << argCode
765 << " appending variant of type: " << containedType;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700766 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700767 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700768 if (r < 0)
769 {
770 return r;
771 }
772
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700773 r = convertJsonToDbus(m, containedType, input_json);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700774 if (r < 0)
775 {
776 return r;
777 }
778
779 r = sd_bus_message_close_container(m);
780 if (r < 0)
781 {
782 return r;
783 }
784 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700785 else if (boost::starts_with(argCode, "(") &&
786 boost::ends_with(argCode, ")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700787 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700788 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700789 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700790 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800791 if (r < 0)
792 {
793 return r;
794 }
795
Ed Tanous1abe55e2018-09-05 08:30:59 -0700796 nlohmann::json::const_iterator it = j->begin();
Ed Tanouscb13a392020-07-25 19:02:03 +0000797 for (const std::string& argCode2 : dbusArgSplit(arg_type))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700798 {
799 if (it == j->end())
800 {
801 return -1;
802 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000803 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700804 if (r < 0)
805 {
806 return r;
807 }
808 it++;
809 }
810 r = sd_bus_message_close_container(m);
811 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700812 else if (boost::starts_with(argCode, "{") &&
813 boost::ends_with(argCode, "}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700814 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700815 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700816 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700817 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800818 if (r < 0)
819 {
820 return r;
821 }
822
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700823 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700824 if (codes.size() != 2)
825 {
826 return -1;
827 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700828 const std::string& keyType = codes[0];
829 const std::string& valueType = codes[1];
Ed Tanous3174e4d2020-10-07 11:41:22 -0700830 for (const auto& it : j->items())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700831 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700832 r = convertJsonToDbus(m, keyType, it.key());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700833 if (r < 0)
834 {
835 return r;
836 }
837
Ed Tanous2c70f802020-09-28 14:29:23 -0700838 r = convertJsonToDbus(m, valueType, it.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700839 if (r < 0)
840 {
841 return r;
842 }
843 }
844 r = sd_bus_message_close_container(m);
845 }
846 else
847 {
848 return -2;
849 }
850 if (r < 0)
851 {
852 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700853 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700854
Ed Tanous1abe55e2018-09-05 08:30:59 -0700855 if (argTypes.size() > 1)
856 {
857 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700858 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700859 }
Matt Spinler127ea542019-01-14 11:04:28 -0600860
861 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700862}
863
Matt Spinlerd22a7132019-01-14 12:14:30 -0600864template <typename T>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500865int readMessageItem(const std::string& typeCode, sdbusplus::message::message& m,
866 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600867{
868 T value;
869
870 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
871 if (r < 0)
872 {
873 BMCWEB_LOG_ERROR << "sd_bus_message_read_basic on type " << typeCode
874 << " failed!";
875 return r;
876 }
877
878 data = value;
879 return 0;
880}
881
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500882int convertDBusToJSON(const std::string& returnType,
883 sdbusplus::message::message& m, nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600884
Ed Tanous23a21a12020-07-25 04:45:05 +0000885inline int readDictEntryFromMessage(const std::string& typeCode,
886 sdbusplus::message::message& m,
887 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600888{
889 std::vector<std::string> types = dbusArgSplit(typeCode);
890 if (types.size() != 2)
891 {
892 BMCWEB_LOG_ERROR << "wrong number contained types in dictionary: "
893 << types.size();
894 return -1;
895 }
896
897 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
898 typeCode.c_str());
899 if (r < 0)
900 {
901 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container with rc " << r;
902 return r;
903 }
904
905 nlohmann::json key;
906 r = convertDBusToJSON(types[0], m, key);
907 if (r < 0)
908 {
909 return r;
910 }
911
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500912 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -0600913 if (keyPtr == nullptr)
914 {
915 // json doesn't support non-string keys. If we hit this condition,
916 // convert the result to a string so we can proceed
917 key = key.dump();
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500918 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -0700919 // in theory this can't fail now, but lets be paranoid about it
920 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -0600921 if (keyPtr == nullptr)
922 {
923 return -1;
924 }
925 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500926 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -0600927
928 r = convertDBusToJSON(types[1], m, value);
929 if (r < 0)
930 {
931 return r;
932 }
933
934 r = sd_bus_message_exit_container(m.get());
935 if (r < 0)
936 {
937 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
938 return r;
939 }
940
941 return 0;
942}
943
Ed Tanous23a21a12020-07-25 04:45:05 +0000944inline int readArrayFromMessage(const std::string& typeCode,
945 sdbusplus::message::message& m,
946 nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -0600947{
948 if (typeCode.size() < 2)
949 {
950 BMCWEB_LOG_ERROR << "Type code " << typeCode
951 << " too small for an array";
952 return -1;
953 }
954
955 std::string containedType = typeCode.substr(1);
956
957 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
958 containedType.c_str());
959 if (r < 0)
960 {
961 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
962 << r;
963 return r;
964 }
965
966 bool dict = boost::starts_with(containedType, "{") &&
967 boost::ends_with(containedType, "}");
968
969 if (dict)
970 {
971 // Remove the { }
972 containedType = containedType.substr(1, containedType.size() - 2);
973 data = nlohmann::json::object();
974 }
975 else
976 {
977 data = nlohmann::json::array();
978 }
979
980 while (true)
981 {
982 r = sd_bus_message_at_end(m.get(), false);
983 if (r < 0)
984 {
985 BMCWEB_LOG_ERROR << "sd_bus_message_at_end failed";
986 return r;
987 }
988
989 if (r > 0)
990 {
991 break;
992 }
993
994 // Dictionaries are only ever seen in an array
995 if (dict)
996 {
997 r = readDictEntryFromMessage(containedType, m, data);
998 if (r < 0)
999 {
1000 return r;
1001 }
1002 }
1003 else
1004 {
1005 data.push_back(nlohmann::json());
1006
1007 r = convertDBusToJSON(containedType, m, data.back());
1008 if (r < 0)
1009 {
1010 return r;
1011 }
1012 }
1013 }
1014
1015 r = sd_bus_message_exit_container(m.get());
1016 if (r < 0)
1017 {
1018 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1019 return r;
1020 }
1021
1022 return 0;
1023}
1024
Ed Tanous23a21a12020-07-25 04:45:05 +00001025inline int readStructFromMessage(const std::string& typeCode,
1026 sdbusplus::message::message& m,
1027 nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001028{
1029 if (typeCode.size() < 3)
1030 {
1031 BMCWEB_LOG_ERROR << "Type code " << typeCode
1032 << " too small for a struct";
1033 return -1;
1034 }
1035
1036 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1037 std::vector<std::string> types = dbusArgSplit(containedTypes);
1038
1039 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1040 containedTypes.c_str());
1041 if (r < 0)
1042 {
1043 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1044 << r;
1045 return r;
1046 }
1047
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001048 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001049 {
1050 data.push_back(nlohmann::json());
1051 r = convertDBusToJSON(type, m, data.back());
1052 if (r < 0)
1053 {
1054 return r;
1055 }
1056 }
1057
1058 r = sd_bus_message_exit_container(m.get());
1059 if (r < 0)
1060 {
1061 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1062 return r;
1063 }
1064 return 0;
1065}
1066
Ed Tanous23a21a12020-07-25 04:45:05 +00001067inline int readVariantFromMessage(sdbusplus::message::message& m,
1068 nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001069{
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001070 const char* containerType;
Ed Tanous99131cd2019-10-24 11:12:47 -07001071 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001072 if (r < 0)
1073 {
1074 BMCWEB_LOG_ERROR << "sd_bus_message_peek_type failed";
1075 return r;
1076 }
1077
1078 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1079 containerType);
1080 if (r < 0)
1081 {
1082 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1083 << r;
1084 return r;
1085 }
1086
1087 r = convertDBusToJSON(containerType, m, data);
1088 if (r < 0)
1089 {
1090 return r;
1091 }
1092
1093 r = sd_bus_message_exit_container(m.get());
1094 if (r < 0)
1095 {
1096 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed";
1097 return r;
1098 }
1099
1100 return 0;
1101}
1102
Ed Tanous23a21a12020-07-25 04:45:05 +00001103inline int convertDBusToJSON(const std::string& returnType,
1104 sdbusplus::message::message& m,
1105 nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001106{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001107 int r = 0;
1108 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1109
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001110 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001111 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001112 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001113 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001114 {
1115 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001116 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001117 }
1118
Ed Tanousd4d25792020-09-29 15:15:03 -07001119 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001120 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001121 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001122 if (r < 0)
1123 {
1124 return r;
1125 }
1126 }
1127 else if (typeCode == "b")
1128 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001129 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001130 if (r < 0)
1131 {
1132 return r;
1133 }
1134
Matt Spinlerf39420c2019-01-30 12:57:18 -06001135 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001136 }
1137 else if (typeCode == "u")
1138 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001139 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001140 if (r < 0)
1141 {
1142 return r;
1143 }
1144 }
1145 else if (typeCode == "i")
1146 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001147 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001148 if (r < 0)
1149 {
1150 return r;
1151 }
1152 }
1153 else if (typeCode == "x")
1154 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001155 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001156 if (r < 0)
1157 {
1158 return r;
1159 }
1160 }
1161 else if (typeCode == "t")
1162 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001163 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001164 if (r < 0)
1165 {
1166 return r;
1167 }
1168 }
1169 else if (typeCode == "n")
1170 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001171 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001172 if (r < 0)
1173 {
1174 return r;
1175 }
1176 }
1177 else if (typeCode == "q")
1178 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001179 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001180 if (r < 0)
1181 {
1182 return r;
1183 }
1184 }
1185 else if (typeCode == "y")
1186 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001187 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001188 if (r < 0)
1189 {
1190 return r;
1191 }
1192 }
1193 else if (typeCode == "d")
1194 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001195 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001196 if (r < 0)
1197 {
1198 return r;
1199 }
1200 }
1201 else if (typeCode == "h")
1202 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001203 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001204 if (r < 0)
1205 {
1206 return r;
1207 }
1208 }
Matt Spinler6df8f992019-01-14 12:47:47 -06001209 else if (boost::starts_with(typeCode, "a"))
1210 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001211 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001212 if (r < 0)
1213 {
1214 return r;
1215 }
1216 }
Matt Spinler75c6c672019-01-14 13:01:46 -06001217 else if (boost::starts_with(typeCode, "(") &&
1218 boost::ends_with(typeCode, ")"))
1219 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001220 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001221 if (r < 0)
1222 {
1223 return r;
1224 }
1225 }
Matt Spinler89c19702019-01-14 13:13:00 -06001226 else if (boost::starts_with(typeCode, "v"))
1227 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001228 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001229 if (r < 0)
1230 {
1231 return r;
1232 }
1233 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001234 else
1235 {
Matt Spinlerd22a7132019-01-14 12:14:30 -06001236 BMCWEB_LOG_ERROR << "Invalid D-Bus signature type " << typeCode;
1237 return -2;
1238 }
1239 }
1240
Matt Spinler16caaee2019-01-15 11:40:34 -06001241 return 0;
1242}
1243
Ed Tanousb5a76932020-09-29 16:16:58 -07001244inline void handleMethodResponse(
1245 const std::shared_ptr<InProgressActionData>& transaction,
1246 sdbusplus::message::message& m, const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001247{
Matt Spinler39a4e392019-01-15 11:53:13 -06001248 nlohmann::json data;
1249
1250 int r = convertDBusToJSON(returnType, m, data);
1251 if (r < 0)
1252 {
1253 transaction->outputFailed = true;
1254 return;
1255 }
1256
1257 if (data.is_null())
1258 {
1259 return;
1260 }
1261
1262 if (transaction->methodResponse.is_null())
1263 {
1264 transaction->methodResponse = std::move(data);
1265 return;
1266 }
1267
1268 // If they're both dictionaries or arrays, merge into one.
1269 // Otherwise, make the results an array with every result
1270 // an entry. Could also just fail in that case, but it
1271 // seems better to get the data back somehow.
1272
1273 if (transaction->methodResponse.is_object() && data.is_object())
1274 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001275 for (const auto& obj : data.items())
Matt Spinler39a4e392019-01-15 11:53:13 -06001276 {
1277 // Note: Will overwrite the data for a duplicate key
1278 transaction->methodResponse.emplace(obj.key(),
1279 std::move(obj.value()));
1280 }
1281 return;
1282 }
1283
1284 if (transaction->methodResponse.is_array() && data.is_array())
1285 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001286 for (auto& obj : data)
Matt Spinler39a4e392019-01-15 11:53:13 -06001287 {
1288 transaction->methodResponse.push_back(std::move(obj));
1289 }
1290 return;
1291 }
1292
1293 if (!transaction->convertedToArray)
1294 {
1295 // They are different types. May as well turn them into an array
1296 nlohmann::json j = std::move(transaction->methodResponse);
1297 transaction->methodResponse = nlohmann::json::array();
1298 transaction->methodResponse.push_back(std::move(j));
1299 transaction->methodResponse.push_back(std::move(data));
1300 transaction->convertedToArray = true;
1301 }
1302 else
1303 {
1304 transaction->methodResponse.push_back(std::move(data));
1305 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001306}
1307
Ed Tanousb5a76932020-09-29 16:16:58 -07001308inline void findActionOnInterface(
1309 const std::shared_ptr<InProgressActionData>& transaction,
1310 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001311{
1312 BMCWEB_LOG_DEBUG << "findActionOnInterface for connection "
1313 << connectionName;
1314 crow::connections::systemBus->async_method_call(
1315 [transaction, connectionName{std::string(connectionName)}](
1316 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001317 const std::string& introspect_xml) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001318 BMCWEB_LOG_DEBUG << "got xml:\n " << introspect_xml;
1319 if (ec)
1320 {
1321 BMCWEB_LOG_ERROR
1322 << "Introspect call failed with error: " << ec.message()
1323 << " on process: " << connectionName << "\n";
Matt Spinler318bd892019-01-15 09:59:20 -06001324 return;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001325 }
Matt Spinler318bd892019-01-15 09:59:20 -06001326 tinyxml2::XMLDocument doc;
1327
1328 doc.Parse(introspect_xml.data(), introspect_xml.size());
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001329 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
Matt Spinler318bd892019-01-15 09:59:20 -06001330 if (pRoot == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001331 {
Matt Spinler318bd892019-01-15 09:59:20 -06001332 BMCWEB_LOG_ERROR << "XML document failed to parse "
1333 << connectionName << "\n";
1334 return;
1335 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001336 tinyxml2::XMLElement* interfaceNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001337 pRoot->FirstChildElement("interface");
1338 while (interfaceNode != nullptr)
1339 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001340 const char* thisInterfaceName =
Matt Spinler318bd892019-01-15 09:59:20 -06001341 interfaceNode->Attribute("name");
1342 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001343 {
Matt Spinler318bd892019-01-15 09:59:20 -06001344 if (!transaction->interfaceName.empty() &&
1345 (transaction->interfaceName != thisInterfaceName))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001346 {
Matt Spinler318bd892019-01-15 09:59:20 -06001347 interfaceNode =
1348 interfaceNode->NextSiblingElement("interface");
1349 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001350 }
Matt Spinler318bd892019-01-15 09:59:20 -06001351
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001352 tinyxml2::XMLElement* methodNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001353 interfaceNode->FirstChildElement("method");
1354 while (methodNode != nullptr)
1355 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001356 const char* thisMethodName =
Matt Spinler318bd892019-01-15 09:59:20 -06001357 methodNode->Attribute("name");
1358 BMCWEB_LOG_DEBUG << "Found method: " << thisMethodName;
1359 if (thisMethodName != nullptr &&
1360 thisMethodName == transaction->methodName)
1361 {
1362 BMCWEB_LOG_DEBUG
1363 << "Found method named " << thisMethodName
1364 << " on interface " << thisInterfaceName;
1365 sdbusplus::message::message m =
1366 crow::connections::systemBus->new_method_call(
1367 connectionName.c_str(),
1368 transaction->path.c_str(),
1369 thisInterfaceName,
1370 transaction->methodName.c_str());
1371
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001372 tinyxml2::XMLElement* argumentNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001373 methodNode->FirstChildElement("arg");
1374
Matt Spinler16caaee2019-01-15 11:40:34 -06001375 std::string returnType;
1376
1377 // Find the output type
1378 while (argumentNode != nullptr)
1379 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001380 const char* argDirection =
Matt Spinler16caaee2019-01-15 11:40:34 -06001381 argumentNode->Attribute("direction");
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001382 const char* argType =
Matt Spinler16caaee2019-01-15 11:40:34 -06001383 argumentNode->Attribute("type");
1384 if (argDirection != nullptr &&
1385 argType != nullptr &&
1386 std::string(argDirection) == "out")
1387 {
1388 returnType = argType;
1389 break;
1390 }
1391 argumentNode =
1392 argumentNode->NextSiblingElement("arg");
1393 }
1394
Matt Spinler318bd892019-01-15 09:59:20 -06001395 nlohmann::json::const_iterator argIt =
1396 transaction->arguments.begin();
1397
Matt Spinler16caaee2019-01-15 11:40:34 -06001398 argumentNode = methodNode->FirstChildElement("arg");
1399
Matt Spinler318bd892019-01-15 09:59:20 -06001400 while (argumentNode != nullptr)
1401 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001402 const char* argDirection =
Matt Spinler318bd892019-01-15 09:59:20 -06001403 argumentNode->Attribute("direction");
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001404 const char* argType =
Matt Spinler318bd892019-01-15 09:59:20 -06001405 argumentNode->Attribute("type");
1406 if (argDirection != nullptr &&
1407 argType != nullptr &&
1408 std::string(argDirection) == "in")
1409 {
1410 if (argIt == transaction->arguments.end())
1411 {
1412 transaction->setErrorStatus(
1413 "Invalid method args");
1414 return;
1415 }
1416 if (convertJsonToDbus(m.get(),
1417 std::string(argType),
1418 *argIt) < 0)
1419 {
1420 transaction->setErrorStatus(
1421 "Invalid method arg type");
1422 return;
1423 }
1424
1425 argIt++;
1426 }
1427 argumentNode =
1428 argumentNode->NextSiblingElement("arg");
1429 }
1430
1431 crow::connections::systemBus->async_send(
Matt Spinler16caaee2019-01-15 11:40:34 -06001432 m, [transaction, returnType](
Ed Tanous23a21a12020-07-25 04:45:05 +00001433 boost::system::error_code ec2,
1434 sdbusplus::message::message& m2) {
1435 if (ec2)
Matt Spinler318bd892019-01-15 09:59:20 -06001436 {
Matt Spinler16caaee2019-01-15 11:40:34 -06001437 transaction->methodFailed = true;
Ed Tanous23a21a12020-07-25 04:45:05 +00001438 const sd_bus_error* e = m2.get_error();
Matt Spinler06b1b632019-06-18 16:09:25 -05001439
1440 if (e)
1441 {
1442 setErrorResponse(
1443 transaction->res,
1444 boost::beast::http::status::
1445 bad_request,
1446 e->name, e->message);
1447 }
1448 else
1449 {
1450 setErrorResponse(
1451 transaction->res,
1452 boost::beast::http::status::
1453 bad_request,
1454 "Method call failed",
1455 methodFailedMsg);
1456 }
Matt Spinler318bd892019-01-15 09:59:20 -06001457 return;
1458 }
Ed Tanous3174e4d2020-10-07 11:41:22 -07001459 transaction->methodPassed = true;
Matt Spinler16caaee2019-01-15 11:40:34 -06001460
Ed Tanous23a21a12020-07-25 04:45:05 +00001461 handleMethodResponse(transaction, m2,
Matt Spinler16caaee2019-01-15 11:40:34 -06001462 returnType);
Matt Spinler318bd892019-01-15 09:59:20 -06001463 });
1464 break;
1465 }
1466 methodNode = methodNode->NextSiblingElement("method");
1467 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001468 }
Matt Spinler318bd892019-01-15 09:59:20 -06001469 interfaceNode = interfaceNode->NextSiblingElement("interface");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001470 }
1471 },
1472 connectionName, transaction->path,
1473 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001474}
1475
Ed Tanous23a21a12020-07-25 04:45:05 +00001476inline void handleAction(const crow::Request& req, crow::Response& res,
1477 const std::string& objectPath,
1478 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001479{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001480 BMCWEB_LOG_DEBUG << "handleAction on path: " << objectPath << " and method "
1481 << methodName;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001482 nlohmann::json requestDbusData =
1483 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001484
Ed Tanous1abe55e2018-09-05 08:30:59 -07001485 if (requestDbusData.is_discarded())
1486 {
Matt Spinler6db06242018-12-11 11:21:22 -06001487 setErrorResponse(res, boost::beast::http::status::bad_request,
1488 noJsonDesc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001489 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001490 return;
1491 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001492 nlohmann::json::iterator data = requestDbusData.find("data");
1493 if (data == requestDbusData.end())
1494 {
Matt Spinler6db06242018-12-11 11:21:22 -06001495 setErrorResponse(res, boost::beast::http::status::bad_request,
1496 noJsonDesc, badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001497 res.end();
1498 return;
1499 }
1500
1501 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001502 {
Matt Spinler6db06242018-12-11 11:21:22 -06001503 setErrorResponse(res, boost::beast::http::status::bad_request,
1504 noJsonDesc, badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001505 res.end();
1506 return;
1507 }
1508 auto transaction = std::make_shared<InProgressActionData>(res);
1509
1510 transaction->path = objectPath;
1511 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001512 transaction->arguments = std::move(*data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001513 crow::connections::systemBus->async_method_call(
1514 [transaction](
1515 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001516 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1517 interfaceNames) {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001518 if (ec || interfaceNames.size() <= 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001519 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001520 BMCWEB_LOG_ERROR << "Can't find object";
Matt Spinler6db06242018-12-11 11:21:22 -06001521 setErrorResponse(transaction->res,
1522 boost::beast::http::status::not_found,
1523 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001524 return;
1525 }
1526
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001527 BMCWEB_LOG_DEBUG << "GetObject returned " << interfaceNames.size()
1528 << " object(s)";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001529
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001530 for (const std::pair<std::string, std::vector<std::string>>&
1531 object : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001532 {
1533 findActionOnInterface(transaction, object.first);
1534 }
1535 },
1536 "xyz.openbmc_project.ObjectMapper",
1537 "/xyz/openbmc_project/object_mapper",
1538 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
1539 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001540}
1541
Ed Tanouscb13a392020-07-25 19:02:03 +00001542inline void handleDelete(crow::Response& res, const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001543{
1544 BMCWEB_LOG_DEBUG << "handleDelete on path: " << objectPath;
1545
1546 crow::connections::systemBus->async_method_call(
1547 [&res, objectPath](
1548 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001549 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1550 interfaceNames) {
Matt Spinlerde818812018-12-11 16:39:20 -06001551 if (ec || interfaceNames.size() <= 0)
1552 {
1553 BMCWEB_LOG_ERROR << "Can't find object";
Matt Spinler62d2e8b2019-01-22 13:45:51 -06001554 setErrorResponse(res,
1555 boost::beast::http::status::method_not_allowed,
1556 methodNotAllowedDesc, methodNotAllowedMsg);
Matt Spinlerde818812018-12-11 16:39:20 -06001557 res.end();
1558 return;
1559 }
1560
1561 auto transaction = std::make_shared<InProgressActionData>(res);
1562 transaction->path = objectPath;
1563 transaction->methodName = "Delete";
1564 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
1565
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001566 for (const std::pair<std::string, std::vector<std::string>>&
1567 object : interfaceNames)
Matt Spinlerde818812018-12-11 16:39:20 -06001568 {
1569 findActionOnInterface(transaction, object.first);
1570 }
1571 },
1572 "xyz.openbmc_project.ObjectMapper",
1573 "/xyz/openbmc_project/object_mapper",
1574 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001575 std::array<const char*, 0>());
Matt Spinlerde818812018-12-11 16:39:20 -06001576}
1577
Ed Tanous23a21a12020-07-25 04:45:05 +00001578inline void handleList(crow::Response& res, const std::string& objectPath,
1579 int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001580{
1581 crow::connections::systemBus->async_method_call(
1582 [&res](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001583 std::vector<std::string>& objectPaths) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001584 if (ec)
1585 {
Matt Spinlerd6091dd2018-12-06 14:08:27 -06001586 setErrorResponse(res, boost::beast::http::status::not_found,
1587 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001588 }
1589 else
1590 {
1591 res.jsonValue = {{"status", "ok"},
1592 {"message", "200 OK"},
1593 {"data", std::move(objectPaths)}};
1594 }
1595 res.end();
1596 },
1597 "xyz.openbmc_project.ObjectMapper",
1598 "/xyz/openbmc_project/object_mapper",
1599 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", objectPath,
Ed Tanousf839dfe2018-11-12 11:11:15 -08001600 depth, std::array<std::string, 0>());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001601}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001602
Ed Tanous23a21a12020-07-25 04:45:05 +00001603inline void handleEnumerate(crow::Response& res, const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001604{
Ed Tanous049a0512018-11-01 13:58:42 -07001605 BMCWEB_LOG_DEBUG << "Doing enumerate on " << objectPath;
1606 auto asyncResp = std::make_shared<bmcweb::AsyncResp>(res);
1607
1608 asyncResp->res.jsonValue = {{"message", "200 OK"},
1609 {"status", "ok"},
1610 {"data", nlohmann::json::object()}};
1611
Ed Tanous1abe55e2018-09-05 08:30:59 -07001612 crow::connections::systemBus->async_method_call(
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001613 [objectPath, asyncResp](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001614 GetSubTreeType& object_names) {
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001615 auto transaction = std::make_shared<InProgressEnumerateData>(
1616 objectPath, asyncResp);
1617
1618 transaction->subtree =
1619 std::make_shared<GetSubTreeType>(std::move(object_names));
1620
Ed Tanous1abe55e2018-09-05 08:30:59 -07001621 if (ec)
1622 {
Matt Spinler2ae60092018-12-06 10:35:36 -06001623 BMCWEB_LOG_ERROR << "GetSubTree failed on "
1624 << transaction->objectPath;
1625 setErrorResponse(transaction->asyncResp->res,
1626 boost::beast::http::status::not_found,
1627 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001628 return;
1629 }
Ed Tanous64530012018-02-06 17:08:16 -08001630
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001631 // Add the data for the path passed in to the results
1632 // as if GetSubTree returned it, and continue on enumerating
1633 getObjectAndEnumerate(transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001634 },
1635 "xyz.openbmc_project.ObjectMapper",
1636 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -07001637 "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath, 0,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001638 std::array<const char*, 0>());
Ed Tanous64530012018-02-06 17:08:16 -08001639}
Ed Tanous911ac312017-08-15 09:37:42 -07001640
Ed Tanous23a21a12020-07-25 04:45:05 +00001641inline void handleGet(crow::Response& res, std::string& objectPath,
1642 std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001643{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001644 BMCWEB_LOG_DEBUG << "handleGet: " << objectPath << " prop:" << destProperty;
1645 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001646 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001647
Ed Tanous1abe55e2018-09-05 08:30:59 -07001648 std::shared_ptr<std::string> path =
1649 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001650
Ed Tanous1abe55e2018-09-05 08:30:59 -07001651 using GetObjectType =
1652 std::vector<std::pair<std::string, std::vector<std::string>>>;
1653 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001654 [&res, path, propertyName](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001655 const GetObjectType& object_names) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001656 if (ec || object_names.size() <= 0)
1657 {
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001658 setErrorResponse(res, boost::beast::http::status::not_found,
1659 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001660 res.end();
1661 return;
1662 }
1663 std::shared_ptr<nlohmann::json> response =
1664 std::make_shared<nlohmann::json>(nlohmann::json::object());
Ed Tanous7c091622019-05-23 11:42:36 -07001665 // The mapper should never give us an empty interface names
1666 // list, but check anyway
Ed Tanous23a21a12020-07-25 04:45:05 +00001667 for (const std::pair<std::string, std::vector<std::string>>&
Ed Tanous1abe55e2018-09-05 08:30:59 -07001668 connection : object_names)
1669 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001670 const std::vector<std::string>& interfaceNames =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001671 connection.second;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001672
Ed Tanous1abe55e2018-09-05 08:30:59 -07001673 if (interfaceNames.size() <= 0)
1674 {
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001675 setErrorResponse(res, boost::beast::http::status::not_found,
1676 notFoundDesc, notFoundMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001677 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001678 return;
1679 }
1680
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001681 for (const std::string& interface : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001682 {
Matt Spinlerfe7e97d2019-01-30 15:33:21 -06001683 sdbusplus::message::message m =
1684 crow::connections::systemBus->new_method_call(
1685 connection.first.c_str(), path->c_str(),
1686 "org.freedesktop.DBus.Properties", "GetAll");
1687 m.append(interface);
1688 crow::connections::systemBus->async_send(
1689 m, [&res, response,
Ed Tanous23a21a12020-07-25 04:45:05 +00001690 propertyName](const boost::system::error_code ec2,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001691 sdbusplus::message::message& msg) {
Ed Tanous23a21a12020-07-25 04:45:05 +00001692 if (ec2)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001693 {
1694 BMCWEB_LOG_ERROR << "Bad dbus request error: "
Ed Tanous23a21a12020-07-25 04:45:05 +00001695 << ec2;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001696 }
1697 else
1698 {
Matt Spinlerfe7e97d2019-01-30 15:33:21 -06001699 nlohmann::json properties;
1700 int r =
1701 convertDBusToJSON("a{sv}", msg, properties);
1702 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001703 {
Matt Spinlerfe7e97d2019-01-30 15:33:21 -06001704 BMCWEB_LOG_ERROR
1705 << "convertDBusToJSON failed";
1706 }
1707 else
1708 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001709 for (auto& prop : properties.items())
Matt Spinlerfe7e97d2019-01-30 15:33:21 -06001710 {
Ed Tanous7c091622019-05-23 11:42:36 -07001711 // if property name is empty, or
1712 // matches our search query, add it
1713 // to the response json
Ed Tanous1abe55e2018-09-05 08:30:59 -07001714
Matt Spinlerfe7e97d2019-01-30 15:33:21 -06001715 if (propertyName->empty())
1716 {
1717 (*response)[prop.key()] =
1718 std::move(prop.value());
1719 }
1720 else if (prop.key() == *propertyName)
1721 {
1722 *response = std::move(prop.value());
1723 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001724 }
1725 }
1726 }
1727 if (response.use_count() == 1)
1728 {
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001729 if (!propertyName->empty() && response->empty())
1730 {
1731 setErrorResponse(
1732 res,
1733 boost::beast::http::status::not_found,
1734 propNotFoundDesc, notFoundMsg);
1735 }
1736 else
1737 {
1738 res.jsonValue = {{"status", "ok"},
1739 {"message", "200 OK"},
1740 {"data", *response}};
1741 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001742 res.end();
1743 }
Matt Spinlerfe7e97d2019-01-30 15:33:21 -06001744 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001745 }
1746 }
1747 },
1748 "xyz.openbmc_project.ObjectMapper",
1749 "/xyz/openbmc_project/object_mapper",
1750 "xyz.openbmc_project.ObjectMapper", "GetObject", *path,
1751 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001752}
1753
Ed Tanous1abe55e2018-09-05 08:30:59 -07001754struct AsyncPutRequest
1755{
Ed Tanous23a21a12020-07-25 04:45:05 +00001756 AsyncPutRequest(crow::Response& resIn) : res(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001757 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001758 ~AsyncPutRequest()
1759 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001760 if (res.jsonValue.empty())
1761 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001762 setErrorResponse(res, boost::beast::http::status::forbidden,
1763 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001764 }
1765
1766 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001767 }
1768
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001769 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001770 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001771 setErrorResponse(res, boost::beast::http::status::internal_server_error,
1772 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001773 }
1774
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001775 crow::Response& res;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001776 std::string objectPath;
1777 std::string propertyName;
1778 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001779};
1780
Ed Tanous23a21a12020-07-25 04:45:05 +00001781inline void handlePut(const crow::Request& req, crow::Response& res,
1782 const std::string& objectPath,
1783 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001784{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001785 if (destProperty.empty())
1786 {
1787 setErrorResponse(res, boost::beast::http::status::forbidden,
1788 forbiddenResDesc, forbiddenMsg);
1789 res.end();
1790 return;
1791 }
1792
Ed Tanous1abe55e2018-09-05 08:30:59 -07001793 nlohmann::json requestDbusData =
1794 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001795
Ed Tanous1abe55e2018-09-05 08:30:59 -07001796 if (requestDbusData.is_discarded())
1797 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001798 setErrorResponse(res, boost::beast::http::status::bad_request,
1799 noJsonDesc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001800 res.end();
1801 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001802 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001803
Ed Tanous1abe55e2018-09-05 08:30:59 -07001804 nlohmann::json::const_iterator propertyIt = requestDbusData.find("data");
1805 if (propertyIt == requestDbusData.end())
1806 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001807 setErrorResponse(res, boost::beast::http::status::bad_request,
1808 noJsonDesc, badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001809 res.end();
1810 return;
1811 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001812 const nlohmann::json& propertySetValue = *propertyIt;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001813 auto transaction = std::make_shared<AsyncPutRequest>(res);
1814 transaction->objectPath = objectPath;
1815 transaction->propertyName = destProperty;
1816 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001817
Ed Tanous1abe55e2018-09-05 08:30:59 -07001818 using GetObjectType =
1819 std::vector<std::pair<std::string, std::vector<std::string>>>;
Ed Tanous911ac312017-08-15 09:37:42 -07001820
Ed Tanous1abe55e2018-09-05 08:30:59 -07001821 crow::connections::systemBus->async_method_call(
Ed Tanous23a21a12020-07-25 04:45:05 +00001822 [transaction](const boost::system::error_code ec2,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001823 const GetObjectType& object_names) {
Ed Tanous23a21a12020-07-25 04:45:05 +00001824 if (!ec2 && object_names.size() <= 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001825 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001826 setErrorResponse(transaction->res,
1827 boost::beast::http::status::not_found,
1828 propNotFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001829 return;
1830 }
Ed Tanous911ac312017-08-15 09:37:42 -07001831
Ed Tanous23a21a12020-07-25 04:45:05 +00001832 for (const std::pair<std::string, std::vector<std::string>>&
Ed Tanous1abe55e2018-09-05 08:30:59 -07001833 connection : object_names)
1834 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001835 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001836
Ed Tanous1abe55e2018-09-05 08:30:59 -07001837 crow::connections::systemBus->async_method_call(
1838 [connectionName{std::string(connectionName)},
Ed Tanous23a21a12020-07-25 04:45:05 +00001839 transaction](const boost::system::error_code ec3,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001840 const std::string& introspectXml) {
Ed Tanous23a21a12020-07-25 04:45:05 +00001841 if (ec3)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001842 {
1843 BMCWEB_LOG_ERROR
1844 << "Introspect call failed with error: "
Ed Tanous23a21a12020-07-25 04:45:05 +00001845 << ec3.message()
Ed Tanous1abe55e2018-09-05 08:30:59 -07001846 << " on process: " << connectionName;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001847 transaction->setErrorStatus("Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001848 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001849 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001850 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001851
Ed Tanous1abe55e2018-09-05 08:30:59 -07001852 doc.Parse(introspectXml.c_str());
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001853 tinyxml2::XMLNode* pRoot =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001854 doc.FirstChildElement("node");
1855 if (pRoot == nullptr)
1856 {
1857 BMCWEB_LOG_ERROR << "XML document failed to parse: "
1858 << introspectXml;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001859 transaction->setErrorStatus("Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001860 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001861 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001862 tinyxml2::XMLElement* ifaceNode =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001863 pRoot->FirstChildElement("interface");
1864 while (ifaceNode != nullptr)
1865 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001866 const char* interfaceName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001867 ifaceNode->Attribute("name");
1868 BMCWEB_LOG_DEBUG << "found interface "
1869 << interfaceName;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001870 tinyxml2::XMLElement* propNode =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001871 ifaceNode->FirstChildElement("property");
1872 while (propNode != nullptr)
1873 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001874 const char* propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001875 propNode->Attribute("name");
1876 BMCWEB_LOG_DEBUG << "Found property "
1877 << propertyName;
1878 if (propertyName == transaction->propertyName)
1879 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001880 const char* argType =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001881 propNode->Attribute("type");
1882 if (argType != nullptr)
1883 {
1884 sdbusplus::message::message m =
1885 crow::connections::systemBus
1886 ->new_method_call(
1887 connectionName.c_str(),
1888 transaction->objectPath
1889 .c_str(),
1890 "org.freedesktop.DBus."
1891 "Properties",
1892 "Set");
1893 m.append(interfaceName,
1894 transaction->propertyName);
1895 int r = sd_bus_message_open_container(
1896 m.get(), SD_BUS_TYPE_VARIANT,
1897 argType);
1898 if (r < 0)
1899 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001900 transaction->setErrorStatus(
1901 "Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001902 return;
1903 }
1904 r = convertJsonToDbus(
1905 m.get(), argType,
1906 transaction->propertyValue);
1907 if (r < 0)
1908 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -05001909 if (r == -ERANGE)
1910 {
1911 transaction->setErrorStatus(
1912 "Provided property value "
1913 "is out of range for the "
1914 "property type");
1915 }
1916 else
1917 {
1918 transaction->setErrorStatus(
1919 "Invalid arg type");
1920 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001921 return;
1922 }
1923 r = sd_bus_message_close_container(
1924 m.get());
1925 if (r < 0)
1926 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001927 transaction->setErrorStatus(
1928 "Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001929 return;
1930 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001931 crow::connections::systemBus
1932 ->async_send(
1933 m,
1934 [transaction](
1935 boost::system::error_code
1936 ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001937 sdbusplus::message::message&
Ed Tanous23a21a12020-07-25 04:45:05 +00001938 m2) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001939 BMCWEB_LOG_DEBUG << "sent";
1940 if (ec)
1941 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001942 const sd_bus_error* e =
Ed Tanous23a21a12020-07-25 04:45:05 +00001943 m2.get_error();
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001944 setErrorResponse(
1945 transaction->res,
1946 boost::beast::http::
1947 status::
1948 forbidden,
Matt Spinler06b1b632019-06-18 16:09:25 -05001949 (e) ? e->name
1950 : ec.category()
1951 .name(),
1952 (e) ? e->message
1953 : ec.message());
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001954 }
1955 else
1956 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001957 transaction->res
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001958 .jsonValue = {
1959 {"status", "ok"},
1960 {"message",
1961 "200 OK"},
1962 {"data", nullptr}};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001963 }
1964 });
1965 }
1966 }
1967 propNode =
1968 propNode->NextSiblingElement("property");
1969 }
1970 ifaceNode =
1971 ifaceNode->NextSiblingElement("interface");
1972 }
1973 },
1974 connectionName, transaction->objectPath,
1975 "org.freedesktop.DBus.Introspectable", "Introspect");
1976 }
1977 },
1978 "xyz.openbmc_project.ObjectMapper",
1979 "/xyz/openbmc_project/object_mapper",
1980 "xyz.openbmc_project.ObjectMapper", "GetObject",
1981 transaction->objectPath, std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001982}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001983
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001984inline void handleDBusUrl(const crow::Request& req, crow::Response& res,
1985 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07001986{
Ed Tanous049a0512018-11-01 13:58:42 -07001987
1988 // If accessing a single attribute, fill in and update objectPath,
1989 // otherwise leave destProperty blank
1990 std::string destProperty = "";
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001991 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07001992 size_t attrPosition = objectPath.find(attrSeperator);
1993 if (attrPosition != objectPath.npos)
1994 {
1995 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
1996 objectPath.length());
1997 objectPath = objectPath.substr(0, attrPosition);
1998 }
1999
Ed Tanousb41187f2019-10-24 16:30:02 -07002000 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002001 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002002 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002003 size_t actionPosition = objectPath.find(actionSeperator);
2004 if (actionPosition != objectPath.npos)
2005 {
2006 std::string postProperty =
2007 objectPath.substr((actionPosition + strlen(actionSeperator)),
2008 objectPath.length());
2009 objectPath = objectPath.substr(0, actionPosition);
2010 handleAction(req, res, objectPath, postProperty);
2011 return;
2012 }
2013 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002014 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002015 {
2016 if (boost::ends_with(objectPath, "/enumerate"))
2017 {
2018 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2019 objectPath.end());
2020 handleEnumerate(res, objectPath);
2021 }
2022 else if (boost::ends_with(objectPath, "/list"))
2023 {
2024 objectPath.erase(objectPath.end() - sizeof("list"),
2025 objectPath.end());
2026 handleList(res, objectPath);
2027 }
2028 else
2029 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002030 // Trim any trailing "/" at the end
2031 if (boost::ends_with(objectPath, "/"))
2032 {
2033 objectPath.pop_back();
2034 handleList(res, objectPath, 1);
2035 }
2036 else
2037 {
2038 handleGet(res, objectPath, destProperty);
2039 }
Ed Tanous049a0512018-11-01 13:58:42 -07002040 }
2041 return;
2042 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002043 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002044 {
2045 handlePut(req, res, objectPath, destProperty);
2046 return;
2047 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002048 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002049 {
Ed Tanouscb13a392020-07-25 19:02:03 +00002050 handleDelete(res, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002051 return;
2052 }
Ed Tanous049a0512018-11-01 13:58:42 -07002053
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002054 setErrorResponse(res, boost::beast::http::status::method_not_allowed,
2055 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002056 res.end();
2057}
2058
Ed Tanous23a21a12020-07-25 04:45:05 +00002059inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002060{
2061 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous23a21a12020-07-25 04:45:05 +00002062 .privileges({"Login"})
Ed Tanousb41187f2019-10-24 16:30:02 -07002063 .methods(boost::beast::http::verb::get)(
Ed Tanouscb13a392020-07-25 19:02:03 +00002064 [](const crow::Request&, crow::Response& res) {
Gunnar Millscaa3ce32020-07-08 14:46:53 -05002065 res.jsonValue = {{"buses", {{{"name", "system"}}}},
Ed Tanous1abe55e2018-09-05 08:30:59 -07002066 {"status", "ok"}};
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002067 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -07002068 });
2069
2070 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous23a21a12020-07-25 04:45:05 +00002071 .privileges({"Login"})
Ed Tanousb41187f2019-10-24 16:30:02 -07002072 .methods(boost::beast::http::verb::get)(
Ed Tanouscb13a392020-07-25 19:02:03 +00002073 [](const crow::Request&, crow::Response& res) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07002074 auto myCallback = [&res](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002075 std::vector<std::string>& names) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07002076 if (ec)
2077 {
2078 BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
2079 res.result(
2080 boost::beast::http::status::internal_server_error);
2081 }
2082 else
2083 {
2084 std::sort(names.begin(), names.end());
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002085 res.jsonValue = {{"status", "ok"}};
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002086 auto& objectsSub = res.jsonValue["objects"];
2087 for (auto& name : names)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002088 {
2089 objectsSub.push_back({{"name", name}});
2090 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002091 }
2092 res.end();
2093 };
2094 crow::connections::systemBus->async_method_call(
2095 std::move(myCallback), "org.freedesktop.DBus", "/",
2096 "org.freedesktop.DBus", "ListNames");
2097 });
2098
2099 BMCWEB_ROUTE(app, "/list/")
Ed Tanous23a21a12020-07-25 04:45:05 +00002100 .privileges({"Login"})
Ed Tanousb41187f2019-10-24 16:30:02 -07002101 .methods(boost::beast::http::verb::get)(
Ed Tanouscb13a392020-07-25 19:02:03 +00002102 [](const crow::Request&, crow::Response& res) {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002103 handleList(res, "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07002104 });
2105
2106 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous23a21a12020-07-25 04:45:05 +00002107 .privileges({"Login"})
Ed Tanousb41187f2019-10-24 16:30:02 -07002108 .methods(boost::beast::http::verb::get)([](const crow::Request& req,
2109 crow::Response& res,
2110 const std::string& path) {
Tanousf00032d2018-11-05 01:18:10 -03002111 std::string objectPath = "/xyz/" + path;
2112 handleDBusUrl(req, res, objectPath);
2113 });
2114
2115 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous23a21a12020-07-25 04:45:05 +00002116 .privileges({"ConfigureComponents", "ConfigureManager"})
Ed Tanousb41187f2019-10-24 16:30:02 -07002117 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2118 boost::beast::http::verb::delete_)(
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002119 [](const crow::Request& req, crow::Response& res,
2120 const std::string& path) {
Ed Tanous049a0512018-11-01 13:58:42 -07002121 std::string objectPath = "/xyz/" + path;
2122 handleDBusUrl(req, res, objectPath);
2123 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002124
Ed Tanous049a0512018-11-01 13:58:42 -07002125 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous23a21a12020-07-25 04:45:05 +00002126 .privileges({"Login"})
Ed Tanousb41187f2019-10-24 16:30:02 -07002127 .methods(boost::beast::http::verb::get)([](const crow::Request& req,
2128 crow::Response& res,
2129 const std::string& path) {
Ed Tanouse1281402019-04-03 07:07:10 -07002130 std::string objectPath = "/org/" + path;
Tanousf00032d2018-11-05 01:18:10 -03002131 handleDBusUrl(req, res, objectPath);
2132 });
2133
2134 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous23a21a12020-07-25 04:45:05 +00002135 .privileges({"ConfigureComponents", "ConfigureManager"})
Ed Tanousb41187f2019-10-24 16:30:02 -07002136 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2137 boost::beast::http::verb::delete_)(
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002138 [](const crow::Request& req, crow::Response& res,
2139 const std::string& path) {
Ed Tanouse1281402019-04-03 07:07:10 -07002140 std::string objectPath = "/org/" + path;
Ed Tanous049a0512018-11-01 13:58:42 -07002141 handleDBusUrl(req, res, objectPath);
2142 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002143
Ed Tanous1abe55e2018-09-05 08:30:59 -07002144 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous23a21a12020-07-25 04:45:05 +00002145 .privileges({"ConfigureManager"})
Ed Tanouscb13a392020-07-25 19:02:03 +00002146 .methods(boost::beast::http::verb::get)([](const crow::Request&,
Ed Tanousb41187f2019-10-24 16:30:02 -07002147 crow::Response& res,
2148 const std::string& dumpId) {
Ed Tanous3174e4d2020-10-07 11:41:22 -07002149 std::regex validFilename(R"(^[\w\- ]+(\.?[\w\- ]*)$)");
Ed Tanous1abe55e2018-09-05 08:30:59 -07002150 if (!std::regex_match(dumpId, validFilename))
2151 {
Ed Tanousad18f072018-11-14 14:07:48 -08002152 res.result(boost::beast::http::status::bad_request);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002153 res.end();
2154 return;
2155 }
James Feistf6150402019-01-08 10:36:20 -08002156 std::filesystem::path loc(
Ed Tanous1abe55e2018-09-05 08:30:59 -07002157 "/var/lib/phosphor-debug-collector/dumps");
2158
Ed Tanousad18f072018-11-14 14:07:48 -08002159 loc /= dumpId;
Ed Tanous1abe55e2018-09-05 08:30:59 -07002160
James Feistf6150402019-01-08 10:36:20 -08002161 if (!std::filesystem::exists(loc) ||
2162 !std::filesystem::is_directory(loc))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002163 {
Ed Tanousad18f072018-11-14 14:07:48 -08002164 BMCWEB_LOG_ERROR << loc << "Not found";
Ed Tanous1abe55e2018-09-05 08:30:59 -07002165 res.result(boost::beast::http::status::not_found);
2166 res.end();
2167 return;
2168 }
James Feistf6150402019-01-08 10:36:20 -08002169 std::filesystem::directory_iterator files(loc);
Ed Tanousad18f072018-11-14 14:07:48 -08002170
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002171 for (auto& file : files)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002172 {
2173 std::ifstream readFile(file.path());
Ed Tanousad18f072018-11-14 14:07:48 -08002174 if (!readFile.good())
Ed Tanous1abe55e2018-09-05 08:30:59 -07002175 {
2176 continue;
2177 }
Ramesh Iyyard9207042019-07-05 08:04:42 -05002178
Ed Tanous1abe55e2018-09-05 08:30:59 -07002179 res.addHeader("Content-Type", "application/octet-stream");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002180
2181 // Assuming only one dump file will be present in the dump id
2182 // directory
2183 std::string dumpFileName = file.path().filename().string();
2184
2185 // Filename should be in alphanumeric, dot and underscore
2186 // Its based on phosphor-debug-collector application dumpfile
2187 // format
2188 std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
2189 if (!std::regex_match(dumpFileName, dumpFileRegex))
2190 {
2191 BMCWEB_LOG_ERROR << "Invalid dump filename "
2192 << dumpFileName;
2193 res.result(boost::beast::http::status::not_found);
2194 res.end();
2195 return;
2196 }
2197 std::string contentDispositionParam =
2198 "attachment; filename=\"" + dumpFileName + "\"";
2199
2200 res.addHeader("Content-Disposition", contentDispositionParam);
2201
Ed Tanous1abe55e2018-09-05 08:30:59 -07002202 res.body() = {std::istreambuf_iterator<char>(readFile),
2203 std::istreambuf_iterator<char>()};
2204 res.end();
Ed Tanousad18f072018-11-14 14:07:48 -08002205 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07002206 }
2207 res.result(boost::beast::http::status::not_found);
2208 res.end();
2209 return;
2210 });
2211
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002212 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous23a21a12020-07-25 04:45:05 +00002213 .privileges({"Login"})
Ed Tanousb41187f2019-10-24 16:30:02 -07002214
2215 .methods(boost::beast::http::verb::get)(
Ed Tanouscb13a392020-07-25 19:02:03 +00002216 [](const crow::Request&, crow::Response& res,
Ed Tanousb41187f2019-10-24 16:30:02 -07002217 const std::string& Connection) {
2218 introspectObjects(Connection, "/",
2219 std::make_shared<bmcweb::AsyncResp>(res));
2220 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002221
2222 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous23a21a12020-07-25 04:45:05 +00002223 .privileges({"ConfigureComponents", "ConfigureManager"})
Ed Tanousb41187f2019-10-24 16:30:02 -07002224 .methods(
2225 boost::beast::http::verb::get,
2226 boost::beast::http::verb::post)([](const crow::Request& req,
2227 crow::Response& res,
2228 const std::string& processName,
2229 const std::string&
2230 requestedPath) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07002231 std::vector<std::string> strs;
2232 boost::split(strs, requestedPath, boost::is_any_of("/"));
2233 std::string objectPath;
2234 std::string interfaceName;
2235 std::string methodName;
2236 auto it = strs.begin();
2237 if (it == strs.end())
2238 {
2239 objectPath = "/";
2240 }
2241 while (it != strs.end())
2242 {
2243 // Check if segment contains ".". If it does, it must be an
2244 // interface
2245 if (it->find(".") != std::string::npos)
2246 {
2247 break;
Gunnar Millscaa3ce32020-07-08 14:46:53 -05002248 // This check is necessary as the trailing slash gets
Ed Tanous7c091622019-05-23 11:42:36 -07002249 // parsed as part of our <path> specifier above, which
2250 // causes the normal trailing backslash redirector to
2251 // fail.
Ed Tanous1abe55e2018-09-05 08:30:59 -07002252 }
Ed Tanous3174e4d2020-10-07 11:41:22 -07002253 if (!it->empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07002254 {
2255 objectPath += "/" + *it;
2256 }
2257 it++;
2258 }
2259 if (it != strs.end())
2260 {
2261 interfaceName = *it;
2262 it++;
2263
2264 // after interface, we might have a method name
2265 if (it != strs.end())
2266 {
2267 methodName = *it;
2268 it++;
2269 }
2270 }
2271 if (it != strs.end())
2272 {
Ed Tanous7c091622019-05-23 11:42:36 -07002273 // if there is more levels past the method name, something
2274 // went wrong, return not found
Ed Tanous1abe55e2018-09-05 08:30:59 -07002275 res.result(boost::beast::http::status::not_found);
AppaRao Puli3c27ed32020-03-31 01:21:57 +05302276 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -07002277 return;
2278 }
2279 if (interfaceName.empty())
2280 {
Ed Tanous7c091622019-05-23 11:42:36 -07002281 std::shared_ptr<bmcweb::AsyncResp> asyncResp =
2282 std::make_shared<bmcweb::AsyncResp>(res);
2283
Ed Tanous1abe55e2018-09-05 08:30:59 -07002284 crow::connections::systemBus->async_method_call(
Ed Tanous7c091622019-05-23 11:42:36 -07002285 [asyncResp, processName,
Ed Tanous1abe55e2018-09-05 08:30:59 -07002286 objectPath](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002287 const std::string& introspect_xml) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07002288 if (ec)
2289 {
2290 BMCWEB_LOG_ERROR
2291 << "Introspect call failed with error: "
2292 << ec.message()
2293 << " on process: " << processName
2294 << " path: " << objectPath << "\n";
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002295 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07002296 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002297 tinyxml2::XMLDocument doc;
2298
2299 doc.Parse(introspect_xml.c_str());
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002300 tinyxml2::XMLNode* pRoot =
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002301 doc.FirstChildElement("node");
2302 if (pRoot == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002303 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002304 BMCWEB_LOG_ERROR << "XML document failed to parse "
2305 << processName << " " << objectPath
2306 << "\n";
Ed Tanous7c091622019-05-23 11:42:36 -07002307 asyncResp->res.jsonValue = {
2308 {"status", "XML parse error"}};
2309 asyncResp->res.result(boost::beast::http::status::
2310 internal_server_error);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002311 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07002312 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002313
2314 BMCWEB_LOG_DEBUG << introspect_xml;
Ed Tanous7c091622019-05-23 11:42:36 -07002315 asyncResp->res.jsonValue = {
2316 {"status", "ok"},
2317 {"bus_name", processName},
2318 {"object_path", objectPath}};
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002319 nlohmann::json& interfacesArray =
Ed Tanous7c091622019-05-23 11:42:36 -07002320 asyncResp->res.jsonValue["interfaces"];
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002321 interfacesArray = nlohmann::json::array();
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002322 tinyxml2::XMLElement* interface =
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002323 pRoot->FirstChildElement("interface");
2324
2325 while (interface != nullptr)
2326 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002327 const char* ifaceName =
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002328 interface->Attribute("name");
2329 if (ifaceName != nullptr)
2330 {
2331 interfacesArray.push_back(
2332 {{"name", ifaceName}});
2333 }
2334
2335 interface =
2336 interface->NextSiblingElement("interface");
2337 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002338 },
2339 processName, objectPath,
2340 "org.freedesktop.DBus.Introspectable", "Introspect");
2341 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002342 else if (methodName.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07002343 {
Ed Tanous7c091622019-05-23 11:42:36 -07002344 std::shared_ptr<bmcweb::AsyncResp> asyncResp =
2345 std::make_shared<bmcweb::AsyncResp>(res);
2346
Ed Tanous1abe55e2018-09-05 08:30:59 -07002347 crow::connections::systemBus->async_method_call(
Ed Tanous7c091622019-05-23 11:42:36 -07002348 [asyncResp, processName, objectPath,
2349 interfaceName](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002350 const std::string& introspect_xml) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07002351 if (ec)
2352 {
2353 BMCWEB_LOG_ERROR
2354 << "Introspect call failed with error: "
2355 << ec.message()
2356 << " on process: " << processName
2357 << " path: " << objectPath << "\n";
Ed Tanous7c091622019-05-23 11:42:36 -07002358 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07002359 }
Ed Tanous7c091622019-05-23 11:42:36 -07002360 tinyxml2::XMLDocument doc;
2361
2362 doc.Parse(introspect_xml.data(), introspect_xml.size());
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002363 tinyxml2::XMLNode* pRoot =
Ed Tanous7c091622019-05-23 11:42:36 -07002364 doc.FirstChildElement("node");
2365 if (pRoot == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002366 {
Ed Tanous7c091622019-05-23 11:42:36 -07002367 BMCWEB_LOG_ERROR << "XML document failed to parse "
2368 << processName << " " << objectPath
2369 << "\n";
2370 asyncResp->res.result(boost::beast::http::status::
2371 internal_server_error);
2372 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07002373 }
Ed Tanous7c091622019-05-23 11:42:36 -07002374 asyncResp->res.jsonValue = {
2375 {"status", "ok"},
2376 {"bus_name", processName},
2377 {"interface", interfaceName},
2378 {"object_path", objectPath}};
2379
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002380 nlohmann::json& methodsArray =
Ed Tanous7c091622019-05-23 11:42:36 -07002381 asyncResp->res.jsonValue["methods"];
2382 methodsArray = nlohmann::json::array();
2383
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002384 nlohmann::json& signalsArray =
Ed Tanous7c091622019-05-23 11:42:36 -07002385 asyncResp->res.jsonValue["signals"];
2386 signalsArray = nlohmann::json::array();
2387
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002388 nlohmann::json& propertiesObj =
Ed Tanous7c091622019-05-23 11:42:36 -07002389 asyncResp->res.jsonValue["properties"];
2390 propertiesObj = nlohmann::json::object();
2391
2392 // if we know we're the only call, build the
2393 // json directly
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002394 tinyxml2::XMLElement* interface =
Ed Tanous7c091622019-05-23 11:42:36 -07002395 pRoot->FirstChildElement("interface");
2396 while (interface != nullptr)
2397 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002398 const char* ifaceName =
Ed Tanous7c091622019-05-23 11:42:36 -07002399 interface->Attribute("name");
2400
2401 if (ifaceName != nullptr &&
2402 ifaceName == interfaceName)
2403 {
2404 break;
2405 }
2406
2407 interface =
2408 interface->NextSiblingElement("interface");
2409 }
2410 if (interface == nullptr)
2411 {
2412 // if we got to the end of the list and
2413 // never found a match, throw 404
2414 asyncResp->res.result(
2415 boost::beast::http::status::not_found);
2416 return;
2417 }
2418
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002419 tinyxml2::XMLElement* methods =
Ed Tanous7c091622019-05-23 11:42:36 -07002420 interface->FirstChildElement("method");
2421 while (methods != nullptr)
2422 {
2423 nlohmann::json argsArray = nlohmann::json::array();
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002424 tinyxml2::XMLElement* arg =
Ed Tanous7c091622019-05-23 11:42:36 -07002425 methods->FirstChildElement("arg");
2426 while (arg != nullptr)
2427 {
2428 nlohmann::json thisArg;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002429 for (const char* fieldName :
2430 std::array<const char*, 3>{
Ed Tanous7c091622019-05-23 11:42:36 -07002431 "name", "direction", "type"})
2432 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002433 const char* fieldValue =
Ed Tanous7c091622019-05-23 11:42:36 -07002434 arg->Attribute(fieldName);
2435 if (fieldValue != nullptr)
2436 {
2437 thisArg[fieldName] = fieldValue;
2438 }
2439 }
2440 argsArray.push_back(std::move(thisArg));
2441 arg = arg->NextSiblingElement("arg");
2442 }
2443
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002444 const char* name = methods->Attribute("name");
Ed Tanous7c091622019-05-23 11:42:36 -07002445 if (name != nullptr)
2446 {
Ed Tanousf23b7292020-10-15 09:41:17 -07002447 std::string uri;
2448 uri.reserve(14 + processName.size() +
2449 objectPath.size() +
2450 interfaceName.size() +
2451 strlen(name));
2452 uri += "/bus/system/";
2453 uri += processName;
2454 uri += objectPath;
2455 uri += "/";
2456 uri += interfaceName;
2457 uri += "/";
2458 uri += name;
2459 methodsArray.push_back({{"name", name},
2460 {"uri", std::move(uri)},
2461 {"args", argsArray}});
Ed Tanous7c091622019-05-23 11:42:36 -07002462 }
2463 methods = methods->NextSiblingElement("method");
2464 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002465 tinyxml2::XMLElement* signals =
Ed Tanous7c091622019-05-23 11:42:36 -07002466 interface->FirstChildElement("signal");
2467 while (signals != nullptr)
2468 {
2469 nlohmann::json argsArray = nlohmann::json::array();
2470
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002471 tinyxml2::XMLElement* arg =
Ed Tanous7c091622019-05-23 11:42:36 -07002472 signals->FirstChildElement("arg");
2473 while (arg != nullptr)
2474 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002475 const char* name = arg->Attribute("name");
2476 const char* type = arg->Attribute("type");
Ed Tanous7c091622019-05-23 11:42:36 -07002477 if (name != nullptr && type != nullptr)
2478 {
2479 argsArray.push_back({
2480 {"name", name},
2481 {"type", type},
2482 });
2483 }
2484 arg = arg->NextSiblingElement("arg");
2485 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002486 const char* name = signals->Attribute("name");
Ed Tanous7c091622019-05-23 11:42:36 -07002487 if (name != nullptr)
2488 {
2489 signalsArray.push_back(
2490 {{"name", name}, {"args", argsArray}});
2491 }
2492
2493 signals = signals->NextSiblingElement("signal");
2494 }
2495
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002496 tinyxml2::XMLElement* property =
Ed Tanous7c091622019-05-23 11:42:36 -07002497 interface->FirstChildElement("property");
2498 while (property != nullptr)
2499 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002500 const char* name = property->Attribute("name");
2501 const char* type = property->Attribute("type");
Ed Tanous7c091622019-05-23 11:42:36 -07002502 if (type != nullptr && name != nullptr)
2503 {
2504 sdbusplus::message::message m =
2505 crow::connections::systemBus
2506 ->new_method_call(processName.c_str(),
2507 objectPath.c_str(),
2508 "org.freedesktop."
2509 "DBus."
2510 "Properties",
2511 "Get");
2512 m.append(interfaceName, name);
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002513 nlohmann::json& propertyItem =
Ed Tanous7c091622019-05-23 11:42:36 -07002514 propertiesObj[name];
2515 crow::connections::systemBus->async_send(
2516 m, [&propertyItem, asyncResp](
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002517 boost::system::error_code& e,
2518 sdbusplus::message::message& msg) {
Ed Tanous271584a2019-07-09 16:24:22 -07002519 if (e)
Ed Tanous7c091622019-05-23 11:42:36 -07002520 {
2521 return;
2522 }
2523
Ed Tanous271584a2019-07-09 16:24:22 -07002524 convertDBusToJSON("v", msg,
2525 propertyItem);
Ed Tanous7c091622019-05-23 11:42:36 -07002526 });
2527 }
2528 property = property->NextSiblingElement("property");
2529 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002530 },
2531 processName, objectPath,
2532 "org.freedesktop.DBus.Introspectable", "Introspect");
2533 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002534 else
2535 {
Ed Tanousb41187f2019-10-24 16:30:02 -07002536 if (req.method() != boost::beast::http::verb::post)
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002537 {
2538 res.result(boost::beast::http::status::not_found);
2539 res.end();
2540 return;
2541 }
2542
2543 nlohmann::json requestDbusData =
2544 nlohmann::json::parse(req.body, nullptr, false);
2545
2546 if (requestDbusData.is_discarded())
2547 {
2548 res.result(boost::beast::http::status::bad_request);
2549 res.end();
2550 return;
2551 }
2552 if (!requestDbusData.is_array())
2553 {
2554 res.result(boost::beast::http::status::bad_request);
2555 res.end();
2556 return;
2557 }
2558 auto transaction = std::make_shared<InProgressActionData>(res);
2559
2560 transaction->path = objectPath;
2561 transaction->methodName = methodName;
2562 transaction->arguments = std::move(requestDbusData);
2563
2564 findActionOnInterface(transaction, processName);
2565 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002566 });
2567}
2568} // namespace openbmc_mapper
2569} // namespace crow