blob: 6bb09d0011929e662368a2ca11bb86de990ca2ed [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 Tanousc94ad492019-10-10 15:39:33 -070016#include <app.h>
Ed Tanous911ac312017-08-15 09:37:42 -070017#include <tinyxml2.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -070018
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 Tanous911ac312017-08-15 09:37:42 -070029
Ed Tanous1abe55e2018-09-05 08:30:59 -070030namespace crow
31{
32namespace openbmc_mapper
33{
Ed Tanousba9f9a62017-10-11 16:40:35 -070034
Matt Spinler3ae4ba72018-12-05 14:01:22 -060035using GetSubTreeType = std::vector<
36 std::pair<std::string,
37 std::vector<std::pair<std::string, std::vector<std::string>>>>>;
38
Ed Tanous23a21a12020-07-25 04:45:05 +000039const constexpr char* notFoundMsg = "404 Not Found";
40const constexpr char* badReqMsg = "400 Bad Request";
41const constexpr char* methodNotAllowedMsg = "405 Method Not Allowed";
42const constexpr char* forbiddenMsg = "403 Forbidden";
43const constexpr char* methodFailedMsg = "500 Method Call Failed";
44const constexpr char* methodOutputFailedMsg = "500 Method Output Error";
45const constexpr char* notFoundDesc =
Matt Spinler2ae60092018-12-06 10:35:36 -060046 "org.freedesktop.DBus.Error.FileNotFound: path or object not found";
Ed Tanous23a21a12020-07-25 04:45:05 +000047const constexpr char* propNotFoundDesc =
48 "The specified property cannot be found";
49const constexpr char* noJsonDesc = "No JSON object could be decoded";
50const constexpr char* methodNotFoundDesc =
51 "The specified method cannot be found";
52const constexpr char* methodNotAllowedDesc = "Method not allowed";
53const constexpr char* forbiddenPropDesc =
54 "The specified property cannot be created";
55const constexpr char* forbiddenResDesc =
56 "The specified resource cannot be created";
Matt Spinler2ae60092018-12-06 10:35:36 -060057
Ed Tanous23a21a12020-07-25 04:45:05 +000058inline void setErrorResponse(crow::Response& res,
59 boost::beast::http::status result,
60 const std::string& desc,
61 const std::string_view msg)
Matt Spinler2ae60092018-12-06 10:35:36 -060062{
63 res.result(result);
64 res.jsonValue = {{"data", {{"description", desc}}},
65 {"message", msg},
66 {"status", "error"}};
67}
68
Ed Tanous23a21a12020-07-25 04:45:05 +000069inline void introspectObjects(const std::string& processName,
70 const std::string& objectPath,
71 std::shared_ptr<bmcweb::AsyncResp> transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -070072{
Ed Tanouse3cb5a32018-08-08 14:16:49 -070073 if (transaction->res.jsonValue.is_null())
74 {
75 transaction->res.jsonValue = {{"status", "ok"},
76 {"bus_name", processName},
77 {"objects", nlohmann::json::array()}};
78 }
79
Ed Tanous1abe55e2018-09-05 08:30:59 -070080 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -070081 [transaction, processName{std::string(processName)},
82 objectPath{std::string(objectPath)}](
83 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -050084 const std::string& introspect_xml) {
Ed Tanous1abe55e2018-09-05 08:30:59 -070085 if (ec)
86 {
87 BMCWEB_LOG_ERROR
88 << "Introspect call failed with error: " << ec.message()
89 << " on process: " << processName << " path: " << objectPath
90 << "\n";
Ed Tanouse3cb5a32018-08-08 14:16:49 -070091 return;
92 }
93 transaction->res.jsonValue["objects"].push_back(
94 {{"path", objectPath}});
95
96 tinyxml2::XMLDocument doc;
97
98 doc.Parse(introspect_xml.c_str());
Gunnar Mills1214b7e2020-06-04 10:11:30 -050099 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700100 if (pRoot == nullptr)
101 {
102 BMCWEB_LOG_ERROR << "XML document failed to parse "
103 << processName << " " << objectPath << "\n";
Ed Tanous911ac312017-08-15 09:37:42 -0700104 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700105 else
106 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500107 tinyxml2::XMLElement* node = pRoot->FirstChildElement("node");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700108 while (node != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700109 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500110 const char* childPath = node->Attribute("name");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700111 if (childPath != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700112 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700113 std::string newpath;
114 if (objectPath != "/")
115 {
116 newpath += objectPath;
117 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700118 newpath += std::string("/") + childPath;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700119 // introspect the subobjects as well
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700120 introspectObjects(processName, newpath, transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700121 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700122
123 node = node->NextSiblingElement("node");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700124 }
125 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700126 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700127 processName, objectPath, "org.freedesktop.DBus.Introspectable",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700128 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -0700129}
Ed Tanous64530012018-02-06 17:08:16 -0800130
Ed Tanous23a21a12020-07-25 04:45:05 +0000131inline void getPropertiesForEnumerate(
132 const std::string& objectPath, const std::string& service,
133 const std::string& interface, std::shared_ptr<bmcweb::AsyncResp> asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600134{
135 BMCWEB_LOG_DEBUG << "getPropertiesForEnumerate " << objectPath << " "
136 << service << " " << interface;
137
138 crow::connections::systemBus->async_method_call(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500139 [asyncResp, objectPath, service, interface](
140 const boost::system::error_code ec,
141 const std::vector<std::pair<
142 std::string, dbus::utility::DbusVariantType>>& propertiesList) {
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600143 if (ec)
144 {
145 BMCWEB_LOG_ERROR << "GetAll on path " << objectPath << " iface "
146 << interface << " service " << service
147 << " failed with code " << ec;
148 return;
149 }
150
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500151 nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
152 nlohmann::json& objectJson = dataJson[objectPath];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600153 if (objectJson.is_null())
154 {
155 objectJson = nlohmann::json::object();
156 }
157
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500158 for (const auto& [name, value] : propertiesList)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600159 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500160 nlohmann::json& propertyJson = objectJson[name];
161 std::visit([&propertyJson](auto&& val) { propertyJson = val; },
Ed Tanousabf2add2019-01-22 16:40:12 -0800162 value);
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600163 }
164 },
165 service, objectPath, "org.freedesktop.DBus.Properties", "GetAll",
166 interface);
167}
168
169// Find any results that weren't picked up by ObjectManagers, to be
170// called after all ObjectManagers are searched for and called.
Ed Tanous23a21a12020-07-25 04:45:05 +0000171inline void findRemainingObjectsForEnumerate(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500172 const std::string& objectPath, std::shared_ptr<GetSubTreeType> subtree,
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600173 std::shared_ptr<bmcweb::AsyncResp> asyncResp)
174{
175 BMCWEB_LOG_DEBUG << "findRemainingObjectsForEnumerate";
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500176 const nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600177
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500178 for (const auto& [path, interface_map] : *subtree)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600179 {
180 if (path == objectPath)
181 {
182 // An enumerate does not return the target path's properties
183 continue;
184 }
185 if (dataJson.find(path) == dataJson.end())
186 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500187 for (const auto& [service, interfaces] : interface_map)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600188 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500189 for (const auto& interface : interfaces)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600190 {
191 if (!boost::starts_with(interface, "org.freedesktop.DBus"))
192 {
193 getPropertiesForEnumerate(path, service, interface,
194 asyncResp);
195 }
196 }
197 }
198 }
199 }
200}
201
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600202struct InProgressEnumerateData
203{
Ed Tanous23a21a12020-07-25 04:45:05 +0000204 InProgressEnumerateData(const std::string& objectPathIn,
205 std::shared_ptr<bmcweb::AsyncResp> asyncRespIn) :
206 objectPath(objectPathIn),
207 asyncResp(asyncRespIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500208 {}
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600209
210 ~InProgressEnumerateData()
211 {
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600212 findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600213 }
214
215 const std::string objectPath;
216 std::shared_ptr<GetSubTreeType> subtree;
217 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
218};
219
Ed Tanous23a21a12020-07-25 04:45:05 +0000220inline void getManagedObjectsForEnumerate(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500221 const std::string& object_name, const std::string& object_manager_path,
222 const std::string& connection_name,
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600223 std::shared_ptr<InProgressEnumerateData> transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700224{
Ed Tanous049a0512018-11-01 13:58:42 -0700225 BMCWEB_LOG_DEBUG << "getManagedObjectsForEnumerate " << object_name
226 << " object_manager_path " << object_manager_path
227 << " connection_name " << connection_name;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700228 crow::connections::systemBus->async_method_call(
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600229 [transaction, object_name,
Ed Tanous049a0512018-11-01 13:58:42 -0700230 connection_name](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500231 const dbus::utility::ManagedObjectType& objects) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700232 if (ec)
233 {
Ed Tanous049a0512018-11-01 13:58:42 -0700234 BMCWEB_LOG_ERROR << "GetManagedObjects on path " << object_name
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600235 << " on connection " << connection_name
Ed Tanous049a0512018-11-01 13:58:42 -0700236 << " failed with code " << ec;
237 return;
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700238 }
Ed Tanous64530012018-02-06 17:08:16 -0800239
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500240 nlohmann::json& dataJson =
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600241 transaction->asyncResp->res.jsonValue["data"];
Ed Tanous049a0512018-11-01 13:58:42 -0700242
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500243 for (const auto& objectPath : objects)
Ed Tanous049a0512018-11-01 13:58:42 -0700244 {
245 if (boost::starts_with(objectPath.first.str, object_name))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700246 {
Ed Tanous049a0512018-11-01 13:58:42 -0700247 BMCWEB_LOG_DEBUG << "Reading object "
248 << objectPath.first.str;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500249 nlohmann::json& objectJson = dataJson[objectPath.first.str];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700250 if (objectJson.is_null())
251 {
252 objectJson = nlohmann::json::object();
253 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500254 for (const auto& interface : objectPath.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700255 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500256 for (const auto& property : interface.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700257 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500258 nlohmann::json& propertyJson =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700259 objectJson[property.first];
Ed Tanousabf2add2019-01-22 16:40:12 -0800260 std::visit([&propertyJson](
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500261 auto&& val) { propertyJson = val; },
Ed Tanousabf2add2019-01-22 16:40:12 -0800262 property.second);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700263 }
264 }
265 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500266 for (const auto& interface : objectPath.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700267 {
268 if (interface.first == "org.freedesktop.DBus.ObjectManager")
269 {
270 getManagedObjectsForEnumerate(
271 objectPath.first.str, objectPath.first.str,
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600272 connection_name, transaction);
Ed Tanous049a0512018-11-01 13:58:42 -0700273 }
274 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700275 }
276 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700277 connection_name, object_manager_path,
278 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
279}
280
Ed Tanous23a21a12020-07-25 04:45:05 +0000281inline void findObjectManagerPathForEnumerate(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500282 const std::string& object_name, const std::string& connection_name,
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600283 std::shared_ptr<InProgressEnumerateData> transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700284{
Ed Tanous049a0512018-11-01 13:58:42 -0700285 BMCWEB_LOG_DEBUG << "Finding objectmanager for path " << object_name
286 << " on connection:" << connection_name;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700287 crow::connections::systemBus->async_method_call(
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600288 [transaction, object_name, connection_name](
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700289 const boost::system::error_code ec,
290 const boost::container::flat_map<
291 std::string, boost::container::flat_map<
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500292 std::string, std::vector<std::string>>>&
293 objects) {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700294 if (ec)
295 {
Ed Tanous049a0512018-11-01 13:58:42 -0700296 BMCWEB_LOG_ERROR << "GetAncestors on path " << object_name
297 << " failed with code " << ec;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700298 return;
299 }
300
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500301 for (const auto& pathGroup : objects)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700302 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500303 for (const auto& connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700304 {
305 if (connectionGroup.first == connection_name)
306 {
307 // Found the object manager path for this resource.
308 getManagedObjectsForEnumerate(
Ed Tanous049a0512018-11-01 13:58:42 -0700309 object_name, pathGroup.first, connection_name,
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600310 transaction);
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700311 return;
312 }
313 }
314 }
315 },
316 "xyz.openbmc_project.ObjectMapper",
317 "/xyz/openbmc_project/object_mapper",
318 "xyz.openbmc_project.ObjectMapper", "GetAncestors", object_name,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500319 std::array<const char*, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700320}
Ed Tanous64530012018-02-06 17:08:16 -0800321
Ed Tanous7c091622019-05-23 11:42:36 -0700322// Uses GetObject to add the object info about the target /enumerate path to
323// the results of GetSubTree, as GetSubTree will not return info for the
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600324// target path, and then continues on enumerating the rest of the tree.
Ed Tanous23a21a12020-07-25 04:45:05 +0000325inline void
326 getObjectAndEnumerate(std::shared_ptr<InProgressEnumerateData> transaction)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600327{
328 using GetObjectType =
329 std::vector<std::pair<std::string, std::vector<std::string>>>;
330
331 crow::connections::systemBus->async_method_call(
332 [transaction](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500333 const GetObjectType& objects) {
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600334 if (ec)
335 {
336 BMCWEB_LOG_ERROR << "GetObject for path "
337 << transaction->objectPath
338 << " failed with code " << ec;
339 return;
340 }
341
342 BMCWEB_LOG_DEBUG << "GetObject for " << transaction->objectPath
343 << " has " << objects.size() << " entries";
344 if (!objects.empty())
345 {
346 transaction->subtree->emplace_back(transaction->objectPath,
347 objects);
348 }
349
350 // Map indicating connection name, and the path where the object
351 // manager exists
352 boost::container::flat_map<std::string, std::string> connections;
353
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500354 for (const auto& object : *(transaction->subtree))
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600355 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500356 for (const auto& connection : object.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600357 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500358 std::string& objectManagerPath =
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600359 connections[connection.first];
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500360 for (const auto& interface : connection.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600361 {
362 BMCWEB_LOG_DEBUG << connection.first
363 << " has interface " << interface;
364 if (interface == "org.freedesktop.DBus.ObjectManager")
365 {
366 BMCWEB_LOG_DEBUG << "found object manager path "
367 << object.first;
368 objectManagerPath = object.first;
369 }
370 }
371 }
372 }
373 BMCWEB_LOG_DEBUG << "Got " << connections.size() << " connections";
374
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500375 for (const auto& connection : connections)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600376 {
Ed Tanous7c091622019-05-23 11:42:36 -0700377 // If we already know where the object manager is, we don't
378 // need to search for it, we can call directly in to
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600379 // getManagedObjects
380 if (!connection.second.empty())
381 {
382 getManagedObjectsForEnumerate(
383 transaction->objectPath, connection.second,
384 connection.first, transaction);
385 }
386 else
387 {
Ed Tanous7c091622019-05-23 11:42:36 -0700388 // otherwise we need to find the object manager path
389 // before we can continue
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600390 findObjectManagerPathForEnumerate(
391 transaction->objectPath, connection.first, transaction);
392 }
393 }
394 },
395 "xyz.openbmc_project.ObjectMapper",
396 "/xyz/openbmc_project/object_mapper",
397 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500398 transaction->objectPath, std::array<const char*, 0>());
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600399}
Ed Tanous64530012018-02-06 17:08:16 -0800400
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700401// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700402struct InProgressActionData
403{
Ed Tanous23a21a12020-07-25 04:45:05 +0000404 InProgressActionData(crow::Response& resIn) : res(resIn)
405 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700406 ~InProgressActionData()
407 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600408 // Methods could have been called across different owners
409 // and interfaces, where some calls failed and some passed.
410 //
411 // The rules for this are:
412 // * if no method was called - error
413 // * if a method failed and none passed - error
414 // (converse: if at least one method passed - OK)
415 // * for the method output:
416 // * if output processing didn't fail, return the data
417
418 // Only deal with method returns if nothing failed earlier
419 if (res.result() == boost::beast::http::status::ok)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700420 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600421 if (!methodPassed)
422 {
Matt Spinler06b1b632019-06-18 16:09:25 -0500423 if (!methodFailed)
Matt Spinler16caaee2019-01-15 11:40:34 -0600424 {
425 setErrorResponse(res, boost::beast::http::status::not_found,
426 methodNotFoundDesc, notFoundMsg);
427 }
428 }
429 else
430 {
431 if (outputFailed)
432 {
433 setErrorResponse(
434 res, boost::beast::http::status::internal_server_error,
435 "Method output failure", methodOutputFailedMsg);
436 }
437 else
438 {
439 res.jsonValue = {{"status", "ok"},
440 {"message", "200 OK"},
441 {"data", methodResponse}};
442 }
443 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700444 }
Matt Spinler16caaee2019-01-15 11:40:34 -0600445
Ed Tanous1abe55e2018-09-05 08:30:59 -0700446 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700447 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700448
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500449 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700450 {
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600451 setErrorResponse(res, boost::beast::http::status::bad_request, desc,
452 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700453 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500454 crow::Response& res;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700455 std::string path;
456 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600457 std::string interfaceName;
Matt Spinler16caaee2019-01-15 11:40:34 -0600458 bool methodPassed = false;
459 bool methodFailed = false;
460 bool outputFailed = false;
Matt Spinler39a4e392019-01-15 11:53:13 -0600461 bool convertedToArray = false;
Matt Spinler16caaee2019-01-15 11:40:34 -0600462 nlohmann::json methodResponse;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700463 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700464};
465
Ed Tanous23a21a12020-07-25 04:45:05 +0000466inline std::vector<std::string> dbusArgSplit(const std::string& string)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700467{
468 std::vector<std::string> ret;
469 if (string.empty())
470 {
471 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700472 }
Ed Tanous0f0353b2019-10-24 11:37:51 -0700473 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700474 int containerDepth = 0;
475
476 for (std::string::const_iterator character = string.begin();
477 character != string.end(); character++)
478 {
479 ret.back() += *character;
480 switch (*character)
481 {
482 case ('a'):
483 break;
484 case ('('):
485 case ('{'):
486 containerDepth++;
487 break;
488 case ('}'):
489 case (')'):
490 containerDepth--;
491 if (containerDepth == 0)
492 {
493 if (character + 1 != string.end())
494 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700495 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700496 }
497 }
498 break;
499 default:
500 if (containerDepth == 0)
501 {
502 if (character + 1 != string.end())
503 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700504 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700505 }
506 }
507 break;
508 }
509 }
Matt Spinler4ae611d2019-01-11 15:37:06 -0600510
511 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700512}
513
Ed Tanous23a21a12020-07-25 04:45:05 +0000514inline int convertJsonToDbus(sd_bus_message* m, const std::string& arg_type,
515 const nlohmann::json& input_json)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700516{
517 int r = 0;
518 BMCWEB_LOG_DEBUG << "Converting " << input_json.dump()
519 << " to type: " << arg_type;
520 const std::vector<std::string> argTypes = dbusArgSplit(arg_type);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700521
Ed Tanous1abe55e2018-09-05 08:30:59 -0700522 // Assume a single object for now.
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500523 const nlohmann::json* j = &input_json;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700524 nlohmann::json::const_iterator jIt = input_json.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700525
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500526 for (const std::string& argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700527 {
528 // If we are decoding multiple objects, grab the pointer to the
529 // iterator, and increment it for the next loop
530 if (argTypes.size() > 1)
531 {
532 if (jIt == input_json.end())
533 {
534 return -2;
535 }
536 j = &*jIt;
537 jIt++;
538 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500539 const int64_t* intValue = j->get_ptr<const int64_t*>();
540 const std::string* stringValue = j->get_ptr<const std::string*>();
541 const double* doubleValue = j->get_ptr<const double*>();
542 const bool* b = j->get_ptr<const bool*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700543 int64_t v = 0;
544 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700545
Ed Tanous1abe55e2018-09-05 08:30:59 -0700546 // Do some basic type conversions that make sense. uint can be
547 // converted to int. int and uint can be converted to double
Ed Tanous66664f22019-10-11 13:05:49 -0700548 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700549 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500550 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700551 if (uintValue != nullptr)
552 {
553 v = static_cast<int64_t>(*uintValue);
554 intValue = &v;
555 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700556 }
Ed Tanous66664f22019-10-11 13:05:49 -0700557 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700558 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500559 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700560 if (uintValue != nullptr)
561 {
562 d = static_cast<double>(*uintValue);
563 doubleValue = &d;
564 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700565 }
Ed Tanous66664f22019-10-11 13:05:49 -0700566 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700567 {
Ed Tanous66664f22019-10-11 13:05:49 -0700568 if (intValue != nullptr)
569 {
570 d = static_cast<double>(*intValue);
571 doubleValue = &d;
572 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700573 }
574
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700575 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700576 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700577 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700578 {
579 return -1;
580 }
Ed Tanous271584a2019-07-09 16:24:22 -0700581 r = sd_bus_message_append_basic(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500582 m, argCode[0], static_cast<const void*>(stringValue->data()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700583 if (r < 0)
584 {
585 return r;
586 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700587 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700588 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700589 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700590 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700591 {
592 return -1;
593 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500594 if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
595 (*intValue > std::numeric_limits<int32_t>::max()))
596 {
597 return -ERANGE;
598 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700599 int32_t i = static_cast<int32_t>(*intValue);
600 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700601 if (r < 0)
602 {
603 return r;
604 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700605 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700606 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700607 {
608 // lots of ways bool could be represented here. Try them all
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700609 int boolInt = false;
610 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700611 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500612 if (*intValue == 1)
613 {
614 boolInt = true;
615 }
616 else if (*intValue == 0)
617 {
618 boolInt = false;
619 }
620 else
621 {
622 return -ERANGE;
623 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700624 }
625 else if (b != nullptr)
626 {
Matt Spinlera2f02632019-01-18 10:15:35 -0600627 boolInt = *b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700628 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700629 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700630 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700631 boolInt = boost::istarts_with(*stringValue, "t") ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700632 }
633 else
634 {
635 return -1;
636 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700637 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700638 if (r < 0)
639 {
640 return r;
641 }
642 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700643 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700644 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700645 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700646 {
647 return -1;
648 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500649 if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
650 (*intValue > std::numeric_limits<int16_t>::max()))
651 {
652 return -ERANGE;
653 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700654 int16_t n = static_cast<int16_t>(*intValue);
655 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700656 if (r < 0)
657 {
658 return r;
659 }
660 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700661 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700662 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700663 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700664 {
665 return -1;
666 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700667 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700668 if (r < 0)
669 {
670 return r;
671 }
672 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700673 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700674 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500675 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700676 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700677 {
678 return -1;
679 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000680 if (*uintValue > std::numeric_limits<uint8_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500681 {
682 return -ERANGE;
683 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700684 uint8_t y = static_cast<uint8_t>(*uintValue);
685 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700686 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700687 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700688 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500689 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700690 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700691 {
692 return -1;
693 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000694 if (*uintValue > std::numeric_limits<uint16_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500695 {
696 return -ERANGE;
697 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700698 uint16_t q = static_cast<uint16_t>(*uintValue);
699 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700700 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700701 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700702 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500703 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700704 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700705 {
706 return -1;
707 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000708 if (*uintValue > std::numeric_limits<uint32_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500709 {
710 return -ERANGE;
711 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700712 uint32_t u = static_cast<uint32_t>(*uintValue);
713 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700714 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700715 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700716 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500717 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700718 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700719 {
720 return -1;
721 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700722 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700723 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700724 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700725 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500726 if (doubleValue == nullptr)
727 {
728 return -1;
729 }
730 if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
731 (*doubleValue > std::numeric_limits<double>::max()))
732 {
733 return -ERANGE;
734 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700735 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700736 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700737 else if (boost::starts_with(argCode, "a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700738 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700739 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700740 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700741 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700742 if (r < 0)
743 {
744 return r;
745 }
746
Ed Tanous0dfeda62019-10-24 11:21:38 -0700747 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700748 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700749 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700750 if (r < 0)
751 {
752 return r;
753 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700754 }
755 sd_bus_message_close_container(m);
756 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700757 else if (boost::starts_with(argCode, "v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700758 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700759 std::string containedType = argCode.substr(1);
760 BMCWEB_LOG_DEBUG << "variant type: " << argCode
761 << " appending variant of type: " << containedType;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700762 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700763 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700764 if (r < 0)
765 {
766 return r;
767 }
768
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700769 r = convertJsonToDbus(m, containedType, input_json);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700770 if (r < 0)
771 {
772 return r;
773 }
774
775 r = sd_bus_message_close_container(m);
776 if (r < 0)
777 {
778 return r;
779 }
780 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700781 else if (boost::starts_with(argCode, "(") &&
782 boost::ends_with(argCode, ")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700783 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700784 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700785 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700786 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800787 if (r < 0)
788 {
789 return r;
790 }
791
Ed Tanous1abe55e2018-09-05 08:30:59 -0700792 nlohmann::json::const_iterator it = j->begin();
Ed Tanouscb13a392020-07-25 19:02:03 +0000793 for (const std::string& argCode2 : dbusArgSplit(arg_type))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700794 {
795 if (it == j->end())
796 {
797 return -1;
798 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000799 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700800 if (r < 0)
801 {
802 return r;
803 }
804 it++;
805 }
806 r = sd_bus_message_close_container(m);
807 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700808 else if (boost::starts_with(argCode, "{") &&
809 boost::ends_with(argCode, "}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700810 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700811 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700812 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700813 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800814 if (r < 0)
815 {
816 return r;
817 }
818
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700819 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700820 if (codes.size() != 2)
821 {
822 return -1;
823 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700824 const std::string& keyType = codes[0];
825 const std::string& valueType = codes[1];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700826 for (auto it : j->items())
827 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700828 r = convertJsonToDbus(m, keyType, it.key());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700829 if (r < 0)
830 {
831 return r;
832 }
833
Ed Tanous2c70f802020-09-28 14:29:23 -0700834 r = convertJsonToDbus(m, valueType, it.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700835 if (r < 0)
836 {
837 return r;
838 }
839 }
840 r = sd_bus_message_close_container(m);
841 }
842 else
843 {
844 return -2;
845 }
846 if (r < 0)
847 {
848 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700849 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700850
Ed Tanous1abe55e2018-09-05 08:30:59 -0700851 if (argTypes.size() > 1)
852 {
853 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700854 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700855 }
Matt Spinler127ea542019-01-14 11:04:28 -0600856
857 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700858}
859
Matt Spinlerd22a7132019-01-14 12:14:30 -0600860template <typename T>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500861int readMessageItem(const std::string& typeCode, sdbusplus::message::message& m,
862 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600863{
864 T value;
865
866 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
867 if (r < 0)
868 {
869 BMCWEB_LOG_ERROR << "sd_bus_message_read_basic on type " << typeCode
870 << " failed!";
871 return r;
872 }
873
874 data = value;
875 return 0;
876}
877
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500878int convertDBusToJSON(const std::string& returnType,
879 sdbusplus::message::message& m, nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600880
Ed Tanous23a21a12020-07-25 04:45:05 +0000881inline int readDictEntryFromMessage(const std::string& typeCode,
882 sdbusplus::message::message& m,
883 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600884{
885 std::vector<std::string> types = dbusArgSplit(typeCode);
886 if (types.size() != 2)
887 {
888 BMCWEB_LOG_ERROR << "wrong number contained types in dictionary: "
889 << types.size();
890 return -1;
891 }
892
893 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
894 typeCode.c_str());
895 if (r < 0)
896 {
897 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container with rc " << r;
898 return r;
899 }
900
901 nlohmann::json key;
902 r = convertDBusToJSON(types[0], m, key);
903 if (r < 0)
904 {
905 return r;
906 }
907
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500908 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -0600909 if (keyPtr == nullptr)
910 {
911 // json doesn't support non-string keys. If we hit this condition,
912 // convert the result to a string so we can proceed
913 key = key.dump();
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500914 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -0700915 // in theory this can't fail now, but lets be paranoid about it
916 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -0600917 if (keyPtr == nullptr)
918 {
919 return -1;
920 }
921 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500922 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -0600923
924 r = convertDBusToJSON(types[1], m, value);
925 if (r < 0)
926 {
927 return r;
928 }
929
930 r = sd_bus_message_exit_container(m.get());
931 if (r < 0)
932 {
933 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
934 return r;
935 }
936
937 return 0;
938}
939
Ed Tanous23a21a12020-07-25 04:45:05 +0000940inline int readArrayFromMessage(const std::string& typeCode,
941 sdbusplus::message::message& m,
942 nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -0600943{
944 if (typeCode.size() < 2)
945 {
946 BMCWEB_LOG_ERROR << "Type code " << typeCode
947 << " too small for an array";
948 return -1;
949 }
950
951 std::string containedType = typeCode.substr(1);
952
953 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
954 containedType.c_str());
955 if (r < 0)
956 {
957 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
958 << r;
959 return r;
960 }
961
962 bool dict = boost::starts_with(containedType, "{") &&
963 boost::ends_with(containedType, "}");
964
965 if (dict)
966 {
967 // Remove the { }
968 containedType = containedType.substr(1, containedType.size() - 2);
969 data = nlohmann::json::object();
970 }
971 else
972 {
973 data = nlohmann::json::array();
974 }
975
976 while (true)
977 {
978 r = sd_bus_message_at_end(m.get(), false);
979 if (r < 0)
980 {
981 BMCWEB_LOG_ERROR << "sd_bus_message_at_end failed";
982 return r;
983 }
984
985 if (r > 0)
986 {
987 break;
988 }
989
990 // Dictionaries are only ever seen in an array
991 if (dict)
992 {
993 r = readDictEntryFromMessage(containedType, m, data);
994 if (r < 0)
995 {
996 return r;
997 }
998 }
999 else
1000 {
1001 data.push_back(nlohmann::json());
1002
1003 r = convertDBusToJSON(containedType, m, data.back());
1004 if (r < 0)
1005 {
1006 return r;
1007 }
1008 }
1009 }
1010
1011 r = sd_bus_message_exit_container(m.get());
1012 if (r < 0)
1013 {
1014 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1015 return r;
1016 }
1017
1018 return 0;
1019}
1020
Ed Tanous23a21a12020-07-25 04:45:05 +00001021inline int readStructFromMessage(const std::string& typeCode,
1022 sdbusplus::message::message& m,
1023 nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001024{
1025 if (typeCode.size() < 3)
1026 {
1027 BMCWEB_LOG_ERROR << "Type code " << typeCode
1028 << " too small for a struct";
1029 return -1;
1030 }
1031
1032 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1033 std::vector<std::string> types = dbusArgSplit(containedTypes);
1034
1035 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1036 containedTypes.c_str());
1037 if (r < 0)
1038 {
1039 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1040 << r;
1041 return r;
1042 }
1043
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001044 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001045 {
1046 data.push_back(nlohmann::json());
1047 r = convertDBusToJSON(type, m, data.back());
1048 if (r < 0)
1049 {
1050 return r;
1051 }
1052 }
1053
1054 r = sd_bus_message_exit_container(m.get());
1055 if (r < 0)
1056 {
1057 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1058 return r;
1059 }
1060 return 0;
1061}
1062
Ed Tanous23a21a12020-07-25 04:45:05 +00001063inline int readVariantFromMessage(sdbusplus::message::message& m,
1064 nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001065{
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001066 const char* containerType;
Ed Tanous99131cd2019-10-24 11:12:47 -07001067 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001068 if (r < 0)
1069 {
1070 BMCWEB_LOG_ERROR << "sd_bus_message_peek_type failed";
1071 return r;
1072 }
1073
1074 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1075 containerType);
1076 if (r < 0)
1077 {
1078 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1079 << r;
1080 return r;
1081 }
1082
1083 r = convertDBusToJSON(containerType, m, data);
1084 if (r < 0)
1085 {
1086 return r;
1087 }
1088
1089 r = sd_bus_message_exit_container(m.get());
1090 if (r < 0)
1091 {
1092 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed";
1093 return r;
1094 }
1095
1096 return 0;
1097}
1098
Ed Tanous23a21a12020-07-25 04:45:05 +00001099inline int convertDBusToJSON(const std::string& returnType,
1100 sdbusplus::message::message& m,
1101 nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001102{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001103 int r = 0;
1104 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1105
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001106 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001107 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001108 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001109 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001110 {
1111 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001112 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001113 }
1114
Ed Tanousd4d25792020-09-29 15:15:03 -07001115 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001116 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001117 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001118 if (r < 0)
1119 {
1120 return r;
1121 }
1122 }
1123 else if (typeCode == "b")
1124 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001125 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001126 if (r < 0)
1127 {
1128 return r;
1129 }
1130
Matt Spinlerf39420c2019-01-30 12:57:18 -06001131 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001132 }
1133 else if (typeCode == "u")
1134 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001135 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001136 if (r < 0)
1137 {
1138 return r;
1139 }
1140 }
1141 else if (typeCode == "i")
1142 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001143 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001144 if (r < 0)
1145 {
1146 return r;
1147 }
1148 }
1149 else if (typeCode == "x")
1150 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001151 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001152 if (r < 0)
1153 {
1154 return r;
1155 }
1156 }
1157 else if (typeCode == "t")
1158 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001159 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001160 if (r < 0)
1161 {
1162 return r;
1163 }
1164 }
1165 else if (typeCode == "n")
1166 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001167 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001168 if (r < 0)
1169 {
1170 return r;
1171 }
1172 }
1173 else if (typeCode == "q")
1174 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001175 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001176 if (r < 0)
1177 {
1178 return r;
1179 }
1180 }
1181 else if (typeCode == "y")
1182 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001183 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001184 if (r < 0)
1185 {
1186 return r;
1187 }
1188 }
1189 else if (typeCode == "d")
1190 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001191 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001192 if (r < 0)
1193 {
1194 return r;
1195 }
1196 }
1197 else if (typeCode == "h")
1198 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001199 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001200 if (r < 0)
1201 {
1202 return r;
1203 }
1204 }
Matt Spinler6df8f992019-01-14 12:47:47 -06001205 else if (boost::starts_with(typeCode, "a"))
1206 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001207 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001208 if (r < 0)
1209 {
1210 return r;
1211 }
1212 }
Matt Spinler75c6c672019-01-14 13:01:46 -06001213 else if (boost::starts_with(typeCode, "(") &&
1214 boost::ends_with(typeCode, ")"))
1215 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001216 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001217 if (r < 0)
1218 {
1219 return r;
1220 }
1221 }
Matt Spinler89c19702019-01-14 13:13:00 -06001222 else if (boost::starts_with(typeCode, "v"))
1223 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001224 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001225 if (r < 0)
1226 {
1227 return r;
1228 }
1229 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001230 else
1231 {
Matt Spinlerd22a7132019-01-14 12:14:30 -06001232 BMCWEB_LOG_ERROR << "Invalid D-Bus signature type " << typeCode;
1233 return -2;
1234 }
1235 }
1236
Matt Spinler16caaee2019-01-15 11:40:34 -06001237 return 0;
1238}
1239
Ed Tanous23a21a12020-07-25 04:45:05 +00001240inline void
1241 handleMethodResponse(std::shared_ptr<InProgressActionData> transaction,
1242 sdbusplus::message::message& m,
1243 const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001244{
Matt Spinler39a4e392019-01-15 11:53:13 -06001245 nlohmann::json data;
1246
1247 int r = convertDBusToJSON(returnType, m, data);
1248 if (r < 0)
1249 {
1250 transaction->outputFailed = true;
1251 return;
1252 }
1253
1254 if (data.is_null())
1255 {
1256 return;
1257 }
1258
1259 if (transaction->methodResponse.is_null())
1260 {
1261 transaction->methodResponse = std::move(data);
1262 return;
1263 }
1264
1265 // If they're both dictionaries or arrays, merge into one.
1266 // Otherwise, make the results an array with every result
1267 // an entry. Could also just fail in that case, but it
1268 // seems better to get the data back somehow.
1269
1270 if (transaction->methodResponse.is_object() && data.is_object())
1271 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001272 for (const auto& obj : data.items())
Matt Spinler39a4e392019-01-15 11:53:13 -06001273 {
1274 // Note: Will overwrite the data for a duplicate key
1275 transaction->methodResponse.emplace(obj.key(),
1276 std::move(obj.value()));
1277 }
1278 return;
1279 }
1280
1281 if (transaction->methodResponse.is_array() && data.is_array())
1282 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001283 for (auto& obj : data)
Matt Spinler39a4e392019-01-15 11:53:13 -06001284 {
1285 transaction->methodResponse.push_back(std::move(obj));
1286 }
1287 return;
1288 }
1289
1290 if (!transaction->convertedToArray)
1291 {
1292 // They are different types. May as well turn them into an array
1293 nlohmann::json j = std::move(transaction->methodResponse);
1294 transaction->methodResponse = nlohmann::json::array();
1295 transaction->methodResponse.push_back(std::move(j));
1296 transaction->methodResponse.push_back(std::move(data));
1297 transaction->convertedToArray = true;
1298 }
1299 else
1300 {
1301 transaction->methodResponse.push_back(std::move(data));
1302 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001303}
1304
Ed Tanous23a21a12020-07-25 04:45:05 +00001305inline void
1306 findActionOnInterface(std::shared_ptr<InProgressActionData> transaction,
1307 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001308{
1309 BMCWEB_LOG_DEBUG << "findActionOnInterface for connection "
1310 << connectionName;
1311 crow::connections::systemBus->async_method_call(
1312 [transaction, connectionName{std::string(connectionName)}](
1313 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001314 const std::string& introspect_xml) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001315 BMCWEB_LOG_DEBUG << "got xml:\n " << introspect_xml;
1316 if (ec)
1317 {
1318 BMCWEB_LOG_ERROR
1319 << "Introspect call failed with error: " << ec.message()
1320 << " on process: " << connectionName << "\n";
Matt Spinler318bd892019-01-15 09:59:20 -06001321 return;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001322 }
Matt Spinler318bd892019-01-15 09:59:20 -06001323 tinyxml2::XMLDocument doc;
1324
1325 doc.Parse(introspect_xml.data(), introspect_xml.size());
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001326 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
Matt Spinler318bd892019-01-15 09:59:20 -06001327 if (pRoot == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001328 {
Matt Spinler318bd892019-01-15 09:59:20 -06001329 BMCWEB_LOG_ERROR << "XML document failed to parse "
1330 << connectionName << "\n";
1331 return;
1332 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001333 tinyxml2::XMLElement* interfaceNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001334 pRoot->FirstChildElement("interface");
1335 while (interfaceNode != nullptr)
1336 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001337 const char* thisInterfaceName =
Matt Spinler318bd892019-01-15 09:59:20 -06001338 interfaceNode->Attribute("name");
1339 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001340 {
Matt Spinler318bd892019-01-15 09:59:20 -06001341 if (!transaction->interfaceName.empty() &&
1342 (transaction->interfaceName != thisInterfaceName))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001343 {
Matt Spinler318bd892019-01-15 09:59:20 -06001344 interfaceNode =
1345 interfaceNode->NextSiblingElement("interface");
1346 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001347 }
Matt Spinler318bd892019-01-15 09:59:20 -06001348
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001349 tinyxml2::XMLElement* methodNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001350 interfaceNode->FirstChildElement("method");
1351 while (methodNode != nullptr)
1352 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001353 const char* thisMethodName =
Matt Spinler318bd892019-01-15 09:59:20 -06001354 methodNode->Attribute("name");
1355 BMCWEB_LOG_DEBUG << "Found method: " << thisMethodName;
1356 if (thisMethodName != nullptr &&
1357 thisMethodName == transaction->methodName)
1358 {
1359 BMCWEB_LOG_DEBUG
1360 << "Found method named " << thisMethodName
1361 << " on interface " << thisInterfaceName;
1362 sdbusplus::message::message m =
1363 crow::connections::systemBus->new_method_call(
1364 connectionName.c_str(),
1365 transaction->path.c_str(),
1366 thisInterfaceName,
1367 transaction->methodName.c_str());
1368
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001369 tinyxml2::XMLElement* argumentNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001370 methodNode->FirstChildElement("arg");
1371
Matt Spinler16caaee2019-01-15 11:40:34 -06001372 std::string returnType;
1373
1374 // Find the output type
1375 while (argumentNode != nullptr)
1376 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001377 const char* argDirection =
Matt Spinler16caaee2019-01-15 11:40:34 -06001378 argumentNode->Attribute("direction");
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001379 const char* argType =
Matt Spinler16caaee2019-01-15 11:40:34 -06001380 argumentNode->Attribute("type");
1381 if (argDirection != nullptr &&
1382 argType != nullptr &&
1383 std::string(argDirection) == "out")
1384 {
1385 returnType = argType;
1386 break;
1387 }
1388 argumentNode =
1389 argumentNode->NextSiblingElement("arg");
1390 }
1391
Matt Spinler318bd892019-01-15 09:59:20 -06001392 nlohmann::json::const_iterator argIt =
1393 transaction->arguments.begin();
1394
Matt Spinler16caaee2019-01-15 11:40:34 -06001395 argumentNode = methodNode->FirstChildElement("arg");
1396
Matt Spinler318bd892019-01-15 09:59:20 -06001397 while (argumentNode != nullptr)
1398 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001399 const char* argDirection =
Matt Spinler318bd892019-01-15 09:59:20 -06001400 argumentNode->Attribute("direction");
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001401 const char* argType =
Matt Spinler318bd892019-01-15 09:59:20 -06001402 argumentNode->Attribute("type");
1403 if (argDirection != nullptr &&
1404 argType != nullptr &&
1405 std::string(argDirection) == "in")
1406 {
1407 if (argIt == transaction->arguments.end())
1408 {
1409 transaction->setErrorStatus(
1410 "Invalid method args");
1411 return;
1412 }
1413 if (convertJsonToDbus(m.get(),
1414 std::string(argType),
1415 *argIt) < 0)
1416 {
1417 transaction->setErrorStatus(
1418 "Invalid method arg type");
1419 return;
1420 }
1421
1422 argIt++;
1423 }
1424 argumentNode =
1425 argumentNode->NextSiblingElement("arg");
1426 }
1427
1428 crow::connections::systemBus->async_send(
Matt Spinler16caaee2019-01-15 11:40:34 -06001429 m, [transaction, returnType](
Ed Tanous23a21a12020-07-25 04:45:05 +00001430 boost::system::error_code ec2,
1431 sdbusplus::message::message& m2) {
1432 if (ec2)
Matt Spinler318bd892019-01-15 09:59:20 -06001433 {
Matt Spinler16caaee2019-01-15 11:40:34 -06001434 transaction->methodFailed = true;
Ed Tanous23a21a12020-07-25 04:45:05 +00001435 const sd_bus_error* e = m2.get_error();
Matt Spinler06b1b632019-06-18 16:09:25 -05001436
1437 if (e)
1438 {
1439 setErrorResponse(
1440 transaction->res,
1441 boost::beast::http::status::
1442 bad_request,
1443 e->name, e->message);
1444 }
1445 else
1446 {
1447 setErrorResponse(
1448 transaction->res,
1449 boost::beast::http::status::
1450 bad_request,
1451 "Method call failed",
1452 methodFailedMsg);
1453 }
Matt Spinler318bd892019-01-15 09:59:20 -06001454 return;
1455 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001456 else
1457 {
1458 transaction->methodPassed = true;
1459 }
1460
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 Tanousad18f072018-11-14 14:07:48 -08002149 std::regex validFilename("^[\\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 }
2253 else if (!it->empty())
2254 {
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 {
2447 methodsArray.push_back(
2448 {{"name", name},
2449 {"uri", "/bus/system/" + processName +
2450 objectPath + "/" +
2451 interfaceName + "/" + name},
2452 {"args", argsArray}});
2453 }
2454 methods = methods->NextSiblingElement("method");
2455 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002456 tinyxml2::XMLElement* signals =
Ed Tanous7c091622019-05-23 11:42:36 -07002457 interface->FirstChildElement("signal");
2458 while (signals != nullptr)
2459 {
2460 nlohmann::json argsArray = nlohmann::json::array();
2461
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002462 tinyxml2::XMLElement* arg =
Ed Tanous7c091622019-05-23 11:42:36 -07002463 signals->FirstChildElement("arg");
2464 while (arg != nullptr)
2465 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002466 const char* name = arg->Attribute("name");
2467 const char* type = arg->Attribute("type");
Ed Tanous7c091622019-05-23 11:42:36 -07002468 if (name != nullptr && type != nullptr)
2469 {
2470 argsArray.push_back({
2471 {"name", name},
2472 {"type", type},
2473 });
2474 }
2475 arg = arg->NextSiblingElement("arg");
2476 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002477 const char* name = signals->Attribute("name");
Ed Tanous7c091622019-05-23 11:42:36 -07002478 if (name != nullptr)
2479 {
2480 signalsArray.push_back(
2481 {{"name", name}, {"args", argsArray}});
2482 }
2483
2484 signals = signals->NextSiblingElement("signal");
2485 }
2486
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002487 tinyxml2::XMLElement* property =
Ed Tanous7c091622019-05-23 11:42:36 -07002488 interface->FirstChildElement("property");
2489 while (property != nullptr)
2490 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002491 const char* name = property->Attribute("name");
2492 const char* type = property->Attribute("type");
Ed Tanous7c091622019-05-23 11:42:36 -07002493 if (type != nullptr && name != nullptr)
2494 {
2495 sdbusplus::message::message m =
2496 crow::connections::systemBus
2497 ->new_method_call(processName.c_str(),
2498 objectPath.c_str(),
2499 "org.freedesktop."
2500 "DBus."
2501 "Properties",
2502 "Get");
2503 m.append(interfaceName, name);
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002504 nlohmann::json& propertyItem =
Ed Tanous7c091622019-05-23 11:42:36 -07002505 propertiesObj[name];
2506 crow::connections::systemBus->async_send(
2507 m, [&propertyItem, asyncResp](
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002508 boost::system::error_code& e,
2509 sdbusplus::message::message& msg) {
Ed Tanous271584a2019-07-09 16:24:22 -07002510 if (e)
Ed Tanous7c091622019-05-23 11:42:36 -07002511 {
2512 return;
2513 }
2514
Ed Tanous271584a2019-07-09 16:24:22 -07002515 convertDBusToJSON("v", msg,
2516 propertyItem);
Ed Tanous7c091622019-05-23 11:42:36 -07002517 });
2518 }
2519 property = property->NextSiblingElement("property");
2520 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002521 },
2522 processName, objectPath,
2523 "org.freedesktop.DBus.Introspectable", "Introspect");
2524 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002525 else
2526 {
Ed Tanousb41187f2019-10-24 16:30:02 -07002527 if (req.method() != boost::beast::http::verb::post)
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002528 {
2529 res.result(boost::beast::http::status::not_found);
2530 res.end();
2531 return;
2532 }
2533
2534 nlohmann::json requestDbusData =
2535 nlohmann::json::parse(req.body, nullptr, false);
2536
2537 if (requestDbusData.is_discarded())
2538 {
2539 res.result(boost::beast::http::status::bad_request);
2540 res.end();
2541 return;
2542 }
2543 if (!requestDbusData.is_array())
2544 {
2545 res.result(boost::beast::http::status::bad_request);
2546 res.end();
2547 return;
2548 }
2549 auto transaction = std::make_shared<InProgressActionData>(res);
2550
2551 transaction->path = objectPath;
2552 transaction->methodName = methodName;
2553 transaction->arguments = std::move(requestDbusData);
2554
2555 findActionOnInterface(transaction, processName);
2556 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002557 });
2558}
2559} // namespace openbmc_mapper
2560} // namespace crow