blob: 7f16ea8f6aa59c2171ee29efd2f94b1967270c75 [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];
Ed Tanousd1a64812021-12-13 12:14:05 -0800164 std::visit(
165 [&propertyJson](auto&& val) {
166 if constexpr (std::is_same_v<
167 std::decay_t<decltype(val)>,
168 sdbusplus::message::unix_fd>)
169 {
170 propertyJson = val.fd;
171 }
172 else
173 {
174
175 propertyJson = val;
176 }
177 },
178 value);
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600179 }
180 },
181 service, objectPath, "org.freedesktop.DBus.Properties", "GetAll",
182 interface);
183}
184
185// Find any results that weren't picked up by ObjectManagers, to be
186// called after all ObjectManagers are searched for and called.
Ed Tanous23a21a12020-07-25 04:45:05 +0000187inline void findRemainingObjectsForEnumerate(
Ed Tanousb5a76932020-09-29 16:16:58 -0700188 const std::string& objectPath,
189 const std::shared_ptr<GetSubTreeType>& subtree,
190 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600191{
192 BMCWEB_LOG_DEBUG << "findRemainingObjectsForEnumerate";
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500193 const nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600194
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500195 for (const auto& [path, interface_map] : *subtree)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600196 {
197 if (path == objectPath)
198 {
199 // An enumerate does not return the target path's properties
200 continue;
201 }
202 if (dataJson.find(path) == dataJson.end())
203 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500204 for (const auto& [service, interfaces] : interface_map)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600205 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500206 for (const auto& interface : interfaces)
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600207 {
208 if (!boost::starts_with(interface, "org.freedesktop.DBus"))
209 {
210 getPropertiesForEnumerate(path, service, interface,
211 asyncResp);
212 }
213 }
214 }
215 }
216 }
217}
218
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600219struct InProgressEnumerateData
220{
zhanghch058d1b46d2021-04-01 11:18:24 +0800221 InProgressEnumerateData(
222 const std::string& objectPathIn,
223 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
Ed Tanous23a21a12020-07-25 04:45:05 +0000224 objectPath(objectPathIn),
zhanghch058d1b46d2021-04-01 11:18:24 +0800225 asyncResp(asyncRespIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500226 {}
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600227
228 ~InProgressEnumerateData()
229 {
Ed Tanous24b2fe82022-01-06 12:45:54 -0800230 try
231 {
232 findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
233 }
234 catch (...)
235 {
236 BMCWEB_LOG_CRITICAL
237 << "findRemainingObjectsForEnumerate threw exception";
238 }
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600239 }
240
241 const std::string objectPath;
242 std::shared_ptr<GetSubTreeType> subtree;
243 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
244};
245
Ed Tanous23a21a12020-07-25 04:45:05 +0000246inline void getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000247 const std::string& objectName, const std::string& objectManagerPath,
248 const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700249 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700250{
Ed Tanous81ce6092020-12-17 16:54:55 +0000251 BMCWEB_LOG_DEBUG << "getManagedObjectsForEnumerate " << objectName
252 << " object_manager_path " << objectManagerPath
253 << " connection_name " << connectionName;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700254 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000255 [transaction, objectName,
256 connectionName](const boost::system::error_code ec,
257 const dbus::utility::ManagedObjectType& objects) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700258 if (ec)
259 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000260 BMCWEB_LOG_ERROR << "GetManagedObjects on path " << objectName
261 << " on connection " << connectionName
Ed Tanous049a0512018-11-01 13:58:42 -0700262 << " failed with code " << ec;
263 return;
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700264 }
Ed Tanous64530012018-02-06 17:08:16 -0800265
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500266 nlohmann::json& dataJson =
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600267 transaction->asyncResp->res.jsonValue["data"];
Ed Tanous049a0512018-11-01 13:58:42 -0700268
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500269 for (const auto& objectPath : objects)
Ed Tanous049a0512018-11-01 13:58:42 -0700270 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000271 if (boost::starts_with(objectPath.first.str, objectName))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700272 {
Ed Tanous049a0512018-11-01 13:58:42 -0700273 BMCWEB_LOG_DEBUG << "Reading object "
274 << objectPath.first.str;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500275 nlohmann::json& objectJson = dataJson[objectPath.first.str];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700276 if (objectJson.is_null())
277 {
278 objectJson = nlohmann::json::object();
279 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500280 for (const auto& interface : objectPath.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700281 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500282 for (const auto& property : interface.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700283 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500284 nlohmann::json& propertyJson =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700285 objectJson[property.first];
Ed Tanousd1a64812021-12-13 12:14:05 -0800286 std::visit(
287 [&propertyJson](auto&& val) {
288 if constexpr (
289 std::is_same_v<
290 std::decay_t<decltype(val)>,
291 sdbusplus::message::unix_fd>)
292 {
293 propertyJson = val.fd;
294 }
295 else
296 {
297
298 propertyJson = val;
299 }
300 },
301 property.second);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700302 }
303 }
304 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500305 for (const auto& interface : objectPath.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700306 {
307 if (interface.first == "org.freedesktop.DBus.ObjectManager")
308 {
309 getManagedObjectsForEnumerate(
310 objectPath.first.str, objectPath.first.str,
Ed Tanous81ce6092020-12-17 16:54:55 +0000311 connectionName, transaction);
Ed Tanous049a0512018-11-01 13:58:42 -0700312 }
313 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700314 }
315 },
Ed Tanous81ce6092020-12-17 16:54:55 +0000316 connectionName, objectManagerPath, "org.freedesktop.DBus.ObjectManager",
317 "GetManagedObjects");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700318}
319
Ed Tanous23a21a12020-07-25 04:45:05 +0000320inline void findObjectManagerPathForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000321 const std::string& objectName, const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700322 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700323{
Ed Tanous81ce6092020-12-17 16:54:55 +0000324 BMCWEB_LOG_DEBUG << "Finding objectmanager for path " << objectName
325 << " on connection:" << connectionName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700326 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000327 [transaction, objectName, connectionName](
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700328 const boost::system::error_code ec,
329 const boost::container::flat_map<
330 std::string, boost::container::flat_map<
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500331 std::string, std::vector<std::string>>>&
332 objects) {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700333 if (ec)
334 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000335 BMCWEB_LOG_ERROR << "GetAncestors on path " << objectName
Ed Tanous049a0512018-11-01 13:58:42 -0700336 << " failed with code " << ec;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700337 return;
338 }
339
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500340 for (const auto& pathGroup : objects)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700341 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500342 for (const auto& connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700343 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000344 if (connectionGroup.first == connectionName)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700345 {
346 // Found the object manager path for this resource.
347 getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000348 objectName, pathGroup.first, connectionName,
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600349 transaction);
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700350 return;
351 }
352 }
353 }
354 },
355 "xyz.openbmc_project.ObjectMapper",
356 "/xyz/openbmc_project/object_mapper",
Ed Tanous81ce6092020-12-17 16:54:55 +0000357 "xyz.openbmc_project.ObjectMapper", "GetAncestors", objectName,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500358 std::array<const char*, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700359}
Ed Tanous64530012018-02-06 17:08:16 -0800360
Ed Tanous7c091622019-05-23 11:42:36 -0700361// Uses GetObject to add the object info about the target /enumerate path to
362// the results of GetSubTree, as GetSubTree will not return info for the
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600363// target path, and then continues on enumerating the rest of the tree.
Ed Tanousb5a76932020-09-29 16:16:58 -0700364inline void getObjectAndEnumerate(
365 const std::shared_ptr<InProgressEnumerateData>& transaction)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600366{
367 using GetObjectType =
368 std::vector<std::pair<std::string, std::vector<std::string>>>;
369
370 crow::connections::systemBus->async_method_call(
371 [transaction](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500372 const GetObjectType& objects) {
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600373 if (ec)
374 {
375 BMCWEB_LOG_ERROR << "GetObject for path "
376 << transaction->objectPath
377 << " failed with code " << ec;
378 return;
379 }
380
381 BMCWEB_LOG_DEBUG << "GetObject for " << transaction->objectPath
382 << " has " << objects.size() << " entries";
383 if (!objects.empty())
384 {
385 transaction->subtree->emplace_back(transaction->objectPath,
386 objects);
387 }
388
389 // Map indicating connection name, and the path where the object
390 // manager exists
391 boost::container::flat_map<std::string, std::string> connections;
392
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500393 for (const auto& object : *(transaction->subtree))
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600394 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500395 for (const auto& connection : object.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600396 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500397 std::string& objectManagerPath =
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600398 connections[connection.first];
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500399 for (const auto& interface : connection.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600400 {
401 BMCWEB_LOG_DEBUG << connection.first
402 << " has interface " << interface;
403 if (interface == "org.freedesktop.DBus.ObjectManager")
404 {
405 BMCWEB_LOG_DEBUG << "found object manager path "
406 << object.first;
407 objectManagerPath = object.first;
408 }
409 }
410 }
411 }
412 BMCWEB_LOG_DEBUG << "Got " << connections.size() << " connections";
413
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500414 for (const auto& connection : connections)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600415 {
Ed Tanous7c091622019-05-23 11:42:36 -0700416 // If we already know where the object manager is, we don't
417 // need to search for it, we can call directly in to
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600418 // getManagedObjects
419 if (!connection.second.empty())
420 {
421 getManagedObjectsForEnumerate(
422 transaction->objectPath, connection.second,
423 connection.first, transaction);
424 }
425 else
426 {
Ed Tanous7c091622019-05-23 11:42:36 -0700427 // otherwise we need to find the object manager path
428 // before we can continue
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600429 findObjectManagerPathForEnumerate(
430 transaction->objectPath, connection.first, transaction);
431 }
432 }
433 },
434 "xyz.openbmc_project.ObjectMapper",
435 "/xyz/openbmc_project/object_mapper",
436 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500437 transaction->objectPath, std::array<const char*, 0>());
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600438}
Ed Tanous64530012018-02-06 17:08:16 -0800439
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700440// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700441struct InProgressActionData
442{
Ed Tanous23a21a12020-07-25 04:45:05 +0000443 InProgressActionData(crow::Response& resIn) : res(resIn)
444 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700445 ~InProgressActionData()
446 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600447 // Methods could have been called across different owners
448 // and interfaces, where some calls failed and some passed.
449 //
450 // The rules for this are:
451 // * if no method was called - error
452 // * if a method failed and none passed - error
453 // (converse: if at least one method passed - OK)
454 // * for the method output:
455 // * if output processing didn't fail, return the data
456
457 // Only deal with method returns if nothing failed earlier
458 if (res.result() == boost::beast::http::status::ok)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700459 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600460 if (!methodPassed)
461 {
Matt Spinler06b1b632019-06-18 16:09:25 -0500462 if (!methodFailed)
Matt Spinler16caaee2019-01-15 11:40:34 -0600463 {
464 setErrorResponse(res, boost::beast::http::status::not_found,
465 methodNotFoundDesc, notFoundMsg);
466 }
467 }
468 else
469 {
470 if (outputFailed)
471 {
472 setErrorResponse(
473 res, boost::beast::http::status::internal_server_error,
474 "Method output failure", methodOutputFailedMsg);
475 }
476 else
477 {
478 res.jsonValue = {{"status", "ok"},
479 {"message", "200 OK"},
480 {"data", methodResponse}};
481 }
482 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700483 }
Matt Spinler16caaee2019-01-15 11:40:34 -0600484
Ed Tanous1abe55e2018-09-05 08:30:59 -0700485 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700486 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700487
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500488 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700489 {
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600490 setErrorResponse(res, boost::beast::http::status::bad_request, desc,
491 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700492 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500493 crow::Response& res;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700494 std::string path;
495 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600496 std::string interfaceName;
Matt Spinler16caaee2019-01-15 11:40:34 -0600497 bool methodPassed = false;
498 bool methodFailed = false;
499 bool outputFailed = false;
Matt Spinler39a4e392019-01-15 11:53:13 -0600500 bool convertedToArray = false;
Matt Spinler16caaee2019-01-15 11:40:34 -0600501 nlohmann::json methodResponse;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700502 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700503};
504
Ed Tanous23a21a12020-07-25 04:45:05 +0000505inline std::vector<std::string> dbusArgSplit(const std::string& string)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700506{
507 std::vector<std::string> ret;
508 if (string.empty())
509 {
510 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700511 }
Ed Tanous0f0353b2019-10-24 11:37:51 -0700512 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700513 int containerDepth = 0;
514
515 for (std::string::const_iterator character = string.begin();
516 character != string.end(); character++)
517 {
518 ret.back() += *character;
519 switch (*character)
520 {
521 case ('a'):
522 break;
523 case ('('):
524 case ('{'):
525 containerDepth++;
526 break;
527 case ('}'):
528 case (')'):
529 containerDepth--;
530 if (containerDepth == 0)
531 {
532 if (character + 1 != string.end())
533 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700534 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700535 }
536 }
537 break;
538 default:
539 if (containerDepth == 0)
540 {
541 if (character + 1 != string.end())
542 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700543 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700544 }
545 }
546 break;
547 }
548 }
Matt Spinler4ae611d2019-01-11 15:37:06 -0600549
550 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700551}
552
Ed Tanous81ce6092020-12-17 16:54:55 +0000553inline int convertJsonToDbus(sd_bus_message* m, const std::string& argType,
554 const nlohmann::json& inputJson)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700555{
556 int r = 0;
Ed Tanous71f52d92021-02-19 08:51:17 -0800557 BMCWEB_LOG_DEBUG << "Converting "
558 << inputJson.dump(2, ' ', true,
559 nlohmann::json::error_handler_t::replace)
Ed Tanous81ce6092020-12-17 16:54:55 +0000560 << " to type: " << argType;
561 const std::vector<std::string> argTypes = dbusArgSplit(argType);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700562
Ed Tanous1abe55e2018-09-05 08:30:59 -0700563 // Assume a single object for now.
Ed Tanous81ce6092020-12-17 16:54:55 +0000564 const nlohmann::json* j = &inputJson;
565 nlohmann::json::const_iterator jIt = inputJson.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700566
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500567 for (const std::string& argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700568 {
569 // If we are decoding multiple objects, grab the pointer to the
570 // iterator, and increment it for the next loop
571 if (argTypes.size() > 1)
572 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000573 if (jIt == inputJson.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700574 {
575 return -2;
576 }
577 j = &*jIt;
578 jIt++;
579 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500580 const int64_t* intValue = j->get_ptr<const int64_t*>();
581 const std::string* stringValue = j->get_ptr<const std::string*>();
582 const double* doubleValue = j->get_ptr<const double*>();
583 const bool* b = j->get_ptr<const bool*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700584 int64_t v = 0;
585 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700586
Ed Tanous1abe55e2018-09-05 08:30:59 -0700587 // Do some basic type conversions that make sense. uint can be
588 // converted to int. int and uint can be converted to double
Ed Tanous66664f22019-10-11 13:05:49 -0700589 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700590 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500591 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700592 if (uintValue != nullptr)
593 {
594 v = static_cast<int64_t>(*uintValue);
595 intValue = &v;
596 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700597 }
Ed Tanous66664f22019-10-11 13:05:49 -0700598 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700599 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500600 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700601 if (uintValue != nullptr)
602 {
603 d = static_cast<double>(*uintValue);
604 doubleValue = &d;
605 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700606 }
Ed Tanous66664f22019-10-11 13:05:49 -0700607 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700608 {
Ed Tanous66664f22019-10-11 13:05:49 -0700609 if (intValue != nullptr)
610 {
611 d = static_cast<double>(*intValue);
612 doubleValue = &d;
613 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700614 }
615
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700616 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700617 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700618 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700619 {
620 return -1;
621 }
Ed Tanous271584a2019-07-09 16:24:22 -0700622 r = sd_bus_message_append_basic(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500623 m, argCode[0], static_cast<const void*>(stringValue->data()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700624 if (r < 0)
625 {
626 return r;
627 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700628 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700629 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700630 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700631 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700632 {
633 return -1;
634 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500635 if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
636 (*intValue > std::numeric_limits<int32_t>::max()))
637 {
638 return -ERANGE;
639 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700640 int32_t i = static_cast<int32_t>(*intValue);
641 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700642 if (r < 0)
643 {
644 return r;
645 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700646 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700647 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700648 {
649 // lots of ways bool could be represented here. Try them all
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700650 int boolInt = false;
651 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700652 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500653 if (*intValue == 1)
654 {
655 boolInt = true;
656 }
657 else if (*intValue == 0)
658 {
659 boolInt = false;
660 }
661 else
662 {
663 return -ERANGE;
664 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700665 }
666 else if (b != nullptr)
667 {
Matt Spinlera2f02632019-01-18 10:15:35 -0600668 boolInt = *b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700669 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700670 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700671 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700672 boolInt = boost::istarts_with(*stringValue, "t") ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700673 }
674 else
675 {
676 return -1;
677 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700678 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700679 if (r < 0)
680 {
681 return r;
682 }
683 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700684 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700685 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700686 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700687 {
688 return -1;
689 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500690 if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
691 (*intValue > std::numeric_limits<int16_t>::max()))
692 {
693 return -ERANGE;
694 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700695 int16_t n = static_cast<int16_t>(*intValue);
696 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700697 if (r < 0)
698 {
699 return r;
700 }
701 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700702 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700703 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700704 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700705 {
706 return -1;
707 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700708 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700709 if (r < 0)
710 {
711 return r;
712 }
713 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700714 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700715 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500716 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700717 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700718 {
719 return -1;
720 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000721 if (*uintValue > std::numeric_limits<uint8_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500722 {
723 return -ERANGE;
724 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700725 uint8_t y = static_cast<uint8_t>(*uintValue);
726 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700727 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700728 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700729 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500730 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700731 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700732 {
733 return -1;
734 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000735 if (*uintValue > std::numeric_limits<uint16_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500736 {
737 return -ERANGE;
738 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700739 uint16_t q = static_cast<uint16_t>(*uintValue);
740 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700741 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700742 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700743 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500744 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700745 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700746 {
747 return -1;
748 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000749 if (*uintValue > std::numeric_limits<uint32_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500750 {
751 return -ERANGE;
752 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700753 uint32_t u = static_cast<uint32_t>(*uintValue);
754 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700755 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700756 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700757 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500758 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700759 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700760 {
761 return -1;
762 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700763 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700764 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700765 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700766 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500767 if (doubleValue == nullptr)
768 {
769 return -1;
770 }
771 if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
772 (*doubleValue > std::numeric_limits<double>::max()))
773 {
774 return -ERANGE;
775 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700776 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700777 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700778 else if (boost::starts_with(argCode, "a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700779 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700780 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700781 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700782 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700783 if (r < 0)
784 {
785 return r;
786 }
787
Ed Tanous0dfeda62019-10-24 11:21:38 -0700788 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700789 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700790 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700791 if (r < 0)
792 {
793 return r;
794 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700795 }
796 sd_bus_message_close_container(m);
797 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700798 else if (boost::starts_with(argCode, "v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700799 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700800 std::string containedType = argCode.substr(1);
801 BMCWEB_LOG_DEBUG << "variant type: " << argCode
802 << " appending variant of type: " << containedType;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700803 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700804 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700805 if (r < 0)
806 {
807 return r;
808 }
809
Ed Tanous81ce6092020-12-17 16:54:55 +0000810 r = convertJsonToDbus(m, containedType, inputJson);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700811 if (r < 0)
812 {
813 return r;
814 }
815
816 r = sd_bus_message_close_container(m);
817 if (r < 0)
818 {
819 return r;
820 }
821 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700822 else if (boost::starts_with(argCode, "(") &&
823 boost::ends_with(argCode, ")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700824 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700825 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700826 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700827 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800828 if (r < 0)
829 {
830 return r;
831 }
832
Ed Tanous1abe55e2018-09-05 08:30:59 -0700833 nlohmann::json::const_iterator it = j->begin();
Ed Tanous81ce6092020-12-17 16:54:55 +0000834 for (const std::string& argCode2 : dbusArgSplit(argType))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700835 {
836 if (it == j->end())
837 {
838 return -1;
839 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000840 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700841 if (r < 0)
842 {
843 return r;
844 }
845 it++;
846 }
847 r = sd_bus_message_close_container(m);
848 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700849 else if (boost::starts_with(argCode, "{") &&
850 boost::ends_with(argCode, "}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700851 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700852 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700853 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700854 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800855 if (r < 0)
856 {
857 return r;
858 }
859
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700860 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700861 if (codes.size() != 2)
862 {
863 return -1;
864 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700865 const std::string& keyType = codes[0];
866 const std::string& valueType = codes[1];
Ed Tanous3174e4d2020-10-07 11:41:22 -0700867 for (const auto& it : j->items())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700868 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700869 r = convertJsonToDbus(m, keyType, it.key());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700870 if (r < 0)
871 {
872 return r;
873 }
874
Ed Tanous2c70f802020-09-28 14:29:23 -0700875 r = convertJsonToDbus(m, valueType, it.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700876 if (r < 0)
877 {
878 return r;
879 }
880 }
881 r = sd_bus_message_close_container(m);
882 }
883 else
884 {
885 return -2;
886 }
887 if (r < 0)
888 {
889 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700890 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700891
Ed Tanous1abe55e2018-09-05 08:30:59 -0700892 if (argTypes.size() > 1)
893 {
894 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700895 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700896 }
Matt Spinler127ea542019-01-14 11:04:28 -0600897
898 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700899}
900
Matt Spinlerd22a7132019-01-14 12:14:30 -0600901template <typename T>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500902int readMessageItem(const std::string& typeCode, sdbusplus::message::message& m,
903 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600904{
905 T value;
906
907 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
908 if (r < 0)
909 {
910 BMCWEB_LOG_ERROR << "sd_bus_message_read_basic on type " << typeCode
911 << " failed!";
912 return r;
913 }
914
915 data = value;
916 return 0;
917}
918
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500919int convertDBusToJSON(const std::string& returnType,
920 sdbusplus::message::message& m, nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600921
Ed Tanous23a21a12020-07-25 04:45:05 +0000922inline int readDictEntryFromMessage(const std::string& typeCode,
923 sdbusplus::message::message& m,
924 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600925{
926 std::vector<std::string> types = dbusArgSplit(typeCode);
927 if (types.size() != 2)
928 {
929 BMCWEB_LOG_ERROR << "wrong number contained types in dictionary: "
930 << types.size();
931 return -1;
932 }
933
934 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
935 typeCode.c_str());
936 if (r < 0)
937 {
938 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container with rc " << r;
939 return r;
940 }
941
942 nlohmann::json key;
943 r = convertDBusToJSON(types[0], m, key);
944 if (r < 0)
945 {
946 return r;
947 }
948
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500949 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -0600950 if (keyPtr == nullptr)
951 {
952 // json doesn't support non-string keys. If we hit this condition,
953 // convert the result to a string so we can proceed
Ed Tanous71f52d92021-02-19 08:51:17 -0800954 key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500955 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -0700956 // in theory this can't fail now, but lets be paranoid about it
957 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -0600958 if (keyPtr == nullptr)
959 {
960 return -1;
961 }
962 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500963 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -0600964
965 r = convertDBusToJSON(types[1], m, value);
966 if (r < 0)
967 {
968 return r;
969 }
970
971 r = sd_bus_message_exit_container(m.get());
972 if (r < 0)
973 {
974 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
975 return r;
976 }
977
978 return 0;
979}
980
Ed Tanous23a21a12020-07-25 04:45:05 +0000981inline int readArrayFromMessage(const std::string& typeCode,
982 sdbusplus::message::message& m,
983 nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -0600984{
985 if (typeCode.size() < 2)
986 {
987 BMCWEB_LOG_ERROR << "Type code " << typeCode
988 << " too small for an array";
989 return -1;
990 }
991
992 std::string containedType = typeCode.substr(1);
993
994 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
995 containedType.c_str());
996 if (r < 0)
997 {
998 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
999 << r;
1000 return r;
1001 }
1002
1003 bool dict = boost::starts_with(containedType, "{") &&
1004 boost::ends_with(containedType, "}");
1005
1006 if (dict)
1007 {
1008 // Remove the { }
1009 containedType = containedType.substr(1, containedType.size() - 2);
1010 data = nlohmann::json::object();
1011 }
1012 else
1013 {
1014 data = nlohmann::json::array();
1015 }
1016
1017 while (true)
1018 {
1019 r = sd_bus_message_at_end(m.get(), false);
1020 if (r < 0)
1021 {
1022 BMCWEB_LOG_ERROR << "sd_bus_message_at_end failed";
1023 return r;
1024 }
1025
1026 if (r > 0)
1027 {
1028 break;
1029 }
1030
1031 // Dictionaries are only ever seen in an array
1032 if (dict)
1033 {
1034 r = readDictEntryFromMessage(containedType, m, data);
1035 if (r < 0)
1036 {
1037 return r;
1038 }
1039 }
1040 else
1041 {
1042 data.push_back(nlohmann::json());
1043
1044 r = convertDBusToJSON(containedType, m, data.back());
1045 if (r < 0)
1046 {
1047 return r;
1048 }
1049 }
1050 }
1051
1052 r = sd_bus_message_exit_container(m.get());
1053 if (r < 0)
1054 {
1055 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1056 return r;
1057 }
1058
1059 return 0;
1060}
1061
Ed Tanous23a21a12020-07-25 04:45:05 +00001062inline int readStructFromMessage(const std::string& typeCode,
1063 sdbusplus::message::message& m,
1064 nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001065{
1066 if (typeCode.size() < 3)
1067 {
1068 BMCWEB_LOG_ERROR << "Type code " << typeCode
1069 << " too small for a struct";
1070 return -1;
1071 }
1072
1073 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1074 std::vector<std::string> types = dbusArgSplit(containedTypes);
1075
1076 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1077 containedTypes.c_str());
1078 if (r < 0)
1079 {
1080 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1081 << r;
1082 return r;
1083 }
1084
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001085 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001086 {
1087 data.push_back(nlohmann::json());
1088 r = convertDBusToJSON(type, m, data.back());
1089 if (r < 0)
1090 {
1091 return r;
1092 }
1093 }
1094
1095 r = sd_bus_message_exit_container(m.get());
1096 if (r < 0)
1097 {
1098 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1099 return r;
1100 }
1101 return 0;
1102}
1103
Ed Tanous23a21a12020-07-25 04:45:05 +00001104inline int readVariantFromMessage(sdbusplus::message::message& m,
1105 nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001106{
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001107 const char* containerType;
Ed Tanous99131cd2019-10-24 11:12:47 -07001108 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001109 if (r < 0)
1110 {
1111 BMCWEB_LOG_ERROR << "sd_bus_message_peek_type failed";
1112 return r;
1113 }
1114
1115 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1116 containerType);
1117 if (r < 0)
1118 {
1119 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1120 << r;
1121 return r;
1122 }
1123
1124 r = convertDBusToJSON(containerType, m, data);
1125 if (r < 0)
1126 {
1127 return r;
1128 }
1129
1130 r = sd_bus_message_exit_container(m.get());
1131 if (r < 0)
1132 {
1133 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed";
1134 return r;
1135 }
1136
1137 return 0;
1138}
1139
Ed Tanous23a21a12020-07-25 04:45:05 +00001140inline int convertDBusToJSON(const std::string& returnType,
1141 sdbusplus::message::message& m,
1142 nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001143{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001144 int r = 0;
1145 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1146
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001147 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001148 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001149 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001150 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001151 {
1152 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001153 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001154 }
1155
Ed Tanousd4d25792020-09-29 15:15:03 -07001156 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001157 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001158 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001159 if (r < 0)
1160 {
1161 return r;
1162 }
1163 }
1164 else if (typeCode == "b")
1165 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001166 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001167 if (r < 0)
1168 {
1169 return r;
1170 }
1171
Matt Spinlerf39420c2019-01-30 12:57:18 -06001172 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001173 }
1174 else if (typeCode == "u")
1175 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001176 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001177 if (r < 0)
1178 {
1179 return r;
1180 }
1181 }
1182 else if (typeCode == "i")
1183 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001184 r = readMessageItem<int32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001185 if (r < 0)
1186 {
1187 return r;
1188 }
1189 }
1190 else if (typeCode == "x")
1191 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001192 r = readMessageItem<int64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001193 if (r < 0)
1194 {
1195 return r;
1196 }
1197 }
1198 else if (typeCode == "t")
1199 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001200 r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001201 if (r < 0)
1202 {
1203 return r;
1204 }
1205 }
1206 else if (typeCode == "n")
1207 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001208 r = readMessageItem<int16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001209 if (r < 0)
1210 {
1211 return r;
1212 }
1213 }
1214 else if (typeCode == "q")
1215 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001216 r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001217 if (r < 0)
1218 {
1219 return r;
1220 }
1221 }
1222 else if (typeCode == "y")
1223 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001224 r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001225 if (r < 0)
1226 {
1227 return r;
1228 }
1229 }
1230 else if (typeCode == "d")
1231 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001232 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001233 if (r < 0)
1234 {
1235 return r;
1236 }
1237 }
1238 else if (typeCode == "h")
1239 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001240 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001241 if (r < 0)
1242 {
1243 return r;
1244 }
1245 }
Matt Spinler6df8f992019-01-14 12:47:47 -06001246 else if (boost::starts_with(typeCode, "a"))
1247 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001248 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001249 if (r < 0)
1250 {
1251 return r;
1252 }
1253 }
Matt Spinler75c6c672019-01-14 13:01:46 -06001254 else if (boost::starts_with(typeCode, "(") &&
1255 boost::ends_with(typeCode, ")"))
1256 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001257 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001258 if (r < 0)
1259 {
1260 return r;
1261 }
1262 }
Matt Spinler89c19702019-01-14 13:13:00 -06001263 else if (boost::starts_with(typeCode, "v"))
1264 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001265 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001266 if (r < 0)
1267 {
1268 return r;
1269 }
1270 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001271 else
1272 {
Matt Spinlerd22a7132019-01-14 12:14:30 -06001273 BMCWEB_LOG_ERROR << "Invalid D-Bus signature type " << typeCode;
1274 return -2;
1275 }
1276 }
1277
Matt Spinler16caaee2019-01-15 11:40:34 -06001278 return 0;
1279}
1280
Ed Tanousb5a76932020-09-29 16:16:58 -07001281inline void handleMethodResponse(
1282 const std::shared_ptr<InProgressActionData>& transaction,
1283 sdbusplus::message::message& m, const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001284{
Matt Spinler39a4e392019-01-15 11:53:13 -06001285 nlohmann::json data;
1286
1287 int r = convertDBusToJSON(returnType, m, data);
1288 if (r < 0)
1289 {
1290 transaction->outputFailed = true;
1291 return;
1292 }
1293
1294 if (data.is_null())
1295 {
1296 return;
1297 }
1298
1299 if (transaction->methodResponse.is_null())
1300 {
1301 transaction->methodResponse = std::move(data);
1302 return;
1303 }
1304
1305 // If they're both dictionaries or arrays, merge into one.
1306 // Otherwise, make the results an array with every result
1307 // an entry. Could also just fail in that case, but it
1308 // seems better to get the data back somehow.
1309
1310 if (transaction->methodResponse.is_object() && data.is_object())
1311 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001312 for (const auto& obj : data.items())
Matt Spinler39a4e392019-01-15 11:53:13 -06001313 {
1314 // Note: Will overwrite the data for a duplicate key
1315 transaction->methodResponse.emplace(obj.key(),
1316 std::move(obj.value()));
1317 }
1318 return;
1319 }
1320
1321 if (transaction->methodResponse.is_array() && data.is_array())
1322 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001323 for (auto& obj : data)
Matt Spinler39a4e392019-01-15 11:53:13 -06001324 {
1325 transaction->methodResponse.push_back(std::move(obj));
1326 }
1327 return;
1328 }
1329
1330 if (!transaction->convertedToArray)
1331 {
1332 // They are different types. May as well turn them into an array
1333 nlohmann::json j = std::move(transaction->methodResponse);
1334 transaction->methodResponse = nlohmann::json::array();
1335 transaction->methodResponse.push_back(std::move(j));
1336 transaction->methodResponse.push_back(std::move(data));
1337 transaction->convertedToArray = true;
1338 }
1339 else
1340 {
1341 transaction->methodResponse.push_back(std::move(data));
1342 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001343}
1344
Ed Tanousb5a76932020-09-29 16:16:58 -07001345inline void findActionOnInterface(
1346 const std::shared_ptr<InProgressActionData>& transaction,
1347 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001348{
1349 BMCWEB_LOG_DEBUG << "findActionOnInterface for connection "
1350 << connectionName;
1351 crow::connections::systemBus->async_method_call(
1352 [transaction, connectionName{std::string(connectionName)}](
1353 const boost::system::error_code ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001354 const std::string& introspectXml) {
1355 BMCWEB_LOG_DEBUG << "got xml:\n " << introspectXml;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001356 if (ec)
1357 {
1358 BMCWEB_LOG_ERROR
1359 << "Introspect call failed with error: " << ec.message()
1360 << " on process: " << connectionName << "\n";
Matt Spinler318bd892019-01-15 09:59:20 -06001361 return;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001362 }
Matt Spinler318bd892019-01-15 09:59:20 -06001363 tinyxml2::XMLDocument doc;
1364
Ed Tanous81ce6092020-12-17 16:54:55 +00001365 doc.Parse(introspectXml.data(), introspectXml.size());
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001366 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
Matt Spinler318bd892019-01-15 09:59:20 -06001367 if (pRoot == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001368 {
Matt Spinler318bd892019-01-15 09:59:20 -06001369 BMCWEB_LOG_ERROR << "XML document failed to parse "
1370 << connectionName << "\n";
1371 return;
1372 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001373 tinyxml2::XMLElement* interfaceNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001374 pRoot->FirstChildElement("interface");
1375 while (interfaceNode != nullptr)
1376 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001377 const char* thisInterfaceName =
Matt Spinler318bd892019-01-15 09:59:20 -06001378 interfaceNode->Attribute("name");
1379 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001380 {
Matt Spinler318bd892019-01-15 09:59:20 -06001381 if (!transaction->interfaceName.empty() &&
1382 (transaction->interfaceName != thisInterfaceName))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001383 {
Matt Spinler318bd892019-01-15 09:59:20 -06001384 interfaceNode =
1385 interfaceNode->NextSiblingElement("interface");
1386 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001387 }
Matt Spinler318bd892019-01-15 09:59:20 -06001388
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001389 tinyxml2::XMLElement* methodNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001390 interfaceNode->FirstChildElement("method");
1391 while (methodNode != nullptr)
1392 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001393 const char* thisMethodName =
Matt Spinler318bd892019-01-15 09:59:20 -06001394 methodNode->Attribute("name");
1395 BMCWEB_LOG_DEBUG << "Found method: " << thisMethodName;
1396 if (thisMethodName != nullptr &&
1397 thisMethodName == transaction->methodName)
1398 {
1399 BMCWEB_LOG_DEBUG
1400 << "Found method named " << thisMethodName
1401 << " on interface " << thisInterfaceName;
1402 sdbusplus::message::message m =
1403 crow::connections::systemBus->new_method_call(
1404 connectionName.c_str(),
1405 transaction->path.c_str(),
1406 thisInterfaceName,
1407 transaction->methodName.c_str());
1408
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001409 tinyxml2::XMLElement* argumentNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001410 methodNode->FirstChildElement("arg");
1411
Matt Spinler16caaee2019-01-15 11:40:34 -06001412 std::string returnType;
1413
1414 // Find the output type
1415 while (argumentNode != nullptr)
1416 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001417 const char* argDirection =
Matt Spinler16caaee2019-01-15 11:40:34 -06001418 argumentNode->Attribute("direction");
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001419 const char* argType =
Matt Spinler16caaee2019-01-15 11:40:34 -06001420 argumentNode->Attribute("type");
1421 if (argDirection != nullptr &&
1422 argType != nullptr &&
1423 std::string(argDirection) == "out")
1424 {
1425 returnType = argType;
1426 break;
1427 }
1428 argumentNode =
1429 argumentNode->NextSiblingElement("arg");
1430 }
1431
Matt Spinler318bd892019-01-15 09:59:20 -06001432 nlohmann::json::const_iterator argIt =
1433 transaction->arguments.begin();
1434
Matt Spinler16caaee2019-01-15 11:40:34 -06001435 argumentNode = methodNode->FirstChildElement("arg");
1436
Matt Spinler318bd892019-01-15 09:59:20 -06001437 while (argumentNode != nullptr)
1438 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001439 const char* argDirection =
Matt Spinler318bd892019-01-15 09:59:20 -06001440 argumentNode->Attribute("direction");
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001441 const char* argType =
Matt Spinler318bd892019-01-15 09:59:20 -06001442 argumentNode->Attribute("type");
1443 if (argDirection != nullptr &&
1444 argType != nullptr &&
1445 std::string(argDirection) == "in")
1446 {
1447 if (argIt == transaction->arguments.end())
1448 {
1449 transaction->setErrorStatus(
1450 "Invalid method args");
1451 return;
1452 }
1453 if (convertJsonToDbus(m.get(),
1454 std::string(argType),
1455 *argIt) < 0)
1456 {
1457 transaction->setErrorStatus(
1458 "Invalid method arg type");
1459 return;
1460 }
1461
1462 argIt++;
1463 }
1464 argumentNode =
1465 argumentNode->NextSiblingElement("arg");
1466 }
1467
1468 crow::connections::systemBus->async_send(
Matt Spinler16caaee2019-01-15 11:40:34 -06001469 m, [transaction, returnType](
Ed Tanous23a21a12020-07-25 04:45:05 +00001470 boost::system::error_code ec2,
1471 sdbusplus::message::message& m2) {
1472 if (ec2)
Matt Spinler318bd892019-01-15 09:59:20 -06001473 {
Matt Spinler16caaee2019-01-15 11:40:34 -06001474 transaction->methodFailed = true;
Ed Tanous23a21a12020-07-25 04:45:05 +00001475 const sd_bus_error* e = m2.get_error();
Matt Spinler06b1b632019-06-18 16:09:25 -05001476
1477 if (e)
1478 {
1479 setErrorResponse(
1480 transaction->res,
1481 boost::beast::http::status::
1482 bad_request,
1483 e->name, e->message);
1484 }
1485 else
1486 {
1487 setErrorResponse(
1488 transaction->res,
1489 boost::beast::http::status::
1490 bad_request,
1491 "Method call failed",
1492 methodFailedMsg);
1493 }
Matt Spinler318bd892019-01-15 09:59:20 -06001494 return;
1495 }
Ed Tanous3174e4d2020-10-07 11:41:22 -07001496 transaction->methodPassed = true;
Matt Spinler16caaee2019-01-15 11:40:34 -06001497
Ed Tanous23a21a12020-07-25 04:45:05 +00001498 handleMethodResponse(transaction, m2,
Matt Spinler16caaee2019-01-15 11:40:34 -06001499 returnType);
Matt Spinler318bd892019-01-15 09:59:20 -06001500 });
1501 break;
1502 }
1503 methodNode = methodNode->NextSiblingElement("method");
1504 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001505 }
Matt Spinler318bd892019-01-15 09:59:20 -06001506 interfaceNode = interfaceNode->NextSiblingElement("interface");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001507 }
1508 },
1509 connectionName, transaction->path,
1510 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001511}
1512
zhanghch058d1b46d2021-04-01 11:18:24 +08001513inline void handleAction(const crow::Request& req,
1514 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001515 const std::string& objectPath,
1516 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001517{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001518 BMCWEB_LOG_DEBUG << "handleAction on path: " << objectPath << " and method "
1519 << methodName;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001520 nlohmann::json requestDbusData =
1521 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001522
Ed Tanous1abe55e2018-09-05 08:30:59 -07001523 if (requestDbusData.is_discarded())
1524 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001525 setErrorResponse(asyncResp->res,
1526 boost::beast::http::status::bad_request, noJsonDesc,
1527 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001528 return;
1529 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001530 nlohmann::json::iterator data = requestDbusData.find("data");
1531 if (data == requestDbusData.end())
1532 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001533 setErrorResponse(asyncResp->res,
1534 boost::beast::http::status::bad_request, noJsonDesc,
1535 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001536 return;
1537 }
1538
1539 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001540 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001541 setErrorResponse(asyncResp->res,
1542 boost::beast::http::status::bad_request, noJsonDesc,
1543 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001544 return;
1545 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001546 auto transaction = std::make_shared<InProgressActionData>(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001547
1548 transaction->path = objectPath;
1549 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001550 transaction->arguments = std::move(*data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001551 crow::connections::systemBus->async_method_call(
1552 [transaction](
1553 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) {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001556 if (ec || interfaceNames.size() <= 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001557 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001558 BMCWEB_LOG_ERROR << "Can't find object";
Matt Spinler6db06242018-12-11 11:21:22 -06001559 setErrorResponse(transaction->res,
1560 boost::beast::http::status::not_found,
1561 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001562 return;
1563 }
1564
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001565 BMCWEB_LOG_DEBUG << "GetObject returned " << interfaceNames.size()
1566 << " object(s)";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001567
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001568 for (const std::pair<std::string, std::vector<std::string>>&
1569 object : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001570 {
1571 findActionOnInterface(transaction, object.first);
1572 }
1573 },
1574 "xyz.openbmc_project.ObjectMapper",
1575 "/xyz/openbmc_project/object_mapper",
1576 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
1577 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001578}
1579
zhanghch058d1b46d2021-04-01 11:18:24 +08001580inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1581 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001582{
1583 BMCWEB_LOG_DEBUG << "handleDelete on path: " << objectPath;
1584
1585 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +08001586 [asyncResp, objectPath](
Matt Spinlerde818812018-12-11 16:39:20 -06001587 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001588 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1589 interfaceNames) {
Matt Spinlerde818812018-12-11 16:39:20 -06001590 if (ec || interfaceNames.size() <= 0)
1591 {
1592 BMCWEB_LOG_ERROR << "Can't find object";
zhanghch058d1b46d2021-04-01 11:18:24 +08001593 setErrorResponse(asyncResp->res,
Matt Spinler62d2e8b2019-01-22 13:45:51 -06001594 boost::beast::http::status::method_not_allowed,
1595 methodNotAllowedDesc, methodNotAllowedMsg);
Matt Spinlerde818812018-12-11 16:39:20 -06001596 return;
1597 }
1598
zhanghch058d1b46d2021-04-01 11:18:24 +08001599 auto transaction =
1600 std::make_shared<InProgressActionData>(asyncResp->res);
Matt Spinlerde818812018-12-11 16:39:20 -06001601 transaction->path = objectPath;
1602 transaction->methodName = "Delete";
1603 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
1604
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001605 for (const std::pair<std::string, std::vector<std::string>>&
1606 object : interfaceNames)
Matt Spinlerde818812018-12-11 16:39:20 -06001607 {
1608 findActionOnInterface(transaction, object.first);
1609 }
1610 },
1611 "xyz.openbmc_project.ObjectMapper",
1612 "/xyz/openbmc_project/object_mapper",
1613 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001614 std::array<const char*, 0>());
Matt Spinlerde818812018-12-11 16:39:20 -06001615}
1616
zhanghch058d1b46d2021-04-01 11:18:24 +08001617inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1618 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001619{
1620 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +08001621 [asyncResp](const boost::system::error_code ec,
Ed Tanous914e2d52022-01-07 11:38:34 -08001622 const std::vector<std::string>& objectPaths) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001623 if (ec)
1624 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001625 setErrorResponse(asyncResp->res,
1626 boost::beast::http::status::not_found,
Matt Spinlerd6091dd2018-12-06 14:08:27 -06001627 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001628 }
1629 else
1630 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001631 asyncResp->res.jsonValue = {{"status", "ok"},
1632 {"message", "200 OK"},
Ed Tanous914e2d52022-01-07 11:38:34 -08001633 {"data", objectPaths}};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001634 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001635 },
1636 "xyz.openbmc_project.ObjectMapper",
1637 "/xyz/openbmc_project/object_mapper",
1638 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", objectPath,
Ed Tanousf839dfe2018-11-12 11:11:15 -08001639 depth, std::array<std::string, 0>());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001640}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001641
zhanghch058d1b46d2021-04-01 11:18:24 +08001642inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1643 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001644{
Ed Tanous049a0512018-11-01 13:58:42 -07001645 BMCWEB_LOG_DEBUG << "Doing enumerate on " << objectPath;
Ed Tanous049a0512018-11-01 13:58:42 -07001646
1647 asyncResp->res.jsonValue = {{"message", "200 OK"},
1648 {"status", "ok"},
1649 {"data", nlohmann::json::object()}};
1650
Ed Tanous1abe55e2018-09-05 08:30:59 -07001651 crow::connections::systemBus->async_method_call(
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001652 [objectPath, asyncResp](const boost::system::error_code ec,
Ed Tanous914e2d52022-01-07 11:38:34 -08001653 const GetSubTreeType& objectNames) {
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001654 auto transaction = std::make_shared<InProgressEnumerateData>(
1655 objectPath, asyncResp);
1656
1657 transaction->subtree =
Ed Tanous914e2d52022-01-07 11:38:34 -08001658 std::make_shared<GetSubTreeType>(objectNames);
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001659
Ed Tanous1abe55e2018-09-05 08:30:59 -07001660 if (ec)
1661 {
Matt Spinler2ae60092018-12-06 10:35:36 -06001662 BMCWEB_LOG_ERROR << "GetSubTree failed on "
1663 << transaction->objectPath;
1664 setErrorResponse(transaction->asyncResp->res,
1665 boost::beast::http::status::not_found,
1666 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001667 return;
1668 }
Ed Tanous64530012018-02-06 17:08:16 -08001669
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001670 // Add the data for the path passed in to the results
1671 // as if GetSubTree returned it, and continue on enumerating
1672 getObjectAndEnumerate(transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001673 },
1674 "xyz.openbmc_project.ObjectMapper",
1675 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -07001676 "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath, 0,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001677 std::array<const char*, 0>());
Ed Tanous64530012018-02-06 17:08:16 -08001678}
Ed Tanous911ac312017-08-15 09:37:42 -07001679
zhanghch058d1b46d2021-04-01 11:18:24 +08001680inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1681 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001682{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001683 BMCWEB_LOG_DEBUG << "handleGet: " << objectPath << " prop:" << destProperty;
1684 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001685 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001686
Ed Tanous1abe55e2018-09-05 08:30:59 -07001687 std::shared_ptr<std::string> path =
1688 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001689
Ed Tanous1abe55e2018-09-05 08:30:59 -07001690 using GetObjectType =
1691 std::vector<std::pair<std::string, std::vector<std::string>>>;
1692 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +08001693 [asyncResp, path, propertyName](const boost::system::error_code ec,
1694 const GetObjectType& objectNames) {
Ed Tanous81ce6092020-12-17 16:54:55 +00001695 if (ec || objectNames.size() <= 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001696 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001697 setErrorResponse(asyncResp->res,
1698 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001699 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001700 return;
1701 }
1702 std::shared_ptr<nlohmann::json> response =
1703 std::make_shared<nlohmann::json>(nlohmann::json::object());
Ed Tanous7c091622019-05-23 11:42:36 -07001704 // The mapper should never give us an empty interface names
1705 // list, but check anyway
Ed Tanous23a21a12020-07-25 04:45:05 +00001706 for (const std::pair<std::string, std::vector<std::string>>&
Ed Tanous81ce6092020-12-17 16:54:55 +00001707 connection : objectNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001708 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001709 const std::vector<std::string>& interfaceNames =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001710 connection.second;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001711
Ed Tanous1abe55e2018-09-05 08:30:59 -07001712 if (interfaceNames.size() <= 0)
1713 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001714 setErrorResponse(asyncResp->res,
1715 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001716 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001717 return;
1718 }
1719
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001720 for (const std::string& interface : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001721 {
Matt Spinlerfe7e97d2019-01-30 15:33:21 -06001722 sdbusplus::message::message m =
1723 crow::connections::systemBus->new_method_call(
1724 connection.first.c_str(), path->c_str(),
1725 "org.freedesktop.DBus.Properties", "GetAll");
1726 m.append(interface);
1727 crow::connections::systemBus->async_send(
zhanghch058d1b46d2021-04-01 11:18:24 +08001728 m, [asyncResp, response,
Ed Tanous23a21a12020-07-25 04:45:05 +00001729 propertyName](const boost::system::error_code ec2,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001730 sdbusplus::message::message& msg) {
Ed Tanous23a21a12020-07-25 04:45:05 +00001731 if (ec2)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001732 {
1733 BMCWEB_LOG_ERROR << "Bad dbus request error: "
Ed Tanous23a21a12020-07-25 04:45:05 +00001734 << ec2;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001735 }
1736 else
1737 {
Ed Tanous984a4c22021-06-02 13:38:26 -07001738 nlohmann::json properties;
1739 int r =
1740 convertDBusToJSON("a{sv}", msg, properties);
1741 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001742 {
Ed Tanous984a4c22021-06-02 13:38:26 -07001743 BMCWEB_LOG_ERROR
1744 << "convertDBusToJSON failed";
1745 }
1746 else
1747 {
1748 for (auto& prop : properties.items())
1749 {
1750 // if property name is empty, or
1751 // matches our search query, add it
1752 // to the response json
Ed Tanous1abe55e2018-09-05 08:30:59 -07001753
Ed Tanous984a4c22021-06-02 13:38:26 -07001754 if (propertyName->empty())
1755 {
1756 (*response)[prop.key()] =
1757 std::move(prop.value());
1758 }
1759 else if (prop.key() == *propertyName)
1760 {
1761 *response = std::move(prop.value());
1762 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001763 }
1764 }
1765 }
1766 if (response.use_count() == 1)
1767 {
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001768 if (!propertyName->empty() && response->empty())
1769 {
1770 setErrorResponse(
zhanghch058d1b46d2021-04-01 11:18:24 +08001771 asyncResp->res,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001772 boost::beast::http::status::not_found,
1773 propNotFoundDesc, notFoundMsg);
1774 }
1775 else
1776 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001777 asyncResp->res.jsonValue = {
1778 {"status", "ok"},
1779 {"message", "200 OK"},
1780 {"data", *response}};
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001781 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001782 }
Matt Spinlerfe7e97d2019-01-30 15:33:21 -06001783 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001784 }
1785 }
1786 },
1787 "xyz.openbmc_project.ObjectMapper",
1788 "/xyz/openbmc_project/object_mapper",
1789 "xyz.openbmc_project.ObjectMapper", "GetObject", *path,
1790 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001791}
1792
Ed Tanous1abe55e2018-09-05 08:30:59 -07001793struct AsyncPutRequest
1794{
zhanghch058d1b46d2021-04-01 11:18:24 +08001795 AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
1796 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001797 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001798 ~AsyncPutRequest()
1799 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001800 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001801 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001802 setErrorResponse(asyncResp->res,
1803 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001804 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001805 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001806 }
1807
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001808 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001809 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001810 setErrorResponse(asyncResp->res,
1811 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001812 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001813 }
1814
zhanghch058d1b46d2021-04-01 11:18:24 +08001815 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001816 std::string objectPath;
1817 std::string propertyName;
1818 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001819};
1820
zhanghch058d1b46d2021-04-01 11:18:24 +08001821inline void handlePut(const crow::Request& req,
1822 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001823 const std::string& objectPath,
1824 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001825{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001826 if (destProperty.empty())
1827 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001828 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001829 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001830 return;
1831 }
1832
Ed Tanous1abe55e2018-09-05 08:30:59 -07001833 nlohmann::json requestDbusData =
1834 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001835
Ed Tanous1abe55e2018-09-05 08:30:59 -07001836 if (requestDbusData.is_discarded())
1837 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001838 setErrorResponse(asyncResp->res,
1839 boost::beast::http::status::bad_request, noJsonDesc,
1840 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001841 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001842 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001843
Ed Tanous1abe55e2018-09-05 08:30:59 -07001844 nlohmann::json::const_iterator propertyIt = requestDbusData.find("data");
1845 if (propertyIt == requestDbusData.end())
1846 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001847 setErrorResponse(asyncResp->res,
1848 boost::beast::http::status::bad_request, noJsonDesc,
1849 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001850 return;
1851 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001852 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001853 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001854 transaction->objectPath = objectPath;
1855 transaction->propertyName = destProperty;
1856 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001857
Ed Tanous1abe55e2018-09-05 08:30:59 -07001858 using GetObjectType =
1859 std::vector<std::pair<std::string, std::vector<std::string>>>;
Ed Tanous911ac312017-08-15 09:37:42 -07001860
Ed Tanous1abe55e2018-09-05 08:30:59 -07001861 crow::connections::systemBus->async_method_call(
Ed Tanous23a21a12020-07-25 04:45:05 +00001862 [transaction](const boost::system::error_code ec2,
Ed Tanous81ce6092020-12-17 16:54:55 +00001863 const GetObjectType& objectNames) {
1864 if (!ec2 && objectNames.size() <= 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001865 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001866 setErrorResponse(transaction->asyncResp->res,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001867 boost::beast::http::status::not_found,
1868 propNotFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001869 return;
1870 }
Ed Tanous911ac312017-08-15 09:37:42 -07001871
Ed Tanous23a21a12020-07-25 04:45:05 +00001872 for (const std::pair<std::string, std::vector<std::string>>&
Ed Tanous81ce6092020-12-17 16:54:55 +00001873 connection : objectNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001874 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001875 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001876
Ed Tanous1abe55e2018-09-05 08:30:59 -07001877 crow::connections::systemBus->async_method_call(
1878 [connectionName{std::string(connectionName)},
Ed Tanous23a21a12020-07-25 04:45:05 +00001879 transaction](const boost::system::error_code ec3,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001880 const std::string& introspectXml) {
Ed Tanous23a21a12020-07-25 04:45:05 +00001881 if (ec3)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001882 {
1883 BMCWEB_LOG_ERROR
1884 << "Introspect call failed with error: "
Ed Tanous23a21a12020-07-25 04:45:05 +00001885 << ec3.message()
Ed Tanous1abe55e2018-09-05 08:30:59 -07001886 << " on process: " << connectionName;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001887 transaction->setErrorStatus("Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001888 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001889 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001890 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001891
Ed Tanous1abe55e2018-09-05 08:30:59 -07001892 doc.Parse(introspectXml.c_str());
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001893 tinyxml2::XMLNode* pRoot =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001894 doc.FirstChildElement("node");
1895 if (pRoot == nullptr)
1896 {
1897 BMCWEB_LOG_ERROR << "XML document failed to parse: "
1898 << introspectXml;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001899 transaction->setErrorStatus("Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001900 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001901 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001902 tinyxml2::XMLElement* ifaceNode =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001903 pRoot->FirstChildElement("interface");
1904 while (ifaceNode != nullptr)
1905 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001906 const char* interfaceName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001907 ifaceNode->Attribute("name");
1908 BMCWEB_LOG_DEBUG << "found interface "
1909 << interfaceName;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001910 tinyxml2::XMLElement* propNode =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001911 ifaceNode->FirstChildElement("property");
1912 while (propNode != nullptr)
1913 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001914 const char* propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001915 propNode->Attribute("name");
1916 BMCWEB_LOG_DEBUG << "Found property "
1917 << propertyName;
1918 if (propertyName == transaction->propertyName)
1919 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001920 const char* argType =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001921 propNode->Attribute("type");
1922 if (argType != nullptr)
1923 {
1924 sdbusplus::message::message m =
1925 crow::connections::systemBus
1926 ->new_method_call(
1927 connectionName.c_str(),
1928 transaction->objectPath
1929 .c_str(),
1930 "org.freedesktop.DBus."
1931 "Properties",
1932 "Set");
1933 m.append(interfaceName,
1934 transaction->propertyName);
1935 int r = sd_bus_message_open_container(
1936 m.get(), SD_BUS_TYPE_VARIANT,
1937 argType);
1938 if (r < 0)
1939 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001940 transaction->setErrorStatus(
1941 "Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001942 return;
1943 }
1944 r = convertJsonToDbus(
1945 m.get(), argType,
1946 transaction->propertyValue);
1947 if (r < 0)
1948 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -05001949 if (r == -ERANGE)
1950 {
1951 transaction->setErrorStatus(
1952 "Provided property value "
1953 "is out of range for the "
1954 "property type");
1955 }
1956 else
1957 {
1958 transaction->setErrorStatus(
1959 "Invalid arg type");
1960 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001961 return;
1962 }
1963 r = sd_bus_message_close_container(
1964 m.get());
1965 if (r < 0)
1966 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001967 transaction->setErrorStatus(
1968 "Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001969 return;
1970 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001971 crow::connections::systemBus
1972 ->async_send(
1973 m,
1974 [transaction](
1975 boost::system::error_code
1976 ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001977 sdbusplus::message::message&
Ed Tanous23a21a12020-07-25 04:45:05 +00001978 m2) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001979 BMCWEB_LOG_DEBUG << "sent";
1980 if (ec)
1981 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001982 const sd_bus_error* e =
Ed Tanous23a21a12020-07-25 04:45:05 +00001983 m2.get_error();
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001984 setErrorResponse(
zhanghch058d1b46d2021-04-01 11:18:24 +08001985 transaction
1986 ->asyncResp
1987 ->res,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001988 boost::beast::http::
1989 status::
1990 forbidden,
Matt Spinler06b1b632019-06-18 16:09:25 -05001991 (e) ? e->name
1992 : ec.category()
1993 .name(),
1994 (e) ? e->message
1995 : ec.message());
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001996 }
1997 else
1998 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001999 transaction->asyncResp
2000 ->res.jsonValue = {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06002001 {"status", "ok"},
2002 {"message",
2003 "200 OK"},
2004 {"data", nullptr}};
Ed Tanous1abe55e2018-09-05 08:30:59 -07002005 }
2006 });
2007 }
2008 }
2009 propNode =
2010 propNode->NextSiblingElement("property");
2011 }
2012 ifaceNode =
2013 ifaceNode->NextSiblingElement("interface");
2014 }
2015 },
2016 connectionName, transaction->objectPath,
2017 "org.freedesktop.DBus.Introspectable", "Introspect");
2018 }
2019 },
2020 "xyz.openbmc_project.ObjectMapper",
2021 "/xyz/openbmc_project/object_mapper",
2022 "xyz.openbmc_project.ObjectMapper", "GetObject",
2023 transaction->objectPath, std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07002024}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002025
zhanghch058d1b46d2021-04-01 11:18:24 +08002026inline void handleDBusUrl(const crow::Request& req,
2027 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002028 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002029{
Ed Tanous049a0512018-11-01 13:58:42 -07002030
2031 // If accessing a single attribute, fill in and update objectPath,
2032 // otherwise leave destProperty blank
2033 std::string destProperty = "";
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002034 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002035 size_t attrPosition = objectPath.find(attrSeperator);
2036 if (attrPosition != objectPath.npos)
2037 {
2038 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2039 objectPath.length());
2040 objectPath = objectPath.substr(0, attrPosition);
2041 }
2042
Ed Tanousb41187f2019-10-24 16:30:02 -07002043 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002044 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002045 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002046 size_t actionPosition = objectPath.find(actionSeperator);
2047 if (actionPosition != objectPath.npos)
2048 {
2049 std::string postProperty =
2050 objectPath.substr((actionPosition + strlen(actionSeperator)),
2051 objectPath.length());
2052 objectPath = objectPath.substr(0, actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002053 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002054 return;
2055 }
2056 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002057 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002058 {
2059 if (boost::ends_with(objectPath, "/enumerate"))
2060 {
2061 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2062 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002063 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002064 }
2065 else if (boost::ends_with(objectPath, "/list"))
2066 {
2067 objectPath.erase(objectPath.end() - sizeof("list"),
2068 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002069 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002070 }
2071 else
2072 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002073 // Trim any trailing "/" at the end
2074 if (boost::ends_with(objectPath, "/"))
2075 {
2076 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002077 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002078 }
2079 else
2080 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002081 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002082 }
Ed Tanous049a0512018-11-01 13:58:42 -07002083 }
2084 return;
2085 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002086 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002087 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002088 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002089 return;
2090 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002091 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002092 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002093 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002094 return;
2095 }
Ed Tanous049a0512018-11-01 13:58:42 -07002096
zhanghch058d1b46d2021-04-01 11:18:24 +08002097 setErrorResponse(asyncResp->res,
2098 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002099 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002100}
2101
Ed Tanous23a21a12020-07-25 04:45:05 +00002102inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002103{
2104 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002105 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002106 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002107 [](const crow::Request&,
2108 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2109 asyncResp->res.jsonValue = {{"buses", {{{"name", "system"}}}},
2110 {"status", "ok"}};
Ed Tanous1abe55e2018-09-05 08:30:59 -07002111 });
2112
2113 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002114 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002115 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002116 [](const crow::Request&,
2117 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
P Dheeraj Srujan Kumar83fd8e12021-07-13 02:53:03 +05302118 auto myCallback = [asyncResp](
zhanghch058d1b46d2021-04-01 11:18:24 +08002119 const boost::system::error_code ec,
2120 std::vector<std::string>& names) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07002121 if (ec)
2122 {
2123 BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +08002124 asyncResp->res.result(
Ed Tanous1abe55e2018-09-05 08:30:59 -07002125 boost::beast::http::status::internal_server_error);
2126 }
2127 else
2128 {
2129 std::sort(names.begin(), names.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002130 asyncResp->res.jsonValue = {{"status", "ok"}};
2131 auto& objectsSub = asyncResp->res.jsonValue["objects"];
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002132 for (auto& name : names)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002133 {
2134 objectsSub.push_back({{"name", name}});
2135 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002136 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002137 };
2138 crow::connections::systemBus->async_method_call(
2139 std::move(myCallback), "org.freedesktop.DBus", "/",
2140 "org.freedesktop.DBus", "ListNames");
2141 });
2142
2143 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002144 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002145 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002146 [](const crow::Request&,
2147 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2148 handleList(asyncResp, "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07002149 });
2150
2151 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002152 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002153 .methods(boost::beast::http::verb::get)(
2154 [](const crow::Request& req,
2155 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002156 const std::string& path) {
Ed Tanous049a0512018-11-01 13:58:42 -07002157 std::string objectPath = "/xyz/" + path;
zhanghch058d1b46d2021-04-01 11:18:24 +08002158 handleDBusUrl(req, asyncResp, objectPath);
2159 });
2160
2161 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002162 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002163 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2164 boost::beast::http::verb::delete_)(
2165 [](const crow::Request& req,
2166 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2167 const std::string& path) {
2168 std::string objectPath = "/xyz/" + path;
2169 handleDBusUrl(req, asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002170 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002171
Ed Tanous049a0512018-11-01 13:58:42 -07002172 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002173 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002174 .methods(boost::beast::http::verb::get)(
2175 [](const crow::Request& req,
2176 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2177 const std::string& path) {
2178 std::string objectPath = "/org/" + path;
2179 handleDBusUrl(req, asyncResp, objectPath);
2180 });
Tanousf00032d2018-11-05 01:18:10 -03002181
2182 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002183 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002184 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2185 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002186 [](const crow::Request& req,
2187 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002188 const std::string& path) {
Ed Tanouse1281402019-04-03 07:07:10 -07002189 std::string objectPath = "/org/" + path;
zhanghch058d1b46d2021-04-01 11:18:24 +08002190 handleDBusUrl(req, asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002191 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002192
Ed Tanous1abe55e2018-09-05 08:30:59 -07002193 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002194 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002195 .methods(boost::beast::http::verb::get)(
2196 [](const crow::Request&,
2197 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2198 const std::string& dumpId) {
2199 std::regex validFilename(R"(^[\w\- ]+(\.?[\w\- ]*)$)");
2200 if (!std::regex_match(dumpId, validFilename))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002201 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002202 asyncResp->res.result(
2203 boost::beast::http::status::bad_request);
Ramesh Iyyard9207042019-07-05 08:04:42 -05002204 return;
2205 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002206 std::filesystem::path loc(
2207 "/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002208
zhanghch058d1b46d2021-04-01 11:18:24 +08002209 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002210
zhanghch058d1b46d2021-04-01 11:18:24 +08002211 if (!std::filesystem::exists(loc) ||
2212 !std::filesystem::is_directory(loc))
2213 {
2214 BMCWEB_LOG_ERROR << loc << "Not found";
2215 asyncResp->res.result(
2216 boost::beast::http::status::not_found);
2217 return;
2218 }
2219 std::filesystem::directory_iterator files(loc);
2220
2221 for (auto& file : files)
2222 {
2223 std::ifstream readFile(file.path());
2224 if (!readFile.good())
2225 {
2226 continue;
2227 }
2228
2229 asyncResp->res.addHeader("Content-Type",
2230 "application/octet-stream");
2231
2232 // Assuming only one dump file will be present in the dump
2233 // id directory
2234 std::string dumpFileName = file.path().filename().string();
2235
2236 // Filename should be in alphanumeric, dot and underscore
2237 // Its based on phosphor-debug-collector application
2238 // dumpfile format
2239 std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
2240 if (!std::regex_match(dumpFileName, dumpFileRegex))
2241 {
2242 BMCWEB_LOG_ERROR << "Invalid dump filename "
2243 << dumpFileName;
2244 asyncResp->res.result(
2245 boost::beast::http::status::not_found);
2246 return;
2247 }
2248 std::string contentDispositionParam =
2249 "attachment; filename=\"" + dumpFileName + "\"";
2250
2251 asyncResp->res.addHeader("Content-Disposition",
2252 contentDispositionParam);
2253
2254 asyncResp->res.body() = {
2255 std::istreambuf_iterator<char>(readFile),
2256 std::istreambuf_iterator<char>()};
2257 return;
2258 }
2259 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002260 return;
zhanghch058d1b46d2021-04-01 11:18:24 +08002261 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002262
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002263 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002264 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002265
2266 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002267 [](const crow::Request&,
2268 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002269 const std::string& connection) {
Gunnar Mills9062d472021-11-16 11:37:47 -06002270 introspectObjects(
2271 connection, "/",
2272 std::make_shared<bmcweb::AsyncResp>(asyncResp->res));
Ed Tanousb41187f2019-10-24 16:30:02 -07002273 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002274
2275 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002276 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002277 .methods(boost::beast::http::verb::get, boost::beast::http::verb::post)(
2278 [](const crow::Request& req,
2279 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2280 const std::string& processName,
2281 const std::string& requestedPath) {
2282 std::vector<std::string> strs;
2283 boost::split(strs, requestedPath, boost::is_any_of("/"));
2284 std::string objectPath;
2285 std::string interfaceName;
2286 std::string methodName;
2287 auto it = strs.begin();
2288 if (it == strs.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -07002289 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002290 objectPath = "/";
Ed Tanous1abe55e2018-09-05 08:30:59 -07002291 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002292 while (it != strs.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -07002293 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002294 // Check if segment contains ".". If it does, it must be an
2295 // interface
2296 if (it->find(".") != std::string::npos)
2297 {
2298 break;
2299 // This check is necessary as the trailing slash gets
2300 // parsed as part of our <path> specifier above, which
2301 // causes the normal trailing backslash redirector to
2302 // fail.
2303 }
2304 if (!it->empty())
2305 {
2306 objectPath += "/" + *it;
2307 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002308 it++;
2309 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002310 if (it != strs.end())
2311 {
2312 interfaceName = *it;
2313 it++;
Ed Tanous7c091622019-05-23 11:42:36 -07002314
zhanghch058d1b46d2021-04-01 11:18:24 +08002315 // after interface, we might have a method name
2316 if (it != strs.end())
2317 {
2318 methodName = *it;
2319 it++;
2320 }
2321 }
2322 if (it != strs.end())
2323 {
2324 // if there is more levels past the method name, something
2325 // went wrong, return not found
2326 asyncResp->res.result(
2327 boost::beast::http::status::not_found);
2328 return;
2329 }
2330 if (interfaceName.empty())
2331 {
2332 crow::connections::systemBus->async_method_call(
2333 [asyncResp, processName,
2334 objectPath](const boost::system::error_code ec,
2335 const std::string& introspectXml) {
2336 if (ec)
2337 {
2338 BMCWEB_LOG_ERROR
2339 << "Introspect call failed with error: "
2340 << ec.message()
2341 << " on process: " << processName
2342 << " path: " << objectPath << "\n";
2343 return;
2344 }
2345 tinyxml2::XMLDocument doc;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002346
zhanghch058d1b46d2021-04-01 11:18:24 +08002347 doc.Parse(introspectXml.c_str());
2348 tinyxml2::XMLNode* pRoot =
2349 doc.FirstChildElement("node");
2350 if (pRoot == nullptr)
2351 {
2352 BMCWEB_LOG_ERROR
2353 << "XML document failed to parse "
2354 << processName << " " << objectPath << "\n";
2355 asyncResp->res.jsonValue = {
2356 {"status", "XML parse error"}};
2357 asyncResp->res.result(
2358 boost::beast::http::status::
2359 internal_server_error);
2360 return;
2361 }
2362
2363 BMCWEB_LOG_DEBUG << introspectXml;
Ed Tanous7c091622019-05-23 11:42:36 -07002364 asyncResp->res.jsonValue = {
zhanghch058d1b46d2021-04-01 11:18:24 +08002365 {"status", "ok"},
2366 {"bus_name", processName},
2367 {"object_path", objectPath}};
2368 nlohmann::json& interfacesArray =
2369 asyncResp->res.jsonValue["interfaces"];
2370 interfacesArray = nlohmann::json::array();
2371 tinyxml2::XMLElement* interface =
2372 pRoot->FirstChildElement("interface");
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002373
zhanghch058d1b46d2021-04-01 11:18:24 +08002374 while (interface != nullptr)
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002375 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002376 const char* ifaceName =
2377 interface->Attribute("name");
2378 if (ifaceName != nullptr)
Ed Tanous7c091622019-05-23 11:42:36 -07002379 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002380 interfacesArray.push_back(
2381 {{"name", ifaceName}});
2382 }
2383
2384 interface =
2385 interface->NextSiblingElement("interface");
2386 }
2387 },
2388 processName, objectPath,
2389 "org.freedesktop.DBus.Introspectable", "Introspect");
2390 }
2391 else if (methodName.empty())
2392 {
2393 crow::connections::systemBus->async_method_call(
2394 [asyncResp, processName, objectPath,
2395 interfaceName](const boost::system::error_code ec,
2396 const std::string& introspectXml) {
2397 if (ec)
2398 {
2399 BMCWEB_LOG_ERROR
2400 << "Introspect call failed with error: "
2401 << ec.message()
2402 << " on process: " << processName
2403 << " path: " << objectPath << "\n";
2404 return;
2405 }
2406 tinyxml2::XMLDocument doc;
2407
2408 doc.Parse(introspectXml.data(),
2409 introspectXml.size());
2410 tinyxml2::XMLNode* pRoot =
2411 doc.FirstChildElement("node");
2412 if (pRoot == nullptr)
2413 {
2414 BMCWEB_LOG_ERROR
2415 << "XML document failed to parse "
2416 << processName << " " << objectPath << "\n";
2417 asyncResp->res.result(
2418 boost::beast::http::status::
2419 internal_server_error);
2420 return;
2421 }
2422 asyncResp->res.jsonValue = {
2423 {"status", "ok"},
2424 {"bus_name", processName},
2425 {"interface", interfaceName},
2426 {"object_path", objectPath}};
2427
2428 nlohmann::json& methodsArray =
2429 asyncResp->res.jsonValue["methods"];
2430 methodsArray = nlohmann::json::array();
2431
2432 nlohmann::json& signalsArray =
2433 asyncResp->res.jsonValue["signals"];
2434 signalsArray = nlohmann::json::array();
2435
2436 nlohmann::json& propertiesObj =
2437 asyncResp->res.jsonValue["properties"];
2438 propertiesObj = nlohmann::json::object();
2439
2440 // if we know we're the only call, build the
2441 // json directly
2442 tinyxml2::XMLElement* interface =
2443 pRoot->FirstChildElement("interface");
2444 while (interface != nullptr)
2445 {
2446 const char* ifaceName =
2447 interface->Attribute("name");
2448
2449 if (ifaceName != nullptr &&
2450 ifaceName == interfaceName)
2451 {
2452 break;
2453 }
2454
2455 interface =
2456 interface->NextSiblingElement("interface");
2457 }
2458 if (interface == nullptr)
2459 {
2460 // if we got to the end of the list and
2461 // never found a match, throw 404
2462 asyncResp->res.result(
2463 boost::beast::http::status::not_found);
2464 return;
2465 }
2466
2467 tinyxml2::XMLElement* methods =
2468 interface->FirstChildElement("method");
2469 while (methods != nullptr)
2470 {
2471 nlohmann::json argsArray =
2472 nlohmann::json::array();
2473 tinyxml2::XMLElement* arg =
2474 methods->FirstChildElement("arg");
2475 while (arg != nullptr)
2476 {
2477 nlohmann::json thisArg;
2478 for (const char* fieldName :
2479 std::array<const char*, 3>{
2480 "name", "direction", "type"})
Ed Tanous7c091622019-05-23 11:42:36 -07002481 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002482 const char* fieldValue =
2483 arg->Attribute(fieldName);
2484 if (fieldValue != nullptr)
Ed Tanous7c091622019-05-23 11:42:36 -07002485 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002486 thisArg[fieldName] = fieldValue;
Ed Tanous7c091622019-05-23 11:42:36 -07002487 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002488 }
2489 argsArray.push_back(std::move(thisArg));
2490 arg = arg->NextSiblingElement("arg");
2491 }
Ed Tanous7c091622019-05-23 11:42:36 -07002492
zhanghch058d1b46d2021-04-01 11:18:24 +08002493 const char* name = methods->Attribute("name");
2494 if (name != nullptr)
2495 {
2496 std::string uri;
2497 uri.reserve(14 + processName.size() +
2498 objectPath.size() +
2499 interfaceName.size() +
2500 strlen(name));
2501 uri += "/bus/system/";
2502 uri += processName;
2503 uri += objectPath;
2504 uri += "/";
2505 uri += interfaceName;
2506 uri += "/";
2507 uri += name;
2508 methodsArray.push_back(
2509 {{"name", name},
2510 {"uri", std::move(uri)},
2511 {"args", argsArray}});
2512 }
2513 methods = methods->NextSiblingElement("method");
Ed Tanous7c091622019-05-23 11:42:36 -07002514 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002515 tinyxml2::XMLElement* signals =
2516 interface->FirstChildElement("signal");
2517 while (signals != nullptr)
2518 {
2519 nlohmann::json argsArray =
2520 nlohmann::json::array();
2521
2522 tinyxml2::XMLElement* arg =
2523 signals->FirstChildElement("arg");
2524 while (arg != nullptr)
2525 {
2526 const char* name = arg->Attribute("name");
2527 const char* type = arg->Attribute("type");
2528 if (name != nullptr && type != nullptr)
2529 {
2530 argsArray.push_back({
2531 {"name", name},
2532 {"type", type},
2533 });
2534 }
2535 arg = arg->NextSiblingElement("arg");
2536 }
2537 const char* name = signals->Attribute("name");
2538 if (name != nullptr)
2539 {
2540 signalsArray.push_back(
2541 {{"name", name}, {"args", argsArray}});
2542 }
2543
2544 signals = signals->NextSiblingElement("signal");
2545 }
2546
2547 tinyxml2::XMLElement* property =
2548 interface->FirstChildElement("property");
2549 while (property != nullptr)
2550 {
2551 const char* name = property->Attribute("name");
2552 const char* type = property->Attribute("type");
2553 if (type != nullptr && name != nullptr)
2554 {
2555 sdbusplus::message::message m =
2556 crow::connections::systemBus
2557 ->new_method_call(
2558 processName.c_str(),
2559 objectPath.c_str(),
2560 "org.freedesktop."
2561 "DBus."
2562 "Properties",
2563 "Get");
2564 m.append(interfaceName, name);
2565 nlohmann::json& propertyItem =
2566 propertiesObj[name];
2567 crow::connections::systemBus->async_send(
2568 m,
2569 [&propertyItem, asyncResp](
2570 boost::system::error_code& e,
2571 sdbusplus::message::message& msg) {
2572 if (e)
2573 {
2574 return;
2575 }
2576
2577 convertDBusToJSON("v", msg,
2578 propertyItem);
2579 });
2580 }
2581 property =
2582 property->NextSiblingElement("property");
2583 }
2584 },
2585 processName, objectPath,
2586 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002587 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002588 else
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002589 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002590 if (req.method() != boost::beast::http::verb::post)
2591 {
2592 asyncResp->res.result(
2593 boost::beast::http::status::not_found);
2594 return;
2595 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002596
zhanghch058d1b46d2021-04-01 11:18:24 +08002597 nlohmann::json requestDbusData =
2598 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002599
zhanghch058d1b46d2021-04-01 11:18:24 +08002600 if (requestDbusData.is_discarded())
2601 {
2602 asyncResp->res.result(
2603 boost::beast::http::status::bad_request);
2604 return;
2605 }
2606 if (!requestDbusData.is_array())
2607 {
2608 asyncResp->res.result(
2609 boost::beast::http::status::bad_request);
2610 return;
2611 }
2612 auto transaction =
2613 std::make_shared<InProgressActionData>(asyncResp->res);
2614
2615 transaction->path = objectPath;
2616 transaction->methodName = methodName;
2617 transaction->arguments = std::move(requestDbusData);
2618
2619 findActionOnInterface(transaction, processName);
2620 }
2621 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002622}
2623} // namespace openbmc_mapper
2624} // namespace crow