blob: f049c009154e9f8ef91ebeeef7e6a14aa204c796 [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
747 for (nlohmann::json::const_iterator it = j->begin(); it != j->end();
748 ++it)
749 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700750 r = convertJsonToDbus(m, containedType, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700751 if (r < 0)
752 {
753 return r;
754 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700755 }
756 sd_bus_message_close_container(m);
757 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700758 else if (boost::starts_with(argCode, "v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700759 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700760 std::string containedType = argCode.substr(1);
761 BMCWEB_LOG_DEBUG << "variant type: " << argCode
762 << " appending variant of type: " << containedType;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700763 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700764 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700765 if (r < 0)
766 {
767 return r;
768 }
769
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700770 r = convertJsonToDbus(m, containedType, input_json);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700771 if (r < 0)
772 {
773 return r;
774 }
775
776 r = sd_bus_message_close_container(m);
777 if (r < 0)
778 {
779 return r;
780 }
781 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700782 else if (boost::starts_with(argCode, "(") &&
783 boost::ends_with(argCode, ")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700784 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700785 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700786 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700787 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800788 if (r < 0)
789 {
790 return r;
791 }
792
Ed Tanous1abe55e2018-09-05 08:30:59 -0700793 nlohmann::json::const_iterator it = j->begin();
Ed Tanouscb13a392020-07-25 19:02:03 +0000794 for (const std::string& argCode2 : dbusArgSplit(arg_type))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700795 {
796 if (it == j->end())
797 {
798 return -1;
799 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000800 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700801 if (r < 0)
802 {
803 return r;
804 }
805 it++;
806 }
807 r = sd_bus_message_close_container(m);
808 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700809 else if (boost::starts_with(argCode, "{") &&
810 boost::ends_with(argCode, "}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700811 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700812 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700813 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700814 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800815 if (r < 0)
816 {
817 return r;
818 }
819
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700820 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700821 if (codes.size() != 2)
822 {
823 return -1;
824 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500825 const std::string& key_type = codes[0];
826 const std::string& value_type = codes[1];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700827 for (auto it : j->items())
828 {
829 r = convertJsonToDbus(m, key_type, it.key());
830 if (r < 0)
831 {
832 return r;
833 }
834
835 r = convertJsonToDbus(m, value_type, it.value());
836 if (r < 0)
837 {
838 return r;
839 }
840 }
841 r = sd_bus_message_close_container(m);
842 }
843 else
844 {
845 return -2;
846 }
847 if (r < 0)
848 {
849 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700850 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700851
Ed Tanous1abe55e2018-09-05 08:30:59 -0700852 if (argTypes.size() > 1)
853 {
854 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700855 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700856 }
Matt Spinler127ea542019-01-14 11:04:28 -0600857
858 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700859}
860
Matt Spinlerd22a7132019-01-14 12:14:30 -0600861template <typename T>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500862int readMessageItem(const std::string& typeCode, sdbusplus::message::message& m,
863 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600864{
865 T value;
866
867 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
868 if (r < 0)
869 {
870 BMCWEB_LOG_ERROR << "sd_bus_message_read_basic on type " << typeCode
871 << " failed!";
872 return r;
873 }
874
875 data = value;
876 return 0;
877}
878
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500879int convertDBusToJSON(const std::string& returnType,
880 sdbusplus::message::message& m, nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600881
Ed Tanous23a21a12020-07-25 04:45:05 +0000882inline int readDictEntryFromMessage(const std::string& typeCode,
883 sdbusplus::message::message& m,
884 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600885{
886 std::vector<std::string> types = dbusArgSplit(typeCode);
887 if (types.size() != 2)
888 {
889 BMCWEB_LOG_ERROR << "wrong number contained types in dictionary: "
890 << types.size();
891 return -1;
892 }
893
894 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
895 typeCode.c_str());
896 if (r < 0)
897 {
898 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container with rc " << r;
899 return r;
900 }
901
902 nlohmann::json key;
903 r = convertDBusToJSON(types[0], m, key);
904 if (r < 0)
905 {
906 return r;
907 }
908
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500909 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -0600910 if (keyPtr == nullptr)
911 {
912 // json doesn't support non-string keys. If we hit this condition,
913 // convert the result to a string so we can proceed
914 key = key.dump();
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500915 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -0700916 // in theory this can't fail now, but lets be paranoid about it
917 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -0600918 if (keyPtr == nullptr)
919 {
920 return -1;
921 }
922 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500923 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -0600924
925 r = convertDBusToJSON(types[1], m, value);
926 if (r < 0)
927 {
928 return r;
929 }
930
931 r = sd_bus_message_exit_container(m.get());
932 if (r < 0)
933 {
934 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
935 return r;
936 }
937
938 return 0;
939}
940
Ed Tanous23a21a12020-07-25 04:45:05 +0000941inline int readArrayFromMessage(const std::string& typeCode,
942 sdbusplus::message::message& m,
943 nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -0600944{
945 if (typeCode.size() < 2)
946 {
947 BMCWEB_LOG_ERROR << "Type code " << typeCode
948 << " too small for an array";
949 return -1;
950 }
951
952 std::string containedType = typeCode.substr(1);
953
954 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
955 containedType.c_str());
956 if (r < 0)
957 {
958 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
959 << r;
960 return r;
961 }
962
963 bool dict = boost::starts_with(containedType, "{") &&
964 boost::ends_with(containedType, "}");
965
966 if (dict)
967 {
968 // Remove the { }
969 containedType = containedType.substr(1, containedType.size() - 2);
970 data = nlohmann::json::object();
971 }
972 else
973 {
974 data = nlohmann::json::array();
975 }
976
977 while (true)
978 {
979 r = sd_bus_message_at_end(m.get(), false);
980 if (r < 0)
981 {
982 BMCWEB_LOG_ERROR << "sd_bus_message_at_end failed";
983 return r;
984 }
985
986 if (r > 0)
987 {
988 break;
989 }
990
991 // Dictionaries are only ever seen in an array
992 if (dict)
993 {
994 r = readDictEntryFromMessage(containedType, m, data);
995 if (r < 0)
996 {
997 return r;
998 }
999 }
1000 else
1001 {
1002 data.push_back(nlohmann::json());
1003
1004 r = convertDBusToJSON(containedType, m, data.back());
1005 if (r < 0)
1006 {
1007 return r;
1008 }
1009 }
1010 }
1011
1012 r = sd_bus_message_exit_container(m.get());
1013 if (r < 0)
1014 {
1015 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1016 return r;
1017 }
1018
1019 return 0;
1020}
1021
Ed Tanous23a21a12020-07-25 04:45:05 +00001022inline int readStructFromMessage(const std::string& typeCode,
1023 sdbusplus::message::message& m,
1024 nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001025{
1026 if (typeCode.size() < 3)
1027 {
1028 BMCWEB_LOG_ERROR << "Type code " << typeCode
1029 << " too small for a struct";
1030 return -1;
1031 }
1032
1033 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1034 std::vector<std::string> types = dbusArgSplit(containedTypes);
1035
1036 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1037 containedTypes.c_str());
1038 if (r < 0)
1039 {
1040 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1041 << r;
1042 return r;
1043 }
1044
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001045 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001046 {
1047 data.push_back(nlohmann::json());
1048 r = convertDBusToJSON(type, m, data.back());
1049 if (r < 0)
1050 {
1051 return r;
1052 }
1053 }
1054
1055 r = sd_bus_message_exit_container(m.get());
1056 if (r < 0)
1057 {
1058 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1059 return r;
1060 }
1061 return 0;
1062}
1063
Ed Tanous23a21a12020-07-25 04:45:05 +00001064inline int readVariantFromMessage(sdbusplus::message::message& m,
1065 nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001066{
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001067 const char* containerType;
Ed Tanous99131cd2019-10-24 11:12:47 -07001068 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001069 if (r < 0)
1070 {
1071 BMCWEB_LOG_ERROR << "sd_bus_message_peek_type failed";
1072 return r;
1073 }
1074
1075 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1076 containerType);
1077 if (r < 0)
1078 {
1079 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1080 << r;
1081 return r;
1082 }
1083
1084 r = convertDBusToJSON(containerType, m, data);
1085 if (r < 0)
1086 {
1087 return r;
1088 }
1089
1090 r = sd_bus_message_exit_container(m.get());
1091 if (r < 0)
1092 {
1093 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed";
1094 return r;
1095 }
1096
1097 return 0;
1098}
1099
Ed Tanous23a21a12020-07-25 04:45:05 +00001100inline int convertDBusToJSON(const std::string& returnType,
1101 sdbusplus::message::message& m,
1102 nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001103{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001104 int r = 0;
1105 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1106
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001107 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001108 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001109 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001110 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001111 {
1112 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001113 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001114 }
1115
1116 if (typeCode == "s")
1117 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001118 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001119 if (r < 0)
1120 {
1121 return r;
1122 }
1123 }
1124 else if (typeCode == "g")
1125 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001126 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001127 if (r < 0)
1128 {
1129 return r;
1130 }
1131 }
1132 else if (typeCode == "o")
1133 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001134 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001135 if (r < 0)
1136 {
1137 return r;
1138 }
1139 }
1140 else if (typeCode == "b")
1141 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001142 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001143 if (r < 0)
1144 {
1145 return r;
1146 }
1147
Matt Spinlerf39420c2019-01-30 12:57:18 -06001148 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001149 }
1150 else if (typeCode == "u")
1151 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001152 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001153 if (r < 0)
1154 {
1155 return r;
1156 }
1157 }
1158 else if (typeCode == "i")
1159 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001160 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001161 if (r < 0)
1162 {
1163 return r;
1164 }
1165 }
1166 else if (typeCode == "x")
1167 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001168 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001169 if (r < 0)
1170 {
1171 return r;
1172 }
1173 }
1174 else if (typeCode == "t")
1175 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001176 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001177 if (r < 0)
1178 {
1179 return r;
1180 }
1181 }
1182 else if (typeCode == "n")
1183 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001184 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001185 if (r < 0)
1186 {
1187 return r;
1188 }
1189 }
1190 else if (typeCode == "q")
1191 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001192 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001193 if (r < 0)
1194 {
1195 return r;
1196 }
1197 }
1198 else if (typeCode == "y")
1199 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001200 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001201 if (r < 0)
1202 {
1203 return r;
1204 }
1205 }
1206 else if (typeCode == "d")
1207 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001208 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001209 if (r < 0)
1210 {
1211 return r;
1212 }
1213 }
1214 else if (typeCode == "h")
1215 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001216 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001217 if (r < 0)
1218 {
1219 return r;
1220 }
1221 }
Matt Spinler6df8f992019-01-14 12:47:47 -06001222 else if (boost::starts_with(typeCode, "a"))
1223 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001224 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001225 if (r < 0)
1226 {
1227 return r;
1228 }
1229 }
Matt Spinler75c6c672019-01-14 13:01:46 -06001230 else if (boost::starts_with(typeCode, "(") &&
1231 boost::ends_with(typeCode, ")"))
1232 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001233 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001234 if (r < 0)
1235 {
1236 return r;
1237 }
1238 }
Matt Spinler89c19702019-01-14 13:13:00 -06001239 else if (boost::starts_with(typeCode, "v"))
1240 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001241 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001242 if (r < 0)
1243 {
1244 return r;
1245 }
1246 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001247 else
1248 {
Matt Spinlerd22a7132019-01-14 12:14:30 -06001249 BMCWEB_LOG_ERROR << "Invalid D-Bus signature type " << typeCode;
1250 return -2;
1251 }
1252 }
1253
Matt Spinler16caaee2019-01-15 11:40:34 -06001254 return 0;
1255}
1256
Ed Tanous23a21a12020-07-25 04:45:05 +00001257inline void
1258 handleMethodResponse(std::shared_ptr<InProgressActionData> transaction,
1259 sdbusplus::message::message& m,
1260 const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001261{
Matt Spinler39a4e392019-01-15 11:53:13 -06001262 nlohmann::json data;
1263
1264 int r = convertDBusToJSON(returnType, m, data);
1265 if (r < 0)
1266 {
1267 transaction->outputFailed = true;
1268 return;
1269 }
1270
1271 if (data.is_null())
1272 {
1273 return;
1274 }
1275
1276 if (transaction->methodResponse.is_null())
1277 {
1278 transaction->methodResponse = std::move(data);
1279 return;
1280 }
1281
1282 // If they're both dictionaries or arrays, merge into one.
1283 // Otherwise, make the results an array with every result
1284 // an entry. Could also just fail in that case, but it
1285 // seems better to get the data back somehow.
1286
1287 if (transaction->methodResponse.is_object() && data.is_object())
1288 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001289 for (const auto& obj : data.items())
Matt Spinler39a4e392019-01-15 11:53:13 -06001290 {
1291 // Note: Will overwrite the data for a duplicate key
1292 transaction->methodResponse.emplace(obj.key(),
1293 std::move(obj.value()));
1294 }
1295 return;
1296 }
1297
1298 if (transaction->methodResponse.is_array() && data.is_array())
1299 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001300 for (auto& obj : data)
Matt Spinler39a4e392019-01-15 11:53:13 -06001301 {
1302 transaction->methodResponse.push_back(std::move(obj));
1303 }
1304 return;
1305 }
1306
1307 if (!transaction->convertedToArray)
1308 {
1309 // They are different types. May as well turn them into an array
1310 nlohmann::json j = std::move(transaction->methodResponse);
1311 transaction->methodResponse = nlohmann::json::array();
1312 transaction->methodResponse.push_back(std::move(j));
1313 transaction->methodResponse.push_back(std::move(data));
1314 transaction->convertedToArray = true;
1315 }
1316 else
1317 {
1318 transaction->methodResponse.push_back(std::move(data));
1319 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001320}
1321
Ed Tanous23a21a12020-07-25 04:45:05 +00001322inline void
1323 findActionOnInterface(std::shared_ptr<InProgressActionData> transaction,
1324 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001325{
1326 BMCWEB_LOG_DEBUG << "findActionOnInterface for connection "
1327 << connectionName;
1328 crow::connections::systemBus->async_method_call(
1329 [transaction, connectionName{std::string(connectionName)}](
1330 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001331 const std::string& introspect_xml) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001332 BMCWEB_LOG_DEBUG << "got xml:\n " << introspect_xml;
1333 if (ec)
1334 {
1335 BMCWEB_LOG_ERROR
1336 << "Introspect call failed with error: " << ec.message()
1337 << " on process: " << connectionName << "\n";
Matt Spinler318bd892019-01-15 09:59:20 -06001338 return;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001339 }
Matt Spinler318bd892019-01-15 09:59:20 -06001340 tinyxml2::XMLDocument doc;
1341
1342 doc.Parse(introspect_xml.data(), introspect_xml.size());
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001343 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
Matt Spinler318bd892019-01-15 09:59:20 -06001344 if (pRoot == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001345 {
Matt Spinler318bd892019-01-15 09:59:20 -06001346 BMCWEB_LOG_ERROR << "XML document failed to parse "
1347 << connectionName << "\n";
1348 return;
1349 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001350 tinyxml2::XMLElement* interfaceNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001351 pRoot->FirstChildElement("interface");
1352 while (interfaceNode != nullptr)
1353 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001354 const char* thisInterfaceName =
Matt Spinler318bd892019-01-15 09:59:20 -06001355 interfaceNode->Attribute("name");
1356 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001357 {
Matt Spinler318bd892019-01-15 09:59:20 -06001358 if (!transaction->interfaceName.empty() &&
1359 (transaction->interfaceName != thisInterfaceName))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001360 {
Matt Spinler318bd892019-01-15 09:59:20 -06001361 interfaceNode =
1362 interfaceNode->NextSiblingElement("interface");
1363 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001364 }
Matt Spinler318bd892019-01-15 09:59:20 -06001365
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001366 tinyxml2::XMLElement* methodNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001367 interfaceNode->FirstChildElement("method");
1368 while (methodNode != nullptr)
1369 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001370 const char* thisMethodName =
Matt Spinler318bd892019-01-15 09:59:20 -06001371 methodNode->Attribute("name");
1372 BMCWEB_LOG_DEBUG << "Found method: " << thisMethodName;
1373 if (thisMethodName != nullptr &&
1374 thisMethodName == transaction->methodName)
1375 {
1376 BMCWEB_LOG_DEBUG
1377 << "Found method named " << thisMethodName
1378 << " on interface " << thisInterfaceName;
1379 sdbusplus::message::message m =
1380 crow::connections::systemBus->new_method_call(
1381 connectionName.c_str(),
1382 transaction->path.c_str(),
1383 thisInterfaceName,
1384 transaction->methodName.c_str());
1385
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001386 tinyxml2::XMLElement* argumentNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001387 methodNode->FirstChildElement("arg");
1388
Matt Spinler16caaee2019-01-15 11:40:34 -06001389 std::string returnType;
1390
1391 // Find the output type
1392 while (argumentNode != nullptr)
1393 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001394 const char* argDirection =
Matt Spinler16caaee2019-01-15 11:40:34 -06001395 argumentNode->Attribute("direction");
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001396 const char* argType =
Matt Spinler16caaee2019-01-15 11:40:34 -06001397 argumentNode->Attribute("type");
1398 if (argDirection != nullptr &&
1399 argType != nullptr &&
1400 std::string(argDirection) == "out")
1401 {
1402 returnType = argType;
1403 break;
1404 }
1405 argumentNode =
1406 argumentNode->NextSiblingElement("arg");
1407 }
1408
Matt Spinler318bd892019-01-15 09:59:20 -06001409 nlohmann::json::const_iterator argIt =
1410 transaction->arguments.begin();
1411
Matt Spinler16caaee2019-01-15 11:40:34 -06001412 argumentNode = methodNode->FirstChildElement("arg");
1413
Matt Spinler318bd892019-01-15 09:59:20 -06001414 while (argumentNode != nullptr)
1415 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001416 const char* argDirection =
Matt Spinler318bd892019-01-15 09:59:20 -06001417 argumentNode->Attribute("direction");
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001418 const char* argType =
Matt Spinler318bd892019-01-15 09:59:20 -06001419 argumentNode->Attribute("type");
1420 if (argDirection != nullptr &&
1421 argType != nullptr &&
1422 std::string(argDirection) == "in")
1423 {
1424 if (argIt == transaction->arguments.end())
1425 {
1426 transaction->setErrorStatus(
1427 "Invalid method args");
1428 return;
1429 }
1430 if (convertJsonToDbus(m.get(),
1431 std::string(argType),
1432 *argIt) < 0)
1433 {
1434 transaction->setErrorStatus(
1435 "Invalid method arg type");
1436 return;
1437 }
1438
1439 argIt++;
1440 }
1441 argumentNode =
1442 argumentNode->NextSiblingElement("arg");
1443 }
1444
1445 crow::connections::systemBus->async_send(
Matt Spinler16caaee2019-01-15 11:40:34 -06001446 m, [transaction, returnType](
Ed Tanous23a21a12020-07-25 04:45:05 +00001447 boost::system::error_code ec2,
1448 sdbusplus::message::message& m2) {
1449 if (ec2)
Matt Spinler318bd892019-01-15 09:59:20 -06001450 {
Matt Spinler16caaee2019-01-15 11:40:34 -06001451 transaction->methodFailed = true;
Ed Tanous23a21a12020-07-25 04:45:05 +00001452 const sd_bus_error* e = m2.get_error();
Matt Spinler06b1b632019-06-18 16:09:25 -05001453
1454 if (e)
1455 {
1456 setErrorResponse(
1457 transaction->res,
1458 boost::beast::http::status::
1459 bad_request,
1460 e->name, e->message);
1461 }
1462 else
1463 {
1464 setErrorResponse(
1465 transaction->res,
1466 boost::beast::http::status::
1467 bad_request,
1468 "Method call failed",
1469 methodFailedMsg);
1470 }
Matt Spinler318bd892019-01-15 09:59:20 -06001471 return;
1472 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001473 else
1474 {
1475 transaction->methodPassed = true;
1476 }
1477
Ed Tanous23a21a12020-07-25 04:45:05 +00001478 handleMethodResponse(transaction, m2,
Matt Spinler16caaee2019-01-15 11:40:34 -06001479 returnType);
Matt Spinler318bd892019-01-15 09:59:20 -06001480 });
1481 break;
1482 }
1483 methodNode = methodNode->NextSiblingElement("method");
1484 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001485 }
Matt Spinler318bd892019-01-15 09:59:20 -06001486 interfaceNode = interfaceNode->NextSiblingElement("interface");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001487 }
1488 },
1489 connectionName, transaction->path,
1490 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001491}
1492
Ed Tanous23a21a12020-07-25 04:45:05 +00001493inline void handleAction(const crow::Request& req, crow::Response& res,
1494 const std::string& objectPath,
1495 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001496{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001497 BMCWEB_LOG_DEBUG << "handleAction on path: " << objectPath << " and method "
1498 << methodName;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001499 nlohmann::json requestDbusData =
1500 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001501
Ed Tanous1abe55e2018-09-05 08:30:59 -07001502 if (requestDbusData.is_discarded())
1503 {
Matt Spinler6db06242018-12-11 11:21:22 -06001504 setErrorResponse(res, boost::beast::http::status::bad_request,
1505 noJsonDesc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001506 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001507 return;
1508 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001509 nlohmann::json::iterator data = requestDbusData.find("data");
1510 if (data == requestDbusData.end())
1511 {
Matt Spinler6db06242018-12-11 11:21:22 -06001512 setErrorResponse(res, boost::beast::http::status::bad_request,
1513 noJsonDesc, badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001514 res.end();
1515 return;
1516 }
1517
1518 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001519 {
Matt Spinler6db06242018-12-11 11:21:22 -06001520 setErrorResponse(res, boost::beast::http::status::bad_request,
1521 noJsonDesc, badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001522 res.end();
1523 return;
1524 }
1525 auto transaction = std::make_shared<InProgressActionData>(res);
1526
1527 transaction->path = objectPath;
1528 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001529 transaction->arguments = std::move(*data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001530 crow::connections::systemBus->async_method_call(
1531 [transaction](
1532 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001533 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1534 interfaceNames) {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001535 if (ec || interfaceNames.size() <= 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001536 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001537 BMCWEB_LOG_ERROR << "Can't find object";
Matt Spinler6db06242018-12-11 11:21:22 -06001538 setErrorResponse(transaction->res,
1539 boost::beast::http::status::not_found,
1540 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001541 return;
1542 }
1543
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001544 BMCWEB_LOG_DEBUG << "GetObject returned " << interfaceNames.size()
1545 << " object(s)";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001546
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001547 for (const std::pair<std::string, std::vector<std::string>>&
1548 object : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001549 {
1550 findActionOnInterface(transaction, object.first);
1551 }
1552 },
1553 "xyz.openbmc_project.ObjectMapper",
1554 "/xyz/openbmc_project/object_mapper",
1555 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
1556 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001557}
1558
Ed Tanouscb13a392020-07-25 19:02:03 +00001559inline void handleDelete(crow::Response& res, const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001560{
1561 BMCWEB_LOG_DEBUG << "handleDelete on path: " << objectPath;
1562
1563 crow::connections::systemBus->async_method_call(
1564 [&res, objectPath](
1565 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001566 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1567 interfaceNames) {
Matt Spinlerde818812018-12-11 16:39:20 -06001568 if (ec || interfaceNames.size() <= 0)
1569 {
1570 BMCWEB_LOG_ERROR << "Can't find object";
Matt Spinler62d2e8b2019-01-22 13:45:51 -06001571 setErrorResponse(res,
1572 boost::beast::http::status::method_not_allowed,
1573 methodNotAllowedDesc, methodNotAllowedMsg);
Matt Spinlerde818812018-12-11 16:39:20 -06001574 res.end();
1575 return;
1576 }
1577
1578 auto transaction = std::make_shared<InProgressActionData>(res);
1579 transaction->path = objectPath;
1580 transaction->methodName = "Delete";
1581 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
1582
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001583 for (const std::pair<std::string, std::vector<std::string>>&
1584 object : interfaceNames)
Matt Spinlerde818812018-12-11 16:39:20 -06001585 {
1586 findActionOnInterface(transaction, object.first);
1587 }
1588 },
1589 "xyz.openbmc_project.ObjectMapper",
1590 "/xyz/openbmc_project/object_mapper",
1591 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001592 std::array<const char*, 0>());
Matt Spinlerde818812018-12-11 16:39:20 -06001593}
1594
Ed Tanous23a21a12020-07-25 04:45:05 +00001595inline void handleList(crow::Response& res, const std::string& objectPath,
1596 int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001597{
1598 crow::connections::systemBus->async_method_call(
1599 [&res](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001600 std::vector<std::string>& objectPaths) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001601 if (ec)
1602 {
Matt Spinlerd6091dd2018-12-06 14:08:27 -06001603 setErrorResponse(res, boost::beast::http::status::not_found,
1604 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001605 }
1606 else
1607 {
1608 res.jsonValue = {{"status", "ok"},
1609 {"message", "200 OK"},
1610 {"data", std::move(objectPaths)}};
1611 }
1612 res.end();
1613 },
1614 "xyz.openbmc_project.ObjectMapper",
1615 "/xyz/openbmc_project/object_mapper",
1616 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", objectPath,
Ed Tanousf839dfe2018-11-12 11:11:15 -08001617 depth, std::array<std::string, 0>());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001618}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001619
Ed Tanous23a21a12020-07-25 04:45:05 +00001620inline void handleEnumerate(crow::Response& res, const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001621{
Ed Tanous049a0512018-11-01 13:58:42 -07001622 BMCWEB_LOG_DEBUG << "Doing enumerate on " << objectPath;
1623 auto asyncResp = std::make_shared<bmcweb::AsyncResp>(res);
1624
1625 asyncResp->res.jsonValue = {{"message", "200 OK"},
1626 {"status", "ok"},
1627 {"data", nlohmann::json::object()}};
1628
Ed Tanous1abe55e2018-09-05 08:30:59 -07001629 crow::connections::systemBus->async_method_call(
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001630 [objectPath, asyncResp](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001631 GetSubTreeType& object_names) {
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001632 auto transaction = std::make_shared<InProgressEnumerateData>(
1633 objectPath, asyncResp);
1634
1635 transaction->subtree =
1636 std::make_shared<GetSubTreeType>(std::move(object_names));
1637
Ed Tanous1abe55e2018-09-05 08:30:59 -07001638 if (ec)
1639 {
Matt Spinler2ae60092018-12-06 10:35:36 -06001640 BMCWEB_LOG_ERROR << "GetSubTree failed on "
1641 << transaction->objectPath;
1642 setErrorResponse(transaction->asyncResp->res,
1643 boost::beast::http::status::not_found,
1644 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001645 return;
1646 }
Ed Tanous64530012018-02-06 17:08:16 -08001647
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001648 // Add the data for the path passed in to the results
1649 // as if GetSubTree returned it, and continue on enumerating
1650 getObjectAndEnumerate(transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001651 },
1652 "xyz.openbmc_project.ObjectMapper",
1653 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -07001654 "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath, 0,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001655 std::array<const char*, 0>());
Ed Tanous64530012018-02-06 17:08:16 -08001656}
Ed Tanous911ac312017-08-15 09:37:42 -07001657
Ed Tanous23a21a12020-07-25 04:45:05 +00001658inline void handleGet(crow::Response& res, std::string& objectPath,
1659 std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001660{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001661 BMCWEB_LOG_DEBUG << "handleGet: " << objectPath << " prop:" << destProperty;
1662 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001663 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001664
Ed Tanous1abe55e2018-09-05 08:30:59 -07001665 std::shared_ptr<std::string> path =
1666 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001667
Ed Tanous1abe55e2018-09-05 08:30:59 -07001668 using GetObjectType =
1669 std::vector<std::pair<std::string, std::vector<std::string>>>;
1670 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001671 [&res, path, propertyName](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001672 const GetObjectType& object_names) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001673 if (ec || object_names.size() <= 0)
1674 {
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001675 setErrorResponse(res, boost::beast::http::status::not_found,
1676 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001677 res.end();
1678 return;
1679 }
1680 std::shared_ptr<nlohmann::json> response =
1681 std::make_shared<nlohmann::json>(nlohmann::json::object());
Ed Tanous7c091622019-05-23 11:42:36 -07001682 // The mapper should never give us an empty interface names
1683 // list, but check anyway
Ed Tanous23a21a12020-07-25 04:45:05 +00001684 for (const std::pair<std::string, std::vector<std::string>>&
Ed Tanous1abe55e2018-09-05 08:30:59 -07001685 connection : object_names)
1686 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001687 const std::vector<std::string>& interfaceNames =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001688 connection.second;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001689
Ed Tanous1abe55e2018-09-05 08:30:59 -07001690 if (interfaceNames.size() <= 0)
1691 {
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001692 setErrorResponse(res, boost::beast::http::status::not_found,
1693 notFoundDesc, notFoundMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001694 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001695 return;
1696 }
1697
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001698 for (const std::string& interface : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001699 {
Matt Spinlerfe7e97d2019-01-30 15:33:21 -06001700 sdbusplus::message::message m =
1701 crow::connections::systemBus->new_method_call(
1702 connection.first.c_str(), path->c_str(),
1703 "org.freedesktop.DBus.Properties", "GetAll");
1704 m.append(interface);
1705 crow::connections::systemBus->async_send(
1706 m, [&res, response,
Ed Tanous23a21a12020-07-25 04:45:05 +00001707 propertyName](const boost::system::error_code ec2,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001708 sdbusplus::message::message& msg) {
Ed Tanous23a21a12020-07-25 04:45:05 +00001709 if (ec2)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001710 {
1711 BMCWEB_LOG_ERROR << "Bad dbus request error: "
Ed Tanous23a21a12020-07-25 04:45:05 +00001712 << ec2;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001713 }
1714 else
1715 {
Matt Spinlerfe7e97d2019-01-30 15:33:21 -06001716 nlohmann::json properties;
1717 int r =
1718 convertDBusToJSON("a{sv}", msg, properties);
1719 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001720 {
Matt Spinlerfe7e97d2019-01-30 15:33:21 -06001721 BMCWEB_LOG_ERROR
1722 << "convertDBusToJSON failed";
1723 }
1724 else
1725 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001726 for (auto& prop : properties.items())
Matt Spinlerfe7e97d2019-01-30 15:33:21 -06001727 {
Ed Tanous7c091622019-05-23 11:42:36 -07001728 // if property name is empty, or
1729 // matches our search query, add it
1730 // to the response json
Ed Tanous1abe55e2018-09-05 08:30:59 -07001731
Matt Spinlerfe7e97d2019-01-30 15:33:21 -06001732 if (propertyName->empty())
1733 {
1734 (*response)[prop.key()] =
1735 std::move(prop.value());
1736 }
1737 else if (prop.key() == *propertyName)
1738 {
1739 *response = std::move(prop.value());
1740 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001741 }
1742 }
1743 }
1744 if (response.use_count() == 1)
1745 {
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001746 if (!propertyName->empty() && response->empty())
1747 {
1748 setErrorResponse(
1749 res,
1750 boost::beast::http::status::not_found,
1751 propNotFoundDesc, notFoundMsg);
1752 }
1753 else
1754 {
1755 res.jsonValue = {{"status", "ok"},
1756 {"message", "200 OK"},
1757 {"data", *response}};
1758 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001759 res.end();
1760 }
Matt Spinlerfe7e97d2019-01-30 15:33:21 -06001761 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001762 }
1763 }
1764 },
1765 "xyz.openbmc_project.ObjectMapper",
1766 "/xyz/openbmc_project/object_mapper",
1767 "xyz.openbmc_project.ObjectMapper", "GetObject", *path,
1768 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001769}
1770
Ed Tanous1abe55e2018-09-05 08:30:59 -07001771struct AsyncPutRequest
1772{
Ed Tanous23a21a12020-07-25 04:45:05 +00001773 AsyncPutRequest(crow::Response& resIn) : res(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001774 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001775 ~AsyncPutRequest()
1776 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001777 if (res.jsonValue.empty())
1778 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001779 setErrorResponse(res, boost::beast::http::status::forbidden,
1780 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001781 }
1782
1783 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001784 }
1785
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001786 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001787 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001788 setErrorResponse(res, boost::beast::http::status::internal_server_error,
1789 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001790 }
1791
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001792 crow::Response& res;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001793 std::string objectPath;
1794 std::string propertyName;
1795 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001796};
1797
Ed Tanous23a21a12020-07-25 04:45:05 +00001798inline void handlePut(const crow::Request& req, crow::Response& res,
1799 const std::string& objectPath,
1800 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001801{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001802 if (destProperty.empty())
1803 {
1804 setErrorResponse(res, boost::beast::http::status::forbidden,
1805 forbiddenResDesc, forbiddenMsg);
1806 res.end();
1807 return;
1808 }
1809
Ed Tanous1abe55e2018-09-05 08:30:59 -07001810 nlohmann::json requestDbusData =
1811 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001812
Ed Tanous1abe55e2018-09-05 08:30:59 -07001813 if (requestDbusData.is_discarded())
1814 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001815 setErrorResponse(res, boost::beast::http::status::bad_request,
1816 noJsonDesc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001817 res.end();
1818 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001819 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001820
Ed Tanous1abe55e2018-09-05 08:30:59 -07001821 nlohmann::json::const_iterator propertyIt = requestDbusData.find("data");
1822 if (propertyIt == requestDbusData.end())
1823 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001824 setErrorResponse(res, boost::beast::http::status::bad_request,
1825 noJsonDesc, badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001826 res.end();
1827 return;
1828 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001829 const nlohmann::json& propertySetValue = *propertyIt;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001830 auto transaction = std::make_shared<AsyncPutRequest>(res);
1831 transaction->objectPath = objectPath;
1832 transaction->propertyName = destProperty;
1833 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001834
Ed Tanous1abe55e2018-09-05 08:30:59 -07001835 using GetObjectType =
1836 std::vector<std::pair<std::string, std::vector<std::string>>>;
Ed Tanous911ac312017-08-15 09:37:42 -07001837
Ed Tanous1abe55e2018-09-05 08:30:59 -07001838 crow::connections::systemBus->async_method_call(
Ed Tanous23a21a12020-07-25 04:45:05 +00001839 [transaction](const boost::system::error_code ec2,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001840 const GetObjectType& object_names) {
Ed Tanous23a21a12020-07-25 04:45:05 +00001841 if (!ec2 && object_names.size() <= 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001842 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001843 setErrorResponse(transaction->res,
1844 boost::beast::http::status::not_found,
1845 propNotFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001846 return;
1847 }
Ed Tanous911ac312017-08-15 09:37:42 -07001848
Ed Tanous23a21a12020-07-25 04:45:05 +00001849 for (const std::pair<std::string, std::vector<std::string>>&
Ed Tanous1abe55e2018-09-05 08:30:59 -07001850 connection : object_names)
1851 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001852 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001853
Ed Tanous1abe55e2018-09-05 08:30:59 -07001854 crow::connections::systemBus->async_method_call(
1855 [connectionName{std::string(connectionName)},
Ed Tanous23a21a12020-07-25 04:45:05 +00001856 transaction](const boost::system::error_code ec3,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001857 const std::string& introspectXml) {
Ed Tanous23a21a12020-07-25 04:45:05 +00001858 if (ec3)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001859 {
1860 BMCWEB_LOG_ERROR
1861 << "Introspect call failed with error: "
Ed Tanous23a21a12020-07-25 04:45:05 +00001862 << ec3.message()
Ed Tanous1abe55e2018-09-05 08:30:59 -07001863 << " on process: " << connectionName;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001864 transaction->setErrorStatus("Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001865 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001866 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001867 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001868
Ed Tanous1abe55e2018-09-05 08:30:59 -07001869 doc.Parse(introspectXml.c_str());
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001870 tinyxml2::XMLNode* pRoot =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001871 doc.FirstChildElement("node");
1872 if (pRoot == nullptr)
1873 {
1874 BMCWEB_LOG_ERROR << "XML document failed to parse: "
1875 << introspectXml;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001876 transaction->setErrorStatus("Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001877 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001878 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001879 tinyxml2::XMLElement* ifaceNode =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001880 pRoot->FirstChildElement("interface");
1881 while (ifaceNode != nullptr)
1882 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001883 const char* interfaceName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001884 ifaceNode->Attribute("name");
1885 BMCWEB_LOG_DEBUG << "found interface "
1886 << interfaceName;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001887 tinyxml2::XMLElement* propNode =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001888 ifaceNode->FirstChildElement("property");
1889 while (propNode != nullptr)
1890 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001891 const char* propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001892 propNode->Attribute("name");
1893 BMCWEB_LOG_DEBUG << "Found property "
1894 << propertyName;
1895 if (propertyName == transaction->propertyName)
1896 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001897 const char* argType =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001898 propNode->Attribute("type");
1899 if (argType != nullptr)
1900 {
1901 sdbusplus::message::message m =
1902 crow::connections::systemBus
1903 ->new_method_call(
1904 connectionName.c_str(),
1905 transaction->objectPath
1906 .c_str(),
1907 "org.freedesktop.DBus."
1908 "Properties",
1909 "Set");
1910 m.append(interfaceName,
1911 transaction->propertyName);
1912 int r = sd_bus_message_open_container(
1913 m.get(), SD_BUS_TYPE_VARIANT,
1914 argType);
1915 if (r < 0)
1916 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001917 transaction->setErrorStatus(
1918 "Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001919 return;
1920 }
1921 r = convertJsonToDbus(
1922 m.get(), argType,
1923 transaction->propertyValue);
1924 if (r < 0)
1925 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -05001926 if (r == -ERANGE)
1927 {
1928 transaction->setErrorStatus(
1929 "Provided property value "
1930 "is out of range for the "
1931 "property type");
1932 }
1933 else
1934 {
1935 transaction->setErrorStatus(
1936 "Invalid arg type");
1937 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001938 return;
1939 }
1940 r = sd_bus_message_close_container(
1941 m.get());
1942 if (r < 0)
1943 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001944 transaction->setErrorStatus(
1945 "Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001946 return;
1947 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001948 crow::connections::systemBus
1949 ->async_send(
1950 m,
1951 [transaction](
1952 boost::system::error_code
1953 ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001954 sdbusplus::message::message&
Ed Tanous23a21a12020-07-25 04:45:05 +00001955 m2) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001956 BMCWEB_LOG_DEBUG << "sent";
1957 if (ec)
1958 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001959 const sd_bus_error* e =
Ed Tanous23a21a12020-07-25 04:45:05 +00001960 m2.get_error();
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001961 setErrorResponse(
1962 transaction->res,
1963 boost::beast::http::
1964 status::
1965 forbidden,
Matt Spinler06b1b632019-06-18 16:09:25 -05001966 (e) ? e->name
1967 : ec.category()
1968 .name(),
1969 (e) ? e->message
1970 : ec.message());
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001971 }
1972 else
1973 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001974 transaction->res
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001975 .jsonValue = {
1976 {"status", "ok"},
1977 {"message",
1978 "200 OK"},
1979 {"data", nullptr}};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001980 }
1981 });
1982 }
1983 }
1984 propNode =
1985 propNode->NextSiblingElement("property");
1986 }
1987 ifaceNode =
1988 ifaceNode->NextSiblingElement("interface");
1989 }
1990 },
1991 connectionName, transaction->objectPath,
1992 "org.freedesktop.DBus.Introspectable", "Introspect");
1993 }
1994 },
1995 "xyz.openbmc_project.ObjectMapper",
1996 "/xyz/openbmc_project/object_mapper",
1997 "xyz.openbmc_project.ObjectMapper", "GetObject",
1998 transaction->objectPath, std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001999}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002000
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002001inline void handleDBusUrl(const crow::Request& req, crow::Response& res,
2002 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002003{
Ed Tanous049a0512018-11-01 13:58:42 -07002004
2005 // If accessing a single attribute, fill in and update objectPath,
2006 // otherwise leave destProperty blank
2007 std::string destProperty = "";
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002008 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002009 size_t attrPosition = objectPath.find(attrSeperator);
2010 if (attrPosition != objectPath.npos)
2011 {
2012 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2013 objectPath.length());
2014 objectPath = objectPath.substr(0, attrPosition);
2015 }
2016
Ed Tanousb41187f2019-10-24 16:30:02 -07002017 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002018 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002019 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002020 size_t actionPosition = objectPath.find(actionSeperator);
2021 if (actionPosition != objectPath.npos)
2022 {
2023 std::string postProperty =
2024 objectPath.substr((actionPosition + strlen(actionSeperator)),
2025 objectPath.length());
2026 objectPath = objectPath.substr(0, actionPosition);
2027 handleAction(req, res, objectPath, postProperty);
2028 return;
2029 }
2030 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002031 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002032 {
2033 if (boost::ends_with(objectPath, "/enumerate"))
2034 {
2035 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2036 objectPath.end());
2037 handleEnumerate(res, objectPath);
2038 }
2039 else if (boost::ends_with(objectPath, "/list"))
2040 {
2041 objectPath.erase(objectPath.end() - sizeof("list"),
2042 objectPath.end());
2043 handleList(res, objectPath);
2044 }
2045 else
2046 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002047 // Trim any trailing "/" at the end
2048 if (boost::ends_with(objectPath, "/"))
2049 {
2050 objectPath.pop_back();
2051 handleList(res, objectPath, 1);
2052 }
2053 else
2054 {
2055 handleGet(res, objectPath, destProperty);
2056 }
Ed Tanous049a0512018-11-01 13:58:42 -07002057 }
2058 return;
2059 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002060 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002061 {
2062 handlePut(req, res, objectPath, destProperty);
2063 return;
2064 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002065 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002066 {
Ed Tanouscb13a392020-07-25 19:02:03 +00002067 handleDelete(res, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002068 return;
2069 }
Ed Tanous049a0512018-11-01 13:58:42 -07002070
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002071 setErrorResponse(res, boost::beast::http::status::method_not_allowed,
2072 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002073 res.end();
2074}
2075
Ed Tanous23a21a12020-07-25 04:45:05 +00002076inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002077{
2078 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous23a21a12020-07-25 04:45:05 +00002079 .privileges({"Login"})
Ed Tanousb41187f2019-10-24 16:30:02 -07002080 .methods(boost::beast::http::verb::get)(
Ed Tanouscb13a392020-07-25 19:02:03 +00002081 [](const crow::Request&, crow::Response& res) {
Gunnar Millscaa3ce32020-07-08 14:46:53 -05002082 res.jsonValue = {{"buses", {{{"name", "system"}}}},
Ed Tanous1abe55e2018-09-05 08:30:59 -07002083 {"status", "ok"}};
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002084 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -07002085 });
2086
2087 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous23a21a12020-07-25 04:45:05 +00002088 .privileges({"Login"})
Ed Tanousb41187f2019-10-24 16:30:02 -07002089 .methods(boost::beast::http::verb::get)(
Ed Tanouscb13a392020-07-25 19:02:03 +00002090 [](const crow::Request&, crow::Response& res) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07002091 auto myCallback = [&res](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002092 std::vector<std::string>& names) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07002093 if (ec)
2094 {
2095 BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
2096 res.result(
2097 boost::beast::http::status::internal_server_error);
2098 }
2099 else
2100 {
2101 std::sort(names.begin(), names.end());
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002102 res.jsonValue = {{"status", "ok"}};
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002103 auto& objectsSub = res.jsonValue["objects"];
2104 for (auto& name : names)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002105 {
2106 objectsSub.push_back({{"name", name}});
2107 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002108 }
2109 res.end();
2110 };
2111 crow::connections::systemBus->async_method_call(
2112 std::move(myCallback), "org.freedesktop.DBus", "/",
2113 "org.freedesktop.DBus", "ListNames");
2114 });
2115
2116 BMCWEB_ROUTE(app, "/list/")
Ed Tanous23a21a12020-07-25 04:45:05 +00002117 .privileges({"Login"})
Ed Tanousb41187f2019-10-24 16:30:02 -07002118 .methods(boost::beast::http::verb::get)(
Ed Tanouscb13a392020-07-25 19:02:03 +00002119 [](const crow::Request&, crow::Response& res) {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002120 handleList(res, "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07002121 });
2122
2123 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous23a21a12020-07-25 04:45:05 +00002124 .privileges({"Login"})
Ed Tanousb41187f2019-10-24 16:30:02 -07002125 .methods(boost::beast::http::verb::get)([](const crow::Request& req,
2126 crow::Response& res,
2127 const std::string& path) {
Tanousf00032d2018-11-05 01:18:10 -03002128 std::string objectPath = "/xyz/" + path;
2129 handleDBusUrl(req, res, objectPath);
2130 });
2131
2132 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous23a21a12020-07-25 04:45:05 +00002133 .privileges({"ConfigureComponents", "ConfigureManager"})
Ed Tanousb41187f2019-10-24 16:30:02 -07002134 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2135 boost::beast::http::verb::delete_)(
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002136 [](const crow::Request& req, crow::Response& res,
2137 const std::string& path) {
Ed Tanous049a0512018-11-01 13:58:42 -07002138 std::string objectPath = "/xyz/" + path;
2139 handleDBusUrl(req, res, objectPath);
2140 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002141
Ed Tanous049a0512018-11-01 13:58:42 -07002142 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous23a21a12020-07-25 04:45:05 +00002143 .privileges({"Login"})
Ed Tanousb41187f2019-10-24 16:30:02 -07002144 .methods(boost::beast::http::verb::get)([](const crow::Request& req,
2145 crow::Response& res,
2146 const std::string& path) {
Ed Tanouse1281402019-04-03 07:07:10 -07002147 std::string objectPath = "/org/" + path;
Tanousf00032d2018-11-05 01:18:10 -03002148 handleDBusUrl(req, res, objectPath);
2149 });
2150
2151 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous23a21a12020-07-25 04:45:05 +00002152 .privileges({"ConfigureComponents", "ConfigureManager"})
Ed Tanousb41187f2019-10-24 16:30:02 -07002153 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2154 boost::beast::http::verb::delete_)(
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002155 [](const crow::Request& req, crow::Response& res,
2156 const std::string& path) {
Ed Tanouse1281402019-04-03 07:07:10 -07002157 std::string objectPath = "/org/" + path;
Ed Tanous049a0512018-11-01 13:58:42 -07002158 handleDBusUrl(req, res, objectPath);
2159 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002160
Ed Tanous1abe55e2018-09-05 08:30:59 -07002161 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous23a21a12020-07-25 04:45:05 +00002162 .privileges({"ConfigureManager"})
Ed Tanouscb13a392020-07-25 19:02:03 +00002163 .methods(boost::beast::http::verb::get)([](const crow::Request&,
Ed Tanousb41187f2019-10-24 16:30:02 -07002164 crow::Response& res,
2165 const std::string& dumpId) {
Ed Tanousad18f072018-11-14 14:07:48 -08002166 std::regex validFilename("^[\\w\\- ]+(\\.?[\\w\\- ]*)$");
Ed Tanous1abe55e2018-09-05 08:30:59 -07002167 if (!std::regex_match(dumpId, validFilename))
2168 {
Ed Tanousad18f072018-11-14 14:07:48 -08002169 res.result(boost::beast::http::status::bad_request);
Ed Tanous1abe55e2018-09-05 08:30:59 -07002170 res.end();
2171 return;
2172 }
James Feistf6150402019-01-08 10:36:20 -08002173 std::filesystem::path loc(
Ed Tanous1abe55e2018-09-05 08:30:59 -07002174 "/var/lib/phosphor-debug-collector/dumps");
2175
Ed Tanousad18f072018-11-14 14:07:48 -08002176 loc /= dumpId;
Ed Tanous1abe55e2018-09-05 08:30:59 -07002177
James Feistf6150402019-01-08 10:36:20 -08002178 if (!std::filesystem::exists(loc) ||
2179 !std::filesystem::is_directory(loc))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002180 {
Ed Tanousad18f072018-11-14 14:07:48 -08002181 BMCWEB_LOG_ERROR << loc << "Not found";
Ed Tanous1abe55e2018-09-05 08:30:59 -07002182 res.result(boost::beast::http::status::not_found);
2183 res.end();
2184 return;
2185 }
James Feistf6150402019-01-08 10:36:20 -08002186 std::filesystem::directory_iterator files(loc);
Ed Tanousad18f072018-11-14 14:07:48 -08002187
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002188 for (auto& file : files)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002189 {
2190 std::ifstream readFile(file.path());
Ed Tanousad18f072018-11-14 14:07:48 -08002191 if (!readFile.good())
Ed Tanous1abe55e2018-09-05 08:30:59 -07002192 {
2193 continue;
2194 }
Ramesh Iyyard9207042019-07-05 08:04:42 -05002195
Ed Tanous1abe55e2018-09-05 08:30:59 -07002196 res.addHeader("Content-Type", "application/octet-stream");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002197
2198 // Assuming only one dump file will be present in the dump id
2199 // directory
2200 std::string dumpFileName = file.path().filename().string();
2201
2202 // Filename should be in alphanumeric, dot and underscore
2203 // Its based on phosphor-debug-collector application dumpfile
2204 // format
2205 std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
2206 if (!std::regex_match(dumpFileName, dumpFileRegex))
2207 {
2208 BMCWEB_LOG_ERROR << "Invalid dump filename "
2209 << dumpFileName;
2210 res.result(boost::beast::http::status::not_found);
2211 res.end();
2212 return;
2213 }
2214 std::string contentDispositionParam =
2215 "attachment; filename=\"" + dumpFileName + "\"";
2216
2217 res.addHeader("Content-Disposition", contentDispositionParam);
2218
Ed Tanous1abe55e2018-09-05 08:30:59 -07002219 res.body() = {std::istreambuf_iterator<char>(readFile),
2220 std::istreambuf_iterator<char>()};
2221 res.end();
Ed Tanousad18f072018-11-14 14:07:48 -08002222 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07002223 }
2224 res.result(boost::beast::http::status::not_found);
2225 res.end();
2226 return;
2227 });
2228
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002229 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous23a21a12020-07-25 04:45:05 +00002230 .privileges({"Login"})
Ed Tanousb41187f2019-10-24 16:30:02 -07002231
2232 .methods(boost::beast::http::verb::get)(
Ed Tanouscb13a392020-07-25 19:02:03 +00002233 [](const crow::Request&, crow::Response& res,
Ed Tanousb41187f2019-10-24 16:30:02 -07002234 const std::string& Connection) {
2235 introspectObjects(Connection, "/",
2236 std::make_shared<bmcweb::AsyncResp>(res));
2237 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002238
2239 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous23a21a12020-07-25 04:45:05 +00002240 .privileges({"ConfigureComponents", "ConfigureManager"})
Ed Tanousb41187f2019-10-24 16:30:02 -07002241 .methods(
2242 boost::beast::http::verb::get,
2243 boost::beast::http::verb::post)([](const crow::Request& req,
2244 crow::Response& res,
2245 const std::string& processName,
2246 const std::string&
2247 requestedPath) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07002248 std::vector<std::string> strs;
2249 boost::split(strs, requestedPath, boost::is_any_of("/"));
2250 std::string objectPath;
2251 std::string interfaceName;
2252 std::string methodName;
2253 auto it = strs.begin();
2254 if (it == strs.end())
2255 {
2256 objectPath = "/";
2257 }
2258 while (it != strs.end())
2259 {
2260 // Check if segment contains ".". If it does, it must be an
2261 // interface
2262 if (it->find(".") != std::string::npos)
2263 {
2264 break;
Gunnar Millscaa3ce32020-07-08 14:46:53 -05002265 // This check is necessary as the trailing slash gets
Ed Tanous7c091622019-05-23 11:42:36 -07002266 // parsed as part of our <path> specifier above, which
2267 // causes the normal trailing backslash redirector to
2268 // fail.
Ed Tanous1abe55e2018-09-05 08:30:59 -07002269 }
2270 else if (!it->empty())
2271 {
2272 objectPath += "/" + *it;
2273 }
2274 it++;
2275 }
2276 if (it != strs.end())
2277 {
2278 interfaceName = *it;
2279 it++;
2280
2281 // after interface, we might have a method name
2282 if (it != strs.end())
2283 {
2284 methodName = *it;
2285 it++;
2286 }
2287 }
2288 if (it != strs.end())
2289 {
Ed Tanous7c091622019-05-23 11:42:36 -07002290 // if there is more levels past the method name, something
2291 // went wrong, return not found
Ed Tanous1abe55e2018-09-05 08:30:59 -07002292 res.result(boost::beast::http::status::not_found);
AppaRao Puli3c27ed32020-03-31 01:21:57 +05302293 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -07002294 return;
2295 }
2296 if (interfaceName.empty())
2297 {
Ed Tanous7c091622019-05-23 11:42:36 -07002298 std::shared_ptr<bmcweb::AsyncResp> asyncResp =
2299 std::make_shared<bmcweb::AsyncResp>(res);
2300
Ed Tanous1abe55e2018-09-05 08:30:59 -07002301 crow::connections::systemBus->async_method_call(
Ed Tanous7c091622019-05-23 11:42:36 -07002302 [asyncResp, processName,
Ed Tanous1abe55e2018-09-05 08:30:59 -07002303 objectPath](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002304 const std::string& introspect_xml) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07002305 if (ec)
2306 {
2307 BMCWEB_LOG_ERROR
2308 << "Introspect call failed with error: "
2309 << ec.message()
2310 << " on process: " << processName
2311 << " path: " << objectPath << "\n";
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002312 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07002313 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002314 tinyxml2::XMLDocument doc;
2315
2316 doc.Parse(introspect_xml.c_str());
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002317 tinyxml2::XMLNode* pRoot =
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002318 doc.FirstChildElement("node");
2319 if (pRoot == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002320 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002321 BMCWEB_LOG_ERROR << "XML document failed to parse "
2322 << processName << " " << objectPath
2323 << "\n";
Ed Tanous7c091622019-05-23 11:42:36 -07002324 asyncResp->res.jsonValue = {
2325 {"status", "XML parse error"}};
2326 asyncResp->res.result(boost::beast::http::status::
2327 internal_server_error);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002328 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07002329 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002330
2331 BMCWEB_LOG_DEBUG << introspect_xml;
Ed Tanous7c091622019-05-23 11:42:36 -07002332 asyncResp->res.jsonValue = {
2333 {"status", "ok"},
2334 {"bus_name", processName},
2335 {"object_path", objectPath}};
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002336 nlohmann::json& interfacesArray =
Ed Tanous7c091622019-05-23 11:42:36 -07002337 asyncResp->res.jsonValue["interfaces"];
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002338 interfacesArray = nlohmann::json::array();
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002339 tinyxml2::XMLElement* interface =
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002340 pRoot->FirstChildElement("interface");
2341
2342 while (interface != nullptr)
2343 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002344 const char* ifaceName =
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002345 interface->Attribute("name");
2346 if (ifaceName != nullptr)
2347 {
2348 interfacesArray.push_back(
2349 {{"name", ifaceName}});
2350 }
2351
2352 interface =
2353 interface->NextSiblingElement("interface");
2354 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002355 },
2356 processName, objectPath,
2357 "org.freedesktop.DBus.Introspectable", "Introspect");
2358 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002359 else if (methodName.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07002360 {
Ed Tanous7c091622019-05-23 11:42:36 -07002361 std::shared_ptr<bmcweb::AsyncResp> asyncResp =
2362 std::make_shared<bmcweb::AsyncResp>(res);
2363
Ed Tanous1abe55e2018-09-05 08:30:59 -07002364 crow::connections::systemBus->async_method_call(
Ed Tanous7c091622019-05-23 11:42:36 -07002365 [asyncResp, processName, objectPath,
2366 interfaceName](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002367 const std::string& introspect_xml) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07002368 if (ec)
2369 {
2370 BMCWEB_LOG_ERROR
2371 << "Introspect call failed with error: "
2372 << ec.message()
2373 << " on process: " << processName
2374 << " path: " << objectPath << "\n";
Ed Tanous7c091622019-05-23 11:42:36 -07002375 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07002376 }
Ed Tanous7c091622019-05-23 11:42:36 -07002377 tinyxml2::XMLDocument doc;
2378
2379 doc.Parse(introspect_xml.data(), introspect_xml.size());
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002380 tinyxml2::XMLNode* pRoot =
Ed Tanous7c091622019-05-23 11:42:36 -07002381 doc.FirstChildElement("node");
2382 if (pRoot == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002383 {
Ed Tanous7c091622019-05-23 11:42:36 -07002384 BMCWEB_LOG_ERROR << "XML document failed to parse "
2385 << processName << " " << objectPath
2386 << "\n";
2387 asyncResp->res.result(boost::beast::http::status::
2388 internal_server_error);
2389 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07002390 }
Ed Tanous7c091622019-05-23 11:42:36 -07002391 asyncResp->res.jsonValue = {
2392 {"status", "ok"},
2393 {"bus_name", processName},
2394 {"interface", interfaceName},
2395 {"object_path", objectPath}};
2396
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002397 nlohmann::json& methodsArray =
Ed Tanous7c091622019-05-23 11:42:36 -07002398 asyncResp->res.jsonValue["methods"];
2399 methodsArray = nlohmann::json::array();
2400
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002401 nlohmann::json& signalsArray =
Ed Tanous7c091622019-05-23 11:42:36 -07002402 asyncResp->res.jsonValue["signals"];
2403 signalsArray = nlohmann::json::array();
2404
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002405 nlohmann::json& propertiesObj =
Ed Tanous7c091622019-05-23 11:42:36 -07002406 asyncResp->res.jsonValue["properties"];
2407 propertiesObj = nlohmann::json::object();
2408
2409 // if we know we're the only call, build the
2410 // json directly
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002411 tinyxml2::XMLElement* interface =
Ed Tanous7c091622019-05-23 11:42:36 -07002412 pRoot->FirstChildElement("interface");
2413 while (interface != nullptr)
2414 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002415 const char* ifaceName =
Ed Tanous7c091622019-05-23 11:42:36 -07002416 interface->Attribute("name");
2417
2418 if (ifaceName != nullptr &&
2419 ifaceName == interfaceName)
2420 {
2421 break;
2422 }
2423
2424 interface =
2425 interface->NextSiblingElement("interface");
2426 }
2427 if (interface == nullptr)
2428 {
2429 // if we got to the end of the list and
2430 // never found a match, throw 404
2431 asyncResp->res.result(
2432 boost::beast::http::status::not_found);
2433 return;
2434 }
2435
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002436 tinyxml2::XMLElement* methods =
Ed Tanous7c091622019-05-23 11:42:36 -07002437 interface->FirstChildElement("method");
2438 while (methods != nullptr)
2439 {
2440 nlohmann::json argsArray = nlohmann::json::array();
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002441 tinyxml2::XMLElement* arg =
Ed Tanous7c091622019-05-23 11:42:36 -07002442 methods->FirstChildElement("arg");
2443 while (arg != nullptr)
2444 {
2445 nlohmann::json thisArg;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002446 for (const char* fieldName :
2447 std::array<const char*, 3>{
Ed Tanous7c091622019-05-23 11:42:36 -07002448 "name", "direction", "type"})
2449 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002450 const char* fieldValue =
Ed Tanous7c091622019-05-23 11:42:36 -07002451 arg->Attribute(fieldName);
2452 if (fieldValue != nullptr)
2453 {
2454 thisArg[fieldName] = fieldValue;
2455 }
2456 }
2457 argsArray.push_back(std::move(thisArg));
2458 arg = arg->NextSiblingElement("arg");
2459 }
2460
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002461 const char* name = methods->Attribute("name");
Ed Tanous7c091622019-05-23 11:42:36 -07002462 if (name != nullptr)
2463 {
2464 methodsArray.push_back(
2465 {{"name", name},
2466 {"uri", "/bus/system/" + processName +
2467 objectPath + "/" +
2468 interfaceName + "/" + name},
2469 {"args", argsArray}});
2470 }
2471 methods = methods->NextSiblingElement("method");
2472 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002473 tinyxml2::XMLElement* signals =
Ed Tanous7c091622019-05-23 11:42:36 -07002474 interface->FirstChildElement("signal");
2475 while (signals != nullptr)
2476 {
2477 nlohmann::json argsArray = nlohmann::json::array();
2478
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002479 tinyxml2::XMLElement* arg =
Ed Tanous7c091622019-05-23 11:42:36 -07002480 signals->FirstChildElement("arg");
2481 while (arg != nullptr)
2482 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002483 const char* name = arg->Attribute("name");
2484 const char* type = arg->Attribute("type");
Ed Tanous7c091622019-05-23 11:42:36 -07002485 if (name != nullptr && type != nullptr)
2486 {
2487 argsArray.push_back({
2488 {"name", name},
2489 {"type", type},
2490 });
2491 }
2492 arg = arg->NextSiblingElement("arg");
2493 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002494 const char* name = signals->Attribute("name");
Ed Tanous7c091622019-05-23 11:42:36 -07002495 if (name != nullptr)
2496 {
2497 signalsArray.push_back(
2498 {{"name", name}, {"args", argsArray}});
2499 }
2500
2501 signals = signals->NextSiblingElement("signal");
2502 }
2503
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002504 tinyxml2::XMLElement* property =
Ed Tanous7c091622019-05-23 11:42:36 -07002505 interface->FirstChildElement("property");
2506 while (property != nullptr)
2507 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002508 const char* name = property->Attribute("name");
2509 const char* type = property->Attribute("type");
Ed Tanous7c091622019-05-23 11:42:36 -07002510 if (type != nullptr && name != nullptr)
2511 {
2512 sdbusplus::message::message m =
2513 crow::connections::systemBus
2514 ->new_method_call(processName.c_str(),
2515 objectPath.c_str(),
2516 "org.freedesktop."
2517 "DBus."
2518 "Properties",
2519 "Get");
2520 m.append(interfaceName, name);
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002521 nlohmann::json& propertyItem =
Ed Tanous7c091622019-05-23 11:42:36 -07002522 propertiesObj[name];
2523 crow::connections::systemBus->async_send(
2524 m, [&propertyItem, asyncResp](
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002525 boost::system::error_code& e,
2526 sdbusplus::message::message& msg) {
Ed Tanous271584a2019-07-09 16:24:22 -07002527 if (e)
Ed Tanous7c091622019-05-23 11:42:36 -07002528 {
2529 return;
2530 }
2531
Ed Tanous271584a2019-07-09 16:24:22 -07002532 convertDBusToJSON("v", msg,
2533 propertyItem);
Ed Tanous7c091622019-05-23 11:42:36 -07002534 });
2535 }
2536 property = property->NextSiblingElement("property");
2537 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002538 },
2539 processName, objectPath,
2540 "org.freedesktop.DBus.Introspectable", "Introspect");
2541 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002542 else
2543 {
Ed Tanousb41187f2019-10-24 16:30:02 -07002544 if (req.method() != boost::beast::http::verb::post)
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002545 {
2546 res.result(boost::beast::http::status::not_found);
2547 res.end();
2548 return;
2549 }
2550
2551 nlohmann::json requestDbusData =
2552 nlohmann::json::parse(req.body, nullptr, false);
2553
2554 if (requestDbusData.is_discarded())
2555 {
2556 res.result(boost::beast::http::status::bad_request);
2557 res.end();
2558 return;
2559 }
2560 if (!requestDbusData.is_array())
2561 {
2562 res.result(boost::beast::http::status::bad_request);
2563 res.end();
2564 return;
2565 }
2566 auto transaction = std::make_shared<InProgressActionData>(res);
2567
2568 transaction->path = objectPath;
2569 transaction->methodName = methodName;
2570 transaction->arguments = std::move(requestDbusData);
2571
2572 findActionOnInterface(transaction, processName);
2573 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002574 });
2575}
2576} // namespace openbmc_mapper
2577} // namespace crow