blob: 78853a5101fddc646aa2f4b0eacd367a73efb124 [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 {
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600230 findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600231 }
232
233 const std::string objectPath;
234 std::shared_ptr<GetSubTreeType> subtree;
235 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
236};
237
Ed Tanous23a21a12020-07-25 04:45:05 +0000238inline void getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000239 const std::string& objectName, const std::string& objectManagerPath,
240 const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700241 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700242{
Ed Tanous81ce6092020-12-17 16:54:55 +0000243 BMCWEB_LOG_DEBUG << "getManagedObjectsForEnumerate " << objectName
244 << " object_manager_path " << objectManagerPath
245 << " connection_name " << connectionName;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700246 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000247 [transaction, objectName,
248 connectionName](const boost::system::error_code ec,
249 const dbus::utility::ManagedObjectType& objects) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700250 if (ec)
251 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000252 BMCWEB_LOG_ERROR << "GetManagedObjects on path " << objectName
253 << " on connection " << connectionName
Ed Tanous049a0512018-11-01 13:58:42 -0700254 << " failed with code " << ec;
255 return;
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700256 }
Ed Tanous64530012018-02-06 17:08:16 -0800257
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500258 nlohmann::json& dataJson =
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600259 transaction->asyncResp->res.jsonValue["data"];
Ed Tanous049a0512018-11-01 13:58:42 -0700260
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500261 for (const auto& objectPath : objects)
Ed Tanous049a0512018-11-01 13:58:42 -0700262 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000263 if (boost::starts_with(objectPath.first.str, objectName))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700264 {
Ed Tanous049a0512018-11-01 13:58:42 -0700265 BMCWEB_LOG_DEBUG << "Reading object "
266 << objectPath.first.str;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500267 nlohmann::json& objectJson = dataJson[objectPath.first.str];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700268 if (objectJson.is_null())
269 {
270 objectJson = nlohmann::json::object();
271 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500272 for (const auto& interface : objectPath.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700273 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500274 for (const auto& property : interface.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700275 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500276 nlohmann::json& propertyJson =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700277 objectJson[property.first];
Ed Tanousd1a64812021-12-13 12:14:05 -0800278 std::visit(
279 [&propertyJson](auto&& val) {
280 if constexpr (
281 std::is_same_v<
282 std::decay_t<decltype(val)>,
283 sdbusplus::message::unix_fd>)
284 {
285 propertyJson = val.fd;
286 }
287 else
288 {
289
290 propertyJson = val;
291 }
292 },
293 property.second);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700294 }
295 }
296 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500297 for (const auto& interface : objectPath.second)
Ed Tanous049a0512018-11-01 13:58:42 -0700298 {
299 if (interface.first == "org.freedesktop.DBus.ObjectManager")
300 {
301 getManagedObjectsForEnumerate(
302 objectPath.first.str, objectPath.first.str,
Ed Tanous81ce6092020-12-17 16:54:55 +0000303 connectionName, transaction);
Ed Tanous049a0512018-11-01 13:58:42 -0700304 }
305 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700306 }
307 },
Ed Tanous81ce6092020-12-17 16:54:55 +0000308 connectionName, objectManagerPath, "org.freedesktop.DBus.ObjectManager",
309 "GetManagedObjects");
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700310}
311
Ed Tanous23a21a12020-07-25 04:45:05 +0000312inline void findObjectManagerPathForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000313 const std::string& objectName, const std::string& connectionName,
Ed Tanousb5a76932020-09-29 16:16:58 -0700314 const std::shared_ptr<InProgressEnumerateData>& transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700315{
Ed Tanous81ce6092020-12-17 16:54:55 +0000316 BMCWEB_LOG_DEBUG << "Finding objectmanager for path " << objectName
317 << " on connection:" << connectionName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700318 crow::connections::systemBus->async_method_call(
Ed Tanous81ce6092020-12-17 16:54:55 +0000319 [transaction, objectName, connectionName](
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700320 const boost::system::error_code ec,
321 const boost::container::flat_map<
322 std::string, boost::container::flat_map<
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500323 std::string, std::vector<std::string>>>&
324 objects) {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700325 if (ec)
326 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000327 BMCWEB_LOG_ERROR << "GetAncestors on path " << objectName
Ed Tanous049a0512018-11-01 13:58:42 -0700328 << " failed with code " << ec;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700329 return;
330 }
331
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500332 for (const auto& pathGroup : objects)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700333 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500334 for (const auto& connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700335 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000336 if (connectionGroup.first == connectionName)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700337 {
338 // Found the object manager path for this resource.
339 getManagedObjectsForEnumerate(
Ed Tanous81ce6092020-12-17 16:54:55 +0000340 objectName, pathGroup.first, connectionName,
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600341 transaction);
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700342 return;
343 }
344 }
345 }
346 },
347 "xyz.openbmc_project.ObjectMapper",
348 "/xyz/openbmc_project/object_mapper",
Ed Tanous81ce6092020-12-17 16:54:55 +0000349 "xyz.openbmc_project.ObjectMapper", "GetAncestors", objectName,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500350 std::array<const char*, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700351}
Ed Tanous64530012018-02-06 17:08:16 -0800352
Ed Tanous7c091622019-05-23 11:42:36 -0700353// Uses GetObject to add the object info about the target /enumerate path to
354// the results of GetSubTree, as GetSubTree will not return info for the
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600355// target path, and then continues on enumerating the rest of the tree.
Ed Tanousb5a76932020-09-29 16:16:58 -0700356inline void getObjectAndEnumerate(
357 const std::shared_ptr<InProgressEnumerateData>& transaction)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600358{
359 using GetObjectType =
360 std::vector<std::pair<std::string, std::vector<std::string>>>;
361
362 crow::connections::systemBus->async_method_call(
363 [transaction](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500364 const GetObjectType& objects) {
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600365 if (ec)
366 {
367 BMCWEB_LOG_ERROR << "GetObject for path "
368 << transaction->objectPath
369 << " failed with code " << ec;
370 return;
371 }
372
373 BMCWEB_LOG_DEBUG << "GetObject for " << transaction->objectPath
374 << " has " << objects.size() << " entries";
375 if (!objects.empty())
376 {
377 transaction->subtree->emplace_back(transaction->objectPath,
378 objects);
379 }
380
381 // Map indicating connection name, and the path where the object
382 // manager exists
383 boost::container::flat_map<std::string, std::string> connections;
384
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500385 for (const auto& object : *(transaction->subtree))
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600386 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500387 for (const auto& connection : object.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600388 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500389 std::string& objectManagerPath =
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600390 connections[connection.first];
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500391 for (const auto& interface : connection.second)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600392 {
393 BMCWEB_LOG_DEBUG << connection.first
394 << " has interface " << interface;
395 if (interface == "org.freedesktop.DBus.ObjectManager")
396 {
397 BMCWEB_LOG_DEBUG << "found object manager path "
398 << object.first;
399 objectManagerPath = object.first;
400 }
401 }
402 }
403 }
404 BMCWEB_LOG_DEBUG << "Got " << connections.size() << " connections";
405
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500406 for (const auto& connection : connections)
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600407 {
Ed Tanous7c091622019-05-23 11:42:36 -0700408 // If we already know where the object manager is, we don't
409 // need to search for it, we can call directly in to
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600410 // getManagedObjects
411 if (!connection.second.empty())
412 {
413 getManagedObjectsForEnumerate(
414 transaction->objectPath, connection.second,
415 connection.first, transaction);
416 }
417 else
418 {
Ed Tanous7c091622019-05-23 11:42:36 -0700419 // otherwise we need to find the object manager path
420 // before we can continue
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600421 findObjectManagerPathForEnumerate(
422 transaction->objectPath, connection.first, transaction);
423 }
424 }
425 },
426 "xyz.openbmc_project.ObjectMapper",
427 "/xyz/openbmc_project/object_mapper",
428 "xyz.openbmc_project.ObjectMapper", "GetObject",
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500429 transaction->objectPath, std::array<const char*, 0>());
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600430}
Ed Tanous64530012018-02-06 17:08:16 -0800431
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700432// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700433struct InProgressActionData
434{
Ed Tanous23a21a12020-07-25 04:45:05 +0000435 InProgressActionData(crow::Response& resIn) : res(resIn)
436 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700437 ~InProgressActionData()
438 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600439 // Methods could have been called across different owners
440 // and interfaces, where some calls failed and some passed.
441 //
442 // The rules for this are:
443 // * if no method was called - error
444 // * if a method failed and none passed - error
445 // (converse: if at least one method passed - OK)
446 // * for the method output:
447 // * if output processing didn't fail, return the data
448
449 // Only deal with method returns if nothing failed earlier
450 if (res.result() == boost::beast::http::status::ok)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700451 {
Matt Spinler16caaee2019-01-15 11:40:34 -0600452 if (!methodPassed)
453 {
Matt Spinler06b1b632019-06-18 16:09:25 -0500454 if (!methodFailed)
Matt Spinler16caaee2019-01-15 11:40:34 -0600455 {
456 setErrorResponse(res, boost::beast::http::status::not_found,
457 methodNotFoundDesc, notFoundMsg);
458 }
459 }
460 else
461 {
462 if (outputFailed)
463 {
464 setErrorResponse(
465 res, boost::beast::http::status::internal_server_error,
466 "Method output failure", methodOutputFailedMsg);
467 }
468 else
469 {
470 res.jsonValue = {{"status", "ok"},
471 {"message", "200 OK"},
472 {"data", methodResponse}};
473 }
474 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700475 }
Matt Spinler16caaee2019-01-15 11:40:34 -0600476
Ed Tanous1abe55e2018-09-05 08:30:59 -0700477 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700478 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700479
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500480 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700481 {
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600482 setErrorResponse(res, boost::beast::http::status::bad_request, desc,
483 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700484 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500485 crow::Response& res;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700486 std::string path;
487 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600488 std::string interfaceName;
Matt Spinler16caaee2019-01-15 11:40:34 -0600489 bool methodPassed = false;
490 bool methodFailed = false;
491 bool outputFailed = false;
Matt Spinler39a4e392019-01-15 11:53:13 -0600492 bool convertedToArray = false;
Matt Spinler16caaee2019-01-15 11:40:34 -0600493 nlohmann::json methodResponse;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700494 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700495};
496
Ed Tanous23a21a12020-07-25 04:45:05 +0000497inline std::vector<std::string> dbusArgSplit(const std::string& string)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700498{
499 std::vector<std::string> ret;
500 if (string.empty())
501 {
502 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700503 }
Ed Tanous0f0353b2019-10-24 11:37:51 -0700504 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700505 int containerDepth = 0;
506
507 for (std::string::const_iterator character = string.begin();
508 character != string.end(); character++)
509 {
510 ret.back() += *character;
511 switch (*character)
512 {
513 case ('a'):
514 break;
515 case ('('):
516 case ('{'):
517 containerDepth++;
518 break;
519 case ('}'):
520 case (')'):
521 containerDepth--;
522 if (containerDepth == 0)
523 {
524 if (character + 1 != string.end())
525 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700526 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700527 }
528 }
529 break;
530 default:
531 if (containerDepth == 0)
532 {
533 if (character + 1 != string.end())
534 {
Ed Tanous0f0353b2019-10-24 11:37:51 -0700535 ret.emplace_back("");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700536 }
537 }
538 break;
539 }
540 }
Matt Spinler4ae611d2019-01-11 15:37:06 -0600541
542 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700543}
544
Ed Tanous81ce6092020-12-17 16:54:55 +0000545inline int convertJsonToDbus(sd_bus_message* m, const std::string& argType,
546 const nlohmann::json& inputJson)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700547{
548 int r = 0;
Ed Tanous71f52d92021-02-19 08:51:17 -0800549 BMCWEB_LOG_DEBUG << "Converting "
550 << inputJson.dump(2, ' ', true,
551 nlohmann::json::error_handler_t::replace)
Ed Tanous81ce6092020-12-17 16:54:55 +0000552 << " to type: " << argType;
553 const std::vector<std::string> argTypes = dbusArgSplit(argType);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700554
Ed Tanous1abe55e2018-09-05 08:30:59 -0700555 // Assume a single object for now.
Ed Tanous81ce6092020-12-17 16:54:55 +0000556 const nlohmann::json* j = &inputJson;
557 nlohmann::json::const_iterator jIt = inputJson.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700558
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500559 for (const std::string& argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700560 {
561 // If we are decoding multiple objects, grab the pointer to the
562 // iterator, and increment it for the next loop
563 if (argTypes.size() > 1)
564 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000565 if (jIt == inputJson.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700566 {
567 return -2;
568 }
569 j = &*jIt;
570 jIt++;
571 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500572 const int64_t* intValue = j->get_ptr<const int64_t*>();
573 const std::string* stringValue = j->get_ptr<const std::string*>();
574 const double* doubleValue = j->get_ptr<const double*>();
575 const bool* b = j->get_ptr<const bool*>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700576 int64_t v = 0;
577 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700578
Ed Tanous1abe55e2018-09-05 08:30:59 -0700579 // Do some basic type conversions that make sense. uint can be
580 // converted to int. int and uint can be converted to double
Ed Tanous66664f22019-10-11 13:05:49 -0700581 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700582 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500583 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700584 if (uintValue != nullptr)
585 {
586 v = static_cast<int64_t>(*uintValue);
587 intValue = &v;
588 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700589 }
Ed Tanous66664f22019-10-11 13:05:49 -0700590 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700591 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500592 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanous66664f22019-10-11 13:05:49 -0700593 if (uintValue != nullptr)
594 {
595 d = static_cast<double>(*uintValue);
596 doubleValue = &d;
597 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700598 }
Ed Tanous66664f22019-10-11 13:05:49 -0700599 if (doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700600 {
Ed Tanous66664f22019-10-11 13:05:49 -0700601 if (intValue != nullptr)
602 {
603 d = static_cast<double>(*intValue);
604 doubleValue = &d;
605 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700606 }
607
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700608 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700609 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700610 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700611 {
612 return -1;
613 }
Ed Tanous271584a2019-07-09 16:24:22 -0700614 r = sd_bus_message_append_basic(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500615 m, argCode[0], static_cast<const void*>(stringValue->data()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700616 if (r < 0)
617 {
618 return r;
619 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700620 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700621 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700622 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700623 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700624 {
625 return -1;
626 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500627 if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
628 (*intValue > std::numeric_limits<int32_t>::max()))
629 {
630 return -ERANGE;
631 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700632 int32_t i = static_cast<int32_t>(*intValue);
633 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700634 if (r < 0)
635 {
636 return r;
637 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700638 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700639 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700640 {
641 // lots of ways bool could be represented here. Try them all
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700642 int boolInt = false;
643 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700644 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500645 if (*intValue == 1)
646 {
647 boolInt = true;
648 }
649 else if (*intValue == 0)
650 {
651 boolInt = false;
652 }
653 else
654 {
655 return -ERANGE;
656 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700657 }
658 else if (b != nullptr)
659 {
Matt Spinlera2f02632019-01-18 10:15:35 -0600660 boolInt = *b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700661 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700662 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700663 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700664 boolInt = boost::istarts_with(*stringValue, "t") ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700665 }
666 else
667 {
668 return -1;
669 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700670 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700671 if (r < 0)
672 {
673 return r;
674 }
675 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700676 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700677 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700678 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700679 {
680 return -1;
681 }
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500682 if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
683 (*intValue > std::numeric_limits<int16_t>::max()))
684 {
685 return -ERANGE;
686 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700687 int16_t n = static_cast<int16_t>(*intValue);
688 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700689 if (r < 0)
690 {
691 return r;
692 }
693 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700694 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700695 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700696 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700697 {
698 return -1;
699 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700700 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700701 if (r < 0)
702 {
703 return r;
704 }
705 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700706 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700707 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500708 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700709 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700710 {
711 return -1;
712 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000713 if (*uintValue > std::numeric_limits<uint8_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500714 {
715 return -ERANGE;
716 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700717 uint8_t y = static_cast<uint8_t>(*uintValue);
718 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700719 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700720 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700721 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500722 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700723 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700724 {
725 return -1;
726 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000727 if (*uintValue > std::numeric_limits<uint16_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500728 {
729 return -ERANGE;
730 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700731 uint16_t q = static_cast<uint16_t>(*uintValue);
732 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700733 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700734 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700735 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500736 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700737 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700738 {
739 return -1;
740 }
Ed Tanous23a21a12020-07-25 04:45:05 +0000741 if (*uintValue > std::numeric_limits<uint32_t>::max())
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500742 {
743 return -ERANGE;
744 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700745 uint32_t u = static_cast<uint32_t>(*uintValue);
746 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700747 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700748 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700749 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500750 const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700751 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700752 {
753 return -1;
754 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700755 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700756 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700757 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700758 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -0500759 if (doubleValue == nullptr)
760 {
761 return -1;
762 }
763 if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
764 (*doubleValue > std::numeric_limits<double>::max()))
765 {
766 return -ERANGE;
767 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700768 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700769 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700770 else if (boost::starts_with(argCode, "a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700771 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700772 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700773 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700774 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700775 if (r < 0)
776 {
777 return r;
778 }
779
Ed Tanous0dfeda62019-10-24 11:21:38 -0700780 for (const auto& it : *j)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700781 {
Ed Tanous0dfeda62019-10-24 11:21:38 -0700782 r = convertJsonToDbus(m, containedType, it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700783 if (r < 0)
784 {
785 return r;
786 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700787 }
788 sd_bus_message_close_container(m);
789 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700790 else if (boost::starts_with(argCode, "v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700791 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700792 std::string containedType = argCode.substr(1);
793 BMCWEB_LOG_DEBUG << "variant type: " << argCode
794 << " appending variant of type: " << containedType;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700795 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700796 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700797 if (r < 0)
798 {
799 return r;
800 }
801
Ed Tanous81ce6092020-12-17 16:54:55 +0000802 r = convertJsonToDbus(m, containedType, inputJson);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700803 if (r < 0)
804 {
805 return r;
806 }
807
808 r = sd_bus_message_close_container(m);
809 if (r < 0)
810 {
811 return r;
812 }
813 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700814 else if (boost::starts_with(argCode, "(") &&
815 boost::ends_with(argCode, ")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700816 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700817 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700818 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700819 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800820 if (r < 0)
821 {
822 return r;
823 }
824
Ed Tanous1abe55e2018-09-05 08:30:59 -0700825 nlohmann::json::const_iterator it = j->begin();
Ed Tanous81ce6092020-12-17 16:54:55 +0000826 for (const std::string& argCode2 : dbusArgSplit(argType))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700827 {
828 if (it == j->end())
829 {
830 return -1;
831 }
Ed Tanouscb13a392020-07-25 19:02:03 +0000832 r = convertJsonToDbus(m, argCode2, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700833 if (r < 0)
834 {
835 return r;
836 }
837 it++;
838 }
839 r = sd_bus_message_close_container(m);
840 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700841 else if (boost::starts_with(argCode, "{") &&
842 boost::ends_with(argCode, "}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700843 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700844 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700845 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700846 containedType.c_str());
Ed Tanousf1eebf02019-03-04 15:57:09 -0800847 if (r < 0)
848 {
849 return r;
850 }
851
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700852 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700853 if (codes.size() != 2)
854 {
855 return -1;
856 }
Ed Tanous2c70f802020-09-28 14:29:23 -0700857 const std::string& keyType = codes[0];
858 const std::string& valueType = codes[1];
Ed Tanous3174e4d2020-10-07 11:41:22 -0700859 for (const auto& it : j->items())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700860 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700861 r = convertJsonToDbus(m, keyType, it.key());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700862 if (r < 0)
863 {
864 return r;
865 }
866
Ed Tanous2c70f802020-09-28 14:29:23 -0700867 r = convertJsonToDbus(m, valueType, it.value());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700868 if (r < 0)
869 {
870 return r;
871 }
872 }
873 r = sd_bus_message_close_container(m);
874 }
875 else
876 {
877 return -2;
878 }
879 if (r < 0)
880 {
881 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700882 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700883
Ed Tanous1abe55e2018-09-05 08:30:59 -0700884 if (argTypes.size() > 1)
885 {
886 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700887 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700888 }
Matt Spinler127ea542019-01-14 11:04:28 -0600889
890 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700891}
892
Matt Spinlerd22a7132019-01-14 12:14:30 -0600893template <typename T>
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500894int readMessageItem(const std::string& typeCode, sdbusplus::message::message& m,
895 nlohmann::json& data)
Matt Spinlerd22a7132019-01-14 12:14:30 -0600896{
897 T value;
898
899 int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
900 if (r < 0)
901 {
902 BMCWEB_LOG_ERROR << "sd_bus_message_read_basic on type " << typeCode
903 << " failed!";
904 return r;
905 }
906
907 data = value;
908 return 0;
909}
910
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500911int convertDBusToJSON(const std::string& returnType,
912 sdbusplus::message::message& m, nlohmann::json& response);
Matt Spinler6df8f992019-01-14 12:47:47 -0600913
Ed Tanous23a21a12020-07-25 04:45:05 +0000914inline int readDictEntryFromMessage(const std::string& typeCode,
915 sdbusplus::message::message& m,
916 nlohmann::json& object)
Matt Spinler6df8f992019-01-14 12:47:47 -0600917{
918 std::vector<std::string> types = dbusArgSplit(typeCode);
919 if (types.size() != 2)
920 {
921 BMCWEB_LOG_ERROR << "wrong number contained types in dictionary: "
922 << types.size();
923 return -1;
924 }
925
926 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
927 typeCode.c_str());
928 if (r < 0)
929 {
930 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container with rc " << r;
931 return r;
932 }
933
934 nlohmann::json key;
935 r = convertDBusToJSON(types[0], m, key);
936 if (r < 0)
937 {
938 return r;
939 }
940
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500941 const std::string* keyPtr = key.get_ptr<const std::string*>();
Matt Spinler6df8f992019-01-14 12:47:47 -0600942 if (keyPtr == nullptr)
943 {
944 // json doesn't support non-string keys. If we hit this condition,
945 // convert the result to a string so we can proceed
Ed Tanous71f52d92021-02-19 08:51:17 -0800946 key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500947 keyPtr = key.get_ptr<const std::string*>();
Ed Tanous7c091622019-05-23 11:42:36 -0700948 // in theory this can't fail now, but lets be paranoid about it
949 // anyway
Matt Spinler6df8f992019-01-14 12:47:47 -0600950 if (keyPtr == nullptr)
951 {
952 return -1;
953 }
954 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500955 nlohmann::json& value = object[*keyPtr];
Matt Spinler6df8f992019-01-14 12:47:47 -0600956
957 r = convertDBusToJSON(types[1], m, value);
958 if (r < 0)
959 {
960 return r;
961 }
962
963 r = sd_bus_message_exit_container(m.get());
964 if (r < 0)
965 {
966 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
967 return r;
968 }
969
970 return 0;
971}
972
Ed Tanous23a21a12020-07-25 04:45:05 +0000973inline int readArrayFromMessage(const std::string& typeCode,
974 sdbusplus::message::message& m,
975 nlohmann::json& data)
Matt Spinler6df8f992019-01-14 12:47:47 -0600976{
977 if (typeCode.size() < 2)
978 {
979 BMCWEB_LOG_ERROR << "Type code " << typeCode
980 << " too small for an array";
981 return -1;
982 }
983
984 std::string containedType = typeCode.substr(1);
985
986 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
987 containedType.c_str());
988 if (r < 0)
989 {
990 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
991 << r;
992 return r;
993 }
994
995 bool dict = boost::starts_with(containedType, "{") &&
996 boost::ends_with(containedType, "}");
997
998 if (dict)
999 {
1000 // Remove the { }
1001 containedType = containedType.substr(1, containedType.size() - 2);
1002 data = nlohmann::json::object();
1003 }
1004 else
1005 {
1006 data = nlohmann::json::array();
1007 }
1008
1009 while (true)
1010 {
1011 r = sd_bus_message_at_end(m.get(), false);
1012 if (r < 0)
1013 {
1014 BMCWEB_LOG_ERROR << "sd_bus_message_at_end failed";
1015 return r;
1016 }
1017
1018 if (r > 0)
1019 {
1020 break;
1021 }
1022
1023 // Dictionaries are only ever seen in an array
1024 if (dict)
1025 {
1026 r = readDictEntryFromMessage(containedType, m, data);
1027 if (r < 0)
1028 {
1029 return r;
1030 }
1031 }
1032 else
1033 {
1034 data.push_back(nlohmann::json());
1035
1036 r = convertDBusToJSON(containedType, m, data.back());
1037 if (r < 0)
1038 {
1039 return r;
1040 }
1041 }
1042 }
1043
1044 r = sd_bus_message_exit_container(m.get());
1045 if (r < 0)
1046 {
1047 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1048 return r;
1049 }
1050
1051 return 0;
1052}
1053
Ed Tanous23a21a12020-07-25 04:45:05 +00001054inline int readStructFromMessage(const std::string& typeCode,
1055 sdbusplus::message::message& m,
1056 nlohmann::json& data)
Matt Spinler75c6c672019-01-14 13:01:46 -06001057{
1058 if (typeCode.size() < 3)
1059 {
1060 BMCWEB_LOG_ERROR << "Type code " << typeCode
1061 << " too small for a struct";
1062 return -1;
1063 }
1064
1065 std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
1066 std::vector<std::string> types = dbusArgSplit(containedTypes);
1067
1068 int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
1069 containedTypes.c_str());
1070 if (r < 0)
1071 {
1072 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1073 << r;
1074 return r;
1075 }
1076
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001077 for (const std::string& type : types)
Matt Spinler75c6c672019-01-14 13:01:46 -06001078 {
1079 data.push_back(nlohmann::json());
1080 r = convertDBusToJSON(type, m, data.back());
1081 if (r < 0)
1082 {
1083 return r;
1084 }
1085 }
1086
1087 r = sd_bus_message_exit_container(m.get());
1088 if (r < 0)
1089 {
1090 BMCWEB_LOG_ERROR << "sd_bus_message_exit_container failed";
1091 return r;
1092 }
1093 return 0;
1094}
1095
Ed Tanous23a21a12020-07-25 04:45:05 +00001096inline int readVariantFromMessage(sdbusplus::message::message& m,
1097 nlohmann::json& data)
Matt Spinler89c19702019-01-14 13:13:00 -06001098{
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001099 const char* containerType;
Ed Tanous99131cd2019-10-24 11:12:47 -07001100 int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
Matt Spinler89c19702019-01-14 13:13:00 -06001101 if (r < 0)
1102 {
1103 BMCWEB_LOG_ERROR << "sd_bus_message_peek_type failed";
1104 return r;
1105 }
1106
1107 r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
1108 containerType);
1109 if (r < 0)
1110 {
1111 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed with rc "
1112 << r;
1113 return r;
1114 }
1115
1116 r = convertDBusToJSON(containerType, m, data);
1117 if (r < 0)
1118 {
1119 return r;
1120 }
1121
1122 r = sd_bus_message_exit_container(m.get());
1123 if (r < 0)
1124 {
1125 BMCWEB_LOG_ERROR << "sd_bus_message_enter_container failed";
1126 return r;
1127 }
1128
1129 return 0;
1130}
1131
Ed Tanous23a21a12020-07-25 04:45:05 +00001132inline int convertDBusToJSON(const std::string& returnType,
1133 sdbusplus::message::message& m,
1134 nlohmann::json& response)
Matt Spinler16caaee2019-01-15 11:40:34 -06001135{
Matt Spinlerd22a7132019-01-14 12:14:30 -06001136 int r = 0;
1137 const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1138
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001139 for (const std::string& typeCode : returnTypes)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001140 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001141 nlohmann::json* thisElement = &response;
Matt Spinlerf39420c2019-01-30 12:57:18 -06001142 if (returnTypes.size() > 1)
Matt Spinlerd22a7132019-01-14 12:14:30 -06001143 {
1144 response.push_back(nlohmann::json{});
Matt Spinlerf39420c2019-01-30 12:57:18 -06001145 thisElement = &response.back();
Matt Spinlerd22a7132019-01-14 12:14:30 -06001146 }
1147
Ed Tanousd4d25792020-09-29 15:15:03 -07001148 if (typeCode == "s" || typeCode == "g" || typeCode == "o")
Matt Spinlerd22a7132019-01-14 12:14:30 -06001149 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001150 r = readMessageItem<char*>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001151 if (r < 0)
1152 {
1153 return r;
1154 }
1155 }
1156 else if (typeCode == "b")
1157 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001158 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001159 if (r < 0)
1160 {
1161 return r;
1162 }
1163
Matt Spinlerf39420c2019-01-30 12:57:18 -06001164 *thisElement = static_cast<bool>(thisElement->get<int>());
Matt Spinlerd22a7132019-01-14 12:14:30 -06001165 }
1166 else if (typeCode == "u")
1167 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001168 r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001169 if (r < 0)
1170 {
1171 return r;
1172 }
1173 }
1174 else if (typeCode == "i")
1175 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001176 r = readMessageItem<int32_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 == "x")
1183 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001184 r = readMessageItem<int64_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 == "t")
1191 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001192 r = readMessageItem<uint64_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 == "n")
1199 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001200 r = readMessageItem<int16_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 == "q")
1207 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001208 r = readMessageItem<uint16_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 == "y")
1215 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001216 r = readMessageItem<uint8_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 == "d")
1223 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001224 r = readMessageItem<double>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001225 if (r < 0)
1226 {
1227 return r;
1228 }
1229 }
1230 else if (typeCode == "h")
1231 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001232 r = readMessageItem<int>(typeCode, m, *thisElement);
Matt Spinlerd22a7132019-01-14 12:14:30 -06001233 if (r < 0)
1234 {
1235 return r;
1236 }
1237 }
Matt Spinler6df8f992019-01-14 12:47:47 -06001238 else if (boost::starts_with(typeCode, "a"))
1239 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001240 r = readArrayFromMessage(typeCode, m, *thisElement);
Matt Spinler6df8f992019-01-14 12:47:47 -06001241 if (r < 0)
1242 {
1243 return r;
1244 }
1245 }
Matt Spinler75c6c672019-01-14 13:01:46 -06001246 else if (boost::starts_with(typeCode, "(") &&
1247 boost::ends_with(typeCode, ")"))
1248 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001249 r = readStructFromMessage(typeCode, m, *thisElement);
Matt Spinler75c6c672019-01-14 13:01:46 -06001250 if (r < 0)
1251 {
1252 return r;
1253 }
1254 }
Matt Spinler89c19702019-01-14 13:13:00 -06001255 else if (boost::starts_with(typeCode, "v"))
1256 {
Matt Spinlerf39420c2019-01-30 12:57:18 -06001257 r = readVariantFromMessage(m, *thisElement);
Matt Spinler89c19702019-01-14 13:13:00 -06001258 if (r < 0)
1259 {
1260 return r;
1261 }
1262 }
Matt Spinlerd22a7132019-01-14 12:14:30 -06001263 else
1264 {
Matt Spinlerd22a7132019-01-14 12:14:30 -06001265 BMCWEB_LOG_ERROR << "Invalid D-Bus signature type " << typeCode;
1266 return -2;
1267 }
1268 }
1269
Matt Spinler16caaee2019-01-15 11:40:34 -06001270 return 0;
1271}
1272
Ed Tanousb5a76932020-09-29 16:16:58 -07001273inline void handleMethodResponse(
1274 const std::shared_ptr<InProgressActionData>& transaction,
1275 sdbusplus::message::message& m, const std::string& returnType)
Matt Spinler16caaee2019-01-15 11:40:34 -06001276{
Matt Spinler39a4e392019-01-15 11:53:13 -06001277 nlohmann::json data;
1278
1279 int r = convertDBusToJSON(returnType, m, data);
1280 if (r < 0)
1281 {
1282 transaction->outputFailed = true;
1283 return;
1284 }
1285
1286 if (data.is_null())
1287 {
1288 return;
1289 }
1290
1291 if (transaction->methodResponse.is_null())
1292 {
1293 transaction->methodResponse = std::move(data);
1294 return;
1295 }
1296
1297 // If they're both dictionaries or arrays, merge into one.
1298 // Otherwise, make the results an array with every result
1299 // an entry. Could also just fail in that case, but it
1300 // seems better to get the data back somehow.
1301
1302 if (transaction->methodResponse.is_object() && data.is_object())
1303 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001304 for (const auto& obj : data.items())
Matt Spinler39a4e392019-01-15 11:53:13 -06001305 {
1306 // Note: Will overwrite the data for a duplicate key
1307 transaction->methodResponse.emplace(obj.key(),
1308 std::move(obj.value()));
1309 }
1310 return;
1311 }
1312
1313 if (transaction->methodResponse.is_array() && data.is_array())
1314 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001315 for (auto& obj : data)
Matt Spinler39a4e392019-01-15 11:53:13 -06001316 {
1317 transaction->methodResponse.push_back(std::move(obj));
1318 }
1319 return;
1320 }
1321
1322 if (!transaction->convertedToArray)
1323 {
1324 // They are different types. May as well turn them into an array
1325 nlohmann::json j = std::move(transaction->methodResponse);
1326 transaction->methodResponse = nlohmann::json::array();
1327 transaction->methodResponse.push_back(std::move(j));
1328 transaction->methodResponse.push_back(std::move(data));
1329 transaction->convertedToArray = true;
1330 }
1331 else
1332 {
1333 transaction->methodResponse.push_back(std::move(data));
1334 }
Matt Spinler16caaee2019-01-15 11:40:34 -06001335}
1336
Ed Tanousb5a76932020-09-29 16:16:58 -07001337inline void findActionOnInterface(
1338 const std::shared_ptr<InProgressActionData>& transaction,
1339 const std::string& connectionName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001340{
1341 BMCWEB_LOG_DEBUG << "findActionOnInterface for connection "
1342 << connectionName;
1343 crow::connections::systemBus->async_method_call(
1344 [transaction, connectionName{std::string(connectionName)}](
1345 const boost::system::error_code ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001346 const std::string& introspectXml) {
1347 BMCWEB_LOG_DEBUG << "got xml:\n " << introspectXml;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001348 if (ec)
1349 {
1350 BMCWEB_LOG_ERROR
1351 << "Introspect call failed with error: " << ec.message()
1352 << " on process: " << connectionName << "\n";
Matt Spinler318bd892019-01-15 09:59:20 -06001353 return;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001354 }
Matt Spinler318bd892019-01-15 09:59:20 -06001355 tinyxml2::XMLDocument doc;
1356
Ed Tanous81ce6092020-12-17 16:54:55 +00001357 doc.Parse(introspectXml.data(), introspectXml.size());
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001358 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
Matt Spinler318bd892019-01-15 09:59:20 -06001359 if (pRoot == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001360 {
Matt Spinler318bd892019-01-15 09:59:20 -06001361 BMCWEB_LOG_ERROR << "XML document failed to parse "
1362 << connectionName << "\n";
1363 return;
1364 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001365 tinyxml2::XMLElement* interfaceNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001366 pRoot->FirstChildElement("interface");
1367 while (interfaceNode != nullptr)
1368 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001369 const char* thisInterfaceName =
Matt Spinler318bd892019-01-15 09:59:20 -06001370 interfaceNode->Attribute("name");
1371 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001372 {
Matt Spinler318bd892019-01-15 09:59:20 -06001373 if (!transaction->interfaceName.empty() &&
1374 (transaction->interfaceName != thisInterfaceName))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001375 {
Matt Spinler318bd892019-01-15 09:59:20 -06001376 interfaceNode =
1377 interfaceNode->NextSiblingElement("interface");
1378 continue;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001379 }
Matt Spinler318bd892019-01-15 09:59:20 -06001380
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001381 tinyxml2::XMLElement* methodNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001382 interfaceNode->FirstChildElement("method");
1383 while (methodNode != nullptr)
1384 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001385 const char* thisMethodName =
Matt Spinler318bd892019-01-15 09:59:20 -06001386 methodNode->Attribute("name");
1387 BMCWEB_LOG_DEBUG << "Found method: " << thisMethodName;
1388 if (thisMethodName != nullptr &&
1389 thisMethodName == transaction->methodName)
1390 {
1391 BMCWEB_LOG_DEBUG
1392 << "Found method named " << thisMethodName
1393 << " on interface " << thisInterfaceName;
1394 sdbusplus::message::message m =
1395 crow::connections::systemBus->new_method_call(
1396 connectionName.c_str(),
1397 transaction->path.c_str(),
1398 thisInterfaceName,
1399 transaction->methodName.c_str());
1400
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001401 tinyxml2::XMLElement* argumentNode =
Matt Spinler318bd892019-01-15 09:59:20 -06001402 methodNode->FirstChildElement("arg");
1403
Matt Spinler16caaee2019-01-15 11:40:34 -06001404 std::string returnType;
1405
1406 // Find the output type
1407 while (argumentNode != nullptr)
1408 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001409 const char* argDirection =
Matt Spinler16caaee2019-01-15 11:40:34 -06001410 argumentNode->Attribute("direction");
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001411 const char* argType =
Matt Spinler16caaee2019-01-15 11:40:34 -06001412 argumentNode->Attribute("type");
1413 if (argDirection != nullptr &&
1414 argType != nullptr &&
1415 std::string(argDirection) == "out")
1416 {
1417 returnType = argType;
1418 break;
1419 }
1420 argumentNode =
1421 argumentNode->NextSiblingElement("arg");
1422 }
1423
Matt Spinler318bd892019-01-15 09:59:20 -06001424 nlohmann::json::const_iterator argIt =
1425 transaction->arguments.begin();
1426
Matt Spinler16caaee2019-01-15 11:40:34 -06001427 argumentNode = methodNode->FirstChildElement("arg");
1428
Matt Spinler318bd892019-01-15 09:59:20 -06001429 while (argumentNode != nullptr)
1430 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001431 const char* argDirection =
Matt Spinler318bd892019-01-15 09:59:20 -06001432 argumentNode->Attribute("direction");
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001433 const char* argType =
Matt Spinler318bd892019-01-15 09:59:20 -06001434 argumentNode->Attribute("type");
1435 if (argDirection != nullptr &&
1436 argType != nullptr &&
1437 std::string(argDirection) == "in")
1438 {
1439 if (argIt == transaction->arguments.end())
1440 {
1441 transaction->setErrorStatus(
1442 "Invalid method args");
1443 return;
1444 }
1445 if (convertJsonToDbus(m.get(),
1446 std::string(argType),
1447 *argIt) < 0)
1448 {
1449 transaction->setErrorStatus(
1450 "Invalid method arg type");
1451 return;
1452 }
1453
1454 argIt++;
1455 }
1456 argumentNode =
1457 argumentNode->NextSiblingElement("arg");
1458 }
1459
1460 crow::connections::systemBus->async_send(
Matt Spinler16caaee2019-01-15 11:40:34 -06001461 m, [transaction, returnType](
Ed Tanous23a21a12020-07-25 04:45:05 +00001462 boost::system::error_code ec2,
1463 sdbusplus::message::message& m2) {
1464 if (ec2)
Matt Spinler318bd892019-01-15 09:59:20 -06001465 {
Matt Spinler16caaee2019-01-15 11:40:34 -06001466 transaction->methodFailed = true;
Ed Tanous23a21a12020-07-25 04:45:05 +00001467 const sd_bus_error* e = m2.get_error();
Matt Spinler06b1b632019-06-18 16:09:25 -05001468
1469 if (e)
1470 {
1471 setErrorResponse(
1472 transaction->res,
1473 boost::beast::http::status::
1474 bad_request,
1475 e->name, e->message);
1476 }
1477 else
1478 {
1479 setErrorResponse(
1480 transaction->res,
1481 boost::beast::http::status::
1482 bad_request,
1483 "Method call failed",
1484 methodFailedMsg);
1485 }
Matt Spinler318bd892019-01-15 09:59:20 -06001486 return;
1487 }
Ed Tanous3174e4d2020-10-07 11:41:22 -07001488 transaction->methodPassed = true;
Matt Spinler16caaee2019-01-15 11:40:34 -06001489
Ed Tanous23a21a12020-07-25 04:45:05 +00001490 handleMethodResponse(transaction, m2,
Matt Spinler16caaee2019-01-15 11:40:34 -06001491 returnType);
Matt Spinler318bd892019-01-15 09:59:20 -06001492 });
1493 break;
1494 }
1495 methodNode = methodNode->NextSiblingElement("method");
1496 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001497 }
Matt Spinler318bd892019-01-15 09:59:20 -06001498 interfaceNode = interfaceNode->NextSiblingElement("interface");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001499 }
1500 },
1501 connectionName, transaction->path,
1502 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001503}
1504
zhanghch058d1b46d2021-04-01 11:18:24 +08001505inline void handleAction(const crow::Request& req,
1506 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001507 const std::string& objectPath,
1508 const std::string& methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001509{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001510 BMCWEB_LOG_DEBUG << "handleAction on path: " << objectPath << " and method "
1511 << methodName;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001512 nlohmann::json requestDbusData =
1513 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001514
Ed Tanous1abe55e2018-09-05 08:30:59 -07001515 if (requestDbusData.is_discarded())
1516 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001517 setErrorResponse(asyncResp->res,
1518 boost::beast::http::status::bad_request, noJsonDesc,
1519 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001520 return;
1521 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001522 nlohmann::json::iterator data = requestDbusData.find("data");
1523 if (data == requestDbusData.end())
1524 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001525 setErrorResponse(asyncResp->res,
1526 boost::beast::http::status::bad_request, noJsonDesc,
1527 badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001528 return;
1529 }
1530
1531 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001532 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001533 setErrorResponse(asyncResp->res,
1534 boost::beast::http::status::bad_request, noJsonDesc,
1535 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001536 return;
1537 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001538 auto transaction = std::make_shared<InProgressActionData>(asyncResp->res);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001539
1540 transaction->path = objectPath;
1541 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001542 transaction->arguments = std::move(*data);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001543 crow::connections::systemBus->async_method_call(
1544 [transaction](
1545 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001546 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1547 interfaceNames) {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001548 if (ec || interfaceNames.size() <= 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001549 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001550 BMCWEB_LOG_ERROR << "Can't find object";
Matt Spinler6db06242018-12-11 11:21:22 -06001551 setErrorResponse(transaction->res,
1552 boost::beast::http::status::not_found,
1553 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001554 return;
1555 }
1556
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001557 BMCWEB_LOG_DEBUG << "GetObject returned " << interfaceNames.size()
1558 << " object(s)";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001559
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001560 for (const std::pair<std::string, std::vector<std::string>>&
1561 object : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001562 {
1563 findActionOnInterface(transaction, object.first);
1564 }
1565 },
1566 "xyz.openbmc_project.ObjectMapper",
1567 "/xyz/openbmc_project/object_mapper",
1568 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
1569 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001570}
1571
zhanghch058d1b46d2021-04-01 11:18:24 +08001572inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1573 const std::string& objectPath)
Matt Spinlerde818812018-12-11 16:39:20 -06001574{
1575 BMCWEB_LOG_DEBUG << "handleDelete on path: " << objectPath;
1576
1577 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +08001578 [asyncResp, objectPath](
Matt Spinlerde818812018-12-11 16:39:20 -06001579 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001580 const std::vector<std::pair<std::string, std::vector<std::string>>>&
1581 interfaceNames) {
Matt Spinlerde818812018-12-11 16:39:20 -06001582 if (ec || interfaceNames.size() <= 0)
1583 {
1584 BMCWEB_LOG_ERROR << "Can't find object";
zhanghch058d1b46d2021-04-01 11:18:24 +08001585 setErrorResponse(asyncResp->res,
Matt Spinler62d2e8b2019-01-22 13:45:51 -06001586 boost::beast::http::status::method_not_allowed,
1587 methodNotAllowedDesc, methodNotAllowedMsg);
Matt Spinlerde818812018-12-11 16:39:20 -06001588 return;
1589 }
1590
zhanghch058d1b46d2021-04-01 11:18:24 +08001591 auto transaction =
1592 std::make_shared<InProgressActionData>(asyncResp->res);
Matt Spinlerde818812018-12-11 16:39:20 -06001593 transaction->path = objectPath;
1594 transaction->methodName = "Delete";
1595 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
1596
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001597 for (const std::pair<std::string, std::vector<std::string>>&
1598 object : interfaceNames)
Matt Spinlerde818812018-12-11 16:39:20 -06001599 {
1600 findActionOnInterface(transaction, object.first);
1601 }
1602 },
1603 "xyz.openbmc_project.ObjectMapper",
1604 "/xyz/openbmc_project/object_mapper",
1605 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001606 std::array<const char*, 0>());
Matt Spinlerde818812018-12-11 16:39:20 -06001607}
1608
zhanghch058d1b46d2021-04-01 11:18:24 +08001609inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1610 const std::string& objectPath, int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001611{
1612 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +08001613 [asyncResp](const boost::system::error_code ec,
1614 std::vector<std::string>& objectPaths) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001615 if (ec)
1616 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001617 setErrorResponse(asyncResp->res,
1618 boost::beast::http::status::not_found,
Matt Spinlerd6091dd2018-12-06 14:08:27 -06001619 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001620 }
1621 else
1622 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001623 asyncResp->res.jsonValue = {{"status", "ok"},
1624 {"message", "200 OK"},
1625 {"data", std::move(objectPaths)}};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001626 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001627 },
1628 "xyz.openbmc_project.ObjectMapper",
1629 "/xyz/openbmc_project/object_mapper",
1630 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", objectPath,
Ed Tanousf839dfe2018-11-12 11:11:15 -08001631 depth, std::array<std::string, 0>());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001632}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001633
zhanghch058d1b46d2021-04-01 11:18:24 +08001634inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1635 const std::string& objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001636{
Ed Tanous049a0512018-11-01 13:58:42 -07001637 BMCWEB_LOG_DEBUG << "Doing enumerate on " << objectPath;
Ed Tanous049a0512018-11-01 13:58:42 -07001638
1639 asyncResp->res.jsonValue = {{"message", "200 OK"},
1640 {"status", "ok"},
1641 {"data", nlohmann::json::object()}};
1642
Ed Tanous1abe55e2018-09-05 08:30:59 -07001643 crow::connections::systemBus->async_method_call(
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001644 [objectPath, asyncResp](const boost::system::error_code ec,
Ed Tanous81ce6092020-12-17 16:54:55 +00001645 GetSubTreeType& objectNames) {
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001646 auto transaction = std::make_shared<InProgressEnumerateData>(
1647 objectPath, asyncResp);
1648
1649 transaction->subtree =
Ed Tanous81ce6092020-12-17 16:54:55 +00001650 std::make_shared<GetSubTreeType>(std::move(objectNames));
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001651
Ed Tanous1abe55e2018-09-05 08:30:59 -07001652 if (ec)
1653 {
Matt Spinler2ae60092018-12-06 10:35:36 -06001654 BMCWEB_LOG_ERROR << "GetSubTree failed on "
1655 << transaction->objectPath;
1656 setErrorResponse(transaction->asyncResp->res,
1657 boost::beast::http::status::not_found,
1658 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001659 return;
1660 }
Ed Tanous64530012018-02-06 17:08:16 -08001661
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001662 // Add the data for the path passed in to the results
1663 // as if GetSubTree returned it, and continue on enumerating
1664 getObjectAndEnumerate(transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001665 },
1666 "xyz.openbmc_project.ObjectMapper",
1667 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -07001668 "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath, 0,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001669 std::array<const char*, 0>());
Ed Tanous64530012018-02-06 17:08:16 -08001670}
Ed Tanous911ac312017-08-15 09:37:42 -07001671
zhanghch058d1b46d2021-04-01 11:18:24 +08001672inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1673 std::string& objectPath, std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001674{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001675 BMCWEB_LOG_DEBUG << "handleGet: " << objectPath << " prop:" << destProperty;
1676 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001677 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001678
Ed Tanous1abe55e2018-09-05 08:30:59 -07001679 std::shared_ptr<std::string> path =
1680 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001681
Ed Tanous1abe55e2018-09-05 08:30:59 -07001682 using GetObjectType =
1683 std::vector<std::pair<std::string, std::vector<std::string>>>;
1684 crow::connections::systemBus->async_method_call(
zhanghch058d1b46d2021-04-01 11:18:24 +08001685 [asyncResp, path, propertyName](const boost::system::error_code ec,
1686 const GetObjectType& objectNames) {
Ed Tanous81ce6092020-12-17 16:54:55 +00001687 if (ec || objectNames.size() <= 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001688 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001689 setErrorResponse(asyncResp->res,
1690 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001691 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001692 return;
1693 }
1694 std::shared_ptr<nlohmann::json> response =
1695 std::make_shared<nlohmann::json>(nlohmann::json::object());
Ed Tanous7c091622019-05-23 11:42:36 -07001696 // The mapper should never give us an empty interface names
1697 // list, but check anyway
Ed Tanous23a21a12020-07-25 04:45:05 +00001698 for (const std::pair<std::string, std::vector<std::string>>&
Ed Tanous81ce6092020-12-17 16:54:55 +00001699 connection : objectNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001700 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001701 const std::vector<std::string>& interfaceNames =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001702 connection.second;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001703
Ed Tanous1abe55e2018-09-05 08:30:59 -07001704 if (interfaceNames.size() <= 0)
1705 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001706 setErrorResponse(asyncResp->res,
1707 boost::beast::http::status::not_found,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001708 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001709 return;
1710 }
1711
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001712 for (const std::string& interface : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001713 {
Matt Spinlerfe7e97d2019-01-30 15:33:21 -06001714 sdbusplus::message::message m =
1715 crow::connections::systemBus->new_method_call(
1716 connection.first.c_str(), path->c_str(),
1717 "org.freedesktop.DBus.Properties", "GetAll");
1718 m.append(interface);
1719 crow::connections::systemBus->async_send(
zhanghch058d1b46d2021-04-01 11:18:24 +08001720 m, [asyncResp, response,
Ed Tanous23a21a12020-07-25 04:45:05 +00001721 propertyName](const boost::system::error_code ec2,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001722 sdbusplus::message::message& msg) {
Ed Tanous23a21a12020-07-25 04:45:05 +00001723 if (ec2)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001724 {
1725 BMCWEB_LOG_ERROR << "Bad dbus request error: "
Ed Tanous23a21a12020-07-25 04:45:05 +00001726 << ec2;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001727 }
1728 else
1729 {
Ed Tanous984a4c22021-06-02 13:38:26 -07001730 nlohmann::json properties;
1731 int r =
1732 convertDBusToJSON("a{sv}", msg, properties);
1733 if (r < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001734 {
Ed Tanous984a4c22021-06-02 13:38:26 -07001735 BMCWEB_LOG_ERROR
1736 << "convertDBusToJSON failed";
1737 }
1738 else
1739 {
1740 for (auto& prop : properties.items())
1741 {
1742 // if property name is empty, or
1743 // matches our search query, add it
1744 // to the response json
Ed Tanous1abe55e2018-09-05 08:30:59 -07001745
Ed Tanous984a4c22021-06-02 13:38:26 -07001746 if (propertyName->empty())
1747 {
1748 (*response)[prop.key()] =
1749 std::move(prop.value());
1750 }
1751 else if (prop.key() == *propertyName)
1752 {
1753 *response = std::move(prop.value());
1754 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001755 }
1756 }
1757 }
1758 if (response.use_count() == 1)
1759 {
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001760 if (!propertyName->empty() && response->empty())
1761 {
1762 setErrorResponse(
zhanghch058d1b46d2021-04-01 11:18:24 +08001763 asyncResp->res,
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001764 boost::beast::http::status::not_found,
1765 propNotFoundDesc, notFoundMsg);
1766 }
1767 else
1768 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001769 asyncResp->res.jsonValue = {
1770 {"status", "ok"},
1771 {"message", "200 OK"},
1772 {"data", *response}};
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001773 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001774 }
Matt Spinlerfe7e97d2019-01-30 15:33:21 -06001775 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001776 }
1777 }
1778 },
1779 "xyz.openbmc_project.ObjectMapper",
1780 "/xyz/openbmc_project/object_mapper",
1781 "xyz.openbmc_project.ObjectMapper", "GetObject", *path,
1782 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001783}
1784
Ed Tanous1abe55e2018-09-05 08:30:59 -07001785struct AsyncPutRequest
1786{
zhanghch058d1b46d2021-04-01 11:18:24 +08001787 AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
1788 asyncResp(resIn)
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001789 {}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001790 ~AsyncPutRequest()
1791 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001792 if (asyncResp->res.jsonValue.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001793 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001794 setErrorResponse(asyncResp->res,
1795 boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001796 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001797 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001798 }
1799
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001800 void setErrorStatus(const std::string& desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001801 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001802 setErrorResponse(asyncResp->res,
1803 boost::beast::http::status::internal_server_error,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001804 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001805 }
1806
zhanghch058d1b46d2021-04-01 11:18:24 +08001807 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001808 std::string objectPath;
1809 std::string propertyName;
1810 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001811};
1812
zhanghch058d1b46d2021-04-01 11:18:24 +08001813inline void handlePut(const crow::Request& req,
1814 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +00001815 const std::string& objectPath,
1816 const std::string& destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001817{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001818 if (destProperty.empty())
1819 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001820 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001821 forbiddenResDesc, forbiddenMsg);
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001822 return;
1823 }
1824
Ed Tanous1abe55e2018-09-05 08:30:59 -07001825 nlohmann::json requestDbusData =
1826 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001827
Ed Tanous1abe55e2018-09-05 08:30:59 -07001828 if (requestDbusData.is_discarded())
1829 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001830 setErrorResponse(asyncResp->res,
1831 boost::beast::http::status::bad_request, noJsonDesc,
1832 badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001833 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001834 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001835
Ed Tanous1abe55e2018-09-05 08:30:59 -07001836 nlohmann::json::const_iterator propertyIt = requestDbusData.find("data");
1837 if (propertyIt == requestDbusData.end())
1838 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001839 setErrorResponse(asyncResp->res,
1840 boost::beast::http::status::bad_request, noJsonDesc,
1841 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001842 return;
1843 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001844 const nlohmann::json& propertySetValue = *propertyIt;
zhanghch058d1b46d2021-04-01 11:18:24 +08001845 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001846 transaction->objectPath = objectPath;
1847 transaction->propertyName = destProperty;
1848 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001849
Ed Tanous1abe55e2018-09-05 08:30:59 -07001850 using GetObjectType =
1851 std::vector<std::pair<std::string, std::vector<std::string>>>;
Ed Tanous911ac312017-08-15 09:37:42 -07001852
Ed Tanous1abe55e2018-09-05 08:30:59 -07001853 crow::connections::systemBus->async_method_call(
Ed Tanous23a21a12020-07-25 04:45:05 +00001854 [transaction](const boost::system::error_code ec2,
Ed Tanous81ce6092020-12-17 16:54:55 +00001855 const GetObjectType& objectNames) {
1856 if (!ec2 && objectNames.size() <= 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001857 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001858 setErrorResponse(transaction->asyncResp->res,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001859 boost::beast::http::status::not_found,
1860 propNotFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001861 return;
1862 }
Ed Tanous911ac312017-08-15 09:37:42 -07001863
Ed Tanous23a21a12020-07-25 04:45:05 +00001864 for (const std::pair<std::string, std::vector<std::string>>&
Ed Tanous81ce6092020-12-17 16:54:55 +00001865 connection : objectNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001866 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001867 const std::string& connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001868
Ed Tanous1abe55e2018-09-05 08:30:59 -07001869 crow::connections::systemBus->async_method_call(
1870 [connectionName{std::string(connectionName)},
Ed Tanous23a21a12020-07-25 04:45:05 +00001871 transaction](const boost::system::error_code ec3,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001872 const std::string& introspectXml) {
Ed Tanous23a21a12020-07-25 04:45:05 +00001873 if (ec3)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001874 {
1875 BMCWEB_LOG_ERROR
1876 << "Introspect call failed with error: "
Ed Tanous23a21a12020-07-25 04:45:05 +00001877 << ec3.message()
Ed Tanous1abe55e2018-09-05 08:30:59 -07001878 << " on process: " << connectionName;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001879 transaction->setErrorStatus("Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001880 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001881 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001882 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001883
Ed Tanous1abe55e2018-09-05 08:30:59 -07001884 doc.Parse(introspectXml.c_str());
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001885 tinyxml2::XMLNode* pRoot =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001886 doc.FirstChildElement("node");
1887 if (pRoot == nullptr)
1888 {
1889 BMCWEB_LOG_ERROR << "XML document failed to parse: "
1890 << introspectXml;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001891 transaction->setErrorStatus("Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001892 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001893 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001894 tinyxml2::XMLElement* ifaceNode =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001895 pRoot->FirstChildElement("interface");
1896 while (ifaceNode != nullptr)
1897 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001898 const char* interfaceName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001899 ifaceNode->Attribute("name");
1900 BMCWEB_LOG_DEBUG << "found interface "
1901 << interfaceName;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001902 tinyxml2::XMLElement* propNode =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001903 ifaceNode->FirstChildElement("property");
1904 while (propNode != nullptr)
1905 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001906 const char* propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001907 propNode->Attribute("name");
1908 BMCWEB_LOG_DEBUG << "Found property "
1909 << propertyName;
1910 if (propertyName == transaction->propertyName)
1911 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001912 const char* argType =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001913 propNode->Attribute("type");
1914 if (argType != nullptr)
1915 {
1916 sdbusplus::message::message m =
1917 crow::connections::systemBus
1918 ->new_method_call(
1919 connectionName.c_str(),
1920 transaction->objectPath
1921 .c_str(),
1922 "org.freedesktop.DBus."
1923 "Properties",
1924 "Set");
1925 m.append(interfaceName,
1926 transaction->propertyName);
1927 int r = sd_bus_message_open_container(
1928 m.get(), SD_BUS_TYPE_VARIANT,
1929 argType);
1930 if (r < 0)
1931 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001932 transaction->setErrorStatus(
1933 "Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001934 return;
1935 }
1936 r = convertJsonToDbus(
1937 m.get(), argType,
1938 transaction->propertyValue);
1939 if (r < 0)
1940 {
Adriana Kobylakc66c8592019-08-06 15:08:05 -05001941 if (r == -ERANGE)
1942 {
1943 transaction->setErrorStatus(
1944 "Provided property value "
1945 "is out of range for the "
1946 "property type");
1947 }
1948 else
1949 {
1950 transaction->setErrorStatus(
1951 "Invalid arg type");
1952 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001953 return;
1954 }
1955 r = sd_bus_message_close_container(
1956 m.get());
1957 if (r < 0)
1958 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001959 transaction->setErrorStatus(
1960 "Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001961 return;
1962 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001963 crow::connections::systemBus
1964 ->async_send(
1965 m,
1966 [transaction](
1967 boost::system::error_code
1968 ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001969 sdbusplus::message::message&
Ed Tanous23a21a12020-07-25 04:45:05 +00001970 m2) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001971 BMCWEB_LOG_DEBUG << "sent";
1972 if (ec)
1973 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001974 const sd_bus_error* e =
Ed Tanous23a21a12020-07-25 04:45:05 +00001975 m2.get_error();
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001976 setErrorResponse(
zhanghch058d1b46d2021-04-01 11:18:24 +08001977 transaction
1978 ->asyncResp
1979 ->res,
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001980 boost::beast::http::
1981 status::
1982 forbidden,
Matt Spinler06b1b632019-06-18 16:09:25 -05001983 (e) ? e->name
1984 : ec.category()
1985 .name(),
1986 (e) ? e->message
1987 : ec.message());
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001988 }
1989 else
1990 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001991 transaction->asyncResp
1992 ->res.jsonValue = {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001993 {"status", "ok"},
1994 {"message",
1995 "200 OK"},
1996 {"data", nullptr}};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001997 }
1998 });
1999 }
2000 }
2001 propNode =
2002 propNode->NextSiblingElement("property");
2003 }
2004 ifaceNode =
2005 ifaceNode->NextSiblingElement("interface");
2006 }
2007 },
2008 connectionName, transaction->objectPath,
2009 "org.freedesktop.DBus.Introspectable", "Introspect");
2010 }
2011 },
2012 "xyz.openbmc_project.ObjectMapper",
2013 "/xyz/openbmc_project/object_mapper",
2014 "xyz.openbmc_project.ObjectMapper", "GetObject",
2015 transaction->objectPath, std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07002016}
Ed Tanous1abe55e2018-09-05 08:30:59 -07002017
zhanghch058d1b46d2021-04-01 11:18:24 +08002018inline void handleDBusUrl(const crow::Request& req,
2019 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002020 std::string& objectPath)
Ed Tanous049a0512018-11-01 13:58:42 -07002021{
Ed Tanous049a0512018-11-01 13:58:42 -07002022
2023 // If accessing a single attribute, fill in and update objectPath,
2024 // otherwise leave destProperty blank
2025 std::string destProperty = "";
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002026 const char* attrSeperator = "/attr/";
Ed Tanous049a0512018-11-01 13:58:42 -07002027 size_t attrPosition = objectPath.find(attrSeperator);
2028 if (attrPosition != objectPath.npos)
2029 {
2030 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2031 objectPath.length());
2032 objectPath = objectPath.substr(0, attrPosition);
2033 }
2034
Ed Tanousb41187f2019-10-24 16:30:02 -07002035 if (req.method() == boost::beast::http::verb::post)
Ed Tanous049a0512018-11-01 13:58:42 -07002036 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002037 constexpr const char* actionSeperator = "/action/";
Ed Tanous049a0512018-11-01 13:58:42 -07002038 size_t actionPosition = objectPath.find(actionSeperator);
2039 if (actionPosition != objectPath.npos)
2040 {
2041 std::string postProperty =
2042 objectPath.substr((actionPosition + strlen(actionSeperator)),
2043 objectPath.length());
2044 objectPath = objectPath.substr(0, actionPosition);
zhanghch058d1b46d2021-04-01 11:18:24 +08002045 handleAction(req, asyncResp, objectPath, postProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002046 return;
2047 }
2048 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002049 else if (req.method() == boost::beast::http::verb::get)
Ed Tanous049a0512018-11-01 13:58:42 -07002050 {
2051 if (boost::ends_with(objectPath, "/enumerate"))
2052 {
2053 objectPath.erase(objectPath.end() - sizeof("enumerate"),
2054 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002055 handleEnumerate(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002056 }
2057 else if (boost::ends_with(objectPath, "/list"))
2058 {
2059 objectPath.erase(objectPath.end() - sizeof("list"),
2060 objectPath.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002061 handleList(asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002062 }
2063 else
2064 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08002065 // Trim any trailing "/" at the end
2066 if (boost::ends_with(objectPath, "/"))
2067 {
2068 objectPath.pop_back();
zhanghch058d1b46d2021-04-01 11:18:24 +08002069 handleList(asyncResp, objectPath, 1);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002070 }
2071 else
2072 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002073 handleGet(asyncResp, objectPath, destProperty);
Ed Tanousf839dfe2018-11-12 11:11:15 -08002074 }
Ed Tanous049a0512018-11-01 13:58:42 -07002075 }
2076 return;
2077 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002078 else if (req.method() == boost::beast::http::verb::put)
Ed Tanous049a0512018-11-01 13:58:42 -07002079 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002080 handlePut(req, asyncResp, objectPath, destProperty);
Ed Tanous049a0512018-11-01 13:58:42 -07002081 return;
2082 }
Ed Tanousb41187f2019-10-24 16:30:02 -07002083 else if (req.method() == boost::beast::http::verb::delete_)
Matt Spinlerde818812018-12-11 16:39:20 -06002084 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002085 handleDelete(asyncResp, objectPath);
Matt Spinlerde818812018-12-11 16:39:20 -06002086 return;
2087 }
Ed Tanous049a0512018-11-01 13:58:42 -07002088
zhanghch058d1b46d2021-04-01 11:18:24 +08002089 setErrorResponse(asyncResp->res,
2090 boost::beast::http::status::method_not_allowed,
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06002091 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07002092}
2093
Ed Tanous23a21a12020-07-25 04:45:05 +00002094inline void requestRoutes(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002095{
2096 BMCWEB_ROUTE(app, "/bus/")
Ed Tanous432a8902021-06-14 15:28:56 -07002097 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002098 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002099 [](const crow::Request&,
2100 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2101 asyncResp->res.jsonValue = {{"buses", {{{"name", "system"}}}},
2102 {"status", "ok"}};
Ed Tanous1abe55e2018-09-05 08:30:59 -07002103 });
2104
2105 BMCWEB_ROUTE(app, "/bus/system/")
Ed Tanous432a8902021-06-14 15:28:56 -07002106 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002107 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002108 [](const crow::Request&,
2109 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
P Dheeraj Srujan Kumar83fd8e12021-07-13 02:53:03 +05302110 auto myCallback = [asyncResp](
zhanghch058d1b46d2021-04-01 11:18:24 +08002111 const boost::system::error_code ec,
2112 std::vector<std::string>& names) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07002113 if (ec)
2114 {
2115 BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
zhanghch058d1b46d2021-04-01 11:18:24 +08002116 asyncResp->res.result(
Ed Tanous1abe55e2018-09-05 08:30:59 -07002117 boost::beast::http::status::internal_server_error);
2118 }
2119 else
2120 {
2121 std::sort(names.begin(), names.end());
zhanghch058d1b46d2021-04-01 11:18:24 +08002122 asyncResp->res.jsonValue = {{"status", "ok"}};
2123 auto& objectsSub = asyncResp->res.jsonValue["objects"];
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002124 for (auto& name : names)
Ed Tanous1abe55e2018-09-05 08:30:59 -07002125 {
2126 objectsSub.push_back({{"name", name}});
2127 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002128 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002129 };
2130 crow::connections::systemBus->async_method_call(
2131 std::move(myCallback), "org.freedesktop.DBus", "/",
2132 "org.freedesktop.DBus", "ListNames");
2133 });
2134
2135 BMCWEB_ROUTE(app, "/list/")
Ed Tanous432a8902021-06-14 15:28:56 -07002136 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002137 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002138 [](const crow::Request&,
2139 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2140 handleList(asyncResp, "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07002141 });
2142
2143 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002144 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002145 .methods(boost::beast::http::verb::get)(
2146 [](const crow::Request& req,
2147 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002148 const std::string& path) {
Ed Tanous049a0512018-11-01 13:58:42 -07002149 std::string objectPath = "/xyz/" + path;
zhanghch058d1b46d2021-04-01 11:18:24 +08002150 handleDBusUrl(req, asyncResp, objectPath);
2151 });
2152
2153 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002154 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002155 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2156 boost::beast::http::verb::delete_)(
2157 [](const crow::Request& req,
2158 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2159 const std::string& path) {
2160 std::string objectPath = "/xyz/" + path;
2161 handleDBusUrl(req, asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002162 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002163
Ed Tanous049a0512018-11-01 13:58:42 -07002164 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002165 .privileges({{"Login"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002166 .methods(boost::beast::http::verb::get)(
2167 [](const crow::Request& req,
2168 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2169 const std::string& path) {
2170 std::string objectPath = "/org/" + path;
2171 handleDBusUrl(req, asyncResp, objectPath);
2172 });
Tanousf00032d2018-11-05 01:18:10 -03002173
2174 BMCWEB_ROUTE(app, "/org/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002175 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002176 .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2177 boost::beast::http::verb::delete_)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002178 [](const crow::Request& req,
2179 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002180 const std::string& path) {
Ed Tanouse1281402019-04-03 07:07:10 -07002181 std::string objectPath = "/org/" + path;
zhanghch058d1b46d2021-04-01 11:18:24 +08002182 handleDBusUrl(req, asyncResp, objectPath);
Ed Tanous049a0512018-11-01 13:58:42 -07002183 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002184
Ed Tanous1abe55e2018-09-05 08:30:59 -07002185 BMCWEB_ROUTE(app, "/download/dump/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002186 .privileges({{"ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002187 .methods(boost::beast::http::verb::get)(
2188 [](const crow::Request&,
2189 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2190 const std::string& dumpId) {
2191 std::regex validFilename(R"(^[\w\- ]+(\.?[\w\- ]*)$)");
2192 if (!std::regex_match(dumpId, validFilename))
Ed Tanous1abe55e2018-09-05 08:30:59 -07002193 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002194 asyncResp->res.result(
2195 boost::beast::http::status::bad_request);
Ramesh Iyyard9207042019-07-05 08:04:42 -05002196 return;
2197 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002198 std::filesystem::path loc(
2199 "/var/lib/phosphor-debug-collector/dumps");
Ramesh Iyyard9207042019-07-05 08:04:42 -05002200
zhanghch058d1b46d2021-04-01 11:18:24 +08002201 loc /= dumpId;
Ramesh Iyyard9207042019-07-05 08:04:42 -05002202
zhanghch058d1b46d2021-04-01 11:18:24 +08002203 if (!std::filesystem::exists(loc) ||
2204 !std::filesystem::is_directory(loc))
2205 {
2206 BMCWEB_LOG_ERROR << loc << "Not found";
2207 asyncResp->res.result(
2208 boost::beast::http::status::not_found);
2209 return;
2210 }
2211 std::filesystem::directory_iterator files(loc);
2212
2213 for (auto& file : files)
2214 {
2215 std::ifstream readFile(file.path());
2216 if (!readFile.good())
2217 {
2218 continue;
2219 }
2220
2221 asyncResp->res.addHeader("Content-Type",
2222 "application/octet-stream");
2223
2224 // Assuming only one dump file will be present in the dump
2225 // id directory
2226 std::string dumpFileName = file.path().filename().string();
2227
2228 // Filename should be in alphanumeric, dot and underscore
2229 // Its based on phosphor-debug-collector application
2230 // dumpfile format
2231 std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
2232 if (!std::regex_match(dumpFileName, dumpFileRegex))
2233 {
2234 BMCWEB_LOG_ERROR << "Invalid dump filename "
2235 << dumpFileName;
2236 asyncResp->res.result(
2237 boost::beast::http::status::not_found);
2238 return;
2239 }
2240 std::string contentDispositionParam =
2241 "attachment; filename=\"" + dumpFileName + "\"";
2242
2243 asyncResp->res.addHeader("Content-Disposition",
2244 contentDispositionParam);
2245
2246 asyncResp->res.body() = {
2247 std::istreambuf_iterator<char>(readFile),
2248 std::istreambuf_iterator<char>()};
2249 return;
2250 }
2251 asyncResp->res.result(boost::beast::http::status::not_found);
Ed Tanousad18f072018-11-14 14:07:48 -08002252 return;
zhanghch058d1b46d2021-04-01 11:18:24 +08002253 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002254
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002255 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous432a8902021-06-14 15:28:56 -07002256 .privileges({{"Login"}})
Ed Tanousb41187f2019-10-24 16:30:02 -07002257
2258 .methods(boost::beast::http::verb::get)(
zhanghch058d1b46d2021-04-01 11:18:24 +08002259 [](const crow::Request&,
2260 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous81ce6092020-12-17 16:54:55 +00002261 const std::string& connection) {
Gunnar Mills9062d472021-11-16 11:37:47 -06002262 introspectObjects(
2263 connection, "/",
2264 std::make_shared<bmcweb::AsyncResp>(asyncResp->res));
Ed Tanousb41187f2019-10-24 16:30:02 -07002265 });
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002266
2267 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
Ed Tanous432a8902021-06-14 15:28:56 -07002268 .privileges({{"ConfigureComponents", "ConfigureManager"}})
zhanghch058d1b46d2021-04-01 11:18:24 +08002269 .methods(boost::beast::http::verb::get, boost::beast::http::verb::post)(
2270 [](const crow::Request& req,
2271 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2272 const std::string& processName,
2273 const std::string& requestedPath) {
2274 std::vector<std::string> strs;
2275 boost::split(strs, requestedPath, boost::is_any_of("/"));
2276 std::string objectPath;
2277 std::string interfaceName;
2278 std::string methodName;
2279 auto it = strs.begin();
2280 if (it == strs.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -07002281 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002282 objectPath = "/";
Ed Tanous1abe55e2018-09-05 08:30:59 -07002283 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002284 while (it != strs.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -07002285 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002286 // Check if segment contains ".". If it does, it must be an
2287 // interface
2288 if (it->find(".") != std::string::npos)
2289 {
2290 break;
2291 // This check is necessary as the trailing slash gets
2292 // parsed as part of our <path> specifier above, which
2293 // causes the normal trailing backslash redirector to
2294 // fail.
2295 }
2296 if (!it->empty())
2297 {
2298 objectPath += "/" + *it;
2299 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07002300 it++;
2301 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002302 if (it != strs.end())
2303 {
2304 interfaceName = *it;
2305 it++;
Ed Tanous7c091622019-05-23 11:42:36 -07002306
zhanghch058d1b46d2021-04-01 11:18:24 +08002307 // after interface, we might have a method name
2308 if (it != strs.end())
2309 {
2310 methodName = *it;
2311 it++;
2312 }
2313 }
2314 if (it != strs.end())
2315 {
2316 // if there is more levels past the method name, something
2317 // went wrong, return not found
2318 asyncResp->res.result(
2319 boost::beast::http::status::not_found);
2320 return;
2321 }
2322 if (interfaceName.empty())
2323 {
2324 crow::connections::systemBus->async_method_call(
2325 [asyncResp, processName,
2326 objectPath](const boost::system::error_code ec,
2327 const std::string& introspectXml) {
2328 if (ec)
2329 {
2330 BMCWEB_LOG_ERROR
2331 << "Introspect call failed with error: "
2332 << ec.message()
2333 << " on process: " << processName
2334 << " path: " << objectPath << "\n";
2335 return;
2336 }
2337 tinyxml2::XMLDocument doc;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002338
zhanghch058d1b46d2021-04-01 11:18:24 +08002339 doc.Parse(introspectXml.c_str());
2340 tinyxml2::XMLNode* pRoot =
2341 doc.FirstChildElement("node");
2342 if (pRoot == nullptr)
2343 {
2344 BMCWEB_LOG_ERROR
2345 << "XML document failed to parse "
2346 << processName << " " << objectPath << "\n";
2347 asyncResp->res.jsonValue = {
2348 {"status", "XML parse error"}};
2349 asyncResp->res.result(
2350 boost::beast::http::status::
2351 internal_server_error);
2352 return;
2353 }
2354
2355 BMCWEB_LOG_DEBUG << introspectXml;
Ed Tanous7c091622019-05-23 11:42:36 -07002356 asyncResp->res.jsonValue = {
zhanghch058d1b46d2021-04-01 11:18:24 +08002357 {"status", "ok"},
2358 {"bus_name", processName},
2359 {"object_path", objectPath}};
2360 nlohmann::json& interfacesArray =
2361 asyncResp->res.jsonValue["interfaces"];
2362 interfacesArray = nlohmann::json::array();
2363 tinyxml2::XMLElement* interface =
2364 pRoot->FirstChildElement("interface");
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002365
zhanghch058d1b46d2021-04-01 11:18:24 +08002366 while (interface != nullptr)
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002367 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002368 const char* ifaceName =
2369 interface->Attribute("name");
2370 if (ifaceName != nullptr)
Ed Tanous7c091622019-05-23 11:42:36 -07002371 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002372 interfacesArray.push_back(
2373 {{"name", ifaceName}});
2374 }
2375
2376 interface =
2377 interface->NextSiblingElement("interface");
2378 }
2379 },
2380 processName, objectPath,
2381 "org.freedesktop.DBus.Introspectable", "Introspect");
2382 }
2383 else if (methodName.empty())
2384 {
2385 crow::connections::systemBus->async_method_call(
2386 [asyncResp, processName, objectPath,
2387 interfaceName](const boost::system::error_code ec,
2388 const std::string& introspectXml) {
2389 if (ec)
2390 {
2391 BMCWEB_LOG_ERROR
2392 << "Introspect call failed with error: "
2393 << ec.message()
2394 << " on process: " << processName
2395 << " path: " << objectPath << "\n";
2396 return;
2397 }
2398 tinyxml2::XMLDocument doc;
2399
2400 doc.Parse(introspectXml.data(),
2401 introspectXml.size());
2402 tinyxml2::XMLNode* pRoot =
2403 doc.FirstChildElement("node");
2404 if (pRoot == nullptr)
2405 {
2406 BMCWEB_LOG_ERROR
2407 << "XML document failed to parse "
2408 << processName << " " << objectPath << "\n";
2409 asyncResp->res.result(
2410 boost::beast::http::status::
2411 internal_server_error);
2412 return;
2413 }
2414 asyncResp->res.jsonValue = {
2415 {"status", "ok"},
2416 {"bus_name", processName},
2417 {"interface", interfaceName},
2418 {"object_path", objectPath}};
2419
2420 nlohmann::json& methodsArray =
2421 asyncResp->res.jsonValue["methods"];
2422 methodsArray = nlohmann::json::array();
2423
2424 nlohmann::json& signalsArray =
2425 asyncResp->res.jsonValue["signals"];
2426 signalsArray = nlohmann::json::array();
2427
2428 nlohmann::json& propertiesObj =
2429 asyncResp->res.jsonValue["properties"];
2430 propertiesObj = nlohmann::json::object();
2431
2432 // if we know we're the only call, build the
2433 // json directly
2434 tinyxml2::XMLElement* interface =
2435 pRoot->FirstChildElement("interface");
2436 while (interface != nullptr)
2437 {
2438 const char* ifaceName =
2439 interface->Attribute("name");
2440
2441 if (ifaceName != nullptr &&
2442 ifaceName == interfaceName)
2443 {
2444 break;
2445 }
2446
2447 interface =
2448 interface->NextSiblingElement("interface");
2449 }
2450 if (interface == nullptr)
2451 {
2452 // if we got to the end of the list and
2453 // never found a match, throw 404
2454 asyncResp->res.result(
2455 boost::beast::http::status::not_found);
2456 return;
2457 }
2458
2459 tinyxml2::XMLElement* methods =
2460 interface->FirstChildElement("method");
2461 while (methods != nullptr)
2462 {
2463 nlohmann::json argsArray =
2464 nlohmann::json::array();
2465 tinyxml2::XMLElement* arg =
2466 methods->FirstChildElement("arg");
2467 while (arg != nullptr)
2468 {
2469 nlohmann::json thisArg;
2470 for (const char* fieldName :
2471 std::array<const char*, 3>{
2472 "name", "direction", "type"})
Ed Tanous7c091622019-05-23 11:42:36 -07002473 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002474 const char* fieldValue =
2475 arg->Attribute(fieldName);
2476 if (fieldValue != nullptr)
Ed Tanous7c091622019-05-23 11:42:36 -07002477 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002478 thisArg[fieldName] = fieldValue;
Ed Tanous7c091622019-05-23 11:42:36 -07002479 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002480 }
2481 argsArray.push_back(std::move(thisArg));
2482 arg = arg->NextSiblingElement("arg");
2483 }
Ed Tanous7c091622019-05-23 11:42:36 -07002484
zhanghch058d1b46d2021-04-01 11:18:24 +08002485 const char* name = methods->Attribute("name");
2486 if (name != nullptr)
2487 {
2488 std::string uri;
2489 uri.reserve(14 + processName.size() +
2490 objectPath.size() +
2491 interfaceName.size() +
2492 strlen(name));
2493 uri += "/bus/system/";
2494 uri += processName;
2495 uri += objectPath;
2496 uri += "/";
2497 uri += interfaceName;
2498 uri += "/";
2499 uri += name;
2500 methodsArray.push_back(
2501 {{"name", name},
2502 {"uri", std::move(uri)},
2503 {"args", argsArray}});
2504 }
2505 methods = methods->NextSiblingElement("method");
Ed Tanous7c091622019-05-23 11:42:36 -07002506 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002507 tinyxml2::XMLElement* signals =
2508 interface->FirstChildElement("signal");
2509 while (signals != nullptr)
2510 {
2511 nlohmann::json argsArray =
2512 nlohmann::json::array();
2513
2514 tinyxml2::XMLElement* arg =
2515 signals->FirstChildElement("arg");
2516 while (arg != nullptr)
2517 {
2518 const char* name = arg->Attribute("name");
2519 const char* type = arg->Attribute("type");
2520 if (name != nullptr && type != nullptr)
2521 {
2522 argsArray.push_back({
2523 {"name", name},
2524 {"type", type},
2525 });
2526 }
2527 arg = arg->NextSiblingElement("arg");
2528 }
2529 const char* name = signals->Attribute("name");
2530 if (name != nullptr)
2531 {
2532 signalsArray.push_back(
2533 {{"name", name}, {"args", argsArray}});
2534 }
2535
2536 signals = signals->NextSiblingElement("signal");
2537 }
2538
2539 tinyxml2::XMLElement* property =
2540 interface->FirstChildElement("property");
2541 while (property != nullptr)
2542 {
2543 const char* name = property->Attribute("name");
2544 const char* type = property->Attribute("type");
2545 if (type != nullptr && name != nullptr)
2546 {
2547 sdbusplus::message::message m =
2548 crow::connections::systemBus
2549 ->new_method_call(
2550 processName.c_str(),
2551 objectPath.c_str(),
2552 "org.freedesktop."
2553 "DBus."
2554 "Properties",
2555 "Get");
2556 m.append(interfaceName, name);
2557 nlohmann::json& propertyItem =
2558 propertiesObj[name];
2559 crow::connections::systemBus->async_send(
2560 m,
2561 [&propertyItem, asyncResp](
2562 boost::system::error_code& e,
2563 sdbusplus::message::message& msg) {
2564 if (e)
2565 {
2566 return;
2567 }
2568
2569 convertDBusToJSON("v", msg,
2570 propertyItem);
2571 });
2572 }
2573 property =
2574 property->NextSiblingElement("property");
2575 }
2576 },
2577 processName, objectPath,
2578 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002579 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002580 else
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002581 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002582 if (req.method() != boost::beast::http::verb::post)
2583 {
2584 asyncResp->res.result(
2585 boost::beast::http::status::not_found);
2586 return;
2587 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002588
zhanghch058d1b46d2021-04-01 11:18:24 +08002589 nlohmann::json requestDbusData =
2590 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanouse3cb5a32018-08-08 14:16:49 -07002591
zhanghch058d1b46d2021-04-01 11:18:24 +08002592 if (requestDbusData.is_discarded())
2593 {
2594 asyncResp->res.result(
2595 boost::beast::http::status::bad_request);
2596 return;
2597 }
2598 if (!requestDbusData.is_array())
2599 {
2600 asyncResp->res.result(
2601 boost::beast::http::status::bad_request);
2602 return;
2603 }
2604 auto transaction =
2605 std::make_shared<InProgressActionData>(asyncResp->res);
2606
2607 transaction->path = objectPath;
2608 transaction->methodName = methodName;
2609 transaction->arguments = std::move(requestDbusData);
2610
2611 findActionOnInterface(transaction, processName);
2612 }
2613 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07002614}
2615} // namespace openbmc_mapper
2616} // namespace crow