140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0
240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
340e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright 2018 Intel Corporation
4b9b2e0b2SEd Tanous
55b4aa86bSJames Feist #pragma once
63ccb3adbSEd Tanous #include "app.hpp"
73ccb3adbSEd Tanous #include "async_resp.hpp"
895c6307aSEd Tanous #include "boost_formatters.hpp"
93ccb3adbSEd Tanous #include "dbus_singleton.hpp"
107a1dbc48SGeorge Liu #include "dbus_utility.hpp"
11d5c80ad9SNan Zhou #include "http_request.hpp"
12d5c80ad9SNan Zhou #include "http_response.hpp"
1395c6307aSEd Tanous #include "json_formatters.hpp"
14d5c80ad9SNan Zhou #include "logging.hpp"
151aa0c2b8SEd Tanous #include "parsing.hpp"
1650ebd4afSEd Tanous #include "str_utility.hpp"
17d5c80ad9SNan Zhou
18d5c80ad9SNan Zhou #include <systemd/sd-bus-protocol.h>
19d5c80ad9SNan Zhou #include <systemd/sd-bus.h>
20911ac317SEd Tanous #include <tinyxml2.h>
211abe55efSEd Tanous
22*d7857201SEd Tanous #include <boost/beast/http/field.hpp>
23d5c80ad9SNan Zhou #include <boost/beast/http/status.hpp>
24d5c80ad9SNan Zhou #include <boost/beast/http/verb.hpp>
25d5c80ad9SNan Zhou #include <boost/container/flat_map.hpp>
26e99073f5SGeorge Liu #include <boost/system/error_code.hpp>
27d5c80ad9SNan Zhou #include <nlohmann/json.hpp>
28d5c80ad9SNan Zhou #include <sdbusplus/asio/connection.hpp>
29d5c80ad9SNan Zhou #include <sdbusplus/message.hpp>
30d5c80ad9SNan Zhou #include <sdbusplus/message/native_types.hpp>
311214b7e7SGunnar Mills
32d5c80ad9SNan Zhou #include <algorithm>
33d5c80ad9SNan Zhou #include <array>
34d5c80ad9SNan Zhou #include <cerrno>
35d5c80ad9SNan Zhou #include <cstdint>
36d5c80ad9SNan Zhou #include <cstring>
374418c7f0SJames Feist #include <filesystem>
38d5c80ad9SNan Zhou #include <functional>
39d5c80ad9SNan Zhou #include <initializer_list>
40d5c80ad9SNan Zhou #include <limits>
41d5c80ad9SNan Zhou #include <map>
42d5c80ad9SNan Zhou #include <memory>
433544d2a7SEd Tanous #include <ranges>
44d9207047SRamesh Iyyar #include <regex>
45d5c80ad9SNan Zhou #include <string>
46d5c80ad9SNan Zhou #include <string_view>
47d5c80ad9SNan Zhou #include <type_traits>
48b5a76932SEd Tanous #include <utility>
49d5c80ad9SNan Zhou #include <variant>
50d5c80ad9SNan Zhou #include <vector>
51d5c80ad9SNan Zhou
521abe55efSEd Tanous namespace crow
531abe55efSEd Tanous {
541abe55efSEd Tanous namespace openbmc_mapper
551abe55efSEd Tanous {
5623a21a1cSEd Tanous const constexpr char* notFoundMsg = "404 Not Found";
5723a21a1cSEd Tanous const constexpr char* badReqMsg = "400 Bad Request";
5823a21a1cSEd Tanous const constexpr char* methodNotAllowedMsg = "405 Method Not Allowed";
5923a21a1cSEd Tanous const constexpr char* forbiddenMsg = "403 Forbidden";
601aa0c2b8SEd Tanous const constexpr char* unsupportedMediaMsg = "415 Unsupported Media Type";
6123a21a1cSEd Tanous const constexpr char* methodFailedMsg = "500 Method Call Failed";
6223a21a1cSEd Tanous const constexpr char* methodOutputFailedMsg = "500 Method Output Error";
6323a21a1cSEd Tanous const constexpr char* notFoundDesc =
642ae60096SMatt Spinler "org.freedesktop.DBus.Error.FileNotFound: path or object not found";
6523a21a1cSEd Tanous const constexpr char* propNotFoundDesc =
6623a21a1cSEd Tanous "The specified property cannot be found";
6723a21a1cSEd Tanous const constexpr char* noJsonDesc = "No JSON object could be decoded";
681aa0c2b8SEd Tanous const constexpr char* invalidContentType =
691aa0c2b8SEd Tanous "Content-type header is missing or invalid";
7023a21a1cSEd Tanous const constexpr char* methodNotFoundDesc =
7123a21a1cSEd Tanous "The specified method cannot be found";
7223a21a1cSEd Tanous const constexpr char* methodNotAllowedDesc = "Method not allowed";
7323a21a1cSEd Tanous const constexpr char* forbiddenPropDesc =
7423a21a1cSEd Tanous "The specified property cannot be created";
7523a21a1cSEd Tanous const constexpr char* forbiddenResDesc =
7623a21a1cSEd Tanous "The specified resource cannot be created";
772ae60096SMatt Spinler
validateFilename(const std::string & filename)78482c45a5SJosh Lehan inline bool validateFilename(const std::string& filename)
79482c45a5SJosh Lehan {
804b242749SEd Tanous static std::regex validFilename(R"(^[\w\- ]+(\.?[\w\- ]*)$)");
81482c45a5SJosh Lehan
82482c45a5SJosh Lehan return std::regex_match(filename, validFilename);
83482c45a5SJosh Lehan }
84482c45a5SJosh Lehan
setErrorResponse(crow::Response & res,boost::beast::http::status result,const std::string & desc,std::string_view msg)8523a21a1cSEd Tanous inline void setErrorResponse(crow::Response& res,
8623a21a1cSEd Tanous boost::beast::http::status result,
8726ccae32SEd Tanous const std::string& desc, std::string_view msg)
882ae60096SMatt Spinler {
892ae60096SMatt Spinler res.result(result);
901476687dSEd Tanous res.jsonValue["data"]["description"] = desc;
911476687dSEd Tanous res.jsonValue["message"] = msg;
921476687dSEd Tanous res.jsonValue["status"] = "error";
932ae60096SMatt Spinler }
942ae60096SMatt Spinler
introspectObjects(const std::string & processName,const std::string & objectPath,const std::shared_ptr<bmcweb::AsyncResp> & transaction)95bd79bce8SPatrick Williams inline void introspectObjects(
96bd79bce8SPatrick Williams const std::string& processName, const std::string& objectPath,
97b5a76932SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& transaction)
981abe55efSEd Tanous {
99e3cb5a31SEd Tanous if (transaction->res.jsonValue.is_null())
100e3cb5a31SEd Tanous {
1011476687dSEd Tanous transaction->res.jsonValue["status"] = "ok";
1021476687dSEd Tanous transaction->res.jsonValue["bus_name"] = processName;
1031476687dSEd Tanous transaction->res.jsonValue["objects"] = nlohmann::json::array();
104e3cb5a31SEd Tanous }
105e3cb5a31SEd Tanous
10655c7b7a2SEd Tanous crow::connections::systemBus->async_method_call(
107e3cb5a31SEd Tanous [transaction, processName{std::string(processName)},
108e3cb5a31SEd Tanous objectPath{std::string(objectPath)}](
1095e7e2dc5SEd Tanous const boost::system::error_code& ec,
11081ce609eSEd Tanous const std::string& introspectXml) {
1111abe55efSEd Tanous if (ec)
1121abe55efSEd Tanous {
11362598e31SEd Tanous BMCWEB_LOG_ERROR(
11462598e31SEd Tanous "Introspect call failed with error: {} on process: {} path: {}",
11562598e31SEd Tanous ec.message(), processName, objectPath);
116e3cb5a31SEd Tanous return;
1171abe55efSEd Tanous }
1181476687dSEd Tanous nlohmann::json::object_t object;
1191476687dSEd Tanous object["path"] = objectPath;
1201476687dSEd Tanous
121bd79bce8SPatrick Williams transaction->res.jsonValue["objects"].emplace_back(
122bd79bce8SPatrick Williams std::move(object));
123911ac317SEd Tanous
124911ac317SEd Tanous tinyxml2::XMLDocument doc;
125911ac317SEd Tanous
12681ce609eSEd Tanous doc.Parse(introspectXml.c_str());
127911ac317SEd Tanous tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1281abe55efSEd Tanous if (pRoot == nullptr)
1291abe55efSEd Tanous {
130bd79bce8SPatrick Williams BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
131bd79bce8SPatrick Williams processName, objectPath);
1321abe55efSEd Tanous }
1331abe55efSEd Tanous else
1341abe55efSEd Tanous {
135e3cb5a31SEd Tanous tinyxml2::XMLElement* node = pRoot->FirstChildElement("node");
1361abe55efSEd Tanous while (node != nullptr)
1371abe55efSEd Tanous {
138e3cb5a31SEd Tanous const char* childPath = node->Attribute("name");
139e3cb5a31SEd Tanous if (childPath != nullptr)
140e3cb5a31SEd Tanous {
141911ac317SEd Tanous std::string newpath;
1421abe55efSEd Tanous if (objectPath != "/")
1431abe55efSEd Tanous {
14455c7b7a2SEd Tanous newpath += objectPath;
145911ac317SEd Tanous }
146e3cb5a31SEd Tanous newpath += std::string("/") + childPath;
14764530018SEd Tanous // introspect the subobjects as well
148e3cb5a31SEd Tanous introspectObjects(processName, newpath, transaction);
149e3cb5a31SEd Tanous }
150911ac317SEd Tanous
151911ac317SEd Tanous node = node->NextSiblingElement("node");
152911ac317SEd Tanous }
153911ac317SEd Tanous }
154911ac317SEd Tanous },
155e3cb5a31SEd Tanous processName, objectPath, "org.freedesktop.DBus.Introspectable",
1561abe55efSEd Tanous "Introspect");
157911ac317SEd Tanous }
15864530018SEd Tanous
getPropertiesForEnumerate(const std::string & objectPath,const std::string & service,const std::string & interface,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)15923a21a1cSEd Tanous inline void getPropertiesForEnumerate(
16023a21a1cSEd Tanous const std::string& objectPath, const std::string& service,
161b5a76932SEd Tanous const std::string& interface,
162b5a76932SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1632df1e7dbSMatt Spinler {
16462598e31SEd Tanous BMCWEB_LOG_DEBUG("getPropertiesForEnumerate {} {} {}", objectPath, service,
16562598e31SEd Tanous interface);
1662df1e7dbSMatt Spinler
167deae6a78SEd Tanous dbus::utility::getAllProperties(
168deae6a78SEd Tanous service, objectPath, interface,
169b9d36b47SEd Tanous [asyncResp, objectPath, service,
1705e7e2dc5SEd Tanous interface](const boost::system::error_code& ec,
171b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& propertiesList) {
1722df1e7dbSMatt Spinler if (ec)
1732df1e7dbSMatt Spinler {
17462598e31SEd Tanous BMCWEB_LOG_ERROR(
17562598e31SEd Tanous "GetAll on path {} iface {} service {} failed with code {}",
17662598e31SEd Tanous objectPath, interface, service, ec);
1772df1e7dbSMatt Spinler return;
1782df1e7dbSMatt Spinler }
1792df1e7dbSMatt Spinler
1802df1e7dbSMatt Spinler nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
1812df1e7dbSMatt Spinler nlohmann::json& objectJson = dataJson[objectPath];
1822df1e7dbSMatt Spinler if (objectJson.is_null())
1832df1e7dbSMatt Spinler {
1842df1e7dbSMatt Spinler objectJson = nlohmann::json::object();
1852df1e7dbSMatt Spinler }
1862df1e7dbSMatt Spinler
1872df1e7dbSMatt Spinler for (const auto& [name, value] : propertiesList)
1882df1e7dbSMatt Spinler {
1892df1e7dbSMatt Spinler nlohmann::json& propertyJson = objectJson[name];
190e3648032SEd Tanous std::visit([&propertyJson](auto&& val) { propertyJson = val; },
191abf2add6SEd Tanous value);
1922df1e7dbSMatt Spinler }
193c1343bf6SKrzysztof Grobelny });
1942df1e7dbSMatt Spinler }
1952df1e7dbSMatt Spinler
1962df1e7dbSMatt Spinler // Find any results that weren't picked up by ObjectManagers, to be
1972df1e7dbSMatt Spinler // called after all ObjectManagers are searched for and called.
findRemainingObjectsForEnumerate(const std::string & objectPath,const std::shared_ptr<dbus::utility::MapperGetSubTreeResponse> & subtree,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)19823a21a1cSEd Tanous inline void findRemainingObjectsForEnumerate(
199b5a76932SEd Tanous const std::string& objectPath,
200b9d36b47SEd Tanous const std::shared_ptr<dbus::utility::MapperGetSubTreeResponse>& subtree,
201b5a76932SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2022df1e7dbSMatt Spinler {
20362598e31SEd Tanous BMCWEB_LOG_DEBUG("findRemainingObjectsForEnumerate");
2042df1e7dbSMatt Spinler const nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
2052df1e7dbSMatt Spinler
2062df1e7dbSMatt Spinler for (const auto& [path, interface_map] : *subtree)
2072df1e7dbSMatt Spinler {
2082df1e7dbSMatt Spinler if (path == objectPath)
2092df1e7dbSMatt Spinler {
2102df1e7dbSMatt Spinler // An enumerate does not return the target path's properties
2112df1e7dbSMatt Spinler continue;
2122df1e7dbSMatt Spinler }
2132df1e7dbSMatt Spinler if (dataJson.find(path) == dataJson.end())
2142df1e7dbSMatt Spinler {
2152df1e7dbSMatt Spinler for (const auto& [service, interfaces] : interface_map)
2162df1e7dbSMatt Spinler {
2172df1e7dbSMatt Spinler for (const auto& interface : interfaces)
2182df1e7dbSMatt Spinler {
21911ba3979SEd Tanous if (!interface.starts_with("org.freedesktop.DBus"))
2202df1e7dbSMatt Spinler {
2212df1e7dbSMatt Spinler getPropertiesForEnumerate(path, service, interface,
2222df1e7dbSMatt Spinler asyncResp);
2232df1e7dbSMatt Spinler }
2242df1e7dbSMatt Spinler }
2252df1e7dbSMatt Spinler }
2262df1e7dbSMatt Spinler }
2272df1e7dbSMatt Spinler }
2282df1e7dbSMatt Spinler }
2292df1e7dbSMatt Spinler
2303ae4ba7bSMatt Spinler struct InProgressEnumerateData
2313ae4ba7bSMatt Spinler {
InProgressEnumerateDatacrow::openbmc_mapper::InProgressEnumerateData2328d1b46d7Szhanghch05 InProgressEnumerateData(
2338d1b46d7Szhanghch05 const std::string& objectPathIn,
2348d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
235bd79bce8SPatrick Williams objectPath(objectPathIn), asyncResp(asyncRespIn)
2361214b7e7SGunnar Mills {}
2373ae4ba7bSMatt Spinler
~InProgressEnumerateDatacrow::openbmc_mapper::InProgressEnumerateData2383ae4ba7bSMatt Spinler ~InProgressEnumerateData()
2393ae4ba7bSMatt Spinler {
24024b2fe81SEd Tanous try
24124b2fe81SEd Tanous {
2422df1e7dbSMatt Spinler findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
2433ae4ba7bSMatt Spinler }
24424b2fe81SEd Tanous catch (...)
24524b2fe81SEd Tanous {
24662598e31SEd Tanous BMCWEB_LOG_CRITICAL(
24762598e31SEd Tanous "findRemainingObjectsForEnumerate threw exception");
24824b2fe81SEd Tanous }
24924b2fe81SEd Tanous }
2503ae4ba7bSMatt Spinler
251ecd6a3a2SEd Tanous InProgressEnumerateData(const InProgressEnumerateData&) = delete;
252ecd6a3a2SEd Tanous InProgressEnumerateData(InProgressEnumerateData&&) = delete;
253ecd6a3a2SEd Tanous InProgressEnumerateData& operator=(const InProgressEnumerateData&) = delete;
254ecd6a3a2SEd Tanous InProgressEnumerateData& operator=(InProgressEnumerateData&&) = delete;
2553ae4ba7bSMatt Spinler const std::string objectPath;
256b9d36b47SEd Tanous std::shared_ptr<dbus::utility::MapperGetSubTreeResponse> subtree;
2573ae4ba7bSMatt Spinler std::shared_ptr<bmcweb::AsyncResp> asyncResp;
2583ae4ba7bSMatt Spinler };
2593ae4ba7bSMatt Spinler
getManagedObjectsForEnumerate(const std::string & objectName,const std::string & objectManagerPath,const std::string & connectionName,const std::shared_ptr<InProgressEnumerateData> & transaction)26023a21a1cSEd Tanous inline void getManagedObjectsForEnumerate(
26181ce609eSEd Tanous const std::string& objectName, const std::string& objectManagerPath,
26281ce609eSEd Tanous const std::string& connectionName,
263b5a76932SEd Tanous const std::shared_ptr<InProgressEnumerateData>& transaction)
2641abe55efSEd Tanous {
26562598e31SEd Tanous BMCWEB_LOG_DEBUG(
26662598e31SEd Tanous "getManagedObjectsForEnumerate {} object_manager_path {} connection_name {}",
26762598e31SEd Tanous objectName, objectManagerPath, connectionName);
2685eb468daSGeorge Liu sdbusplus::message::object_path path(objectManagerPath);
2695eb468daSGeorge Liu dbus::utility::getManagedObjects(
2705eb468daSGeorge Liu connectionName, path,
27181ce609eSEd Tanous [transaction, objectName,
2725e7e2dc5SEd Tanous connectionName](const boost::system::error_code& ec,
2735b4aa86bSJames Feist const dbus::utility::ManagedObjectType& objects) {
2741abe55efSEd Tanous if (ec)
2751abe55efSEd Tanous {
27662598e31SEd Tanous BMCWEB_LOG_ERROR(
27762598e31SEd Tanous "GetManagedObjects on path {} on connection {} failed with code {}",
27862598e31SEd Tanous objectName, connectionName, ec);
279049a0515SEd Tanous return;
2801abe55efSEd Tanous }
281aa2e59c1SEd Tanous
2823ae4ba7bSMatt Spinler nlohmann::json& dataJson =
2833ae4ba7bSMatt Spinler transaction->asyncResp->res.jsonValue["data"];
284049a0515SEd Tanous
285049a0515SEd Tanous for (const auto& objectPath : objects)
2861abe55efSEd Tanous {
28711ba3979SEd Tanous if (objectPath.first.str.starts_with(objectName))
288049a0515SEd Tanous {
28962598e31SEd Tanous BMCWEB_LOG_DEBUG("Reading object {}", objectPath.first.str);
290049a0515SEd Tanous nlohmann::json& objectJson = dataJson[objectPath.first.str];
2911abe55efSEd Tanous if (objectJson.is_null())
2921abe55efSEd Tanous {
29355c7b7a2SEd Tanous objectJson = nlohmann::json::object();
294aa2e59c1SEd Tanous }
2951abe55efSEd Tanous for (const auto& interface : objectPath.second)
2961abe55efSEd Tanous {
2971abe55efSEd Tanous for (const auto& property : interface.second)
2981abe55efSEd Tanous {
2991abe55efSEd Tanous nlohmann::json& propertyJson =
3001abe55efSEd Tanous objectJson[property.first];
301d1a64814SEd Tanous std::visit(
302d1a64814SEd Tanous [&propertyJson](auto&& val) {
303bd79bce8SPatrick Williams if constexpr (
304bd79bce8SPatrick Williams std::is_same_v<
305d1a64814SEd Tanous std::decay_t<decltype(val)>,
306d1a64814SEd Tanous sdbusplus::message::unix_fd>)
307d1a64814SEd Tanous {
308d1a64814SEd Tanous propertyJson = val.fd;
309d1a64814SEd Tanous }
310d1a64814SEd Tanous else
311d1a64814SEd Tanous {
312d1a64814SEd Tanous propertyJson = val;
313d1a64814SEd Tanous }
314d1a64814SEd Tanous },
31564530018SEd Tanous property.second);
31664530018SEd Tanous }
31764530018SEd Tanous }
31864530018SEd Tanous }
319049a0515SEd Tanous for (const auto& interface : objectPath.second)
3201abe55efSEd Tanous {
321049a0515SEd Tanous if (interface.first == "org.freedesktop.DBus.ObjectManager")
322049a0515SEd Tanous {
323bd79bce8SPatrick Williams getManagedObjectsForEnumerate(
324bd79bce8SPatrick Williams objectPath.first.str, objectPath.first.str,
32581ce609eSEd Tanous connectionName, transaction);
326049a0515SEd Tanous }
327049a0515SEd Tanous }
32864530018SEd Tanous }
3295eb468daSGeorge Liu });
330e3cb5a31SEd Tanous }
331e3cb5a31SEd Tanous
findObjectManagerPathForEnumerate(const std::string & objectName,const std::string & connectionName,const std::shared_ptr<InProgressEnumerateData> & transaction)33223a21a1cSEd Tanous inline void findObjectManagerPathForEnumerate(
33381ce609eSEd Tanous const std::string& objectName, const std::string& connectionName,
334b5a76932SEd Tanous const std::shared_ptr<InProgressEnumerateData>& transaction)
335e3cb5a31SEd Tanous {
33662598e31SEd Tanous BMCWEB_LOG_DEBUG("Finding objectmanager for path {} on connection:{}",
33762598e31SEd Tanous objectName, connectionName);
338e3cb5a31SEd Tanous crow::connections::systemBus->async_method_call(
33981ce609eSEd Tanous [transaction, objectName, connectionName](
3405e7e2dc5SEd Tanous const boost::system::error_code& ec,
341b9d36b47SEd Tanous const dbus::utility::MapperGetAncestorsResponse& objects) {
342e3cb5a31SEd Tanous if (ec)
343e3cb5a31SEd Tanous {
34462598e31SEd Tanous BMCWEB_LOG_ERROR("GetAncestors on path {} failed with code {}",
34562598e31SEd Tanous objectName, ec);
346e3cb5a31SEd Tanous return;
347e3cb5a31SEd Tanous }
348e3cb5a31SEd Tanous
349f254ba77SEd Tanous for (const auto& pathGroup : objects)
350e3cb5a31SEd Tanous {
351f254ba77SEd Tanous for (const auto& connectionGroup : pathGroup.second)
352e3cb5a31SEd Tanous {
35381ce609eSEd Tanous if (connectionGroup.first == connectionName)
354e3cb5a31SEd Tanous {
355e3cb5a31SEd Tanous // Found the object manager path for this resource.
356bd79bce8SPatrick Williams getManagedObjectsForEnumerate(
357bd79bce8SPatrick Williams objectName, pathGroup.first, connectionName,
358bd79bce8SPatrick Williams transaction);
359e3cb5a31SEd Tanous return;
360e3cb5a31SEd Tanous }
361e3cb5a31SEd Tanous }
362e3cb5a31SEd Tanous }
363e3cb5a31SEd Tanous },
364e3cb5a31SEd Tanous "xyz.openbmc_project.ObjectMapper",
365e3cb5a31SEd Tanous "/xyz/openbmc_project/object_mapper",
36681ce609eSEd Tanous "xyz.openbmc_project.ObjectMapper", "GetAncestors", objectName,
367e3cb5a31SEd Tanous std::array<const char*, 1>{"org.freedesktop.DBus.ObjectManager"});
368aa2e59c1SEd Tanous }
36964530018SEd Tanous
3707c09162aSEd Tanous // Uses GetObject to add the object info about the target /enumerate path to
3717c09162aSEd Tanous // the results of GetSubTree, as GetSubTree will not return info for the
3723ae4ba7bSMatt Spinler // target path, and then continues on enumerating the rest of the tree.
getObjectAndEnumerate(const std::shared_ptr<InProgressEnumerateData> & transaction)373b5a76932SEd Tanous inline void getObjectAndEnumerate(
374b5a76932SEd Tanous const std::shared_ptr<InProgressEnumerateData>& transaction)
3753ae4ba7bSMatt Spinler {
3762b73119cSGeorge Liu dbus::utility::getDbusObject(
3772b73119cSGeorge Liu transaction->objectPath, {},
3782b73119cSGeorge Liu [transaction](const boost::system::error_code& ec,
379b9d36b47SEd Tanous const dbus::utility::MapperGetObject& objects) {
3803ae4ba7bSMatt Spinler if (ec)
3813ae4ba7bSMatt Spinler {
38262598e31SEd Tanous BMCWEB_LOG_ERROR("GetObject for path {} failed with code {}",
38362598e31SEd Tanous transaction->objectPath, ec);
3843ae4ba7bSMatt Spinler return;
3853ae4ba7bSMatt Spinler }
3863ae4ba7bSMatt Spinler
38762598e31SEd Tanous BMCWEB_LOG_DEBUG("GetObject for {} has {} entries",
38862598e31SEd Tanous transaction->objectPath, objects.size());
3893ae4ba7bSMatt Spinler if (!objects.empty())
3903ae4ba7bSMatt Spinler {
3913ae4ba7bSMatt Spinler transaction->subtree->emplace_back(transaction->objectPath,
3923ae4ba7bSMatt Spinler objects);
3933ae4ba7bSMatt Spinler }
3943ae4ba7bSMatt Spinler
3953ae4ba7bSMatt Spinler // Map indicating connection name, and the path where the object
3963ae4ba7bSMatt Spinler // manager exists
39718f8f608SEd Tanous boost::container::flat_map<
39818f8f608SEd Tanous std::string, std::string, std::less<>,
39918f8f608SEd Tanous std::vector<std::pair<std::string, std::string>>>
40018f8f608SEd Tanous connections;
4013ae4ba7bSMatt Spinler
4023ae4ba7bSMatt Spinler for (const auto& object : *(transaction->subtree))
4033ae4ba7bSMatt Spinler {
4043ae4ba7bSMatt Spinler for (const auto& connection : object.second)
4053ae4ba7bSMatt Spinler {
4063ae4ba7bSMatt Spinler for (const auto& interface : connection.second)
4073ae4ba7bSMatt Spinler {
408bd79bce8SPatrick Williams BMCWEB_LOG_DEBUG("{} has interface {}",
409bd79bce8SPatrick Williams connection.first, interface);
4103ae4ba7bSMatt Spinler if (interface == "org.freedesktop.DBus.ObjectManager")
4113ae4ba7bSMatt Spinler {
41262598e31SEd Tanous BMCWEB_LOG_DEBUG("found object manager path {}",
41362598e31SEd Tanous object.first);
414f8fe53e7SEd Tanous connections[connection.first] = object.first;
4153ae4ba7bSMatt Spinler }
4163ae4ba7bSMatt Spinler }
4173ae4ba7bSMatt Spinler }
4183ae4ba7bSMatt Spinler }
41962598e31SEd Tanous BMCWEB_LOG_DEBUG("Got {} connections", connections.size());
4203ae4ba7bSMatt Spinler
4213ae4ba7bSMatt Spinler for (const auto& connection : connections)
4223ae4ba7bSMatt Spinler {
4237c09162aSEd Tanous // If we already know where the object manager is, we don't
4247c09162aSEd Tanous // need to search for it, we can call directly in to
4253ae4ba7bSMatt Spinler // getManagedObjects
4263ae4ba7bSMatt Spinler if (!connection.second.empty())
4273ae4ba7bSMatt Spinler {
428bd79bce8SPatrick Williams getManagedObjectsForEnumerate(
429bd79bce8SPatrick Williams transaction->objectPath, connection.second,
4303ae4ba7bSMatt Spinler connection.first, transaction);
4313ae4ba7bSMatt Spinler }
4323ae4ba7bSMatt Spinler else
4333ae4ba7bSMatt Spinler {
4347c09162aSEd Tanous // otherwise we need to find the object manager path
4357c09162aSEd Tanous // before we can continue
4363ae4ba7bSMatt Spinler findObjectManagerPathForEnumerate(
4373ae4ba7bSMatt Spinler transaction->objectPath, connection.first, transaction);
4383ae4ba7bSMatt Spinler }
4393ae4ba7bSMatt Spinler }
4402b73119cSGeorge Liu });
4413ae4ba7bSMatt Spinler }
44264530018SEd Tanous
443d4bb9bbdSEd Tanous // Structure for storing data on an in progress action
4441abe55efSEd Tanous struct InProgressActionData
4451abe55efSEd Tanous {
InProgressActionDatacrow::openbmc_mapper::InProgressActionData44628dd5ca1SLei YU explicit InProgressActionData(
447bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& res) : asyncResp(res)
44823a21a1cSEd Tanous {}
~InProgressActionDatacrow::openbmc_mapper::InProgressActionData4491abe55efSEd Tanous ~InProgressActionData()
4501abe55efSEd Tanous {
45116caaee1SMatt Spinler // Methods could have been called across different owners
45216caaee1SMatt Spinler // and interfaces, where some calls failed and some passed.
45316caaee1SMatt Spinler //
45416caaee1SMatt Spinler // The rules for this are:
45516caaee1SMatt Spinler // * if no method was called - error
45616caaee1SMatt Spinler // * if a method failed and none passed - error
45716caaee1SMatt Spinler // (converse: if at least one method passed - OK)
45816caaee1SMatt Spinler // * for the method output:
45916caaee1SMatt Spinler // * if output processing didn't fail, return the data
46016caaee1SMatt Spinler
46116caaee1SMatt Spinler // Only deal with method returns if nothing failed earlier
46228dd5ca1SLei YU if (asyncResp->res.result() == boost::beast::http::status::ok)
46316caaee1SMatt Spinler {
46416caaee1SMatt Spinler if (!methodPassed)
46516caaee1SMatt Spinler {
46606b1b63cSMatt Spinler if (!methodFailed)
4671abe55efSEd Tanous {
46828dd5ca1SLei YU setErrorResponse(asyncResp->res,
46928dd5ca1SLei YU boost::beast::http::status::not_found,
4706db06242SMatt Spinler methodNotFoundDesc, notFoundMsg);
471d4bb9bbdSEd Tanous }
47216caaee1SMatt Spinler }
47316caaee1SMatt Spinler else
47416caaee1SMatt Spinler {
47516caaee1SMatt Spinler if (outputFailed)
47616caaee1SMatt Spinler {
47716caaee1SMatt Spinler setErrorResponse(
47828dd5ca1SLei YU asyncResp->res,
47928dd5ca1SLei YU boost::beast::http::status::internal_server_error,
48016caaee1SMatt Spinler "Method output failure", methodOutputFailedMsg);
48116caaee1SMatt Spinler }
48216caaee1SMatt Spinler else
48316caaee1SMatt Spinler {
48428dd5ca1SLei YU asyncResp->res.jsonValue["status"] = "ok";
48528dd5ca1SLei YU asyncResp->res.jsonValue["message"] = "200 OK";
48628dd5ca1SLei YU asyncResp->res.jsonValue["data"] = methodResponse;
48716caaee1SMatt Spinler }
48816caaee1SMatt Spinler }
48916caaee1SMatt Spinler }
490d4bb9bbdSEd Tanous }
491ecd6a3a2SEd Tanous InProgressActionData(const InProgressActionData&) = delete;
492ecd6a3a2SEd Tanous InProgressActionData(InProgressActionData&&) = delete;
493ecd6a3a2SEd Tanous InProgressActionData& operator=(const InProgressActionData&) = delete;
494ecd6a3a2SEd Tanous InProgressActionData& operator=(InProgressActionData&&) = delete;
495d4bb9bbdSEd Tanous
setErrorStatuscrow::openbmc_mapper::InProgressActionData4966db06242SMatt Spinler void setErrorStatus(const std::string& desc)
4971abe55efSEd Tanous {
49828dd5ca1SLei YU setErrorResponse(asyncResp->res,
49928dd5ca1SLei YU boost::beast::http::status::bad_request, desc,
500c0eb9bd9SMatt Spinler badReqMsg);
501d4bb9bbdSEd Tanous }
50228dd5ca1SLei YU std::shared_ptr<bmcweb::AsyncResp> asyncResp;
503d4bb9bbdSEd Tanous std::string path;
504d76323e5SEd Tanous std::string methodName;
505de81881fSMatt Spinler std::string interfaceName;
50616caaee1SMatt Spinler bool methodPassed = false;
50716caaee1SMatt Spinler bool methodFailed = false;
50816caaee1SMatt Spinler bool outputFailed = false;
50939a4e39fSMatt Spinler bool convertedToArray = false;
51016caaee1SMatt Spinler nlohmann::json methodResponse;
511d4bb9bbdSEd Tanous nlohmann::json arguments;
512d4bb9bbdSEd Tanous };
513d4bb9bbdSEd Tanous
dbusArgSplit(const std::string & string)51423a21a1cSEd Tanous inline std::vector<std::string> dbusArgSplit(const std::string& string)
5151abe55efSEd Tanous {
516d4bb9bbdSEd Tanous std::vector<std::string> ret;
5171abe55efSEd Tanous if (string.empty())
5181abe55efSEd Tanous {
519d4bb9bbdSEd Tanous return ret;
520d4bb9bbdSEd Tanous }
5210f0353b6SEd Tanous ret.emplace_back("");
522d76323e5SEd Tanous int containerDepth = 0;
52375db20e9SEd Tanous
52475db20e9SEd Tanous for (std::string::const_iterator character = string.begin();
5251abe55efSEd Tanous character != string.end(); character++)
5261abe55efSEd Tanous {
52775db20e9SEd Tanous ret.back() += *character;
5281abe55efSEd Tanous switch (*character)
5291abe55efSEd Tanous {
530d4bb9bbdSEd Tanous case ('a'):
531d4bb9bbdSEd Tanous break;
532d4bb9bbdSEd Tanous case ('('):
533d4bb9bbdSEd Tanous case ('{'):
534d76323e5SEd Tanous containerDepth++;
535d4bb9bbdSEd Tanous break;
536d4bb9bbdSEd Tanous case ('}'):
537d4bb9bbdSEd Tanous case (')'):
538d76323e5SEd Tanous containerDepth--;
5391abe55efSEd Tanous if (containerDepth == 0)
5401abe55efSEd Tanous {
5411abe55efSEd Tanous if (character + 1 != string.end())
5421abe55efSEd Tanous {
5430f0353b6SEd Tanous ret.emplace_back("");
544d4bb9bbdSEd Tanous }
545d4bb9bbdSEd Tanous }
546d4bb9bbdSEd Tanous break;
547d4bb9bbdSEd Tanous default:
5481abe55efSEd Tanous if (containerDepth == 0)
5491abe55efSEd Tanous {
5501abe55efSEd Tanous if (character + 1 != string.end())
5511abe55efSEd Tanous {
5520f0353b6SEd Tanous ret.emplace_back("");
553d4bb9bbdSEd Tanous }
554d4bb9bbdSEd Tanous }
555d4bb9bbdSEd Tanous break;
556d4bb9bbdSEd Tanous }
557d4bb9bbdSEd Tanous }
5584ae611d9SMatt Spinler
5594ae611d9SMatt Spinler return ret;
560d4bb9bbdSEd Tanous }
561d4bb9bbdSEd Tanous
convertJsonToDbus(sd_bus_message * m,const std::string & argType,const nlohmann::json & inputJson)56281ce609eSEd Tanous inline int convertJsonToDbus(sd_bus_message* m, const std::string& argType,
56381ce609eSEd Tanous const nlohmann::json& inputJson)
5641abe55efSEd Tanous {
565d4bb9bbdSEd Tanous int r = 0;
566296579beSEd Tanous BMCWEB_LOG_DEBUG("Converting {} to type: {}", inputJson, argType);
56781ce609eSEd Tanous const std::vector<std::string> argTypes = dbusArgSplit(argType);
568d4bb9bbdSEd Tanous
569d4bb9bbdSEd Tanous // Assume a single object for now.
57081ce609eSEd Tanous const nlohmann::json* j = &inputJson;
57181ce609eSEd Tanous nlohmann::json::const_iterator jIt = inputJson.begin();
572d4bb9bbdSEd Tanous
573e3cb5a31SEd Tanous for (const std::string& argCode : argTypes)
5741abe55efSEd Tanous {
5751abe55efSEd Tanous // If we are decoding multiple objects, grab the pointer to the
5761abe55efSEd Tanous // iterator, and increment it for the next loop
5771abe55efSEd Tanous if (argTypes.size() > 1)
5781abe55efSEd Tanous {
57981ce609eSEd Tanous if (jIt == inputJson.end())
5801abe55efSEd Tanous {
581d4bb9bbdSEd Tanous return -2;
582d4bb9bbdSEd Tanous }
583d76323e5SEd Tanous j = &*jIt;
584d76323e5SEd Tanous jIt++;
585d4bb9bbdSEd Tanous }
586e3cb5a31SEd Tanous const int64_t* intValue = j->get_ptr<const int64_t*>();
587e3cb5a31SEd Tanous const std::string* stringValue = j->get_ptr<const std::string*>();
588e3cb5a31SEd Tanous const double* doubleValue = j->get_ptr<const double*>();
589d4bb9bbdSEd Tanous const bool* b = j->get_ptr<const bool*>();
590d4bb9bbdSEd Tanous int64_t v = 0;
591d4bb9bbdSEd Tanous double d = 0.0;
592d4bb9bbdSEd Tanous
5931abe55efSEd Tanous // Do some basic type conversions that make sense. uint can be
5941abe55efSEd Tanous // converted to int. int and uint can be converted to double
59566664f25SEd Tanous if (intValue == nullptr)
59666664f25SEd Tanous {
59766664f25SEd Tanous const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
59866664f25SEd Tanous if (uintValue != nullptr)
5991abe55efSEd Tanous {
600e3cb5a31SEd Tanous v = static_cast<int64_t>(*uintValue);
601e3cb5a31SEd Tanous intValue = &v;
602d4bb9bbdSEd Tanous }
60366664f25SEd Tanous }
60466664f25SEd Tanous if (doubleValue == nullptr)
60566664f25SEd Tanous {
60666664f25SEd Tanous const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
60766664f25SEd Tanous if (uintValue != nullptr)
6081abe55efSEd Tanous {
609e3cb5a31SEd Tanous d = static_cast<double>(*uintValue);
610e3cb5a31SEd Tanous doubleValue = &d;
611d4bb9bbdSEd Tanous }
61266664f25SEd Tanous }
61366664f25SEd Tanous if (doubleValue == nullptr)
61466664f25SEd Tanous {
61566664f25SEd Tanous if (intValue != nullptr)
6161abe55efSEd Tanous {
617e3cb5a31SEd Tanous d = static_cast<double>(*intValue);
618e3cb5a31SEd Tanous doubleValue = &d;
619d4bb9bbdSEd Tanous }
62066664f25SEd Tanous }
621d4bb9bbdSEd Tanous
622e3cb5a31SEd Tanous if (argCode == "s")
6231abe55efSEd Tanous {
624e3cb5a31SEd Tanous if (stringValue == nullptr)
6251abe55efSEd Tanous {
626d4bb9bbdSEd Tanous return -1;
627d4bb9bbdSEd Tanous }
628271584abSEd Tanous r = sd_bus_message_append_basic(
629271584abSEd Tanous m, argCode[0], static_cast<const void*>(stringValue->data()));
6301abe55efSEd Tanous if (r < 0)
6311abe55efSEd Tanous {
632d4bb9bbdSEd Tanous return r;
633d4bb9bbdSEd Tanous }
6341abe55efSEd Tanous }
635e3cb5a31SEd Tanous else if (argCode == "i")
6361abe55efSEd Tanous {
637e3cb5a31SEd Tanous if (intValue == nullptr)
6381abe55efSEd Tanous {
639d4bb9bbdSEd Tanous return -1;
640d4bb9bbdSEd Tanous }
641c66c859cSAdriana Kobylak if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
642c66c859cSAdriana Kobylak (*intValue > std::numeric_limits<int32_t>::max()))
643c66c859cSAdriana Kobylak {
644c66c859cSAdriana Kobylak return -ERANGE;
645c66c859cSAdriana Kobylak }
646e3cb5a31SEd Tanous int32_t i = static_cast<int32_t>(*intValue);
647e3cb5a31SEd Tanous r = sd_bus_message_append_basic(m, argCode[0], &i);
6481abe55efSEd Tanous if (r < 0)
6491abe55efSEd Tanous {
650d4bb9bbdSEd Tanous return r;
651d4bb9bbdSEd Tanous }
6521abe55efSEd Tanous }
653e3cb5a31SEd Tanous else if (argCode == "b")
6541abe55efSEd Tanous {
655d4bb9bbdSEd Tanous // lots of ways bool could be represented here. Try them all
656e662eae8SEd Tanous int boolInt = 0;
657e3cb5a31SEd Tanous if (intValue != nullptr)
6581abe55efSEd Tanous {
659c66c859cSAdriana Kobylak if (*intValue == 1)
660c66c859cSAdriana Kobylak {
661e662eae8SEd Tanous boolInt = 1;
662c66c859cSAdriana Kobylak }
663c66c859cSAdriana Kobylak else if (*intValue == 0)
664c66c859cSAdriana Kobylak {
665e662eae8SEd Tanous boolInt = 0;
666c66c859cSAdriana Kobylak }
667c66c859cSAdriana Kobylak else
668c66c859cSAdriana Kobylak {
669c66c859cSAdriana Kobylak return -ERANGE;
670c66c859cSAdriana Kobylak }
6711abe55efSEd Tanous }
6721abe55efSEd Tanous else if (b != nullptr)
6731abe55efSEd Tanous {
674a2f02638SMatt Spinler boolInt = *b ? 1 : 0;
6751abe55efSEd Tanous }
676e3cb5a31SEd Tanous else if (stringValue != nullptr)
6771abe55efSEd Tanous {
67818f8f608SEd Tanous if (!stringValue->empty())
67918f8f608SEd Tanous {
68018f8f608SEd Tanous if (stringValue->front() == 't' ||
68118f8f608SEd Tanous stringValue->front() == 'T')
68218f8f608SEd Tanous {
68318f8f608SEd Tanous boolInt = 1;
68418f8f608SEd Tanous }
68518f8f608SEd Tanous }
6861abe55efSEd Tanous }
6871abe55efSEd Tanous else
6881abe55efSEd Tanous {
689d4bb9bbdSEd Tanous return -1;
690d4bb9bbdSEd Tanous }
691e3cb5a31SEd Tanous r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
6921abe55efSEd Tanous if (r < 0)
6931abe55efSEd Tanous {
694d4bb9bbdSEd Tanous return r;
695d4bb9bbdSEd Tanous }
6961abe55efSEd Tanous }
697e3cb5a31SEd Tanous else if (argCode == "n")
6981abe55efSEd Tanous {
699e3cb5a31SEd Tanous if (intValue == nullptr)
7001abe55efSEd Tanous {
701d4bb9bbdSEd Tanous return -1;
702d4bb9bbdSEd Tanous }
703c66c859cSAdriana Kobylak if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
704c66c859cSAdriana Kobylak (*intValue > std::numeric_limits<int16_t>::max()))
705c66c859cSAdriana Kobylak {
706c66c859cSAdriana Kobylak return -ERANGE;
707c66c859cSAdriana Kobylak }
708e3cb5a31SEd Tanous int16_t n = static_cast<int16_t>(*intValue);
709e3cb5a31SEd Tanous r = sd_bus_message_append_basic(m, argCode[0], &n);
7101abe55efSEd Tanous if (r < 0)
7111abe55efSEd Tanous {
712d4bb9bbdSEd Tanous return r;
713d4bb9bbdSEd Tanous }
7141abe55efSEd Tanous }
715e3cb5a31SEd Tanous else if (argCode == "x")
7161abe55efSEd Tanous {
717e3cb5a31SEd Tanous if (intValue == nullptr)
7181abe55efSEd Tanous {
719d4bb9bbdSEd Tanous return -1;
720d4bb9bbdSEd Tanous }
721e3cb5a31SEd Tanous r = sd_bus_message_append_basic(m, argCode[0], intValue);
7221abe55efSEd Tanous if (r < 0)
7231abe55efSEd Tanous {
724d4bb9bbdSEd Tanous return r;
725d4bb9bbdSEd Tanous }
7261abe55efSEd Tanous }
727e3cb5a31SEd Tanous else if (argCode == "y")
7281abe55efSEd Tanous {
72966664f25SEd Tanous const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
730e3cb5a31SEd Tanous if (uintValue == nullptr)
7311abe55efSEd Tanous {
732d4bb9bbdSEd Tanous return -1;
733d4bb9bbdSEd Tanous }
73423a21a1cSEd Tanous if (*uintValue > std::numeric_limits<uint8_t>::max())
735c66c859cSAdriana Kobylak {
736c66c859cSAdriana Kobylak return -ERANGE;
737c66c859cSAdriana Kobylak }
738e3cb5a31SEd Tanous uint8_t y = static_cast<uint8_t>(*uintValue);
739e3cb5a31SEd Tanous r = sd_bus_message_append_basic(m, argCode[0], &y);
7401abe55efSEd Tanous }
741e3cb5a31SEd Tanous else if (argCode == "q")
7421abe55efSEd Tanous {
74366664f25SEd Tanous const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
744e3cb5a31SEd Tanous if (uintValue == nullptr)
7451abe55efSEd Tanous {
746d4bb9bbdSEd Tanous return -1;
747d4bb9bbdSEd Tanous }
74823a21a1cSEd Tanous if (*uintValue > std::numeric_limits<uint16_t>::max())
749c66c859cSAdriana Kobylak {
750c66c859cSAdriana Kobylak return -ERANGE;
751c66c859cSAdriana Kobylak }
752e3cb5a31SEd Tanous uint16_t q = static_cast<uint16_t>(*uintValue);
753e3cb5a31SEd Tanous r = sd_bus_message_append_basic(m, argCode[0], &q);
7541abe55efSEd Tanous }
755e3cb5a31SEd Tanous else if (argCode == "u")
7561abe55efSEd Tanous {
75766664f25SEd Tanous const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
758e3cb5a31SEd Tanous if (uintValue == nullptr)
7591abe55efSEd Tanous {
760d4bb9bbdSEd Tanous return -1;
761d4bb9bbdSEd Tanous }
76223a21a1cSEd Tanous if (*uintValue > std::numeric_limits<uint32_t>::max())
763c66c859cSAdriana Kobylak {
764c66c859cSAdriana Kobylak return -ERANGE;
765c66c859cSAdriana Kobylak }
766e3cb5a31SEd Tanous uint32_t u = static_cast<uint32_t>(*uintValue);
767e3cb5a31SEd Tanous r = sd_bus_message_append_basic(m, argCode[0], &u);
7681abe55efSEd Tanous }
769e3cb5a31SEd Tanous else if (argCode == "t")
7701abe55efSEd Tanous {
77166664f25SEd Tanous const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
772e3cb5a31SEd Tanous if (uintValue == nullptr)
7731abe55efSEd Tanous {
774d4bb9bbdSEd Tanous return -1;
775d4bb9bbdSEd Tanous }
776e3cb5a31SEd Tanous r = sd_bus_message_append_basic(m, argCode[0], uintValue);
7771abe55efSEd Tanous }
778e3cb5a31SEd Tanous else if (argCode == "d")
7791abe55efSEd Tanous {
780c66c859cSAdriana Kobylak if (doubleValue == nullptr)
781c66c859cSAdriana Kobylak {
782c66c859cSAdriana Kobylak return -1;
783c66c859cSAdriana Kobylak }
784c66c859cSAdriana Kobylak if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
785c66c859cSAdriana Kobylak (*doubleValue > std::numeric_limits<double>::max()))
786c66c859cSAdriana Kobylak {
787c66c859cSAdriana Kobylak return -ERANGE;
788c66c859cSAdriana Kobylak }
78907900817SEd Tanous r = sd_bus_message_append_basic(m, argCode[0], doubleValue);
79007900817SEd Tanous if (r < 0)
79107900817SEd Tanous {
79207900817SEd Tanous return r;
79307900817SEd Tanous }
7941abe55efSEd Tanous }
79511ba3979SEd Tanous else if (argCode.starts_with("a"))
7961abe55efSEd Tanous {
797e3cb5a31SEd Tanous std::string containedType = argCode.substr(1);
798d4bb9bbdSEd Tanous r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
799e3cb5a31SEd Tanous containedType.c_str());
8001abe55efSEd Tanous if (r < 0)
8011abe55efSEd Tanous {
802d4bb9bbdSEd Tanous return r;
803d4bb9bbdSEd Tanous }
804d4bb9bbdSEd Tanous
8050dfeda62SEd Tanous for (const auto& it : *j)
8061abe55efSEd Tanous {
8070dfeda62SEd Tanous r = convertJsonToDbus(m, containedType, it);
8081abe55efSEd Tanous if (r < 0)
8091abe55efSEd Tanous {
810d4bb9bbdSEd Tanous return r;
811d4bb9bbdSEd Tanous }
812d4bb9bbdSEd Tanous }
813d4bb9bbdSEd Tanous sd_bus_message_close_container(m);
8141abe55efSEd Tanous }
81511ba3979SEd Tanous else if (argCode.starts_with("v"))
8161abe55efSEd Tanous {
817e3cb5a31SEd Tanous std::string containedType = argCode.substr(1);
81862598e31SEd Tanous BMCWEB_LOG_DEBUG("variant type: {} appending variant of type: {}",
81962598e31SEd Tanous argCode, containedType);
820d4bb9bbdSEd Tanous r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
821e3cb5a31SEd Tanous containedType.c_str());
8221abe55efSEd Tanous if (r < 0)
8231abe55efSEd Tanous {
824d4bb9bbdSEd Tanous return r;
825d4bb9bbdSEd Tanous }
826d4bb9bbdSEd Tanous
82781ce609eSEd Tanous r = convertJsonToDbus(m, containedType, inputJson);
8281abe55efSEd Tanous if (r < 0)
8291abe55efSEd Tanous {
830d4bb9bbdSEd Tanous return r;
831d4bb9bbdSEd Tanous }
832d4bb9bbdSEd Tanous
833d4bb9bbdSEd Tanous r = sd_bus_message_close_container(m);
8341abe55efSEd Tanous if (r < 0)
8351abe55efSEd Tanous {
836d4bb9bbdSEd Tanous return r;
837d4bb9bbdSEd Tanous }
8381abe55efSEd Tanous }
83911ba3979SEd Tanous else if (argCode.starts_with("(") && argCode.ends_with(")"))
8401abe55efSEd Tanous {
841f3477566SMikhail Zhvakin std::string containedType = argCode.substr(1, argCode.size() - 2);
842d4bb9bbdSEd Tanous r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
843e3cb5a31SEd Tanous containedType.c_str());
844f1eebf06SEd Tanous if (r < 0)
845f1eebf06SEd Tanous {
846f1eebf06SEd Tanous return r;
847f1eebf06SEd Tanous }
848f1eebf06SEd Tanous
849d4bb9bbdSEd Tanous nlohmann::json::const_iterator it = j->begin();
850f3477566SMikhail Zhvakin for (const std::string& argCode2 : dbusArgSplit(containedType))
8511abe55efSEd Tanous {
8521abe55efSEd Tanous if (it == j->end())
8531abe55efSEd Tanous {
854d4bb9bbdSEd Tanous return -1;
855d4bb9bbdSEd Tanous }
856cb13a392SEd Tanous r = convertJsonToDbus(m, argCode2, *it);
8571abe55efSEd Tanous if (r < 0)
8581abe55efSEd Tanous {
859d4bb9bbdSEd Tanous return r;
860d4bb9bbdSEd Tanous }
861d4bb9bbdSEd Tanous it++;
862d4bb9bbdSEd Tanous }
863d4bb9bbdSEd Tanous r = sd_bus_message_close_container(m);
8641abe55efSEd Tanous }
86511ba3979SEd Tanous else if (argCode.starts_with("{") && argCode.ends_with("}"))
8661abe55efSEd Tanous {
867f3477566SMikhail Zhvakin std::string containedType = argCode.substr(1, argCode.size() - 2);
868d4bb9bbdSEd Tanous r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
869e3cb5a31SEd Tanous containedType.c_str());
870f1eebf06SEd Tanous if (r < 0)
871f1eebf06SEd Tanous {
872f1eebf06SEd Tanous return r;
873f1eebf06SEd Tanous }
874f1eebf06SEd Tanous
875e3cb5a31SEd Tanous std::vector<std::string> codes = dbusArgSplit(containedType);
8761abe55efSEd Tanous if (codes.size() != 2)
8771abe55efSEd Tanous {
878d4bb9bbdSEd Tanous return -1;
879d4bb9bbdSEd Tanous }
8802c70f800SEd Tanous const std::string& keyType = codes[0];
8812c70f800SEd Tanous const std::string& valueType = codes[1];
8820bdda665SEd Tanous const nlohmann::json::object_t* arr =
8830bdda665SEd Tanous j->get_ptr<const nlohmann::json::object_t*>();
8840bdda665SEd Tanous if (arr == nullptr)
8851abe55efSEd Tanous {
8860bdda665SEd Tanous return -1;
8870bdda665SEd Tanous }
8880bdda665SEd Tanous for (const auto& it : *arr)
8890bdda665SEd Tanous {
8900bdda665SEd Tanous r = convertJsonToDbus(m, keyType, it.first);
8911abe55efSEd Tanous if (r < 0)
8921abe55efSEd Tanous {
893d4bb9bbdSEd Tanous return r;
89475db20e9SEd Tanous }
895d4bb9bbdSEd Tanous
8960bdda665SEd Tanous r = convertJsonToDbus(m, valueType, it.second);
8971abe55efSEd Tanous if (r < 0)
8981abe55efSEd Tanous {
899d4bb9bbdSEd Tanous return r;
900d4bb9bbdSEd Tanous }
901d4bb9bbdSEd Tanous }
902d4bb9bbdSEd Tanous r = sd_bus_message_close_container(m);
9031abe55efSEd Tanous }
9041abe55efSEd Tanous else
9051abe55efSEd Tanous {
906d4bb9bbdSEd Tanous return -2;
907d4bb9bbdSEd Tanous }
9081abe55efSEd Tanous if (r < 0)
9091abe55efSEd Tanous {
910d4bb9bbdSEd Tanous return r;
911d4bb9bbdSEd Tanous }
912d4bb9bbdSEd Tanous
9131abe55efSEd Tanous if (argTypes.size() > 1)
9141abe55efSEd Tanous {
915d76323e5SEd Tanous jIt++;
916d4bb9bbdSEd Tanous }
917d4bb9bbdSEd Tanous }
918127ea546SMatt Spinler
919127ea546SMatt Spinler return r;
920d4bb9bbdSEd Tanous }
921d4bb9bbdSEd Tanous
922d22a7131SMatt Spinler template <typename T>
readMessageItem(const std::string & typeCode,sdbusplus::message_t & m,nlohmann::json & data)92359d494eeSPatrick Williams int readMessageItem(const std::string& typeCode, sdbusplus::message_t& m,
924d22a7131SMatt Spinler nlohmann::json& data)
925d22a7131SMatt Spinler {
926d22a7131SMatt Spinler T value;
927f79ce6a8SEd Tanous // When T == char*, this warning fires. Unclear how to resolve
928f79ce6a8SEd Tanous // Given that sd-bus takes a void pointer to a char*, and that's
929f79ce6a8SEd Tanous // Not something we can fix.
930f79ce6a8SEd Tanous // NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion)
931d22a7131SMatt Spinler int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
932d22a7131SMatt Spinler if (r < 0)
933d22a7131SMatt Spinler {
93462598e31SEd Tanous BMCWEB_LOG_ERROR("sd_bus_message_read_basic on type {} failed!",
93562598e31SEd Tanous typeCode);
936d22a7131SMatt Spinler return r;
937d22a7131SMatt Spinler }
938d22a7131SMatt Spinler
939d22a7131SMatt Spinler data = value;
940d22a7131SMatt Spinler return 0;
941d22a7131SMatt Spinler }
942d22a7131SMatt Spinler
94359d494eeSPatrick Williams int convertDBusToJSON(const std::string& returnType, sdbusplus::message_t& m,
94459d494eeSPatrick Williams nlohmann::json& response);
9456df8f990SMatt Spinler
readDictEntryFromMessage(const std::string & typeCode,sdbusplus::message_t & m,nlohmann::json & object)94623a21a1cSEd Tanous inline int readDictEntryFromMessage(const std::string& typeCode,
94759d494eeSPatrick Williams sdbusplus::message_t& m,
9486df8f990SMatt Spinler nlohmann::json& object)
9496df8f990SMatt Spinler {
9506df8f990SMatt Spinler std::vector<std::string> types = dbusArgSplit(typeCode);
9516df8f990SMatt Spinler if (types.size() != 2)
9526df8f990SMatt Spinler {
95362598e31SEd Tanous BMCWEB_LOG_ERROR("wrong number contained types in dictionary: {}",
95462598e31SEd Tanous types.size());
9556df8f990SMatt Spinler return -1;
9566df8f990SMatt Spinler }
9576df8f990SMatt Spinler
9586df8f990SMatt Spinler int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
9596df8f990SMatt Spinler typeCode.c_str());
9606df8f990SMatt Spinler if (r < 0)
9616df8f990SMatt Spinler {
96262598e31SEd Tanous BMCWEB_LOG_ERROR("sd_bus_message_enter_container with rc {}", r);
9636df8f990SMatt Spinler return r;
9646df8f990SMatt Spinler }
9656df8f990SMatt Spinler
9666df8f990SMatt Spinler nlohmann::json key;
9676df8f990SMatt Spinler r = convertDBusToJSON(types[0], m, key);
9686df8f990SMatt Spinler if (r < 0)
9696df8f990SMatt Spinler {
9706df8f990SMatt Spinler return r;
9716df8f990SMatt Spinler }
9726df8f990SMatt Spinler
9736df8f990SMatt Spinler const std::string* keyPtr = key.get_ptr<const std::string*>();
9746df8f990SMatt Spinler if (keyPtr == nullptr)
9756df8f990SMatt Spinler {
9766df8f990SMatt Spinler // json doesn't support non-string keys. If we hit this condition,
9776df8f990SMatt Spinler // convert the result to a string so we can proceed
97871f52d96SEd Tanous key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
9796df8f990SMatt Spinler keyPtr = key.get_ptr<const std::string*>();
9807c09162aSEd Tanous // in theory this can't fail now, but lets be paranoid about it
9817c09162aSEd Tanous // anyway
9826df8f990SMatt Spinler if (keyPtr == nullptr)
9836df8f990SMatt Spinler {
9846df8f990SMatt Spinler return -1;
9856df8f990SMatt Spinler }
9866df8f990SMatt Spinler }
9876df8f990SMatt Spinler nlohmann::json& value = object[*keyPtr];
9886df8f990SMatt Spinler
9896df8f990SMatt Spinler r = convertDBusToJSON(types[1], m, value);
9906df8f990SMatt Spinler if (r < 0)
9916df8f990SMatt Spinler {
9926df8f990SMatt Spinler return r;
9936df8f990SMatt Spinler }
9946df8f990SMatt Spinler
9956df8f990SMatt Spinler r = sd_bus_message_exit_container(m.get());
9966df8f990SMatt Spinler if (r < 0)
9976df8f990SMatt Spinler {
99862598e31SEd Tanous BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
9996df8f990SMatt Spinler return r;
10006df8f990SMatt Spinler }
10016df8f990SMatt Spinler
10026df8f990SMatt Spinler return 0;
10036df8f990SMatt Spinler }
10046df8f990SMatt Spinler
readArrayFromMessage(const std::string & typeCode,sdbusplus::message_t & m,nlohmann::json & data)100523a21a1cSEd Tanous inline int readArrayFromMessage(const std::string& typeCode,
100659d494eeSPatrick Williams sdbusplus::message_t& m, nlohmann::json& data)
10076df8f990SMatt Spinler {
10086df8f990SMatt Spinler if (typeCode.size() < 2)
10096df8f990SMatt Spinler {
101062598e31SEd Tanous BMCWEB_LOG_ERROR("Type code {} too small for an array", typeCode);
10116df8f990SMatt Spinler return -1;
10126df8f990SMatt Spinler }
10136df8f990SMatt Spinler
10146df8f990SMatt Spinler std::string containedType = typeCode.substr(1);
10156df8f990SMatt Spinler
10166df8f990SMatt Spinler int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
10176df8f990SMatt Spinler containedType.c_str());
10186df8f990SMatt Spinler if (r < 0)
10196df8f990SMatt Spinler {
102062598e31SEd Tanous BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
10216df8f990SMatt Spinler return r;
10226df8f990SMatt Spinler }
10236df8f990SMatt Spinler
102411ba3979SEd Tanous bool dict = containedType.starts_with("{") && containedType.ends_with("}");
10256df8f990SMatt Spinler
10266df8f990SMatt Spinler if (dict)
10276df8f990SMatt Spinler {
10286df8f990SMatt Spinler // Remove the { }
10296df8f990SMatt Spinler containedType = containedType.substr(1, containedType.size() - 2);
10306df8f990SMatt Spinler data = nlohmann::json::object();
10316df8f990SMatt Spinler }
10326df8f990SMatt Spinler else
10336df8f990SMatt Spinler {
10346df8f990SMatt Spinler data = nlohmann::json::array();
10356df8f990SMatt Spinler }
10366df8f990SMatt Spinler
10376df8f990SMatt Spinler while (true)
10386df8f990SMatt Spinler {
1039e662eae8SEd Tanous r = sd_bus_message_at_end(m.get(), 0);
10406df8f990SMatt Spinler if (r < 0)
10416df8f990SMatt Spinler {
104262598e31SEd Tanous BMCWEB_LOG_ERROR("sd_bus_message_at_end failed");
10436df8f990SMatt Spinler return r;
10446df8f990SMatt Spinler }
10456df8f990SMatt Spinler
10466df8f990SMatt Spinler if (r > 0)
10476df8f990SMatt Spinler {
10486df8f990SMatt Spinler break;
10496df8f990SMatt Spinler }
10506df8f990SMatt Spinler
10516df8f990SMatt Spinler // Dictionaries are only ever seen in an array
10526df8f990SMatt Spinler if (dict)
10536df8f990SMatt Spinler {
10546df8f990SMatt Spinler r = readDictEntryFromMessage(containedType, m, data);
10556df8f990SMatt Spinler if (r < 0)
10566df8f990SMatt Spinler {
10576df8f990SMatt Spinler return r;
10586df8f990SMatt Spinler }
10596df8f990SMatt Spinler }
10606df8f990SMatt Spinler else
10616df8f990SMatt Spinler {
10626df8f990SMatt Spinler data.push_back(nlohmann::json());
10636df8f990SMatt Spinler
10646df8f990SMatt Spinler r = convertDBusToJSON(containedType, m, data.back());
10656df8f990SMatt Spinler if (r < 0)
10666df8f990SMatt Spinler {
10676df8f990SMatt Spinler return r;
10686df8f990SMatt Spinler }
10696df8f990SMatt Spinler }
10706df8f990SMatt Spinler }
10716df8f990SMatt Spinler
10726df8f990SMatt Spinler r = sd_bus_message_exit_container(m.get());
10736df8f990SMatt Spinler if (r < 0)
10746df8f990SMatt Spinler {
107562598e31SEd Tanous BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
10766df8f990SMatt Spinler return r;
10776df8f990SMatt Spinler }
10786df8f990SMatt Spinler
10796df8f990SMatt Spinler return 0;
10806df8f990SMatt Spinler }
10816df8f990SMatt Spinler
readStructFromMessage(const std::string & typeCode,sdbusplus::message_t & m,nlohmann::json & data)108223a21a1cSEd Tanous inline int readStructFromMessage(const std::string& typeCode,
108359d494eeSPatrick Williams sdbusplus::message_t& m, nlohmann::json& data)
108475c6c67fSMatt Spinler {
108575c6c67fSMatt Spinler if (typeCode.size() < 3)
108675c6c67fSMatt Spinler {
108762598e31SEd Tanous BMCWEB_LOG_ERROR("Type code {} too small for a struct", typeCode);
108875c6c67fSMatt Spinler return -1;
108975c6c67fSMatt Spinler }
109075c6c67fSMatt Spinler
109175c6c67fSMatt Spinler std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
109275c6c67fSMatt Spinler std::vector<std::string> types = dbusArgSplit(containedTypes);
109375c6c67fSMatt Spinler
109475c6c67fSMatt Spinler int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
109575c6c67fSMatt Spinler containedTypes.c_str());
109675c6c67fSMatt Spinler if (r < 0)
109775c6c67fSMatt Spinler {
109862598e31SEd Tanous BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
109975c6c67fSMatt Spinler return r;
110075c6c67fSMatt Spinler }
110175c6c67fSMatt Spinler
110275c6c67fSMatt Spinler for (const std::string& type : types)
110375c6c67fSMatt Spinler {
110475c6c67fSMatt Spinler data.push_back(nlohmann::json());
110575c6c67fSMatt Spinler r = convertDBusToJSON(type, m, data.back());
110675c6c67fSMatt Spinler if (r < 0)
110775c6c67fSMatt Spinler {
110875c6c67fSMatt Spinler return r;
110975c6c67fSMatt Spinler }
111075c6c67fSMatt Spinler }
111175c6c67fSMatt Spinler
111275c6c67fSMatt Spinler r = sd_bus_message_exit_container(m.get());
111375c6c67fSMatt Spinler if (r < 0)
111475c6c67fSMatt Spinler {
111562598e31SEd Tanous BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
111675c6c67fSMatt Spinler return r;
111775c6c67fSMatt Spinler }
111875c6c67fSMatt Spinler return 0;
111975c6c67fSMatt Spinler }
112075c6c67fSMatt Spinler
readVariantFromMessage(sdbusplus::message_t & m,nlohmann::json & data)112159d494eeSPatrick Williams inline int readVariantFromMessage(sdbusplus::message_t& m, nlohmann::json& data)
112289c1970bSMatt Spinler {
1123543f4400SEd Tanous const char* containerType = nullptr;
112499131cd0SEd Tanous int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
112589c1970bSMatt Spinler if (r < 0)
112689c1970bSMatt Spinler {
112762598e31SEd Tanous BMCWEB_LOG_ERROR("sd_bus_message_peek_type failed");
112889c1970bSMatt Spinler return r;
112989c1970bSMatt Spinler }
113089c1970bSMatt Spinler
113189c1970bSMatt Spinler r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
113289c1970bSMatt Spinler containerType);
113389c1970bSMatt Spinler if (r < 0)
113489c1970bSMatt Spinler {
113562598e31SEd Tanous BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
113689c1970bSMatt Spinler return r;
113789c1970bSMatt Spinler }
113889c1970bSMatt Spinler
113989c1970bSMatt Spinler r = convertDBusToJSON(containerType, m, data);
114089c1970bSMatt Spinler if (r < 0)
114189c1970bSMatt Spinler {
114289c1970bSMatt Spinler return r;
114389c1970bSMatt Spinler }
114489c1970bSMatt Spinler
114589c1970bSMatt Spinler r = sd_bus_message_exit_container(m.get());
114689c1970bSMatt Spinler if (r < 0)
114789c1970bSMatt Spinler {
114862598e31SEd Tanous BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed");
114989c1970bSMatt Spinler return r;
115089c1970bSMatt Spinler }
115189c1970bSMatt Spinler
115289c1970bSMatt Spinler return 0;
115389c1970bSMatt Spinler }
115489c1970bSMatt Spinler
convertDBusToJSON(const std::string & returnType,sdbusplus::message_t & m,nlohmann::json & response)115523a21a1cSEd Tanous inline int convertDBusToJSON(const std::string& returnType,
115659d494eeSPatrick Williams sdbusplus::message_t& m, nlohmann::json& response)
115716caaee1SMatt Spinler {
1158d22a7131SMatt Spinler int r = 0;
1159d22a7131SMatt Spinler const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1160d22a7131SMatt Spinler
1161d22a7131SMatt Spinler for (const std::string& typeCode : returnTypes)
1162d22a7131SMatt Spinler {
1163f39420c7SMatt Spinler nlohmann::json* thisElement = &response;
1164f39420c7SMatt Spinler if (returnTypes.size() > 1)
1165d22a7131SMatt Spinler {
1166d22a7131SMatt Spinler response.push_back(nlohmann::json{});
1167f39420c7SMatt Spinler thisElement = &response.back();
1168d22a7131SMatt Spinler }
1169d22a7131SMatt Spinler
1170d4d25793SEd Tanous if (typeCode == "s" || typeCode == "g" || typeCode == "o")
1171d22a7131SMatt Spinler {
1172f39420c7SMatt Spinler r = readMessageItem<char*>(typeCode, m, *thisElement);
1173d22a7131SMatt Spinler if (r < 0)
1174d22a7131SMatt Spinler {
1175d22a7131SMatt Spinler return r;
1176d22a7131SMatt Spinler }
1177d22a7131SMatt Spinler }
1178d22a7131SMatt Spinler else if (typeCode == "b")
1179d22a7131SMatt Spinler {
1180f39420c7SMatt Spinler r = readMessageItem<int>(typeCode, m, *thisElement);
1181d22a7131SMatt Spinler if (r < 0)
1182d22a7131SMatt Spinler {
1183d22a7131SMatt Spinler return r;
1184d22a7131SMatt Spinler }
1185d22a7131SMatt Spinler
1186f39420c7SMatt Spinler *thisElement = static_cast<bool>(thisElement->get<int>());
1187d22a7131SMatt Spinler }
1188d22a7131SMatt Spinler else if (typeCode == "u")
1189d22a7131SMatt Spinler {
1190f39420c7SMatt Spinler r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
1191d22a7131SMatt Spinler if (r < 0)
1192d22a7131SMatt Spinler {
1193d22a7131SMatt Spinler return r;
1194d22a7131SMatt Spinler }
1195d22a7131SMatt Spinler }
1196d22a7131SMatt Spinler else if (typeCode == "i")
1197d22a7131SMatt Spinler {
1198f39420c7SMatt Spinler r = readMessageItem<int32_t>(typeCode, m, *thisElement);
1199d22a7131SMatt Spinler if (r < 0)
1200d22a7131SMatt Spinler {
1201d22a7131SMatt Spinler return r;
1202d22a7131SMatt Spinler }
1203d22a7131SMatt Spinler }
1204d22a7131SMatt Spinler else if (typeCode == "x")
1205d22a7131SMatt Spinler {
1206f39420c7SMatt Spinler r = readMessageItem<int64_t>(typeCode, m, *thisElement);
1207d22a7131SMatt Spinler if (r < 0)
1208d22a7131SMatt Spinler {
1209d22a7131SMatt Spinler return r;
1210d22a7131SMatt Spinler }
1211d22a7131SMatt Spinler }
1212d22a7131SMatt Spinler else if (typeCode == "t")
1213d22a7131SMatt Spinler {
1214f39420c7SMatt Spinler r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
1215d22a7131SMatt Spinler if (r < 0)
1216d22a7131SMatt Spinler {
1217d22a7131SMatt Spinler return r;
1218d22a7131SMatt Spinler }
1219d22a7131SMatt Spinler }
1220d22a7131SMatt Spinler else if (typeCode == "n")
1221d22a7131SMatt Spinler {
1222f39420c7SMatt Spinler r = readMessageItem<int16_t>(typeCode, m, *thisElement);
1223d22a7131SMatt Spinler if (r < 0)
1224d22a7131SMatt Spinler {
1225d22a7131SMatt Spinler return r;
1226d22a7131SMatt Spinler }
1227d22a7131SMatt Spinler }
1228d22a7131SMatt Spinler else if (typeCode == "q")
1229d22a7131SMatt Spinler {
1230f39420c7SMatt Spinler r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
1231d22a7131SMatt Spinler if (r < 0)
1232d22a7131SMatt Spinler {
1233d22a7131SMatt Spinler return r;
1234d22a7131SMatt Spinler }
1235d22a7131SMatt Spinler }
1236d22a7131SMatt Spinler else if (typeCode == "y")
1237d22a7131SMatt Spinler {
1238f39420c7SMatt Spinler r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
1239d22a7131SMatt Spinler if (r < 0)
1240d22a7131SMatt Spinler {
1241d22a7131SMatt Spinler return r;
1242d22a7131SMatt Spinler }
1243d22a7131SMatt Spinler }
1244d22a7131SMatt Spinler else if (typeCode == "d")
1245d22a7131SMatt Spinler {
1246f39420c7SMatt Spinler r = readMessageItem<double>(typeCode, m, *thisElement);
1247d22a7131SMatt Spinler if (r < 0)
1248d22a7131SMatt Spinler {
1249d22a7131SMatt Spinler return r;
1250d22a7131SMatt Spinler }
1251d22a7131SMatt Spinler }
1252d22a7131SMatt Spinler else if (typeCode == "h")
1253d22a7131SMatt Spinler {
1254f39420c7SMatt Spinler r = readMessageItem<int>(typeCode, m, *thisElement);
1255d22a7131SMatt Spinler if (r < 0)
1256d22a7131SMatt Spinler {
1257d22a7131SMatt Spinler return r;
1258d22a7131SMatt Spinler }
1259d22a7131SMatt Spinler }
126011ba3979SEd Tanous else if (typeCode.starts_with("a"))
12616df8f990SMatt Spinler {
1262f39420c7SMatt Spinler r = readArrayFromMessage(typeCode, m, *thisElement);
12636df8f990SMatt Spinler if (r < 0)
12646df8f990SMatt Spinler {
12656df8f990SMatt Spinler return r;
12666df8f990SMatt Spinler }
12676df8f990SMatt Spinler }
126811ba3979SEd Tanous else if (typeCode.starts_with("(") && typeCode.ends_with(")"))
126975c6c67fSMatt Spinler {
1270f39420c7SMatt Spinler r = readStructFromMessage(typeCode, m, *thisElement);
127175c6c67fSMatt Spinler if (r < 0)
127275c6c67fSMatt Spinler {
127375c6c67fSMatt Spinler return r;
127475c6c67fSMatt Spinler }
127575c6c67fSMatt Spinler }
127611ba3979SEd Tanous else if (typeCode.starts_with("v"))
127789c1970bSMatt Spinler {
1278f39420c7SMatt Spinler r = readVariantFromMessage(m, *thisElement);
127989c1970bSMatt Spinler if (r < 0)
128089c1970bSMatt Spinler {
128189c1970bSMatt Spinler return r;
128289c1970bSMatt Spinler }
128389c1970bSMatt Spinler }
1284d22a7131SMatt Spinler else
1285d22a7131SMatt Spinler {
128662598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid D-Bus signature type {}", typeCode);
1287d22a7131SMatt Spinler return -2;
1288d22a7131SMatt Spinler }
1289d22a7131SMatt Spinler }
1290d22a7131SMatt Spinler
129116caaee1SMatt Spinler return 0;
129216caaee1SMatt Spinler }
129316caaee1SMatt Spinler
handleMethodResponse(const std::shared_ptr<InProgressActionData> & transaction,sdbusplus::message_t & m,const std::string & returnType)1294b5a76932SEd Tanous inline void handleMethodResponse(
1295b5a76932SEd Tanous const std::shared_ptr<InProgressActionData>& transaction,
129659d494eeSPatrick Williams sdbusplus::message_t& m, const std::string& returnType)
129716caaee1SMatt Spinler {
129839a4e39fSMatt Spinler nlohmann::json data;
129939a4e39fSMatt Spinler
130039a4e39fSMatt Spinler int r = convertDBusToJSON(returnType, m, data);
130139a4e39fSMatt Spinler if (r < 0)
130239a4e39fSMatt Spinler {
130339a4e39fSMatt Spinler transaction->outputFailed = true;
130439a4e39fSMatt Spinler return;
130539a4e39fSMatt Spinler }
130639a4e39fSMatt Spinler
130739a4e39fSMatt Spinler if (data.is_null())
130839a4e39fSMatt Spinler {
130939a4e39fSMatt Spinler return;
131039a4e39fSMatt Spinler }
131139a4e39fSMatt Spinler
131239a4e39fSMatt Spinler if (transaction->methodResponse.is_null())
131339a4e39fSMatt Spinler {
131439a4e39fSMatt Spinler transaction->methodResponse = std::move(data);
131539a4e39fSMatt Spinler return;
131639a4e39fSMatt Spinler }
131739a4e39fSMatt Spinler
131839a4e39fSMatt Spinler // If they're both dictionaries or arrays, merge into one.
131939a4e39fSMatt Spinler // Otherwise, make the results an array with every result
132039a4e39fSMatt Spinler // an entry. Could also just fail in that case, but it
132139a4e39fSMatt Spinler // seems better to get the data back somehow.
13220bdda665SEd Tanous nlohmann::json::object_t* dataobj =
13230bdda665SEd Tanous data.get_ptr<nlohmann::json::object_t*>();
13240bdda665SEd Tanous if (transaction->methodResponse.is_object() && dataobj != nullptr)
132539a4e39fSMatt Spinler {
13260bdda665SEd Tanous for (auto& obj : *dataobj)
132739a4e39fSMatt Spinler {
132839a4e39fSMatt Spinler // Note: Will overwrite the data for a duplicate key
13290bdda665SEd Tanous transaction->methodResponse.emplace(obj.first,
13300bdda665SEd Tanous std::move(obj.second));
133139a4e39fSMatt Spinler }
133239a4e39fSMatt Spinler return;
133339a4e39fSMatt Spinler }
133439a4e39fSMatt Spinler
13350bdda665SEd Tanous nlohmann::json::array_t* dataarr = data.get_ptr<nlohmann::json::array_t*>();
13360bdda665SEd Tanous if (transaction->methodResponse.is_array() && dataarr != nullptr)
133739a4e39fSMatt Spinler {
13380bdda665SEd Tanous for (auto& obj : *dataarr)
133939a4e39fSMatt Spinler {
1340b2ba3072SPatrick Williams transaction->methodResponse.emplace_back(std::move(obj));
134139a4e39fSMatt Spinler }
134239a4e39fSMatt Spinler return;
134339a4e39fSMatt Spinler }
134439a4e39fSMatt Spinler
134539a4e39fSMatt Spinler if (!transaction->convertedToArray)
134639a4e39fSMatt Spinler {
134739a4e39fSMatt Spinler // They are different types. May as well turn them into an array
134839a4e39fSMatt Spinler nlohmann::json j = std::move(transaction->methodResponse);
134939a4e39fSMatt Spinler transaction->methodResponse = nlohmann::json::array();
1350b2ba3072SPatrick Williams transaction->methodResponse.emplace_back(std::move(j));
1351b2ba3072SPatrick Williams transaction->methodResponse.emplace_back(std::move(data));
135239a4e39fSMatt Spinler transaction->convertedToArray = true;
135339a4e39fSMatt Spinler }
135439a4e39fSMatt Spinler else
135539a4e39fSMatt Spinler {
1356b2ba3072SPatrick Williams transaction->methodResponse.emplace_back(std::move(data));
135739a4e39fSMatt Spinler }
135816caaee1SMatt Spinler }
135916caaee1SMatt Spinler
findActionOnInterface(const std::shared_ptr<InProgressActionData> & transaction,const std::string & connectionName)1360b5a76932SEd Tanous inline void findActionOnInterface(
1361b5a76932SEd Tanous const std::shared_ptr<InProgressActionData>& transaction,
13621abe55efSEd Tanous const std::string& connectionName)
13631abe55efSEd Tanous {
136462598e31SEd Tanous BMCWEB_LOG_DEBUG("findActionOnInterface for connection {}", connectionName);
136555c7b7a2SEd Tanous crow::connections::systemBus->async_method_call(
13661abe55efSEd Tanous [transaction, connectionName{std::string(connectionName)}](
13675e7e2dc5SEd Tanous const boost::system::error_code& ec,
136881ce609eSEd Tanous const std::string& introspectXml) {
136962598e31SEd Tanous BMCWEB_LOG_DEBUG("got xml:\n {}", introspectXml);
13701abe55efSEd Tanous if (ec)
13711abe55efSEd Tanous {
137262598e31SEd Tanous BMCWEB_LOG_ERROR(
137362598e31SEd Tanous "Introspect call failed with error: {} on process: {}",
137462598e31SEd Tanous ec.message(), connectionName);
1375318bd892SMatt Spinler return;
13761abe55efSEd Tanous }
1377d4bb9bbdSEd Tanous tinyxml2::XMLDocument doc;
1378d4bb9bbdSEd Tanous
137981ce609eSEd Tanous doc.Parse(introspectXml.data(), introspectXml.size());
1380d4bb9bbdSEd Tanous tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
13811abe55efSEd Tanous if (pRoot == nullptr)
13821abe55efSEd Tanous {
1383bd79bce8SPatrick Williams BMCWEB_LOG_ERROR("XML document failed to parse {}",
1384bd79bce8SPatrick Williams connectionName);
1385e3cb5a31SEd Tanous return;
13861abe55efSEd Tanous }
1387e3cb5a31SEd Tanous tinyxml2::XMLElement* interfaceNode =
1388d4bb9bbdSEd Tanous pRoot->FirstChildElement("interface");
1389e3cb5a31SEd Tanous while (interfaceNode != nullptr)
13901abe55efSEd Tanous {
1391bd79bce8SPatrick Williams const char* thisInterfaceName =
1392bd79bce8SPatrick Williams interfaceNode->Attribute("name");
1393e3cb5a31SEd Tanous if (thisInterfaceName != nullptr)
13941abe55efSEd Tanous {
1395de81881fSMatt Spinler if (!transaction->interfaceName.empty() &&
1396de81881fSMatt Spinler (transaction->interfaceName != thisInterfaceName))
1397de81881fSMatt Spinler {
1398de81881fSMatt Spinler interfaceNode =
1399de81881fSMatt Spinler interfaceNode->NextSiblingElement("interface");
1400de81881fSMatt Spinler continue;
1401de81881fSMatt Spinler }
1402de81881fSMatt Spinler
1403e3cb5a31SEd Tanous tinyxml2::XMLElement* methodNode =
1404e3cb5a31SEd Tanous interfaceNode->FirstChildElement("method");
1405e3cb5a31SEd Tanous while (methodNode != nullptr)
1406e3cb5a31SEd Tanous {
1407bd79bce8SPatrick Williams const char* thisMethodName =
1408bd79bce8SPatrick Williams methodNode->Attribute("name");
140962598e31SEd Tanous BMCWEB_LOG_DEBUG("Found method: {}", thisMethodName);
1410e3cb5a31SEd Tanous if (thisMethodName != nullptr &&
1411e3cb5a31SEd Tanous thisMethodName == transaction->methodName)
14121abe55efSEd Tanous {
141362598e31SEd Tanous BMCWEB_LOG_DEBUG(
141462598e31SEd Tanous "Found method named {} on interface {}",
141562598e31SEd Tanous thisMethodName, thisInterfaceName);
141659d494eeSPatrick Williams sdbusplus::message_t m =
1417318bd892SMatt Spinler crow::connections::systemBus->new_method_call(
14181abe55efSEd Tanous connectionName.c_str(),
1419bd79bce8SPatrick Williams transaction->path.c_str(),
1420bd79bce8SPatrick Williams thisInterfaceName,
1421d76323e5SEd Tanous transaction->methodName.c_str());
1422d4bb9bbdSEd Tanous
1423e3cb5a31SEd Tanous tinyxml2::XMLElement* argumentNode =
1424e3cb5a31SEd Tanous methodNode->FirstChildElement("arg");
1425d4bb9bbdSEd Tanous
142616caaee1SMatt Spinler std::string returnType;
142716caaee1SMatt Spinler
142816caaee1SMatt Spinler // Find the output type
142916caaee1SMatt Spinler while (argumentNode != nullptr)
143016caaee1SMatt Spinler {
143116caaee1SMatt Spinler const char* argDirection =
143216caaee1SMatt Spinler argumentNode->Attribute("direction");
143316caaee1SMatt Spinler const char* argType =
143416caaee1SMatt Spinler argumentNode->Attribute("type");
1435bd79bce8SPatrick Williams if (argDirection != nullptr &&
1436bd79bce8SPatrick Williams argType != nullptr &&
143716caaee1SMatt Spinler std::string(argDirection) == "out")
143816caaee1SMatt Spinler {
143916caaee1SMatt Spinler returnType = argType;
144016caaee1SMatt Spinler break;
144116caaee1SMatt Spinler }
144216caaee1SMatt Spinler argumentNode =
144316caaee1SMatt Spinler argumentNode->NextSiblingElement("arg");
144416caaee1SMatt Spinler }
144516caaee1SMatt Spinler
1446b2ec0ce5SNan Zhou auto argIt = transaction->arguments.begin();
1447d4bb9bbdSEd Tanous
144816caaee1SMatt Spinler argumentNode = methodNode->FirstChildElement("arg");
144916caaee1SMatt Spinler
1450e3cb5a31SEd Tanous while (argumentNode != nullptr)
14511abe55efSEd Tanous {
1452e3cb5a31SEd Tanous const char* argDirection =
1453e3cb5a31SEd Tanous argumentNode->Attribute("direction");
1454e3cb5a31SEd Tanous const char* argType =
1455e3cb5a31SEd Tanous argumentNode->Attribute("type");
1456bd79bce8SPatrick Williams if (argDirection != nullptr &&
1457bd79bce8SPatrick Williams argType != nullptr &&
1458e3cb5a31SEd Tanous std::string(argDirection) == "in")
14591abe55efSEd Tanous {
1460318bd892SMatt Spinler if (argIt == transaction->arguments.end())
14611abe55efSEd Tanous {
14626db06242SMatt Spinler transaction->setErrorStatus(
14636db06242SMatt Spinler "Invalid method args");
1464d4bb9bbdSEd Tanous return;
1465d4bb9bbdSEd Tanous }
1466318bd892SMatt Spinler if (convertJsonToDbus(m.get(),
1467318bd892SMatt Spinler std::string(argType),
1468e3cb5a31SEd Tanous *argIt) < 0)
14691abe55efSEd Tanous {
14706db06242SMatt Spinler transaction->setErrorStatus(
14716db06242SMatt Spinler "Invalid method arg type");
1472d4bb9bbdSEd Tanous return;
1473d4bb9bbdSEd Tanous }
1474d4bb9bbdSEd Tanous
1475e3cb5a31SEd Tanous argIt++;
1476d4bb9bbdSEd Tanous }
1477e3cb5a31SEd Tanous argumentNode =
14784d72dcc3SAppaRao Puli argumentNode->NextSiblingElement("arg");
1479d4bb9bbdSEd Tanous }
1480e3cb5a31SEd Tanous
148155c7b7a2SEd Tanous crow::connections::systemBus->async_send(
14825a39f77aSPatrick Williams m, [transaction, returnType](
14835a39f77aSPatrick Williams const boost::system::error_code& ec2,
148459d494eeSPatrick Williams sdbusplus::message_t& m2) {
148523a21a1cSEd Tanous if (ec2)
14861abe55efSEd Tanous {
148716caaee1SMatt Spinler transaction->methodFailed = true;
148823a21a1cSEd Tanous const sd_bus_error* e = m2.get_error();
148906b1b63cSMatt Spinler
1490e662eae8SEd Tanous if (e != nullptr)
149106b1b63cSMatt Spinler {
149206b1b63cSMatt Spinler setErrorResponse(
149328dd5ca1SLei YU transaction->asyncResp->res,
1494bd79bce8SPatrick Williams boost::beast::http::status::
1495bd79bce8SPatrick Williams bad_request,
149606b1b63cSMatt Spinler e->name, e->message);
149706b1b63cSMatt Spinler }
149806b1b63cSMatt Spinler else
149906b1b63cSMatt Spinler {
150006b1b63cSMatt Spinler setErrorResponse(
150128dd5ca1SLei YU transaction->asyncResp->res,
1502bd79bce8SPatrick Williams boost::beast::http::status::
1503bd79bce8SPatrick Williams bad_request,
1504bd79bce8SPatrick Williams "Method call failed",
1505bd79bce8SPatrick Williams methodFailedMsg);
150606b1b63cSMatt Spinler }
1507d4bb9bbdSEd Tanous return;
1508d4bb9bbdSEd Tanous }
150916caaee1SMatt Spinler transaction->methodPassed = true;
151016caaee1SMatt Spinler
1511bd79bce8SPatrick Williams handleMethodResponse(transaction, m2,
1512bd79bce8SPatrick Williams returnType);
1513d4bb9bbdSEd Tanous });
1514d4bb9bbdSEd Tanous break;
1515d4bb9bbdSEd Tanous }
1516318bd892SMatt Spinler methodNode = methodNode->NextSiblingElement("method");
1517d4bb9bbdSEd Tanous }
1518d4bb9bbdSEd Tanous }
1519318bd892SMatt Spinler interfaceNode = interfaceNode->NextSiblingElement("interface");
1520d4bb9bbdSEd Tanous }
1521d4bb9bbdSEd Tanous },
15221abe55efSEd Tanous connectionName, transaction->path,
15231abe55efSEd Tanous "org.freedesktop.DBus.Introspectable", "Introspect");
1524d4bb9bbdSEd Tanous }
1525d4bb9bbdSEd Tanous
handleAction(const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & objectPath,const std::string & methodName)15268d1b46d7Szhanghch05 inline void handleAction(const crow::Request& req,
15278d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
152823a21a1cSEd Tanous const std::string& objectPath,
152923a21a1cSEd Tanous const std::string& methodName)
15301abe55efSEd Tanous {
153162598e31SEd Tanous BMCWEB_LOG_DEBUG("handleAction on path: {} and method {}", objectPath,
153262598e31SEd Tanous methodName);
15331aa0c2b8SEd Tanous nlohmann::json requestDbusData;
1534d4bb9bbdSEd Tanous
15351aa0c2b8SEd Tanous JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
15361aa0c2b8SEd Tanous if (ret == JsonParseResult::BadContentType)
15371aa0c2b8SEd Tanous {
15381aa0c2b8SEd Tanous setErrorResponse(asyncResp->res,
15391aa0c2b8SEd Tanous boost::beast::http::status::unsupported_media_type,
15401aa0c2b8SEd Tanous invalidContentType, unsupportedMediaMsg);
15411aa0c2b8SEd Tanous return;
15421aa0c2b8SEd Tanous }
15431aa0c2b8SEd Tanous if (ret != JsonParseResult::Success)
15441abe55efSEd Tanous {
15458d1b46d7Szhanghch05 setErrorResponse(asyncResp->res,
15468d1b46d7Szhanghch05 boost::beast::http::status::bad_request, noJsonDesc,
15478d1b46d7Szhanghch05 badReqMsg);
1548d4bb9bbdSEd Tanous return;
1549d4bb9bbdSEd Tanous }
1550e3cb5a31SEd Tanous nlohmann::json::iterator data = requestDbusData.find("data");
1551e3cb5a31SEd Tanous if (data == requestDbusData.end())
1552e3cb5a31SEd Tanous {
15538d1b46d7Szhanghch05 setErrorResponse(asyncResp->res,
15548d1b46d7Szhanghch05 boost::beast::http::status::bad_request, noJsonDesc,
15558d1b46d7Szhanghch05 badReqMsg);
1556e3cb5a31SEd Tanous return;
1557e3cb5a31SEd Tanous }
1558e3cb5a31SEd Tanous
1559e3cb5a31SEd Tanous if (!data->is_array())
15601abe55efSEd Tanous {
15618d1b46d7Szhanghch05 setErrorResponse(asyncResp->res,
15628d1b46d7Szhanghch05 boost::beast::http::status::bad_request, noJsonDesc,
15638d1b46d7Szhanghch05 badReqMsg);
1564d4bb9bbdSEd Tanous return;
1565d4bb9bbdSEd Tanous }
156628dd5ca1SLei YU auto transaction = std::make_shared<InProgressActionData>(asyncResp);
1567d4bb9bbdSEd Tanous
1568d76323e5SEd Tanous transaction->path = objectPath;
1569d76323e5SEd Tanous transaction->methodName = methodName;
1570e3cb5a31SEd Tanous transaction->arguments = std::move(*data);
15712b73119cSGeorge Liu dbus::utility::getDbusObject(
15722b73119cSGeorge Liu objectPath, {},
1573d4bb9bbdSEd Tanous [transaction](
15742b73119cSGeorge Liu const boost::system::error_code& ec,
15751214b7e7SGunnar Mills const std::vector<std::pair<std::string, std::vector<std::string>>>&
15761214b7e7SGunnar Mills interfaceNames) {
157726f6976fSEd Tanous if (ec || interfaceNames.empty())
15781abe55efSEd Tanous {
157962598e31SEd Tanous BMCWEB_LOG_ERROR("Can't find object");
158028dd5ca1SLei YU setErrorResponse(transaction->asyncResp->res,
15816db06242SMatt Spinler boost::beast::http::status::not_found,
15826db06242SMatt Spinler notFoundDesc, notFoundMsg);
1583d4bb9bbdSEd Tanous return;
1584d4bb9bbdSEd Tanous }
1585d4bb9bbdSEd Tanous
158662598e31SEd Tanous BMCWEB_LOG_DEBUG("GetObject returned {} object(s)",
158762598e31SEd Tanous interfaceNames.size());
1588d4bb9bbdSEd Tanous
1589bd79bce8SPatrick Williams for (const std::pair<std::string, std::vector<std::string>>&
1590bd79bce8SPatrick Williams object : interfaceNames)
15911abe55efSEd Tanous {
1592d76323e5SEd Tanous findActionOnInterface(transaction, object.first);
1593d4bb9bbdSEd Tanous }
15942b73119cSGeorge Liu });
1595d4bb9bbdSEd Tanous }
1596d4bb9bbdSEd Tanous
handleDelete(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & objectPath)15978d1b46d7Szhanghch05 inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
15988d1b46d7Szhanghch05 const std::string& objectPath)
1599de81881fSMatt Spinler {
160062598e31SEd Tanous BMCWEB_LOG_DEBUG("handleDelete on path: {}", objectPath);
1601de81881fSMatt Spinler
16022b73119cSGeorge Liu dbus::utility::getDbusObject(
16032b73119cSGeorge Liu objectPath, {},
16048d1b46d7Szhanghch05 [asyncResp, objectPath](
16052b73119cSGeorge Liu const boost::system::error_code& ec,
16061214b7e7SGunnar Mills const std::vector<std::pair<std::string, std::vector<std::string>>>&
16071214b7e7SGunnar Mills interfaceNames) {
160826f6976fSEd Tanous if (ec || interfaceNames.empty())
1609de81881fSMatt Spinler {
161062598e31SEd Tanous BMCWEB_LOG_ERROR("Can't find object");
16118d1b46d7Szhanghch05 setErrorResponse(asyncResp->res,
161262d2e8b6SMatt Spinler boost::beast::http::status::method_not_allowed,
161362d2e8b6SMatt Spinler methodNotAllowedDesc, methodNotAllowedMsg);
1614de81881fSMatt Spinler return;
1615de81881fSMatt Spinler }
1616de81881fSMatt Spinler
1617bd79bce8SPatrick Williams auto transaction =
1618bd79bce8SPatrick Williams std::make_shared<InProgressActionData>(asyncResp);
1619de81881fSMatt Spinler transaction->path = objectPath;
1620de81881fSMatt Spinler transaction->methodName = "Delete";
1621de81881fSMatt Spinler transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
1622de81881fSMatt Spinler
1623bd79bce8SPatrick Williams for (const std::pair<std::string, std::vector<std::string>>&
1624bd79bce8SPatrick Williams object : interfaceNames)
1625de81881fSMatt Spinler {
1626de81881fSMatt Spinler findActionOnInterface(transaction, object.first);
1627de81881fSMatt Spinler }
16282b73119cSGeorge Liu });
1629de81881fSMatt Spinler }
1630de81881fSMatt Spinler
handleList(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & objectPath,int32_t depth=0)16318d1b46d7Szhanghch05 inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
16328d1b46d7Szhanghch05 const std::string& objectPath, int32_t depth = 0)
16331abe55efSEd Tanous {
16347a1dbc48SGeorge Liu dbus::utility::getSubTreePaths(
16357a1dbc48SGeorge Liu objectPath, depth, {},
1636b9d36b47SEd Tanous [asyncResp](
16377a1dbc48SGeorge Liu const boost::system::error_code& ec,
1638b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& objectPaths) {
16391abe55efSEd Tanous if (ec)
16401abe55efSEd Tanous {
16418d1b46d7Szhanghch05 setErrorResponse(asyncResp->res,
16428d1b46d7Szhanghch05 boost::beast::http::status::not_found,
1643d6091dddSMatt Spinler notFoundDesc, notFoundMsg);
16441abe55efSEd Tanous }
16451abe55efSEd Tanous else
16461abe55efSEd Tanous {
16471476687dSEd Tanous asyncResp->res.jsonValue["status"] = "ok";
16481476687dSEd Tanous asyncResp->res.jsonValue["message"] = "200 OK";
16491476687dSEd Tanous asyncResp->res.jsonValue["data"] = objectPaths;
1650d4bb9bbdSEd Tanous }
16517a1dbc48SGeorge Liu });
1652d4bb9bbdSEd Tanous }
1653d4bb9bbdSEd Tanous
handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & objectPath)16548d1b46d7Szhanghch05 inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
16558d1b46d7Szhanghch05 const std::string& objectPath)
16561abe55efSEd Tanous {
165762598e31SEd Tanous BMCWEB_LOG_DEBUG("Doing enumerate on {}", objectPath);
1658049a0515SEd Tanous
16591476687dSEd Tanous asyncResp->res.jsonValue["message"] = "200 OK";
16601476687dSEd Tanous asyncResp->res.jsonValue["status"] = "ok";
16611476687dSEd Tanous asyncResp->res.jsonValue["data"] = nlohmann::json::object();
1662d4bb9bbdSEd Tanous
1663e99073f5SGeorge Liu dbus::utility::getSubTree(
1664e99073f5SGeorge Liu objectPath, 0, {},
1665b9d36b47SEd Tanous [objectPath, asyncResp](
1666e99073f5SGeorge Liu const boost::system::error_code& ec,
1667b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreeResponse& objectNames) {
1668bd79bce8SPatrick Williams auto transaction = std::make_shared<InProgressEnumerateData>(
1669bd79bce8SPatrick Williams objectPath, asyncResp);
16703ae4ba7bSMatt Spinler
16713ae4ba7bSMatt Spinler transaction->subtree =
1672b9d36b47SEd Tanous std::make_shared<dbus::utility::MapperGetSubTreeResponse>(
1673b9d36b47SEd Tanous objectNames);
16743ae4ba7bSMatt Spinler
1675049a0515SEd Tanous if (ec)
1676049a0515SEd Tanous {
167762598e31SEd Tanous BMCWEB_LOG_ERROR("GetSubTree failed on {}",
167862598e31SEd Tanous transaction->objectPath);
16792ae60096SMatt Spinler setErrorResponse(transaction->asyncResp->res,
16802ae60096SMatt Spinler boost::beast::http::status::not_found,
16812ae60096SMatt Spinler notFoundDesc, notFoundMsg);
168264530018SEd Tanous return;
168364530018SEd Tanous }
168464530018SEd Tanous
16853ae4ba7bSMatt Spinler // Add the data for the path passed in to the results
16863ae4ba7bSMatt Spinler // as if GetSubTree returned it, and continue on enumerating
16873ae4ba7bSMatt Spinler getObjectAndEnumerate(transaction);
1688e99073f5SGeorge Liu });
168964530018SEd Tanous }
1690911ac317SEd Tanous
handleGet(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,std::string & objectPath,std::string & destProperty)16918d1b46d7Szhanghch05 inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
16928d1b46d7Szhanghch05 std::string& objectPath, std::string& destProperty)
16931abe55efSEd Tanous {
169462598e31SEd Tanous BMCWEB_LOG_DEBUG("handleGet: {} prop:{}", objectPath, destProperty);
1695e3cb5a31SEd Tanous std::shared_ptr<std::string> propertyName =
1696d76323e5SEd Tanous std::make_shared<std::string>(std::move(destProperty));
169775db20e9SEd Tanous
169875db20e9SEd Tanous std::shared_ptr<std::string> path =
1699d76323e5SEd Tanous std::make_shared<std::string>(std::move(objectPath));
170075db20e9SEd Tanous
17012b73119cSGeorge Liu dbus::utility::getDbusObject(
17022b73119cSGeorge Liu *path, {},
1703b9d36b47SEd Tanous [asyncResp, path,
17042b73119cSGeorge Liu propertyName](const boost::system::error_code& ec,
1705b9d36b47SEd Tanous const dbus::utility::MapperGetObject& objectNames) {
170626f6976fSEd Tanous if (ec || objectNames.empty())
17071abe55efSEd Tanous {
17088d1b46d7Szhanghch05 setErrorResponse(asyncResp->res,
17098d1b46d7Szhanghch05 boost::beast::http::status::not_found,
1710dc2f9f11SMatt Spinler notFoundDesc, notFoundMsg);
1711d4bb9bbdSEd Tanous return;
1712d4bb9bbdSEd Tanous }
1713d4bb9bbdSEd Tanous std::shared_ptr<nlohmann::json> response =
1714d4bb9bbdSEd Tanous std::make_shared<nlohmann::json>(nlohmann::json::object());
171523a21a1cSEd Tanous for (const std::pair<std::string, std::vector<std::string>>&
171681ce609eSEd Tanous connection : objectNames)
17171abe55efSEd Tanous {
1718bd79bce8SPatrick Williams const std::vector<std::string>& interfaceNames =
1719bd79bce8SPatrick Williams connection.second;
1720d4bb9bbdSEd Tanous
172126f6976fSEd Tanous if (interfaceNames.empty())
17221abe55efSEd Tanous {
172365622a5dSLei YU // mapper allows empty interfaces in case an
172465622a5dSLei YU // object does not implement any interface.
172565622a5dSLei YU continue;
1726d4bb9bbdSEd Tanous }
1727d4bb9bbdSEd Tanous
17281abe55efSEd Tanous for (const std::string& interface : interfaceNames)
17291abe55efSEd Tanous {
173059d494eeSPatrick Williams sdbusplus::message_t m =
1731fe7e97d3SMatt Spinler crow::connections::systemBus->new_method_call(
1732fe7e97d3SMatt Spinler connection.first.c_str(), path->c_str(),
1733fe7e97d3SMatt Spinler "org.freedesktop.DBus.Properties", "GetAll");
1734fe7e97d3SMatt Spinler m.append(interface);
1735fe7e97d3SMatt Spinler crow::connections::systemBus->async_send(
17368d1b46d7Szhanghch05 m, [asyncResp, response,
17375e7e2dc5SEd Tanous propertyName](const boost::system::error_code& ec2,
173859d494eeSPatrick Williams sdbusplus::message_t& msg) {
173923a21a1cSEd Tanous if (ec2)
17401abe55efSEd Tanous {
1741bd79bce8SPatrick Williams BMCWEB_LOG_ERROR("Bad dbus request error: {}",
1742bd79bce8SPatrick Williams ec2);
17431abe55efSEd Tanous }
1744984a4c2bSEd Tanous else
1745984a4c2bSEd Tanous {
1746fe7e97d3SMatt Spinler nlohmann::json properties;
1747bd79bce8SPatrick Williams int r =
1748bd79bce8SPatrick Williams convertDBusToJSON("a{sv}", msg, properties);
1749fe7e97d3SMatt Spinler if (r < 0)
17501abe55efSEd Tanous {
1751bd79bce8SPatrick Williams BMCWEB_LOG_ERROR(
1752bd79bce8SPatrick Williams "convertDBusToJSON failed");
1753fe7e97d3SMatt Spinler }
1754fe7e97d3SMatt Spinler else
1755fe7e97d3SMatt Spinler {
17560bdda665SEd Tanous nlohmann::json::object_t* obj =
1757bd79bce8SPatrick Williams properties.get_ptr<
1758bd79bce8SPatrick Williams nlohmann::json::object_t*>();
17590bdda665SEd Tanous if (obj == nullptr)
17600bdda665SEd Tanous {
17610bdda665SEd Tanous return;
17620bdda665SEd Tanous }
17630bdda665SEd Tanous for (auto& prop : *obj)
1764fe7e97d3SMatt Spinler {
17657c09162aSEd Tanous // if property name is empty, or
17667c09162aSEd Tanous // matches our search query, add it
17677c09162aSEd Tanous // to the response json
1768d4bb9bbdSEd Tanous
1769e3cb5a31SEd Tanous if (propertyName->empty())
17701abe55efSEd Tanous {
17710bdda665SEd Tanous (*response)[prop.first] =
17720bdda665SEd Tanous std::move(prop.second);
17731abe55efSEd Tanous }
17740bdda665SEd Tanous else if (prop.first == *propertyName)
17751abe55efSEd Tanous {
17760bdda665SEd Tanous *response = std::move(prop.second);
1777fe7e97d3SMatt Spinler }
1778d4bb9bbdSEd Tanous }
1779d4bb9bbdSEd Tanous }
1780984a4c2bSEd Tanous }
17811abe55efSEd Tanous if (response.use_count() == 1)
17821abe55efSEd Tanous {
1783dc2f9f11SMatt Spinler if (!propertyName->empty() && response->empty())
1784dc2f9f11SMatt Spinler {
1785dc2f9f11SMatt Spinler setErrorResponse(
17868d1b46d7Szhanghch05 asyncResp->res,
1787dc2f9f11SMatt Spinler boost::beast::http::status::not_found,
1788dc2f9f11SMatt Spinler propNotFoundDesc, notFoundMsg);
1789dc2f9f11SMatt Spinler }
1790dc2f9f11SMatt Spinler else
1791dc2f9f11SMatt Spinler {
17921476687dSEd Tanous asyncResp->res.jsonValue["status"] = "ok";
1793bd79bce8SPatrick Williams asyncResp->res.jsonValue["message"] =
1794bd79bce8SPatrick Williams "200 OK";
1795bd79bce8SPatrick Williams asyncResp->res.jsonValue["data"] =
1796bd79bce8SPatrick Williams *response;
1797dc2f9f11SMatt Spinler }
1798d4bb9bbdSEd Tanous }
1799fe7e97d3SMatt Spinler });
1800d4bb9bbdSEd Tanous }
1801d4bb9bbdSEd Tanous }
18022b73119cSGeorge Liu });
1803d4bb9bbdSEd Tanous }
1804d4bb9bbdSEd Tanous
18051abe55efSEd Tanous struct AsyncPutRequest
18061abe55efSEd Tanous {
AsyncPutRequestcrow::openbmc_mapper::AsyncPutRequest18074e23a444SEd Tanous explicit AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
18088d1b46d7Szhanghch05 asyncResp(resIn)
18091214b7e7SGunnar Mills {}
~AsyncPutRequestcrow::openbmc_mapper::AsyncPutRequest18101abe55efSEd Tanous ~AsyncPutRequest()
18111abe55efSEd Tanous {
18128d1b46d7Szhanghch05 if (asyncResp->res.jsonValue.empty())
18131abe55efSEd Tanous {
18148d1b46d7Szhanghch05 setErrorResponse(asyncResp->res,
18158d1b46d7Szhanghch05 boost::beast::http::status::forbidden,
1816fbc19ea6SMatt Spinler forbiddenMsg, forbiddenPropDesc);
1817d4bb9bbdSEd Tanous }
1818d4bb9bbdSEd Tanous }
1819d4bb9bbdSEd Tanous
1820ecd6a3a2SEd Tanous AsyncPutRequest(const AsyncPutRequest&) = delete;
1821ecd6a3a2SEd Tanous AsyncPutRequest(AsyncPutRequest&&) = delete;
1822ecd6a3a2SEd Tanous AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1823ecd6a3a2SEd Tanous AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1824ecd6a3a2SEd Tanous
setErrorStatuscrow::openbmc_mapper::AsyncPutRequest1825fbc19ea6SMatt Spinler void setErrorStatus(const std::string& desc)
18261abe55efSEd Tanous {
18278d1b46d7Szhanghch05 setErrorResponse(asyncResp->res,
18288d1b46d7Szhanghch05 boost::beast::http::status::internal_server_error,
1829fbc19ea6SMatt Spinler desc, badReqMsg);
1830d4bb9bbdSEd Tanous }
1831d4bb9bbdSEd Tanous
18328d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
1833d4bb9bbdSEd Tanous std::string objectPath;
1834d4bb9bbdSEd Tanous std::string propertyName;
1835d4bb9bbdSEd Tanous nlohmann::json propertyValue;
1836d4bb9bbdSEd Tanous };
1837d4bb9bbdSEd Tanous
handlePut(const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & objectPath,const std::string & destProperty)18388d1b46d7Szhanghch05 inline void handlePut(const crow::Request& req,
18398d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
184023a21a1cSEd Tanous const std::string& objectPath,
184123a21a1cSEd Tanous const std::string& destProperty)
18421abe55efSEd Tanous {
1843fbc19ea6SMatt Spinler if (destProperty.empty())
1844fbc19ea6SMatt Spinler {
18458d1b46d7Szhanghch05 setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
1846fbc19ea6SMatt Spinler forbiddenResDesc, forbiddenMsg);
1847fbc19ea6SMatt Spinler return;
1848fbc19ea6SMatt Spinler }
18491aa0c2b8SEd Tanous nlohmann::json requestDbusData;
1850fbc19ea6SMatt Spinler
18511aa0c2b8SEd Tanous JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
18521aa0c2b8SEd Tanous if (ret == JsonParseResult::BadContentType)
18531aa0c2b8SEd Tanous {
18541aa0c2b8SEd Tanous setErrorResponse(asyncResp->res,
18551aa0c2b8SEd Tanous boost::beast::http::status::unsupported_media_type,
18561aa0c2b8SEd Tanous invalidContentType, unsupportedMediaMsg);
18571aa0c2b8SEd Tanous return;
18581aa0c2b8SEd Tanous }
1859d4bb9bbdSEd Tanous
18601aa0c2b8SEd Tanous if (ret != JsonParseResult::Success)
18611abe55efSEd Tanous {
18628d1b46d7Szhanghch05 setErrorResponse(asyncResp->res,
18638d1b46d7Szhanghch05 boost::beast::http::status::bad_request, noJsonDesc,
18648d1b46d7Szhanghch05 badReqMsg);
1865d4bb9bbdSEd Tanous return;
1866d4bb9bbdSEd Tanous }
1867d4bb9bbdSEd Tanous
1868b2ec0ce5SNan Zhou auto propertyIt = requestDbusData.find("data");
18691abe55efSEd Tanous if (propertyIt == requestDbusData.end())
18701abe55efSEd Tanous {
18718d1b46d7Szhanghch05 setErrorResponse(asyncResp->res,
18728d1b46d7Szhanghch05 boost::beast::http::status::bad_request, noJsonDesc,
18738d1b46d7Szhanghch05 badReqMsg);
1874d4bb9bbdSEd Tanous return;
1875d4bb9bbdSEd Tanous }
1876d76323e5SEd Tanous const nlohmann::json& propertySetValue = *propertyIt;
18778d1b46d7Szhanghch05 auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
1878d4bb9bbdSEd Tanous transaction->objectPath = objectPath;
1879d4bb9bbdSEd Tanous transaction->propertyName = destProperty;
1880d4bb9bbdSEd Tanous transaction->propertyValue = propertySetValue;
1881d4bb9bbdSEd Tanous
18822b73119cSGeorge Liu dbus::utility::getDbusObject(
18832b73119cSGeorge Liu transaction->objectPath, {},
18842b73119cSGeorge Liu [transaction](const boost::system::error_code& ec2,
1885b9d36b47SEd Tanous const dbus::utility::MapperGetObject& objectNames) {
188626f6976fSEd Tanous if (!ec2 && objectNames.empty())
18871abe55efSEd Tanous {
18888d1b46d7Szhanghch05 setErrorResponse(transaction->asyncResp->res,
1889fbc19ea6SMatt Spinler boost::beast::http::status::not_found,
1890fbc19ea6SMatt Spinler propNotFoundDesc, notFoundMsg);
1891d4bb9bbdSEd Tanous return;
1892d4bb9bbdSEd Tanous }
1893d4bb9bbdSEd Tanous
189423a21a1cSEd Tanous for (const std::pair<std::string, std::vector<std::string>>&
189581ce609eSEd Tanous connection : objectNames)
18961abe55efSEd Tanous {
1897d4bb9bbdSEd Tanous const std::string& connectionName = connection.first;
1898d4bb9bbdSEd Tanous
189955c7b7a2SEd Tanous crow::connections::systemBus->async_method_call(
19001abe55efSEd Tanous [connectionName{std::string(connectionName)},
19015e7e2dc5SEd Tanous transaction](const boost::system::error_code& ec3,
1902d4bb9bbdSEd Tanous const std::string& introspectXml) {
190323a21a1cSEd Tanous if (ec3)
19041abe55efSEd Tanous {
190562598e31SEd Tanous BMCWEB_LOG_ERROR(
190662598e31SEd Tanous "Introspect call failed with error: {} on process: {}",
190762598e31SEd Tanous ec3.message(), connectionName);
1908fbc19ea6SMatt Spinler transaction->setErrorStatus("Unexpected Error");
1909d4bb9bbdSEd Tanous return;
1910d4bb9bbdSEd Tanous }
1911d4bb9bbdSEd Tanous tinyxml2::XMLDocument doc;
1912d4bb9bbdSEd Tanous
1913d4bb9bbdSEd Tanous doc.Parse(introspectXml.c_str());
1914bd79bce8SPatrick Williams tinyxml2::XMLNode* pRoot =
1915bd79bce8SPatrick Williams doc.FirstChildElement("node");
19161abe55efSEd Tanous if (pRoot == nullptr)
19171abe55efSEd Tanous {
191862598e31SEd Tanous BMCWEB_LOG_ERROR("XML document failed to parse: {}",
191962598e31SEd Tanous introspectXml);
1920fbc19ea6SMatt Spinler transaction->setErrorStatus("Unexpected Error");
1921d4bb9bbdSEd Tanous return;
1922d4bb9bbdSEd Tanous }
1923d4bb9bbdSEd Tanous tinyxml2::XMLElement* ifaceNode =
1924d4bb9bbdSEd Tanous pRoot->FirstChildElement("interface");
19251abe55efSEd Tanous while (ifaceNode != nullptr)
19261abe55efSEd Tanous {
1927bd79bce8SPatrick Williams const char* interfaceName =
1928bd79bce8SPatrick Williams ifaceNode->Attribute("name");
1929bd79bce8SPatrick Williams BMCWEB_LOG_DEBUG("found interface {}",
1930bd79bce8SPatrick Williams interfaceName);
1931d4bb9bbdSEd Tanous tinyxml2::XMLElement* propNode =
1932d4bb9bbdSEd Tanous ifaceNode->FirstChildElement("property");
19331abe55efSEd Tanous while (propNode != nullptr)
19341abe55efSEd Tanous {
1935bd79bce8SPatrick Williams const char* propertyName =
1936bd79bce8SPatrick Williams propNode->Attribute("name");
1937b0b6152cSEd Tanous if (propertyName == nullptr)
1938b0b6152cSEd Tanous {
1939bd79bce8SPatrick Williams BMCWEB_LOG_DEBUG(
1940bd79bce8SPatrick Williams "Couldn't find name property");
1941b0b6152cSEd Tanous continue;
1942b0b6152cSEd Tanous }
1943bd79bce8SPatrick Williams BMCWEB_LOG_DEBUG("Found property {}",
1944bd79bce8SPatrick Williams propertyName);
19451abe55efSEd Tanous if (propertyName == transaction->propertyName)
19461abe55efSEd Tanous {
1947bd79bce8SPatrick Williams const char* argType =
1948bd79bce8SPatrick Williams propNode->Attribute("type");
19491abe55efSEd Tanous if (argType != nullptr)
19501abe55efSEd Tanous {
195159d494eeSPatrick Williams sdbusplus::message_t m =
19521abe55efSEd Tanous crow::connections::systemBus
19531abe55efSEd Tanous ->new_method_call(
1954d4bb9bbdSEd Tanous connectionName.c_str(),
1955bd79bce8SPatrick Williams transaction->objectPath
1956bd79bce8SPatrick Williams .c_str(),
19571abe55efSEd Tanous "org.freedesktop.DBus."
19581abe55efSEd Tanous "Properties",
19591abe55efSEd Tanous "Set");
19601abe55efSEd Tanous m.append(interfaceName,
19611abe55efSEd Tanous transaction->propertyName);
1962d4bb9bbdSEd Tanous int r = sd_bus_message_open_container(
1963bd79bce8SPatrick Williams m.get(), SD_BUS_TYPE_VARIANT,
1964bd79bce8SPatrick Williams argType);
19651abe55efSEd Tanous if (r < 0)
19661abe55efSEd Tanous {
1967fbc19ea6SMatt Spinler transaction->setErrorStatus(
1968fbc19ea6SMatt Spinler "Unexpected Error");
1969d4bb9bbdSEd Tanous return;
1970d4bb9bbdSEd Tanous }
19711abe55efSEd Tanous r = convertJsonToDbus(
19721abe55efSEd Tanous m.get(), argType,
1973d4bb9bbdSEd Tanous transaction->propertyValue);
19741abe55efSEd Tanous if (r < 0)
19751abe55efSEd Tanous {
1976c66c859cSAdriana Kobylak if (r == -ERANGE)
1977c66c859cSAdriana Kobylak {
1978c66c859cSAdriana Kobylak transaction->setErrorStatus(
1979c66c859cSAdriana Kobylak "Provided property value "
1980c66c859cSAdriana Kobylak "is out of range for the "
1981c66c859cSAdriana Kobylak "property type");
1982c66c859cSAdriana Kobylak }
1983c66c859cSAdriana Kobylak else
1984c66c859cSAdriana Kobylak {
1985fbc19ea6SMatt Spinler transaction->setErrorStatus(
1986fbc19ea6SMatt Spinler "Invalid arg type");
1987c66c859cSAdriana Kobylak }
1988d4bb9bbdSEd Tanous return;
1989d4bb9bbdSEd Tanous }
1990bd79bce8SPatrick Williams r = sd_bus_message_close_container(
1991bd79bce8SPatrick Williams m.get());
19921abe55efSEd Tanous if (r < 0)
19931abe55efSEd Tanous {
1994fbc19ea6SMatt Spinler transaction->setErrorStatus(
1995fbc19ea6SMatt Spinler "Unexpected Error");
1996d4bb9bbdSEd Tanous return;
1997d4bb9bbdSEd Tanous }
1998bd79bce8SPatrick Williams crow::connections::systemBus
1999bd79bce8SPatrick Williams ->async_send(
2000bd79bce8SPatrick Williams m,
2001bd79bce8SPatrick Williams [transaction](
2002bd79bce8SPatrick Williams const boost::system::
2003bd79bce8SPatrick Williams error_code& ec,
200459d494eeSPatrick Williams sdbusplus::message_t& m2) {
200562598e31SEd Tanous BMCWEB_LOG_DEBUG("sent");
20061abe55efSEd Tanous if (ec)
20071abe55efSEd Tanous {
2008bd79bce8SPatrick Williams const sd_bus_error* e =
2009bd79bce8SPatrick Williams m2.get_error();
2010fbc19ea6SMatt Spinler setErrorResponse(
2011bd79bce8SPatrick Williams transaction
2012bd79bce8SPatrick Williams ->asyncResp
2013bd79bce8SPatrick Williams ->res,
2014bd79bce8SPatrick Williams boost::beast::http::
2015bd79bce8SPatrick Williams status::
2016fbc19ea6SMatt Spinler forbidden,
2017e662eae8SEd Tanous (e) != nullptr
2018e662eae8SEd Tanous ? e->name
2019bd79bce8SPatrick Williams : ec.category()
2020bd79bce8SPatrick Williams .name(),
2021bd79bce8SPatrick Williams (e) != nullptr
2022bd79bce8SPatrick Williams ? e->message
202306b1b63cSMatt Spinler : ec.message());
2024fbc19ea6SMatt Spinler }
2025fbc19ea6SMatt Spinler else
2026fbc19ea6SMatt Spinler {
2027bd79bce8SPatrick Williams transaction->asyncResp
2028bd79bce8SPatrick Williams ->res.jsonValue
2029bd79bce8SPatrick Williams ["status"] =
2030bd79bce8SPatrick Williams "ok";
2031bd79bce8SPatrick Williams transaction->asyncResp
2032bd79bce8SPatrick Williams ->res.jsonValue
2033bd79bce8SPatrick Williams ["message"] =
2034bd79bce8SPatrick Williams "200 OK";
2035bd79bce8SPatrick Williams transaction->asyncResp
2036bd79bce8SPatrick Williams ->res
2037bd79bce8SPatrick Williams .jsonValue["data"] =
2038bd79bce8SPatrick Williams nullptr;
2039d4bb9bbdSEd Tanous }
2040d4bb9bbdSEd Tanous });
2041d4bb9bbdSEd Tanous }
2042d4bb9bbdSEd Tanous }
2043bd79bce8SPatrick Williams propNode =
2044bd79bce8SPatrick Williams propNode->NextSiblingElement("property");
2045d4bb9bbdSEd Tanous }
2046bd79bce8SPatrick Williams ifaceNode =
2047bd79bce8SPatrick Williams ifaceNode->NextSiblingElement("interface");
2048d4bb9bbdSEd Tanous }
2049d4bb9bbdSEd Tanous },
2050d4bb9bbdSEd Tanous connectionName, transaction->objectPath,
2051d4bb9bbdSEd Tanous "org.freedesktop.DBus.Introspectable", "Introspect");
2052d4bb9bbdSEd Tanous }
20532b73119cSGeorge Liu });
2054d4bb9bbdSEd Tanous }
2055d4bb9bbdSEd Tanous
handleDBusUrl(const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,std::string & objectPath)20568d1b46d7Szhanghch05 inline void handleDBusUrl(const crow::Request& req,
20578d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2058049a0515SEd Tanous std::string& objectPath)
2059049a0515SEd Tanous {
2060049a0515SEd Tanous // If accessing a single attribute, fill in and update objectPath,
2061049a0515SEd Tanous // otherwise leave destProperty blank
2062e05aec50SEd Tanous std::string destProperty;
2063049a0515SEd Tanous const char* attrSeperator = "/attr/";
2064049a0515SEd Tanous size_t attrPosition = objectPath.find(attrSeperator);
206571d5d8dbSEd Tanous if (attrPosition != std::string::npos)
2066049a0515SEd Tanous {
2067049a0515SEd Tanous destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2068049a0515SEd Tanous objectPath.length());
20697f57f195SEd Tanous objectPath.resize(attrPosition);
2070049a0515SEd Tanous }
2071049a0515SEd Tanous
2072b41187faSEd Tanous if (req.method() == boost::beast::http::verb::post)
2073049a0515SEd Tanous {
2074049a0515SEd Tanous constexpr const char* actionSeperator = "/action/";
2075049a0515SEd Tanous size_t actionPosition = objectPath.find(actionSeperator);
207671d5d8dbSEd Tanous if (actionPosition != std::string::npos)
2077049a0515SEd Tanous {
2078049a0515SEd Tanous std::string postProperty =
2079049a0515SEd Tanous objectPath.substr((actionPosition + strlen(actionSeperator)),
2080049a0515SEd Tanous objectPath.length());
20817f57f195SEd Tanous objectPath.resize(actionPosition);
20828d1b46d7Szhanghch05 handleAction(req, asyncResp, objectPath, postProperty);
2083049a0515SEd Tanous return;
2084049a0515SEd Tanous }
2085049a0515SEd Tanous }
2086b41187faSEd Tanous else if (req.method() == boost::beast::http::verb::get)
2087049a0515SEd Tanous {
208811ba3979SEd Tanous if (objectPath.ends_with("/enumerate"))
2089049a0515SEd Tanous {
2090049a0515SEd Tanous objectPath.erase(objectPath.end() - sizeof("enumerate"),
2091049a0515SEd Tanous objectPath.end());
20928d1b46d7Szhanghch05 handleEnumerate(asyncResp, objectPath);
2093049a0515SEd Tanous }
209411ba3979SEd Tanous else if (objectPath.ends_with("/list"))
2095049a0515SEd Tanous {
2096049a0515SEd Tanous objectPath.erase(objectPath.end() - sizeof("list"),
2097049a0515SEd Tanous objectPath.end());
20988d1b46d7Szhanghch05 handleList(asyncResp, objectPath);
2099049a0515SEd Tanous }
2100049a0515SEd Tanous else
2101049a0515SEd Tanous {
2102f839dfeeSEd Tanous // Trim any trailing "/" at the end
210311ba3979SEd Tanous if (objectPath.ends_with("/"))
2104f839dfeeSEd Tanous {
2105f839dfeeSEd Tanous objectPath.pop_back();
21068d1b46d7Szhanghch05 handleList(asyncResp, objectPath, 1);
2107f839dfeeSEd Tanous }
2108f839dfeeSEd Tanous else
2109f839dfeeSEd Tanous {
21108d1b46d7Szhanghch05 handleGet(asyncResp, objectPath, destProperty);
2111049a0515SEd Tanous }
2112f839dfeeSEd Tanous }
2113049a0515SEd Tanous return;
2114049a0515SEd Tanous }
2115b41187faSEd Tanous else if (req.method() == boost::beast::http::verb::put)
2116049a0515SEd Tanous {
21178d1b46d7Szhanghch05 handlePut(req, asyncResp, objectPath, destProperty);
2118049a0515SEd Tanous return;
2119049a0515SEd Tanous }
2120b41187faSEd Tanous else if (req.method() == boost::beast::http::verb::delete_)
2121de81881fSMatt Spinler {
21228d1b46d7Szhanghch05 handleDelete(asyncResp, objectPath);
2123de81881fSMatt Spinler return;
2124de81881fSMatt Spinler }
2125049a0515SEd Tanous
21268d1b46d7Szhanghch05 setErrorResponse(asyncResp->res,
21278d1b46d7Szhanghch05 boost::beast::http::status::method_not_allowed,
2128c4e8d21dSMatt Spinler methodNotAllowedDesc, methodNotAllowedMsg);
2129049a0515SEd Tanous }
2130049a0515SEd Tanous
handleBusSystemPost(const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & processName,const std::string & requestedPath)2131bd79bce8SPatrick Williams inline void handleBusSystemPost(
2132bd79bce8SPatrick Williams const crow::Request& req,
21331656b296SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2134bd79bce8SPatrick Williams const std::string& processName, const std::string& requestedPath)
21351656b296SEd Tanous {
21361656b296SEd Tanous std::vector<std::string> strs;
213750ebd4afSEd Tanous
213850ebd4afSEd Tanous bmcweb::split(strs, requestedPath, '/');
21391656b296SEd Tanous std::string objectPath;
21401656b296SEd Tanous std::string interfaceName;
21411656b296SEd Tanous std::string methodName;
21421656b296SEd Tanous auto it = strs.begin();
21431656b296SEd Tanous if (it == strs.end())
21441656b296SEd Tanous {
21451656b296SEd Tanous objectPath = "/";
21461656b296SEd Tanous }
21471656b296SEd Tanous while (it != strs.end())
21481656b296SEd Tanous {
21491656b296SEd Tanous // Check if segment contains ".". If it does, it must be an
21501656b296SEd Tanous // interface
21511656b296SEd Tanous if (it->find(".") != std::string::npos)
21521656b296SEd Tanous {
21531656b296SEd Tanous break;
21541656b296SEd Tanous // This check is necessary as the trailing slash gets
21551656b296SEd Tanous // parsed as part of our <path> specifier above, which
21561656b296SEd Tanous // causes the normal trailing backslash redirector to
21571656b296SEd Tanous // fail.
21581656b296SEd Tanous }
21591656b296SEd Tanous if (!it->empty())
21601656b296SEd Tanous {
21611656b296SEd Tanous objectPath += "/" + *it;
21621656b296SEd Tanous }
21631656b296SEd Tanous it++;
21641656b296SEd Tanous }
21651656b296SEd Tanous if (it != strs.end())
21661656b296SEd Tanous {
21671656b296SEd Tanous interfaceName = *it;
21681656b296SEd Tanous it++;
21691656b296SEd Tanous
21701656b296SEd Tanous // after interface, we might have a method name
21711656b296SEd Tanous if (it != strs.end())
21721656b296SEd Tanous {
21731656b296SEd Tanous methodName = *it;
21741656b296SEd Tanous it++;
21751656b296SEd Tanous }
21761656b296SEd Tanous }
21771656b296SEd Tanous if (it != strs.end())
21781656b296SEd Tanous {
21791656b296SEd Tanous // if there is more levels past the method name, something
21801656b296SEd Tanous // went wrong, return not found
21811656b296SEd Tanous asyncResp->res.result(boost::beast::http::status::not_found);
21821656b296SEd Tanous return;
21831656b296SEd Tanous }
21841656b296SEd Tanous if (interfaceName.empty())
21851656b296SEd Tanous {
21861656b296SEd Tanous crow::connections::systemBus->async_method_call(
21871656b296SEd Tanous [asyncResp, processName,
21885e7e2dc5SEd Tanous objectPath](const boost::system::error_code& ec,
21891656b296SEd Tanous const std::string& introspectXml) {
21901656b296SEd Tanous if (ec)
21911656b296SEd Tanous {
219262598e31SEd Tanous BMCWEB_LOG_ERROR(
219362598e31SEd Tanous "Introspect call failed with error: {} on process: {} path: {}",
219462598e31SEd Tanous ec.message(), processName, objectPath);
21951656b296SEd Tanous return;
21961656b296SEd Tanous }
21971656b296SEd Tanous tinyxml2::XMLDocument doc;
21981656b296SEd Tanous
21991656b296SEd Tanous doc.Parse(introspectXml.c_str());
22001656b296SEd Tanous tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
22011656b296SEd Tanous if (pRoot == nullptr)
22021656b296SEd Tanous {
220362598e31SEd Tanous BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
220462598e31SEd Tanous processName, objectPath);
22051476687dSEd Tanous asyncResp->res.jsonValue["status"] = "XML parse error";
22061656b296SEd Tanous asyncResp->res.result(
22071656b296SEd Tanous boost::beast::http::status::internal_server_error);
22081656b296SEd Tanous return;
22091656b296SEd Tanous }
22101656b296SEd Tanous
221162598e31SEd Tanous BMCWEB_LOG_DEBUG("{}", introspectXml);
22121476687dSEd Tanous asyncResp->res.jsonValue["status"] = "ok";
22131476687dSEd Tanous asyncResp->res.jsonValue["bus_name"] = processName;
22141476687dSEd Tanous asyncResp->res.jsonValue["object_path"] = objectPath;
22151476687dSEd Tanous
22161656b296SEd Tanous nlohmann::json& interfacesArray =
22171656b296SEd Tanous asyncResp->res.jsonValue["interfaces"];
22181656b296SEd Tanous interfacesArray = nlohmann::json::array();
22191656b296SEd Tanous tinyxml2::XMLElement* interface =
22201656b296SEd Tanous pRoot->FirstChildElement("interface");
22211656b296SEd Tanous
22221656b296SEd Tanous while (interface != nullptr)
22231656b296SEd Tanous {
22241656b296SEd Tanous const char* ifaceName = interface->Attribute("name");
22251656b296SEd Tanous if (ifaceName != nullptr)
22261656b296SEd Tanous {
22278a592810SEd Tanous nlohmann::json::object_t interfaceObj;
22288a592810SEd Tanous interfaceObj["name"] = ifaceName;
2229b2ba3072SPatrick Williams interfacesArray.emplace_back(std::move(interfaceObj));
22301656b296SEd Tanous }
22311656b296SEd Tanous
22321656b296SEd Tanous interface = interface->NextSiblingElement("interface");
22331656b296SEd Tanous }
22341656b296SEd Tanous },
22351656b296SEd Tanous processName, objectPath, "org.freedesktop.DBus.Introspectable",
22361656b296SEd Tanous "Introspect");
22371656b296SEd Tanous }
22381656b296SEd Tanous else if (methodName.empty())
22391656b296SEd Tanous {
22401656b296SEd Tanous crow::connections::systemBus->async_method_call(
22411656b296SEd Tanous [asyncResp, processName, objectPath,
22425e7e2dc5SEd Tanous interfaceName](const boost::system::error_code& ec,
22431656b296SEd Tanous const std::string& introspectXml) {
22441656b296SEd Tanous if (ec)
22451656b296SEd Tanous {
224662598e31SEd Tanous BMCWEB_LOG_ERROR(
224762598e31SEd Tanous "Introspect call failed with error: {} on process: {} path: {}",
224862598e31SEd Tanous ec.message(), processName, objectPath);
22491656b296SEd Tanous return;
22501656b296SEd Tanous }
22511656b296SEd Tanous tinyxml2::XMLDocument doc;
22521656b296SEd Tanous
22531656b296SEd Tanous doc.Parse(introspectXml.data(), introspectXml.size());
22541656b296SEd Tanous tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
22551656b296SEd Tanous if (pRoot == nullptr)
22561656b296SEd Tanous {
225762598e31SEd Tanous BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
225862598e31SEd Tanous processName, objectPath);
22591656b296SEd Tanous asyncResp->res.result(
22601656b296SEd Tanous boost::beast::http::status::internal_server_error);
22611656b296SEd Tanous return;
22621656b296SEd Tanous }
22631476687dSEd Tanous
22641476687dSEd Tanous asyncResp->res.jsonValue["status"] = "ok";
22651476687dSEd Tanous asyncResp->res.jsonValue["bus_name"] = processName;
22661476687dSEd Tanous asyncResp->res.jsonValue["interface"] = interfaceName;
22671476687dSEd Tanous asyncResp->res.jsonValue["object_path"] = objectPath;
22681656b296SEd Tanous
2269bd79bce8SPatrick Williams nlohmann::json& methodsArray =
2270bd79bce8SPatrick Williams asyncResp->res.jsonValue["methods"];
22711656b296SEd Tanous methodsArray = nlohmann::json::array();
22721656b296SEd Tanous
2273bd79bce8SPatrick Williams nlohmann::json& signalsArray =
2274bd79bce8SPatrick Williams asyncResp->res.jsonValue["signals"];
22751656b296SEd Tanous signalsArray = nlohmann::json::array();
22761656b296SEd Tanous
22771656b296SEd Tanous nlohmann::json& propertiesObj =
22781656b296SEd Tanous asyncResp->res.jsonValue["properties"];
22791656b296SEd Tanous propertiesObj = nlohmann::json::object();
22801656b296SEd Tanous
22811656b296SEd Tanous // if we know we're the only call, build the
22821656b296SEd Tanous // json directly
22831656b296SEd Tanous tinyxml2::XMLElement* interface =
22841656b296SEd Tanous pRoot->FirstChildElement("interface");
22851656b296SEd Tanous while (interface != nullptr)
22861656b296SEd Tanous {
22871656b296SEd Tanous const char* ifaceName = interface->Attribute("name");
22881656b296SEd Tanous
22891656b296SEd Tanous if (ifaceName != nullptr && ifaceName == interfaceName)
22901656b296SEd Tanous {
22911656b296SEd Tanous break;
22921656b296SEd Tanous }
22931656b296SEd Tanous
22941656b296SEd Tanous interface = interface->NextSiblingElement("interface");
22951656b296SEd Tanous }
22961656b296SEd Tanous if (interface == nullptr)
22971656b296SEd Tanous {
22981656b296SEd Tanous // if we got to the end of the list and
22991656b296SEd Tanous // never found a match, throw 404
2300bd79bce8SPatrick Williams asyncResp->res.result(
2301bd79bce8SPatrick Williams boost::beast::http::status::not_found);
23021656b296SEd Tanous return;
23031656b296SEd Tanous }
23041656b296SEd Tanous
23051656b296SEd Tanous tinyxml2::XMLElement* methods =
23061656b296SEd Tanous interface->FirstChildElement("method");
23071656b296SEd Tanous while (methods != nullptr)
23081656b296SEd Tanous {
23091656b296SEd Tanous nlohmann::json argsArray = nlohmann::json::array();
2310bd79bce8SPatrick Williams tinyxml2::XMLElement* arg =
2311bd79bce8SPatrick Williams methods->FirstChildElement("arg");
23121656b296SEd Tanous while (arg != nullptr)
23131656b296SEd Tanous {
23141656b296SEd Tanous nlohmann::json thisArg;
23151656b296SEd Tanous for (const char* fieldName : std::array<const char*, 3>{
23161656b296SEd Tanous "name", "direction", "type"})
23171656b296SEd Tanous {
23181656b296SEd Tanous const char* fieldValue = arg->Attribute(fieldName);
23191656b296SEd Tanous if (fieldValue != nullptr)
23201656b296SEd Tanous {
23211656b296SEd Tanous thisArg[fieldName] = fieldValue;
23221656b296SEd Tanous }
23231656b296SEd Tanous }
2324b2ba3072SPatrick Williams argsArray.emplace_back(std::move(thisArg));
23251656b296SEd Tanous arg = arg->NextSiblingElement("arg");
23261656b296SEd Tanous }
23271656b296SEd Tanous
23281656b296SEd Tanous const char* name = methods->Attribute("name");
23291656b296SEd Tanous if (name != nullptr)
23301656b296SEd Tanous {
23311656b296SEd Tanous std::string uri;
2332bd79bce8SPatrick Williams uri.reserve(14 + processName.size() +
2333bd79bce8SPatrick Williams objectPath.size() + interfaceName.size() +
2334bd79bce8SPatrick Williams strlen(name));
23351656b296SEd Tanous uri += "/bus/system/";
23361656b296SEd Tanous uri += processName;
23371656b296SEd Tanous uri += objectPath;
23381656b296SEd Tanous uri += "/";
23391656b296SEd Tanous uri += interfaceName;
23401656b296SEd Tanous uri += "/";
23411656b296SEd Tanous uri += name;
23421476687dSEd Tanous
23431476687dSEd Tanous nlohmann::json::object_t object;
23441476687dSEd Tanous object["name"] = name;
23451476687dSEd Tanous object["uri"] = std::move(uri);
23461476687dSEd Tanous object["args"] = argsArray;
23471476687dSEd Tanous
2348b2ba3072SPatrick Williams methodsArray.emplace_back(std::move(object));
23491656b296SEd Tanous }
23501656b296SEd Tanous methods = methods->NextSiblingElement("method");
23511656b296SEd Tanous }
23521656b296SEd Tanous tinyxml2::XMLElement* signals =
23531656b296SEd Tanous interface->FirstChildElement("signal");
23541656b296SEd Tanous while (signals != nullptr)
23551656b296SEd Tanous {
23561656b296SEd Tanous nlohmann::json argsArray = nlohmann::json::array();
23571656b296SEd Tanous
2358bd79bce8SPatrick Williams tinyxml2::XMLElement* arg =
2359bd79bce8SPatrick Williams signals->FirstChildElement("arg");
23601656b296SEd Tanous while (arg != nullptr)
23611656b296SEd Tanous {
23621656b296SEd Tanous const char* name = arg->Attribute("name");
23631656b296SEd Tanous const char* type = arg->Attribute("type");
23641656b296SEd Tanous if (name != nullptr && type != nullptr)
23651656b296SEd Tanous {
236620fa6a2cSEd Tanous nlohmann::json::object_t params;
236720fa6a2cSEd Tanous params["name"] = name;
236820fa6a2cSEd Tanous params["type"] = type;
236920fa6a2cSEd Tanous argsArray.push_back(std::move(params));
23701656b296SEd Tanous }
23711656b296SEd Tanous arg = arg->NextSiblingElement("arg");
23721656b296SEd Tanous }
23731656b296SEd Tanous const char* name = signals->Attribute("name");
23741656b296SEd Tanous if (name != nullptr)
23751656b296SEd Tanous {
23761476687dSEd Tanous nlohmann::json::object_t object;
23771476687dSEd Tanous object["name"] = name;
23781476687dSEd Tanous object["args"] = argsArray;
2379b2ba3072SPatrick Williams signalsArray.emplace_back(std::move(object));
23801656b296SEd Tanous }
23811656b296SEd Tanous
23821656b296SEd Tanous signals = signals->NextSiblingElement("signal");
23831656b296SEd Tanous }
23841656b296SEd Tanous
23851656b296SEd Tanous tinyxml2::XMLElement* property =
23861656b296SEd Tanous interface->FirstChildElement("property");
23871656b296SEd Tanous while (property != nullptr)
23881656b296SEd Tanous {
23891656b296SEd Tanous const char* name = property->Attribute("name");
23901656b296SEd Tanous const char* type = property->Attribute("type");
23911656b296SEd Tanous if (type != nullptr && name != nullptr)
23921656b296SEd Tanous {
239359d494eeSPatrick Williams sdbusplus::message_t m =
23941656b296SEd Tanous crow::connections::systemBus->new_method_call(
23951656b296SEd Tanous processName.c_str(), objectPath.c_str(),
23961656b296SEd Tanous "org.freedesktop."
23971656b296SEd Tanous "DBus."
23981656b296SEd Tanous "Properties",
23991656b296SEd Tanous "Get");
24001656b296SEd Tanous m.append(interfaceName, name);
24011656b296SEd Tanous nlohmann::json& propertyItem = propertiesObj[name];
24021656b296SEd Tanous crow::connections::systemBus->async_send(
24031656b296SEd Tanous m, [&propertyItem,
24048b24275dSEd Tanous asyncResp](const boost::system::error_code& ec2,
240559d494eeSPatrick Williams sdbusplus::message_t& msg) {
24068b24275dSEd Tanous if (ec2)
24071656b296SEd Tanous {
24081656b296SEd Tanous return;
24091656b296SEd Tanous }
24101656b296SEd Tanous
2411bd79bce8SPatrick Williams int r =
2412bd79bce8SPatrick Williams convertDBusToJSON("v", msg, propertyItem);
241307900817SEd Tanous if (r < 0)
241407900817SEd Tanous {
2415bd79bce8SPatrick Williams BMCWEB_LOG_ERROR(
2416bd79bce8SPatrick Williams "Couldn't convert vector to json");
241707900817SEd Tanous }
24181656b296SEd Tanous });
24191656b296SEd Tanous }
24201656b296SEd Tanous property = property->NextSiblingElement("property");
24211656b296SEd Tanous }
24221656b296SEd Tanous },
24231656b296SEd Tanous processName, objectPath, "org.freedesktop.DBus.Introspectable",
24241656b296SEd Tanous "Introspect");
24251656b296SEd Tanous }
24261656b296SEd Tanous else
24271656b296SEd Tanous {
24281656b296SEd Tanous if (req.method() != boost::beast::http::verb::post)
24291656b296SEd Tanous {
24301656b296SEd Tanous asyncResp->res.result(boost::beast::http::status::not_found);
24311656b296SEd Tanous return;
24321656b296SEd Tanous }
24331656b296SEd Tanous
24341aa0c2b8SEd Tanous nlohmann::json requestDbusData;
24351aa0c2b8SEd Tanous JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
24361aa0c2b8SEd Tanous if (ret == JsonParseResult::BadContentType)
24371656b296SEd Tanous {
24381aa0c2b8SEd Tanous setErrorResponse(asyncResp->res,
24391aa0c2b8SEd Tanous boost::beast::http::status::unsupported_media_type,
24401aa0c2b8SEd Tanous invalidContentType, unsupportedMediaMsg);
24411656b296SEd Tanous return;
24421656b296SEd Tanous }
24431aa0c2b8SEd Tanous if (ret != JsonParseResult::Success)
24441aa0c2b8SEd Tanous {
24451aa0c2b8SEd Tanous setErrorResponse(asyncResp->res,
24461aa0c2b8SEd Tanous boost::beast::http::status::bad_request,
24471aa0c2b8SEd Tanous noJsonDesc, badReqMsg);
24481aa0c2b8SEd Tanous return;
24491aa0c2b8SEd Tanous }
24501aa0c2b8SEd Tanous
24511656b296SEd Tanous if (!requestDbusData.is_array())
24521656b296SEd Tanous {
24531656b296SEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request);
24541656b296SEd Tanous return;
24551656b296SEd Tanous }
245628dd5ca1SLei YU auto transaction = std::make_shared<InProgressActionData>(asyncResp);
24571656b296SEd Tanous
24581656b296SEd Tanous transaction->path = objectPath;
24591656b296SEd Tanous transaction->methodName = methodName;
24601656b296SEd Tanous transaction->arguments = std::move(requestDbusData);
24611656b296SEd Tanous
24621656b296SEd Tanous findActionOnInterface(transaction, processName);
24631656b296SEd Tanous }
24641656b296SEd Tanous }
24651656b296SEd Tanous
requestRoutes(App & app)246623a21a1cSEd Tanous inline void requestRoutes(App& app)
24671abe55efSEd Tanous {
246855c7b7a2SEd Tanous BMCWEB_ROUTE(app, "/bus/")
2469432a890cSEd Tanous .privileges({{"Login"}})
2470b41187faSEd Tanous .methods(boost::beast::http::verb::get)(
24718d1b46d7Szhanghch05 [](const crow::Request&,
24728d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
24731476687dSEd Tanous nlohmann::json::array_t buses;
24741476687dSEd Tanous nlohmann::json& bus = buses.emplace_back();
24751476687dSEd Tanous bus["name"] = "system";
24761476687dSEd Tanous asyncResp->res.jsonValue["busses"] = std::move(buses);
24771476687dSEd Tanous asyncResp->res.jsonValue["status"] = "ok";
2478911ac317SEd Tanous });
2479911ac317SEd Tanous
248055c7b7a2SEd Tanous BMCWEB_ROUTE(app, "/bus/system/")
2481432a890cSEd Tanous .privileges({{"Login"}})
2482b41187faSEd Tanous .methods(boost::beast::http::verb::get)(
24838d1b46d7Szhanghch05 [](const crow::Request&,
24848d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2485bd79bce8SPatrick Williams auto myCallback = [asyncResp](
2486bd79bce8SPatrick Williams const boost::system::error_code& ec,
2487aa2e59c1SEd Tanous std::vector<std::string>& names) {
24881abe55efSEd Tanous if (ec)
24891abe55efSEd Tanous {
249062598e31SEd Tanous BMCWEB_LOG_ERROR("Dbus call failed with code {}", ec);
24918d1b46d7Szhanghch05 asyncResp->res.result(
24921abe55efSEd Tanous boost::beast::http::status::internal_server_error);
24931abe55efSEd Tanous }
24941abe55efSEd Tanous else
24951abe55efSEd Tanous {
24963544d2a7SEd Tanous std::ranges::sort(names);
24971476687dSEd Tanous asyncResp->res.jsonValue["status"] = "ok";
24988d1b46d7Szhanghch05 auto& objectsSub = asyncResp->res.jsonValue["objects"];
249902cad96eSEd Tanous for (const auto& name : names)
25001abe55efSEd Tanous {
25011476687dSEd Tanous nlohmann::json::object_t object;
25021476687dSEd Tanous object["name"] = name;
2503b2ba3072SPatrick Williams objectsSub.emplace_back(std::move(object));
2504911ac317SEd Tanous }
2505911ac317SEd Tanous }
2506aa2e59c1SEd Tanous };
250755c7b7a2SEd Tanous crow::connections::systemBus->async_method_call(
2508aa2e59c1SEd Tanous std::move(myCallback), "org.freedesktop.DBus", "/",
2509aa2e59c1SEd Tanous "org.freedesktop.DBus", "ListNames");
2510911ac317SEd Tanous });
2511911ac317SEd Tanous
251255c7b7a2SEd Tanous BMCWEB_ROUTE(app, "/list/")
2513432a890cSEd Tanous .privileges({{"Login"}})
2514b41187faSEd Tanous .methods(boost::beast::http::verb::get)(
25158d1b46d7Szhanghch05 [](const crow::Request&,
25168d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
25178d1b46d7Szhanghch05 handleList(asyncResp, "/");
2518ba9f9a6cSEd Tanous });
2519ba9f9a6cSEd Tanous
252055c7b7a2SEd Tanous BMCWEB_ROUTE(app, "/xyz/<path>")
2521432a890cSEd Tanous .privileges({{"Login"}})
25228d1b46d7Szhanghch05 .methods(boost::beast::http::verb::get)(
25238d1b46d7Szhanghch05 [](const crow::Request& req,
25248d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2525f00032dbSTanous const std::string& path) {
2526f00032dbSTanous std::string objectPath = "/xyz/" + path;
25278d1b46d7Szhanghch05 handleDBusUrl(req, asyncResp, objectPath);
2528f00032dbSTanous });
2529f00032dbSTanous
2530f00032dbSTanous BMCWEB_ROUTE(app, "/xyz/<path>")
2531432a890cSEd Tanous .privileges({{"ConfigureComponents", "ConfigureManager"}})
2532b41187faSEd Tanous .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2533b41187faSEd Tanous boost::beast::http::verb::delete_)(
25348d1b46d7Szhanghch05 [](const crow::Request& req,
25358d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2536ba9f9a6cSEd Tanous const std::string& path) {
2537d76323e5SEd Tanous std::string objectPath = "/xyz/" + path;
25388d1b46d7Szhanghch05 handleDBusUrl(req, asyncResp, objectPath);
2539049a0515SEd Tanous });
2540a4e18f2aSEd Tanous
2541049a0515SEd Tanous BMCWEB_ROUTE(app, "/org/<path>")
2542432a890cSEd Tanous .privileges({{"Login"}})
25438d1b46d7Szhanghch05 .methods(boost::beast::http::verb::get)(
25448d1b46d7Szhanghch05 [](const crow::Request& req,
25458d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2546f00032dbSTanous const std::string& path) {
2547e1281403SEd Tanous std::string objectPath = "/org/" + path;
25488d1b46d7Szhanghch05 handleDBusUrl(req, asyncResp, objectPath);
2549f00032dbSTanous });
2550f00032dbSTanous
2551f00032dbSTanous BMCWEB_ROUTE(app, "/org/<path>")
2552432a890cSEd Tanous .privileges({{"ConfigureComponents", "ConfigureManager"}})
2553b41187faSEd Tanous .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2554b41187faSEd Tanous boost::beast::http::verb::delete_)(
25558d1b46d7Szhanghch05 [](const crow::Request& req,
25568d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2557049a0515SEd Tanous const std::string& path) {
2558e1281403SEd Tanous std::string objectPath = "/org/" + path;
25598d1b46d7Szhanghch05 handleDBusUrl(req, asyncResp, objectPath);
2560ba9f9a6cSEd Tanous });
256100b92f79Sshiyilei
256255c7b7a2SEd Tanous BMCWEB_ROUTE(app, "/download/dump/<str>/")
2563432a890cSEd Tanous .privileges({{"ConfigureManager"}})
25648d1b46d7Szhanghch05 .methods(boost::beast::http::verb::get)(
25658d1b46d7Szhanghch05 [](const crow::Request&,
25668d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2567d4bb9bbdSEd Tanous const std::string& dumpId) {
2568482c45a5SJosh Lehan if (!validateFilename(dumpId))
25691abe55efSEd Tanous {
2570bd79bce8SPatrick Williams asyncResp->res.result(
2571bd79bce8SPatrick Williams boost::beast::http::status::bad_request);
2572d4bb9bbdSEd Tanous return;
2573d4bb9bbdSEd Tanous }
2574bd79bce8SPatrick Williams std::filesystem::path loc(
2575bd79bce8SPatrick Williams "/var/lib/phosphor-debug-collector/dumps");
2576d4bb9bbdSEd Tanous
2577ad18f070SEd Tanous loc /= dumpId;
2578d4bb9bbdSEd Tanous
2579f6150403SJames Feist if (!std::filesystem::exists(loc) ||
2580f6150403SJames Feist !std::filesystem::is_directory(loc))
25811abe55efSEd Tanous {
258262598e31SEd Tanous BMCWEB_LOG_ERROR("{}Not found", loc.string());
2583bd79bce8SPatrick Williams asyncResp->res.result(
2584bd79bce8SPatrick Williams boost::beast::http::status::not_found);
2585d4bb9bbdSEd Tanous return;
2586d4bb9bbdSEd Tanous }
2587f6150403SJames Feist std::filesystem::directory_iterator files(loc);
2588ad18f070SEd Tanous
25899eb808c1SEd Tanous for (const auto& file : files)
25901abe55efSEd Tanous {
2591d51c61b4SMyung Bae if (asyncResp->res.openFile(file) !=
2592d51c61b4SMyung Bae crow::OpenCode::Success)
25931abe55efSEd Tanous {
2594d4bb9bbdSEd Tanous continue;
2595d4bb9bbdSEd Tanous }
2596d9207047SRamesh Iyyar
2597bd79bce8SPatrick Williams asyncResp->res.addHeader(
2598bd79bce8SPatrick Williams boost::beast::http::field::content_type,
25998d1b46d7Szhanghch05 "application/octet-stream");
2600d9207047SRamesh Iyyar
26018d1b46d7Szhanghch05 // Assuming only one dump file will be present in the dump
26028d1b46d7Szhanghch05 // id directory
2603d9207047SRamesh Iyyar std::string dumpFileName = file.path().filename().string();
2604d9207047SRamesh Iyyar
2605d9207047SRamesh Iyyar // Filename should be in alphanumeric, dot and underscore
26068d1b46d7Szhanghch05 // Its based on phosphor-debug-collector application
26078d1b46d7Szhanghch05 // dumpfile format
26084b242749SEd Tanous static std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
2609d9207047SRamesh Iyyar if (!std::regex_match(dumpFileName, dumpFileRegex))
2610d9207047SRamesh Iyyar {
2611bd79bce8SPatrick Williams BMCWEB_LOG_ERROR("Invalid dump filename {}",
2612bd79bce8SPatrick Williams dumpFileName);
2613bd79bce8SPatrick Williams asyncResp->res.result(
2614bd79bce8SPatrick Williams boost::beast::http::status::not_found);
2615d9207047SRamesh Iyyar return;
2616d9207047SRamesh Iyyar }
2617bd79bce8SPatrick Williams std::string contentDispositionParam =
2618bd79bce8SPatrick Williams "attachment; filename=\"" + dumpFileName + "\"";
2619d9207047SRamesh Iyyar
2620d9f6c621SEd Tanous asyncResp->res.addHeader(
2621d9f6c621SEd Tanous boost::beast::http::field::content_disposition,
26228d1b46d7Szhanghch05 contentDispositionParam);
2623d9207047SRamesh Iyyar
2624ad18f070SEd Tanous return;
2625d4bb9bbdSEd Tanous }
26268d1b46d7Szhanghch05 asyncResp->res.result(boost::beast::http::status::not_found);
2627d4bb9bbdSEd Tanous return;
2628d4bb9bbdSEd Tanous });
2629d4bb9bbdSEd Tanous
2630e3cb5a31SEd Tanous BMCWEB_ROUTE(app, "/bus/system/<str>/")
2631432a890cSEd Tanous .privileges({{"Login"}})
2632b41187faSEd Tanous
2633b41187faSEd Tanous .methods(boost::beast::http::verb::get)(
26348d1b46d7Szhanghch05 [](const crow::Request&,
26358d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
263681ce609eSEd Tanous const std::string& connection) {
263772374eb7SNan Zhou introspectObjects(connection, "/", asyncResp);
2638e3cb5a31SEd Tanous });
2639e3cb5a31SEd Tanous
2640e3cb5a31SEd Tanous BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
2641432a890cSEd Tanous .privileges({{"ConfigureComponents", "ConfigureManager"}})
26421656b296SEd Tanous .methods(boost::beast::http::verb::get,
26431656b296SEd Tanous boost::beast::http::verb::post)(handleBusSystemPost);
2644d4bb9bbdSEd Tanous }
2645911ac317SEd Tanous } // namespace openbmc_mapper
2646911ac317SEd Tanous } // namespace crow
2647