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