16be832e2SEd Tanous /*
26be832e2SEd Tanous Copyright (c) 2018 Intel Corporation
36be832e2SEd Tanous 
46be832e2SEd Tanous Licensed under the Apache License, Version 2.0 (the "License");
56be832e2SEd Tanous you may not use this file except in compliance with the License.
66be832e2SEd Tanous You may obtain a copy of the License at
76be832e2SEd Tanous 
86be832e2SEd Tanous     http://www.apache.org/licenses/LICENSE-2.0
96be832e2SEd Tanous 
106be832e2SEd Tanous Unless required by applicable law or agreed to in writing, software
116be832e2SEd Tanous distributed under the License is distributed on an "AS IS" BASIS,
126be832e2SEd Tanous WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136be832e2SEd Tanous See the License for the specific language governing permissions and
146be832e2SEd Tanous limitations under the License.
156be832e2SEd Tanous */
16b9b2e0b2SEd Tanous 
175b4aa86bSJames Feist #pragma once
183ccb3adbSEd Tanous #include "app.hpp"
193ccb3adbSEd Tanous #include "async_resp.hpp"
2095c6307aSEd Tanous #include "boost_formatters.hpp"
213ccb3adbSEd Tanous #include "dbus_singleton.hpp"
227a1dbc48SGeorge Liu #include "dbus_utility.hpp"
23d5c80ad9SNan Zhou #include "http_request.hpp"
24d5c80ad9SNan Zhou #include "http_response.hpp"
2595c6307aSEd Tanous #include "json_formatters.hpp"
26d5c80ad9SNan Zhou #include "logging.hpp"
271aa0c2b8SEd Tanous #include "parsing.hpp"
28d5c80ad9SNan Zhou #include "routing.hpp"
2950ebd4afSEd Tanous #include "str_utility.hpp"
30d5c80ad9SNan Zhou 
31d5c80ad9SNan Zhou #include <systemd/sd-bus-protocol.h>
32d5c80ad9SNan Zhou #include <systemd/sd-bus.h>
33911ac317SEd Tanous #include <tinyxml2.h>
341abe55efSEd Tanous 
35d5c80ad9SNan Zhou #include <boost/beast/http/status.hpp>
36d5c80ad9SNan Zhou #include <boost/beast/http/verb.hpp>
37d5c80ad9SNan Zhou #include <boost/container/flat_map.hpp>
38d5c80ad9SNan Zhou #include <boost/container/vector.hpp>
39e99073f5SGeorge Liu #include <boost/system/error_code.hpp>
40d5c80ad9SNan Zhou #include <nlohmann/json.hpp>
41d5c80ad9SNan Zhou #include <sdbusplus/asio/connection.hpp>
42c1343bf6SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp>
43d5c80ad9SNan Zhou #include <sdbusplus/exception.hpp>
44d5c80ad9SNan Zhou #include <sdbusplus/message.hpp>
45d5c80ad9SNan Zhou #include <sdbusplus/message/native_types.hpp>
461214b7e7SGunnar Mills 
47d5c80ad9SNan Zhou #include <algorithm>
48d5c80ad9SNan Zhou #include <array>
49d5c80ad9SNan Zhou #include <cerrno>
50d5c80ad9SNan Zhou #include <cstdint>
51d5c80ad9SNan Zhou #include <cstring>
524418c7f0SJames Feist #include <filesystem>
53d4bb9bbdSEd Tanous #include <fstream>
54d5c80ad9SNan Zhou #include <functional>
55d5c80ad9SNan Zhou #include <initializer_list>
56d5c80ad9SNan Zhou #include <iterator>
57d5c80ad9SNan Zhou #include <limits>
58d5c80ad9SNan Zhou #include <map>
59d5c80ad9SNan Zhou #include <memory>
603544d2a7SEd Tanous #include <ranges>
61d9207047SRamesh Iyyar #include <regex>
62d5c80ad9SNan Zhou #include <string>
63d5c80ad9SNan Zhou #include <string_view>
64d5c80ad9SNan Zhou #include <type_traits>
65b5a76932SEd Tanous #include <utility>
66d5c80ad9SNan Zhou #include <variant>
67d5c80ad9SNan Zhou #include <vector>
68d5c80ad9SNan Zhou 
691abe55efSEd Tanous namespace crow
701abe55efSEd Tanous {
711abe55efSEd Tanous namespace openbmc_mapper
721abe55efSEd Tanous {
7323a21a1cSEd Tanous const constexpr char* notFoundMsg = "404 Not Found";
7423a21a1cSEd Tanous const constexpr char* badReqMsg = "400 Bad Request";
7523a21a1cSEd Tanous const constexpr char* methodNotAllowedMsg = "405 Method Not Allowed";
7623a21a1cSEd Tanous const constexpr char* forbiddenMsg = "403 Forbidden";
771aa0c2b8SEd Tanous const constexpr char* unsupportedMediaMsg = "415 Unsupported Media Type";
7823a21a1cSEd Tanous const constexpr char* methodFailedMsg = "500 Method Call Failed";
7923a21a1cSEd Tanous const constexpr char* methodOutputFailedMsg = "500 Method Output Error";
8023a21a1cSEd Tanous const constexpr char* notFoundDesc =
812ae60096SMatt Spinler     "org.freedesktop.DBus.Error.FileNotFound: path or object not found";
8223a21a1cSEd Tanous const constexpr char* propNotFoundDesc =
8323a21a1cSEd Tanous     "The specified property cannot be found";
8423a21a1cSEd Tanous const constexpr char* noJsonDesc = "No JSON object could be decoded";
851aa0c2b8SEd Tanous const constexpr char* invalidContentType =
861aa0c2b8SEd Tanous     "Content-type header is missing or invalid";
8723a21a1cSEd Tanous const constexpr char* methodNotFoundDesc =
8823a21a1cSEd Tanous     "The specified method cannot be found";
8923a21a1cSEd Tanous const constexpr char* methodNotAllowedDesc = "Method not allowed";
9023a21a1cSEd Tanous const constexpr char* forbiddenPropDesc =
9123a21a1cSEd Tanous     "The specified property cannot be created";
9223a21a1cSEd Tanous const constexpr char* forbiddenResDesc =
9323a21a1cSEd Tanous     "The specified resource cannot be created";
942ae60096SMatt Spinler 
validateFilename(const std::string & filename)95482c45a5SJosh Lehan inline bool validateFilename(const std::string& filename)
96482c45a5SJosh Lehan {
974b242749SEd Tanous     static std::regex validFilename(R"(^[\w\- ]+(\.?[\w\- ]*)$)");
98482c45a5SJosh Lehan 
99482c45a5SJosh Lehan     return std::regex_match(filename, validFilename);
100482c45a5SJosh Lehan }
101482c45a5SJosh Lehan 
setErrorResponse(crow::Response & res,boost::beast::http::status result,const std::string & desc,std::string_view msg)10223a21a1cSEd Tanous inline void setErrorResponse(crow::Response& res,
10323a21a1cSEd Tanous                              boost::beast::http::status result,
10426ccae32SEd Tanous                              const std::string& desc, std::string_view msg)
1052ae60096SMatt Spinler {
1062ae60096SMatt Spinler     res.result(result);
1071476687dSEd Tanous     res.jsonValue["data"]["description"] = desc;
1081476687dSEd Tanous     res.jsonValue["message"] = msg;
1091476687dSEd Tanous     res.jsonValue["status"] = "error";
1102ae60096SMatt Spinler }
1112ae60096SMatt Spinler 
introspectObjects(const std::string & processName,const std::string & objectPath,const std::shared_ptr<bmcweb::AsyncResp> & transaction)112bd79bce8SPatrick Williams inline void introspectObjects(
113bd79bce8SPatrick Williams     const std::string& processName, const std::string& objectPath,
114b5a76932SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& transaction)
1151abe55efSEd Tanous {
116e3cb5a31SEd Tanous     if (transaction->res.jsonValue.is_null())
117e3cb5a31SEd Tanous     {
1181476687dSEd Tanous         transaction->res.jsonValue["status"] = "ok";
1191476687dSEd Tanous         transaction->res.jsonValue["bus_name"] = processName;
1201476687dSEd Tanous         transaction->res.jsonValue["objects"] = nlohmann::json::array();
121e3cb5a31SEd Tanous     }
122e3cb5a31SEd Tanous 
12355c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
124e3cb5a31SEd Tanous         [transaction, processName{std::string(processName)},
125e3cb5a31SEd Tanous          objectPath{std::string(objectPath)}](
1265e7e2dc5SEd Tanous             const boost::system::error_code& ec,
12781ce609eSEd Tanous             const std::string& introspectXml) {
1281abe55efSEd Tanous             if (ec)
1291abe55efSEd Tanous             {
13062598e31SEd Tanous                 BMCWEB_LOG_ERROR(
13162598e31SEd Tanous                     "Introspect call failed with error: {} on process: {} path: {}",
13262598e31SEd Tanous                     ec.message(), processName, objectPath);
133e3cb5a31SEd Tanous                 return;
1341abe55efSEd Tanous             }
1351476687dSEd Tanous             nlohmann::json::object_t object;
1361476687dSEd Tanous             object["path"] = objectPath;
1371476687dSEd Tanous 
138bd79bce8SPatrick Williams             transaction->res.jsonValue["objects"].emplace_back(
139bd79bce8SPatrick Williams                 std::move(object));
140911ac317SEd Tanous 
141911ac317SEd Tanous             tinyxml2::XMLDocument doc;
142911ac317SEd Tanous 
14381ce609eSEd Tanous             doc.Parse(introspectXml.c_str());
144911ac317SEd Tanous             tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
1451abe55efSEd Tanous             if (pRoot == nullptr)
1461abe55efSEd Tanous             {
147bd79bce8SPatrick Williams                 BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
148bd79bce8SPatrick Williams                                  processName, objectPath);
1491abe55efSEd Tanous             }
1501abe55efSEd Tanous             else
1511abe55efSEd Tanous             {
152e3cb5a31SEd Tanous                 tinyxml2::XMLElement* node = pRoot->FirstChildElement("node");
1531abe55efSEd Tanous                 while (node != nullptr)
1541abe55efSEd Tanous                 {
155e3cb5a31SEd Tanous                     const char* childPath = node->Attribute("name");
156e3cb5a31SEd Tanous                     if (childPath != nullptr)
157e3cb5a31SEd Tanous                     {
158911ac317SEd Tanous                         std::string newpath;
1591abe55efSEd Tanous                         if (objectPath != "/")
1601abe55efSEd Tanous                         {
16155c7b7a2SEd Tanous                             newpath += objectPath;
162911ac317SEd Tanous                         }
163e3cb5a31SEd Tanous                         newpath += std::string("/") + childPath;
16464530018SEd Tanous                         // introspect the subobjects as well
165e3cb5a31SEd Tanous                         introspectObjects(processName, newpath, transaction);
166e3cb5a31SEd Tanous                     }
167911ac317SEd Tanous 
168911ac317SEd Tanous                     node = node->NextSiblingElement("node");
169911ac317SEd Tanous                 }
170911ac317SEd Tanous             }
171911ac317SEd Tanous         },
172e3cb5a31SEd Tanous         processName, objectPath, "org.freedesktop.DBus.Introspectable",
1731abe55efSEd Tanous         "Introspect");
174911ac317SEd Tanous }
17564530018SEd Tanous 
getPropertiesForEnumerate(const std::string & objectPath,const std::string & service,const std::string & interface,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)17623a21a1cSEd Tanous inline void getPropertiesForEnumerate(
17723a21a1cSEd Tanous     const std::string& objectPath, const std::string& service,
178b5a76932SEd Tanous     const std::string& interface,
179b5a76932SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1802df1e7dbSMatt Spinler {
18162598e31SEd Tanous     BMCWEB_LOG_DEBUG("getPropertiesForEnumerate {} {} {}", objectPath, service,
18262598e31SEd Tanous                      interface);
1832df1e7dbSMatt Spinler 
184c1343bf6SKrzysztof Grobelny     sdbusplus::asio::getAllProperties(
185c1343bf6SKrzysztof Grobelny         *crow::connections::systemBus, service, objectPath, interface,
186b9d36b47SEd Tanous         [asyncResp, objectPath, service,
1875e7e2dc5SEd Tanous          interface](const boost::system::error_code& ec,
188b9d36b47SEd Tanous                     const dbus::utility::DBusPropertiesMap& propertiesList) {
1892df1e7dbSMatt Spinler             if (ec)
1902df1e7dbSMatt Spinler             {
19162598e31SEd Tanous                 BMCWEB_LOG_ERROR(
19262598e31SEd Tanous                     "GetAll on path {} iface {} service {} failed with code {}",
19362598e31SEd Tanous                     objectPath, interface, service, ec);
1942df1e7dbSMatt Spinler                 return;
1952df1e7dbSMatt Spinler             }
1962df1e7dbSMatt Spinler 
1972df1e7dbSMatt Spinler             nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
1982df1e7dbSMatt Spinler             nlohmann::json& objectJson = dataJson[objectPath];
1992df1e7dbSMatt Spinler             if (objectJson.is_null())
2002df1e7dbSMatt Spinler             {
2012df1e7dbSMatt Spinler                 objectJson = nlohmann::json::object();
2022df1e7dbSMatt Spinler             }
2032df1e7dbSMatt Spinler 
2042df1e7dbSMatt Spinler             for (const auto& [name, value] : propertiesList)
2052df1e7dbSMatt Spinler             {
2062df1e7dbSMatt Spinler                 nlohmann::json& propertyJson = objectJson[name];
207d1a64814SEd Tanous                 std::visit(
208d1a64814SEd Tanous                     [&propertyJson](auto&& val) {
209bd79bce8SPatrick Williams                         if constexpr (std::is_same_v<
210bd79bce8SPatrick Williams                                           std::decay_t<decltype(val)>,
211d1a64814SEd Tanous                                           sdbusplus::message::unix_fd>)
212d1a64814SEd Tanous                         {
213d1a64814SEd Tanous                             propertyJson = val.fd;
214d1a64814SEd Tanous                         }
215d1a64814SEd Tanous                         else
216d1a64814SEd Tanous                         {
217d1a64814SEd Tanous                             propertyJson = val;
218d1a64814SEd Tanous                         }
219d1a64814SEd Tanous                     },
220abf2add6SEd Tanous                     value);
2212df1e7dbSMatt Spinler             }
222c1343bf6SKrzysztof Grobelny         });
2232df1e7dbSMatt Spinler }
2242df1e7dbSMatt Spinler 
2252df1e7dbSMatt Spinler // Find any results that weren't picked up by ObjectManagers, to be
2262df1e7dbSMatt 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)22723a21a1cSEd Tanous inline void findRemainingObjectsForEnumerate(
228b5a76932SEd Tanous     const std::string& objectPath,
229b9d36b47SEd Tanous     const std::shared_ptr<dbus::utility::MapperGetSubTreeResponse>& subtree,
230b5a76932SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2312df1e7dbSMatt Spinler {
23262598e31SEd Tanous     BMCWEB_LOG_DEBUG("findRemainingObjectsForEnumerate");
2332df1e7dbSMatt Spinler     const nlohmann::json& dataJson = asyncResp->res.jsonValue["data"];
2342df1e7dbSMatt Spinler 
2352df1e7dbSMatt Spinler     for (const auto& [path, interface_map] : *subtree)
2362df1e7dbSMatt Spinler     {
2372df1e7dbSMatt Spinler         if (path == objectPath)
2382df1e7dbSMatt Spinler         {
2392df1e7dbSMatt Spinler             // An enumerate does not return the target path's properties
2402df1e7dbSMatt Spinler             continue;
2412df1e7dbSMatt Spinler         }
2422df1e7dbSMatt Spinler         if (dataJson.find(path) == dataJson.end())
2432df1e7dbSMatt Spinler         {
2442df1e7dbSMatt Spinler             for (const auto& [service, interfaces] : interface_map)
2452df1e7dbSMatt Spinler             {
2462df1e7dbSMatt Spinler                 for (const auto& interface : interfaces)
2472df1e7dbSMatt Spinler                 {
24811ba3979SEd Tanous                     if (!interface.starts_with("org.freedesktop.DBus"))
2492df1e7dbSMatt Spinler                     {
2502df1e7dbSMatt Spinler                         getPropertiesForEnumerate(path, service, interface,
2512df1e7dbSMatt Spinler                                                   asyncResp);
2522df1e7dbSMatt Spinler                     }
2532df1e7dbSMatt Spinler                 }
2542df1e7dbSMatt Spinler             }
2552df1e7dbSMatt Spinler         }
2562df1e7dbSMatt Spinler     }
2572df1e7dbSMatt Spinler }
2582df1e7dbSMatt Spinler 
2593ae4ba7bSMatt Spinler struct InProgressEnumerateData
2603ae4ba7bSMatt Spinler {
InProgressEnumerateDatacrow::openbmc_mapper::InProgressEnumerateData2618d1b46d7Szhanghch05     InProgressEnumerateData(
2628d1b46d7Szhanghch05         const std::string& objectPathIn,
2638d1b46d7Szhanghch05         const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
264bd79bce8SPatrick Williams         objectPath(objectPathIn), asyncResp(asyncRespIn)
2651214b7e7SGunnar Mills     {}
2663ae4ba7bSMatt Spinler 
~InProgressEnumerateDatacrow::openbmc_mapper::InProgressEnumerateData2673ae4ba7bSMatt Spinler     ~InProgressEnumerateData()
2683ae4ba7bSMatt Spinler     {
26924b2fe81SEd Tanous         try
27024b2fe81SEd Tanous         {
2712df1e7dbSMatt Spinler             findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
2723ae4ba7bSMatt Spinler         }
27324b2fe81SEd Tanous         catch (...)
27424b2fe81SEd Tanous         {
27562598e31SEd Tanous             BMCWEB_LOG_CRITICAL(
27662598e31SEd Tanous                 "findRemainingObjectsForEnumerate threw exception");
27724b2fe81SEd Tanous         }
27824b2fe81SEd Tanous     }
2793ae4ba7bSMatt Spinler 
280ecd6a3a2SEd Tanous     InProgressEnumerateData(const InProgressEnumerateData&) = delete;
281ecd6a3a2SEd Tanous     InProgressEnumerateData(InProgressEnumerateData&&) = delete;
282ecd6a3a2SEd Tanous     InProgressEnumerateData& operator=(const InProgressEnumerateData&) = delete;
283ecd6a3a2SEd Tanous     InProgressEnumerateData& operator=(InProgressEnumerateData&&) = delete;
2843ae4ba7bSMatt Spinler     const std::string objectPath;
285b9d36b47SEd Tanous     std::shared_ptr<dbus::utility::MapperGetSubTreeResponse> subtree;
2863ae4ba7bSMatt Spinler     std::shared_ptr<bmcweb::AsyncResp> asyncResp;
2873ae4ba7bSMatt Spinler };
2883ae4ba7bSMatt Spinler 
getManagedObjectsForEnumerate(const std::string & objectName,const std::string & objectManagerPath,const std::string & connectionName,const std::shared_ptr<InProgressEnumerateData> & transaction)28923a21a1cSEd Tanous inline void getManagedObjectsForEnumerate(
29081ce609eSEd Tanous     const std::string& objectName, const std::string& objectManagerPath,
29181ce609eSEd Tanous     const std::string& connectionName,
292b5a76932SEd Tanous     const std::shared_ptr<InProgressEnumerateData>& transaction)
2931abe55efSEd Tanous {
29462598e31SEd Tanous     BMCWEB_LOG_DEBUG(
29562598e31SEd Tanous         "getManagedObjectsForEnumerate {} object_manager_path {} connection_name {}",
29662598e31SEd Tanous         objectName, objectManagerPath, connectionName);
2975eb468daSGeorge Liu     sdbusplus::message::object_path path(objectManagerPath);
2985eb468daSGeorge Liu     dbus::utility::getManagedObjects(
2995eb468daSGeorge Liu         connectionName, path,
30081ce609eSEd Tanous         [transaction, objectName,
3015e7e2dc5SEd Tanous          connectionName](const boost::system::error_code& ec,
3025b4aa86bSJames Feist                          const dbus::utility::ManagedObjectType& objects) {
3031abe55efSEd Tanous             if (ec)
3041abe55efSEd Tanous             {
30562598e31SEd Tanous                 BMCWEB_LOG_ERROR(
30662598e31SEd Tanous                     "GetManagedObjects on path {} on connection {} failed with code {}",
30762598e31SEd Tanous                     objectName, connectionName, ec);
308049a0515SEd Tanous                 return;
3091abe55efSEd Tanous             }
310aa2e59c1SEd Tanous 
3113ae4ba7bSMatt Spinler             nlohmann::json& dataJson =
3123ae4ba7bSMatt Spinler                 transaction->asyncResp->res.jsonValue["data"];
313049a0515SEd Tanous 
314049a0515SEd Tanous             for (const auto& objectPath : objects)
3151abe55efSEd Tanous             {
31611ba3979SEd Tanous                 if (objectPath.first.str.starts_with(objectName))
317049a0515SEd Tanous                 {
31862598e31SEd Tanous                     BMCWEB_LOG_DEBUG("Reading object {}", objectPath.first.str);
319049a0515SEd Tanous                     nlohmann::json& objectJson = dataJson[objectPath.first.str];
3201abe55efSEd Tanous                     if (objectJson.is_null())
3211abe55efSEd Tanous                     {
32255c7b7a2SEd Tanous                         objectJson = nlohmann::json::object();
323aa2e59c1SEd Tanous                     }
3241abe55efSEd Tanous                     for (const auto& interface : objectPath.second)
3251abe55efSEd Tanous                     {
3261abe55efSEd Tanous                         for (const auto& property : interface.second)
3271abe55efSEd Tanous                         {
3281abe55efSEd Tanous                             nlohmann::json& propertyJson =
3291abe55efSEd Tanous                                 objectJson[property.first];
330d1a64814SEd Tanous                             std::visit(
331d1a64814SEd Tanous                                 [&propertyJson](auto&& val) {
332bd79bce8SPatrick Williams                                     if constexpr (
333bd79bce8SPatrick Williams                                         std::is_same_v<
334d1a64814SEd Tanous                                             std::decay_t<decltype(val)>,
335d1a64814SEd Tanous                                             sdbusplus::message::unix_fd>)
336d1a64814SEd Tanous                                     {
337d1a64814SEd Tanous                                         propertyJson = val.fd;
338d1a64814SEd Tanous                                     }
339d1a64814SEd Tanous                                     else
340d1a64814SEd Tanous                                     {
341d1a64814SEd Tanous                                         propertyJson = val;
342d1a64814SEd Tanous                                     }
343d1a64814SEd Tanous                                 },
34464530018SEd Tanous                                 property.second);
34564530018SEd Tanous                         }
34664530018SEd Tanous                     }
34764530018SEd Tanous                 }
348049a0515SEd Tanous                 for (const auto& interface : objectPath.second)
3491abe55efSEd Tanous                 {
350049a0515SEd Tanous                     if (interface.first == "org.freedesktop.DBus.ObjectManager")
351049a0515SEd Tanous                     {
352bd79bce8SPatrick Williams                         getManagedObjectsForEnumerate(
353bd79bce8SPatrick Williams                             objectPath.first.str, objectPath.first.str,
35481ce609eSEd Tanous                             connectionName, transaction);
355049a0515SEd Tanous                     }
356049a0515SEd Tanous                 }
35764530018SEd Tanous             }
3585eb468daSGeorge Liu         });
359e3cb5a31SEd Tanous }
360e3cb5a31SEd Tanous 
findObjectManagerPathForEnumerate(const std::string & objectName,const std::string & connectionName,const std::shared_ptr<InProgressEnumerateData> & transaction)36123a21a1cSEd Tanous inline void findObjectManagerPathForEnumerate(
36281ce609eSEd Tanous     const std::string& objectName, const std::string& connectionName,
363b5a76932SEd Tanous     const std::shared_ptr<InProgressEnumerateData>& transaction)
364e3cb5a31SEd Tanous {
36562598e31SEd Tanous     BMCWEB_LOG_DEBUG("Finding objectmanager for path {} on connection:{}",
36662598e31SEd Tanous                      objectName, connectionName);
367e3cb5a31SEd Tanous     crow::connections::systemBus->async_method_call(
36881ce609eSEd Tanous         [transaction, objectName, connectionName](
3695e7e2dc5SEd Tanous             const boost::system::error_code& ec,
370b9d36b47SEd Tanous             const dbus::utility::MapperGetAncestorsResponse& objects) {
371e3cb5a31SEd Tanous             if (ec)
372e3cb5a31SEd Tanous             {
37362598e31SEd Tanous                 BMCWEB_LOG_ERROR("GetAncestors on path {} failed with code {}",
37462598e31SEd Tanous                                  objectName, ec);
375e3cb5a31SEd Tanous                 return;
376e3cb5a31SEd Tanous             }
377e3cb5a31SEd Tanous 
378f254ba77SEd Tanous             for (const auto& pathGroup : objects)
379e3cb5a31SEd Tanous             {
380f254ba77SEd Tanous                 for (const auto& connectionGroup : pathGroup.second)
381e3cb5a31SEd Tanous                 {
38281ce609eSEd Tanous                     if (connectionGroup.first == connectionName)
383e3cb5a31SEd Tanous                     {
384e3cb5a31SEd Tanous                         // Found the object manager path for this resource.
385bd79bce8SPatrick Williams                         getManagedObjectsForEnumerate(
386bd79bce8SPatrick Williams                             objectName, pathGroup.first, connectionName,
387bd79bce8SPatrick Williams                             transaction);
388e3cb5a31SEd Tanous                         return;
389e3cb5a31SEd Tanous                     }
390e3cb5a31SEd Tanous                 }
391e3cb5a31SEd Tanous             }
392e3cb5a31SEd Tanous         },
393e3cb5a31SEd Tanous         "xyz.openbmc_project.ObjectMapper",
394e3cb5a31SEd Tanous         "/xyz/openbmc_project/object_mapper",
39581ce609eSEd Tanous         "xyz.openbmc_project.ObjectMapper", "GetAncestors", objectName,
396e3cb5a31SEd Tanous         std::array<const char*, 1>{"org.freedesktop.DBus.ObjectManager"});
397aa2e59c1SEd Tanous }
39864530018SEd Tanous 
3997c09162aSEd Tanous // Uses GetObject to add the object info about the target /enumerate path to
4007c09162aSEd Tanous // the results of GetSubTree, as GetSubTree will not return info for the
4013ae4ba7bSMatt Spinler // target path, and then continues on enumerating the rest of the tree.
getObjectAndEnumerate(const std::shared_ptr<InProgressEnumerateData> & transaction)402b5a76932SEd Tanous inline void getObjectAndEnumerate(
403b5a76932SEd Tanous     const std::shared_ptr<InProgressEnumerateData>& transaction)
4043ae4ba7bSMatt Spinler {
4052b73119cSGeorge Liu     dbus::utility::getDbusObject(
4062b73119cSGeorge Liu         transaction->objectPath, {},
4072b73119cSGeorge Liu         [transaction](const boost::system::error_code& ec,
408b9d36b47SEd Tanous                       const dbus::utility::MapperGetObject& objects) {
4093ae4ba7bSMatt Spinler             if (ec)
4103ae4ba7bSMatt Spinler             {
41162598e31SEd Tanous                 BMCWEB_LOG_ERROR("GetObject for path {} failed with code {}",
41262598e31SEd Tanous                                  transaction->objectPath, ec);
4133ae4ba7bSMatt Spinler                 return;
4143ae4ba7bSMatt Spinler             }
4153ae4ba7bSMatt Spinler 
41662598e31SEd Tanous             BMCWEB_LOG_DEBUG("GetObject for {} has {} entries",
41762598e31SEd Tanous                              transaction->objectPath, objects.size());
4183ae4ba7bSMatt Spinler             if (!objects.empty())
4193ae4ba7bSMatt Spinler             {
4203ae4ba7bSMatt Spinler                 transaction->subtree->emplace_back(transaction->objectPath,
4213ae4ba7bSMatt Spinler                                                    objects);
4223ae4ba7bSMatt Spinler             }
4233ae4ba7bSMatt Spinler 
4243ae4ba7bSMatt Spinler             // Map indicating connection name, and the path where the object
4253ae4ba7bSMatt Spinler             // manager exists
42618f8f608SEd Tanous             boost::container::flat_map<
42718f8f608SEd Tanous                 std::string, std::string, std::less<>,
42818f8f608SEd Tanous                 std::vector<std::pair<std::string, std::string>>>
42918f8f608SEd Tanous                 connections;
4303ae4ba7bSMatt Spinler 
4313ae4ba7bSMatt Spinler             for (const auto& object : *(transaction->subtree))
4323ae4ba7bSMatt Spinler             {
4333ae4ba7bSMatt Spinler                 for (const auto& connection : object.second)
4343ae4ba7bSMatt Spinler                 {
4353ae4ba7bSMatt Spinler                     for (const auto& interface : connection.second)
4363ae4ba7bSMatt Spinler                     {
437bd79bce8SPatrick Williams                         BMCWEB_LOG_DEBUG("{} has interface {}",
438bd79bce8SPatrick Williams                                          connection.first, interface);
4393ae4ba7bSMatt Spinler                         if (interface == "org.freedesktop.DBus.ObjectManager")
4403ae4ba7bSMatt Spinler                         {
44162598e31SEd Tanous                             BMCWEB_LOG_DEBUG("found object manager path {}",
44262598e31SEd Tanous                                              object.first);
443f8fe53e7SEd Tanous                             connections[connection.first] = object.first;
4443ae4ba7bSMatt Spinler                         }
4453ae4ba7bSMatt Spinler                     }
4463ae4ba7bSMatt Spinler                 }
4473ae4ba7bSMatt Spinler             }
44862598e31SEd Tanous             BMCWEB_LOG_DEBUG("Got {} connections", connections.size());
4493ae4ba7bSMatt Spinler 
4503ae4ba7bSMatt Spinler             for (const auto& connection : connections)
4513ae4ba7bSMatt Spinler             {
4527c09162aSEd Tanous                 // If we already know where the object manager is, we don't
4537c09162aSEd Tanous                 // need to search for it, we can call directly in to
4543ae4ba7bSMatt Spinler                 // getManagedObjects
4553ae4ba7bSMatt Spinler                 if (!connection.second.empty())
4563ae4ba7bSMatt Spinler                 {
457bd79bce8SPatrick Williams                     getManagedObjectsForEnumerate(
458bd79bce8SPatrick Williams                         transaction->objectPath, connection.second,
4593ae4ba7bSMatt Spinler                         connection.first, transaction);
4603ae4ba7bSMatt Spinler                 }
4613ae4ba7bSMatt Spinler                 else
4623ae4ba7bSMatt Spinler                 {
4637c09162aSEd Tanous                     // otherwise we need to find the object manager path
4647c09162aSEd Tanous                     // before we can continue
4653ae4ba7bSMatt Spinler                     findObjectManagerPathForEnumerate(
4663ae4ba7bSMatt Spinler                         transaction->objectPath, connection.first, transaction);
4673ae4ba7bSMatt Spinler                 }
4683ae4ba7bSMatt Spinler             }
4692b73119cSGeorge Liu         });
4703ae4ba7bSMatt Spinler }
47164530018SEd Tanous 
472d4bb9bbdSEd Tanous // Structure for storing data on an in progress action
4731abe55efSEd Tanous struct InProgressActionData
4741abe55efSEd Tanous {
InProgressActionDatacrow::openbmc_mapper::InProgressActionData47528dd5ca1SLei YU     explicit InProgressActionData(
476bd79bce8SPatrick Williams         const std::shared_ptr<bmcweb::AsyncResp>& res) : asyncResp(res)
47723a21a1cSEd Tanous     {}
~InProgressActionDatacrow::openbmc_mapper::InProgressActionData4781abe55efSEd Tanous     ~InProgressActionData()
4791abe55efSEd Tanous     {
48016caaee1SMatt Spinler         // Methods could have been called across different owners
48116caaee1SMatt Spinler         // and interfaces, where some calls failed and some passed.
48216caaee1SMatt Spinler         //
48316caaee1SMatt Spinler         // The rules for this are:
48416caaee1SMatt Spinler         // * if no method was called - error
48516caaee1SMatt Spinler         // * if a method failed and none passed - error
48616caaee1SMatt Spinler         //   (converse: if at least one method passed - OK)
48716caaee1SMatt Spinler         // * for the method output:
48816caaee1SMatt Spinler         //   * if output processing didn't fail, return the data
48916caaee1SMatt Spinler 
49016caaee1SMatt Spinler         // Only deal with method returns if nothing failed earlier
49128dd5ca1SLei YU         if (asyncResp->res.result() == boost::beast::http::status::ok)
49216caaee1SMatt Spinler         {
49316caaee1SMatt Spinler             if (!methodPassed)
49416caaee1SMatt Spinler             {
49506b1b63cSMatt Spinler                 if (!methodFailed)
4961abe55efSEd Tanous                 {
49728dd5ca1SLei YU                     setErrorResponse(asyncResp->res,
49828dd5ca1SLei YU                                      boost::beast::http::status::not_found,
4996db06242SMatt Spinler                                      methodNotFoundDesc, notFoundMsg);
500d4bb9bbdSEd Tanous                 }
50116caaee1SMatt Spinler             }
50216caaee1SMatt Spinler             else
50316caaee1SMatt Spinler             {
50416caaee1SMatt Spinler                 if (outputFailed)
50516caaee1SMatt Spinler                 {
50616caaee1SMatt Spinler                     setErrorResponse(
50728dd5ca1SLei YU                         asyncResp->res,
50828dd5ca1SLei YU                         boost::beast::http::status::internal_server_error,
50916caaee1SMatt Spinler                         "Method output failure", methodOutputFailedMsg);
51016caaee1SMatt Spinler                 }
51116caaee1SMatt Spinler                 else
51216caaee1SMatt Spinler                 {
51328dd5ca1SLei YU                     asyncResp->res.jsonValue["status"] = "ok";
51428dd5ca1SLei YU                     asyncResp->res.jsonValue["message"] = "200 OK";
51528dd5ca1SLei YU                     asyncResp->res.jsonValue["data"] = methodResponse;
51616caaee1SMatt Spinler                 }
51716caaee1SMatt Spinler             }
51816caaee1SMatt Spinler         }
519d4bb9bbdSEd Tanous     }
520ecd6a3a2SEd Tanous     InProgressActionData(const InProgressActionData&) = delete;
521ecd6a3a2SEd Tanous     InProgressActionData(InProgressActionData&&) = delete;
522ecd6a3a2SEd Tanous     InProgressActionData& operator=(const InProgressActionData&) = delete;
523ecd6a3a2SEd Tanous     InProgressActionData& operator=(InProgressActionData&&) = delete;
524d4bb9bbdSEd Tanous 
setErrorStatuscrow::openbmc_mapper::InProgressActionData5256db06242SMatt Spinler     void setErrorStatus(const std::string& desc)
5261abe55efSEd Tanous     {
52728dd5ca1SLei YU         setErrorResponse(asyncResp->res,
52828dd5ca1SLei YU                          boost::beast::http::status::bad_request, desc,
529c0eb9bd9SMatt Spinler                          badReqMsg);
530d4bb9bbdSEd Tanous     }
53128dd5ca1SLei YU     std::shared_ptr<bmcweb::AsyncResp> asyncResp;
532d4bb9bbdSEd Tanous     std::string path;
533d76323e5SEd Tanous     std::string methodName;
534de81881fSMatt Spinler     std::string interfaceName;
53516caaee1SMatt Spinler     bool methodPassed = false;
53616caaee1SMatt Spinler     bool methodFailed = false;
53716caaee1SMatt Spinler     bool outputFailed = false;
53839a4e39fSMatt Spinler     bool convertedToArray = false;
53916caaee1SMatt Spinler     nlohmann::json methodResponse;
540d4bb9bbdSEd Tanous     nlohmann::json arguments;
541d4bb9bbdSEd Tanous };
542d4bb9bbdSEd Tanous 
dbusArgSplit(const std::string & string)54323a21a1cSEd Tanous inline std::vector<std::string> dbusArgSplit(const std::string& string)
5441abe55efSEd Tanous {
545d4bb9bbdSEd Tanous     std::vector<std::string> ret;
5461abe55efSEd Tanous     if (string.empty())
5471abe55efSEd Tanous     {
548d4bb9bbdSEd Tanous         return ret;
549d4bb9bbdSEd Tanous     }
5500f0353b6SEd Tanous     ret.emplace_back("");
551d76323e5SEd Tanous     int containerDepth = 0;
55275db20e9SEd Tanous 
55375db20e9SEd Tanous     for (std::string::const_iterator character = string.begin();
5541abe55efSEd Tanous          character != string.end(); character++)
5551abe55efSEd Tanous     {
55675db20e9SEd Tanous         ret.back() += *character;
5571abe55efSEd Tanous         switch (*character)
5581abe55efSEd Tanous         {
559d4bb9bbdSEd Tanous             case ('a'):
560d4bb9bbdSEd Tanous                 break;
561d4bb9bbdSEd Tanous             case ('('):
562d4bb9bbdSEd Tanous             case ('{'):
563d76323e5SEd Tanous                 containerDepth++;
564d4bb9bbdSEd Tanous                 break;
565d4bb9bbdSEd Tanous             case ('}'):
566d4bb9bbdSEd Tanous             case (')'):
567d76323e5SEd Tanous                 containerDepth--;
5681abe55efSEd Tanous                 if (containerDepth == 0)
5691abe55efSEd Tanous                 {
5701abe55efSEd Tanous                     if (character + 1 != string.end())
5711abe55efSEd Tanous                     {
5720f0353b6SEd Tanous                         ret.emplace_back("");
573d4bb9bbdSEd Tanous                     }
574d4bb9bbdSEd Tanous                 }
575d4bb9bbdSEd Tanous                 break;
576d4bb9bbdSEd Tanous             default:
5771abe55efSEd Tanous                 if (containerDepth == 0)
5781abe55efSEd Tanous                 {
5791abe55efSEd Tanous                     if (character + 1 != string.end())
5801abe55efSEd Tanous                     {
5810f0353b6SEd Tanous                         ret.emplace_back("");
582d4bb9bbdSEd Tanous                     }
583d4bb9bbdSEd Tanous                 }
584d4bb9bbdSEd Tanous                 break;
585d4bb9bbdSEd Tanous         }
586d4bb9bbdSEd Tanous     }
5874ae611d9SMatt Spinler 
5884ae611d9SMatt Spinler     return ret;
589d4bb9bbdSEd Tanous }
590d4bb9bbdSEd Tanous 
convertJsonToDbus(sd_bus_message * m,const std::string & argType,const nlohmann::json & inputJson)59181ce609eSEd Tanous inline int convertJsonToDbus(sd_bus_message* m, const std::string& argType,
59281ce609eSEd Tanous                              const nlohmann::json& inputJson)
5931abe55efSEd Tanous {
594d4bb9bbdSEd Tanous     int r = 0;
595296579beSEd Tanous     BMCWEB_LOG_DEBUG("Converting {} to type: {}", inputJson, argType);
59681ce609eSEd Tanous     const std::vector<std::string> argTypes = dbusArgSplit(argType);
597d4bb9bbdSEd Tanous 
598d4bb9bbdSEd Tanous     // Assume a single object for now.
59981ce609eSEd Tanous     const nlohmann::json* j = &inputJson;
60081ce609eSEd Tanous     nlohmann::json::const_iterator jIt = inputJson.begin();
601d4bb9bbdSEd Tanous 
602e3cb5a31SEd Tanous     for (const std::string& argCode : argTypes)
6031abe55efSEd Tanous     {
6041abe55efSEd Tanous         // If we are decoding multiple objects, grab the pointer to the
6051abe55efSEd Tanous         // iterator, and increment it for the next loop
6061abe55efSEd Tanous         if (argTypes.size() > 1)
6071abe55efSEd Tanous         {
60881ce609eSEd Tanous             if (jIt == inputJson.end())
6091abe55efSEd Tanous             {
610d4bb9bbdSEd Tanous                 return -2;
611d4bb9bbdSEd Tanous             }
612d76323e5SEd Tanous             j = &*jIt;
613d76323e5SEd Tanous             jIt++;
614d4bb9bbdSEd Tanous         }
615e3cb5a31SEd Tanous         const int64_t* intValue = j->get_ptr<const int64_t*>();
616e3cb5a31SEd Tanous         const std::string* stringValue = j->get_ptr<const std::string*>();
617e3cb5a31SEd Tanous         const double* doubleValue = j->get_ptr<const double*>();
618d4bb9bbdSEd Tanous         const bool* b = j->get_ptr<const bool*>();
619d4bb9bbdSEd Tanous         int64_t v = 0;
620d4bb9bbdSEd Tanous         double d = 0.0;
621d4bb9bbdSEd Tanous 
6221abe55efSEd Tanous         // Do some basic type conversions that make sense.  uint can be
6231abe55efSEd Tanous         // converted to int.  int and uint can be converted to double
62466664f25SEd Tanous         if (intValue == nullptr)
62566664f25SEd Tanous         {
62666664f25SEd Tanous             const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
62766664f25SEd Tanous             if (uintValue != nullptr)
6281abe55efSEd Tanous             {
629e3cb5a31SEd Tanous                 v = static_cast<int64_t>(*uintValue);
630e3cb5a31SEd Tanous                 intValue = &v;
631d4bb9bbdSEd Tanous             }
63266664f25SEd Tanous         }
63366664f25SEd Tanous         if (doubleValue == nullptr)
63466664f25SEd Tanous         {
63566664f25SEd Tanous             const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
63666664f25SEd Tanous             if (uintValue != nullptr)
6371abe55efSEd Tanous             {
638e3cb5a31SEd Tanous                 d = static_cast<double>(*uintValue);
639e3cb5a31SEd Tanous                 doubleValue = &d;
640d4bb9bbdSEd Tanous             }
64166664f25SEd Tanous         }
64266664f25SEd Tanous         if (doubleValue == nullptr)
64366664f25SEd Tanous         {
64466664f25SEd Tanous             if (intValue != nullptr)
6451abe55efSEd Tanous             {
646e3cb5a31SEd Tanous                 d = static_cast<double>(*intValue);
647e3cb5a31SEd Tanous                 doubleValue = &d;
648d4bb9bbdSEd Tanous             }
64966664f25SEd Tanous         }
650d4bb9bbdSEd Tanous 
651e3cb5a31SEd Tanous         if (argCode == "s")
6521abe55efSEd Tanous         {
653e3cb5a31SEd Tanous             if (stringValue == nullptr)
6541abe55efSEd Tanous             {
655d4bb9bbdSEd Tanous                 return -1;
656d4bb9bbdSEd Tanous             }
657271584abSEd Tanous             r = sd_bus_message_append_basic(
658271584abSEd Tanous                 m, argCode[0], static_cast<const void*>(stringValue->data()));
6591abe55efSEd Tanous             if (r < 0)
6601abe55efSEd Tanous             {
661d4bb9bbdSEd Tanous                 return r;
662d4bb9bbdSEd Tanous             }
6631abe55efSEd Tanous         }
664e3cb5a31SEd Tanous         else if (argCode == "i")
6651abe55efSEd Tanous         {
666e3cb5a31SEd Tanous             if (intValue == nullptr)
6671abe55efSEd Tanous             {
668d4bb9bbdSEd Tanous                 return -1;
669d4bb9bbdSEd Tanous             }
670c66c859cSAdriana Kobylak             if ((*intValue < std::numeric_limits<int32_t>::lowest()) ||
671c66c859cSAdriana Kobylak                 (*intValue > std::numeric_limits<int32_t>::max()))
672c66c859cSAdriana Kobylak             {
673c66c859cSAdriana Kobylak                 return -ERANGE;
674c66c859cSAdriana Kobylak             }
675e3cb5a31SEd Tanous             int32_t i = static_cast<int32_t>(*intValue);
676e3cb5a31SEd Tanous             r = sd_bus_message_append_basic(m, argCode[0], &i);
6771abe55efSEd Tanous             if (r < 0)
6781abe55efSEd Tanous             {
679d4bb9bbdSEd Tanous                 return r;
680d4bb9bbdSEd Tanous             }
6811abe55efSEd Tanous         }
682e3cb5a31SEd Tanous         else if (argCode == "b")
6831abe55efSEd Tanous         {
684d4bb9bbdSEd Tanous             // lots of ways bool could be represented here.  Try them all
685e662eae8SEd Tanous             int boolInt = 0;
686e3cb5a31SEd Tanous             if (intValue != nullptr)
6871abe55efSEd Tanous             {
688c66c859cSAdriana Kobylak                 if (*intValue == 1)
689c66c859cSAdriana Kobylak                 {
690e662eae8SEd Tanous                     boolInt = 1;
691c66c859cSAdriana Kobylak                 }
692c66c859cSAdriana Kobylak                 else if (*intValue == 0)
693c66c859cSAdriana Kobylak                 {
694e662eae8SEd Tanous                     boolInt = 0;
695c66c859cSAdriana Kobylak                 }
696c66c859cSAdriana Kobylak                 else
697c66c859cSAdriana Kobylak                 {
698c66c859cSAdriana Kobylak                     return -ERANGE;
699c66c859cSAdriana Kobylak                 }
7001abe55efSEd Tanous             }
7011abe55efSEd Tanous             else if (b != nullptr)
7021abe55efSEd Tanous             {
703a2f02638SMatt Spinler                 boolInt = *b ? 1 : 0;
7041abe55efSEd Tanous             }
705e3cb5a31SEd Tanous             else if (stringValue != nullptr)
7061abe55efSEd Tanous             {
70718f8f608SEd Tanous                 if (!stringValue->empty())
70818f8f608SEd Tanous                 {
70918f8f608SEd Tanous                     if (stringValue->front() == 't' ||
71018f8f608SEd Tanous                         stringValue->front() == 'T')
71118f8f608SEd Tanous                     {
71218f8f608SEd Tanous                         boolInt = 1;
71318f8f608SEd Tanous                     }
71418f8f608SEd Tanous                 }
7151abe55efSEd Tanous             }
7161abe55efSEd Tanous             else
7171abe55efSEd Tanous             {
718d4bb9bbdSEd Tanous                 return -1;
719d4bb9bbdSEd Tanous             }
720e3cb5a31SEd Tanous             r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
7211abe55efSEd Tanous             if (r < 0)
7221abe55efSEd Tanous             {
723d4bb9bbdSEd Tanous                 return r;
724d4bb9bbdSEd Tanous             }
7251abe55efSEd Tanous         }
726e3cb5a31SEd Tanous         else if (argCode == "n")
7271abe55efSEd Tanous         {
728e3cb5a31SEd Tanous             if (intValue == nullptr)
7291abe55efSEd Tanous             {
730d4bb9bbdSEd Tanous                 return -1;
731d4bb9bbdSEd Tanous             }
732c66c859cSAdriana Kobylak             if ((*intValue < std::numeric_limits<int16_t>::lowest()) ||
733c66c859cSAdriana Kobylak                 (*intValue > std::numeric_limits<int16_t>::max()))
734c66c859cSAdriana Kobylak             {
735c66c859cSAdriana Kobylak                 return -ERANGE;
736c66c859cSAdriana Kobylak             }
737e3cb5a31SEd Tanous             int16_t n = static_cast<int16_t>(*intValue);
738e3cb5a31SEd Tanous             r = sd_bus_message_append_basic(m, argCode[0], &n);
7391abe55efSEd Tanous             if (r < 0)
7401abe55efSEd Tanous             {
741d4bb9bbdSEd Tanous                 return r;
742d4bb9bbdSEd Tanous             }
7431abe55efSEd Tanous         }
744e3cb5a31SEd Tanous         else if (argCode == "x")
7451abe55efSEd Tanous         {
746e3cb5a31SEd Tanous             if (intValue == nullptr)
7471abe55efSEd Tanous             {
748d4bb9bbdSEd Tanous                 return -1;
749d4bb9bbdSEd Tanous             }
750e3cb5a31SEd Tanous             r = sd_bus_message_append_basic(m, argCode[0], intValue);
7511abe55efSEd Tanous             if (r < 0)
7521abe55efSEd Tanous             {
753d4bb9bbdSEd Tanous                 return r;
754d4bb9bbdSEd Tanous             }
7551abe55efSEd Tanous         }
756e3cb5a31SEd Tanous         else if (argCode == "y")
7571abe55efSEd Tanous         {
75866664f25SEd Tanous             const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
759e3cb5a31SEd Tanous             if (uintValue == nullptr)
7601abe55efSEd Tanous             {
761d4bb9bbdSEd Tanous                 return -1;
762d4bb9bbdSEd Tanous             }
76323a21a1cSEd Tanous             if (*uintValue > std::numeric_limits<uint8_t>::max())
764c66c859cSAdriana Kobylak             {
765c66c859cSAdriana Kobylak                 return -ERANGE;
766c66c859cSAdriana Kobylak             }
767e3cb5a31SEd Tanous             uint8_t y = static_cast<uint8_t>(*uintValue);
768e3cb5a31SEd Tanous             r = sd_bus_message_append_basic(m, argCode[0], &y);
7691abe55efSEd Tanous         }
770e3cb5a31SEd Tanous         else if (argCode == "q")
7711abe55efSEd Tanous         {
77266664f25SEd Tanous             const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
773e3cb5a31SEd Tanous             if (uintValue == nullptr)
7741abe55efSEd Tanous             {
775d4bb9bbdSEd Tanous                 return -1;
776d4bb9bbdSEd Tanous             }
77723a21a1cSEd Tanous             if (*uintValue > std::numeric_limits<uint16_t>::max())
778c66c859cSAdriana Kobylak             {
779c66c859cSAdriana Kobylak                 return -ERANGE;
780c66c859cSAdriana Kobylak             }
781e3cb5a31SEd Tanous             uint16_t q = static_cast<uint16_t>(*uintValue);
782e3cb5a31SEd Tanous             r = sd_bus_message_append_basic(m, argCode[0], &q);
7831abe55efSEd Tanous         }
784e3cb5a31SEd Tanous         else if (argCode == "u")
7851abe55efSEd Tanous         {
78666664f25SEd Tanous             const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
787e3cb5a31SEd Tanous             if (uintValue == nullptr)
7881abe55efSEd Tanous             {
789d4bb9bbdSEd Tanous                 return -1;
790d4bb9bbdSEd Tanous             }
79123a21a1cSEd Tanous             if (*uintValue > std::numeric_limits<uint32_t>::max())
792c66c859cSAdriana Kobylak             {
793c66c859cSAdriana Kobylak                 return -ERANGE;
794c66c859cSAdriana Kobylak             }
795e3cb5a31SEd Tanous             uint32_t u = static_cast<uint32_t>(*uintValue);
796e3cb5a31SEd Tanous             r = sd_bus_message_append_basic(m, argCode[0], &u);
7971abe55efSEd Tanous         }
798e3cb5a31SEd Tanous         else if (argCode == "t")
7991abe55efSEd Tanous         {
80066664f25SEd Tanous             const uint64_t* uintValue = j->get_ptr<const uint64_t*>();
801e3cb5a31SEd Tanous             if (uintValue == nullptr)
8021abe55efSEd Tanous             {
803d4bb9bbdSEd Tanous                 return -1;
804d4bb9bbdSEd Tanous             }
805e3cb5a31SEd Tanous             r = sd_bus_message_append_basic(m, argCode[0], uintValue);
8061abe55efSEd Tanous         }
807e3cb5a31SEd Tanous         else if (argCode == "d")
8081abe55efSEd Tanous         {
809c66c859cSAdriana Kobylak             if (doubleValue == nullptr)
810c66c859cSAdriana Kobylak             {
811c66c859cSAdriana Kobylak                 return -1;
812c66c859cSAdriana Kobylak             }
813c66c859cSAdriana Kobylak             if ((*doubleValue < std::numeric_limits<double>::lowest()) ||
814c66c859cSAdriana Kobylak                 (*doubleValue > std::numeric_limits<double>::max()))
815c66c859cSAdriana Kobylak             {
816c66c859cSAdriana Kobylak                 return -ERANGE;
817c66c859cSAdriana Kobylak             }
81807900817SEd Tanous             r = sd_bus_message_append_basic(m, argCode[0], doubleValue);
81907900817SEd Tanous             if (r < 0)
82007900817SEd Tanous             {
82107900817SEd Tanous                 return r;
82207900817SEd Tanous             }
8231abe55efSEd Tanous         }
82411ba3979SEd Tanous         else if (argCode.starts_with("a"))
8251abe55efSEd Tanous         {
826e3cb5a31SEd Tanous             std::string containedType = argCode.substr(1);
827d4bb9bbdSEd Tanous             r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
828e3cb5a31SEd Tanous                                               containedType.c_str());
8291abe55efSEd Tanous             if (r < 0)
8301abe55efSEd Tanous             {
831d4bb9bbdSEd Tanous                 return r;
832d4bb9bbdSEd Tanous             }
833d4bb9bbdSEd Tanous 
8340dfeda62SEd Tanous             for (const auto& it : *j)
8351abe55efSEd Tanous             {
8360dfeda62SEd Tanous                 r = convertJsonToDbus(m, containedType, it);
8371abe55efSEd Tanous                 if (r < 0)
8381abe55efSEd Tanous                 {
839d4bb9bbdSEd Tanous                     return r;
840d4bb9bbdSEd Tanous                 }
841d4bb9bbdSEd Tanous             }
842d4bb9bbdSEd Tanous             sd_bus_message_close_container(m);
8431abe55efSEd Tanous         }
84411ba3979SEd Tanous         else if (argCode.starts_with("v"))
8451abe55efSEd Tanous         {
846e3cb5a31SEd Tanous             std::string containedType = argCode.substr(1);
84762598e31SEd Tanous             BMCWEB_LOG_DEBUG("variant type: {} appending variant of type: {}",
84862598e31SEd Tanous                              argCode, containedType);
849d4bb9bbdSEd Tanous             r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
850e3cb5a31SEd Tanous                                               containedType.c_str());
8511abe55efSEd Tanous             if (r < 0)
8521abe55efSEd Tanous             {
853d4bb9bbdSEd Tanous                 return r;
854d4bb9bbdSEd Tanous             }
855d4bb9bbdSEd Tanous 
85681ce609eSEd Tanous             r = convertJsonToDbus(m, containedType, inputJson);
8571abe55efSEd Tanous             if (r < 0)
8581abe55efSEd Tanous             {
859d4bb9bbdSEd Tanous                 return r;
860d4bb9bbdSEd Tanous             }
861d4bb9bbdSEd Tanous 
862d4bb9bbdSEd Tanous             r = sd_bus_message_close_container(m);
8631abe55efSEd Tanous             if (r < 0)
8641abe55efSEd Tanous             {
865d4bb9bbdSEd Tanous                 return r;
866d4bb9bbdSEd Tanous             }
8671abe55efSEd Tanous         }
86811ba3979SEd Tanous         else if (argCode.starts_with("(") && argCode.ends_with(")"))
8691abe55efSEd Tanous         {
870f3477566SMikhail Zhvakin             std::string containedType = argCode.substr(1, argCode.size() - 2);
871d4bb9bbdSEd Tanous             r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
872e3cb5a31SEd Tanous                                               containedType.c_str());
873f1eebf06SEd Tanous             if (r < 0)
874f1eebf06SEd Tanous             {
875f1eebf06SEd Tanous                 return r;
876f1eebf06SEd Tanous             }
877f1eebf06SEd Tanous 
878d4bb9bbdSEd Tanous             nlohmann::json::const_iterator it = j->begin();
879f3477566SMikhail Zhvakin             for (const std::string& argCode2 : dbusArgSplit(containedType))
8801abe55efSEd Tanous             {
8811abe55efSEd Tanous                 if (it == j->end())
8821abe55efSEd Tanous                 {
883d4bb9bbdSEd Tanous                     return -1;
884d4bb9bbdSEd Tanous                 }
885cb13a392SEd Tanous                 r = convertJsonToDbus(m, argCode2, *it);
8861abe55efSEd Tanous                 if (r < 0)
8871abe55efSEd Tanous                 {
888d4bb9bbdSEd Tanous                     return r;
889d4bb9bbdSEd Tanous                 }
890d4bb9bbdSEd Tanous                 it++;
891d4bb9bbdSEd Tanous             }
892d4bb9bbdSEd Tanous             r = sd_bus_message_close_container(m);
8931abe55efSEd Tanous         }
89411ba3979SEd Tanous         else if (argCode.starts_with("{") && argCode.ends_with("}"))
8951abe55efSEd Tanous         {
896f3477566SMikhail Zhvakin             std::string containedType = argCode.substr(1, argCode.size() - 2);
897d4bb9bbdSEd Tanous             r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
898e3cb5a31SEd Tanous                                               containedType.c_str());
899f1eebf06SEd Tanous             if (r < 0)
900f1eebf06SEd Tanous             {
901f1eebf06SEd Tanous                 return r;
902f1eebf06SEd Tanous             }
903f1eebf06SEd Tanous 
904e3cb5a31SEd Tanous             std::vector<std::string> codes = dbusArgSplit(containedType);
9051abe55efSEd Tanous             if (codes.size() != 2)
9061abe55efSEd Tanous             {
907d4bb9bbdSEd Tanous                 return -1;
908d4bb9bbdSEd Tanous             }
9092c70f800SEd Tanous             const std::string& keyType = codes[0];
9102c70f800SEd Tanous             const std::string& valueType = codes[1];
9110bdda665SEd Tanous             const nlohmann::json::object_t* arr =
9120bdda665SEd Tanous                 j->get_ptr<const nlohmann::json::object_t*>();
9130bdda665SEd Tanous             if (arr == nullptr)
9141abe55efSEd Tanous             {
9150bdda665SEd Tanous                 return -1;
9160bdda665SEd Tanous             }
9170bdda665SEd Tanous             for (const auto& it : *arr)
9180bdda665SEd Tanous             {
9190bdda665SEd Tanous                 r = convertJsonToDbus(m, keyType, it.first);
9201abe55efSEd Tanous                 if (r < 0)
9211abe55efSEd Tanous                 {
922d4bb9bbdSEd Tanous                     return r;
92375db20e9SEd Tanous                 }
924d4bb9bbdSEd Tanous 
9250bdda665SEd Tanous                 r = convertJsonToDbus(m, valueType, it.second);
9261abe55efSEd Tanous                 if (r < 0)
9271abe55efSEd Tanous                 {
928d4bb9bbdSEd Tanous                     return r;
929d4bb9bbdSEd Tanous                 }
930d4bb9bbdSEd Tanous             }
931d4bb9bbdSEd Tanous             r = sd_bus_message_close_container(m);
9321abe55efSEd Tanous         }
9331abe55efSEd Tanous         else
9341abe55efSEd Tanous         {
935d4bb9bbdSEd Tanous             return -2;
936d4bb9bbdSEd Tanous         }
9371abe55efSEd Tanous         if (r < 0)
9381abe55efSEd Tanous         {
939d4bb9bbdSEd Tanous             return r;
940d4bb9bbdSEd Tanous         }
941d4bb9bbdSEd Tanous 
9421abe55efSEd Tanous         if (argTypes.size() > 1)
9431abe55efSEd Tanous         {
944d76323e5SEd Tanous             jIt++;
945d4bb9bbdSEd Tanous         }
946d4bb9bbdSEd Tanous     }
947127ea546SMatt Spinler 
948127ea546SMatt Spinler     return r;
949d4bb9bbdSEd Tanous }
950d4bb9bbdSEd Tanous 
951d22a7131SMatt Spinler template <typename T>
readMessageItem(const std::string & typeCode,sdbusplus::message_t & m,nlohmann::json & data)95259d494eeSPatrick Williams int readMessageItem(const std::string& typeCode, sdbusplus::message_t& m,
953d22a7131SMatt Spinler                     nlohmann::json& data)
954d22a7131SMatt Spinler {
955d22a7131SMatt Spinler     T value;
956f79ce6a8SEd Tanous     // When T == char*, this warning fires.  Unclear how to resolve
957f79ce6a8SEd Tanous     // Given that sd-bus takes a void pointer to a char*, and that's
958f79ce6a8SEd Tanous     // Not something we can fix.
959f79ce6a8SEd Tanous     // NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion)
960d22a7131SMatt Spinler     int r = sd_bus_message_read_basic(m.get(), typeCode.front(), &value);
961d22a7131SMatt Spinler     if (r < 0)
962d22a7131SMatt Spinler     {
96362598e31SEd Tanous         BMCWEB_LOG_ERROR("sd_bus_message_read_basic on type {} failed!",
96462598e31SEd Tanous                          typeCode);
965d22a7131SMatt Spinler         return r;
966d22a7131SMatt Spinler     }
967d22a7131SMatt Spinler 
968d22a7131SMatt Spinler     data = value;
969d22a7131SMatt Spinler     return 0;
970d22a7131SMatt Spinler }
971d22a7131SMatt Spinler 
97259d494eeSPatrick Williams int convertDBusToJSON(const std::string& returnType, sdbusplus::message_t& m,
97359d494eeSPatrick Williams                       nlohmann::json& response);
9746df8f990SMatt Spinler 
readDictEntryFromMessage(const std::string & typeCode,sdbusplus::message_t & m,nlohmann::json & object)97523a21a1cSEd Tanous inline int readDictEntryFromMessage(const std::string& typeCode,
97659d494eeSPatrick Williams                                     sdbusplus::message_t& m,
9776df8f990SMatt Spinler                                     nlohmann::json& object)
9786df8f990SMatt Spinler {
9796df8f990SMatt Spinler     std::vector<std::string> types = dbusArgSplit(typeCode);
9806df8f990SMatt Spinler     if (types.size() != 2)
9816df8f990SMatt Spinler     {
98262598e31SEd Tanous         BMCWEB_LOG_ERROR("wrong number contained types in dictionary: {}",
98362598e31SEd Tanous                          types.size());
9846df8f990SMatt Spinler         return -1;
9856df8f990SMatt Spinler     }
9866df8f990SMatt Spinler 
9876df8f990SMatt Spinler     int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_DICT_ENTRY,
9886df8f990SMatt Spinler                                            typeCode.c_str());
9896df8f990SMatt Spinler     if (r < 0)
9906df8f990SMatt Spinler     {
99162598e31SEd Tanous         BMCWEB_LOG_ERROR("sd_bus_message_enter_container with rc {}", r);
9926df8f990SMatt Spinler         return r;
9936df8f990SMatt Spinler     }
9946df8f990SMatt Spinler 
9956df8f990SMatt Spinler     nlohmann::json key;
9966df8f990SMatt Spinler     r = convertDBusToJSON(types[0], m, key);
9976df8f990SMatt Spinler     if (r < 0)
9986df8f990SMatt Spinler     {
9996df8f990SMatt Spinler         return r;
10006df8f990SMatt Spinler     }
10016df8f990SMatt Spinler 
10026df8f990SMatt Spinler     const std::string* keyPtr = key.get_ptr<const std::string*>();
10036df8f990SMatt Spinler     if (keyPtr == nullptr)
10046df8f990SMatt Spinler     {
10056df8f990SMatt Spinler         // json doesn't support non-string keys.  If we hit this condition,
10066df8f990SMatt Spinler         // convert the result to a string so we can proceed
100771f52d96SEd Tanous         key = key.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
10086df8f990SMatt Spinler         keyPtr = key.get_ptr<const std::string*>();
10097c09162aSEd Tanous         // in theory this can't fail now, but lets be paranoid about it
10107c09162aSEd Tanous         // anyway
10116df8f990SMatt Spinler         if (keyPtr == nullptr)
10126df8f990SMatt Spinler         {
10136df8f990SMatt Spinler             return -1;
10146df8f990SMatt Spinler         }
10156df8f990SMatt Spinler     }
10166df8f990SMatt Spinler     nlohmann::json& value = object[*keyPtr];
10176df8f990SMatt Spinler 
10186df8f990SMatt Spinler     r = convertDBusToJSON(types[1], m, value);
10196df8f990SMatt Spinler     if (r < 0)
10206df8f990SMatt Spinler     {
10216df8f990SMatt Spinler         return r;
10226df8f990SMatt Spinler     }
10236df8f990SMatt Spinler 
10246df8f990SMatt Spinler     r = sd_bus_message_exit_container(m.get());
10256df8f990SMatt Spinler     if (r < 0)
10266df8f990SMatt Spinler     {
102762598e31SEd Tanous         BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
10286df8f990SMatt Spinler         return r;
10296df8f990SMatt Spinler     }
10306df8f990SMatt Spinler 
10316df8f990SMatt Spinler     return 0;
10326df8f990SMatt Spinler }
10336df8f990SMatt Spinler 
readArrayFromMessage(const std::string & typeCode,sdbusplus::message_t & m,nlohmann::json & data)103423a21a1cSEd Tanous inline int readArrayFromMessage(const std::string& typeCode,
103559d494eeSPatrick Williams                                 sdbusplus::message_t& m, nlohmann::json& data)
10366df8f990SMatt Spinler {
10376df8f990SMatt Spinler     if (typeCode.size() < 2)
10386df8f990SMatt Spinler     {
103962598e31SEd Tanous         BMCWEB_LOG_ERROR("Type code {} too small for an array", typeCode);
10406df8f990SMatt Spinler         return -1;
10416df8f990SMatt Spinler     }
10426df8f990SMatt Spinler 
10436df8f990SMatt Spinler     std::string containedType = typeCode.substr(1);
10446df8f990SMatt Spinler 
10456df8f990SMatt Spinler     int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_ARRAY,
10466df8f990SMatt Spinler                                            containedType.c_str());
10476df8f990SMatt Spinler     if (r < 0)
10486df8f990SMatt Spinler     {
104962598e31SEd Tanous         BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
10506df8f990SMatt Spinler         return r;
10516df8f990SMatt Spinler     }
10526df8f990SMatt Spinler 
105311ba3979SEd Tanous     bool dict = containedType.starts_with("{") && containedType.ends_with("}");
10546df8f990SMatt Spinler 
10556df8f990SMatt Spinler     if (dict)
10566df8f990SMatt Spinler     {
10576df8f990SMatt Spinler         // Remove the { }
10586df8f990SMatt Spinler         containedType = containedType.substr(1, containedType.size() - 2);
10596df8f990SMatt Spinler         data = nlohmann::json::object();
10606df8f990SMatt Spinler     }
10616df8f990SMatt Spinler     else
10626df8f990SMatt Spinler     {
10636df8f990SMatt Spinler         data = nlohmann::json::array();
10646df8f990SMatt Spinler     }
10656df8f990SMatt Spinler 
10666df8f990SMatt Spinler     while (true)
10676df8f990SMatt Spinler     {
1068e662eae8SEd Tanous         r = sd_bus_message_at_end(m.get(), 0);
10696df8f990SMatt Spinler         if (r < 0)
10706df8f990SMatt Spinler         {
107162598e31SEd Tanous             BMCWEB_LOG_ERROR("sd_bus_message_at_end failed");
10726df8f990SMatt Spinler             return r;
10736df8f990SMatt Spinler         }
10746df8f990SMatt Spinler 
10756df8f990SMatt Spinler         if (r > 0)
10766df8f990SMatt Spinler         {
10776df8f990SMatt Spinler             break;
10786df8f990SMatt Spinler         }
10796df8f990SMatt Spinler 
10806df8f990SMatt Spinler         // Dictionaries are only ever seen in an array
10816df8f990SMatt Spinler         if (dict)
10826df8f990SMatt Spinler         {
10836df8f990SMatt Spinler             r = readDictEntryFromMessage(containedType, m, data);
10846df8f990SMatt Spinler             if (r < 0)
10856df8f990SMatt Spinler             {
10866df8f990SMatt Spinler                 return r;
10876df8f990SMatt Spinler             }
10886df8f990SMatt Spinler         }
10896df8f990SMatt Spinler         else
10906df8f990SMatt Spinler         {
10916df8f990SMatt Spinler             data.push_back(nlohmann::json());
10926df8f990SMatt Spinler 
10936df8f990SMatt Spinler             r = convertDBusToJSON(containedType, m, data.back());
10946df8f990SMatt Spinler             if (r < 0)
10956df8f990SMatt Spinler             {
10966df8f990SMatt Spinler                 return r;
10976df8f990SMatt Spinler             }
10986df8f990SMatt Spinler         }
10996df8f990SMatt Spinler     }
11006df8f990SMatt Spinler 
11016df8f990SMatt Spinler     r = sd_bus_message_exit_container(m.get());
11026df8f990SMatt Spinler     if (r < 0)
11036df8f990SMatt Spinler     {
110462598e31SEd Tanous         BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
11056df8f990SMatt Spinler         return r;
11066df8f990SMatt Spinler     }
11076df8f990SMatt Spinler 
11086df8f990SMatt Spinler     return 0;
11096df8f990SMatt Spinler }
11106df8f990SMatt Spinler 
readStructFromMessage(const std::string & typeCode,sdbusplus::message_t & m,nlohmann::json & data)111123a21a1cSEd Tanous inline int readStructFromMessage(const std::string& typeCode,
111259d494eeSPatrick Williams                                  sdbusplus::message_t& m, nlohmann::json& data)
111375c6c67fSMatt Spinler {
111475c6c67fSMatt Spinler     if (typeCode.size() < 3)
111575c6c67fSMatt Spinler     {
111662598e31SEd Tanous         BMCWEB_LOG_ERROR("Type code {} too small for a struct", typeCode);
111775c6c67fSMatt Spinler         return -1;
111875c6c67fSMatt Spinler     }
111975c6c67fSMatt Spinler 
112075c6c67fSMatt Spinler     std::string containedTypes = typeCode.substr(1, typeCode.size() - 2);
112175c6c67fSMatt Spinler     std::vector<std::string> types = dbusArgSplit(containedTypes);
112275c6c67fSMatt Spinler 
112375c6c67fSMatt Spinler     int r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_STRUCT,
112475c6c67fSMatt Spinler                                            containedTypes.c_str());
112575c6c67fSMatt Spinler     if (r < 0)
112675c6c67fSMatt Spinler     {
112762598e31SEd Tanous         BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
112875c6c67fSMatt Spinler         return r;
112975c6c67fSMatt Spinler     }
113075c6c67fSMatt Spinler 
113175c6c67fSMatt Spinler     for (const std::string& type : types)
113275c6c67fSMatt Spinler     {
113375c6c67fSMatt Spinler         data.push_back(nlohmann::json());
113475c6c67fSMatt Spinler         r = convertDBusToJSON(type, m, data.back());
113575c6c67fSMatt Spinler         if (r < 0)
113675c6c67fSMatt Spinler         {
113775c6c67fSMatt Spinler             return r;
113875c6c67fSMatt Spinler         }
113975c6c67fSMatt Spinler     }
114075c6c67fSMatt Spinler 
114175c6c67fSMatt Spinler     r = sd_bus_message_exit_container(m.get());
114275c6c67fSMatt Spinler     if (r < 0)
114375c6c67fSMatt Spinler     {
114462598e31SEd Tanous         BMCWEB_LOG_ERROR("sd_bus_message_exit_container failed");
114575c6c67fSMatt Spinler         return r;
114675c6c67fSMatt Spinler     }
114775c6c67fSMatt Spinler     return 0;
114875c6c67fSMatt Spinler }
114975c6c67fSMatt Spinler 
readVariantFromMessage(sdbusplus::message_t & m,nlohmann::json & data)115059d494eeSPatrick Williams inline int readVariantFromMessage(sdbusplus::message_t& m, nlohmann::json& data)
115189c1970bSMatt Spinler {
1152543f4400SEd Tanous     const char* containerType = nullptr;
115399131cd0SEd Tanous     int r = sd_bus_message_peek_type(m.get(), nullptr, &containerType);
115489c1970bSMatt Spinler     if (r < 0)
115589c1970bSMatt Spinler     {
115662598e31SEd Tanous         BMCWEB_LOG_ERROR("sd_bus_message_peek_type failed");
115789c1970bSMatt Spinler         return r;
115889c1970bSMatt Spinler     }
115989c1970bSMatt Spinler 
116089c1970bSMatt Spinler     r = sd_bus_message_enter_container(m.get(), SD_BUS_TYPE_VARIANT,
116189c1970bSMatt Spinler                                        containerType);
116289c1970bSMatt Spinler     if (r < 0)
116389c1970bSMatt Spinler     {
116462598e31SEd Tanous         BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed with rc {}", r);
116589c1970bSMatt Spinler         return r;
116689c1970bSMatt Spinler     }
116789c1970bSMatt Spinler 
116889c1970bSMatt Spinler     r = convertDBusToJSON(containerType, m, data);
116989c1970bSMatt Spinler     if (r < 0)
117089c1970bSMatt Spinler     {
117189c1970bSMatt Spinler         return r;
117289c1970bSMatt Spinler     }
117389c1970bSMatt Spinler 
117489c1970bSMatt Spinler     r = sd_bus_message_exit_container(m.get());
117589c1970bSMatt Spinler     if (r < 0)
117689c1970bSMatt Spinler     {
117762598e31SEd Tanous         BMCWEB_LOG_ERROR("sd_bus_message_enter_container failed");
117889c1970bSMatt Spinler         return r;
117989c1970bSMatt Spinler     }
118089c1970bSMatt Spinler 
118189c1970bSMatt Spinler     return 0;
118289c1970bSMatt Spinler }
118389c1970bSMatt Spinler 
convertDBusToJSON(const std::string & returnType,sdbusplus::message_t & m,nlohmann::json & response)118423a21a1cSEd Tanous inline int convertDBusToJSON(const std::string& returnType,
118559d494eeSPatrick Williams                              sdbusplus::message_t& m, nlohmann::json& response)
118616caaee1SMatt Spinler {
1187d22a7131SMatt Spinler     int r = 0;
1188d22a7131SMatt Spinler     const std::vector<std::string> returnTypes = dbusArgSplit(returnType);
1189d22a7131SMatt Spinler 
1190d22a7131SMatt Spinler     for (const std::string& typeCode : returnTypes)
1191d22a7131SMatt Spinler     {
1192f39420c7SMatt Spinler         nlohmann::json* thisElement = &response;
1193f39420c7SMatt Spinler         if (returnTypes.size() > 1)
1194d22a7131SMatt Spinler         {
1195d22a7131SMatt Spinler             response.push_back(nlohmann::json{});
1196f39420c7SMatt Spinler             thisElement = &response.back();
1197d22a7131SMatt Spinler         }
1198d22a7131SMatt Spinler 
1199d4d25793SEd Tanous         if (typeCode == "s" || typeCode == "g" || typeCode == "o")
1200d22a7131SMatt Spinler         {
1201f39420c7SMatt Spinler             r = readMessageItem<char*>(typeCode, m, *thisElement);
1202d22a7131SMatt Spinler             if (r < 0)
1203d22a7131SMatt Spinler             {
1204d22a7131SMatt Spinler                 return r;
1205d22a7131SMatt Spinler             }
1206d22a7131SMatt Spinler         }
1207d22a7131SMatt Spinler         else if (typeCode == "b")
1208d22a7131SMatt Spinler         {
1209f39420c7SMatt Spinler             r = readMessageItem<int>(typeCode, m, *thisElement);
1210d22a7131SMatt Spinler             if (r < 0)
1211d22a7131SMatt Spinler             {
1212d22a7131SMatt Spinler                 return r;
1213d22a7131SMatt Spinler             }
1214d22a7131SMatt Spinler 
1215f39420c7SMatt Spinler             *thisElement = static_cast<bool>(thisElement->get<int>());
1216d22a7131SMatt Spinler         }
1217d22a7131SMatt Spinler         else if (typeCode == "u")
1218d22a7131SMatt Spinler         {
1219f39420c7SMatt Spinler             r = readMessageItem<uint32_t>(typeCode, m, *thisElement);
1220d22a7131SMatt Spinler             if (r < 0)
1221d22a7131SMatt Spinler             {
1222d22a7131SMatt Spinler                 return r;
1223d22a7131SMatt Spinler             }
1224d22a7131SMatt Spinler         }
1225d22a7131SMatt Spinler         else if (typeCode == "i")
1226d22a7131SMatt Spinler         {
1227f39420c7SMatt Spinler             r = readMessageItem<int32_t>(typeCode, m, *thisElement);
1228d22a7131SMatt Spinler             if (r < 0)
1229d22a7131SMatt Spinler             {
1230d22a7131SMatt Spinler                 return r;
1231d22a7131SMatt Spinler             }
1232d22a7131SMatt Spinler         }
1233d22a7131SMatt Spinler         else if (typeCode == "x")
1234d22a7131SMatt Spinler         {
1235f39420c7SMatt Spinler             r = readMessageItem<int64_t>(typeCode, m, *thisElement);
1236d22a7131SMatt Spinler             if (r < 0)
1237d22a7131SMatt Spinler             {
1238d22a7131SMatt Spinler                 return r;
1239d22a7131SMatt Spinler             }
1240d22a7131SMatt Spinler         }
1241d22a7131SMatt Spinler         else if (typeCode == "t")
1242d22a7131SMatt Spinler         {
1243f39420c7SMatt Spinler             r = readMessageItem<uint64_t>(typeCode, m, *thisElement);
1244d22a7131SMatt Spinler             if (r < 0)
1245d22a7131SMatt Spinler             {
1246d22a7131SMatt Spinler                 return r;
1247d22a7131SMatt Spinler             }
1248d22a7131SMatt Spinler         }
1249d22a7131SMatt Spinler         else if (typeCode == "n")
1250d22a7131SMatt Spinler         {
1251f39420c7SMatt Spinler             r = readMessageItem<int16_t>(typeCode, m, *thisElement);
1252d22a7131SMatt Spinler             if (r < 0)
1253d22a7131SMatt Spinler             {
1254d22a7131SMatt Spinler                 return r;
1255d22a7131SMatt Spinler             }
1256d22a7131SMatt Spinler         }
1257d22a7131SMatt Spinler         else if (typeCode == "q")
1258d22a7131SMatt Spinler         {
1259f39420c7SMatt Spinler             r = readMessageItem<uint16_t>(typeCode, m, *thisElement);
1260d22a7131SMatt Spinler             if (r < 0)
1261d22a7131SMatt Spinler             {
1262d22a7131SMatt Spinler                 return r;
1263d22a7131SMatt Spinler             }
1264d22a7131SMatt Spinler         }
1265d22a7131SMatt Spinler         else if (typeCode == "y")
1266d22a7131SMatt Spinler         {
1267f39420c7SMatt Spinler             r = readMessageItem<uint8_t>(typeCode, m, *thisElement);
1268d22a7131SMatt Spinler             if (r < 0)
1269d22a7131SMatt Spinler             {
1270d22a7131SMatt Spinler                 return r;
1271d22a7131SMatt Spinler             }
1272d22a7131SMatt Spinler         }
1273d22a7131SMatt Spinler         else if (typeCode == "d")
1274d22a7131SMatt Spinler         {
1275f39420c7SMatt Spinler             r = readMessageItem<double>(typeCode, m, *thisElement);
1276d22a7131SMatt Spinler             if (r < 0)
1277d22a7131SMatt Spinler             {
1278d22a7131SMatt Spinler                 return r;
1279d22a7131SMatt Spinler             }
1280d22a7131SMatt Spinler         }
1281d22a7131SMatt Spinler         else if (typeCode == "h")
1282d22a7131SMatt Spinler         {
1283f39420c7SMatt Spinler             r = readMessageItem<int>(typeCode, m, *thisElement);
1284d22a7131SMatt Spinler             if (r < 0)
1285d22a7131SMatt Spinler             {
1286d22a7131SMatt Spinler                 return r;
1287d22a7131SMatt Spinler             }
1288d22a7131SMatt Spinler         }
128911ba3979SEd Tanous         else if (typeCode.starts_with("a"))
12906df8f990SMatt Spinler         {
1291f39420c7SMatt Spinler             r = readArrayFromMessage(typeCode, m, *thisElement);
12926df8f990SMatt Spinler             if (r < 0)
12936df8f990SMatt Spinler             {
12946df8f990SMatt Spinler                 return r;
12956df8f990SMatt Spinler             }
12966df8f990SMatt Spinler         }
129711ba3979SEd Tanous         else if (typeCode.starts_with("(") && typeCode.ends_with(")"))
129875c6c67fSMatt Spinler         {
1299f39420c7SMatt Spinler             r = readStructFromMessage(typeCode, m, *thisElement);
130075c6c67fSMatt Spinler             if (r < 0)
130175c6c67fSMatt Spinler             {
130275c6c67fSMatt Spinler                 return r;
130375c6c67fSMatt Spinler             }
130475c6c67fSMatt Spinler         }
130511ba3979SEd Tanous         else if (typeCode.starts_with("v"))
130689c1970bSMatt Spinler         {
1307f39420c7SMatt Spinler             r = readVariantFromMessage(m, *thisElement);
130889c1970bSMatt Spinler             if (r < 0)
130989c1970bSMatt Spinler             {
131089c1970bSMatt Spinler                 return r;
131189c1970bSMatt Spinler             }
131289c1970bSMatt Spinler         }
1313d22a7131SMatt Spinler         else
1314d22a7131SMatt Spinler         {
131562598e31SEd Tanous             BMCWEB_LOG_ERROR("Invalid D-Bus signature type {}", typeCode);
1316d22a7131SMatt Spinler             return -2;
1317d22a7131SMatt Spinler         }
1318d22a7131SMatt Spinler     }
1319d22a7131SMatt Spinler 
132016caaee1SMatt Spinler     return 0;
132116caaee1SMatt Spinler }
132216caaee1SMatt Spinler 
handleMethodResponse(const std::shared_ptr<InProgressActionData> & transaction,sdbusplus::message_t & m,const std::string & returnType)1323b5a76932SEd Tanous inline void handleMethodResponse(
1324b5a76932SEd Tanous     const std::shared_ptr<InProgressActionData>& transaction,
132559d494eeSPatrick Williams     sdbusplus::message_t& m, const std::string& returnType)
132616caaee1SMatt Spinler {
132739a4e39fSMatt Spinler     nlohmann::json data;
132839a4e39fSMatt Spinler 
132939a4e39fSMatt Spinler     int r = convertDBusToJSON(returnType, m, data);
133039a4e39fSMatt Spinler     if (r < 0)
133139a4e39fSMatt Spinler     {
133239a4e39fSMatt Spinler         transaction->outputFailed = true;
133339a4e39fSMatt Spinler         return;
133439a4e39fSMatt Spinler     }
133539a4e39fSMatt Spinler 
133639a4e39fSMatt Spinler     if (data.is_null())
133739a4e39fSMatt Spinler     {
133839a4e39fSMatt Spinler         return;
133939a4e39fSMatt Spinler     }
134039a4e39fSMatt Spinler 
134139a4e39fSMatt Spinler     if (transaction->methodResponse.is_null())
134239a4e39fSMatt Spinler     {
134339a4e39fSMatt Spinler         transaction->methodResponse = std::move(data);
134439a4e39fSMatt Spinler         return;
134539a4e39fSMatt Spinler     }
134639a4e39fSMatt Spinler 
134739a4e39fSMatt Spinler     // If they're both dictionaries or arrays, merge into one.
134839a4e39fSMatt Spinler     // Otherwise, make the results an array with every result
134939a4e39fSMatt Spinler     // an entry.  Could also just fail in that case, but it
135039a4e39fSMatt Spinler     // seems better to get the data back somehow.
13510bdda665SEd Tanous     nlohmann::json::object_t* dataobj =
13520bdda665SEd Tanous         data.get_ptr<nlohmann::json::object_t*>();
13530bdda665SEd Tanous     if (transaction->methodResponse.is_object() && dataobj != nullptr)
135439a4e39fSMatt Spinler     {
13550bdda665SEd Tanous         for (auto& obj : *dataobj)
135639a4e39fSMatt Spinler         {
135739a4e39fSMatt Spinler             // Note: Will overwrite the data for a duplicate key
13580bdda665SEd Tanous             transaction->methodResponse.emplace(obj.first,
13590bdda665SEd Tanous                                                 std::move(obj.second));
136039a4e39fSMatt Spinler         }
136139a4e39fSMatt Spinler         return;
136239a4e39fSMatt Spinler     }
136339a4e39fSMatt Spinler 
13640bdda665SEd Tanous     nlohmann::json::array_t* dataarr = data.get_ptr<nlohmann::json::array_t*>();
13650bdda665SEd Tanous     if (transaction->methodResponse.is_array() && dataarr != nullptr)
136639a4e39fSMatt Spinler     {
13670bdda665SEd Tanous         for (auto& obj : *dataarr)
136839a4e39fSMatt Spinler         {
1369b2ba3072SPatrick Williams             transaction->methodResponse.emplace_back(std::move(obj));
137039a4e39fSMatt Spinler         }
137139a4e39fSMatt Spinler         return;
137239a4e39fSMatt Spinler     }
137339a4e39fSMatt Spinler 
137439a4e39fSMatt Spinler     if (!transaction->convertedToArray)
137539a4e39fSMatt Spinler     {
137639a4e39fSMatt Spinler         // They are different types. May as well turn them into an array
137739a4e39fSMatt Spinler         nlohmann::json j = std::move(transaction->methodResponse);
137839a4e39fSMatt Spinler         transaction->methodResponse = nlohmann::json::array();
1379b2ba3072SPatrick Williams         transaction->methodResponse.emplace_back(std::move(j));
1380b2ba3072SPatrick Williams         transaction->methodResponse.emplace_back(std::move(data));
138139a4e39fSMatt Spinler         transaction->convertedToArray = true;
138239a4e39fSMatt Spinler     }
138339a4e39fSMatt Spinler     else
138439a4e39fSMatt Spinler     {
1385b2ba3072SPatrick Williams         transaction->methodResponse.emplace_back(std::move(data));
138639a4e39fSMatt Spinler     }
138716caaee1SMatt Spinler }
138816caaee1SMatt Spinler 
findActionOnInterface(const std::shared_ptr<InProgressActionData> & transaction,const std::string & connectionName)1389b5a76932SEd Tanous inline void findActionOnInterface(
1390b5a76932SEd Tanous     const std::shared_ptr<InProgressActionData>& transaction,
13911abe55efSEd Tanous     const std::string& connectionName)
13921abe55efSEd Tanous {
139362598e31SEd Tanous     BMCWEB_LOG_DEBUG("findActionOnInterface for connection {}", connectionName);
139455c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
13951abe55efSEd Tanous         [transaction, connectionName{std::string(connectionName)}](
13965e7e2dc5SEd Tanous             const boost::system::error_code& ec,
139781ce609eSEd Tanous             const std::string& introspectXml) {
139862598e31SEd Tanous             BMCWEB_LOG_DEBUG("got xml:\n {}", introspectXml);
13991abe55efSEd Tanous             if (ec)
14001abe55efSEd Tanous             {
140162598e31SEd Tanous                 BMCWEB_LOG_ERROR(
140262598e31SEd Tanous                     "Introspect call failed with error: {} on process: {}",
140362598e31SEd Tanous                     ec.message(), connectionName);
1404318bd892SMatt Spinler                 return;
14051abe55efSEd Tanous             }
1406d4bb9bbdSEd Tanous             tinyxml2::XMLDocument doc;
1407d4bb9bbdSEd Tanous 
140881ce609eSEd Tanous             doc.Parse(introspectXml.data(), introspectXml.size());
1409d4bb9bbdSEd Tanous             tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
14101abe55efSEd Tanous             if (pRoot == nullptr)
14111abe55efSEd Tanous             {
1412bd79bce8SPatrick Williams                 BMCWEB_LOG_ERROR("XML document failed to parse {}",
1413bd79bce8SPatrick Williams                                  connectionName);
1414e3cb5a31SEd Tanous                 return;
14151abe55efSEd Tanous             }
1416e3cb5a31SEd Tanous             tinyxml2::XMLElement* interfaceNode =
1417d4bb9bbdSEd Tanous                 pRoot->FirstChildElement("interface");
1418e3cb5a31SEd Tanous             while (interfaceNode != nullptr)
14191abe55efSEd Tanous             {
1420bd79bce8SPatrick Williams                 const char* thisInterfaceName =
1421bd79bce8SPatrick Williams                     interfaceNode->Attribute("name");
1422e3cb5a31SEd Tanous                 if (thisInterfaceName != nullptr)
14231abe55efSEd Tanous                 {
1424de81881fSMatt Spinler                     if (!transaction->interfaceName.empty() &&
1425de81881fSMatt Spinler                         (transaction->interfaceName != thisInterfaceName))
1426de81881fSMatt Spinler                     {
1427de81881fSMatt Spinler                         interfaceNode =
1428de81881fSMatt Spinler                             interfaceNode->NextSiblingElement("interface");
1429de81881fSMatt Spinler                         continue;
1430de81881fSMatt Spinler                     }
1431de81881fSMatt Spinler 
1432e3cb5a31SEd Tanous                     tinyxml2::XMLElement* methodNode =
1433e3cb5a31SEd Tanous                         interfaceNode->FirstChildElement("method");
1434e3cb5a31SEd Tanous                     while (methodNode != nullptr)
1435e3cb5a31SEd Tanous                     {
1436bd79bce8SPatrick Williams                         const char* thisMethodName =
1437bd79bce8SPatrick Williams                             methodNode->Attribute("name");
143862598e31SEd Tanous                         BMCWEB_LOG_DEBUG("Found method: {}", thisMethodName);
1439e3cb5a31SEd Tanous                         if (thisMethodName != nullptr &&
1440e3cb5a31SEd Tanous                             thisMethodName == transaction->methodName)
14411abe55efSEd Tanous                         {
144262598e31SEd Tanous                             BMCWEB_LOG_DEBUG(
144362598e31SEd Tanous                                 "Found method named {} on interface {}",
144462598e31SEd Tanous                                 thisMethodName, thisInterfaceName);
144559d494eeSPatrick Williams                             sdbusplus::message_t m =
1446318bd892SMatt Spinler                                 crow::connections::systemBus->new_method_call(
14471abe55efSEd Tanous                                     connectionName.c_str(),
1448bd79bce8SPatrick Williams                                     transaction->path.c_str(),
1449bd79bce8SPatrick Williams                                     thisInterfaceName,
1450d76323e5SEd Tanous                                     transaction->methodName.c_str());
1451d4bb9bbdSEd Tanous 
1452e3cb5a31SEd Tanous                             tinyxml2::XMLElement* argumentNode =
1453e3cb5a31SEd Tanous                                 methodNode->FirstChildElement("arg");
1454d4bb9bbdSEd Tanous 
145516caaee1SMatt Spinler                             std::string returnType;
145616caaee1SMatt Spinler 
145716caaee1SMatt Spinler                             // Find the output type
145816caaee1SMatt Spinler                             while (argumentNode != nullptr)
145916caaee1SMatt Spinler                             {
146016caaee1SMatt Spinler                                 const char* argDirection =
146116caaee1SMatt Spinler                                     argumentNode->Attribute("direction");
146216caaee1SMatt Spinler                                 const char* argType =
146316caaee1SMatt Spinler                                     argumentNode->Attribute("type");
1464bd79bce8SPatrick Williams                                 if (argDirection != nullptr &&
1465bd79bce8SPatrick Williams                                     argType != nullptr &&
146616caaee1SMatt Spinler                                     std::string(argDirection) == "out")
146716caaee1SMatt Spinler                                 {
146816caaee1SMatt Spinler                                     returnType = argType;
146916caaee1SMatt Spinler                                     break;
147016caaee1SMatt Spinler                                 }
147116caaee1SMatt Spinler                                 argumentNode =
147216caaee1SMatt Spinler                                     argumentNode->NextSiblingElement("arg");
147316caaee1SMatt Spinler                             }
147416caaee1SMatt Spinler 
1475b2ec0ce5SNan Zhou                             auto argIt = transaction->arguments.begin();
1476d4bb9bbdSEd Tanous 
147716caaee1SMatt Spinler                             argumentNode = methodNode->FirstChildElement("arg");
147816caaee1SMatt Spinler 
1479e3cb5a31SEd Tanous                             while (argumentNode != nullptr)
14801abe55efSEd Tanous                             {
1481e3cb5a31SEd Tanous                                 const char* argDirection =
1482e3cb5a31SEd Tanous                                     argumentNode->Attribute("direction");
1483e3cb5a31SEd Tanous                                 const char* argType =
1484e3cb5a31SEd Tanous                                     argumentNode->Attribute("type");
1485bd79bce8SPatrick Williams                                 if (argDirection != nullptr &&
1486bd79bce8SPatrick Williams                                     argType != nullptr &&
1487e3cb5a31SEd Tanous                                     std::string(argDirection) == "in")
14881abe55efSEd Tanous                                 {
1489318bd892SMatt Spinler                                     if (argIt == transaction->arguments.end())
14901abe55efSEd Tanous                                     {
14916db06242SMatt Spinler                                         transaction->setErrorStatus(
14926db06242SMatt Spinler                                             "Invalid method args");
1493d4bb9bbdSEd Tanous                                         return;
1494d4bb9bbdSEd Tanous                                     }
1495318bd892SMatt Spinler                                     if (convertJsonToDbus(m.get(),
1496318bd892SMatt Spinler                                                           std::string(argType),
1497e3cb5a31SEd Tanous                                                           *argIt) < 0)
14981abe55efSEd Tanous                                     {
14996db06242SMatt Spinler                                         transaction->setErrorStatus(
15006db06242SMatt Spinler                                             "Invalid method arg type");
1501d4bb9bbdSEd Tanous                                         return;
1502d4bb9bbdSEd Tanous                                     }
1503d4bb9bbdSEd Tanous 
1504e3cb5a31SEd Tanous                                     argIt++;
1505d4bb9bbdSEd Tanous                                 }
1506e3cb5a31SEd Tanous                                 argumentNode =
15074d72dcc3SAppaRao Puli                                     argumentNode->NextSiblingElement("arg");
1508d4bb9bbdSEd Tanous                             }
1509e3cb5a31SEd Tanous 
151055c7b7a2SEd Tanous                             crow::connections::systemBus->async_send(
15115a39f77aSPatrick Williams                                 m, [transaction, returnType](
15125a39f77aSPatrick Williams                                        const boost::system::error_code& ec2,
151359d494eeSPatrick Williams                                        sdbusplus::message_t& m2) {
151423a21a1cSEd Tanous                                     if (ec2)
15151abe55efSEd Tanous                                     {
151616caaee1SMatt Spinler                                         transaction->methodFailed = true;
151723a21a1cSEd Tanous                                         const sd_bus_error* e = m2.get_error();
151806b1b63cSMatt Spinler 
1519e662eae8SEd Tanous                                         if (e != nullptr)
152006b1b63cSMatt Spinler                                         {
152106b1b63cSMatt Spinler                                             setErrorResponse(
152228dd5ca1SLei YU                                                 transaction->asyncResp->res,
1523bd79bce8SPatrick Williams                                                 boost::beast::http::status::
1524bd79bce8SPatrick Williams                                                     bad_request,
152506b1b63cSMatt Spinler                                                 e->name, e->message);
152606b1b63cSMatt Spinler                                         }
152706b1b63cSMatt Spinler                                         else
152806b1b63cSMatt Spinler                                         {
152906b1b63cSMatt Spinler                                             setErrorResponse(
153028dd5ca1SLei YU                                                 transaction->asyncResp->res,
1531bd79bce8SPatrick Williams                                                 boost::beast::http::status::
1532bd79bce8SPatrick Williams                                                     bad_request,
1533bd79bce8SPatrick Williams                                                 "Method call failed",
1534bd79bce8SPatrick Williams                                                 methodFailedMsg);
153506b1b63cSMatt Spinler                                         }
1536d4bb9bbdSEd Tanous                                         return;
1537d4bb9bbdSEd Tanous                                     }
153816caaee1SMatt Spinler                                     transaction->methodPassed = true;
153916caaee1SMatt Spinler 
1540bd79bce8SPatrick Williams                                     handleMethodResponse(transaction, m2,
1541bd79bce8SPatrick Williams                                                          returnType);
1542d4bb9bbdSEd Tanous                                 });
1543d4bb9bbdSEd Tanous                             break;
1544d4bb9bbdSEd Tanous                         }
1545318bd892SMatt Spinler                         methodNode = methodNode->NextSiblingElement("method");
1546d4bb9bbdSEd Tanous                     }
1547d4bb9bbdSEd Tanous                 }
1548318bd892SMatt Spinler                 interfaceNode = interfaceNode->NextSiblingElement("interface");
1549d4bb9bbdSEd Tanous             }
1550d4bb9bbdSEd Tanous         },
15511abe55efSEd Tanous         connectionName, transaction->path,
15521abe55efSEd Tanous         "org.freedesktop.DBus.Introspectable", "Introspect");
1553d4bb9bbdSEd Tanous }
1554d4bb9bbdSEd Tanous 
handleAction(const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & objectPath,const std::string & methodName)15558d1b46d7Szhanghch05 inline void handleAction(const crow::Request& req,
15568d1b46d7Szhanghch05                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
155723a21a1cSEd Tanous                          const std::string& objectPath,
155823a21a1cSEd Tanous                          const std::string& methodName)
15591abe55efSEd Tanous {
156062598e31SEd Tanous     BMCWEB_LOG_DEBUG("handleAction on path: {} and method {}", objectPath,
156162598e31SEd Tanous                      methodName);
15621aa0c2b8SEd Tanous     nlohmann::json requestDbusData;
1563d4bb9bbdSEd Tanous 
15641aa0c2b8SEd Tanous     JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
15651aa0c2b8SEd Tanous     if (ret == JsonParseResult::BadContentType)
15661aa0c2b8SEd Tanous     {
15671aa0c2b8SEd Tanous         setErrorResponse(asyncResp->res,
15681aa0c2b8SEd Tanous                          boost::beast::http::status::unsupported_media_type,
15691aa0c2b8SEd Tanous                          invalidContentType, unsupportedMediaMsg);
15701aa0c2b8SEd Tanous         return;
15711aa0c2b8SEd Tanous     }
15721aa0c2b8SEd Tanous     if (ret != JsonParseResult::Success)
15731abe55efSEd Tanous     {
15748d1b46d7Szhanghch05         setErrorResponse(asyncResp->res,
15758d1b46d7Szhanghch05                          boost::beast::http::status::bad_request, noJsonDesc,
15768d1b46d7Szhanghch05                          badReqMsg);
1577d4bb9bbdSEd Tanous         return;
1578d4bb9bbdSEd Tanous     }
1579e3cb5a31SEd Tanous     nlohmann::json::iterator data = requestDbusData.find("data");
1580e3cb5a31SEd Tanous     if (data == requestDbusData.end())
1581e3cb5a31SEd Tanous     {
15828d1b46d7Szhanghch05         setErrorResponse(asyncResp->res,
15838d1b46d7Szhanghch05                          boost::beast::http::status::bad_request, noJsonDesc,
15848d1b46d7Szhanghch05                          badReqMsg);
1585e3cb5a31SEd Tanous         return;
1586e3cb5a31SEd Tanous     }
1587e3cb5a31SEd Tanous 
1588e3cb5a31SEd Tanous     if (!data->is_array())
15891abe55efSEd Tanous     {
15908d1b46d7Szhanghch05         setErrorResponse(asyncResp->res,
15918d1b46d7Szhanghch05                          boost::beast::http::status::bad_request, noJsonDesc,
15928d1b46d7Szhanghch05                          badReqMsg);
1593d4bb9bbdSEd Tanous         return;
1594d4bb9bbdSEd Tanous     }
159528dd5ca1SLei YU     auto transaction = std::make_shared<InProgressActionData>(asyncResp);
1596d4bb9bbdSEd Tanous 
1597d76323e5SEd Tanous     transaction->path = objectPath;
1598d76323e5SEd Tanous     transaction->methodName = methodName;
1599e3cb5a31SEd Tanous     transaction->arguments = std::move(*data);
16002b73119cSGeorge Liu     dbus::utility::getDbusObject(
16012b73119cSGeorge Liu         objectPath, {},
1602d4bb9bbdSEd Tanous         [transaction](
16032b73119cSGeorge Liu             const boost::system::error_code& ec,
16041214b7e7SGunnar Mills             const std::vector<std::pair<std::string, std::vector<std::string>>>&
16051214b7e7SGunnar Mills                 interfaceNames) {
160626f6976fSEd Tanous             if (ec || interfaceNames.empty())
16071abe55efSEd Tanous             {
160862598e31SEd Tanous                 BMCWEB_LOG_ERROR("Can't find object");
160928dd5ca1SLei YU                 setErrorResponse(transaction->asyncResp->res,
16106db06242SMatt Spinler                                  boost::beast::http::status::not_found,
16116db06242SMatt Spinler                                  notFoundDesc, notFoundMsg);
1612d4bb9bbdSEd Tanous                 return;
1613d4bb9bbdSEd Tanous             }
1614d4bb9bbdSEd Tanous 
161562598e31SEd Tanous             BMCWEB_LOG_DEBUG("GetObject returned {} object(s)",
161662598e31SEd Tanous                              interfaceNames.size());
1617d4bb9bbdSEd Tanous 
1618bd79bce8SPatrick Williams             for (const std::pair<std::string, std::vector<std::string>>&
1619bd79bce8SPatrick Williams                      object : interfaceNames)
16201abe55efSEd Tanous             {
1621d76323e5SEd Tanous                 findActionOnInterface(transaction, object.first);
1622d4bb9bbdSEd Tanous             }
16232b73119cSGeorge Liu         });
1624d4bb9bbdSEd Tanous }
1625d4bb9bbdSEd Tanous 
handleDelete(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & objectPath)16268d1b46d7Szhanghch05 inline void handleDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
16278d1b46d7Szhanghch05                          const std::string& objectPath)
1628de81881fSMatt Spinler {
162962598e31SEd Tanous     BMCWEB_LOG_DEBUG("handleDelete on path: {}", objectPath);
1630de81881fSMatt Spinler 
16312b73119cSGeorge Liu     dbus::utility::getDbusObject(
16322b73119cSGeorge Liu         objectPath, {},
16338d1b46d7Szhanghch05         [asyncResp, objectPath](
16342b73119cSGeorge Liu             const boost::system::error_code& ec,
16351214b7e7SGunnar Mills             const std::vector<std::pair<std::string, std::vector<std::string>>>&
16361214b7e7SGunnar Mills                 interfaceNames) {
163726f6976fSEd Tanous             if (ec || interfaceNames.empty())
1638de81881fSMatt Spinler             {
163962598e31SEd Tanous                 BMCWEB_LOG_ERROR("Can't find object");
16408d1b46d7Szhanghch05                 setErrorResponse(asyncResp->res,
164162d2e8b6SMatt Spinler                                  boost::beast::http::status::method_not_allowed,
164262d2e8b6SMatt Spinler                                  methodNotAllowedDesc, methodNotAllowedMsg);
1643de81881fSMatt Spinler                 return;
1644de81881fSMatt Spinler             }
1645de81881fSMatt Spinler 
1646bd79bce8SPatrick Williams             auto transaction =
1647bd79bce8SPatrick Williams                 std::make_shared<InProgressActionData>(asyncResp);
1648de81881fSMatt Spinler             transaction->path = objectPath;
1649de81881fSMatt Spinler             transaction->methodName = "Delete";
1650de81881fSMatt Spinler             transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
1651de81881fSMatt Spinler 
1652bd79bce8SPatrick Williams             for (const std::pair<std::string, std::vector<std::string>>&
1653bd79bce8SPatrick Williams                      object : interfaceNames)
1654de81881fSMatt Spinler             {
1655de81881fSMatt Spinler                 findActionOnInterface(transaction, object.first);
1656de81881fSMatt Spinler             }
16572b73119cSGeorge Liu         });
1658de81881fSMatt Spinler }
1659de81881fSMatt Spinler 
handleList(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & objectPath,int32_t depth=0)16608d1b46d7Szhanghch05 inline void handleList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
16618d1b46d7Szhanghch05                        const std::string& objectPath, int32_t depth = 0)
16621abe55efSEd Tanous {
16637a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
16647a1dbc48SGeorge Liu         objectPath, depth, {},
1665b9d36b47SEd Tanous         [asyncResp](
16667a1dbc48SGeorge Liu             const boost::system::error_code& ec,
1667b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreePathsResponse& objectPaths) {
16681abe55efSEd Tanous             if (ec)
16691abe55efSEd Tanous             {
16708d1b46d7Szhanghch05                 setErrorResponse(asyncResp->res,
16718d1b46d7Szhanghch05                                  boost::beast::http::status::not_found,
1672d6091dddSMatt Spinler                                  notFoundDesc, notFoundMsg);
16731abe55efSEd Tanous             }
16741abe55efSEd Tanous             else
16751abe55efSEd Tanous             {
16761476687dSEd Tanous                 asyncResp->res.jsonValue["status"] = "ok";
16771476687dSEd Tanous                 asyncResp->res.jsonValue["message"] = "200 OK";
16781476687dSEd Tanous                 asyncResp->res.jsonValue["data"] = objectPaths;
1679d4bb9bbdSEd Tanous             }
16807a1dbc48SGeorge Liu         });
1681d4bb9bbdSEd Tanous }
1682d4bb9bbdSEd Tanous 
handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & objectPath)16838d1b46d7Szhanghch05 inline void handleEnumerate(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
16848d1b46d7Szhanghch05                             const std::string& objectPath)
16851abe55efSEd Tanous {
168662598e31SEd Tanous     BMCWEB_LOG_DEBUG("Doing enumerate on {}", objectPath);
1687049a0515SEd Tanous 
16881476687dSEd Tanous     asyncResp->res.jsonValue["message"] = "200 OK";
16891476687dSEd Tanous     asyncResp->res.jsonValue["status"] = "ok";
16901476687dSEd Tanous     asyncResp->res.jsonValue["data"] = nlohmann::json::object();
1691d4bb9bbdSEd Tanous 
1692e99073f5SGeorge Liu     dbus::utility::getSubTree(
1693e99073f5SGeorge Liu         objectPath, 0, {},
1694b9d36b47SEd Tanous         [objectPath, asyncResp](
1695e99073f5SGeorge Liu             const boost::system::error_code& ec,
1696b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreeResponse& objectNames) {
1697bd79bce8SPatrick Williams             auto transaction = std::make_shared<InProgressEnumerateData>(
1698bd79bce8SPatrick Williams                 objectPath, asyncResp);
16993ae4ba7bSMatt Spinler 
17003ae4ba7bSMatt Spinler             transaction->subtree =
1701b9d36b47SEd Tanous                 std::make_shared<dbus::utility::MapperGetSubTreeResponse>(
1702b9d36b47SEd Tanous                     objectNames);
17033ae4ba7bSMatt Spinler 
1704049a0515SEd Tanous             if (ec)
1705049a0515SEd Tanous             {
170662598e31SEd Tanous                 BMCWEB_LOG_ERROR("GetSubTree failed on {}",
170762598e31SEd Tanous                                  transaction->objectPath);
17082ae60096SMatt Spinler                 setErrorResponse(transaction->asyncResp->res,
17092ae60096SMatt Spinler                                  boost::beast::http::status::not_found,
17102ae60096SMatt Spinler                                  notFoundDesc, notFoundMsg);
171164530018SEd Tanous                 return;
171264530018SEd Tanous             }
171364530018SEd Tanous 
17143ae4ba7bSMatt Spinler             // Add the data for the path passed in to the results
17153ae4ba7bSMatt Spinler             // as if GetSubTree returned it, and continue on enumerating
17163ae4ba7bSMatt Spinler             getObjectAndEnumerate(transaction);
1717e99073f5SGeorge Liu         });
171864530018SEd Tanous }
1719911ac317SEd Tanous 
handleGet(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,std::string & objectPath,std::string & destProperty)17208d1b46d7Szhanghch05 inline void handleGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
17218d1b46d7Szhanghch05                       std::string& objectPath, std::string& destProperty)
17221abe55efSEd Tanous {
172362598e31SEd Tanous     BMCWEB_LOG_DEBUG("handleGet: {} prop:{}", objectPath, destProperty);
1724e3cb5a31SEd Tanous     std::shared_ptr<std::string> propertyName =
1725d76323e5SEd Tanous         std::make_shared<std::string>(std::move(destProperty));
172675db20e9SEd Tanous 
172775db20e9SEd Tanous     std::shared_ptr<std::string> path =
1728d76323e5SEd Tanous         std::make_shared<std::string>(std::move(objectPath));
172975db20e9SEd Tanous 
17302b73119cSGeorge Liu     dbus::utility::getDbusObject(
17312b73119cSGeorge Liu         *path, {},
1732b9d36b47SEd Tanous         [asyncResp, path,
17332b73119cSGeorge Liu          propertyName](const boost::system::error_code& ec,
1734b9d36b47SEd Tanous                        const dbus::utility::MapperGetObject& objectNames) {
173526f6976fSEd Tanous             if (ec || objectNames.empty())
17361abe55efSEd Tanous             {
17378d1b46d7Szhanghch05                 setErrorResponse(asyncResp->res,
17388d1b46d7Szhanghch05                                  boost::beast::http::status::not_found,
1739dc2f9f11SMatt Spinler                                  notFoundDesc, notFoundMsg);
1740d4bb9bbdSEd Tanous                 return;
1741d4bb9bbdSEd Tanous             }
1742d4bb9bbdSEd Tanous             std::shared_ptr<nlohmann::json> response =
1743d4bb9bbdSEd Tanous                 std::make_shared<nlohmann::json>(nlohmann::json::object());
17447c09162aSEd Tanous             // The mapper should never give us an empty interface names
17457c09162aSEd Tanous             // list, but check anyway
174623a21a1cSEd Tanous             for (const std::pair<std::string, std::vector<std::string>>&
174781ce609eSEd Tanous                      connection : objectNames)
17481abe55efSEd Tanous             {
1749bd79bce8SPatrick Williams                 const std::vector<std::string>& interfaceNames =
1750bd79bce8SPatrick Williams                     connection.second;
1751d4bb9bbdSEd Tanous 
175226f6976fSEd Tanous                 if (interfaceNames.empty())
17531abe55efSEd Tanous                 {
17548d1b46d7Szhanghch05                     setErrorResponse(asyncResp->res,
17558d1b46d7Szhanghch05                                      boost::beast::http::status::not_found,
1756dc2f9f11SMatt Spinler                                      notFoundDesc, notFoundMsg);
1757d4bb9bbdSEd Tanous                     return;
1758d4bb9bbdSEd Tanous                 }
1759d4bb9bbdSEd Tanous 
17601abe55efSEd Tanous                 for (const std::string& interface : interfaceNames)
17611abe55efSEd Tanous                 {
176259d494eeSPatrick Williams                     sdbusplus::message_t m =
1763fe7e97d3SMatt Spinler                         crow::connections::systemBus->new_method_call(
1764fe7e97d3SMatt Spinler                             connection.first.c_str(), path->c_str(),
1765fe7e97d3SMatt Spinler                             "org.freedesktop.DBus.Properties", "GetAll");
1766fe7e97d3SMatt Spinler                     m.append(interface);
1767fe7e97d3SMatt Spinler                     crow::connections::systemBus->async_send(
17688d1b46d7Szhanghch05                         m, [asyncResp, response,
17695e7e2dc5SEd Tanous                             propertyName](const boost::system::error_code& ec2,
177059d494eeSPatrick Williams                                           sdbusplus::message_t& msg) {
177123a21a1cSEd Tanous                             if (ec2)
17721abe55efSEd Tanous                             {
1773bd79bce8SPatrick Williams                                 BMCWEB_LOG_ERROR("Bad dbus request error: {}",
1774bd79bce8SPatrick Williams                                                  ec2);
17751abe55efSEd Tanous                             }
1776984a4c2bSEd Tanous                             else
1777984a4c2bSEd Tanous                             {
1778fe7e97d3SMatt Spinler                                 nlohmann::json properties;
1779bd79bce8SPatrick Williams                                 int r =
1780bd79bce8SPatrick Williams                                     convertDBusToJSON("a{sv}", msg, properties);
1781fe7e97d3SMatt Spinler                                 if (r < 0)
17821abe55efSEd Tanous                                 {
1783bd79bce8SPatrick Williams                                     BMCWEB_LOG_ERROR(
1784bd79bce8SPatrick Williams                                         "convertDBusToJSON failed");
1785fe7e97d3SMatt Spinler                                 }
1786fe7e97d3SMatt Spinler                                 else
1787fe7e97d3SMatt Spinler                                 {
17880bdda665SEd Tanous                                     nlohmann::json::object_t* obj =
1789bd79bce8SPatrick Williams                                         properties.get_ptr<
1790bd79bce8SPatrick Williams                                             nlohmann::json::object_t*>();
17910bdda665SEd Tanous                                     if (obj == nullptr)
17920bdda665SEd Tanous                                     {
17930bdda665SEd Tanous                                         return;
17940bdda665SEd Tanous                                     }
17950bdda665SEd Tanous                                     for (auto& prop : *obj)
1796fe7e97d3SMatt Spinler                                     {
17977c09162aSEd Tanous                                         // if property name is empty, or
17987c09162aSEd Tanous                                         // matches our search query, add it
17997c09162aSEd Tanous                                         // to the response json
1800d4bb9bbdSEd Tanous 
1801e3cb5a31SEd Tanous                                         if (propertyName->empty())
18021abe55efSEd Tanous                                         {
18030bdda665SEd Tanous                                             (*response)[prop.first] =
18040bdda665SEd Tanous                                                 std::move(prop.second);
18051abe55efSEd Tanous                                         }
18060bdda665SEd Tanous                                         else if (prop.first == *propertyName)
18071abe55efSEd Tanous                                         {
18080bdda665SEd Tanous                                             *response = std::move(prop.second);
1809fe7e97d3SMatt Spinler                                         }
1810d4bb9bbdSEd Tanous                                     }
1811d4bb9bbdSEd Tanous                                 }
1812984a4c2bSEd Tanous                             }
18131abe55efSEd Tanous                             if (response.use_count() == 1)
18141abe55efSEd Tanous                             {
1815dc2f9f11SMatt Spinler                                 if (!propertyName->empty() && response->empty())
1816dc2f9f11SMatt Spinler                                 {
1817dc2f9f11SMatt Spinler                                     setErrorResponse(
18188d1b46d7Szhanghch05                                         asyncResp->res,
1819dc2f9f11SMatt Spinler                                         boost::beast::http::status::not_found,
1820dc2f9f11SMatt Spinler                                         propNotFoundDesc, notFoundMsg);
1821dc2f9f11SMatt Spinler                                 }
1822dc2f9f11SMatt Spinler                                 else
1823dc2f9f11SMatt Spinler                                 {
18241476687dSEd Tanous                                     asyncResp->res.jsonValue["status"] = "ok";
1825bd79bce8SPatrick Williams                                     asyncResp->res.jsonValue["message"] =
1826bd79bce8SPatrick Williams                                         "200 OK";
1827bd79bce8SPatrick Williams                                     asyncResp->res.jsonValue["data"] =
1828bd79bce8SPatrick Williams                                         *response;
1829dc2f9f11SMatt Spinler                                 }
1830d4bb9bbdSEd Tanous                             }
1831fe7e97d3SMatt Spinler                         });
1832d4bb9bbdSEd Tanous                 }
1833d4bb9bbdSEd Tanous             }
18342b73119cSGeorge Liu         });
1835d4bb9bbdSEd Tanous }
1836d4bb9bbdSEd Tanous 
18371abe55efSEd Tanous struct AsyncPutRequest
18381abe55efSEd Tanous {
AsyncPutRequestcrow::openbmc_mapper::AsyncPutRequest18394e23a444SEd Tanous     explicit AsyncPutRequest(const std::shared_ptr<bmcweb::AsyncResp>& resIn) :
18408d1b46d7Szhanghch05         asyncResp(resIn)
18411214b7e7SGunnar Mills     {}
~AsyncPutRequestcrow::openbmc_mapper::AsyncPutRequest18421abe55efSEd Tanous     ~AsyncPutRequest()
18431abe55efSEd Tanous     {
18448d1b46d7Szhanghch05         if (asyncResp->res.jsonValue.empty())
18451abe55efSEd Tanous         {
18468d1b46d7Szhanghch05             setErrorResponse(asyncResp->res,
18478d1b46d7Szhanghch05                              boost::beast::http::status::forbidden,
1848fbc19ea6SMatt Spinler                              forbiddenMsg, forbiddenPropDesc);
1849d4bb9bbdSEd Tanous         }
1850d4bb9bbdSEd Tanous     }
1851d4bb9bbdSEd Tanous 
1852ecd6a3a2SEd Tanous     AsyncPutRequest(const AsyncPutRequest&) = delete;
1853ecd6a3a2SEd Tanous     AsyncPutRequest(AsyncPutRequest&&) = delete;
1854ecd6a3a2SEd Tanous     AsyncPutRequest& operator=(const AsyncPutRequest&) = delete;
1855ecd6a3a2SEd Tanous     AsyncPutRequest& operator=(AsyncPutRequest&&) = delete;
1856ecd6a3a2SEd Tanous 
setErrorStatuscrow::openbmc_mapper::AsyncPutRequest1857fbc19ea6SMatt Spinler     void setErrorStatus(const std::string& desc)
18581abe55efSEd Tanous     {
18598d1b46d7Szhanghch05         setErrorResponse(asyncResp->res,
18608d1b46d7Szhanghch05                          boost::beast::http::status::internal_server_error,
1861fbc19ea6SMatt Spinler                          desc, badReqMsg);
1862d4bb9bbdSEd Tanous     }
1863d4bb9bbdSEd Tanous 
18648d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
1865d4bb9bbdSEd Tanous     std::string objectPath;
1866d4bb9bbdSEd Tanous     std::string propertyName;
1867d4bb9bbdSEd Tanous     nlohmann::json propertyValue;
1868d4bb9bbdSEd Tanous };
1869d4bb9bbdSEd Tanous 
handlePut(const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & objectPath,const std::string & destProperty)18708d1b46d7Szhanghch05 inline void handlePut(const crow::Request& req,
18718d1b46d7Szhanghch05                       const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
187223a21a1cSEd Tanous                       const std::string& objectPath,
187323a21a1cSEd Tanous                       const std::string& destProperty)
18741abe55efSEd Tanous {
1875fbc19ea6SMatt Spinler     if (destProperty.empty())
1876fbc19ea6SMatt Spinler     {
18778d1b46d7Szhanghch05         setErrorResponse(asyncResp->res, boost::beast::http::status::forbidden,
1878fbc19ea6SMatt Spinler                          forbiddenResDesc, forbiddenMsg);
1879fbc19ea6SMatt Spinler         return;
1880fbc19ea6SMatt Spinler     }
18811aa0c2b8SEd Tanous     nlohmann::json requestDbusData;
1882fbc19ea6SMatt Spinler 
18831aa0c2b8SEd Tanous     JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
18841aa0c2b8SEd Tanous     if (ret == JsonParseResult::BadContentType)
18851aa0c2b8SEd Tanous     {
18861aa0c2b8SEd Tanous         setErrorResponse(asyncResp->res,
18871aa0c2b8SEd Tanous                          boost::beast::http::status::unsupported_media_type,
18881aa0c2b8SEd Tanous                          invalidContentType, unsupportedMediaMsg);
18891aa0c2b8SEd Tanous         return;
18901aa0c2b8SEd Tanous     }
1891d4bb9bbdSEd Tanous 
18921aa0c2b8SEd Tanous     if (ret != JsonParseResult::Success)
18931abe55efSEd Tanous     {
18948d1b46d7Szhanghch05         setErrorResponse(asyncResp->res,
18958d1b46d7Szhanghch05                          boost::beast::http::status::bad_request, noJsonDesc,
18968d1b46d7Szhanghch05                          badReqMsg);
1897d4bb9bbdSEd Tanous         return;
1898d4bb9bbdSEd Tanous     }
1899d4bb9bbdSEd Tanous 
1900b2ec0ce5SNan Zhou     auto propertyIt = requestDbusData.find("data");
19011abe55efSEd Tanous     if (propertyIt == requestDbusData.end())
19021abe55efSEd Tanous     {
19038d1b46d7Szhanghch05         setErrorResponse(asyncResp->res,
19048d1b46d7Szhanghch05                          boost::beast::http::status::bad_request, noJsonDesc,
19058d1b46d7Szhanghch05                          badReqMsg);
1906d4bb9bbdSEd Tanous         return;
1907d4bb9bbdSEd Tanous     }
1908d76323e5SEd Tanous     const nlohmann::json& propertySetValue = *propertyIt;
19098d1b46d7Szhanghch05     auto transaction = std::make_shared<AsyncPutRequest>(asyncResp);
1910d4bb9bbdSEd Tanous     transaction->objectPath = objectPath;
1911d4bb9bbdSEd Tanous     transaction->propertyName = destProperty;
1912d4bb9bbdSEd Tanous     transaction->propertyValue = propertySetValue;
1913d4bb9bbdSEd Tanous 
19142b73119cSGeorge Liu     dbus::utility::getDbusObject(
19152b73119cSGeorge Liu         transaction->objectPath, {},
19162b73119cSGeorge Liu         [transaction](const boost::system::error_code& ec2,
1917b9d36b47SEd Tanous                       const dbus::utility::MapperGetObject& objectNames) {
191826f6976fSEd Tanous             if (!ec2 && objectNames.empty())
19191abe55efSEd Tanous             {
19208d1b46d7Szhanghch05                 setErrorResponse(transaction->asyncResp->res,
1921fbc19ea6SMatt Spinler                                  boost::beast::http::status::not_found,
1922fbc19ea6SMatt Spinler                                  propNotFoundDesc, notFoundMsg);
1923d4bb9bbdSEd Tanous                 return;
1924d4bb9bbdSEd Tanous             }
1925d4bb9bbdSEd Tanous 
192623a21a1cSEd Tanous             for (const std::pair<std::string, std::vector<std::string>>&
192781ce609eSEd Tanous                      connection : objectNames)
19281abe55efSEd Tanous             {
1929d4bb9bbdSEd Tanous                 const std::string& connectionName = connection.first;
1930d4bb9bbdSEd Tanous 
193155c7b7a2SEd Tanous                 crow::connections::systemBus->async_method_call(
19321abe55efSEd Tanous                     [connectionName{std::string(connectionName)},
19335e7e2dc5SEd Tanous                      transaction](const boost::system::error_code& ec3,
1934d4bb9bbdSEd Tanous                                   const std::string& introspectXml) {
193523a21a1cSEd Tanous                         if (ec3)
19361abe55efSEd Tanous                         {
193762598e31SEd Tanous                             BMCWEB_LOG_ERROR(
193862598e31SEd Tanous                                 "Introspect call failed with error: {} on process: {}",
193962598e31SEd Tanous                                 ec3.message(), connectionName);
1940fbc19ea6SMatt Spinler                             transaction->setErrorStatus("Unexpected Error");
1941d4bb9bbdSEd Tanous                             return;
1942d4bb9bbdSEd Tanous                         }
1943d4bb9bbdSEd Tanous                         tinyxml2::XMLDocument doc;
1944d4bb9bbdSEd Tanous 
1945d4bb9bbdSEd Tanous                         doc.Parse(introspectXml.c_str());
1946bd79bce8SPatrick Williams                         tinyxml2::XMLNode* pRoot =
1947bd79bce8SPatrick Williams                             doc.FirstChildElement("node");
19481abe55efSEd Tanous                         if (pRoot == nullptr)
19491abe55efSEd Tanous                         {
195062598e31SEd Tanous                             BMCWEB_LOG_ERROR("XML document failed to parse: {}",
195162598e31SEd Tanous                                              introspectXml);
1952fbc19ea6SMatt Spinler                             transaction->setErrorStatus("Unexpected Error");
1953d4bb9bbdSEd Tanous                             return;
1954d4bb9bbdSEd Tanous                         }
1955d4bb9bbdSEd Tanous                         tinyxml2::XMLElement* ifaceNode =
1956d4bb9bbdSEd Tanous                             pRoot->FirstChildElement("interface");
19571abe55efSEd Tanous                         while (ifaceNode != nullptr)
19581abe55efSEd Tanous                         {
1959bd79bce8SPatrick Williams                             const char* interfaceName =
1960bd79bce8SPatrick Williams                                 ifaceNode->Attribute("name");
1961bd79bce8SPatrick Williams                             BMCWEB_LOG_DEBUG("found interface {}",
1962bd79bce8SPatrick Williams                                              interfaceName);
1963d4bb9bbdSEd Tanous                             tinyxml2::XMLElement* propNode =
1964d4bb9bbdSEd Tanous                                 ifaceNode->FirstChildElement("property");
19651abe55efSEd Tanous                             while (propNode != nullptr)
19661abe55efSEd Tanous                             {
1967bd79bce8SPatrick Williams                                 const char* propertyName =
1968bd79bce8SPatrick Williams                                     propNode->Attribute("name");
1969b0b6152cSEd Tanous                                 if (propertyName == nullptr)
1970b0b6152cSEd Tanous                                 {
1971bd79bce8SPatrick Williams                                     BMCWEB_LOG_DEBUG(
1972bd79bce8SPatrick Williams                                         "Couldn't find name property");
1973b0b6152cSEd Tanous                                     continue;
1974b0b6152cSEd Tanous                                 }
1975bd79bce8SPatrick Williams                                 BMCWEB_LOG_DEBUG("Found property {}",
1976bd79bce8SPatrick Williams                                                  propertyName);
19771abe55efSEd Tanous                                 if (propertyName == transaction->propertyName)
19781abe55efSEd Tanous                                 {
1979bd79bce8SPatrick Williams                                     const char* argType =
1980bd79bce8SPatrick Williams                                         propNode->Attribute("type");
19811abe55efSEd Tanous                                     if (argType != nullptr)
19821abe55efSEd Tanous                                     {
198359d494eeSPatrick Williams                                         sdbusplus::message_t m =
19841abe55efSEd Tanous                                             crow::connections::systemBus
19851abe55efSEd Tanous                                                 ->new_method_call(
1986d4bb9bbdSEd Tanous                                                     connectionName.c_str(),
1987bd79bce8SPatrick Williams                                                     transaction->objectPath
1988bd79bce8SPatrick Williams                                                         .c_str(),
19891abe55efSEd Tanous                                                     "org.freedesktop.DBus."
19901abe55efSEd Tanous                                                     "Properties",
19911abe55efSEd Tanous                                                     "Set");
19921abe55efSEd Tanous                                         m.append(interfaceName,
19931abe55efSEd Tanous                                                  transaction->propertyName);
1994d4bb9bbdSEd Tanous                                         int r = sd_bus_message_open_container(
1995bd79bce8SPatrick Williams                                             m.get(), SD_BUS_TYPE_VARIANT,
1996bd79bce8SPatrick Williams                                             argType);
19971abe55efSEd Tanous                                         if (r < 0)
19981abe55efSEd Tanous                                         {
1999fbc19ea6SMatt Spinler                                             transaction->setErrorStatus(
2000fbc19ea6SMatt Spinler                                                 "Unexpected Error");
2001d4bb9bbdSEd Tanous                                             return;
2002d4bb9bbdSEd Tanous                                         }
20031abe55efSEd Tanous                                         r = convertJsonToDbus(
20041abe55efSEd Tanous                                             m.get(), argType,
2005d4bb9bbdSEd Tanous                                             transaction->propertyValue);
20061abe55efSEd Tanous                                         if (r < 0)
20071abe55efSEd Tanous                                         {
2008c66c859cSAdriana Kobylak                                             if (r == -ERANGE)
2009c66c859cSAdriana Kobylak                                             {
2010c66c859cSAdriana Kobylak                                                 transaction->setErrorStatus(
2011c66c859cSAdriana Kobylak                                                     "Provided property value "
2012c66c859cSAdriana Kobylak                                                     "is out of range for the "
2013c66c859cSAdriana Kobylak                                                     "property type");
2014c66c859cSAdriana Kobylak                                             }
2015c66c859cSAdriana Kobylak                                             else
2016c66c859cSAdriana Kobylak                                             {
2017fbc19ea6SMatt Spinler                                                 transaction->setErrorStatus(
2018fbc19ea6SMatt Spinler                                                     "Invalid arg type");
2019c66c859cSAdriana Kobylak                                             }
2020d4bb9bbdSEd Tanous                                             return;
2021d4bb9bbdSEd Tanous                                         }
2022bd79bce8SPatrick Williams                                         r = sd_bus_message_close_container(
2023bd79bce8SPatrick Williams                                             m.get());
20241abe55efSEd Tanous                                         if (r < 0)
20251abe55efSEd Tanous                                         {
2026fbc19ea6SMatt Spinler                                             transaction->setErrorStatus(
2027fbc19ea6SMatt Spinler                                                 "Unexpected Error");
2028d4bb9bbdSEd Tanous                                             return;
2029d4bb9bbdSEd Tanous                                         }
2030bd79bce8SPatrick Williams                                         crow::connections::systemBus
2031bd79bce8SPatrick Williams                                             ->async_send(
2032bd79bce8SPatrick Williams                                                 m,
2033bd79bce8SPatrick Williams                                                 [transaction](
2034bd79bce8SPatrick Williams                                                     const boost::system::
2035bd79bce8SPatrick Williams                                                         error_code& ec,
203659d494eeSPatrick Williams                                                     sdbusplus::message_t& m2) {
203762598e31SEd Tanous                                                     BMCWEB_LOG_DEBUG("sent");
20381abe55efSEd Tanous                                                     if (ec)
20391abe55efSEd Tanous                                                     {
2040bd79bce8SPatrick Williams                                                         const sd_bus_error* e =
2041bd79bce8SPatrick Williams                                                             m2.get_error();
2042fbc19ea6SMatt Spinler                                                         setErrorResponse(
2043bd79bce8SPatrick Williams                                                             transaction
2044bd79bce8SPatrick Williams                                                                 ->asyncResp
2045bd79bce8SPatrick Williams                                                                 ->res,
2046bd79bce8SPatrick Williams                                                             boost::beast::http::
2047bd79bce8SPatrick Williams                                                                 status::
2048fbc19ea6SMatt Spinler                                                                     forbidden,
2049e662eae8SEd Tanous                                                             (e) != nullptr
2050e662eae8SEd Tanous                                                                 ? e->name
2051bd79bce8SPatrick Williams                                                                 : ec.category()
2052bd79bce8SPatrick Williams                                                                       .name(),
2053bd79bce8SPatrick Williams                                                             (e) != nullptr
2054bd79bce8SPatrick Williams                                                                 ? e->message
205506b1b63cSMatt Spinler                                                                 : ec.message());
2056fbc19ea6SMatt Spinler                                                     }
2057fbc19ea6SMatt Spinler                                                     else
2058fbc19ea6SMatt Spinler                                                     {
2059bd79bce8SPatrick Williams                                                         transaction->asyncResp
2060bd79bce8SPatrick Williams                                                             ->res.jsonValue
2061bd79bce8SPatrick Williams                                                                 ["status"] =
2062bd79bce8SPatrick Williams                                                             "ok";
2063bd79bce8SPatrick Williams                                                         transaction->asyncResp
2064bd79bce8SPatrick Williams                                                             ->res.jsonValue
2065bd79bce8SPatrick Williams                                                                 ["message"] =
2066bd79bce8SPatrick Williams                                                             "200 OK";
2067bd79bce8SPatrick Williams                                                         transaction->asyncResp
2068bd79bce8SPatrick Williams                                                             ->res
2069bd79bce8SPatrick Williams                                                             .jsonValue["data"] =
2070bd79bce8SPatrick Williams                                                             nullptr;
2071d4bb9bbdSEd Tanous                                                     }
2072d4bb9bbdSEd Tanous                                                 });
2073d4bb9bbdSEd Tanous                                     }
2074d4bb9bbdSEd Tanous                                 }
2075bd79bce8SPatrick Williams                                 propNode =
2076bd79bce8SPatrick Williams                                     propNode->NextSiblingElement("property");
2077d4bb9bbdSEd Tanous                             }
2078bd79bce8SPatrick Williams                             ifaceNode =
2079bd79bce8SPatrick Williams                                 ifaceNode->NextSiblingElement("interface");
2080d4bb9bbdSEd Tanous                         }
2081d4bb9bbdSEd Tanous                     },
2082d4bb9bbdSEd Tanous                     connectionName, transaction->objectPath,
2083d4bb9bbdSEd Tanous                     "org.freedesktop.DBus.Introspectable", "Introspect");
2084d4bb9bbdSEd Tanous             }
20852b73119cSGeorge Liu         });
2086d4bb9bbdSEd Tanous }
2087d4bb9bbdSEd Tanous 
handleDBusUrl(const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,std::string & objectPath)20888d1b46d7Szhanghch05 inline void handleDBusUrl(const crow::Request& req,
20898d1b46d7Szhanghch05                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2090049a0515SEd Tanous                           std::string& objectPath)
2091049a0515SEd Tanous {
2092049a0515SEd Tanous     // If accessing a single attribute, fill in and update objectPath,
2093049a0515SEd Tanous     // otherwise leave destProperty blank
2094e05aec50SEd Tanous     std::string destProperty;
2095049a0515SEd Tanous     const char* attrSeperator = "/attr/";
2096049a0515SEd Tanous     size_t attrPosition = objectPath.find(attrSeperator);
209771d5d8dbSEd Tanous     if (attrPosition != std::string::npos)
2098049a0515SEd Tanous     {
2099049a0515SEd Tanous         destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
2100049a0515SEd Tanous                                          objectPath.length());
21017f57f195SEd Tanous         objectPath.resize(attrPosition);
2102049a0515SEd Tanous     }
2103049a0515SEd Tanous 
2104b41187faSEd Tanous     if (req.method() == boost::beast::http::verb::post)
2105049a0515SEd Tanous     {
2106049a0515SEd Tanous         constexpr const char* actionSeperator = "/action/";
2107049a0515SEd Tanous         size_t actionPosition = objectPath.find(actionSeperator);
210871d5d8dbSEd Tanous         if (actionPosition != std::string::npos)
2109049a0515SEd Tanous         {
2110049a0515SEd Tanous             std::string postProperty =
2111049a0515SEd Tanous                 objectPath.substr((actionPosition + strlen(actionSeperator)),
2112049a0515SEd Tanous                                   objectPath.length());
21137f57f195SEd Tanous             objectPath.resize(actionPosition);
21148d1b46d7Szhanghch05             handleAction(req, asyncResp, objectPath, postProperty);
2115049a0515SEd Tanous             return;
2116049a0515SEd Tanous         }
2117049a0515SEd Tanous     }
2118b41187faSEd Tanous     else if (req.method() == boost::beast::http::verb::get)
2119049a0515SEd Tanous     {
212011ba3979SEd Tanous         if (objectPath.ends_with("/enumerate"))
2121049a0515SEd Tanous         {
2122049a0515SEd Tanous             objectPath.erase(objectPath.end() - sizeof("enumerate"),
2123049a0515SEd Tanous                              objectPath.end());
21248d1b46d7Szhanghch05             handleEnumerate(asyncResp, objectPath);
2125049a0515SEd Tanous         }
212611ba3979SEd Tanous         else if (objectPath.ends_with("/list"))
2127049a0515SEd Tanous         {
2128049a0515SEd Tanous             objectPath.erase(objectPath.end() - sizeof("list"),
2129049a0515SEd Tanous                              objectPath.end());
21308d1b46d7Szhanghch05             handleList(asyncResp, objectPath);
2131049a0515SEd Tanous         }
2132049a0515SEd Tanous         else
2133049a0515SEd Tanous         {
2134f839dfeeSEd Tanous             // Trim any trailing "/" at the end
213511ba3979SEd Tanous             if (objectPath.ends_with("/"))
2136f839dfeeSEd Tanous             {
2137f839dfeeSEd Tanous                 objectPath.pop_back();
21388d1b46d7Szhanghch05                 handleList(asyncResp, objectPath, 1);
2139f839dfeeSEd Tanous             }
2140f839dfeeSEd Tanous             else
2141f839dfeeSEd Tanous             {
21428d1b46d7Szhanghch05                 handleGet(asyncResp, objectPath, destProperty);
2143049a0515SEd Tanous             }
2144f839dfeeSEd Tanous         }
2145049a0515SEd Tanous         return;
2146049a0515SEd Tanous     }
2147b41187faSEd Tanous     else if (req.method() == boost::beast::http::verb::put)
2148049a0515SEd Tanous     {
21498d1b46d7Szhanghch05         handlePut(req, asyncResp, objectPath, destProperty);
2150049a0515SEd Tanous         return;
2151049a0515SEd Tanous     }
2152b41187faSEd Tanous     else if (req.method() == boost::beast::http::verb::delete_)
2153de81881fSMatt Spinler     {
21548d1b46d7Szhanghch05         handleDelete(asyncResp, objectPath);
2155de81881fSMatt Spinler         return;
2156de81881fSMatt Spinler     }
2157049a0515SEd Tanous 
21588d1b46d7Szhanghch05     setErrorResponse(asyncResp->res,
21598d1b46d7Szhanghch05                      boost::beast::http::status::method_not_allowed,
2160c4e8d21dSMatt Spinler                      methodNotAllowedDesc, methodNotAllowedMsg);
2161049a0515SEd Tanous }
2162049a0515SEd Tanous 
handleBusSystemPost(const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & processName,const std::string & requestedPath)2163bd79bce8SPatrick Williams inline void handleBusSystemPost(
2164bd79bce8SPatrick Williams     const crow::Request& req,
21651656b296SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2166bd79bce8SPatrick Williams     const std::string& processName, const std::string& requestedPath)
21671656b296SEd Tanous {
21681656b296SEd Tanous     std::vector<std::string> strs;
216950ebd4afSEd Tanous 
217050ebd4afSEd Tanous     bmcweb::split(strs, requestedPath, '/');
21711656b296SEd Tanous     std::string objectPath;
21721656b296SEd Tanous     std::string interfaceName;
21731656b296SEd Tanous     std::string methodName;
21741656b296SEd Tanous     auto it = strs.begin();
21751656b296SEd Tanous     if (it == strs.end())
21761656b296SEd Tanous     {
21771656b296SEd Tanous         objectPath = "/";
21781656b296SEd Tanous     }
21791656b296SEd Tanous     while (it != strs.end())
21801656b296SEd Tanous     {
21811656b296SEd Tanous         // Check if segment contains ".".  If it does, it must be an
21821656b296SEd Tanous         // interface
21831656b296SEd Tanous         if (it->find(".") != std::string::npos)
21841656b296SEd Tanous         {
21851656b296SEd Tanous             break;
21861656b296SEd Tanous             // This check is necessary as the trailing slash gets
21871656b296SEd Tanous             // parsed as part of our <path> specifier above, which
21881656b296SEd Tanous             // causes the normal trailing backslash redirector to
21891656b296SEd Tanous             // fail.
21901656b296SEd Tanous         }
21911656b296SEd Tanous         if (!it->empty())
21921656b296SEd Tanous         {
21931656b296SEd Tanous             objectPath += "/" + *it;
21941656b296SEd Tanous         }
21951656b296SEd Tanous         it++;
21961656b296SEd Tanous     }
21971656b296SEd Tanous     if (it != strs.end())
21981656b296SEd Tanous     {
21991656b296SEd Tanous         interfaceName = *it;
22001656b296SEd Tanous         it++;
22011656b296SEd Tanous 
22021656b296SEd Tanous         // after interface, we might have a method name
22031656b296SEd Tanous         if (it != strs.end())
22041656b296SEd Tanous         {
22051656b296SEd Tanous             methodName = *it;
22061656b296SEd Tanous             it++;
22071656b296SEd Tanous         }
22081656b296SEd Tanous     }
22091656b296SEd Tanous     if (it != strs.end())
22101656b296SEd Tanous     {
22111656b296SEd Tanous         // if there is more levels past the method name, something
22121656b296SEd Tanous         // went wrong, return not found
22131656b296SEd Tanous         asyncResp->res.result(boost::beast::http::status::not_found);
22141656b296SEd Tanous         return;
22151656b296SEd Tanous     }
22161656b296SEd Tanous     if (interfaceName.empty())
22171656b296SEd Tanous     {
22181656b296SEd Tanous         crow::connections::systemBus->async_method_call(
22191656b296SEd Tanous             [asyncResp, processName,
22205e7e2dc5SEd Tanous              objectPath](const boost::system::error_code& ec,
22211656b296SEd Tanous                          const std::string& introspectXml) {
22221656b296SEd Tanous                 if (ec)
22231656b296SEd Tanous                 {
222462598e31SEd Tanous                     BMCWEB_LOG_ERROR(
222562598e31SEd Tanous                         "Introspect call failed with error: {} on process: {} path: {}",
222662598e31SEd Tanous                         ec.message(), processName, objectPath);
22271656b296SEd Tanous                     return;
22281656b296SEd Tanous                 }
22291656b296SEd Tanous                 tinyxml2::XMLDocument doc;
22301656b296SEd Tanous 
22311656b296SEd Tanous                 doc.Parse(introspectXml.c_str());
22321656b296SEd Tanous                 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
22331656b296SEd Tanous                 if (pRoot == nullptr)
22341656b296SEd Tanous                 {
223562598e31SEd Tanous                     BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
223662598e31SEd Tanous                                      processName, objectPath);
22371476687dSEd Tanous                     asyncResp->res.jsonValue["status"] = "XML parse error";
22381656b296SEd Tanous                     asyncResp->res.result(
22391656b296SEd Tanous                         boost::beast::http::status::internal_server_error);
22401656b296SEd Tanous                     return;
22411656b296SEd Tanous                 }
22421656b296SEd Tanous 
224362598e31SEd Tanous                 BMCWEB_LOG_DEBUG("{}", introspectXml);
22441476687dSEd Tanous                 asyncResp->res.jsonValue["status"] = "ok";
22451476687dSEd Tanous                 asyncResp->res.jsonValue["bus_name"] = processName;
22461476687dSEd Tanous                 asyncResp->res.jsonValue["object_path"] = objectPath;
22471476687dSEd Tanous 
22481656b296SEd Tanous                 nlohmann::json& interfacesArray =
22491656b296SEd Tanous                     asyncResp->res.jsonValue["interfaces"];
22501656b296SEd Tanous                 interfacesArray = nlohmann::json::array();
22511656b296SEd Tanous                 tinyxml2::XMLElement* interface =
22521656b296SEd Tanous                     pRoot->FirstChildElement("interface");
22531656b296SEd Tanous 
22541656b296SEd Tanous                 while (interface != nullptr)
22551656b296SEd Tanous                 {
22561656b296SEd Tanous                     const char* ifaceName = interface->Attribute("name");
22571656b296SEd Tanous                     if (ifaceName != nullptr)
22581656b296SEd Tanous                     {
22598a592810SEd Tanous                         nlohmann::json::object_t interfaceObj;
22608a592810SEd Tanous                         interfaceObj["name"] = ifaceName;
2261b2ba3072SPatrick Williams                         interfacesArray.emplace_back(std::move(interfaceObj));
22621656b296SEd Tanous                     }
22631656b296SEd Tanous 
22641656b296SEd Tanous                     interface = interface->NextSiblingElement("interface");
22651656b296SEd Tanous                 }
22661656b296SEd Tanous             },
22671656b296SEd Tanous             processName, objectPath, "org.freedesktop.DBus.Introspectable",
22681656b296SEd Tanous             "Introspect");
22691656b296SEd Tanous     }
22701656b296SEd Tanous     else if (methodName.empty())
22711656b296SEd Tanous     {
22721656b296SEd Tanous         crow::connections::systemBus->async_method_call(
22731656b296SEd Tanous             [asyncResp, processName, objectPath,
22745e7e2dc5SEd Tanous              interfaceName](const boost::system::error_code& ec,
22751656b296SEd Tanous                             const std::string& introspectXml) {
22761656b296SEd Tanous                 if (ec)
22771656b296SEd Tanous                 {
227862598e31SEd Tanous                     BMCWEB_LOG_ERROR(
227962598e31SEd Tanous                         "Introspect call failed with error: {} on process: {} path: {}",
228062598e31SEd Tanous                         ec.message(), processName, objectPath);
22811656b296SEd Tanous                     return;
22821656b296SEd Tanous                 }
22831656b296SEd Tanous                 tinyxml2::XMLDocument doc;
22841656b296SEd Tanous 
22851656b296SEd Tanous                 doc.Parse(introspectXml.data(), introspectXml.size());
22861656b296SEd Tanous                 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
22871656b296SEd Tanous                 if (pRoot == nullptr)
22881656b296SEd Tanous                 {
228962598e31SEd Tanous                     BMCWEB_LOG_ERROR("XML document failed to parse {} {}",
229062598e31SEd Tanous                                      processName, objectPath);
22911656b296SEd Tanous                     asyncResp->res.result(
22921656b296SEd Tanous                         boost::beast::http::status::internal_server_error);
22931656b296SEd Tanous                     return;
22941656b296SEd Tanous                 }
22951476687dSEd Tanous 
22961476687dSEd Tanous                 asyncResp->res.jsonValue["status"] = "ok";
22971476687dSEd Tanous                 asyncResp->res.jsonValue["bus_name"] = processName;
22981476687dSEd Tanous                 asyncResp->res.jsonValue["interface"] = interfaceName;
22991476687dSEd Tanous                 asyncResp->res.jsonValue["object_path"] = objectPath;
23001656b296SEd Tanous 
2301bd79bce8SPatrick Williams                 nlohmann::json& methodsArray =
2302bd79bce8SPatrick Williams                     asyncResp->res.jsonValue["methods"];
23031656b296SEd Tanous                 methodsArray = nlohmann::json::array();
23041656b296SEd Tanous 
2305bd79bce8SPatrick Williams                 nlohmann::json& signalsArray =
2306bd79bce8SPatrick Williams                     asyncResp->res.jsonValue["signals"];
23071656b296SEd Tanous                 signalsArray = nlohmann::json::array();
23081656b296SEd Tanous 
23091656b296SEd Tanous                 nlohmann::json& propertiesObj =
23101656b296SEd Tanous                     asyncResp->res.jsonValue["properties"];
23111656b296SEd Tanous                 propertiesObj = nlohmann::json::object();
23121656b296SEd Tanous 
23131656b296SEd Tanous                 // if we know we're the only call, build the
23141656b296SEd Tanous                 // json directly
23151656b296SEd Tanous                 tinyxml2::XMLElement* interface =
23161656b296SEd Tanous                     pRoot->FirstChildElement("interface");
23171656b296SEd Tanous                 while (interface != nullptr)
23181656b296SEd Tanous                 {
23191656b296SEd Tanous                     const char* ifaceName = interface->Attribute("name");
23201656b296SEd Tanous 
23211656b296SEd Tanous                     if (ifaceName != nullptr && ifaceName == interfaceName)
23221656b296SEd Tanous                     {
23231656b296SEd Tanous                         break;
23241656b296SEd Tanous                     }
23251656b296SEd Tanous 
23261656b296SEd Tanous                     interface = interface->NextSiblingElement("interface");
23271656b296SEd Tanous                 }
23281656b296SEd Tanous                 if (interface == nullptr)
23291656b296SEd Tanous                 {
23301656b296SEd Tanous                     // if we got to the end of the list and
23311656b296SEd Tanous                     // never found a match, throw 404
2332bd79bce8SPatrick Williams                     asyncResp->res.result(
2333bd79bce8SPatrick Williams                         boost::beast::http::status::not_found);
23341656b296SEd Tanous                     return;
23351656b296SEd Tanous                 }
23361656b296SEd Tanous 
23371656b296SEd Tanous                 tinyxml2::XMLElement* methods =
23381656b296SEd Tanous                     interface->FirstChildElement("method");
23391656b296SEd Tanous                 while (methods != nullptr)
23401656b296SEd Tanous                 {
23411656b296SEd Tanous                     nlohmann::json argsArray = nlohmann::json::array();
2342bd79bce8SPatrick Williams                     tinyxml2::XMLElement* arg =
2343bd79bce8SPatrick Williams                         methods->FirstChildElement("arg");
23441656b296SEd Tanous                     while (arg != nullptr)
23451656b296SEd Tanous                     {
23461656b296SEd Tanous                         nlohmann::json thisArg;
23471656b296SEd Tanous                         for (const char* fieldName : std::array<const char*, 3>{
23481656b296SEd Tanous                                  "name", "direction", "type"})
23491656b296SEd Tanous                         {
23501656b296SEd Tanous                             const char* fieldValue = arg->Attribute(fieldName);
23511656b296SEd Tanous                             if (fieldValue != nullptr)
23521656b296SEd Tanous                             {
23531656b296SEd Tanous                                 thisArg[fieldName] = fieldValue;
23541656b296SEd Tanous                             }
23551656b296SEd Tanous                         }
2356b2ba3072SPatrick Williams                         argsArray.emplace_back(std::move(thisArg));
23571656b296SEd Tanous                         arg = arg->NextSiblingElement("arg");
23581656b296SEd Tanous                     }
23591656b296SEd Tanous 
23601656b296SEd Tanous                     const char* name = methods->Attribute("name");
23611656b296SEd Tanous                     if (name != nullptr)
23621656b296SEd Tanous                     {
23631656b296SEd Tanous                         std::string uri;
2364bd79bce8SPatrick Williams                         uri.reserve(14 + processName.size() +
2365bd79bce8SPatrick Williams                                     objectPath.size() + interfaceName.size() +
2366bd79bce8SPatrick Williams                                     strlen(name));
23671656b296SEd Tanous                         uri += "/bus/system/";
23681656b296SEd Tanous                         uri += processName;
23691656b296SEd Tanous                         uri += objectPath;
23701656b296SEd Tanous                         uri += "/";
23711656b296SEd Tanous                         uri += interfaceName;
23721656b296SEd Tanous                         uri += "/";
23731656b296SEd Tanous                         uri += name;
23741476687dSEd Tanous 
23751476687dSEd Tanous                         nlohmann::json::object_t object;
23761476687dSEd Tanous                         object["name"] = name;
23771476687dSEd Tanous                         object["uri"] = std::move(uri);
23781476687dSEd Tanous                         object["args"] = argsArray;
23791476687dSEd Tanous 
2380b2ba3072SPatrick Williams                         methodsArray.emplace_back(std::move(object));
23811656b296SEd Tanous                     }
23821656b296SEd Tanous                     methods = methods->NextSiblingElement("method");
23831656b296SEd Tanous                 }
23841656b296SEd Tanous                 tinyxml2::XMLElement* signals =
23851656b296SEd Tanous                     interface->FirstChildElement("signal");
23861656b296SEd Tanous                 while (signals != nullptr)
23871656b296SEd Tanous                 {
23881656b296SEd Tanous                     nlohmann::json argsArray = nlohmann::json::array();
23891656b296SEd Tanous 
2390bd79bce8SPatrick Williams                     tinyxml2::XMLElement* arg =
2391bd79bce8SPatrick Williams                         signals->FirstChildElement("arg");
23921656b296SEd Tanous                     while (arg != nullptr)
23931656b296SEd Tanous                     {
23941656b296SEd Tanous                         const char* name = arg->Attribute("name");
23951656b296SEd Tanous                         const char* type = arg->Attribute("type");
23961656b296SEd Tanous                         if (name != nullptr && type != nullptr)
23971656b296SEd Tanous                         {
239820fa6a2cSEd Tanous                             nlohmann::json::object_t params;
239920fa6a2cSEd Tanous                             params["name"] = name;
240020fa6a2cSEd Tanous                             params["type"] = type;
240120fa6a2cSEd Tanous                             argsArray.push_back(std::move(params));
24021656b296SEd Tanous                         }
24031656b296SEd Tanous                         arg = arg->NextSiblingElement("arg");
24041656b296SEd Tanous                     }
24051656b296SEd Tanous                     const char* name = signals->Attribute("name");
24061656b296SEd Tanous                     if (name != nullptr)
24071656b296SEd Tanous                     {
24081476687dSEd Tanous                         nlohmann::json::object_t object;
24091476687dSEd Tanous                         object["name"] = name;
24101476687dSEd Tanous                         object["args"] = argsArray;
2411b2ba3072SPatrick Williams                         signalsArray.emplace_back(std::move(object));
24121656b296SEd Tanous                     }
24131656b296SEd Tanous 
24141656b296SEd Tanous                     signals = signals->NextSiblingElement("signal");
24151656b296SEd Tanous                 }
24161656b296SEd Tanous 
24171656b296SEd Tanous                 tinyxml2::XMLElement* property =
24181656b296SEd Tanous                     interface->FirstChildElement("property");
24191656b296SEd Tanous                 while (property != nullptr)
24201656b296SEd Tanous                 {
24211656b296SEd Tanous                     const char* name = property->Attribute("name");
24221656b296SEd Tanous                     const char* type = property->Attribute("type");
24231656b296SEd Tanous                     if (type != nullptr && name != nullptr)
24241656b296SEd Tanous                     {
242559d494eeSPatrick Williams                         sdbusplus::message_t m =
24261656b296SEd Tanous                             crow::connections::systemBus->new_method_call(
24271656b296SEd Tanous                                 processName.c_str(), objectPath.c_str(),
24281656b296SEd Tanous                                 "org.freedesktop."
24291656b296SEd Tanous                                 "DBus."
24301656b296SEd Tanous                                 "Properties",
24311656b296SEd Tanous                                 "Get");
24321656b296SEd Tanous                         m.append(interfaceName, name);
24331656b296SEd Tanous                         nlohmann::json& propertyItem = propertiesObj[name];
24341656b296SEd Tanous                         crow::connections::systemBus->async_send(
24351656b296SEd Tanous                             m, [&propertyItem,
24368b24275dSEd Tanous                                 asyncResp](const boost::system::error_code& ec2,
243759d494eeSPatrick Williams                                            sdbusplus::message_t& msg) {
24388b24275dSEd Tanous                                 if (ec2)
24391656b296SEd Tanous                                 {
24401656b296SEd Tanous                                     return;
24411656b296SEd Tanous                                 }
24421656b296SEd Tanous 
2443bd79bce8SPatrick Williams                                 int r =
2444bd79bce8SPatrick Williams                                     convertDBusToJSON("v", msg, propertyItem);
244507900817SEd Tanous                                 if (r < 0)
244607900817SEd Tanous                                 {
2447bd79bce8SPatrick Williams                                     BMCWEB_LOG_ERROR(
2448bd79bce8SPatrick Williams                                         "Couldn't convert vector to json");
244907900817SEd Tanous                                 }
24501656b296SEd Tanous                             });
24511656b296SEd Tanous                     }
24521656b296SEd Tanous                     property = property->NextSiblingElement("property");
24531656b296SEd Tanous                 }
24541656b296SEd Tanous             },
24551656b296SEd Tanous             processName, objectPath, "org.freedesktop.DBus.Introspectable",
24561656b296SEd Tanous             "Introspect");
24571656b296SEd Tanous     }
24581656b296SEd Tanous     else
24591656b296SEd Tanous     {
24601656b296SEd Tanous         if (req.method() != boost::beast::http::verb::post)
24611656b296SEd Tanous         {
24621656b296SEd Tanous             asyncResp->res.result(boost::beast::http::status::not_found);
24631656b296SEd Tanous             return;
24641656b296SEd Tanous         }
24651656b296SEd Tanous 
24661aa0c2b8SEd Tanous         nlohmann::json requestDbusData;
24671aa0c2b8SEd Tanous         JsonParseResult ret = parseRequestAsJson(req, requestDbusData);
24681aa0c2b8SEd Tanous         if (ret == JsonParseResult::BadContentType)
24691656b296SEd Tanous         {
24701aa0c2b8SEd Tanous             setErrorResponse(asyncResp->res,
24711aa0c2b8SEd Tanous                              boost::beast::http::status::unsupported_media_type,
24721aa0c2b8SEd Tanous                              invalidContentType, unsupportedMediaMsg);
24731656b296SEd Tanous             return;
24741656b296SEd Tanous         }
24751aa0c2b8SEd Tanous         if (ret != JsonParseResult::Success)
24761aa0c2b8SEd Tanous         {
24771aa0c2b8SEd Tanous             setErrorResponse(asyncResp->res,
24781aa0c2b8SEd Tanous                              boost::beast::http::status::bad_request,
24791aa0c2b8SEd Tanous                              noJsonDesc, badReqMsg);
24801aa0c2b8SEd Tanous             return;
24811aa0c2b8SEd Tanous         }
24821aa0c2b8SEd Tanous 
24831656b296SEd Tanous         if (!requestDbusData.is_array())
24841656b296SEd Tanous         {
24851656b296SEd Tanous             asyncResp->res.result(boost::beast::http::status::bad_request);
24861656b296SEd Tanous             return;
24871656b296SEd Tanous         }
248828dd5ca1SLei YU         auto transaction = std::make_shared<InProgressActionData>(asyncResp);
24891656b296SEd Tanous 
24901656b296SEd Tanous         transaction->path = objectPath;
24911656b296SEd Tanous         transaction->methodName = methodName;
24921656b296SEd Tanous         transaction->arguments = std::move(requestDbusData);
24931656b296SEd Tanous 
24941656b296SEd Tanous         findActionOnInterface(transaction, processName);
24951656b296SEd Tanous     }
24961656b296SEd Tanous }
24971656b296SEd Tanous 
requestRoutes(App & app)249823a21a1cSEd Tanous inline void requestRoutes(App& app)
24991abe55efSEd Tanous {
250055c7b7a2SEd Tanous     BMCWEB_ROUTE(app, "/bus/")
2501432a890cSEd Tanous         .privileges({{"Login"}})
2502b41187faSEd Tanous         .methods(boost::beast::http::verb::get)(
25038d1b46d7Szhanghch05             [](const crow::Request&,
25048d1b46d7Szhanghch05                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
25051476687dSEd Tanous                 nlohmann::json::array_t buses;
25061476687dSEd Tanous                 nlohmann::json& bus = buses.emplace_back();
25071476687dSEd Tanous                 bus["name"] = "system";
25081476687dSEd Tanous                 asyncResp->res.jsonValue["busses"] = std::move(buses);
25091476687dSEd Tanous                 asyncResp->res.jsonValue["status"] = "ok";
2510911ac317SEd Tanous             });
2511911ac317SEd Tanous 
251255c7b7a2SEd Tanous     BMCWEB_ROUTE(app, "/bus/system/")
2513432a890cSEd Tanous         .privileges({{"Login"}})
2514b41187faSEd Tanous         .methods(boost::beast::http::verb::get)(
25158d1b46d7Szhanghch05             [](const crow::Request&,
25168d1b46d7Szhanghch05                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2517bd79bce8SPatrick Williams                 auto myCallback = [asyncResp](
2518bd79bce8SPatrick Williams                                       const boost::system::error_code& ec,
2519aa2e59c1SEd Tanous                                       std::vector<std::string>& names) {
25201abe55efSEd Tanous                     if (ec)
25211abe55efSEd Tanous                     {
252262598e31SEd Tanous                         BMCWEB_LOG_ERROR("Dbus call failed with code {}", ec);
25238d1b46d7Szhanghch05                         asyncResp->res.result(
25241abe55efSEd Tanous                             boost::beast::http::status::internal_server_error);
25251abe55efSEd Tanous                     }
25261abe55efSEd Tanous                     else
25271abe55efSEd Tanous                     {
25283544d2a7SEd Tanous                         std::ranges::sort(names);
25291476687dSEd Tanous                         asyncResp->res.jsonValue["status"] = "ok";
25308d1b46d7Szhanghch05                         auto& objectsSub = asyncResp->res.jsonValue["objects"];
253102cad96eSEd Tanous                         for (const auto& name : names)
25321abe55efSEd Tanous                         {
25331476687dSEd Tanous                             nlohmann::json::object_t object;
25341476687dSEd Tanous                             object["name"] = name;
2535b2ba3072SPatrick Williams                             objectsSub.emplace_back(std::move(object));
2536911ac317SEd Tanous                         }
2537911ac317SEd Tanous                     }
2538aa2e59c1SEd Tanous                 };
253955c7b7a2SEd Tanous                 crow::connections::systemBus->async_method_call(
2540aa2e59c1SEd Tanous                     std::move(myCallback), "org.freedesktop.DBus", "/",
2541aa2e59c1SEd Tanous                     "org.freedesktop.DBus", "ListNames");
2542911ac317SEd Tanous             });
2543911ac317SEd Tanous 
254455c7b7a2SEd Tanous     BMCWEB_ROUTE(app, "/list/")
2545432a890cSEd Tanous         .privileges({{"Login"}})
2546b41187faSEd Tanous         .methods(boost::beast::http::verb::get)(
25478d1b46d7Szhanghch05             [](const crow::Request&,
25488d1b46d7Szhanghch05                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
25498d1b46d7Szhanghch05                 handleList(asyncResp, "/");
2550ba9f9a6cSEd Tanous             });
2551ba9f9a6cSEd Tanous 
255255c7b7a2SEd Tanous     BMCWEB_ROUTE(app, "/xyz/<path>")
2553432a890cSEd Tanous         .privileges({{"Login"}})
25548d1b46d7Szhanghch05         .methods(boost::beast::http::verb::get)(
25558d1b46d7Szhanghch05             [](const crow::Request& req,
25568d1b46d7Szhanghch05                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2557f00032dbSTanous                const std::string& path) {
2558f00032dbSTanous                 std::string objectPath = "/xyz/" + path;
25598d1b46d7Szhanghch05                 handleDBusUrl(req, asyncResp, objectPath);
2560f00032dbSTanous             });
2561f00032dbSTanous 
2562f00032dbSTanous     BMCWEB_ROUTE(app, "/xyz/<path>")
2563432a890cSEd Tanous         .privileges({{"ConfigureComponents", "ConfigureManager"}})
2564b41187faSEd Tanous         .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2565b41187faSEd Tanous                  boost::beast::http::verb::delete_)(
25668d1b46d7Szhanghch05             [](const crow::Request& req,
25678d1b46d7Szhanghch05                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2568ba9f9a6cSEd Tanous                const std::string& path) {
2569d76323e5SEd Tanous                 std::string objectPath = "/xyz/" + path;
25708d1b46d7Szhanghch05                 handleDBusUrl(req, asyncResp, objectPath);
2571049a0515SEd Tanous             });
2572a4e18f2aSEd Tanous 
2573049a0515SEd Tanous     BMCWEB_ROUTE(app, "/org/<path>")
2574432a890cSEd Tanous         .privileges({{"Login"}})
25758d1b46d7Szhanghch05         .methods(boost::beast::http::verb::get)(
25768d1b46d7Szhanghch05             [](const crow::Request& req,
25778d1b46d7Szhanghch05                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2578f00032dbSTanous                const std::string& path) {
2579e1281403SEd Tanous                 std::string objectPath = "/org/" + path;
25808d1b46d7Szhanghch05                 handleDBusUrl(req, asyncResp, objectPath);
2581f00032dbSTanous             });
2582f00032dbSTanous 
2583f00032dbSTanous     BMCWEB_ROUTE(app, "/org/<path>")
2584432a890cSEd Tanous         .privileges({{"ConfigureComponents", "ConfigureManager"}})
2585b41187faSEd Tanous         .methods(boost::beast::http::verb::put, boost::beast::http::verb::post,
2586b41187faSEd Tanous                  boost::beast::http::verb::delete_)(
25878d1b46d7Szhanghch05             [](const crow::Request& req,
25888d1b46d7Szhanghch05                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2589049a0515SEd Tanous                const std::string& path) {
2590e1281403SEd Tanous                 std::string objectPath = "/org/" + path;
25918d1b46d7Szhanghch05                 handleDBusUrl(req, asyncResp, objectPath);
2592ba9f9a6cSEd Tanous             });
259300b92f79Sshiyilei 
259455c7b7a2SEd Tanous     BMCWEB_ROUTE(app, "/download/dump/<str>/")
2595432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
25968d1b46d7Szhanghch05         .methods(boost::beast::http::verb::get)(
25978d1b46d7Szhanghch05             [](const crow::Request&,
25988d1b46d7Szhanghch05                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2599d4bb9bbdSEd Tanous                const std::string& dumpId) {
2600482c45a5SJosh Lehan                 if (!validateFilename(dumpId))
26011abe55efSEd Tanous                 {
2602bd79bce8SPatrick Williams                     asyncResp->res.result(
2603bd79bce8SPatrick Williams                         boost::beast::http::status::bad_request);
2604d4bb9bbdSEd Tanous                     return;
2605d4bb9bbdSEd Tanous                 }
2606bd79bce8SPatrick Williams                 std::filesystem::path loc(
2607bd79bce8SPatrick Williams                     "/var/lib/phosphor-debug-collector/dumps");
2608d4bb9bbdSEd Tanous 
2609ad18f070SEd Tanous                 loc /= dumpId;
2610d4bb9bbdSEd Tanous 
2611f6150403SJames Feist                 if (!std::filesystem::exists(loc) ||
2612f6150403SJames Feist                     !std::filesystem::is_directory(loc))
26131abe55efSEd Tanous                 {
261462598e31SEd Tanous                     BMCWEB_LOG_ERROR("{}Not found", loc.string());
2615bd79bce8SPatrick Williams                     asyncResp->res.result(
2616bd79bce8SPatrick Williams                         boost::beast::http::status::not_found);
2617d4bb9bbdSEd Tanous                     return;
2618d4bb9bbdSEd Tanous                 }
2619f6150403SJames Feist                 std::filesystem::directory_iterator files(loc);
2620ad18f070SEd Tanous 
26219eb808c1SEd Tanous                 for (const auto& file : files)
26221abe55efSEd Tanous                 {
2623*d51c61b4SMyung Bae                     if (asyncResp->res.openFile(file) !=
2624*d51c61b4SMyung Bae                         crow::OpenCode::Success)
26251abe55efSEd Tanous                     {
2626d4bb9bbdSEd Tanous                         continue;
2627d4bb9bbdSEd Tanous                     }
2628d9207047SRamesh Iyyar 
2629bd79bce8SPatrick Williams                     asyncResp->res.addHeader(
2630bd79bce8SPatrick Williams                         boost::beast::http::field::content_type,
26318d1b46d7Szhanghch05                         "application/octet-stream");
2632d9207047SRamesh Iyyar 
26338d1b46d7Szhanghch05                     // Assuming only one dump file will be present in the dump
26348d1b46d7Szhanghch05                     // id directory
2635d9207047SRamesh Iyyar                     std::string dumpFileName = file.path().filename().string();
2636d9207047SRamesh Iyyar 
2637d9207047SRamesh Iyyar                     // Filename should be in alphanumeric, dot and underscore
26388d1b46d7Szhanghch05                     // Its based on phosphor-debug-collector application
26398d1b46d7Szhanghch05                     // dumpfile format
26404b242749SEd Tanous                     static std::regex dumpFileRegex("[a-zA-Z0-9\\._]+");
2641d9207047SRamesh Iyyar                     if (!std::regex_match(dumpFileName, dumpFileRegex))
2642d9207047SRamesh Iyyar                     {
2643bd79bce8SPatrick Williams                         BMCWEB_LOG_ERROR("Invalid dump filename {}",
2644bd79bce8SPatrick Williams                                          dumpFileName);
2645bd79bce8SPatrick Williams                         asyncResp->res.result(
2646bd79bce8SPatrick Williams                             boost::beast::http::status::not_found);
2647d9207047SRamesh Iyyar                         return;
2648d9207047SRamesh Iyyar                     }
2649bd79bce8SPatrick Williams                     std::string contentDispositionParam =
2650bd79bce8SPatrick Williams                         "attachment; filename=\"" + dumpFileName + "\"";
2651d9207047SRamesh Iyyar 
2652d9f6c621SEd Tanous                     asyncResp->res.addHeader(
2653d9f6c621SEd Tanous                         boost::beast::http::field::content_disposition,
26548d1b46d7Szhanghch05                         contentDispositionParam);
2655d9207047SRamesh Iyyar 
2656ad18f070SEd Tanous                     return;
2657d4bb9bbdSEd Tanous                 }
26588d1b46d7Szhanghch05                 asyncResp->res.result(boost::beast::http::status::not_found);
2659d4bb9bbdSEd Tanous                 return;
2660d4bb9bbdSEd Tanous             });
2661d4bb9bbdSEd Tanous 
2662e3cb5a31SEd Tanous     BMCWEB_ROUTE(app, "/bus/system/<str>/")
2663432a890cSEd Tanous         .privileges({{"Login"}})
2664b41187faSEd Tanous 
2665b41187faSEd Tanous         .methods(boost::beast::http::verb::get)(
26668d1b46d7Szhanghch05             [](const crow::Request&,
26678d1b46d7Szhanghch05                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
266881ce609eSEd Tanous                const std::string& connection) {
266972374eb7SNan Zhou                 introspectObjects(connection, "/", asyncResp);
2670e3cb5a31SEd Tanous             });
2671e3cb5a31SEd Tanous 
2672e3cb5a31SEd Tanous     BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
2673432a890cSEd Tanous         .privileges({{"ConfigureComponents", "ConfigureManager"}})
26741656b296SEd Tanous         .methods(boost::beast::http::verb::get,
26751656b296SEd Tanous                  boost::beast::http::verb::post)(handleBusSystemPost);
2676d4bb9bbdSEd Tanous }
2677911ac317SEd Tanous } // namespace openbmc_mapper
2678911ac317SEd Tanous } // namespace crow
2679