blob: c242539843ae76270910236c8b224627b356db2b [file] [log] [blame]
James Feist5b4aa862018-08-16 14:07:01 -07001// Copyright (c) 2018 Intel Corporation
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
Ed Tanousb9b2e0b2018-09-13 13:47:50 -070014
James Feist5b4aa862018-08-16 14:07:01 -070015#pragma once
Ed Tanous911ac312017-08-15 09:37:42 -070016#include <crow/app.h>
Ed Tanous911ac312017-08-15 09:37:42 -070017#include <tinyxml2.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -070018
Ed Tanouse3cb5a32018-08-08 14:16:49 -070019#include <async_resp.hpp>
Ed Tanous1abe55e2018-09-05 08:30:59 -070020#include <boost/algorithm/string.hpp>
21#include <boost/container/flat_set.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -070022#include <dbus_singleton.hpp>
James Feist5b4aa862018-08-16 14:07:01 -070023#include <dbus_utility.hpp>
Ed Tanousd4bb9bb2018-05-16 13:36:42 -070024#include <experimental/filesystem>
25#include <fstream>
William A. Kennington III0a63b1c2018-10-18 13:37:19 -070026#include <sdbusplus/message/types.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -070027
Ed Tanous1abe55e2018-09-05 08:30:59 -070028namespace crow
29{
30namespace openbmc_mapper
31{
Ed Tanousba9f9a62017-10-11 16:40:35 -070032
Ed Tanouse3cb5a32018-08-08 14:16:49 -070033void introspectObjects(const std::string &processName,
34 const std::string &objectPath,
35 std::shared_ptr<bmcweb::AsyncResp> transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -070036{
Ed Tanouse3cb5a32018-08-08 14:16:49 -070037 if (transaction->res.jsonValue.is_null())
38 {
39 transaction->res.jsonValue = {{"status", "ok"},
40 {"bus_name", processName},
41 {"objects", nlohmann::json::array()}};
42 }
43
Ed Tanous1abe55e2018-09-05 08:30:59 -070044 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -070045 [transaction, processName{std::string(processName)},
46 objectPath{std::string(objectPath)}](
47 const boost::system::error_code ec,
48 const std::string &introspect_xml) {
Ed Tanous1abe55e2018-09-05 08:30:59 -070049 if (ec)
50 {
51 BMCWEB_LOG_ERROR
52 << "Introspect call failed with error: " << ec.message()
53 << " on process: " << processName << " path: " << objectPath
54 << "\n";
Ed Tanouse3cb5a32018-08-08 14:16:49 -070055 return;
56 }
57 transaction->res.jsonValue["objects"].push_back(
58 {{"path", objectPath}});
59
60 tinyxml2::XMLDocument doc;
61
62 doc.Parse(introspect_xml.c_str());
63 tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
64 if (pRoot == nullptr)
65 {
66 BMCWEB_LOG_ERROR << "XML document failed to parse "
67 << processName << " " << objectPath << "\n";
Ed Tanous911ac312017-08-15 09:37:42 -070068 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070069 else
70 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -070071 tinyxml2::XMLElement *node = pRoot->FirstChildElement("node");
72 while (node != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -070073 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -070074 const char *childPath = node->Attribute("name");
75 if (childPath != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -070076 {
Ed Tanous1abe55e2018-09-05 08:30:59 -070077 std::string newpath;
78 if (objectPath != "/")
79 {
80 newpath += objectPath;
81 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -070082 newpath += std::string("/") + childPath;
Ed Tanous1abe55e2018-09-05 08:30:59 -070083 // introspect the subobjects as well
Ed Tanouse3cb5a32018-08-08 14:16:49 -070084 introspectObjects(processName, newpath, transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -070085 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -070086
87 node = node->NextSiblingElement("node");
Ed Tanous1abe55e2018-09-05 08:30:59 -070088 }
89 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070090 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -070091 processName, objectPath, "org.freedesktop.DBus.Introspectable",
Ed Tanous1abe55e2018-09-05 08:30:59 -070092 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -070093}
Ed Tanous64530012018-02-06 17:08:16 -080094
Ed Tanous1abe55e2018-09-05 08:30:59 -070095void getManagedObjectsForEnumerate(const std::string &object_name,
Ed Tanouse3cb5a32018-08-08 14:16:49 -070096 const std::string &object_manager_path,
Ed Tanous1abe55e2018-09-05 08:30:59 -070097 const std::string &connection_name,
Ed Tanous049a0512018-11-01 13:58:42 -070098 std::shared_ptr<bmcweb::AsyncResp> asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -070099{
Ed Tanous049a0512018-11-01 13:58:42 -0700100 BMCWEB_LOG_DEBUG << "getManagedObjectsForEnumerate " << object_name
101 << " object_manager_path " << object_manager_path
102 << " connection_name " << connection_name;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700103 crow::connections::systemBus->async_method_call(
Ed Tanous049a0512018-11-01 13:58:42 -0700104 [asyncResp, object_name,
105 connection_name](const boost::system::error_code ec,
106 const dbus::utility::ManagedObjectType &objects) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700107 if (ec)
108 {
Ed Tanous049a0512018-11-01 13:58:42 -0700109 BMCWEB_LOG_ERROR << "GetManagedObjects on path " << object_name
110 << " failed with code " << ec;
111 return;
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700112 }
Ed Tanous64530012018-02-06 17:08:16 -0800113
Ed Tanous049a0512018-11-01 13:58:42 -0700114 nlohmann::json &dataJson = asyncResp->res.jsonValue["data"];
115
116 for (const auto &objectPath : objects)
117 {
118 if (boost::starts_with(objectPath.first.str, object_name))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700119 {
Ed Tanous049a0512018-11-01 13:58:42 -0700120 BMCWEB_LOG_DEBUG << "Reading object "
121 << objectPath.first.str;
122 nlohmann::json &objectJson = dataJson[objectPath.first.str];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123 if (objectJson.is_null())
124 {
125 objectJson = nlohmann::json::object();
126 }
127 for (const auto &interface : objectPath.second)
128 {
129 for (const auto &property : interface.second)
130 {
131 nlohmann::json &propertyJson =
132 objectJson[property.first];
William A. Kennington III0a63b1c2018-10-18 13:37:19 -0700133 sdbusplus::message::variant_ns::visit(
Ed Tanous1abe55e2018-09-05 08:30:59 -0700134 [&propertyJson](auto &&val) {
135 propertyJson = val;
136 },
137 property.second);
138 }
139 }
140 }
Ed Tanous049a0512018-11-01 13:58:42 -0700141 for (const auto &interface : objectPath.second)
142 {
143 if (interface.first == "org.freedesktop.DBus.ObjectManager")
144 {
145 getManagedObjectsForEnumerate(
146 objectPath.first.str, objectPath.first.str,
147 connection_name, asyncResp);
148 }
149 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700150 }
151 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700152 connection_name, object_manager_path,
153 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
154}
155
156void findObjectManagerPathForEnumerate(
157 const std::string &object_name, const std::string &connection_name,
Ed Tanous049a0512018-11-01 13:58:42 -0700158 std::shared_ptr<bmcweb::AsyncResp> asyncResp)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700159{
Ed Tanous049a0512018-11-01 13:58:42 -0700160 BMCWEB_LOG_DEBUG << "Finding objectmanager for path " << object_name
161 << " on connection:" << connection_name;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700162 crow::connections::systemBus->async_method_call(
Ed Tanous049a0512018-11-01 13:58:42 -0700163 [asyncResp, object_name, connection_name](
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700164 const boost::system::error_code ec,
165 const boost::container::flat_map<
166 std::string, boost::container::flat_map<
167 std::string, std::vector<std::string>>>
168 &objects) {
169 if (ec)
170 {
Ed Tanous049a0512018-11-01 13:58:42 -0700171 BMCWEB_LOG_ERROR << "GetAncestors on path " << object_name
172 << " failed with code " << ec;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700173 return;
174 }
175
Ed Tanousf254ba72018-10-12 13:40:35 -0700176 for (const auto &pathGroup : objects)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700177 {
Ed Tanousf254ba72018-10-12 13:40:35 -0700178 for (const auto &connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700179 {
180 if (connectionGroup.first == connection_name)
181 {
182 // Found the object manager path for this resource.
183 getManagedObjectsForEnumerate(
Ed Tanous049a0512018-11-01 13:58:42 -0700184 object_name, pathGroup.first, connection_name,
185 asyncResp);
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700186 return;
187 }
188 }
189 }
190 },
191 "xyz.openbmc_project.ObjectMapper",
192 "/xyz/openbmc_project/object_mapper",
193 "xyz.openbmc_project.ObjectMapper", "GetAncestors", object_name,
194 std::array<const char *, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700195}
Ed Tanous64530012018-02-06 17:08:16 -0800196
197using GetSubTreeType = std::vector<
198 std::pair<std::string,
199 std::vector<std::pair<std::string, std::vector<std::string>>>>>;
200
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700201// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700202struct InProgressActionData
203{
204 InProgressActionData(crow::Response &res) : res(res){};
205 ~InProgressActionData()
206 {
207 if (res.result() == boost::beast::http::status::internal_server_error)
208 {
209 // Reset the json object to clear out any data that made it in
210 // before the error happened todo(ed) handle error condition with
211 // proper code
212 res.jsonValue = nlohmann::json::object();
213 }
214 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700215 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700216
Ed Tanous1abe55e2018-09-05 08:30:59 -0700217 void setErrorStatus()
218 {
219 res.result(boost::beast::http::status::internal_server_error);
220 }
221 crow::Response &res;
222 std::string path;
223 std::string methodName;
224 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700225};
226
Ed Tanous1abe55e2018-09-05 08:30:59 -0700227std::vector<std::string> dbusArgSplit(const std::string &string)
228{
229 std::vector<std::string> ret;
230 if (string.empty())
231 {
232 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700233 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700234 ret.push_back("");
235 int containerDepth = 0;
236
237 for (std::string::const_iterator character = string.begin();
238 character != string.end(); character++)
239 {
240 ret.back() += *character;
241 switch (*character)
242 {
243 case ('a'):
244 break;
245 case ('('):
246 case ('{'):
247 containerDepth++;
248 break;
249 case ('}'):
250 case (')'):
251 containerDepth--;
252 if (containerDepth == 0)
253 {
254 if (character + 1 != string.end())
255 {
256 ret.push_back("");
257 }
258 }
259 break;
260 default:
261 if (containerDepth == 0)
262 {
263 if (character + 1 != string.end())
264 {
265 ret.push_back("");
266 }
267 }
268 break;
269 }
270 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700271}
272
Ed Tanousd76323e2018-08-07 14:35:40 -0700273int convertJsonToDbus(sd_bus_message *m, const std::string &arg_type,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700274 const nlohmann::json &input_json)
275{
276 int r = 0;
277 BMCWEB_LOG_DEBUG << "Converting " << input_json.dump()
278 << " to type: " << arg_type;
279 const std::vector<std::string> argTypes = dbusArgSplit(arg_type);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700280
Ed Tanous1abe55e2018-09-05 08:30:59 -0700281 // Assume a single object for now.
282 const nlohmann::json *j = &input_json;
283 nlohmann::json::const_iterator jIt = input_json.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700284
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700285 for (const std::string &argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700286 {
287 // If we are decoding multiple objects, grab the pointer to the
288 // iterator, and increment it for the next loop
289 if (argTypes.size() > 1)
290 {
291 if (jIt == input_json.end())
292 {
293 return -2;
294 }
295 j = &*jIt;
296 jIt++;
297 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700298 const int64_t *intValue = j->get_ptr<const int64_t *>();
299 const uint64_t *uintValue = j->get_ptr<const uint64_t *>();
300 const std::string *stringValue = j->get_ptr<const std::string *>();
301 const double *doubleValue = j->get_ptr<const double *>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700302 const bool *b = j->get_ptr<const bool *>();
303 int64_t v = 0;
304 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700305
Ed Tanous1abe55e2018-09-05 08:30:59 -0700306 // Do some basic type conversions that make sense. uint can be
307 // converted to int. int and uint can be converted to double
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700308 if (uintValue != nullptr && intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700309 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700310 v = static_cast<int64_t>(*uintValue);
311 intValue = &v;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700312 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700313 if (uintValue != nullptr && doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700314 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700315 d = static_cast<double>(*uintValue);
316 doubleValue = &d;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700317 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700318 if (intValue != nullptr && doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700319 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700320 d = static_cast<double>(*intValue);
321 doubleValue = &d;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700322 }
323
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700324 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700325 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700326 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700327 {
328 return -1;
329 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700330 r = sd_bus_message_append_basic(m, argCode[0],
331 (void *)stringValue->c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700332 if (r < 0)
333 {
334 return r;
335 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700336 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700337 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700338 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700339 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700340 {
341 return -1;
342 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700343 int32_t i = static_cast<int32_t>(*intValue);
344 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700345 if (r < 0)
346 {
347 return r;
348 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700349 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700350 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700351 {
352 // lots of ways bool could be represented here. Try them all
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700353 int boolInt = false;
354 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700355 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700356 boolInt = *intValue > 0 ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700357 }
358 else if (b != nullptr)
359 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700360 boolInt = b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700361 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700362 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700363 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700364 boolInt = boost::istarts_with(*stringValue, "t") ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700365 }
366 else
367 {
368 return -1;
369 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700370 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700371 if (r < 0)
372 {
373 return r;
374 }
375 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700376 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700377 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700378 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700379 {
380 return -1;
381 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700382 int16_t n = static_cast<int16_t>(*intValue);
383 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700384 if (r < 0)
385 {
386 return r;
387 }
388 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700389 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700390 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700391 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700392 {
393 return -1;
394 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700395 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700396 if (r < 0)
397 {
398 return r;
399 }
400 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700401 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700402 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700403 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700404 {
405 return -1;
406 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700407 uint8_t y = static_cast<uint8_t>(*uintValue);
408 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700409 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700410 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700411 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700412 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700413 {
414 return -1;
415 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700416 uint16_t q = static_cast<uint16_t>(*uintValue);
417 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700418 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700419 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700420 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700421 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700422 {
423 return -1;
424 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700425 uint32_t u = static_cast<uint32_t>(*uintValue);
426 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700427 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700428 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700429 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700430 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700431 {
432 return -1;
433 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700434 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700435 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700436 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700437 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700438 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700439 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700440 else if (boost::starts_with(argCode, "a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700441 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700442 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700443 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700444 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700445 if (r < 0)
446 {
447 return r;
448 }
449
450 for (nlohmann::json::const_iterator it = j->begin(); it != j->end();
451 ++it)
452 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700453 r = convertJsonToDbus(m, containedType, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700454 if (r < 0)
455 {
456 return r;
457 }
458
459 it++;
460 }
461 sd_bus_message_close_container(m);
462 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700463 else if (boost::starts_with(argCode, "v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700464 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700465 std::string containedType = argCode.substr(1);
466 BMCWEB_LOG_DEBUG << "variant type: " << argCode
467 << " appending variant of type: " << containedType;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700468 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700469 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700470 if (r < 0)
471 {
472 return r;
473 }
474
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700475 r = convertJsonToDbus(m, containedType, input_json);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700476 if (r < 0)
477 {
478 return r;
479 }
480
481 r = sd_bus_message_close_container(m);
482 if (r < 0)
483 {
484 return r;
485 }
486 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700487 else if (boost::starts_with(argCode, "(") &&
488 boost::ends_with(argCode, ")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700489 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700490 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700491 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700492 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700493 nlohmann::json::const_iterator it = j->begin();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700494 for (const std::string &argCode : dbusArgSplit(arg_type))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700495 {
496 if (it == j->end())
497 {
498 return -1;
499 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700500 r = convertJsonToDbus(m, argCode, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700501 if (r < 0)
502 {
503 return r;
504 }
505 it++;
506 }
507 r = sd_bus_message_close_container(m);
508 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700509 else if (boost::starts_with(argCode, "{") &&
510 boost::ends_with(argCode, "}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700511 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700512 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700513 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700514 containedType.c_str());
515 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700516 if (codes.size() != 2)
517 {
518 return -1;
519 }
520 const std::string &key_type = codes[0];
521 const std::string &value_type = codes[1];
522 for (auto it : j->items())
523 {
524 r = convertJsonToDbus(m, key_type, it.key());
525 if (r < 0)
526 {
527 return r;
528 }
529
530 r = convertJsonToDbus(m, value_type, it.value());
531 if (r < 0)
532 {
533 return r;
534 }
535 }
536 r = sd_bus_message_close_container(m);
537 }
538 else
539 {
540 return -2;
541 }
542 if (r < 0)
543 {
544 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700545 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700546
Ed Tanous1abe55e2018-09-05 08:30:59 -0700547 if (argTypes.size() > 1)
548 {
549 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700550 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700551 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700552}
553
Ed Tanousd76323e2018-08-07 14:35:40 -0700554void findActionOnInterface(std::shared_ptr<InProgressActionData> transaction,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700555 const std::string &connectionName)
556{
557 BMCWEB_LOG_DEBUG << "findActionOnInterface for connection "
558 << connectionName;
559 crow::connections::systemBus->async_method_call(
560 [transaction, connectionName{std::string(connectionName)}](
561 const boost::system::error_code ec,
562 const std::string &introspect_xml) {
563 BMCWEB_LOG_DEBUG << "got xml:\n " << introspect_xml;
564 if (ec)
565 {
566 BMCWEB_LOG_ERROR
567 << "Introspect call failed with error: " << ec.message()
568 << " on process: " << connectionName << "\n";
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700569 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700570 else
571 {
572 tinyxml2::XMLDocument doc;
573
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700574 doc.Parse(introspect_xml.data(), introspect_xml.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700575 tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
576 if (pRoot == nullptr)
577 {
578 BMCWEB_LOG_ERROR << "XML document failed to parse "
579 << connectionName << "\n";
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700580 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700581 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700582 tinyxml2::XMLElement *interfaceNode =
583 pRoot->FirstChildElement("interface");
584 while (interfaceNode != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700585 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700586 const char *thisInterfaceName =
587 interfaceNode->Attribute("name");
588 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700589 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700590 tinyxml2::XMLElement *methodNode =
591 interfaceNode->FirstChildElement("method");
592 while (methodNode != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700593 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700594 const char *thisMethodName =
595 methodNode->Attribute("name");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700596 BMCWEB_LOG_DEBUG << "Found method: "
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700597 << thisMethodName;
598 if (thisMethodName != nullptr &&
599 thisMethodName == transaction->methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700600 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700601 BMCWEB_LOG_DEBUG
602 << "Found method named " << thisMethodName
603 << " on interface " << thisInterfaceName;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700604 sdbusplus::message::message m =
605 crow::connections::systemBus
606 ->new_method_call(
607 connectionName.c_str(),
608 transaction->path.c_str(),
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700609 thisInterfaceName,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700610 transaction->methodName.c_str());
611
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700612 tinyxml2::XMLElement *argumentNode =
613 methodNode->FirstChildElement("arg");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700614
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700615 nlohmann::json::const_iterator argIt =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700616 transaction->arguments.begin();
617
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700618 while (argumentNode != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700619 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700620 const char *argDirection =
621 argumentNode->Attribute("direction");
622 const char *argType =
623 argumentNode->Attribute("type");
624 if (argDirection != nullptr &&
625 argType != nullptr &&
626 std::string(argDirection) == "in")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700627 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700628
629 if (argIt ==
Ed Tanous1abe55e2018-09-05 08:30:59 -0700630 transaction->arguments.end())
631 {
632 transaction->setErrorStatus();
633 return;
634 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700635 if (convertJsonToDbus(
636 m.get(), std::string(argType),
637 *argIt) < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700638 {
639 transaction->setErrorStatus();
640 return;
641 }
642
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700643 argIt++;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700644 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700645 argumentNode =
646 methodNode->NextSiblingElement("arg");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700647 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700648
Ed Tanous1abe55e2018-09-05 08:30:59 -0700649 crow::connections::systemBus->async_send(
650 m, [transaction](
651 boost::system::error_code ec,
652 sdbusplus::message::message &m) {
653 if (ec)
654 {
655 transaction->setErrorStatus();
656 return;
657 }
658 transaction->res.jsonValue = {
659 {"status", "ok"},
660 {"message", "200 OK"},
661 {"data", nullptr}};
662 });
663 break;
664 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700665 methodNode =
666 methodNode->NextSiblingElement("method");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700667 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700668 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700669 interfaceNode =
670 interfaceNode->NextSiblingElement("interface");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700671 }
672 }
673 },
674 connectionName, transaction->path,
675 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700676}
677
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700678void handleAction(const crow::Request &req, crow::Response &res,
679 const std::string &objectPath, const std::string &methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700680{
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700681 BMCWEB_LOG_DEBUG << "handleAction on path: " << objectPath << " and method "
682 << methodName;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700683 nlohmann::json requestDbusData =
684 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700685
Ed Tanous1abe55e2018-09-05 08:30:59 -0700686 if (requestDbusData.is_discarded())
687 {
688 res.result(boost::beast::http::status::bad_request);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700689 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700690 return;
691 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700692 nlohmann::json::iterator data = requestDbusData.find("data");
693 if (data == requestDbusData.end())
694 {
695 res.result(boost::beast::http::status::bad_request);
696 res.end();
697 return;
698 }
699
700 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700701 {
702 res.result(boost::beast::http::status::bad_request);
703 res.end();
704 return;
705 }
706 auto transaction = std::make_shared<InProgressActionData>(res);
707
708 transaction->path = objectPath;
709 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700710 transaction->arguments = std::move(*data);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700711 crow::connections::systemBus->async_method_call(
712 [transaction](
713 const boost::system::error_code ec,
714 const std::vector<std::pair<std::string, std::vector<std::string>>>
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700715 &interfaceNames) {
716 if (ec || interfaceNames.size() <= 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700717 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700718 BMCWEB_LOG_ERROR << "Can't find object";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700719 transaction->setErrorStatus();
720 return;
721 }
722
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700723 BMCWEB_LOG_DEBUG << "GetObject returned " << interfaceNames.size()
724 << " object(s)";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700725
726 for (const std::pair<std::string, std::vector<std::string>>
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700727 &object : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700728 {
729 findActionOnInterface(transaction, object.first);
730 }
731 },
732 "xyz.openbmc_project.ObjectMapper",
733 "/xyz/openbmc_project/object_mapper",
734 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
735 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700736}
737
Ed Tanousf839dfe2018-11-12 11:11:15 -0800738void handleList(crow::Response &res, const std::string &objectPath,
739 int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700740{
741 crow::connections::systemBus->async_method_call(
742 [&res](const boost::system::error_code ec,
743 std::vector<std::string> &objectPaths) {
744 if (ec)
745 {
746 res.result(boost::beast::http::status::internal_server_error);
747 }
748 else
749 {
750 res.jsonValue = {{"status", "ok"},
751 {"message", "200 OK"},
752 {"data", std::move(objectPaths)}};
753 }
754 res.end();
755 },
756 "xyz.openbmc_project.ObjectMapper",
757 "/xyz/openbmc_project/object_mapper",
758 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", objectPath,
Ed Tanousf839dfe2018-11-12 11:11:15 -0800759 depth, std::array<std::string, 0>());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700760}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700761
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700762void handleEnumerate(crow::Response &res, const std::string &objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700763{
Ed Tanous049a0512018-11-01 13:58:42 -0700764 BMCWEB_LOG_DEBUG << "Doing enumerate on " << objectPath;
765 auto asyncResp = std::make_shared<bmcweb::AsyncResp>(res);
766
767 asyncResp->res.jsonValue = {{"message", "200 OK"},
768 {"status", "ok"},
769 {"data", nlohmann::json::object()}};
770
Ed Tanous1abe55e2018-09-05 08:30:59 -0700771 crow::connections::systemBus->async_method_call(
Ed Tanous049a0512018-11-01 13:58:42 -0700772 [asyncResp, objectPath](const boost::system::error_code ec,
773 const GetSubTreeType &object_names) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700774 if (ec)
775 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700776 return;
777 }
Ed Tanous049a0512018-11-01 13:58:42 -0700778 // Map indicating connection name, and the path where the object
779 // manager exists
780 boost::container::flat_map<std::string, std::string> connections;
Ed Tanous64530012018-02-06 17:08:16 -0800781
Ed Tanous1abe55e2018-09-05 08:30:59 -0700782 for (const auto &object : object_names)
783 {
Ed Tanous049a0512018-11-01 13:58:42 -0700784 for (const auto &connection : object.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700785 {
Ed Tanous049a0512018-11-01 13:58:42 -0700786 std::string &objectManagerPath =
787 connections[connection.first];
788 for (const auto &interface : connection.second)
789 {
790 BMCWEB_LOG_DEBUG << connection.first
791 << " has interface " << interface;
792 if (interface == "org.freedesktop.DBus.ObjectManager")
793 {
794 objectManagerPath = object.first;
795 }
796 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700797 }
798 }
Ed Tanous049a0512018-11-01 13:58:42 -0700799 BMCWEB_LOG_DEBUG << "Got " << connections.size() << " connections";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700800
Ed Tanous049a0512018-11-01 13:58:42 -0700801 for (const auto &connection : connections)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700802 {
Ed Tanous049a0512018-11-01 13:58:42 -0700803 // If we already know where the object manager is, we don't need
804 // to search for it, we can call directly in to
805 // getManagedObjects
806 if (!connection.second.empty())
807 {
808 getManagedObjectsForEnumerate(objectPath, connection.second,
809 connection.first, asyncResp);
810 }
811 else
812 {
813 // otherwise we need to find the object manager path before
814 // we can continue
815 findObjectManagerPathForEnumerate(
816 objectPath, connection.first, asyncResp);
817 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700818 }
819 },
820 "xyz.openbmc_project.ObjectMapper",
821 "/xyz/openbmc_project/object_mapper",
822 "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath,
Ed Tanous049a0512018-11-01 13:58:42 -0700823 static_cast<int32_t>(0), std::array<const char *, 0>());
Ed Tanous64530012018-02-06 17:08:16 -0800824}
Ed Tanous911ac312017-08-15 09:37:42 -0700825
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700826void handleGet(crow::Response &res, std::string &objectPath,
827 std::string &destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700828{
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700829 BMCWEB_LOG_DEBUG << "handleGet: " << objectPath << " prop:" << destProperty;
830 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700831 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -0700832
Ed Tanous1abe55e2018-09-05 08:30:59 -0700833 std::shared_ptr<std::string> path =
834 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -0700835
Ed Tanous1abe55e2018-09-05 08:30:59 -0700836 using GetObjectType =
837 std::vector<std::pair<std::string, std::vector<std::string>>>;
838 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700839 [&res, path, propertyName](const boost::system::error_code ec,
840 const GetObjectType &object_names) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700841 if (ec || object_names.size() <= 0)
842 {
843 res.result(boost::beast::http::status::not_found);
844 res.end();
845 return;
846 }
847 std::shared_ptr<nlohmann::json> response =
848 std::make_shared<nlohmann::json>(nlohmann::json::object());
849 // The mapper should never give us an empty interface names list,
850 // but check anyway
851 for (const std::pair<std::string, std::vector<std::string>>
852 connection : object_names)
853 {
854 const std::vector<std::string> &interfaceNames =
855 connection.second;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700856
Ed Tanous1abe55e2018-09-05 08:30:59 -0700857 if (interfaceNames.size() <= 0)
858 {
859 res.result(boost::beast::http::status::not_found);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700860 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700861 return;
862 }
863
864 for (const std::string &interface : interfaceNames)
865 {
866 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700867 [&res, response, propertyName](
Ed Tanous1abe55e2018-09-05 08:30:59 -0700868 const boost::system::error_code ec,
James Feist5b4aa862018-08-16 14:07:01 -0700869 const std::vector<std::pair<
870 std::string, dbus::utility::DbusVariantType>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700871 &properties) {
872 if (ec)
873 {
874 BMCWEB_LOG_ERROR << "Bad dbus request error: "
875 << ec;
876 }
877 else
878 {
James Feist5b4aa862018-08-16 14:07:01 -0700879 for (const std::pair<
880 std::string,
881 dbus::utility::DbusVariantType>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700882 &property : properties)
883 {
884 // if property name is empty, or matches our
885 // search query, add it to the response json
886
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700887 if (propertyName->empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700888 {
William A. Kennington III0a63b1c2018-10-18 13:37:19 -0700889 sdbusplus::message::variant_ns::visit(
Ed Tanous1abe55e2018-09-05 08:30:59 -0700890 [&response, &property](auto &&val) {
891 (*response)[property.first] =
892 val;
893 },
894 property.second);
895 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700896 else if (property.first == *propertyName)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700897 {
William A. Kennington III0a63b1c2018-10-18 13:37:19 -0700898 sdbusplus::message::variant_ns::visit(
Ed Tanous1abe55e2018-09-05 08:30:59 -0700899 [&response](auto &&val) {
900 (*response) = val;
901 },
902 property.second);
903 }
904 }
905 }
906 if (response.use_count() == 1)
907 {
908 res.jsonValue = {{"status", "ok"},
909 {"message", "200 OK"},
910 {"data", *response}};
911
912 res.end();
913 }
914 },
915 connection.first, *path,
916 "org.freedesktop.DBus.Properties", "GetAll", interface);
917 }
918 }
919 },
920 "xyz.openbmc_project.ObjectMapper",
921 "/xyz/openbmc_project/object_mapper",
922 "xyz.openbmc_project.ObjectMapper", "GetObject", *path,
923 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700924}
925
Ed Tanous1abe55e2018-09-05 08:30:59 -0700926struct AsyncPutRequest
927{
928 AsyncPutRequest(crow::Response &res) : res(res)
929 {
930 res.jsonValue = {
931 {"status", "ok"}, {"message", "200 OK"}, {"data", nullptr}};
932 }
933 ~AsyncPutRequest()
934 {
935 if (res.result() == boost::beast::http::status::internal_server_error)
936 {
937 // Reset the json object to clear out any data that made it in
938 // before the error happened todo(ed) handle error condition with
939 // proper code
940 res.jsonValue = nlohmann::json::object();
941 }
942
943 if (res.jsonValue.empty())
944 {
945 res.result(boost::beast::http::status::forbidden);
946 res.jsonValue = {
947 {"status", "error"},
948 {"message", "403 Forbidden"},
949 {"data",
950 {{"message", "The specified property cannot be created: " +
951 propertyName}}}};
952 }
953
954 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700955 }
956
Ed Tanous1abe55e2018-09-05 08:30:59 -0700957 void setErrorStatus()
958 {
959 res.result(boost::beast::http::status::internal_server_error);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700960 }
961
Ed Tanous1abe55e2018-09-05 08:30:59 -0700962 crow::Response &res;
963 std::string objectPath;
964 std::string propertyName;
965 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700966};
967
Ed Tanousd76323e2018-08-07 14:35:40 -0700968void handlePut(const crow::Request &req, crow::Response &res,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700969 const std::string &objectPath, const std::string &destProperty)
970{
971 nlohmann::json requestDbusData =
972 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700973
Ed Tanous1abe55e2018-09-05 08:30:59 -0700974 if (requestDbusData.is_discarded())
975 {
976 res.result(boost::beast::http::status::bad_request);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700977 res.end();
978 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700979 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700980
Ed Tanous1abe55e2018-09-05 08:30:59 -0700981 nlohmann::json::const_iterator propertyIt = requestDbusData.find("data");
982 if (propertyIt == requestDbusData.end())
983 {
984 res.result(boost::beast::http::status::bad_request);
985 res.end();
986 return;
987 }
988 const nlohmann::json &propertySetValue = *propertyIt;
989 auto transaction = std::make_shared<AsyncPutRequest>(res);
990 transaction->objectPath = objectPath;
991 transaction->propertyName = destProperty;
992 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -0700993
Ed Tanous1abe55e2018-09-05 08:30:59 -0700994 using GetObjectType =
995 std::vector<std::pair<std::string, std::vector<std::string>>>;
Ed Tanous911ac312017-08-15 09:37:42 -0700996
Ed Tanous1abe55e2018-09-05 08:30:59 -0700997 crow::connections::systemBus->async_method_call(
998 [transaction](const boost::system::error_code ec,
999 const GetObjectType &object_names) {
1000 if (!ec && object_names.size() <= 0)
1001 {
1002 transaction->res.result(boost::beast::http::status::not_found);
1003 return;
1004 }
Ed Tanous911ac312017-08-15 09:37:42 -07001005
Ed Tanous1abe55e2018-09-05 08:30:59 -07001006 for (const std::pair<std::string, std::vector<std::string>>
1007 connection : object_names)
1008 {
1009 const std::string &connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001010
Ed Tanous1abe55e2018-09-05 08:30:59 -07001011 crow::connections::systemBus->async_method_call(
1012 [connectionName{std::string(connectionName)},
1013 transaction](const boost::system::error_code ec,
1014 const std::string &introspectXml) {
1015 if (ec)
1016 {
1017 BMCWEB_LOG_ERROR
1018 << "Introspect call failed with error: "
1019 << ec.message()
1020 << " on process: " << connectionName;
1021 transaction->setErrorStatus();
1022 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001023 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001024 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001025
Ed Tanous1abe55e2018-09-05 08:30:59 -07001026 doc.Parse(introspectXml.c_str());
1027 tinyxml2::XMLNode *pRoot =
1028 doc.FirstChildElement("node");
1029 if (pRoot == nullptr)
1030 {
1031 BMCWEB_LOG_ERROR << "XML document failed to parse: "
1032 << introspectXml;
1033 transaction->setErrorStatus();
1034 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001035 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001036 tinyxml2::XMLElement *ifaceNode =
1037 pRoot->FirstChildElement("interface");
1038 while (ifaceNode != nullptr)
1039 {
1040 const char *interfaceName =
1041 ifaceNode->Attribute("name");
1042 BMCWEB_LOG_DEBUG << "found interface "
1043 << interfaceName;
1044 tinyxml2::XMLElement *propNode =
1045 ifaceNode->FirstChildElement("property");
1046 while (propNode != nullptr)
1047 {
1048 const char *propertyName =
1049 propNode->Attribute("name");
1050 BMCWEB_LOG_DEBUG << "Found property "
1051 << propertyName;
1052 if (propertyName == transaction->propertyName)
1053 {
1054 const char *argType =
1055 propNode->Attribute("type");
1056 if (argType != nullptr)
1057 {
1058 sdbusplus::message::message m =
1059 crow::connections::systemBus
1060 ->new_method_call(
1061 connectionName.c_str(),
1062 transaction->objectPath
1063 .c_str(),
1064 "org.freedesktop.DBus."
1065 "Properties",
1066 "Set");
1067 m.append(interfaceName,
1068 transaction->propertyName);
1069 int r = sd_bus_message_open_container(
1070 m.get(), SD_BUS_TYPE_VARIANT,
1071 argType);
1072 if (r < 0)
1073 {
1074 transaction->setErrorStatus();
1075 return;
1076 }
1077 r = convertJsonToDbus(
1078 m.get(), argType,
1079 transaction->propertyValue);
1080 if (r < 0)
1081 {
1082 transaction->setErrorStatus();
1083 return;
1084 }
1085 r = sd_bus_message_close_container(
1086 m.get());
1087 if (r < 0)
1088 {
1089 transaction->setErrorStatus();
1090 return;
1091 }
Ed Tanous911ac312017-08-15 09:37:42 -07001092
Ed Tanous1abe55e2018-09-05 08:30:59 -07001093 crow::connections::systemBus
1094 ->async_send(
1095 m,
1096 [transaction](
1097 boost::system::error_code
1098 ec,
1099 sdbusplus::message::message
1100 &m) {
1101 BMCWEB_LOG_DEBUG << "sent";
1102 if (ec)
1103 {
1104 transaction->res
1105 .jsonValue
1106 ["status"] =
1107 "error";
1108 transaction->res
1109 .jsonValue
1110 ["message"] =
1111 ec.message();
1112 }
1113 });
1114 }
1115 }
1116 propNode =
1117 propNode->NextSiblingElement("property");
1118 }
1119 ifaceNode =
1120 ifaceNode->NextSiblingElement("interface");
1121 }
1122 },
1123 connectionName, transaction->objectPath,
1124 "org.freedesktop.DBus.Introspectable", "Introspect");
1125 }
1126 },
1127 "xyz.openbmc_project.ObjectMapper",
1128 "/xyz/openbmc_project/object_mapper",
1129 "xyz.openbmc_project.ObjectMapper", "GetObject",
1130 transaction->objectPath, std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001131}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001132
Ed Tanous049a0512018-11-01 13:58:42 -07001133inline void handleDBusUrl(const crow::Request &req, crow::Response &res,
1134 std::string &objectPath)
1135{
Ed Tanous049a0512018-11-01 13:58:42 -07001136
1137 // If accessing a single attribute, fill in and update objectPath,
1138 // otherwise leave destProperty blank
1139 std::string destProperty = "";
1140 const char *attrSeperator = "/attr/";
1141 size_t attrPosition = objectPath.find(attrSeperator);
1142 if (attrPosition != objectPath.npos)
1143 {
1144 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
1145 objectPath.length());
1146 objectPath = objectPath.substr(0, attrPosition);
1147 }
1148
1149 if (req.method() == "POST"_method)
1150 {
1151 constexpr const char *actionSeperator = "/action/";
1152 size_t actionPosition = objectPath.find(actionSeperator);
1153 if (actionPosition != objectPath.npos)
1154 {
1155 std::string postProperty =
1156 objectPath.substr((actionPosition + strlen(actionSeperator)),
1157 objectPath.length());
1158 objectPath = objectPath.substr(0, actionPosition);
1159 handleAction(req, res, objectPath, postProperty);
1160 return;
1161 }
1162 }
1163 else if (req.method() == "GET"_method)
1164 {
1165 if (boost::ends_with(objectPath, "/enumerate"))
1166 {
1167 objectPath.erase(objectPath.end() - sizeof("enumerate"),
1168 objectPath.end());
1169 handleEnumerate(res, objectPath);
1170 }
1171 else if (boost::ends_with(objectPath, "/list"))
1172 {
1173 objectPath.erase(objectPath.end() - sizeof("list"),
1174 objectPath.end());
1175 handleList(res, objectPath);
1176 }
1177 else
1178 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08001179 // Trim any trailing "/" at the end
1180 if (boost::ends_with(objectPath, "/"))
1181 {
1182 objectPath.pop_back();
1183 handleList(res, objectPath, 1);
1184 }
1185 else
1186 {
1187 handleGet(res, objectPath, destProperty);
1188 }
Ed Tanous049a0512018-11-01 13:58:42 -07001189 }
1190 return;
1191 }
1192 else if (req.method() == "PUT"_method)
1193 {
1194 handlePut(req, res, objectPath, destProperty);
1195 return;
1196 }
1197
1198 res.result(boost::beast::http::status::method_not_allowed);
1199 res.end();
1200}
1201
Ed Tanous1abe55e2018-09-05 08:30:59 -07001202template <typename... Middlewares> void requestRoutes(Crow<Middlewares...> &app)
1203{
1204 BMCWEB_ROUTE(app, "/bus/")
1205 .methods("GET"_method)(
1206 [](const crow::Request &req, crow::Response &res) {
1207 res.jsonValue = {{"busses", {{{"name", "system"}}}},
1208 {"status", "ok"}};
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001209 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001210 });
1211
1212 BMCWEB_ROUTE(app, "/bus/system/")
1213 .methods("GET"_method)(
1214 [](const crow::Request &req, crow::Response &res) {
1215 auto myCallback = [&res](const boost::system::error_code ec,
1216 std::vector<std::string> &names) {
1217 if (ec)
1218 {
1219 BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
1220 res.result(
1221 boost::beast::http::status::internal_server_error);
1222 }
1223 else
1224 {
1225 std::sort(names.begin(), names.end());
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001226 res.jsonValue = {{"status", "ok"}};
1227 auto &objectsSub = res.jsonValue["objects"];
Ed Tanous1abe55e2018-09-05 08:30:59 -07001228 for (auto &name : names)
1229 {
1230 objectsSub.push_back({{"name", name}});
1231 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001232 }
1233 res.end();
1234 };
1235 crow::connections::systemBus->async_method_call(
1236 std::move(myCallback), "org.freedesktop.DBus", "/",
1237 "org.freedesktop.DBus", "ListNames");
1238 });
1239
1240 BMCWEB_ROUTE(app, "/list/")
1241 .methods("GET"_method)(
1242 [](const crow::Request &req, crow::Response &res) {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001243 handleList(res, "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001244 });
1245
1246 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous049a0512018-11-01 13:58:42 -07001247 .methods("GET"_method, "PUT"_method, "POST"_method)(
1248 [](const crow::Request &req, crow::Response &res,
1249 const std::string &path) {
1250 std::string objectPath = "/xyz/" + path;
1251 handleDBusUrl(req, res, objectPath);
1252 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001253
Ed Tanous049a0512018-11-01 13:58:42 -07001254 BMCWEB_ROUTE(app, "/org/<path>")
1255 .methods("GET"_method, "PUT"_method, "POST"_method)(
1256 [](const crow::Request &req, crow::Response &res,
1257 const std::string &path) {
1258 std::string objectPath = "/org/" + path;
1259 handleDBusUrl(req, res, objectPath);
1260 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001261
Ed Tanous1abe55e2018-09-05 08:30:59 -07001262 BMCWEB_ROUTE(app, "/download/dump/<str>/")
1263 .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
1264 const std::string &dumpId) {
1265 std::regex validFilename("^[\\w\\- ]+(\\.?[\\w\\- ]+)$");
1266 if (!std::regex_match(dumpId, validFilename))
1267 {
1268 res.result(boost::beast::http::status::not_found);
1269 res.end();
1270 return;
1271 }
1272 std::experimental::filesystem::path loc(
1273 "/var/lib/phosphor-debug-collector/dumps");
1274
1275 loc += dumpId;
1276
1277 if (!std::experimental::filesystem::exists(loc) ||
1278 !std::experimental::filesystem::is_directory(loc))
1279 {
1280 res.result(boost::beast::http::status::not_found);
1281 res.end();
1282 return;
1283 }
1284 std::experimental::filesystem::directory_iterator files(loc);
1285 for (auto &file : files)
1286 {
1287 std::ifstream readFile(file.path());
1288 if (readFile.good())
1289 {
1290 continue;
1291 }
1292 res.addHeader("Content-Type", "application/octet-stream");
1293 res.body() = {std::istreambuf_iterator<char>(readFile),
1294 std::istreambuf_iterator<char>()};
1295 res.end();
1296 }
1297 res.result(boost::beast::http::status::not_found);
1298 res.end();
1299 return;
1300 });
1301
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001302 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous1abe55e2018-09-05 08:30:59 -07001303 .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001304 const std::string &Connection) {
1305 introspectObjects(Connection, "/",
1306 std::make_shared<bmcweb::AsyncResp>(res));
1307 });
1308
1309 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
1310 .methods("GET"_method,
1311 "POST"_method)([](const crow::Request &req,
1312 crow::Response &res,
1313 const std::string &processName,
1314 const std::string &requestedPath) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001315 std::vector<std::string> strs;
1316 boost::split(strs, requestedPath, boost::is_any_of("/"));
1317 std::string objectPath;
1318 std::string interfaceName;
1319 std::string methodName;
1320 auto it = strs.begin();
1321 if (it == strs.end())
1322 {
1323 objectPath = "/";
1324 }
1325 while (it != strs.end())
1326 {
1327 // Check if segment contains ".". If it does, it must be an
1328 // interface
1329 if (it->find(".") != std::string::npos)
1330 {
1331 break;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001332 // This check is neccesary as the trailing slash gets parsed
Ed Tanous1abe55e2018-09-05 08:30:59 -07001333 // as part of our <path> specifier above, which causes the
1334 // normal trailing backslash redirector to fail.
1335 }
1336 else if (!it->empty())
1337 {
1338 objectPath += "/" + *it;
1339 }
1340 it++;
1341 }
1342 if (it != strs.end())
1343 {
1344 interfaceName = *it;
1345 it++;
1346
1347 // after interface, we might have a method name
1348 if (it != strs.end())
1349 {
1350 methodName = *it;
1351 it++;
1352 }
1353 }
1354 if (it != strs.end())
1355 {
1356 // if there is more levels past the method name, something went
1357 // wrong, return not found
1358 res.result(boost::beast::http::status::not_found);
1359 res.end();
1360 return;
1361 }
1362 if (interfaceName.empty())
1363 {
1364 crow::connections::systemBus->async_method_call(
1365 [&, processName,
1366 objectPath](const boost::system::error_code ec,
1367 const std::string &introspect_xml) {
1368 if (ec)
1369 {
1370 BMCWEB_LOG_ERROR
1371 << "Introspect call failed with error: "
1372 << ec.message()
1373 << " on process: " << processName
1374 << " path: " << objectPath << "\n";
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001375 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001376 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001377 tinyxml2::XMLDocument doc;
1378
1379 doc.Parse(introspect_xml.c_str());
1380 tinyxml2::XMLNode *pRoot =
1381 doc.FirstChildElement("node");
1382 if (pRoot == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001383 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001384 BMCWEB_LOG_ERROR << "XML document failed to parse "
1385 << processName << " " << objectPath
1386 << "\n";
1387 res.jsonValue = {{"status", "XML parse error"}};
1388 res.result(boost::beast::http::status::
1389 internal_server_error);
1390 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001391 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001392
1393 BMCWEB_LOG_DEBUG << introspect_xml;
1394 res.jsonValue = {{"status", "ok"},
1395 {"bus_name", processName},
1396 {"object_path", objectPath}};
1397 nlohmann::json &interfacesArray =
1398 res.jsonValue["interfaces"];
1399 interfacesArray = nlohmann::json::array();
1400 tinyxml2::XMLElement *interface =
1401 pRoot->FirstChildElement("interface");
1402
1403 while (interface != nullptr)
1404 {
1405 const char *ifaceName =
1406 interface->Attribute("name");
1407 if (ifaceName != nullptr)
1408 {
1409 interfacesArray.push_back(
1410 {{"name", ifaceName}});
1411 }
1412
1413 interface =
1414 interface->NextSiblingElement("interface");
1415 }
1416
Ed Tanous1abe55e2018-09-05 08:30:59 -07001417 res.end();
1418 },
1419 processName, objectPath,
1420 "org.freedesktop.DBus.Introspectable", "Introspect");
1421 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001422 else if (methodName.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001423 {
1424 crow::connections::systemBus->async_method_call(
1425 [&, processName, objectPath,
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001426 interfaceName{std::move(interfaceName)}](
Ed Tanous1abe55e2018-09-05 08:30:59 -07001427 const boost::system::error_code ec,
1428 const std::string &introspect_xml) {
1429 if (ec)
1430 {
1431 BMCWEB_LOG_ERROR
1432 << "Introspect call failed with error: "
1433 << ec.message()
1434 << " on process: " << processName
1435 << " path: " << objectPath << "\n";
1436 }
1437 else
1438 {
1439 tinyxml2::XMLDocument doc;
1440
1441 doc.Parse(introspect_xml.c_str());
1442 tinyxml2::XMLNode *pRoot =
1443 doc.FirstChildElement("node");
1444 if (pRoot == nullptr)
1445 {
1446 BMCWEB_LOG_ERROR
1447 << "XML document failed to parse "
1448 << processName << " " << objectPath << "\n";
1449 res.result(boost::beast::http::status::
1450 internal_server_error);
1451 }
1452 else
1453 {
1454 tinyxml2::XMLElement *node =
1455 pRoot->FirstChildElement("node");
1456
1457 // if we know we're the only call, build the
1458 // json directly
Ed Tanous1abe55e2018-09-05 08:30:59 -07001459 tinyxml2::XMLElement *interface =
1460 pRoot->FirstChildElement("interface");
1461
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001462 res.jsonValue = {
1463 {"status", "ok"},
1464 {"bus_name", processName},
1465 {"interface", interfaceName},
1466 {"object_path", objectPath},
1467 {"properties", nlohmann::json::object()}};
1468
1469 nlohmann::json &methodsArray =
1470 res.jsonValue["methods"];
1471 methodsArray = nlohmann::json::array();
1472
1473 nlohmann::json &signalsArray =
1474 res.jsonValue["signals"];
1475 signalsArray = nlohmann::json::array();
1476
Ed Tanous1abe55e2018-09-05 08:30:59 -07001477 while (interface != nullptr)
1478 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001479 const char *ifaceName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001480 interface->Attribute("name");
1481
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001482 if (ifaceName != nullptr &&
1483 ifaceName == interfaceName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001484 {
1485 tinyxml2::XMLElement *methods =
1486 interface->FirstChildElement(
1487 "method");
1488 while (methods != nullptr)
1489 {
1490 nlohmann::json argsArray =
1491 nlohmann::json::array();
1492 tinyxml2::XMLElement *arg =
1493 methods->FirstChildElement(
1494 "arg");
1495 while (arg != nullptr)
1496 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001497 nlohmann::json thisArg;
1498 for (const char *fieldName :
1499 std::array<const char *,
1500 3>{"name",
1501 "direction",
1502 "type"})
1503 {
1504 const char *fieldValue =
1505 arg->Attribute(
1506 fieldName);
1507 if (fieldValue != nullptr)
1508 {
1509 thisArg[fieldName] =
1510 fieldValue;
1511 }
1512 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001513 argsArray.push_back(
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001514 std::move(thisArg));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001515 arg = arg->NextSiblingElement(
1516 "arg");
1517 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001518
1519 const char *name =
1520 methods->Attribute("name");
1521 if (name != nullptr)
1522 {
1523 methodsArray.push_back(
1524 {{"name", name},
1525 {"uri", "/bus/system/" +
1526 processName +
1527 objectPath +
1528 "/" +
1529 interfaceName +
1530 "/" + name},
1531 {"args", argsArray}});
1532 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001533 methods =
1534 methods->NextSiblingElement(
1535 "method");
1536 }
1537 tinyxml2::XMLElement *signals =
1538 interface->FirstChildElement(
1539 "signal");
1540 while (signals != nullptr)
1541 {
1542 nlohmann::json argsArray =
1543 nlohmann::json::array();
1544
1545 tinyxml2::XMLElement *arg =
1546 signals->FirstChildElement(
1547 "arg");
1548 while (arg != nullptr)
1549 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001550 const char *name =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001551 arg->Attribute("name");
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001552 const char *type =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001553 arg->Attribute("type");
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001554 if (name != nullptr &&
1555 type != nullptr)
1556 {
1557 argsArray.push_back({
1558 {"name", name},
1559 {"type", type},
1560 });
1561 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001562 arg = arg->NextSiblingElement(
1563 "arg");
1564 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001565 const char *name =
1566 signals->Attribute("name");
1567 if (name != nullptr)
1568 {
1569 signalsArray.push_back(
1570 {{"name", name},
1571 {"args", argsArray}});
1572 }
1573
Ed Tanous1abe55e2018-09-05 08:30:59 -07001574 signals =
1575 signals->NextSiblingElement(
1576 "signal");
1577 }
1578
Ed Tanous1abe55e2018-09-05 08:30:59 -07001579 break;
1580 }
1581
1582 interface = interface->NextSiblingElement(
1583 "interface");
1584 }
1585 if (interface == nullptr)
1586 {
1587 // if we got to the end of the list and
1588 // never found a match, throw 404
1589 res.result(
1590 boost::beast::http::status::not_found);
1591 }
1592 }
1593 }
1594 res.end();
1595 },
1596 processName, objectPath,
1597 "org.freedesktop.DBus.Introspectable", "Introspect");
1598 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001599 else
1600 {
1601 if (req.method() != "POST"_method)
1602 {
1603 res.result(boost::beast::http::status::not_found);
1604 res.end();
1605 return;
1606 }
1607
1608 nlohmann::json requestDbusData =
1609 nlohmann::json::parse(req.body, nullptr, false);
1610
1611 if (requestDbusData.is_discarded())
1612 {
1613 res.result(boost::beast::http::status::bad_request);
1614 res.end();
1615 return;
1616 }
1617 if (!requestDbusData.is_array())
1618 {
1619 res.result(boost::beast::http::status::bad_request);
1620 res.end();
1621 return;
1622 }
1623 auto transaction = std::make_shared<InProgressActionData>(res);
1624
1625 transaction->path = objectPath;
1626 transaction->methodName = methodName;
1627 transaction->arguments = std::move(requestDbusData);
1628
1629 findActionOnInterface(transaction, processName);
1630 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001631 });
1632}
1633} // namespace openbmc_mapper
1634} // namespace crow