blob: 3188188befde81a56895069ccd9c57b43d128f9f [file] [log] [blame]
James Feist5b4aa862018-08-16 14:07:01 -07001// Copyright (c) 2018 Intel Corporation
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
Ed Tanousb9b2e0b2018-09-13 13:47:50 -070014
James Feist5b4aa862018-08-16 14:07:01 -070015#pragma once
Ed Tanous911ac312017-08-15 09:37:42 -070016#include <tinyxml2.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -070017
Ed Tanous04e438c2020-10-03 08:06:26 -070018#include <app.hpp>
Ed Tanouse3cb5a32018-08-08 14:16:49 -070019#include <async_resp.hpp>
Ed Tanous1abe55e2018-09-05 08:30:59 -070020#include <boost/algorithm/string.hpp>
21#include <boost/container/flat_set.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -070022#include <dbus_singleton.hpp>
James Feist5b4aa862018-08-16 14:07:01 -070023#include <dbus_utility.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050024#include <sdbusplus/message/types.hpp>
25
James Feist4418c7f2019-04-15 11:09:15 -070026#include <filesystem>
Ed Tanousd4bb9bb2018-05-16 13:36:42 -070027#include <fstream>
Ramesh Iyyard9207042019-07-05 08:04:42 -050028#include <regex>
Ed Tanousb5a76932020-09-29 16:16:58 -070029#include <utility>
Ed Tanous911ac312017-08-15 09:37:42 -070030
Ed Tanous1abe55e2018-09-05 08:30:59 -070031namespace crow
32{
33namespace openbmc_mapper
34{
Ed Tanousba9f9a62017-10-11 16:40:35 -070035
Matt Spinler3ae4ba72018-12-05 14:01:22 -060036using GetSubTreeType = std::vector<
37 std::pair<std::string,
38 std::vector<std::pair<std::string, std::vector<std::string>>>>>;
39
Ed Tanous23a21a12020-07-25 04:45:05 +000040const constexpr char* notFoundMsg = "404 Not Found";
41const constexpr char* badReqMsg = "400 Bad Request";
42const constexpr char* methodNotAllowedMsg = "405 Method Not Allowed";
43const constexpr char* forbiddenMsg = "403 Forbidden";
44const constexpr char* methodFailedMsg = "500 Method Call Failed";
45const constexpr char* methodOutputFailedMsg = "500 Method Output Error";
46const constexpr char* notFoundDesc =
Matt Spinler2ae60092018-12-06 10:35:36 -060047 "org.freedesktop.DBus.Error.FileNotFound: path or object not found";
Ed Tanous23a21a12020-07-25 04:45:05 +000048const constexpr char* propNotFoundDesc =
49 "The specified property cannot be found";
50const constexpr char* noJsonDesc = "No JSON object could be decoded";
51const constexpr char* methodNotFoundDesc =
52 "The specified method cannot be found";
53const constexpr char* methodNotAllowedDesc = "Method not allowed";
54const constexpr char* forbiddenPropDesc =
55 "The specified property cannot be created";
56const constexpr char* forbiddenResDesc =
57 "The specified resource cannot be created";
Matt Spinler2ae60092018-12-06 10:35:36 -060058
Ed Tanous23a21a12020-07-25 04:45:05 +000059inline void setErrorResponse(crow::Response& res,
60 boost::beast::http::status result,
61 const std::string& desc,
62 const std::string_view msg)
Matt Spinler2ae60092018-12-06 10:35:36 -060063{
64 res.result(result);
65 res.jsonValue = {{"data", {{"description", desc}}},
66 {"message", msg},
67 {"status", "error"}};
68}
69
Ed Tanousb5a76932020-09-29 16:16:58 -070070inline void
71 introspectObjects(const std::string& processName,
72 const std::string& objectPath,
73 const std::shared_ptr<bmcweb::AsyncResp>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -070074{
Ed Tanouse3cb5a32018-08-08 14:16:49 -070075 if (transaction->res.jsonValue.is_null())
76 {
77 transaction->res.jsonValue = {{"status", "ok"},
78 {"bus_name", processName},
79 {"objects", nlohmann::json::array()}};
80 }
81
Ed Tanous1abe55e2018-09-05 08:30:59 -070082 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -070083 [transaction, processName{std::string(processName)},
84 objectPath{std::string(objectPath)}](
85 const boost::system::error_code ec,
Ed Tanous81ce6092020-12-17 16:54:55 +000086 const std::string& introspectXml) {
Ed Tanous1abe55e2018-09-05 08:30:59 -070087 if (ec)
88 {
89 BMCWEB_LOG_ERROR
90 << "Introspect call failed with error: " << ec.message()
91 << " on process: " << processName << " path: " << objectPath
92 << "\n";
Ed Tanouse3cb5a32018-08-08 14:16:49 -070093 return;
94 }
95 transaction->res.jsonValue["objects"].push_back(
96 {{"path", objectPath}});
97
98 tinyxml2::XMLDocument doc;
99
Ed Tanous81ce6092020-12-17 16:54:55 +0000100 doc.Parse(introspectXml.c_str());
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500101 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700102 if (pRoot == nullptr)
103 {
104 BMCWEB_LOG_ERROR << "XML document failed to parse "
105 << processName << " " << objectPath << "\n";
Ed Tanous911ac312017-08-15 09:37:42 -0700106 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700107 else
108 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500109 tinyxml2::XMLElement* node = pRoot->FirstChildElement("node");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700110 while (node != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700111 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500112 const char* childPath = node->Attribute("name");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700113 if (childPath != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700114 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700115 std::string newpath;
116 if (objectPath != "/")
117 {
118 newpath += objectPath;
119 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700120 newpath += std::string("/") + childPath;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700121 // introspect the subobjects as well
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700122 introspectObjects(processName, newpath, transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700124
125 node = node->NextSiblingElement("node");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700126 }
127 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700128 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700129 processName, objectPath, "org.freedesktop.DBus.Introspectable",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700130 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -0700131}
Ed Tanous64530012018-02-06 17:08:16 -0800132
Ed Tanous23a21a12020-07-25 04:45:05 +0000133inline void getPropertiesForEnumerate(
134 const std::string& objectPath, const std::string& service,
Ed Tanousb5a76932020-09-29 16:16:58 -0700135 const std::string& interface,
136 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600137{
138 BMCWEB_LOG_DEBUG << "getPropertiesForEnumerate " << objectPath << " "
139 << service << " " << interface;
140
141 crow::connections::systemBus->async_method_call(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500142 [asyncResp, objectPath, service, interface](
143 const boost::system::error_code ec,
144 const std::vector<std::pair<
145 std::string, dbus::utility::DbusVariantType>>& propertiesList) {
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600146 if (ec)
147 {
148 BMCWEB_LOG_ERROR << "GetAll on path " << objectPath << " iface "
149 << interface << " service " << service
150 << " failed with code " << ec;
151 return;
152 }
153
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500154 nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
155 nlohmann::json& objectJson = dataJson[objectPath];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600156 if (objectJson.is_null())
157 {
158 objectJson = nlohmann::json::object();
159 }
160
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500161 for (const auto& [name, value] : propertiesList)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600162 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500163 nlohmann::json& propertyJson = objectJson[name];
164 std::visit([&propertyJson](auto&& val) { propertyJson = val; },
Ed Tanousabf2add2019-01-22 16:40:12 -0800165 value);
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600166 }
167 },
168 service, objectPath, "org.freedesktop.DBus.Properties", "GetAll",
169 interface);
170}
171
172// Find any results that weren't picked up by ObjectManagers, to be
173// called after all ObjectManagers are searched for and called.
Ed Tanous23a21a12020-07-25 04:45:05 +0000174inline void findRemainingObjectsForEnumerate(
Ed Tanousb5a76932020-09-29 16:16:58 -0700175 const std::string& objectPath,
176 const std::shared_ptr<GetSubTreeType>& subtree,
177 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600178{
179 BMCWEB_LOG_DEBUG << "findRemainingObjectsForEnumerate";
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500180 const nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600181
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500182 for (const auto& [path, interface_map] : *subtree)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600183 {
184 if (path == objectPath)
185 {
186 // An enumerate does not return the target path's properties
187 continue;
188 }
189 if (dataJson.find(path) == dataJson.end())
190 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500191 for (const auto& [service, interfaces] : interface_map)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600192 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500193 for (const auto& interface : interfaces)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600194 {
195 if (!boost::starts_with(interface, "org.freedesktop.DBus"))
196 {
197 getPropertiesForEnumerate(path, service, interface,
198 asyncResp);
199 }
200 }
201 }
202 }
203 }
204}
205
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600206struct InProgressEnumerateData
207{
zhanghch058d1b46d2021-04-01 11:18:24 +0800208 InProgressEnumerateData(
209 const std::string& objectPathIn,
210 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
Ed Tanous23a21a12020-07-25 04:45:05 +0000211 objectPath(objectPathIn),
zhanghch058d1b46d2021-04-01 11:18:24 +0800212 asyncResp(asyncRespIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500213 {}
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600214
215 ~InProgressEnumerateData()
216 {
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600217 findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600218 }
219
220 const std::string objectPath;
221 std::shared_ptr<GetSubTreeType> subtree;
222 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
223};
224
Ed Tanous23a21a12020-07-25 04:45:05 +0000225inline void getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000226 const std::string& objectName, const std::string& objectManagerPath,
227 const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700228 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700229{
Ed Tanous81ce6092020-12-17 16:54:55 +0000230 BMCWEB_LOG_DEBUG << "getManagedObjectsForEnumerate " << objectName
231 << " object_manager_path " << objectManagerPath
232 << " connection_name " << connectionName;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700233 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000234 [transaction, objectName,
235 connectionName](const boost::system::error_code ec,
236 const dbus::utility::ManagedObjectType& objects) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700237 if (ec)
238 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000239 BMCWEB_LOG_ERROR << "GetManagedObjects on path " << objectName
240 << " on connection " << connectionName
Ed Tanous049a0512018-11-01 13:58:42 -0700241 << " failed with code " << ec;
242 return;
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700243 }
Ed Tanous64530012018-02-06 17:08:16 -0800244
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500245 nlohmann::json& dataJson =
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600246 transaction->asyncResp->res.jsonValue["data"];
Ed Tanous049a0512018-11-01 13:58:42 -0700247
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500248 for (const auto& objectPath : objects)
Ed Tanous049a0512018-11-01 13:58:42 -0700249 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000250 if (boost::starts_with(objectPath.first.str, objectName))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700251 {
Ed Tanous049a0512018-11-01 13:58:42 -0700252 BMCWEB_LOG_DEBUG << "Reading object "
253 << objectPath.first.str;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500254 nlohmann::json& objectJson = dataJson[objectPath.first.str];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700255 if (objectJson.is_null())
256 {
257 objectJson = nlohmann::json::object();
258 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500259 for (const auto& interface : objectPath.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700260 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500261 for (const auto& property : interface.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700262 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500263 nlohmann::json& propertyJson =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700264 objectJson[property.first];
Ed Tanousabf2add2019-01-22 16:40:12 -0800265 std::visit([&propertyJson](
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500266 auto&& val) { propertyJson = val; },
Ed Tanousabf2add2019-01-22 16:40:12 -0800267 property.second);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700268 }
269 }
270 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500271 for (const auto& interface : objectPath.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700272 {
273 if (interface.first == "org.freedesktop.DBus.ObjectManager")
274 {
275 getManagedObjectsForEnumerate(
276 objectPath.first.str, objectPath.first.str,
Ed Tanous81ce6092020-12-17 16:54:55 +0000277 connectionName, transaction);
Ed Tanous049a0512018-11-01 13:58:42 -0700278 }
279 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700280 }
281 },
Ed Tanous81ce6092020-12-17 16:54:55 +0000282 connectionName, objectManagerPath, "org.freedesktop.DBus.ObjectManager",
283 "GetManagedObjects");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700284}
285
Ed Tanous23a21a12020-07-25 04:45:05 +0000286inline void findObjectManagerPathForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000287 const std::string& objectName, const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700288 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700289{
Ed Tanous81ce6092020-12-17 16:54:55 +0000290 BMCWEB_LOG_DEBUG << "Finding objectmanager for path " << objectName
291 << " on connection:" << connectionName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700292 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000293 [transaction, objectName, connectionName](
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700294 const boost::system::error_code ec,
295 const boost::container::flat_map<
296 std::string, boost::container::flat_map<
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500297 std::string, std::vector<std::string>>>&
298 objects) {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700299 if (ec)
300 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000301 BMCWEB_LOG_ERROR << "GetAncestors on path " << objectName
Ed Tanous049a0512018-11-01 13:58:42 -0700302 << " failed with code " << ec;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700303 return;
304 }
305
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500306 for (const auto& pathGroup : objects)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700307 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500308 for (const auto& connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700309 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000310 if (connectionGroup.first == connectionName)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700311 {
312 // Found the object manager path for this resource.
313 getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000314 objectName, pathGroup.first, connectionName,
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600315 transaction);
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700316 return;
317 }
318 }
319 }
320 },
321 "xyz.openbmc_project.ObjectMapper",
322 "/xyz/openbmc_project/object_mapper",
Ed Tanous81ce6092020-12-17 16:54:55 +0000323 "xyz.openbmc_project.ObjectMapper", "GetAncestors", objectName,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500324 std::array<const char*, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700325}
Ed Tanous64530012018-02-06 17:08:16 -0800326
Ed Tanous7c091622019-05-23 11:42:36 -0700327// Uses GetObject to add the object info about the target /enumerate path to
328// the results of GetSubTree, as GetSubTree will not return info for the
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600329// target path, and then continues on enumerating the rest of the tree.
Ed Tanousb5a76932020-09-29 16:16:58 -0700330inline void getObjectAndEnumerate(
331 const std::shared_ptr<InProgressEnumerateData>& transaction)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600332{
333 using GetObjectType =
334 std::vector<std::pair<std::string, std::vector<std::string>>>;
335
336 crow::connections::systemBus->async_method_call(
337 [transaction](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500338 const GetObjectType& objects) {
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600339 if (ec)
340 {
341 BMCWEB_LOG_ERROR << "GetObject for path "
342 << transaction->objectPath
343 << " failed with code " << ec;
344 return;
345 }
346
347 BMCWEB_LOG_DEBUG << "GetObject for " << transaction->objectPath
348 << " has " << objects.size() << " entries";
349 if (!objects.empty())
350 {
351 transaction->subtree->emplace_back(transaction->objectPath,
352 objects);
353 }
354
355 // Map indicating connection name, and the path where the object
356 // manager exists
357 boost::container::flat_map<std::string, std::string> connections;
358
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500359 for (const auto& object : *(transaction->subtree))
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600360 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500361 for (const auto& connection : object.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600362 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500363 std::string& objectManagerPath =
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600364 connections[connection.first];
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500365 for (const auto& interface : connection.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600366 {
367 BMCWEB_LOG_DEBUG << connection.first
368 << " has interface " << interface;
369 if (interface == "org.freedesktop.DBus.ObjectManager")
370 {
371 BMCWEB_LOG_DEBUG << "found object manager path "
372 << object.first;
373 objectManagerPath = object.first;
374 }
375 }
376 }
377 }
378 BMCWEB_LOG_DEBUG << "Got " << connections.size() << " connections";
379
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500380 for (const auto& connection : connections)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600381 {
Ed Tanous7c091622019-05-23 11:42:36 -0700382 // If we already know where the object manager is, we don't
383 // need to search for it, we can call directly in to
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600384 // getManagedObjects
385 if (!connection.second.empty())
386 {
387 getManagedObjectsForEnumerate(
388 transaction->objectPath, connection.second,
389 connection.first, transaction);
390 }
391 else
392 {
Ed Tanous7c091622019-05-23 11:42:36 -0700393 // otherwise we need to find the object manager path
394 // before we can continue
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600395 findObjectManagerPathForEnumerate(
396 transaction->objectPath, connection.first, transaction);
397 }
398 }
399 },
400 "xyz.openbmc_project.ObjectMapper",
401 "/xyz/openbmc_project/object_mapper",
402 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500403 transaction->objectPath, std::array<const char*, 0>());
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600404}
Ed Tanous64530012018-02-06 17:08:16 -0800405
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700406// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700407struct InProgressActionData
408{
Ed Tanous23a21a12020-07-25 04:45:05 +0000409 InProgressActionData(crow::Response& resIn) : res(resIn)
410 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700411 ~InProgressActionData()
412 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600413 // Methods could have been called across different owners
414 // and interfaces, where some calls failed and some passed.
415 //
416 // The rules for this are:
417 // * if no method was called - error
418 // * if a method failed and none passed - error
419 // (converse: if at least one method passed - OK)
420 // * for the method output:
421 // * if output processing didn't fail, return the data
422
423 // Only deal with method returns if nothing failed earlier
424 if (res.result() == boost::beast::http::status::ok)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700425 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600426 if (!methodPassed)
427 {
Matt Spinler06b1b632019-06-18 16:09:25 -0500428 if (!methodFailed)
Matt Spinler16caaee2019-01-15 11:40:34 -0600429 {
430 setErrorResponse(res, boost::beast::http::status::not_found,
431 methodNotFoundDesc, notFoundMsg);
432 }
433 }
434 else
435 {
436 if (outputFailed)
437 {
438 setErrorResponse(
439 res, boost::beast::http::status::internal_server_error,
440 "Method output failure", methodOutputFailedMsg);
441 }
442 else
443 {
444 res.jsonValue = {{"status", "ok"},
445 {"message", "200 OK"},
446 {"data", methodResponse}};
447 }
448 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700449 }
Matt Spinler16caaee2019-01-15 11:40:34 -0600450
Ed Tanous1abe55e2018-09-05 08:30:59 -0700451 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700452 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700453
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500454 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700455 {
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600456 setErrorResponse(res, boost::beast::http::status::bad_request, desc,
457 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700458 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500459 crow::Response& res;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700460 std::string path;
461 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600462 std::string interfaceName;
Matt Spinler16caaee2019-01-15 11:40:34 -0600463 bool methodPassed = false;
464 bool methodFailed = false;
465 bool outputFailed = false;
Matt Spinler39a4e392019-01-15 11:53:13 -0600466 bool convertedToArray = false;
Matt Spinler16caaee2019-01-15 11:40:34 -0600467 nlohmann::json methodResponse;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700468 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700469};
470
Ed Tanous23a21a12020-07-25 04:45:05 +0000471inline std::vector<std::string> dbusArgSplit(const std::string& string)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700472{
473 std::vector<std::string> ret;
474 if (string.empty())
475 {
476 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700477 }
Ed Tanous0f0353b2019-10-24 11:37:51 -0700478 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700479 int containerDepth = 0;
480
481 for (std::string::const_iterator character = string.begin();
482 character != string.end(); character++)
483 {
484 ret.back() += *character;
485 switch (*character)
486 {
487 case ('a'):
488 break;
489 case ('('):
490 case ('{'):
491 containerDepth++;
492 break;
493 case ('}'):
494 case (')'):
495 containerDepth--;
496 if (containerDepth == 0)
497 {
498 if (character + 1 != string.end())
499 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700500 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700501 }
502 }
503 break;
504 default:
505 if (containerDepth == 0)
506 {
507 if (character + 1 != string.end())
508 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700509 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700510 }
511 }
512 break;
513 }
514 }
Matt Spinler4ae611d2019-01-11 15:37:06 -0600515
516 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700517}
518
Ed Tanous81ce6092020-12-17 16:54:55 +0000519inline int convertJsonToDbus(sd_bus_message* m, const std::string& argType,
520 const nlohmann::json& inputJson)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700521{
522 int r = 0;
Ed Tanous71f52d92021-02-19 08:51:17 -0800523 BMCWEB_LOG_DEBUG << "Converting "
524 << inputJson.dump(2, ' ', true,
525 nlohmann::json::error_handler_t::replace)
Ed Tanous81ce6092020-12-17 16:54:55 +0000526 << " to type: " << argType;
527 const std::vector<std::string> argTypes = dbusArgSplit(argType);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700528
Ed Tanous1abe55e2018-09-05 08:30:59 -0700529 // Assume a single object for now.
Ed Tanous81ce6092020-12-17 16:54:55 +0000530 const nlohmann::json* j = &inputJson;
531 nlohmann::json::const_iterator jIt = inputJson.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700532
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500533 for (const std::string& argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700534 {
535 // If we are decoding multiple objects, grab the pointer to the
536 // iterator, and increment it for the next loop
537 if (argTypes.size() > 1)
538 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000539 if (jIt == inputJson.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700540 {
541 return -2;
542 }
543 j = &*jIt;
544 jIt++;
545 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500546 const int64_t* intValue = j->get_ptr<const int64_t*>();
547 const std::string* stringValue = j->get_ptr<const std::string*>();
548 const double* doubleValue = j->get_ptr<const double*>();
549 const bool* b = j->get_ptr<const bool*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700550 int64_t v = 0;
551 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700552
Ed Tanous1abe55e2018-09-05 08:30:59 -0700553 // Do some basic type conversions that make sense. uint can be
554 // converted to int. int and uint can be converted to double
Ed Tanous66664f22019-10-11 13:05:49 -0700555 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700556 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500557 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700558 if (uintValue != nullptr)
559 {
560 v = static_cast<int64_t>(*uintValue);
561 intValue = &v;
562 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700563 }
Ed Tanous66664f22019-10-11 13:05:49 -0700564 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700565 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500566 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700567 if (uintValue != nullptr)
568 {
569 d = static_cast<double>(*uintValue);
570 doubleValue = &d;
571 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700572 }
Ed Tanous66664f22019-10-11 13:05:49 -0700573 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700574 {
Ed Tanous66664f22019-10-11 13:05:49 -0700575 if (intValue != nullptr)
576 {
577 d = static_cast<double>(*intValue);
578 doubleValue = &d;
579 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700580 }
581
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700582 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700583 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700584 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700585 {
586 return -1;
587 }
Ed Tanous271584a2019-07-09 16:24:22 -0700588 r = sd_bus_message_append_basic(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500589 m, argCode[0], static_cast<const void*>(stringValue->data()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700590 if (r < 0)
591 {
592 return r;
593 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700594 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700595 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700596 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700597 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700598 {
599 return -1;
600 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500601 if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
602 (*intValue > std::numeric_limits<int32_t>::max()))
603 {
604 return -ERANGE;
605 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700606 int32_t i = static_cast<int32_t>(*intValue);
607 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700608 if (r < 0)
609 {
610 return r;
611 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700612 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700613 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700614 {
615 // lots of ways bool could be represented here. Try them all
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700616 int boolInt = false;
617 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700618 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500619 if (*intValue == 1)
620 {
621 boolInt = true;
622 }
623 else if (*intValue == 0)
624 {
625 boolInt = false;
626 }
627 else
628 {
629 return -ERANGE;
630 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700631 }
632 else if (b != nullptr)
633 {
Matt Spinlera2f02632019-01-18 10:15:35 -0600634 boolInt = *b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700635 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700636 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700637 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700638 boolInt = boost::istarts_with(*stringValue, "t") ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700639 }
640 else
641 {
642 return -1;
643 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700644 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700645 if (r < 0)
646 {
647 return r;
648 }
649 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700650 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700651 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700652 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700653 {
654 return -1;
655 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500656 if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
657 (*intValue > std::numeric_limits<int16_t>::max()))
658 {
659 return -ERANGE;
660 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700661 int16_t n = static_cast<int16_t>(*intValue);
662 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700663 if (r < 0)
664 {
665 return r;
666 }
667 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700668 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700669 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700670 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700671 {
672 return -1;
673 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700674 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700675 if (r < 0)
676 {
677 return r;
678 }
679 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700680 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700681 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500682 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700683 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700684 {
685 return -1;
686 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000687 if (*uintValue > std::numeric_limits<uint8_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500688 {
689 return -ERANGE;
690 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700691 uint8_t y = static_cast<uint8_t>(*uintValue);
692 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700693 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700694 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700695 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500696 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700697 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700698 {
699 return -1;
700 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000701 if (*uintValue > std::numeric_limits<uint16_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500702 {
703 return -ERANGE;
704 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700705 uint16_t q = static_cast<uint16_t>(*uintValue);
706 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700707 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700708 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700709 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500710 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700711 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700712 {
713 return -1;
714 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000715 if (*uintValue > std::numeric_limits<uint32_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500716 {
717 return -ERANGE;
718 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700719 uint32_t u = static_cast<uint32_t>(*uintValue);
720 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700721 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700722 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700723 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500724 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700725 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700726 {
727 return -1;
728 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700729 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700730 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700731 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700732 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500733 if (doubleValue == nullptr)
734 {
735 return -1;
736 }
737 if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
738 (*doubleValue > std::numeric_limits<double>::max()))
739 {
740 return -ERANGE;
741 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700742 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700743 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700744 else if (boost::starts_with(argCode, "a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700745 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700746 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700747 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700748 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700749 if (r < 0)
750 {
751 return r;
752 }
753
Ed Tanous0dfeda62019-10-24 11:21:38 -0700754 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700755 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700756 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700757 if (r < 0)
758 {
759 return r;
760 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700761 }
762 sd_bus_message_close_container(m);
763 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700764 else if (boost::starts_with(argCode, "v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700765 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700766 std::string containedType = argCode.substr(1);
767 BMCWEB_LOG_DEBUG << "variant type: " << argCode
768 << " appending variant of type: " << containedType;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700769 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700770 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700771 if (r < 0)
772 {
773 return r;
774 }
775
Ed Tanous81ce6092020-12-17 16:54:55 +0000776 r = convertJsonToDbus(m, containedType, inputJson);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700777 if (r < 0)
778 {
779 return r;
780 }
781
782 r = sd_bus_message_close_container(m);
783 if (r < 0)
784 {
785 return r;
786 }
787 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700788 else if (boost::starts_with(argCode, "(") &&
789 boost::ends_with(argCode, ")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700790 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700791 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700792 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700793 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800794 if (r < 0)
795 {
796 return r;
797 }
798
Ed Tanous1abe55e2018-09-05 08:30:59 -0700799 nlohmann::json::const_iterator it = j->begin();
Ed Tanous81ce6092020-12-17 16:54:55 +0000800 for (const std::string& argCode2 : dbusArgSplit(argType))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700801 {
802 if (it == j->end())
803 {
804 return -1;
805 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000806 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700807 if (r < 0)
808 {
809 return r;
810 }
811 it++;
812 }
813 r = sd_bus_message_close_container(m);
814 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700815 else if (boost::starts_with(argCode, "{") &&
816 boost::ends_with(argCode, "}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700817 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700818 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700819 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700820 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800821 if (r < 0)
822 {
823 return r;
824 }
825
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700826 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700827 if (codes.size() != 2)
828 {
829 return -1;
830 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700831 const std::string& keyType = codes[0];
832 const std::string& valueType = codes[1];
Ed Tanous3174e4d2020-10-07 11:41:22 -0700833 for (const auto& it : j->items())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700834 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700835 r = convertJsonToDbus(m, keyType, it.key());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700836 if (r < 0)
837 {
838 return r;
839 }
840
Ed Tanous2c70f802020-09-28 14:29:23 -0700841 r = convertJsonToDbus(m, valueType, it.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700842 if (r < 0)
843 {
844 return r;
845 }
846 }
847 r = sd_bus_message_close_container(m);
848 }
849 else
850 {
851 return -2;
852 }
853 if (r < 0)
854 {
855 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700856 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700857
Ed Tanous1abe55e2018-09-05 08:30:59 -0700858 if (argTypes.size() > 1)
859 {
860 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700861 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700862 }
Matt Spinler127ea542019-01-14 11:04:28 -0600863
864 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700865}
866
Matt Spinlerd22a7132019-01-14 12:14:30 -0600867template <typename T>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500868int readMessageItem(const std::string& typeCode, sdbusplus::message::message& m,
869 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600870{
871 T value;
872
873 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
874 if (r < 0)
875 {
876 BMCWEB_LOG_ERROR << "sd_bus_message_read_basic on type " << typeCode
877 << " failed!";
878 return r;
879 }
880
881 data = value;
882 return 0;
883}
884
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500885int convertDBusToJSON(const std::string& returnType,
886 sdbusplus::message::message& m, nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600887
Ed Tanous23a21a12020-07-25 04:45:05 +0000888inline int readDictEntryFromMessage(const std::string& typeCode,
889 sdbusplus::message::message& m,
890 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600891{
892 std::vector<std::string> types = dbusArgSplit(typeCode);
893 if (types.size() != 2)
894 {
895 BMCWEB_LOG_ERROR << "wrong number contained types in dictionary: "
896 << types.size();
897 return -1;
898 }
899
900 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
901 typeCode.c_str());
902 if (r < 0)
903 {
904 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container with rc " << r;
905 return r;
906 }
907
908 nlohmann::json key;
909 r = convertDBusToJSON(types[0], m, key);
910 if (r < 0)
911 {
912 return r;
913 }
914
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500915 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -0600916 if (keyPtr == nullptr)
917 {
918 // json doesn't support non-string keys. If we hit this condition,
919 // convert the result to a string so we can proceed
Ed Tanous71f52d92021-02-19 08:51:17 -0800920 key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500921 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -0700922 // in theory this can't fail now, but lets be paranoid about it
923 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -0600924 if (keyPtr == nullptr)
925 {
926 return -1;
927 }
928 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500929 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -0600930
931 r = convertDBusToJSON(types[1], m, value);
932 if (r < 0)
933 {
934 return r;
935 }
936
937 r = sd_bus_message_exit_container(m.get());
938 if (r < 0)
939 {
940 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
941 return r;
942 }
943
944 return 0;
945}
946
Ed Tanous23a21a12020-07-25 04:45:05 +0000947inline int readArrayFromMessage(const std::string& typeCode,
948 sdbusplus::message::message& m,
949 nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -0600950{
951 if (typeCode.size() < 2)
952 {
953 BMCWEB_LOG_ERROR << "Type code " << typeCode
954 << " too small for an array";
955 return -1;
956 }
957
958 std::string containedType = typeCode.substr(1);
959
960 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
961 containedType.c_str());
962 if (r < 0)
963 {
964 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
965 << r;
966 return r;
967 }
968
969 bool dict = boost::starts_with(containedType, "{") &&
970 boost::ends_with(containedType, "}");
971
972 if (dict)
973 {
974 // Remove the { }
975 containedType = containedType.substr(1, containedType.size() - 2);
976 data = nlohmann::json::object();
977 }
978 else
979 {
980 data = nlohmann::json::array();
981 }
982
983 while (true)
984 {
985 r = sd_bus_message_at_end(m.get(), false);
986 if (r < 0)
987 {
988 BMCWEB_LOG_ERROR << "sd_bus_message_at_end failed";
989 return r;
990 }
991
992 if (r > 0)
993 {
994 break;
995 }
996
997 // Dictionaries are only ever seen in an array
998 if (dict)
999 {
1000 r = readDictEntryFromMessage(containedType, m, data);
1001 if (r < 0)
1002 {
1003 return r;
1004 }
1005 }
1006 else
1007 {
1008 data.push_back(nlohmann::json());
1009
1010 r = convertDBusToJSON(containedType, m, data.back());
1011 if (r < 0)
1012 {
1013 return r;
1014 }
1015 }
1016 }
1017
1018 r = sd_bus_message_exit_container(m.get());
1019 if (r < 0)
1020 {
1021 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1022 return r;
1023 }
1024
1025 return 0;
1026}
1027
Ed Tanous23a21a12020-07-25 04:45:05 +00001028inline int readStructFromMessage(const std::string& typeCode,
1029 sdbusplus::message::message& m,
1030 nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001031{
1032 if (typeCode.size() < 3)
1033 {
1034 BMCWEB_LOG_ERROR << "Type code " << typeCode
1035 << " too small for a struct";
1036 return -1;
1037 }
1038
1039 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1040 std::vector<std::string> types = dbusArgSplit(containedTypes);
1041
1042 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1043 containedTypes.c_str());
1044 if (r < 0)
1045 {
1046 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1047 << r;
1048 return r;
1049 }
1050
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001051 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001052 {
1053 data.push_back(nlohmann::json());
1054 r = convertDBusToJSON(type, m, data.back());
1055 if (r < 0)
1056 {
1057 return r;
1058 }
1059 }
1060
1061 r = sd_bus_message_exit_container(m.get());
1062 if (r < 0)
1063 {
1064 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1065 return r;
1066 }
1067 return 0;
1068}
1069
Ed Tanous23a21a12020-07-25 04:45:05 +00001070inline int readVariantFromMessage(sdbusplus::message::message& m,
1071 nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001072{
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001073 const char* containerType;
Ed Tanous99131cd2019-10-24 11:12:47 -07001074 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001075 if (r < 0)
1076 {
1077 BMCWEB_LOG_ERROR << "sd_bus_message_peek_type failed";
1078 return r;
1079 }
1080
1081 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1082 containerType);
1083 if (r < 0)
1084 {
1085 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1086 << r;
1087 return r;
1088 }
1089
1090 r = convertDBusToJSON(containerType, m, data);
1091 if (r < 0)
1092 {
1093 return r;
1094 }
1095
1096 r = sd_bus_message_exit_container(m.get());
1097 if (r < 0)
1098 {
1099 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed";
1100 return r;
1101 }
1102
1103 return 0;
1104}
1105
Ed Tanous23a21a12020-07-25 04:45:05 +00001106inline int convertDBusToJSON(const std::string& returnType,
1107 sdbusplus::message::message& m,
1108 nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001109{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001110 int r = 0;
1111 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1112
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001113 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001114 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001115 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001116 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001117 {
1118 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001119 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001120 }
1121
Ed Tanousd4d25792020-09-29 15:15:03 -07001122 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001123 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001124 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001125 if (r < 0)
1126 {
1127 return r;
1128 }
1129 }
1130 else if (typeCode == "b")
1131 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001132 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001133 if (r < 0)
1134 {
1135 return r;
1136 }
1137
Matt Spinlerf39420c2019-01-30 12:57:18 -06001138 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001139 }
1140 else if (typeCode == "u")
1141 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001142 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001143 if (r < 0)
1144 {
1145 return r;
1146 }
1147 }
1148 else if (typeCode == "i")
1149 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001150 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001151 if (r < 0)
1152 {
1153 return r;
1154 }
1155 }
1156 else if (typeCode == "x")
1157 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001158 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001159 if (r < 0)
1160 {
1161 return r;
1162 }
1163 }
1164 else if (typeCode == "t")
1165 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001166 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001167 if (r < 0)
1168 {
1169 return r;
1170 }
1171 }
1172 else if (typeCode == "n")
1173 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001174 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001175 if (r < 0)
1176 {
1177 return r;
1178 }
1179 }
1180 else if (typeCode == "q")
1181 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001182 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001183 if (r < 0)
1184 {
1185 return r;
1186 }
1187 }
1188 else if (typeCode == "y")
1189 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001190 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001191 if (r < 0)
1192 {
1193 return r;
1194 }
1195 }
1196 else if (typeCode == "d")
1197 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001198 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001199 if (r < 0)
1200 {
1201 return r;
1202 }
1203 }
1204 else if (typeCode == "h")
1205 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001206 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001207 if (r < 0)
1208 {
1209 return r;
1210 }
1211 }
Matt Spinler6df8f992019-01-14 12:47:47 -06001212 else if (boost::starts_with(typeCode, "a"))
1213 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001214 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001215 if (r < 0)
1216 {
1217 return r;
1218 }
1219 }
Matt Spinler75c6c672019-01-14 13:01:46 -06001220 else if (boost::starts_with(typeCode, "(") &&
1221 boost::ends_with(typeCode, ")"))
1222 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001223 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001224 if (r < 0)
1225 {
1226 return r;
1227 }
1228 }
Matt Spinler89c19702019-01-14 13:13:00 -06001229 else if (boost::starts_with(typeCode, "v"))
1230 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001231 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001232 if (r < 0)
1233 {
1234 return r;
1235 }
1236 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001237 else
1238 {
Matt Spinlerd22a7132019-01-14 12:14:30 -06001239 BMCWEB_LOG_ERROR << "Invalid D-Bus signature type " << typeCode;
1240 return -2;
1241 }
1242 }
1243
Matt Spinler16caaee2019-01-15 11:40:34 -06001244 return 0;
1245}
1246
Ed Tanousb5a76932020-09-29 16:16:58 -07001247inline void handleMethodResponse(
1248 const std::shared_ptr<InProgressActionData>& transaction,
1249 sdbusplus::message::message& m, const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001250{
Matt Spinler39a4e392019-01-15 11:53:13 -06001251 nlohmann::json data;
1252
1253 int r = convertDBusToJSON(returnType, m, data);
1254 if (r < 0)
1255 {
1256 transaction->outputFailed = true;
1257 return;
1258 }
1259
1260 if (data.is_null())
1261 {
1262 return;
1263 }
1264
1265 if (transaction->methodResponse.is_null())
1266 {
1267 transaction->methodResponse = std::move(data);
1268 return;
1269 }
1270
1271 // If they're both dictionaries or arrays, merge into one.
1272 // Otherwise, make the results an array with every result
1273 // an entry. Could also just fail in that case, but it
1274 // seems better to get the data back somehow.
1275
1276 if (transaction->methodResponse.is_object() && data.is_object())
1277 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001278 for (const auto& obj : data.items())
Matt Spinler39a4e392019-01-15 11:53:13 -06001279 {
1280 // Note: Will overwrite the data for a duplicate key
1281 transaction->methodResponse.emplace(obj.key(),
1282 std::move(obj.value()));
1283 }
1284 return;
1285 }
1286
1287 if (transaction->methodResponse.is_array() && data.is_array())
1288 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001289 for (auto& obj : data)
Matt Spinler39a4e392019-01-15 11:53:13 -06001290 {
1291 transaction->methodResponse.push_back(std::move(obj));
1292 }
1293 return;
1294 }
1295
1296 if (!transaction->convertedToArray)
1297 {
1298 // They are different types. May as well turn them into an array
1299 nlohmann::json j = std::move(transaction->methodResponse);
1300 transaction->methodResponse = nlohmann::json::array();
1301 transaction->methodResponse.push_back(std::move(j));
1302 transaction->methodResponse.push_back(std::move(data));
1303 transaction->convertedToArray = true;
1304 }
1305 else
1306 {
1307 transaction->methodResponse.push_back(std::move(data));
1308 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001309}
1310
Ed Tanousb5a76932020-09-29 16:16:58 -07001311inline void findActionOnInterface(
1312 const std::shared_ptr<InProgressActionData>& transaction,
1313 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001314{
1315 BMCWEB_LOG_DEBUG << "findActionOnInterface for connection "
1316 << connectionName;
1317 crow::connections::systemBus->async_method_call(
1318 [transaction, connectionName{std::string(connectionName)}](
1319 const boost::system::error_code ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001320 const std::string& introspectXml) {
1321 BMCWEB_LOG_DEBUG << "got xml:\n " << introspectXml;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001322 if (ec)
1323 {
1324 BMCWEB_LOG_ERROR
1325 << "Introspect call failed with error: " << ec.message()
1326 << " on process: " << connectionName << "\n";
Matt Spinler318bd892019-01-15 09:59:20 -06001327 return;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001328 }
Matt Spinler318bd892019-01-15 09:59:20 -06001329 tinyxml2::XMLDocument doc;
1330
Ed Tanous81ce6092020-12-17 16:54:55 +00001331 doc.Parse(introspectXml.data(), introspectXml.size());
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001332 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
Matt Spinler318bd892019-01-15 09:59:20 -06001333 if (pRoot == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001334 {
Matt Spinler318bd892019-01-15 09:59:20 -06001335 BMCWEB_LOG_ERROR << "XML document failed to parse "
1336 << connectionName << "\n";
1337 return;
1338 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001339 tinyxml2::XMLElement* interfaceNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001340 pRoot->FirstChildElement("interface");
1341 while (interfaceNode != nullptr)
1342 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001343 const char* thisInterfaceName =
Matt Spinler318bd892019-01-15 09:59:20 -06001344 interfaceNode->Attribute("name");
1345 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001346 {
Matt Spinler318bd892019-01-15 09:59:20 -06001347 if (!transaction->interfaceName.empty() &&
1348 (transaction->interfaceName != thisInterfaceName))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001349 {
Matt Spinler318bd892019-01-15 09:59:20 -06001350 interfaceNode =
1351 interfaceNode->NextSiblingElement("interface");
1352 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001353 }
Matt Spinler318bd892019-01-15 09:59:20 -06001354
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001355 tinyxml2::XMLElement* methodNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001356 interfaceNode->FirstChildElement("method");
1357 while (methodNode != nullptr)
1358 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001359 const char* thisMethodName =
Matt Spinler318bd892019-01-15 09:59:20 -06001360 methodNode->Attribute("name");
1361 BMCWEB_LOG_DEBUG << "Found method: " << thisMethodName;
1362 if (thisMethodName != nullptr &&
1363 thisMethodName == transaction->methodName)
1364 {
1365 BMCWEB_LOG_DEBUG
1366 << "Found method named " << thisMethodName
1367 << " on interface " << thisInterfaceName;
1368 sdbusplus::message::message m =
1369 crow::connections::systemBus->new_method_call(
1370 connectionName.c_str(),
1371 transaction->path.c_str(),
1372 thisInterfaceName,
1373 transaction->methodName.c_str());
1374
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001375 tinyxml2::XMLElement* argumentNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001376 methodNode->FirstChildElement("arg");
1377
Matt Spinler16caaee2019-01-15 11:40:34 -06001378 std::string returnType;
1379
1380 // Find the output type
1381 while (argumentNode != nullptr)
1382 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001383 const char* argDirection =
Matt Spinler16caaee2019-01-15 11:40:34 -06001384 argumentNode->Attribute("direction");
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001385 const char* argType =
Matt Spinler16caaee2019-01-15 11:40:34 -06001386 argumentNode->Attribute("type");
1387 if (argDirection != nullptr &&
1388 argType != nullptr &&
1389 std::string(argDirection) == "out")
1390 {
1391 returnType = argType;
1392 break;
1393 }
1394 argumentNode =
1395 argumentNode->NextSiblingElement("arg");
1396 }
1397
Matt Spinler318bd892019-01-15 09:59:20 -06001398 nlohmann::json::const_iterator argIt =
1399 transaction->arguments.begin();
1400
Matt Spinler16caaee2019-01-15 11:40:34 -06001401 argumentNode = methodNode->FirstChildElement("arg");
1402
Matt Spinler318bd892019-01-15 09:59:20 -06001403 while (argumentNode != nullptr)
1404 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001405 const char* argDirection =
Matt Spinler318bd892019-01-15 09:59:20 -06001406 argumentNode->Attribute("direction");
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001407 const char* argType =
Matt Spinler318bd892019-01-15 09:59:20 -06001408 argumentNode->Attribute("type");
1409 if (argDirection != nullptr &&
1410 argType != nullptr &&
1411 std::string(argDirection) == "in")
1412 {
1413 if (argIt == transaction->arguments.end())
1414 {
1415 transaction->setErrorStatus(
1416 "Invalid method args");
1417 return;
1418 }
1419 if (convertJsonToDbus(m.get(),
1420 std::string(argType),
1421 *argIt) < 0)
1422 {
1423 transaction->setErrorStatus(
1424 "Invalid method arg type");
1425 return;
1426 }
1427
1428 argIt++;
1429 }
1430 argumentNode =
1431 argumentNode->NextSiblingElement("arg");
1432 }
1433
1434 crow::connections::systemBus->async_send(
Matt Spinler16caaee2019-01-15 11:40:34 -06001435 m, [transaction, returnType](
Ed Tanous23a21a12020-07-25 04:45:05 +00001436 boost::system::error_code ec2,
1437 sdbusplus::message::message& m2) {
1438 if (ec2)
Matt Spinler318bd892019-01-15 09:59:20 -06001439 {
Matt Spinler16caaee2019-01-15 11:40:34 -06001440 transaction->methodFailed = true;
Ed Tanous23a21a12020-07-25 04:45:05 +00001441 const sd_bus_error* e = m2.get_error();
Matt Spinler06b1b632019-06-18 16:09:25 -05001442
1443 if (e)
1444 {
1445 setErrorResponse(
1446 transaction->res,
1447 boost::beast::http::status::
1448 bad_request,
1449 e->name, e->message);
1450 }
1451 else
1452 {
1453 setErrorResponse(
1454 transaction->res,
1455 boost::beast::http::status::
1456 bad_request,
1457 "Method call failed",
1458 methodFailedMsg);
1459 }
Matt Spinler318bd892019-01-15 09:59:20 -06001460 return;
1461 }
Ed Tanous3174e4d2020-10-07 11:41:22 -07001462 transaction->methodPassed = true;
Matt Spinler16caaee2019-01-15 11:40:34 -06001463
Ed Tanous23a21a12020-07-25 04:45:05 +00001464 handleMethodResponse(transaction, m2,
Matt Spinler16caaee2019-01-15 11:40:34 -06001465 returnType);
Matt Spinler318bd892019-01-15 09:59:20 -06001466 });
1467 break;
1468 }
1469 methodNode = methodNode->NextSiblingElement("method");
1470 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001471 }
Matt Spinler318bd892019-01-15 09:59:20 -06001472 interfaceNode = interfaceNode->NextSiblingElement("interface");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001473 }
1474 },
1475 connectionName, transaction->path,
1476 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001477}
1478
zhanghch058d1b46d2021-04-01 11:18:24 +08001479inline void handleAction(const crow::Request& req,
1480 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001481 const std::string& objectPath,
1482 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001483{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001484 BMCWEB_LOG_DEBUG << "handleAction on path: " << objectPath << " and method "
1485 << methodName;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001486 nlohmann::json requestDbusData =
1487 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001488
Ed Tanous1abe55e2018-09-05 08:30:59 -07001489 if (requestDbusData.is_discarded())
1490 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001491 setErrorResponse(asyncResp->res,
1492 boost::beast::http::status::bad_request, noJsonDesc,
1493 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001494 return;
1495 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001496 nlohmann::json::iterator data = requestDbusData.find("data");
1497 if (data == requestDbusData.end())
1498 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001499 setErrorResponse(asyncResp->res,
1500 boost::beast::http::status::bad_request, noJsonDesc,
1501 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001502 return;
1503 }
1504
1505 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001506 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001507 setErrorResponse(asyncResp->res,
1508 boost::beast::http::status::bad_request, noJsonDesc,
1509 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001510 return;
1511 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001512 auto transaction = std::make_shared<InProgressActionData>(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001513
1514 transaction->path = objectPath;
1515 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001516 transaction->arguments = std::move(*data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001517 crow::connections::systemBus->async_method_call(
1518 [transaction](
1519 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001520 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1521 interfaceNames) {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001522 if (ec || interfaceNames.size() <= 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001523 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001524 BMCWEB_LOG_ERROR << "Can't find object";
Matt Spinler6db06242018-12-11 11:21:22 -06001525 setErrorResponse(transaction->res,
1526 boost::beast::http::status::not_found,
1527 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001528 return;
1529 }
1530
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001531 BMCWEB_LOG_DEBUG << "GetObject returned " << interfaceNames.size()
1532 << " object(s)";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001533
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001534 for (const std::pair<std::string, std::vector<std::string>>&
1535 object : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001536 {
1537 findActionOnInterface(transaction, object.first);
1538 }
1539 },
1540 "xyz.openbmc_project.ObjectMapper",
1541 "/xyz/openbmc_project/object_mapper",
1542 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
1543 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001544}
1545
zhanghch058d1b46d2021-04-01 11:18:24 +08001546inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1547 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001548{
1549 BMCWEB_LOG_DEBUG << "handleDelete on path: " << objectPath;
1550
1551 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +08001552 [asyncResp, objectPath](
Matt Spinlerde818812018-12-11 16:39:20 -06001553 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001554 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1555 interfaceNames) {
Matt Spinlerde818812018-12-11 16:39:20 -06001556 if (ec || interfaceNames.size() <= 0)
1557 {
1558 BMCWEB_LOG_ERROR << "Can't find object";
zhanghch058d1b46d2021-04-01 11:18:24 +08001559 setErrorResponse(asyncResp->res,
Matt Spinler62d2e8b2019-01-22 13:45:51 -06001560 boost::beast::http::status::method_not_allowed,
1561 methodNotAllowedDesc, methodNotAllowedMsg);
Matt Spinlerde818812018-12-11 16:39:20 -06001562 return;
1563 }
1564
zhanghch058d1b46d2021-04-01 11:18:24 +08001565 auto transaction =
1566 std::make_shared<InProgressActionData>(asyncResp->res);
Matt Spinlerde818812018-12-11 16:39:20 -06001567 transaction->path = objectPath;
1568 transaction->methodName = "Delete";
1569 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
1570
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001571 for (const std::pair<std::string, std::vector<std::string>>&
1572 object : interfaceNames)
Matt Spinlerde818812018-12-11 16:39:20 -06001573 {
1574 findActionOnInterface(transaction, object.first);
1575 }
1576 },
1577 "xyz.openbmc_project.ObjectMapper",
1578 "/xyz/openbmc_project/object_mapper",
1579 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001580 std::array<const char*, 0>());
Matt Spinlerde818812018-12-11 16:39:20 -06001581}
1582
zhanghch058d1b46d2021-04-01 11:18:24 +08001583inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1584 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001585{
1586 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +08001587 [asyncResp](const boost::system::error_code ec,
1588 std::vector<std::string>& objectPaths) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001589 if (ec)
1590 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001591 setErrorResponse(asyncResp->res,
1592 boost::beast::http::status::not_found,
Matt Spinlerd6091dd2018-12-06 14:08:27 -06001593 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001594 }
1595 else
1596 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001597 asyncResp->res.jsonValue = {{"status", "ok"},
1598 {"message", "200 OK"},
1599 {"data", std::move(objectPaths)}};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001600 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001601 },
1602 "xyz.openbmc_project.ObjectMapper",
1603 "/xyz/openbmc_project/object_mapper",
1604 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", objectPath,
Ed Tanousf839dfe2018-11-12 11:11:15 -08001605 depth, std::array<std::string, 0>());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001606}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001607
zhanghch058d1b46d2021-04-01 11:18:24 +08001608inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1609 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001610{
Ed Tanous049a0512018-11-01 13:58:42 -07001611 BMCWEB_LOG_DEBUG << "Doing enumerate on " << objectPath;
Ed Tanous049a0512018-11-01 13:58:42 -07001612
1613 asyncResp->res.jsonValue = {{"message", "200 OK"},
1614 {"status", "ok"},
1615 {"data", nlohmann::json::object()}};
1616
Ed Tanous1abe55e2018-09-05 08:30:59 -07001617 crow::connections::systemBus->async_method_call(
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001618 [objectPath, asyncResp](const boost::system::error_code ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001619 GetSubTreeType& objectNames) {
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001620 auto transaction = std::make_shared<InProgressEnumerateData>(
1621 objectPath, asyncResp);
1622
1623 transaction->subtree =
Ed Tanous81ce6092020-12-17 16:54:55 +00001624 std::make_shared<GetSubTreeType>(std::move(objectNames));
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001625
Ed Tanous1abe55e2018-09-05 08:30:59 -07001626 if (ec)
1627 {
Matt Spinler2ae60092018-12-06 10:35:36 -06001628 BMCWEB_LOG_ERROR << "GetSubTree failed on "
1629 << transaction->objectPath;
1630 setErrorResponse(transaction->asyncResp->res,
1631 boost::beast::http::status::not_found,
1632 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001633 return;
1634 }
Ed Tanous64530012018-02-06 17:08:16 -08001635
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001636 // Add the data for the path passed in to the results
1637 // as if GetSubTree returned it, and continue on enumerating
1638 getObjectAndEnumerate(transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001639 },
1640 "xyz.openbmc_project.ObjectMapper",
1641 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -07001642 "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath, 0,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001643 std::array<const char*, 0>());
Ed Tanous64530012018-02-06 17:08:16 -08001644}
Ed Tanous911ac312017-08-15 09:37:42 -07001645
zhanghch058d1b46d2021-04-01 11:18:24 +08001646inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1647 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001648{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001649 BMCWEB_LOG_DEBUG << "handleGet: " << objectPath << " prop:" << destProperty;
1650 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001651 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001652
Ed Tanous1abe55e2018-09-05 08:30:59 -07001653 std::shared_ptr<std::string> path =
1654 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001655
Ed Tanous1abe55e2018-09-05 08:30:59 -07001656 using GetObjectType =
1657 std::vector<std::pair<std::string, std::vector<std::string>>>;
1658 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +08001659 [asyncResp, path, propertyName](const boost::system::error_code ec,
1660 const GetObjectType& objectNames) {
Ed Tanous81ce6092020-12-17 16:54:55 +00001661 if (ec || objectNames.size() <= 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001662 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001663 setErrorResponse(asyncResp->res,
1664 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001665 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001666 return;
1667 }
1668 std::shared_ptr<nlohmann::json> response =
1669 std::make_shared<nlohmann::json>(nlohmann::json::object());
Ed Tanous7c091622019-05-23 11:42:36 -07001670 // The mapper should never give us an empty interface names
1671 // list, but check anyway
Ed Tanous23a21a12020-07-25 04:45:05 +00001672 for (const std::pair<std::string, std::vector<std::string>>&
Ed Tanous81ce6092020-12-17 16:54:55 +00001673 connection : objectNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001674 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001675 const std::vector<std::string>& interfaceNames =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001676 connection.second;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001677
Ed Tanous1abe55e2018-09-05 08:30:59 -07001678 if (interfaceNames.size() <= 0)
1679 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001680 setErrorResponse(asyncResp->res,
1681 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001682 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001683 return;
1684 }
1685
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001686 for (const std::string& interface : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001687 {
Matt Spinlerfe7e97d2019-01-30 15:33:21 -06001688 sdbusplus::message::message m =
1689 crow::connections::systemBus->new_method_call(
1690 connection.first.c_str(), path->c_str(),
1691 "org.freedesktop.DBus.Properties", "GetAll");
1692 m.append(interface);
1693 crow::connections::systemBus->async_send(
zhanghch058d1b46d2021-04-01 11:18:24 +08001694 m, [asyncResp, response,
Ed Tanous23a21a12020-07-25 04:45:05 +00001695 propertyName](const boost::system::error_code ec2,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001696 sdbusplus::message::message& msg) {
Ed Tanous23a21a12020-07-25 04:45:05 +00001697 if (ec2)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001698 {
1699 BMCWEB_LOG_ERROR << "Bad dbus request error: "
Ed Tanous23a21a12020-07-25 04:45:05 +00001700 << ec2;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001701 }
1702 else
1703 {
Ed Tanous984a4c22021-06-02 13:38:26 -07001704 nlohmann::json properties;
1705 int r =
1706 convertDBusToJSON("a{sv}", msg, properties);
1707 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001708 {
Ed Tanous984a4c22021-06-02 13:38:26 -07001709 BMCWEB_LOG_ERROR
1710 << "convertDBusToJSON failed";
1711 }
1712 else
1713 {
1714 for (auto& prop : properties.items())
1715 {
1716 // if property name is empty, or
1717 // matches our search query, add it
1718 // to the response json
Ed Tanous1abe55e2018-09-05 08:30:59 -07001719
Ed Tanous984a4c22021-06-02 13:38:26 -07001720 if (propertyName->empty())
1721 {
1722 (*response)[prop.key()] =
1723 std::move(prop.value());
1724 }
1725 else if (prop.key() == *propertyName)
1726 {
1727 *response = std::move(prop.value());
1728 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001729 }
1730 }
1731 }
1732 if (response.use_count() == 1)
1733 {
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001734 if (!propertyName->empty() && response->empty())
1735 {
1736 setErrorResponse(
zhanghch058d1b46d2021-04-01 11:18:24 +08001737 asyncResp->res,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001738 boost::beast::http::status::not_found,
1739 propNotFoundDesc, notFoundMsg);
1740 }
1741 else
1742 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001743 asyncResp->res.jsonValue = {
1744 {"status", "ok"},
1745 {"message", "200 OK"},
1746 {"data", *response}};
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001747 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001748 }
Matt Spinlerfe7e97d2019-01-30 15:33:21 -06001749 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001750 }
1751 }
1752 },
1753 "xyz.openbmc_project.ObjectMapper",
1754 "/xyz/openbmc_project/object_mapper",
1755 "xyz.openbmc_project.ObjectMapper", "GetObject", *path,
1756 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001757}
1758
Ed Tanous1abe55e2018-09-05 08:30:59 -07001759struct AsyncPutRequest
1760{
zhanghch058d1b46d2021-04-01 11:18:24 +08001761 AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
1762 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001763 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001764 ~AsyncPutRequest()
1765 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001766 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001767 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001768 setErrorResponse(asyncResp->res,
1769 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001770 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001771 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001772 }
1773
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001774 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001775 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001776 setErrorResponse(asyncResp->res,
1777 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001778 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001779 }
1780
zhanghch058d1b46d2021-04-01 11:18:24 +08001781 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001782 std::string objectPath;
1783 std::string propertyName;
1784 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001785};
1786
zhanghch058d1b46d2021-04-01 11:18:24 +08001787inline void handlePut(const crow::Request& req,
1788 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001789 const std::string& objectPath,
1790 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001791{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001792 if (destProperty.empty())
1793 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001794 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001795 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001796 return;
1797 }
1798
Ed Tanous1abe55e2018-09-05 08:30:59 -07001799 nlohmann::json requestDbusData =
1800 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001801
Ed Tanous1abe55e2018-09-05 08:30:59 -07001802 if (requestDbusData.is_discarded())
1803 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001804 setErrorResponse(asyncResp->res,
1805 boost::beast::http::status::bad_request, noJsonDesc,
1806 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001807 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001808 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001809
Ed Tanous1abe55e2018-09-05 08:30:59 -07001810 nlohmann::json::const_iterator propertyIt = requestDbusData.find("data");
1811 if (propertyIt == requestDbusData.end())
1812 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001813 setErrorResponse(asyncResp->res,
1814 boost::beast::http::status::bad_request, noJsonDesc,
1815 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001816 return;
1817 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001818 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001819 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001820 transaction->objectPath = objectPath;
1821 transaction->propertyName = destProperty;
1822 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001823
Ed Tanous1abe55e2018-09-05 08:30:59 -07001824 using GetObjectType =
1825 std::vector<std::pair<std::string, std::vector<std::string>>>;
Ed Tanous911ac312017-08-15 09:37:42 -07001826
Ed Tanous1abe55e2018-09-05 08:30:59 -07001827 crow::connections::systemBus->async_method_call(
Ed Tanous23a21a12020-07-25 04:45:05 +00001828 [transaction](const boost::system::error_code ec2,
Ed Tanous81ce6092020-12-17 16:54:55 +00001829 const GetObjectType& objectNames) {
1830 if (!ec2 && objectNames.size() <= 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001831 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001832 setErrorResponse(transaction->asyncResp->res,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001833 boost::beast::http::status::not_found,
1834 propNotFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001835 return;
1836 }
Ed Tanous911ac312017-08-15 09:37:42 -07001837
Ed Tanous23a21a12020-07-25 04:45:05 +00001838 for (const std::pair<std::string, std::vector<std::string>>&
Ed Tanous81ce6092020-12-17 16:54:55 +00001839 connection : objectNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001840 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001841 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001842
Ed Tanous1abe55e2018-09-05 08:30:59 -07001843 crow::connections::systemBus->async_method_call(
1844 [connectionName{std::string(connectionName)},
Ed Tanous23a21a12020-07-25 04:45:05 +00001845 transaction](const boost::system::error_code ec3,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001846 const std::string& introspectXml) {
Ed Tanous23a21a12020-07-25 04:45:05 +00001847 if (ec3)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001848 {
1849 BMCWEB_LOG_ERROR
1850 << "Introspect call failed with error: "
Ed Tanous23a21a12020-07-25 04:45:05 +00001851 << ec3.message()
Ed Tanous1abe55e2018-09-05 08:30:59 -07001852 << " on process: " << connectionName;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001853 transaction->setErrorStatus("Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001854 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001855 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001856 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001857
Ed Tanous1abe55e2018-09-05 08:30:59 -07001858 doc.Parse(introspectXml.c_str());
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001859 tinyxml2::XMLNode* pRoot =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001860 doc.FirstChildElement("node");
1861 if (pRoot == nullptr)
1862 {
1863 BMCWEB_LOG_ERROR << "XML document failed to parse: "
1864 << introspectXml;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001865 transaction->setErrorStatus("Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001866 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001867 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001868 tinyxml2::XMLElement* ifaceNode =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001869 pRoot->FirstChildElement("interface");
1870 while (ifaceNode != nullptr)
1871 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001872 const char* interfaceName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001873 ifaceNode->Attribute("name");
1874 BMCWEB_LOG_DEBUG << "found interface "
1875 << interfaceName;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001876 tinyxml2::XMLElement* propNode =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001877 ifaceNode->FirstChildElement("property");
1878 while (propNode != nullptr)
1879 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001880 const char* propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001881 propNode->Attribute("name");
1882 BMCWEB_LOG_DEBUG << "Found property "
1883 << propertyName;
1884 if (propertyName == transaction->propertyName)
1885 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001886 const char* argType =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001887 propNode->Attribute("type");
1888 if (argType != nullptr)
1889 {
1890 sdbusplus::message::message m =
1891 crow::connections::systemBus
1892 ->new_method_call(
1893 connectionName.c_str(),
1894 transaction->objectPath
1895 .c_str(),
1896 "org.freedesktop.DBus."
1897 "Properties",
1898 "Set");
1899 m.append(interfaceName,
1900 transaction->propertyName);
1901 int r = sd_bus_message_open_container(
1902 m.get(), SD_BUS_TYPE_VARIANT,
1903 argType);
1904 if (r < 0)
1905 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001906 transaction->setErrorStatus(
1907 "Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001908 return;
1909 }
1910 r = convertJsonToDbus(
1911 m.get(), argType,
1912 transaction->propertyValue);
1913 if (r < 0)
1914 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -05001915 if (r == -ERANGE)
1916 {
1917 transaction->setErrorStatus(
1918 "Provided property value "
1919 "is out of range for the "
1920 "property type");
1921 }
1922 else
1923 {
1924 transaction->setErrorStatus(
1925 "Invalid arg type");
1926 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001927 return;
1928 }
1929 r = sd_bus_message_close_container(
1930 m.get());
1931 if (r < 0)
1932 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001933 transaction->setErrorStatus(
1934 "Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001935 return;
1936 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001937 crow::connections::systemBus
1938 ->async_send(
1939 m,
1940 [transaction](
1941 boost::system::error_code
1942 ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001943 sdbusplus::message::message&
Ed Tanous23a21a12020-07-25 04:45:05 +00001944 m2) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001945 BMCWEB_LOG_DEBUG << "sent";
1946 if (ec)
1947 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001948 const sd_bus_error* e =
Ed Tanous23a21a12020-07-25 04:45:05 +00001949 m2.get_error();
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001950 setErrorResponse(
zhanghch058d1b46d2021-04-01 11:18:24 +08001951 transaction
1952 ->asyncResp
1953 ->res,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001954 boost::beast::http::
1955 status::
1956 forbidden,
Matt Spinler06b1b632019-06-18 16:09:25 -05001957 (e) ? e->name
1958 : ec.category()
1959 .name(),
1960 (e) ? e->message
1961 : ec.message());
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001962 }
1963 else
1964 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001965 transaction->asyncResp
1966 ->res.jsonValue = {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001967 {"status", "ok"},
1968 {"message",
1969 "200 OK"},
1970 {"data", nullptr}};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001971 }
1972 });
1973 }
1974 }
1975 propNode =
1976 propNode->NextSiblingElement("property");
1977 }
1978 ifaceNode =
1979 ifaceNode->NextSiblingElement("interface");
1980 }
1981 },
1982 connectionName, transaction->objectPath,
1983 "org.freedesktop.DBus.Introspectable", "Introspect");
1984 }
1985 },
1986 "xyz.openbmc_project.ObjectMapper",
1987 "/xyz/openbmc_project/object_mapper",
1988 "xyz.openbmc_project.ObjectMapper", "GetObject",
1989 transaction->objectPath, std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001990}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001991
zhanghch058d1b46d2021-04-01 11:18:24 +08001992inline void handleDBusUrl(const crow::Request& req,
1993 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001994 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07001995{
Ed Tanous049a0512018-11-01 13:58:42 -07001996
1997 // If accessing a single attribute, fill in and update objectPath,
1998 // otherwise leave destProperty blank
1999 std::string destProperty = "";
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002000 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002001 size_t attrPosition = objectPath.find(attrSeperator);
2002 if (attrPosition != objectPath.npos)
2003 {
2004 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2005 objectPath.length());
2006 objectPath = objectPath.substr(0, attrPosition);
2007 }
2008
Ed Tanousb41187f2019-10-24 16:30:02 -07002009 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002010 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002011 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002012 size_t actionPosition = objectPath.find(actionSeperator);
2013 if (actionPosition != objectPath.npos)
2014 {
2015 std::string postProperty =
2016 objectPath.substr((actionPosition + strlen(actionSeperator)),
2017 objectPath.length());
2018 objectPath = objectPath.substr(0, actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002019 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002020 return;
2021 }
2022 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002023 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002024 {
2025 if (boost::ends_with(objectPath, "/enumerate"))
2026 {
2027 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2028 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002029 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002030 }
2031 else if (boost::ends_with(objectPath, "/list"))
2032 {
2033 objectPath.erase(objectPath.end() - sizeof("list"),
2034 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002035 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002036 }
2037 else
2038 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002039 // Trim any trailing "/" at the end
2040 if (boost::ends_with(objectPath, "/"))
2041 {
2042 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002043 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002044 }
2045 else
2046 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002047 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002048 }
Ed Tanous049a0512018-11-01 13:58:42 -07002049 }
2050 return;
2051 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002052 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002053 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002054 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002055 return;
2056 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002057 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002058 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002059 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002060 return;
2061 }
Ed Tanous049a0512018-11-01 13:58:42 -07002062
zhanghch058d1b46d2021-04-01 11:18:24 +08002063 setErrorResponse(asyncResp->res,
2064 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002065 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002066}
2067
Ed Tanous23a21a12020-07-25 04:45:05 +00002068inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002069{
2070 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002071 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002072 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002073 [](const crow::Request&,
2074 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2075 asyncResp->res.jsonValue = {{"buses", {{{"name", "system"}}}},
2076 {"status", "ok"}};
Ed Tanous1abe55e2018-09-05 08:30:59 -07002077 });
2078
2079 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002080 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002081 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002082 [](const crow::Request&,
2083 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
P Dheeraj Srujan Kumar83fd8e12021-07-13 02:53:03 +05302084 auto myCallback = [asyncResp](
zhanghch058d1b46d2021-04-01 11:18:24 +08002085 const boost::system::error_code ec,
2086 std::vector<std::string>& names) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07002087 if (ec)
2088 {
2089 BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +08002090 asyncResp->res.result(
Ed Tanous1abe55e2018-09-05 08:30:59 -07002091 boost::beast::http::status::internal_server_error);
2092 }
2093 else
2094 {
2095 std::sort(names.begin(), names.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002096 asyncResp->res.jsonValue = {{"status", "ok"}};
2097 auto& objectsSub = asyncResp->res.jsonValue["objects"];
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002098 for (auto& name : names)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002099 {
2100 objectsSub.push_back({{"name", name}});
2101 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002102 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002103 };
2104 crow::connections::systemBus->async_method_call(
2105 std::move(myCallback), "org.freedesktop.DBus", "/",
2106 "org.freedesktop.DBus", "ListNames");
2107 });
2108
2109 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002110 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002111 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002112 [](const crow::Request&,
2113 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2114 handleList(asyncResp, "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07002115 });
2116
2117 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002118 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002119 .methods(boost::beast::http::verb::get)(
2120 [](const crow::Request& req,
2121 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002122 const std::string& path) {
Ed Tanous049a0512018-11-01 13:58:42 -07002123 std::string objectPath = "/xyz/" + path;
zhanghch058d1b46d2021-04-01 11:18:24 +08002124 handleDBusUrl(req, asyncResp, objectPath);
2125 });
2126
2127 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002128 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002129 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2130 boost::beast::http::verb::delete_)(
2131 [](const crow::Request& req,
2132 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2133 const std::string& path) {
2134 std::string objectPath = "/xyz/" + path;
2135 handleDBusUrl(req, asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002136 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002137
Ed Tanous049a0512018-11-01 13:58:42 -07002138 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002139 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002140 .methods(boost::beast::http::verb::get)(
2141 [](const crow::Request& req,
2142 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2143 const std::string& path) {
2144 std::string objectPath = "/org/" + path;
2145 handleDBusUrl(req, asyncResp, objectPath);
2146 });
Tanousf00032d2018-11-05 01:18:10 -03002147
2148 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002149 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002150 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2151 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002152 [](const crow::Request& req,
2153 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002154 const std::string& path) {
Ed Tanouse1281402019-04-03 07:07:10 -07002155 std::string objectPath = "/org/" + path;
zhanghch058d1b46d2021-04-01 11:18:24 +08002156 handleDBusUrl(req, asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002157 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002158
Ed Tanous1abe55e2018-09-05 08:30:59 -07002159 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002160 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002161 .methods(boost::beast::http::verb::get)(
2162 [](const crow::Request&,
2163 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2164 const std::string& dumpId) {
2165 std::regex validFilename(R"(^[\w\- ]+(\.?[\w\- ]*)$)");
2166 if (!std::regex_match(dumpId, validFilename))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002167 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002168 asyncResp->res.result(
2169 boost::beast::http::status::bad_request);
Ramesh Iyyard9207042019-07-05 08:04:42 -05002170 return;
2171 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002172 std::filesystem::path loc(
2173 "/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002174
zhanghch058d1b46d2021-04-01 11:18:24 +08002175 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002176
zhanghch058d1b46d2021-04-01 11:18:24 +08002177 if (!std::filesystem::exists(loc) ||
2178 !std::filesystem::is_directory(loc))
2179 {
2180 BMCWEB_LOG_ERROR << loc << "Not found";
2181 asyncResp->res.result(
2182 boost::beast::http::status::not_found);
2183 return;
2184 }
2185 std::filesystem::directory_iterator files(loc);
2186
2187 for (auto& file : files)
2188 {
2189 std::ifstream readFile(file.path());
2190 if (!readFile.good())
2191 {
2192 continue;
2193 }
2194
2195 asyncResp->res.addHeader("Content-Type",
2196 "application/octet-stream");
2197
2198 // Assuming only one dump file will be present in the dump
2199 // id 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
2204 // dumpfile 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 asyncResp->res.result(
2211 boost::beast::http::status::not_found);
2212 return;
2213 }
2214 std::string contentDispositionParam =
2215 "attachment; filename=\"" + dumpFileName + "\"";
2216
2217 asyncResp->res.addHeader("Content-Disposition",
2218 contentDispositionParam);
2219
2220 asyncResp->res.body() = {
2221 std::istreambuf_iterator<char>(readFile),
2222 std::istreambuf_iterator<char>()};
2223 return;
2224 }
2225 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002226 return;
zhanghch058d1b46d2021-04-01 11:18:24 +08002227 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002228
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002229 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002230 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002231
2232 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002233 [](const crow::Request&,
2234 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002235 const std::string& connection) {
Gunnar Mills9062d472021-11-16 11:37:47 -06002236 introspectObjects(
2237 connection, "/",
2238 std::make_shared<bmcweb::AsyncResp>(asyncResp->res));
Ed Tanousb41187f2019-10-24 16:30:02 -07002239 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002240
2241 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002242 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002243 .methods(boost::beast::http::verb::get, boost::beast::http::verb::post)(
2244 [](const crow::Request& req,
2245 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2246 const std::string& processName,
2247 const std::string& requestedPath) {
2248 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())
Ed Tanous1abe55e2018-09-05 08:30:59 -07002255 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002256 objectPath = "/";
Ed Tanous1abe55e2018-09-05 08:30:59 -07002257 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002258 while (it != strs.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -07002259 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002260 // Check if segment contains ".". If it does, it must be an
2261 // interface
2262 if (it->find(".") != std::string::npos)
2263 {
2264 break;
2265 // This check is necessary as the trailing slash gets
2266 // parsed as part of our <path> specifier above, which
2267 // causes the normal trailing backslash redirector to
2268 // fail.
2269 }
2270 if (!it->empty())
2271 {
2272 objectPath += "/" + *it;
2273 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002274 it++;
2275 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002276 if (it != strs.end())
2277 {
2278 interfaceName = *it;
2279 it++;
Ed Tanous7c091622019-05-23 11:42:36 -07002280
zhanghch058d1b46d2021-04-01 11:18:24 +08002281 // 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 {
2290 // if there is more levels past the method name, something
2291 // went wrong, return not found
2292 asyncResp->res.result(
2293 boost::beast::http::status::not_found);
2294 return;
2295 }
2296 if (interfaceName.empty())
2297 {
2298 crow::connections::systemBus->async_method_call(
2299 [asyncResp, processName,
2300 objectPath](const boost::system::error_code ec,
2301 const std::string& introspectXml) {
2302 if (ec)
2303 {
2304 BMCWEB_LOG_ERROR
2305 << "Introspect call failed with error: "
2306 << ec.message()
2307 << " on process: " << processName
2308 << " path: " << objectPath << "\n";
2309 return;
2310 }
2311 tinyxml2::XMLDocument doc;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002312
zhanghch058d1b46d2021-04-01 11:18:24 +08002313 doc.Parse(introspectXml.c_str());
2314 tinyxml2::XMLNode* pRoot =
2315 doc.FirstChildElement("node");
2316 if (pRoot == nullptr)
2317 {
2318 BMCWEB_LOG_ERROR
2319 << "XML document failed to parse "
2320 << processName << " " << objectPath << "\n";
2321 asyncResp->res.jsonValue = {
2322 {"status", "XML parse error"}};
2323 asyncResp->res.result(
2324 boost::beast::http::status::
2325 internal_server_error);
2326 return;
2327 }
2328
2329 BMCWEB_LOG_DEBUG << introspectXml;
Ed Tanous7c091622019-05-23 11:42:36 -07002330 asyncResp->res.jsonValue = {
zhanghch058d1b46d2021-04-01 11:18:24 +08002331 {"status", "ok"},
2332 {"bus_name", processName},
2333 {"object_path", objectPath}};
2334 nlohmann::json& interfacesArray =
2335 asyncResp->res.jsonValue["interfaces"];
2336 interfacesArray = nlohmann::json::array();
2337 tinyxml2::XMLElement* interface =
2338 pRoot->FirstChildElement("interface");
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002339
zhanghch058d1b46d2021-04-01 11:18:24 +08002340 while (interface != nullptr)
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002341 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002342 const char* ifaceName =
2343 interface->Attribute("name");
2344 if (ifaceName != nullptr)
Ed Tanous7c091622019-05-23 11:42:36 -07002345 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002346 interfacesArray.push_back(
2347 {{"name", ifaceName}});
2348 }
2349
2350 interface =
2351 interface->NextSiblingElement("interface");
2352 }
2353 },
2354 processName, objectPath,
2355 "org.freedesktop.DBus.Introspectable", "Introspect");
2356 }
2357 else if (methodName.empty())
2358 {
2359 crow::connections::systemBus->async_method_call(
2360 [asyncResp, processName, objectPath,
2361 interfaceName](const boost::system::error_code ec,
2362 const std::string& introspectXml) {
2363 if (ec)
2364 {
2365 BMCWEB_LOG_ERROR
2366 << "Introspect call failed with error: "
2367 << ec.message()
2368 << " on process: " << processName
2369 << " path: " << objectPath << "\n";
2370 return;
2371 }
2372 tinyxml2::XMLDocument doc;
2373
2374 doc.Parse(introspectXml.data(),
2375 introspectXml.size());
2376 tinyxml2::XMLNode* pRoot =
2377 doc.FirstChildElement("node");
2378 if (pRoot == nullptr)
2379 {
2380 BMCWEB_LOG_ERROR
2381 << "XML document failed to parse "
2382 << processName << " " << objectPath << "\n";
2383 asyncResp->res.result(
2384 boost::beast::http::status::
2385 internal_server_error);
2386 return;
2387 }
2388 asyncResp->res.jsonValue = {
2389 {"status", "ok"},
2390 {"bus_name", processName},
2391 {"interface", interfaceName},
2392 {"object_path", objectPath}};
2393
2394 nlohmann::json& methodsArray =
2395 asyncResp->res.jsonValue["methods"];
2396 methodsArray = nlohmann::json::array();
2397
2398 nlohmann::json& signalsArray =
2399 asyncResp->res.jsonValue["signals"];
2400 signalsArray = nlohmann::json::array();
2401
2402 nlohmann::json& propertiesObj =
2403 asyncResp->res.jsonValue["properties"];
2404 propertiesObj = nlohmann::json::object();
2405
2406 // if we know we're the only call, build the
2407 // json directly
2408 tinyxml2::XMLElement* interface =
2409 pRoot->FirstChildElement("interface");
2410 while (interface != nullptr)
2411 {
2412 const char* ifaceName =
2413 interface->Attribute("name");
2414
2415 if (ifaceName != nullptr &&
2416 ifaceName == interfaceName)
2417 {
2418 break;
2419 }
2420
2421 interface =
2422 interface->NextSiblingElement("interface");
2423 }
2424 if (interface == nullptr)
2425 {
2426 // if we got to the end of the list and
2427 // never found a match, throw 404
2428 asyncResp->res.result(
2429 boost::beast::http::status::not_found);
2430 return;
2431 }
2432
2433 tinyxml2::XMLElement* methods =
2434 interface->FirstChildElement("method");
2435 while (methods != nullptr)
2436 {
2437 nlohmann::json argsArray =
2438 nlohmann::json::array();
2439 tinyxml2::XMLElement* arg =
2440 methods->FirstChildElement("arg");
2441 while (arg != nullptr)
2442 {
2443 nlohmann::json thisArg;
2444 for (const char* fieldName :
2445 std::array<const char*, 3>{
2446 "name", "direction", "type"})
Ed Tanous7c091622019-05-23 11:42:36 -07002447 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002448 const char* fieldValue =
2449 arg->Attribute(fieldName);
2450 if (fieldValue != nullptr)
Ed Tanous7c091622019-05-23 11:42:36 -07002451 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002452 thisArg[fieldName] = fieldValue;
Ed Tanous7c091622019-05-23 11:42:36 -07002453 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002454 }
2455 argsArray.push_back(std::move(thisArg));
2456 arg = arg->NextSiblingElement("arg");
2457 }
Ed Tanous7c091622019-05-23 11:42:36 -07002458
zhanghch058d1b46d2021-04-01 11:18:24 +08002459 const char* name = methods->Attribute("name");
2460 if (name != nullptr)
2461 {
2462 std::string uri;
2463 uri.reserve(14 + processName.size() +
2464 objectPath.size() +
2465 interfaceName.size() +
2466 strlen(name));
2467 uri += "/bus/system/";
2468 uri += processName;
2469 uri += objectPath;
2470 uri += "/";
2471 uri += interfaceName;
2472 uri += "/";
2473 uri += name;
2474 methodsArray.push_back(
2475 {{"name", name},
2476 {"uri", std::move(uri)},
2477 {"args", argsArray}});
2478 }
2479 methods = methods->NextSiblingElement("method");
Ed Tanous7c091622019-05-23 11:42:36 -07002480 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002481 tinyxml2::XMLElement* signals =
2482 interface->FirstChildElement("signal");
2483 while (signals != nullptr)
2484 {
2485 nlohmann::json argsArray =
2486 nlohmann::json::array();
2487
2488 tinyxml2::XMLElement* arg =
2489 signals->FirstChildElement("arg");
2490 while (arg != nullptr)
2491 {
2492 const char* name = arg->Attribute("name");
2493 const char* type = arg->Attribute("type");
2494 if (name != nullptr && type != nullptr)
2495 {
2496 argsArray.push_back({
2497 {"name", name},
2498 {"type", type},
2499 });
2500 }
2501 arg = arg->NextSiblingElement("arg");
2502 }
2503 const char* name = signals->Attribute("name");
2504 if (name != nullptr)
2505 {
2506 signalsArray.push_back(
2507 {{"name", name}, {"args", argsArray}});
2508 }
2509
2510 signals = signals->NextSiblingElement("signal");
2511 }
2512
2513 tinyxml2::XMLElement* property =
2514 interface->FirstChildElement("property");
2515 while (property != nullptr)
2516 {
2517 const char* name = property->Attribute("name");
2518 const char* type = property->Attribute("type");
2519 if (type != nullptr && name != nullptr)
2520 {
2521 sdbusplus::message::message m =
2522 crow::connections::systemBus
2523 ->new_method_call(
2524 processName.c_str(),
2525 objectPath.c_str(),
2526 "org.freedesktop."
2527 "DBus."
2528 "Properties",
2529 "Get");
2530 m.append(interfaceName, name);
2531 nlohmann::json& propertyItem =
2532 propertiesObj[name];
2533 crow::connections::systemBus->async_send(
2534 m,
2535 [&propertyItem, asyncResp](
2536 boost::system::error_code& e,
2537 sdbusplus::message::message& msg) {
2538 if (e)
2539 {
2540 return;
2541 }
2542
2543 convertDBusToJSON("v", msg,
2544 propertyItem);
2545 });
2546 }
2547 property =
2548 property->NextSiblingElement("property");
2549 }
2550 },
2551 processName, objectPath,
2552 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002553 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002554 else
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002555 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002556 if (req.method() != boost::beast::http::verb::post)
2557 {
2558 asyncResp->res.result(
2559 boost::beast::http::status::not_found);
2560 return;
2561 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002562
zhanghch058d1b46d2021-04-01 11:18:24 +08002563 nlohmann::json requestDbusData =
2564 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002565
zhanghch058d1b46d2021-04-01 11:18:24 +08002566 if (requestDbusData.is_discarded())
2567 {
2568 asyncResp->res.result(
2569 boost::beast::http::status::bad_request);
2570 return;
2571 }
2572 if (!requestDbusData.is_array())
2573 {
2574 asyncResp->res.result(
2575 boost::beast::http::status::bad_request);
2576 return;
2577 }
2578 auto transaction =
2579 std::make_shared<InProgressActionData>(asyncResp->res);
2580
2581 transaction->path = objectPath;
2582 transaction->methodName = methodName;
2583 transaction->arguments = std::move(requestDbusData);
2584
2585 findActionOnInterface(transaction, processName);
2586 }
2587 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002588}
2589} // namespace openbmc_mapper
2590} // namespace crow