blob: 6cdc24bc2a359dc64c6d403410ad9093e7d5a0b0 [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 Tanouse3cb5a32018-08-08 14:16:49 -0700738void handleList(crow::Response &res, const std::string &objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700739{
740 crow::connections::systemBus->async_method_call(
741 [&res](const boost::system::error_code ec,
742 std::vector<std::string> &objectPaths) {
743 if (ec)
744 {
745 res.result(boost::beast::http::status::internal_server_error);
746 }
747 else
748 {
749 res.jsonValue = {{"status", "ok"},
750 {"message", "200 OK"},
751 {"data", std::move(objectPaths)}};
752 }
753 res.end();
754 },
755 "xyz.openbmc_project.ObjectMapper",
756 "/xyz/openbmc_project/object_mapper",
757 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", objectPath,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700758 static_cast<int32_t>(0), std::array<std::string, 0>());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700759}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700760
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700761void handleEnumerate(crow::Response &res, const std::string &objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700762{
Ed Tanous049a0512018-11-01 13:58:42 -0700763 BMCWEB_LOG_DEBUG << "Doing enumerate on " << objectPath;
764 auto asyncResp = std::make_shared<bmcweb::AsyncResp>(res);
765
766 asyncResp->res.jsonValue = {{"message", "200 OK"},
767 {"status", "ok"},
768 {"data", nlohmann::json::object()}};
769
Ed Tanous1abe55e2018-09-05 08:30:59 -0700770 crow::connections::systemBus->async_method_call(
Ed Tanous049a0512018-11-01 13:58:42 -0700771 [asyncResp, objectPath](const boost::system::error_code ec,
772 const GetSubTreeType &object_names) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700773 if (ec)
774 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700775 return;
776 }
Ed Tanous049a0512018-11-01 13:58:42 -0700777 // Map indicating connection name, and the path where the object
778 // manager exists
779 boost::container::flat_map<std::string, std::string> connections;
Ed Tanous64530012018-02-06 17:08:16 -0800780
Ed Tanous1abe55e2018-09-05 08:30:59 -0700781 for (const auto &object : object_names)
782 {
Ed Tanous049a0512018-11-01 13:58:42 -0700783 for (const auto &connection : object.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700784 {
Ed Tanous049a0512018-11-01 13:58:42 -0700785 std::string &objectManagerPath =
786 connections[connection.first];
787 for (const auto &interface : connection.second)
788 {
789 BMCWEB_LOG_DEBUG << connection.first
790 << " has interface " << interface;
791 if (interface == "org.freedesktop.DBus.ObjectManager")
792 {
793 objectManagerPath = object.first;
794 }
795 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700796 }
797 }
Ed Tanous049a0512018-11-01 13:58:42 -0700798 BMCWEB_LOG_DEBUG << "Got " << connections.size() << " connections";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700799
Ed Tanous049a0512018-11-01 13:58:42 -0700800 for (const auto &connection : connections)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700801 {
Ed Tanous049a0512018-11-01 13:58:42 -0700802 // If we already know where the object manager is, we don't need
803 // to search for it, we can call directly in to
804 // getManagedObjects
805 if (!connection.second.empty())
806 {
807 getManagedObjectsForEnumerate(objectPath, connection.second,
808 connection.first, asyncResp);
809 }
810 else
811 {
812 // otherwise we need to find the object manager path before
813 // we can continue
814 findObjectManagerPathForEnumerate(
815 objectPath, connection.first, asyncResp);
816 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700817 }
818 },
819 "xyz.openbmc_project.ObjectMapper",
820 "/xyz/openbmc_project/object_mapper",
821 "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath,
Ed Tanous049a0512018-11-01 13:58:42 -0700822 static_cast<int32_t>(0), std::array<const char *, 0>());
Ed Tanous64530012018-02-06 17:08:16 -0800823}
Ed Tanous911ac312017-08-15 09:37:42 -0700824
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700825void handleGet(crow::Response &res, std::string &objectPath,
826 std::string &destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700827{
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700828 BMCWEB_LOG_DEBUG << "handleGet: " << objectPath << " prop:" << destProperty;
829 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700830 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -0700831
Ed Tanous1abe55e2018-09-05 08:30:59 -0700832 std::shared_ptr<std::string> path =
833 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -0700834
Ed Tanous1abe55e2018-09-05 08:30:59 -0700835 using GetObjectType =
836 std::vector<std::pair<std::string, std::vector<std::string>>>;
837 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700838 [&res, path, propertyName](const boost::system::error_code ec,
839 const GetObjectType &object_names) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700840 if (ec || object_names.size() <= 0)
841 {
842 res.result(boost::beast::http::status::not_found);
843 res.end();
844 return;
845 }
846 std::shared_ptr<nlohmann::json> response =
847 std::make_shared<nlohmann::json>(nlohmann::json::object());
848 // The mapper should never give us an empty interface names list,
849 // but check anyway
850 for (const std::pair<std::string, std::vector<std::string>>
851 connection : object_names)
852 {
853 const std::vector<std::string> &interfaceNames =
854 connection.second;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700855
Ed Tanous1abe55e2018-09-05 08:30:59 -0700856 if (interfaceNames.size() <= 0)
857 {
858 res.result(boost::beast::http::status::not_found);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700859 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700860 return;
861 }
862
863 for (const std::string &interface : interfaceNames)
864 {
865 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700866 [&res, response, propertyName](
Ed Tanous1abe55e2018-09-05 08:30:59 -0700867 const boost::system::error_code ec,
James Feist5b4aa862018-08-16 14:07:01 -0700868 const std::vector<std::pair<
869 std::string, dbus::utility::DbusVariantType>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700870 &properties) {
871 if (ec)
872 {
873 BMCWEB_LOG_ERROR << "Bad dbus request error: "
874 << ec;
875 }
876 else
877 {
James Feist5b4aa862018-08-16 14:07:01 -0700878 for (const std::pair<
879 std::string,
880 dbus::utility::DbusVariantType>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700881 &property : properties)
882 {
883 // if property name is empty, or matches our
884 // search query, add it to the response json
885
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700886 if (propertyName->empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700887 {
William A. Kennington III0a63b1c2018-10-18 13:37:19 -0700888 sdbusplus::message::variant_ns::visit(
Ed Tanous1abe55e2018-09-05 08:30:59 -0700889 [&response, &property](auto &&val) {
890 (*response)[property.first] =
891 val;
892 },
893 property.second);
894 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700895 else if (property.first == *propertyName)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700896 {
William A. Kennington III0a63b1c2018-10-18 13:37:19 -0700897 sdbusplus::message::variant_ns::visit(
Ed Tanous1abe55e2018-09-05 08:30:59 -0700898 [&response](auto &&val) {
899 (*response) = val;
900 },
901 property.second);
902 }
903 }
904 }
905 if (response.use_count() == 1)
906 {
907 res.jsonValue = {{"status", "ok"},
908 {"message", "200 OK"},
909 {"data", *response}};
910
911 res.end();
912 }
913 },
914 connection.first, *path,
915 "org.freedesktop.DBus.Properties", "GetAll", interface);
916 }
917 }
918 },
919 "xyz.openbmc_project.ObjectMapper",
920 "/xyz/openbmc_project/object_mapper",
921 "xyz.openbmc_project.ObjectMapper", "GetObject", *path,
922 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700923}
924
Ed Tanous1abe55e2018-09-05 08:30:59 -0700925struct AsyncPutRequest
926{
927 AsyncPutRequest(crow::Response &res) : res(res)
928 {
929 res.jsonValue = {
930 {"status", "ok"}, {"message", "200 OK"}, {"data", nullptr}};
931 }
932 ~AsyncPutRequest()
933 {
934 if (res.result() == boost::beast::http::status::internal_server_error)
935 {
936 // Reset the json object to clear out any data that made it in
937 // before the error happened todo(ed) handle error condition with
938 // proper code
939 res.jsonValue = nlohmann::json::object();
940 }
941
942 if (res.jsonValue.empty())
943 {
944 res.result(boost::beast::http::status::forbidden);
945 res.jsonValue = {
946 {"status", "error"},
947 {"message", "403 Forbidden"},
948 {"data",
949 {{"message", "The specified property cannot be created: " +
950 propertyName}}}};
951 }
952
953 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700954 }
955
Ed Tanous1abe55e2018-09-05 08:30:59 -0700956 void setErrorStatus()
957 {
958 res.result(boost::beast::http::status::internal_server_error);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700959 }
960
Ed Tanous1abe55e2018-09-05 08:30:59 -0700961 crow::Response &res;
962 std::string objectPath;
963 std::string propertyName;
964 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700965};
966
Ed Tanousd76323e2018-08-07 14:35:40 -0700967void handlePut(const crow::Request &req, crow::Response &res,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700968 const std::string &objectPath, const std::string &destProperty)
969{
970 nlohmann::json requestDbusData =
971 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700972
Ed Tanous1abe55e2018-09-05 08:30:59 -0700973 if (requestDbusData.is_discarded())
974 {
975 res.result(boost::beast::http::status::bad_request);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700976 res.end();
977 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700978 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700979
Ed Tanous1abe55e2018-09-05 08:30:59 -0700980 nlohmann::json::const_iterator propertyIt = requestDbusData.find("data");
981 if (propertyIt == requestDbusData.end())
982 {
983 res.result(boost::beast::http::status::bad_request);
984 res.end();
985 return;
986 }
987 const nlohmann::json &propertySetValue = *propertyIt;
988 auto transaction = std::make_shared<AsyncPutRequest>(res);
989 transaction->objectPath = objectPath;
990 transaction->propertyName = destProperty;
991 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -0700992
Ed Tanous1abe55e2018-09-05 08:30:59 -0700993 using GetObjectType =
994 std::vector<std::pair<std::string, std::vector<std::string>>>;
Ed Tanous911ac312017-08-15 09:37:42 -0700995
Ed Tanous1abe55e2018-09-05 08:30:59 -0700996 crow::connections::systemBus->async_method_call(
997 [transaction](const boost::system::error_code ec,
998 const GetObjectType &object_names) {
999 if (!ec && object_names.size() <= 0)
1000 {
1001 transaction->res.result(boost::beast::http::status::not_found);
1002 return;
1003 }
Ed Tanous911ac312017-08-15 09:37:42 -07001004
Ed Tanous1abe55e2018-09-05 08:30:59 -07001005 for (const std::pair<std::string, std::vector<std::string>>
1006 connection : object_names)
1007 {
1008 const std::string &connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001009
Ed Tanous1abe55e2018-09-05 08:30:59 -07001010 crow::connections::systemBus->async_method_call(
1011 [connectionName{std::string(connectionName)},
1012 transaction](const boost::system::error_code ec,
1013 const std::string &introspectXml) {
1014 if (ec)
1015 {
1016 BMCWEB_LOG_ERROR
1017 << "Introspect call failed with error: "
1018 << ec.message()
1019 << " on process: " << connectionName;
1020 transaction->setErrorStatus();
1021 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001022 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001023 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001024
Ed Tanous1abe55e2018-09-05 08:30:59 -07001025 doc.Parse(introspectXml.c_str());
1026 tinyxml2::XMLNode *pRoot =
1027 doc.FirstChildElement("node");
1028 if (pRoot == nullptr)
1029 {
1030 BMCWEB_LOG_ERROR << "XML document failed to parse: "
1031 << introspectXml;
1032 transaction->setErrorStatus();
1033 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001034 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001035 tinyxml2::XMLElement *ifaceNode =
1036 pRoot->FirstChildElement("interface");
1037 while (ifaceNode != nullptr)
1038 {
1039 const char *interfaceName =
1040 ifaceNode->Attribute("name");
1041 BMCWEB_LOG_DEBUG << "found interface "
1042 << interfaceName;
1043 tinyxml2::XMLElement *propNode =
1044 ifaceNode->FirstChildElement("property");
1045 while (propNode != nullptr)
1046 {
1047 const char *propertyName =
1048 propNode->Attribute("name");
1049 BMCWEB_LOG_DEBUG << "Found property "
1050 << propertyName;
1051 if (propertyName == transaction->propertyName)
1052 {
1053 const char *argType =
1054 propNode->Attribute("type");
1055 if (argType != nullptr)
1056 {
1057 sdbusplus::message::message m =
1058 crow::connections::systemBus
1059 ->new_method_call(
1060 connectionName.c_str(),
1061 transaction->objectPath
1062 .c_str(),
1063 "org.freedesktop.DBus."
1064 "Properties",
1065 "Set");
1066 m.append(interfaceName,
1067 transaction->propertyName);
1068 int r = sd_bus_message_open_container(
1069 m.get(), SD_BUS_TYPE_VARIANT,
1070 argType);
1071 if (r < 0)
1072 {
1073 transaction->setErrorStatus();
1074 return;
1075 }
1076 r = convertJsonToDbus(
1077 m.get(), argType,
1078 transaction->propertyValue);
1079 if (r < 0)
1080 {
1081 transaction->setErrorStatus();
1082 return;
1083 }
1084 r = sd_bus_message_close_container(
1085 m.get());
1086 if (r < 0)
1087 {
1088 transaction->setErrorStatus();
1089 return;
1090 }
Ed Tanous911ac312017-08-15 09:37:42 -07001091
Ed Tanous1abe55e2018-09-05 08:30:59 -07001092 crow::connections::systemBus
1093 ->async_send(
1094 m,
1095 [transaction](
1096 boost::system::error_code
1097 ec,
1098 sdbusplus::message::message
1099 &m) {
1100 BMCWEB_LOG_DEBUG << "sent";
1101 if (ec)
1102 {
1103 transaction->res
1104 .jsonValue
1105 ["status"] =
1106 "error";
1107 transaction->res
1108 .jsonValue
1109 ["message"] =
1110 ec.message();
1111 }
1112 });
1113 }
1114 }
1115 propNode =
1116 propNode->NextSiblingElement("property");
1117 }
1118 ifaceNode =
1119 ifaceNode->NextSiblingElement("interface");
1120 }
1121 },
1122 connectionName, transaction->objectPath,
1123 "org.freedesktop.DBus.Introspectable", "Introspect");
1124 }
1125 },
1126 "xyz.openbmc_project.ObjectMapper",
1127 "/xyz/openbmc_project/object_mapper",
1128 "xyz.openbmc_project.ObjectMapper", "GetObject",
1129 transaction->objectPath, std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001130}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001131
Ed Tanous049a0512018-11-01 13:58:42 -07001132inline void handleDBusUrl(const crow::Request &req, crow::Response &res,
1133 std::string &objectPath)
1134{
1135 // Trim any trailing "/" at the end
1136 if (boost::ends_with(objectPath, "/"))
1137 {
1138 objectPath.pop_back();
1139 }
1140
1141 // If accessing a single attribute, fill in and update objectPath,
1142 // otherwise leave destProperty blank
1143 std::string destProperty = "";
1144 const char *attrSeperator = "/attr/";
1145 size_t attrPosition = objectPath.find(attrSeperator);
1146 if (attrPosition != objectPath.npos)
1147 {
1148 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
1149 objectPath.length());
1150 objectPath = objectPath.substr(0, attrPosition);
1151 }
1152
1153 if (req.method() == "POST"_method)
1154 {
1155 constexpr const char *actionSeperator = "/action/";
1156 size_t actionPosition = objectPath.find(actionSeperator);
1157 if (actionPosition != objectPath.npos)
1158 {
1159 std::string postProperty =
1160 objectPath.substr((actionPosition + strlen(actionSeperator)),
1161 objectPath.length());
1162 objectPath = objectPath.substr(0, actionPosition);
1163 handleAction(req, res, objectPath, postProperty);
1164 return;
1165 }
1166 }
1167 else if (req.method() == "GET"_method)
1168 {
1169 if (boost::ends_with(objectPath, "/enumerate"))
1170 {
1171 objectPath.erase(objectPath.end() - sizeof("enumerate"),
1172 objectPath.end());
1173 handleEnumerate(res, objectPath);
1174 }
1175 else if (boost::ends_with(objectPath, "/list"))
1176 {
1177 objectPath.erase(objectPath.end() - sizeof("list"),
1178 objectPath.end());
1179 handleList(res, objectPath);
1180 }
1181 else
1182 {
1183 handleGet(res, objectPath, destProperty);
1184 }
1185 return;
1186 }
1187 else if (req.method() == "PUT"_method)
1188 {
1189 handlePut(req, res, objectPath, destProperty);
1190 return;
1191 }
1192
1193 res.result(boost::beast::http::status::method_not_allowed);
1194 res.end();
1195}
1196
Ed Tanous1abe55e2018-09-05 08:30:59 -07001197template <typename... Middlewares> void requestRoutes(Crow<Middlewares...> &app)
1198{
1199 BMCWEB_ROUTE(app, "/bus/")
1200 .methods("GET"_method)(
1201 [](const crow::Request &req, crow::Response &res) {
1202 res.jsonValue = {{"busses", {{{"name", "system"}}}},
1203 {"status", "ok"}};
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001204 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001205 });
1206
1207 BMCWEB_ROUTE(app, "/bus/system/")
1208 .methods("GET"_method)(
1209 [](const crow::Request &req, crow::Response &res) {
1210 auto myCallback = [&res](const boost::system::error_code ec,
1211 std::vector<std::string> &names) {
1212 if (ec)
1213 {
1214 BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
1215 res.result(
1216 boost::beast::http::status::internal_server_error);
1217 }
1218 else
1219 {
1220 std::sort(names.begin(), names.end());
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001221 res.jsonValue = {{"status", "ok"}};
1222 auto &objectsSub = res.jsonValue["objects"];
Ed Tanous1abe55e2018-09-05 08:30:59 -07001223 for (auto &name : names)
1224 {
1225 objectsSub.push_back({{"name", name}});
1226 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001227 }
1228 res.end();
1229 };
1230 crow::connections::systemBus->async_method_call(
1231 std::move(myCallback), "org.freedesktop.DBus", "/",
1232 "org.freedesktop.DBus", "ListNames");
1233 });
1234
1235 BMCWEB_ROUTE(app, "/list/")
1236 .methods("GET"_method)(
1237 [](const crow::Request &req, crow::Response &res) {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001238 handleList(res, "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001239 });
1240
1241 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous049a0512018-11-01 13:58:42 -07001242 .methods("GET"_method, "PUT"_method, "POST"_method)(
1243 [](const crow::Request &req, crow::Response &res,
1244 const std::string &path) {
1245 std::string objectPath = "/xyz/" + path;
1246 handleDBusUrl(req, res, objectPath);
1247 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001248
Ed Tanous049a0512018-11-01 13:58:42 -07001249 BMCWEB_ROUTE(app, "/org/<path>")
1250 .methods("GET"_method, "PUT"_method, "POST"_method)(
1251 [](const crow::Request &req, crow::Response &res,
1252 const std::string &path) {
1253 std::string objectPath = "/org/" + path;
1254 handleDBusUrl(req, res, objectPath);
1255 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001256
Ed Tanous1abe55e2018-09-05 08:30:59 -07001257 BMCWEB_ROUTE(app, "/download/dump/<str>/")
1258 .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
1259 const std::string &dumpId) {
1260 std::regex validFilename("^[\\w\\- ]+(\\.?[\\w\\- ]+)$");
1261 if (!std::regex_match(dumpId, validFilename))
1262 {
1263 res.result(boost::beast::http::status::not_found);
1264 res.end();
1265 return;
1266 }
1267 std::experimental::filesystem::path loc(
1268 "/var/lib/phosphor-debug-collector/dumps");
1269
1270 loc += dumpId;
1271
1272 if (!std::experimental::filesystem::exists(loc) ||
1273 !std::experimental::filesystem::is_directory(loc))
1274 {
1275 res.result(boost::beast::http::status::not_found);
1276 res.end();
1277 return;
1278 }
1279 std::experimental::filesystem::directory_iterator files(loc);
1280 for (auto &file : files)
1281 {
1282 std::ifstream readFile(file.path());
1283 if (readFile.good())
1284 {
1285 continue;
1286 }
1287 res.addHeader("Content-Type", "application/octet-stream");
1288 res.body() = {std::istreambuf_iterator<char>(readFile),
1289 std::istreambuf_iterator<char>()};
1290 res.end();
1291 }
1292 res.result(boost::beast::http::status::not_found);
1293 res.end();
1294 return;
1295 });
1296
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001297 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous1abe55e2018-09-05 08:30:59 -07001298 .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001299 const std::string &Connection) {
1300 introspectObjects(Connection, "/",
1301 std::make_shared<bmcweb::AsyncResp>(res));
1302 });
1303
1304 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
1305 .methods("GET"_method,
1306 "POST"_method)([](const crow::Request &req,
1307 crow::Response &res,
1308 const std::string &processName,
1309 const std::string &requestedPath) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001310 std::vector<std::string> strs;
1311 boost::split(strs, requestedPath, boost::is_any_of("/"));
1312 std::string objectPath;
1313 std::string interfaceName;
1314 std::string methodName;
1315 auto it = strs.begin();
1316 if (it == strs.end())
1317 {
1318 objectPath = "/";
1319 }
1320 while (it != strs.end())
1321 {
1322 // Check if segment contains ".". If it does, it must be an
1323 // interface
1324 if (it->find(".") != std::string::npos)
1325 {
1326 break;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001327 // This check is neccesary as the trailing slash gets parsed
Ed Tanous1abe55e2018-09-05 08:30:59 -07001328 // as part of our <path> specifier above, which causes the
1329 // normal trailing backslash redirector to fail.
1330 }
1331 else if (!it->empty())
1332 {
1333 objectPath += "/" + *it;
1334 }
1335 it++;
1336 }
1337 if (it != strs.end())
1338 {
1339 interfaceName = *it;
1340 it++;
1341
1342 // after interface, we might have a method name
1343 if (it != strs.end())
1344 {
1345 methodName = *it;
1346 it++;
1347 }
1348 }
1349 if (it != strs.end())
1350 {
1351 // if there is more levels past the method name, something went
1352 // wrong, return not found
1353 res.result(boost::beast::http::status::not_found);
1354 res.end();
1355 return;
1356 }
1357 if (interfaceName.empty())
1358 {
1359 crow::connections::systemBus->async_method_call(
1360 [&, processName,
1361 objectPath](const boost::system::error_code ec,
1362 const std::string &introspect_xml) {
1363 if (ec)
1364 {
1365 BMCWEB_LOG_ERROR
1366 << "Introspect call failed with error: "
1367 << ec.message()
1368 << " on process: " << processName
1369 << " path: " << objectPath << "\n";
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001370 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001371 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001372 tinyxml2::XMLDocument doc;
1373
1374 doc.Parse(introspect_xml.c_str());
1375 tinyxml2::XMLNode *pRoot =
1376 doc.FirstChildElement("node");
1377 if (pRoot == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001378 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001379 BMCWEB_LOG_ERROR << "XML document failed to parse "
1380 << processName << " " << objectPath
1381 << "\n";
1382 res.jsonValue = {{"status", "XML parse error"}};
1383 res.result(boost::beast::http::status::
1384 internal_server_error);
1385 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001386 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001387
1388 BMCWEB_LOG_DEBUG << introspect_xml;
1389 res.jsonValue = {{"status", "ok"},
1390 {"bus_name", processName},
1391 {"object_path", objectPath}};
1392 nlohmann::json &interfacesArray =
1393 res.jsonValue["interfaces"];
1394 interfacesArray = nlohmann::json::array();
1395 tinyxml2::XMLElement *interface =
1396 pRoot->FirstChildElement("interface");
1397
1398 while (interface != nullptr)
1399 {
1400 const char *ifaceName =
1401 interface->Attribute("name");
1402 if (ifaceName != nullptr)
1403 {
1404 interfacesArray.push_back(
1405 {{"name", ifaceName}});
1406 }
1407
1408 interface =
1409 interface->NextSiblingElement("interface");
1410 }
1411
Ed Tanous1abe55e2018-09-05 08:30:59 -07001412 res.end();
1413 },
1414 processName, objectPath,
1415 "org.freedesktop.DBus.Introspectable", "Introspect");
1416 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001417 else if (methodName.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001418 {
1419 crow::connections::systemBus->async_method_call(
1420 [&, processName, objectPath,
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001421 interfaceName{std::move(interfaceName)}](
Ed Tanous1abe55e2018-09-05 08:30:59 -07001422 const boost::system::error_code ec,
1423 const std::string &introspect_xml) {
1424 if (ec)
1425 {
1426 BMCWEB_LOG_ERROR
1427 << "Introspect call failed with error: "
1428 << ec.message()
1429 << " on process: " << processName
1430 << " path: " << objectPath << "\n";
1431 }
1432 else
1433 {
1434 tinyxml2::XMLDocument doc;
1435
1436 doc.Parse(introspect_xml.c_str());
1437 tinyxml2::XMLNode *pRoot =
1438 doc.FirstChildElement("node");
1439 if (pRoot == nullptr)
1440 {
1441 BMCWEB_LOG_ERROR
1442 << "XML document failed to parse "
1443 << processName << " " << objectPath << "\n";
1444 res.result(boost::beast::http::status::
1445 internal_server_error);
1446 }
1447 else
1448 {
1449 tinyxml2::XMLElement *node =
1450 pRoot->FirstChildElement("node");
1451
1452 // if we know we're the only call, build the
1453 // json directly
Ed Tanous1abe55e2018-09-05 08:30:59 -07001454 tinyxml2::XMLElement *interface =
1455 pRoot->FirstChildElement("interface");
1456
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001457 res.jsonValue = {
1458 {"status", "ok"},
1459 {"bus_name", processName},
1460 {"interface", interfaceName},
1461 {"object_path", objectPath},
1462 {"properties", nlohmann::json::object()}};
1463
1464 nlohmann::json &methodsArray =
1465 res.jsonValue["methods"];
1466 methodsArray = nlohmann::json::array();
1467
1468 nlohmann::json &signalsArray =
1469 res.jsonValue["signals"];
1470 signalsArray = nlohmann::json::array();
1471
Ed Tanous1abe55e2018-09-05 08:30:59 -07001472 while (interface != nullptr)
1473 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001474 const char *ifaceName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001475 interface->Attribute("name");
1476
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001477 if (ifaceName != nullptr &&
1478 ifaceName == interfaceName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001479 {
1480 tinyxml2::XMLElement *methods =
1481 interface->FirstChildElement(
1482 "method");
1483 while (methods != nullptr)
1484 {
1485 nlohmann::json argsArray =
1486 nlohmann::json::array();
1487 tinyxml2::XMLElement *arg =
1488 methods->FirstChildElement(
1489 "arg");
1490 while (arg != nullptr)
1491 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001492 nlohmann::json thisArg;
1493 for (const char *fieldName :
1494 std::array<const char *,
1495 3>{"name",
1496 "direction",
1497 "type"})
1498 {
1499 const char *fieldValue =
1500 arg->Attribute(
1501 fieldName);
1502 if (fieldValue != nullptr)
1503 {
1504 thisArg[fieldName] =
1505 fieldValue;
1506 }
1507 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001508 argsArray.push_back(
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001509 std::move(thisArg));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001510 arg = arg->NextSiblingElement(
1511 "arg");
1512 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001513
1514 const char *name =
1515 methods->Attribute("name");
1516 if (name != nullptr)
1517 {
1518 methodsArray.push_back(
1519 {{"name", name},
1520 {"uri", "/bus/system/" +
1521 processName +
1522 objectPath +
1523 "/" +
1524 interfaceName +
1525 "/" + name},
1526 {"args", argsArray}});
1527 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001528 methods =
1529 methods->NextSiblingElement(
1530 "method");
1531 }
1532 tinyxml2::XMLElement *signals =
1533 interface->FirstChildElement(
1534 "signal");
1535 while (signals != nullptr)
1536 {
1537 nlohmann::json argsArray =
1538 nlohmann::json::array();
1539
1540 tinyxml2::XMLElement *arg =
1541 signals->FirstChildElement(
1542 "arg");
1543 while (arg != nullptr)
1544 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001545 const char *name =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001546 arg->Attribute("name");
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001547 const char *type =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001548 arg->Attribute("type");
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001549 if (name != nullptr &&
1550 type != nullptr)
1551 {
1552 argsArray.push_back({
1553 {"name", name},
1554 {"type", type},
1555 });
1556 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001557 arg = arg->NextSiblingElement(
1558 "arg");
1559 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001560 const char *name =
1561 signals->Attribute("name");
1562 if (name != nullptr)
1563 {
1564 signalsArray.push_back(
1565 {{"name", name},
1566 {"args", argsArray}});
1567 }
1568
Ed Tanous1abe55e2018-09-05 08:30:59 -07001569 signals =
1570 signals->NextSiblingElement(
1571 "signal");
1572 }
1573
Ed Tanous1abe55e2018-09-05 08:30:59 -07001574 break;
1575 }
1576
1577 interface = interface->NextSiblingElement(
1578 "interface");
1579 }
1580 if (interface == nullptr)
1581 {
1582 // if we got to the end of the list and
1583 // never found a match, throw 404
1584 res.result(
1585 boost::beast::http::status::not_found);
1586 }
1587 }
1588 }
1589 res.end();
1590 },
1591 processName, objectPath,
1592 "org.freedesktop.DBus.Introspectable", "Introspect");
1593 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001594 else
1595 {
1596 if (req.method() != "POST"_method)
1597 {
1598 res.result(boost::beast::http::status::not_found);
1599 res.end();
1600 return;
1601 }
1602
1603 nlohmann::json requestDbusData =
1604 nlohmann::json::parse(req.body, nullptr, false);
1605
1606 if (requestDbusData.is_discarded())
1607 {
1608 res.result(boost::beast::http::status::bad_request);
1609 res.end();
1610 return;
1611 }
1612 if (!requestDbusData.is_array())
1613 {
1614 res.result(boost::beast::http::status::bad_request);
1615 res.end();
1616 return;
1617 }
1618 auto transaction = std::make_shared<InProgressActionData>(res);
1619
1620 transaction->path = objectPath;
1621 transaction->methodName = methodName;
1622 transaction->arguments = std::move(requestDbusData);
1623
1624 findActionOnInterface(transaction, processName);
1625 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001626 });
1627}
1628} // namespace openbmc_mapper
1629} // namespace crow