blob: 73c6f37ce215633e7b0dd2bac42b02953ccceb3a [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
Matt Spinler3ae4ba72018-12-05 14:01:22 -060033using GetSubTreeType = std::vector<
34 std::pair<std::string,
35 std::vector<std::pair<std::string, std::vector<std::string>>>>>;
36
Ed Tanouse3cb5a32018-08-08 14:16:49 -070037void introspectObjects(const std::string &processName,
38 const std::string &objectPath,
39 std::shared_ptr<bmcweb::AsyncResp> transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -070040{
Ed Tanouse3cb5a32018-08-08 14:16:49 -070041 if (transaction->res.jsonValue.is_null())
42 {
43 transaction->res.jsonValue = {{"status", "ok"},
44 {"bus_name", processName},
45 {"objects", nlohmann::json::array()}};
46 }
47
Ed Tanous1abe55e2018-09-05 08:30:59 -070048 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -070049 [transaction, processName{std::string(processName)},
50 objectPath{std::string(objectPath)}](
51 const boost::system::error_code ec,
52 const std::string &introspect_xml) {
Ed Tanous1abe55e2018-09-05 08:30:59 -070053 if (ec)
54 {
55 BMCWEB_LOG_ERROR
56 << "Introspect call failed with error: " << ec.message()
57 << " on process: " << processName << " path: " << objectPath
58 << "\n";
Ed Tanouse3cb5a32018-08-08 14:16:49 -070059 return;
60 }
61 transaction->res.jsonValue["objects"].push_back(
62 {{"path", objectPath}});
63
64 tinyxml2::XMLDocument doc;
65
66 doc.Parse(introspect_xml.c_str());
67 tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
68 if (pRoot == nullptr)
69 {
70 BMCWEB_LOG_ERROR << "XML document failed to parse "
71 << processName << " " << objectPath << "\n";
Ed Tanous911ac312017-08-15 09:37:42 -070072 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070073 else
74 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -070075 tinyxml2::XMLElement *node = pRoot->FirstChildElement("node");
76 while (node != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -070077 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -070078 const char *childPath = node->Attribute("name");
79 if (childPath != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -070080 {
Ed Tanous1abe55e2018-09-05 08:30:59 -070081 std::string newpath;
82 if (objectPath != "/")
83 {
84 newpath += objectPath;
85 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -070086 newpath += std::string("/") + childPath;
Ed Tanous1abe55e2018-09-05 08:30:59 -070087 // introspect the subobjects as well
Ed Tanouse3cb5a32018-08-08 14:16:49 -070088 introspectObjects(processName, newpath, transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -070089 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -070090
91 node = node->NextSiblingElement("node");
Ed Tanous1abe55e2018-09-05 08:30:59 -070092 }
93 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070094 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -070095 processName, objectPath, "org.freedesktop.DBus.Introspectable",
Ed Tanous1abe55e2018-09-05 08:30:59 -070096 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -070097}
Ed Tanous64530012018-02-06 17:08:16 -080098
Matt Spinler3ae4ba72018-12-05 14:01:22 -060099struct InProgressEnumerateData
100{
101 InProgressEnumerateData(const std::string &objectPath,
102 std::shared_ptr<bmcweb::AsyncResp> asyncResp) :
103 objectPath(objectPath),
104 asyncResp(asyncResp)
105 {
106 }
107
108 ~InProgressEnumerateData()
109 {
110 // TODO
111 }
112
113 const std::string objectPath;
114 std::shared_ptr<GetSubTreeType> subtree;
115 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
116};
117
118void getManagedObjectsForEnumerate(
119 const std::string &object_name, const std::string &object_manager_path,
120 const std::string &connection_name,
121 std::shared_ptr<InProgressEnumerateData> transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700122{
Ed Tanous049a0512018-11-01 13:58:42 -0700123 BMCWEB_LOG_DEBUG << "getManagedObjectsForEnumerate " << object_name
124 << " object_manager_path " << object_manager_path
125 << " connection_name " << connection_name;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700126 crow::connections::systemBus->async_method_call(
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600127 [transaction, object_name,
Ed Tanous049a0512018-11-01 13:58:42 -0700128 connection_name](const boost::system::error_code ec,
129 const dbus::utility::ManagedObjectType &objects) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700130 if (ec)
131 {
Ed Tanous049a0512018-11-01 13:58:42 -0700132 BMCWEB_LOG_ERROR << "GetManagedObjects on path " << object_name
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600133 << " on connection " << connection_name
Ed Tanous049a0512018-11-01 13:58:42 -0700134 << " failed with code " << ec;
135 return;
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700136 }
Ed Tanous64530012018-02-06 17:08:16 -0800137
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600138 nlohmann::json &dataJson =
139 transaction->asyncResp->res.jsonValue["data"];
Ed Tanous049a0512018-11-01 13:58:42 -0700140
141 for (const auto &objectPath : objects)
142 {
143 if (boost::starts_with(objectPath.first.str, object_name))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700144 {
Ed Tanous049a0512018-11-01 13:58:42 -0700145 BMCWEB_LOG_DEBUG << "Reading object "
146 << objectPath.first.str;
147 nlohmann::json &objectJson = dataJson[objectPath.first.str];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700148 if (objectJson.is_null())
149 {
150 objectJson = nlohmann::json::object();
151 }
152 for (const auto &interface : objectPath.second)
153 {
154 for (const auto &property : interface.second)
155 {
156 nlohmann::json &propertyJson =
157 objectJson[property.first];
William A. Kennington III0a63b1c2018-10-18 13:37:19 -0700158 sdbusplus::message::variant_ns::visit(
Ed Tanous1abe55e2018-09-05 08:30:59 -0700159 [&propertyJson](auto &&val) {
160 propertyJson = val;
161 },
162 property.second);
163 }
164 }
165 }
Ed Tanous049a0512018-11-01 13:58:42 -0700166 for (const auto &interface : objectPath.second)
167 {
168 if (interface.first == "org.freedesktop.DBus.ObjectManager")
169 {
170 getManagedObjectsForEnumerate(
171 objectPath.first.str, objectPath.first.str,
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600172 connection_name, transaction);
Ed Tanous049a0512018-11-01 13:58:42 -0700173 }
174 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700175 }
176 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700177 connection_name, object_manager_path,
178 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
179}
180
181void findObjectManagerPathForEnumerate(
182 const std::string &object_name, const std::string &connection_name,
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600183 std::shared_ptr<InProgressEnumerateData> transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700184{
Ed Tanous049a0512018-11-01 13:58:42 -0700185 BMCWEB_LOG_DEBUG << "Finding objectmanager for path " << object_name
186 << " on connection:" << connection_name;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700187 crow::connections::systemBus->async_method_call(
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600188 [transaction, object_name, connection_name](
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700189 const boost::system::error_code ec,
190 const boost::container::flat_map<
191 std::string, boost::container::flat_map<
192 std::string, std::vector<std::string>>>
193 &objects) {
194 if (ec)
195 {
Ed Tanous049a0512018-11-01 13:58:42 -0700196 BMCWEB_LOG_ERROR << "GetAncestors on path " << object_name
197 << " failed with code " << ec;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700198 return;
199 }
200
Ed Tanousf254ba72018-10-12 13:40:35 -0700201 for (const auto &pathGroup : objects)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700202 {
Ed Tanousf254ba72018-10-12 13:40:35 -0700203 for (const auto &connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700204 {
205 if (connectionGroup.first == connection_name)
206 {
207 // Found the object manager path for this resource.
208 getManagedObjectsForEnumerate(
Ed Tanous049a0512018-11-01 13:58:42 -0700209 object_name, pathGroup.first, connection_name,
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600210 transaction);
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700211 return;
212 }
213 }
214 }
215 },
216 "xyz.openbmc_project.ObjectMapper",
217 "/xyz/openbmc_project/object_mapper",
218 "xyz.openbmc_project.ObjectMapper", "GetAncestors", object_name,
219 std::array<const char *, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700220}
Ed Tanous64530012018-02-06 17:08:16 -0800221
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600222// Uses GetObject to add the object info about the target /enumerate path to the
223// results of GetSubTree, as GetSubTree will not return info for the
224// target path, and then continues on enumerating the rest of the tree.
225void getObjectAndEnumerate(std::shared_ptr<InProgressEnumerateData> transaction)
226{
227 using GetObjectType =
228 std::vector<std::pair<std::string, std::vector<std::string>>>;
229
230 crow::connections::systemBus->async_method_call(
231 [transaction](const boost::system::error_code ec,
232 const GetObjectType &objects) {
233 if (ec)
234 {
235 BMCWEB_LOG_ERROR << "GetObject for path "
236 << transaction->objectPath
237 << " failed with code " << ec;
238 return;
239 }
240
241 BMCWEB_LOG_DEBUG << "GetObject for " << transaction->objectPath
242 << " has " << objects.size() << " entries";
243 if (!objects.empty())
244 {
245 transaction->subtree->emplace_back(transaction->objectPath,
246 objects);
247 }
248
249 // Map indicating connection name, and the path where the object
250 // manager exists
251 boost::container::flat_map<std::string, std::string> connections;
252
253 for (const auto &object : *(transaction->subtree))
254 {
255 for (const auto &connection : object.second)
256 {
257 std::string &objectManagerPath =
258 connections[connection.first];
259 for (const auto &interface : connection.second)
260 {
261 BMCWEB_LOG_DEBUG << connection.first
262 << " has interface " << interface;
263 if (interface == "org.freedesktop.DBus.ObjectManager")
264 {
265 BMCWEB_LOG_DEBUG << "found object manager path "
266 << object.first;
267 objectManagerPath = object.first;
268 }
269 }
270 }
271 }
272 BMCWEB_LOG_DEBUG << "Got " << connections.size() << " connections";
273
274 for (const auto &connection : connections)
275 {
276 // If we already know where the object manager is, we don't need
277 // to search for it, we can call directly in to
278 // getManagedObjects
279 if (!connection.second.empty())
280 {
281 getManagedObjectsForEnumerate(
282 transaction->objectPath, connection.second,
283 connection.first, transaction);
284 }
285 else
286 {
287 // otherwise we need to find the object manager path before
288 // we can continue
289 findObjectManagerPathForEnumerate(
290 transaction->objectPath, connection.first, transaction);
291 }
292 }
293 },
294 "xyz.openbmc_project.ObjectMapper",
295 "/xyz/openbmc_project/object_mapper",
296 "xyz.openbmc_project.ObjectMapper", "GetObject",
297 transaction->objectPath, std::array<const char *, 0>());
298}
Ed Tanous64530012018-02-06 17:08:16 -0800299
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700300// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700301struct InProgressActionData
302{
303 InProgressActionData(crow::Response &res) : res(res){};
304 ~InProgressActionData()
305 {
306 if (res.result() == boost::beast::http::status::internal_server_error)
307 {
308 // Reset the json object to clear out any data that made it in
309 // before the error happened todo(ed) handle error condition with
310 // proper code
311 res.jsonValue = nlohmann::json::object();
312 }
313 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700314 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700315
Ed Tanous1abe55e2018-09-05 08:30:59 -0700316 void setErrorStatus()
317 {
318 res.result(boost::beast::http::status::internal_server_error);
319 }
320 crow::Response &res;
321 std::string path;
322 std::string methodName;
323 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700324};
325
Ed Tanous1abe55e2018-09-05 08:30:59 -0700326std::vector<std::string> dbusArgSplit(const std::string &string)
327{
328 std::vector<std::string> ret;
329 if (string.empty())
330 {
331 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700332 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700333 ret.push_back("");
334 int containerDepth = 0;
335
336 for (std::string::const_iterator character = string.begin();
337 character != string.end(); character++)
338 {
339 ret.back() += *character;
340 switch (*character)
341 {
342 case ('a'):
343 break;
344 case ('('):
345 case ('{'):
346 containerDepth++;
347 break;
348 case ('}'):
349 case (')'):
350 containerDepth--;
351 if (containerDepth == 0)
352 {
353 if (character + 1 != string.end())
354 {
355 ret.push_back("");
356 }
357 }
358 break;
359 default:
360 if (containerDepth == 0)
361 {
362 if (character + 1 != string.end())
363 {
364 ret.push_back("");
365 }
366 }
367 break;
368 }
369 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700370}
371
Ed Tanousd76323e2018-08-07 14:35:40 -0700372int convertJsonToDbus(sd_bus_message *m, const std::string &arg_type,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700373 const nlohmann::json &input_json)
374{
375 int r = 0;
376 BMCWEB_LOG_DEBUG << "Converting " << input_json.dump()
377 << " to type: " << arg_type;
378 const std::vector<std::string> argTypes = dbusArgSplit(arg_type);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700379
Ed Tanous1abe55e2018-09-05 08:30:59 -0700380 // Assume a single object for now.
381 const nlohmann::json *j = &input_json;
382 nlohmann::json::const_iterator jIt = input_json.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700383
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700384 for (const std::string &argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700385 {
386 // If we are decoding multiple objects, grab the pointer to the
387 // iterator, and increment it for the next loop
388 if (argTypes.size() > 1)
389 {
390 if (jIt == input_json.end())
391 {
392 return -2;
393 }
394 j = &*jIt;
395 jIt++;
396 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700397 const int64_t *intValue = j->get_ptr<const int64_t *>();
398 const uint64_t *uintValue = j->get_ptr<const uint64_t *>();
399 const std::string *stringValue = j->get_ptr<const std::string *>();
400 const double *doubleValue = j->get_ptr<const double *>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700401 const bool *b = j->get_ptr<const bool *>();
402 int64_t v = 0;
403 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700404
Ed Tanous1abe55e2018-09-05 08:30:59 -0700405 // Do some basic type conversions that make sense. uint can be
406 // converted to int. int and uint can be converted to double
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700407 if (uintValue != nullptr && intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700408 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700409 v = static_cast<int64_t>(*uintValue);
410 intValue = &v;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700411 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700412 if (uintValue != nullptr && doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700413 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700414 d = static_cast<double>(*uintValue);
415 doubleValue = &d;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700416 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700417 if (intValue != nullptr && doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700418 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700419 d = static_cast<double>(*intValue);
420 doubleValue = &d;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700421 }
422
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700423 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700424 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700425 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700426 {
427 return -1;
428 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700429 r = sd_bus_message_append_basic(m, argCode[0],
430 (void *)stringValue->c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700431 if (r < 0)
432 {
433 return r;
434 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700435 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700436 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700437 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700438 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700439 {
440 return -1;
441 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700442 int32_t i = static_cast<int32_t>(*intValue);
443 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700444 if (r < 0)
445 {
446 return r;
447 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700448 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700449 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700450 {
451 // lots of ways bool could be represented here. Try them all
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700452 int boolInt = false;
453 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700454 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700455 boolInt = *intValue > 0 ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700456 }
457 else if (b != nullptr)
458 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700459 boolInt = b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700460 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700461 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700462 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700463 boolInt = boost::istarts_with(*stringValue, "t") ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700464 }
465 else
466 {
467 return -1;
468 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700469 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
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 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700476 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700477 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700478 {
479 return -1;
480 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700481 int16_t n = static_cast<int16_t>(*intValue);
482 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700483 if (r < 0)
484 {
485 return r;
486 }
487 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700488 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700489 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700490 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700491 {
492 return -1;
493 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700494 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700495 if (r < 0)
496 {
497 return r;
498 }
499 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700500 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700501 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700502 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700503 {
504 return -1;
505 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700506 uint8_t y = static_cast<uint8_t>(*uintValue);
507 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700508 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700509 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700510 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700511 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700512 {
513 return -1;
514 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700515 uint16_t q = static_cast<uint16_t>(*uintValue);
516 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700517 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700518 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700519 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700520 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700521 {
522 return -1;
523 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700524 uint32_t u = static_cast<uint32_t>(*uintValue);
525 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700526 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700527 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700528 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700529 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700530 {
531 return -1;
532 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700533 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700534 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700535 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700536 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700537 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700538 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700539 else if (boost::starts_with(argCode, "a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700540 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700541 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700542 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700543 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700544 if (r < 0)
545 {
546 return r;
547 }
548
549 for (nlohmann::json::const_iterator it = j->begin(); it != j->end();
550 ++it)
551 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700552 r = convertJsonToDbus(m, containedType, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700553 if (r < 0)
554 {
555 return r;
556 }
557
558 it++;
559 }
560 sd_bus_message_close_container(m);
561 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700562 else if (boost::starts_with(argCode, "v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700563 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700564 std::string containedType = argCode.substr(1);
565 BMCWEB_LOG_DEBUG << "variant type: " << argCode
566 << " appending variant of type: " << containedType;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700567 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700568 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700569 if (r < 0)
570 {
571 return r;
572 }
573
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700574 r = convertJsonToDbus(m, containedType, input_json);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700575 if (r < 0)
576 {
577 return r;
578 }
579
580 r = sd_bus_message_close_container(m);
581 if (r < 0)
582 {
583 return r;
584 }
585 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700586 else if (boost::starts_with(argCode, "(") &&
587 boost::ends_with(argCode, ")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700588 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700589 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700590 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700591 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700592 nlohmann::json::const_iterator it = j->begin();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700593 for (const std::string &argCode : dbusArgSplit(arg_type))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700594 {
595 if (it == j->end())
596 {
597 return -1;
598 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700599 r = convertJsonToDbus(m, argCode, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700600 if (r < 0)
601 {
602 return r;
603 }
604 it++;
605 }
606 r = sd_bus_message_close_container(m);
607 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700608 else if (boost::starts_with(argCode, "{") &&
609 boost::ends_with(argCode, "}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700610 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700611 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700612 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700613 containedType.c_str());
614 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700615 if (codes.size() != 2)
616 {
617 return -1;
618 }
619 const std::string &key_type = codes[0];
620 const std::string &value_type = codes[1];
621 for (auto it : j->items())
622 {
623 r = convertJsonToDbus(m, key_type, it.key());
624 if (r < 0)
625 {
626 return r;
627 }
628
629 r = convertJsonToDbus(m, value_type, it.value());
630 if (r < 0)
631 {
632 return r;
633 }
634 }
635 r = sd_bus_message_close_container(m);
636 }
637 else
638 {
639 return -2;
640 }
641 if (r < 0)
642 {
643 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700644 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700645
Ed Tanous1abe55e2018-09-05 08:30:59 -0700646 if (argTypes.size() > 1)
647 {
648 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700649 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700650 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700651}
652
Ed Tanousd76323e2018-08-07 14:35:40 -0700653void findActionOnInterface(std::shared_ptr<InProgressActionData> transaction,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700654 const std::string &connectionName)
655{
656 BMCWEB_LOG_DEBUG << "findActionOnInterface for connection "
657 << connectionName;
658 crow::connections::systemBus->async_method_call(
659 [transaction, connectionName{std::string(connectionName)}](
660 const boost::system::error_code ec,
661 const std::string &introspect_xml) {
662 BMCWEB_LOG_DEBUG << "got xml:\n " << introspect_xml;
663 if (ec)
664 {
665 BMCWEB_LOG_ERROR
666 << "Introspect call failed with error: " << ec.message()
667 << " on process: " << connectionName << "\n";
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700668 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700669 else
670 {
671 tinyxml2::XMLDocument doc;
672
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700673 doc.Parse(introspect_xml.data(), introspect_xml.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700674 tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
675 if (pRoot == nullptr)
676 {
677 BMCWEB_LOG_ERROR << "XML document failed to parse "
678 << connectionName << "\n";
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700679 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700680 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700681 tinyxml2::XMLElement *interfaceNode =
682 pRoot->FirstChildElement("interface");
683 while (interfaceNode != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700684 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700685 const char *thisInterfaceName =
686 interfaceNode->Attribute("name");
687 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700688 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700689 tinyxml2::XMLElement *methodNode =
690 interfaceNode->FirstChildElement("method");
691 while (methodNode != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700692 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700693 const char *thisMethodName =
694 methodNode->Attribute("name");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700695 BMCWEB_LOG_DEBUG << "Found method: "
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700696 << thisMethodName;
697 if (thisMethodName != nullptr &&
698 thisMethodName == transaction->methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700699 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700700 BMCWEB_LOG_DEBUG
701 << "Found method named " << thisMethodName
702 << " on interface " << thisInterfaceName;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700703 sdbusplus::message::message m =
704 crow::connections::systemBus
705 ->new_method_call(
706 connectionName.c_str(),
707 transaction->path.c_str(),
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700708 thisInterfaceName,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700709 transaction->methodName.c_str());
710
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700711 tinyxml2::XMLElement *argumentNode =
712 methodNode->FirstChildElement("arg");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700713
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700714 nlohmann::json::const_iterator argIt =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700715 transaction->arguments.begin();
716
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700717 while (argumentNode != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700718 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700719 const char *argDirection =
720 argumentNode->Attribute("direction");
721 const char *argType =
722 argumentNode->Attribute("type");
723 if (argDirection != nullptr &&
724 argType != nullptr &&
725 std::string(argDirection) == "in")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700726 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700727
728 if (argIt ==
Ed Tanous1abe55e2018-09-05 08:30:59 -0700729 transaction->arguments.end())
730 {
731 transaction->setErrorStatus();
732 return;
733 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700734 if (convertJsonToDbus(
735 m.get(), std::string(argType),
736 *argIt) < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700737 {
738 transaction->setErrorStatus();
739 return;
740 }
741
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700742 argIt++;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700743 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700744 argumentNode =
745 methodNode->NextSiblingElement("arg");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700746 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700747
Ed Tanous1abe55e2018-09-05 08:30:59 -0700748 crow::connections::systemBus->async_send(
749 m, [transaction](
750 boost::system::error_code ec,
751 sdbusplus::message::message &m) {
752 if (ec)
753 {
754 transaction->setErrorStatus();
755 return;
756 }
757 transaction->res.jsonValue = {
758 {"status", "ok"},
759 {"message", "200 OK"},
760 {"data", nullptr}};
761 });
762 break;
763 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700764 methodNode =
765 methodNode->NextSiblingElement("method");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700766 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700767 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700768 interfaceNode =
769 interfaceNode->NextSiblingElement("interface");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700770 }
771 }
772 },
773 connectionName, transaction->path,
774 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700775}
776
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700777void handleAction(const crow::Request &req, crow::Response &res,
778 const std::string &objectPath, const std::string &methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700779{
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700780 BMCWEB_LOG_DEBUG << "handleAction on path: " << objectPath << " and method "
781 << methodName;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700782 nlohmann::json requestDbusData =
783 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700784
Ed Tanous1abe55e2018-09-05 08:30:59 -0700785 if (requestDbusData.is_discarded())
786 {
787 res.result(boost::beast::http::status::bad_request);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700788 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700789 return;
790 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700791 nlohmann::json::iterator data = requestDbusData.find("data");
792 if (data == requestDbusData.end())
793 {
794 res.result(boost::beast::http::status::bad_request);
795 res.end();
796 return;
797 }
798
799 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700800 {
801 res.result(boost::beast::http::status::bad_request);
802 res.end();
803 return;
804 }
805 auto transaction = std::make_shared<InProgressActionData>(res);
806
807 transaction->path = objectPath;
808 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700809 transaction->arguments = std::move(*data);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700810 crow::connections::systemBus->async_method_call(
811 [transaction](
812 const boost::system::error_code ec,
813 const std::vector<std::pair<std::string, std::vector<std::string>>>
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700814 &interfaceNames) {
815 if (ec || interfaceNames.size() <= 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700816 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700817 BMCWEB_LOG_ERROR << "Can't find object";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700818 transaction->setErrorStatus();
819 return;
820 }
821
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700822 BMCWEB_LOG_DEBUG << "GetObject returned " << interfaceNames.size()
823 << " object(s)";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700824
825 for (const std::pair<std::string, std::vector<std::string>>
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700826 &object : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700827 {
828 findActionOnInterface(transaction, object.first);
829 }
830 },
831 "xyz.openbmc_project.ObjectMapper",
832 "/xyz/openbmc_project/object_mapper",
833 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
834 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700835}
836
Ed Tanousf839dfe2018-11-12 11:11:15 -0800837void handleList(crow::Response &res, const std::string &objectPath,
838 int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700839{
840 crow::connections::systemBus->async_method_call(
841 [&res](const boost::system::error_code ec,
842 std::vector<std::string> &objectPaths) {
843 if (ec)
844 {
845 res.result(boost::beast::http::status::internal_server_error);
846 }
847 else
848 {
849 res.jsonValue = {{"status", "ok"},
850 {"message", "200 OK"},
851 {"data", std::move(objectPaths)}};
852 }
853 res.end();
854 },
855 "xyz.openbmc_project.ObjectMapper",
856 "/xyz/openbmc_project/object_mapper",
857 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", objectPath,
Ed Tanousf839dfe2018-11-12 11:11:15 -0800858 depth, std::array<std::string, 0>());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700859}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700860
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700861void handleEnumerate(crow::Response &res, const std::string &objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700862{
Ed Tanous049a0512018-11-01 13:58:42 -0700863 BMCWEB_LOG_DEBUG << "Doing enumerate on " << objectPath;
864 auto asyncResp = std::make_shared<bmcweb::AsyncResp>(res);
865
866 asyncResp->res.jsonValue = {{"message", "200 OK"},
867 {"status", "ok"},
868 {"data", nlohmann::json::object()}};
869
Ed Tanous1abe55e2018-09-05 08:30:59 -0700870 crow::connections::systemBus->async_method_call(
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600871 [objectPath, asyncResp](const boost::system::error_code ec,
872 GetSubTreeType &object_names) {
873 auto transaction = std::make_shared<InProgressEnumerateData>(
874 objectPath, asyncResp);
875
876 transaction->subtree =
877 std::make_shared<GetSubTreeType>(std::move(object_names));
878
Ed Tanous1abe55e2018-09-05 08:30:59 -0700879 if (ec)
880 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700881 return;
882 }
Ed Tanous64530012018-02-06 17:08:16 -0800883
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600884 // Add the data for the path passed in to the results
885 // as if GetSubTree returned it, and continue on enumerating
886 getObjectAndEnumerate(transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700887 },
888 "xyz.openbmc_project.ObjectMapper",
889 "/xyz/openbmc_project/object_mapper",
890 "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath,
Ed Tanous049a0512018-11-01 13:58:42 -0700891 static_cast<int32_t>(0), std::array<const char *, 0>());
Ed Tanous64530012018-02-06 17:08:16 -0800892}
Ed Tanous911ac312017-08-15 09:37:42 -0700893
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700894void handleGet(crow::Response &res, std::string &objectPath,
895 std::string &destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700896{
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700897 BMCWEB_LOG_DEBUG << "handleGet: " << objectPath << " prop:" << destProperty;
898 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700899 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -0700900
Ed Tanous1abe55e2018-09-05 08:30:59 -0700901 std::shared_ptr<std::string> path =
902 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -0700903
Ed Tanous1abe55e2018-09-05 08:30:59 -0700904 using GetObjectType =
905 std::vector<std::pair<std::string, std::vector<std::string>>>;
906 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700907 [&res, path, propertyName](const boost::system::error_code ec,
908 const GetObjectType &object_names) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700909 if (ec || object_names.size() <= 0)
910 {
911 res.result(boost::beast::http::status::not_found);
912 res.end();
913 return;
914 }
915 std::shared_ptr<nlohmann::json> response =
916 std::make_shared<nlohmann::json>(nlohmann::json::object());
917 // The mapper should never give us an empty interface names list,
918 // but check anyway
919 for (const std::pair<std::string, std::vector<std::string>>
920 connection : object_names)
921 {
922 const std::vector<std::string> &interfaceNames =
923 connection.second;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700924
Ed Tanous1abe55e2018-09-05 08:30:59 -0700925 if (interfaceNames.size() <= 0)
926 {
927 res.result(boost::beast::http::status::not_found);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700928 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700929 return;
930 }
931
932 for (const std::string &interface : interfaceNames)
933 {
934 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700935 [&res, response, propertyName](
Ed Tanous1abe55e2018-09-05 08:30:59 -0700936 const boost::system::error_code ec,
James Feist5b4aa862018-08-16 14:07:01 -0700937 const std::vector<std::pair<
938 std::string, dbus::utility::DbusVariantType>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700939 &properties) {
940 if (ec)
941 {
942 BMCWEB_LOG_ERROR << "Bad dbus request error: "
943 << ec;
944 }
945 else
946 {
James Feist5b4aa862018-08-16 14:07:01 -0700947 for (const std::pair<
948 std::string,
949 dbus::utility::DbusVariantType>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700950 &property : properties)
951 {
952 // if property name is empty, or matches our
953 // search query, add it to the response json
954
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700955 if (propertyName->empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700956 {
William A. Kennington III0a63b1c2018-10-18 13:37:19 -0700957 sdbusplus::message::variant_ns::visit(
Ed Tanous1abe55e2018-09-05 08:30:59 -0700958 [&response, &property](auto &&val) {
959 (*response)[property.first] =
960 val;
961 },
962 property.second);
963 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700964 else if (property.first == *propertyName)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700965 {
William A. Kennington III0a63b1c2018-10-18 13:37:19 -0700966 sdbusplus::message::variant_ns::visit(
Ed Tanous1abe55e2018-09-05 08:30:59 -0700967 [&response](auto &&val) {
968 (*response) = val;
969 },
970 property.second);
971 }
972 }
973 }
974 if (response.use_count() == 1)
975 {
976 res.jsonValue = {{"status", "ok"},
977 {"message", "200 OK"},
978 {"data", *response}};
979
980 res.end();
981 }
982 },
983 connection.first, *path,
984 "org.freedesktop.DBus.Properties", "GetAll", interface);
985 }
986 }
987 },
988 "xyz.openbmc_project.ObjectMapper",
989 "/xyz/openbmc_project/object_mapper",
990 "xyz.openbmc_project.ObjectMapper", "GetObject", *path,
991 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700992}
993
Ed Tanous1abe55e2018-09-05 08:30:59 -0700994struct AsyncPutRequest
995{
996 AsyncPutRequest(crow::Response &res) : res(res)
997 {
998 res.jsonValue = {
999 {"status", "ok"}, {"message", "200 OK"}, {"data", nullptr}};
1000 }
1001 ~AsyncPutRequest()
1002 {
1003 if (res.result() == boost::beast::http::status::internal_server_error)
1004 {
1005 // Reset the json object to clear out any data that made it in
1006 // before the error happened todo(ed) handle error condition with
1007 // proper code
1008 res.jsonValue = nlohmann::json::object();
1009 }
1010
1011 if (res.jsonValue.empty())
1012 {
1013 res.result(boost::beast::http::status::forbidden);
1014 res.jsonValue = {
1015 {"status", "error"},
1016 {"message", "403 Forbidden"},
1017 {"data",
1018 {{"message", "The specified property cannot be created: " +
1019 propertyName}}}};
1020 }
1021
1022 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001023 }
1024
Ed Tanous1abe55e2018-09-05 08:30:59 -07001025 void setErrorStatus()
1026 {
1027 res.result(boost::beast::http::status::internal_server_error);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001028 }
1029
Ed Tanous1abe55e2018-09-05 08:30:59 -07001030 crow::Response &res;
1031 std::string objectPath;
1032 std::string propertyName;
1033 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001034};
1035
Ed Tanousd76323e2018-08-07 14:35:40 -07001036void handlePut(const crow::Request &req, crow::Response &res,
Ed Tanous1abe55e2018-09-05 08:30:59 -07001037 const std::string &objectPath, const std::string &destProperty)
1038{
1039 nlohmann::json requestDbusData =
1040 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001041
Ed Tanous1abe55e2018-09-05 08:30:59 -07001042 if (requestDbusData.is_discarded())
1043 {
1044 res.result(boost::beast::http::status::bad_request);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001045 res.end();
1046 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001047 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001048
Ed Tanous1abe55e2018-09-05 08:30:59 -07001049 nlohmann::json::const_iterator propertyIt = requestDbusData.find("data");
1050 if (propertyIt == requestDbusData.end())
1051 {
1052 res.result(boost::beast::http::status::bad_request);
1053 res.end();
1054 return;
1055 }
1056 const nlohmann::json &propertySetValue = *propertyIt;
1057 auto transaction = std::make_shared<AsyncPutRequest>(res);
1058 transaction->objectPath = objectPath;
1059 transaction->propertyName = destProperty;
1060 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001061
Ed Tanous1abe55e2018-09-05 08:30:59 -07001062 using GetObjectType =
1063 std::vector<std::pair<std::string, std::vector<std::string>>>;
Ed Tanous911ac312017-08-15 09:37:42 -07001064
Ed Tanous1abe55e2018-09-05 08:30:59 -07001065 crow::connections::systemBus->async_method_call(
1066 [transaction](const boost::system::error_code ec,
1067 const GetObjectType &object_names) {
1068 if (!ec && object_names.size() <= 0)
1069 {
1070 transaction->res.result(boost::beast::http::status::not_found);
1071 return;
1072 }
Ed Tanous911ac312017-08-15 09:37:42 -07001073
Ed Tanous1abe55e2018-09-05 08:30:59 -07001074 for (const std::pair<std::string, std::vector<std::string>>
1075 connection : object_names)
1076 {
1077 const std::string &connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001078
Ed Tanous1abe55e2018-09-05 08:30:59 -07001079 crow::connections::systemBus->async_method_call(
1080 [connectionName{std::string(connectionName)},
1081 transaction](const boost::system::error_code ec,
1082 const std::string &introspectXml) {
1083 if (ec)
1084 {
1085 BMCWEB_LOG_ERROR
1086 << "Introspect call failed with error: "
1087 << ec.message()
1088 << " on process: " << connectionName;
1089 transaction->setErrorStatus();
1090 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001091 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001092 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001093
Ed Tanous1abe55e2018-09-05 08:30:59 -07001094 doc.Parse(introspectXml.c_str());
1095 tinyxml2::XMLNode *pRoot =
1096 doc.FirstChildElement("node");
1097 if (pRoot == nullptr)
1098 {
1099 BMCWEB_LOG_ERROR << "XML document failed to parse: "
1100 << introspectXml;
1101 transaction->setErrorStatus();
1102 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001103 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001104 tinyxml2::XMLElement *ifaceNode =
1105 pRoot->FirstChildElement("interface");
1106 while (ifaceNode != nullptr)
1107 {
1108 const char *interfaceName =
1109 ifaceNode->Attribute("name");
1110 BMCWEB_LOG_DEBUG << "found interface "
1111 << interfaceName;
1112 tinyxml2::XMLElement *propNode =
1113 ifaceNode->FirstChildElement("property");
1114 while (propNode != nullptr)
1115 {
1116 const char *propertyName =
1117 propNode->Attribute("name");
1118 BMCWEB_LOG_DEBUG << "Found property "
1119 << propertyName;
1120 if (propertyName == transaction->propertyName)
1121 {
1122 const char *argType =
1123 propNode->Attribute("type");
1124 if (argType != nullptr)
1125 {
1126 sdbusplus::message::message m =
1127 crow::connections::systemBus
1128 ->new_method_call(
1129 connectionName.c_str(),
1130 transaction->objectPath
1131 .c_str(),
1132 "org.freedesktop.DBus."
1133 "Properties",
1134 "Set");
1135 m.append(interfaceName,
1136 transaction->propertyName);
1137 int r = sd_bus_message_open_container(
1138 m.get(), SD_BUS_TYPE_VARIANT,
1139 argType);
1140 if (r < 0)
1141 {
1142 transaction->setErrorStatus();
1143 return;
1144 }
1145 r = convertJsonToDbus(
1146 m.get(), argType,
1147 transaction->propertyValue);
1148 if (r < 0)
1149 {
1150 transaction->setErrorStatus();
1151 return;
1152 }
1153 r = sd_bus_message_close_container(
1154 m.get());
1155 if (r < 0)
1156 {
1157 transaction->setErrorStatus();
1158 return;
1159 }
Ed Tanous911ac312017-08-15 09:37:42 -07001160
Ed Tanous1abe55e2018-09-05 08:30:59 -07001161 crow::connections::systemBus
1162 ->async_send(
1163 m,
1164 [transaction](
1165 boost::system::error_code
1166 ec,
1167 sdbusplus::message::message
1168 &m) {
1169 BMCWEB_LOG_DEBUG << "sent";
1170 if (ec)
1171 {
1172 transaction->res
1173 .jsonValue
1174 ["status"] =
1175 "error";
1176 transaction->res
1177 .jsonValue
1178 ["message"] =
1179 ec.message();
1180 }
1181 });
1182 }
1183 }
1184 propNode =
1185 propNode->NextSiblingElement("property");
1186 }
1187 ifaceNode =
1188 ifaceNode->NextSiblingElement("interface");
1189 }
1190 },
1191 connectionName, transaction->objectPath,
1192 "org.freedesktop.DBus.Introspectable", "Introspect");
1193 }
1194 },
1195 "xyz.openbmc_project.ObjectMapper",
1196 "/xyz/openbmc_project/object_mapper",
1197 "xyz.openbmc_project.ObjectMapper", "GetObject",
1198 transaction->objectPath, std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001199}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001200
Ed Tanous049a0512018-11-01 13:58:42 -07001201inline void handleDBusUrl(const crow::Request &req, crow::Response &res,
1202 std::string &objectPath)
1203{
Ed Tanous049a0512018-11-01 13:58:42 -07001204
1205 // If accessing a single attribute, fill in and update objectPath,
1206 // otherwise leave destProperty blank
1207 std::string destProperty = "";
1208 const char *attrSeperator = "/attr/";
1209 size_t attrPosition = objectPath.find(attrSeperator);
1210 if (attrPosition != objectPath.npos)
1211 {
1212 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
1213 objectPath.length());
1214 objectPath = objectPath.substr(0, attrPosition);
1215 }
1216
1217 if (req.method() == "POST"_method)
1218 {
1219 constexpr const char *actionSeperator = "/action/";
1220 size_t actionPosition = objectPath.find(actionSeperator);
1221 if (actionPosition != objectPath.npos)
1222 {
1223 std::string postProperty =
1224 objectPath.substr((actionPosition + strlen(actionSeperator)),
1225 objectPath.length());
1226 objectPath = objectPath.substr(0, actionPosition);
1227 handleAction(req, res, objectPath, postProperty);
1228 return;
1229 }
1230 }
1231 else if (req.method() == "GET"_method)
1232 {
1233 if (boost::ends_with(objectPath, "/enumerate"))
1234 {
1235 objectPath.erase(objectPath.end() - sizeof("enumerate"),
1236 objectPath.end());
1237 handleEnumerate(res, objectPath);
1238 }
1239 else if (boost::ends_with(objectPath, "/list"))
1240 {
1241 objectPath.erase(objectPath.end() - sizeof("list"),
1242 objectPath.end());
1243 handleList(res, objectPath);
1244 }
1245 else
1246 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08001247 // Trim any trailing "/" at the end
1248 if (boost::ends_with(objectPath, "/"))
1249 {
1250 objectPath.pop_back();
1251 handleList(res, objectPath, 1);
1252 }
1253 else
1254 {
1255 handleGet(res, objectPath, destProperty);
1256 }
Ed Tanous049a0512018-11-01 13:58:42 -07001257 }
1258 return;
1259 }
1260 else if (req.method() == "PUT"_method)
1261 {
1262 handlePut(req, res, objectPath, destProperty);
1263 return;
1264 }
1265
1266 res.result(boost::beast::http::status::method_not_allowed);
1267 res.end();
1268}
1269
Ed Tanous1abe55e2018-09-05 08:30:59 -07001270template <typename... Middlewares> void requestRoutes(Crow<Middlewares...> &app)
1271{
1272 BMCWEB_ROUTE(app, "/bus/")
1273 .methods("GET"_method)(
1274 [](const crow::Request &req, crow::Response &res) {
1275 res.jsonValue = {{"busses", {{{"name", "system"}}}},
1276 {"status", "ok"}};
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001277 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001278 });
1279
1280 BMCWEB_ROUTE(app, "/bus/system/")
1281 .methods("GET"_method)(
1282 [](const crow::Request &req, crow::Response &res) {
1283 auto myCallback = [&res](const boost::system::error_code ec,
1284 std::vector<std::string> &names) {
1285 if (ec)
1286 {
1287 BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
1288 res.result(
1289 boost::beast::http::status::internal_server_error);
1290 }
1291 else
1292 {
1293 std::sort(names.begin(), names.end());
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001294 res.jsonValue = {{"status", "ok"}};
1295 auto &objectsSub = res.jsonValue["objects"];
Ed Tanous1abe55e2018-09-05 08:30:59 -07001296 for (auto &name : names)
1297 {
1298 objectsSub.push_back({{"name", name}});
1299 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001300 }
1301 res.end();
1302 };
1303 crow::connections::systemBus->async_method_call(
1304 std::move(myCallback), "org.freedesktop.DBus", "/",
1305 "org.freedesktop.DBus", "ListNames");
1306 });
1307
1308 BMCWEB_ROUTE(app, "/list/")
1309 .methods("GET"_method)(
1310 [](const crow::Request &req, crow::Response &res) {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001311 handleList(res, "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001312 });
1313
1314 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous049a0512018-11-01 13:58:42 -07001315 .methods("GET"_method, "PUT"_method, "POST"_method)(
1316 [](const crow::Request &req, crow::Response &res,
1317 const std::string &path) {
1318 std::string objectPath = "/xyz/" + path;
1319 handleDBusUrl(req, res, objectPath);
1320 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001321
Ed Tanous049a0512018-11-01 13:58:42 -07001322 BMCWEB_ROUTE(app, "/org/<path>")
1323 .methods("GET"_method, "PUT"_method, "POST"_method)(
1324 [](const crow::Request &req, crow::Response &res,
1325 const std::string &path) {
1326 std::string objectPath = "/org/" + path;
1327 handleDBusUrl(req, res, objectPath);
1328 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001329
Ed Tanous1abe55e2018-09-05 08:30:59 -07001330 BMCWEB_ROUTE(app, "/download/dump/<str>/")
1331 .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
1332 const std::string &dumpId) {
1333 std::regex validFilename("^[\\w\\- ]+(\\.?[\\w\\- ]+)$");
1334 if (!std::regex_match(dumpId, validFilename))
1335 {
1336 res.result(boost::beast::http::status::not_found);
1337 res.end();
1338 return;
1339 }
1340 std::experimental::filesystem::path loc(
1341 "/var/lib/phosphor-debug-collector/dumps");
1342
1343 loc += dumpId;
1344
1345 if (!std::experimental::filesystem::exists(loc) ||
1346 !std::experimental::filesystem::is_directory(loc))
1347 {
1348 res.result(boost::beast::http::status::not_found);
1349 res.end();
1350 return;
1351 }
1352 std::experimental::filesystem::directory_iterator files(loc);
1353 for (auto &file : files)
1354 {
1355 std::ifstream readFile(file.path());
1356 if (readFile.good())
1357 {
1358 continue;
1359 }
1360 res.addHeader("Content-Type", "application/octet-stream");
1361 res.body() = {std::istreambuf_iterator<char>(readFile),
1362 std::istreambuf_iterator<char>()};
1363 res.end();
1364 }
1365 res.result(boost::beast::http::status::not_found);
1366 res.end();
1367 return;
1368 });
1369
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001370 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous1abe55e2018-09-05 08:30:59 -07001371 .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001372 const std::string &Connection) {
1373 introspectObjects(Connection, "/",
1374 std::make_shared<bmcweb::AsyncResp>(res));
1375 });
1376
1377 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
1378 .methods("GET"_method,
1379 "POST"_method)([](const crow::Request &req,
1380 crow::Response &res,
1381 const std::string &processName,
1382 const std::string &requestedPath) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001383 std::vector<std::string> strs;
1384 boost::split(strs, requestedPath, boost::is_any_of("/"));
1385 std::string objectPath;
1386 std::string interfaceName;
1387 std::string methodName;
1388 auto it = strs.begin();
1389 if (it == strs.end())
1390 {
1391 objectPath = "/";
1392 }
1393 while (it != strs.end())
1394 {
1395 // Check if segment contains ".". If it does, it must be an
1396 // interface
1397 if (it->find(".") != std::string::npos)
1398 {
1399 break;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001400 // This check is neccesary as the trailing slash gets parsed
Ed Tanous1abe55e2018-09-05 08:30:59 -07001401 // as part of our <path> specifier above, which causes the
1402 // normal trailing backslash redirector to fail.
1403 }
1404 else if (!it->empty())
1405 {
1406 objectPath += "/" + *it;
1407 }
1408 it++;
1409 }
1410 if (it != strs.end())
1411 {
1412 interfaceName = *it;
1413 it++;
1414
1415 // after interface, we might have a method name
1416 if (it != strs.end())
1417 {
1418 methodName = *it;
1419 it++;
1420 }
1421 }
1422 if (it != strs.end())
1423 {
1424 // if there is more levels past the method name, something went
1425 // wrong, return not found
1426 res.result(boost::beast::http::status::not_found);
1427 res.end();
1428 return;
1429 }
1430 if (interfaceName.empty())
1431 {
1432 crow::connections::systemBus->async_method_call(
1433 [&, processName,
1434 objectPath](const boost::system::error_code ec,
1435 const std::string &introspect_xml) {
1436 if (ec)
1437 {
1438 BMCWEB_LOG_ERROR
1439 << "Introspect call failed with error: "
1440 << ec.message()
1441 << " on process: " << processName
1442 << " path: " << objectPath << "\n";
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001443 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001444 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001445 tinyxml2::XMLDocument doc;
1446
1447 doc.Parse(introspect_xml.c_str());
1448 tinyxml2::XMLNode *pRoot =
1449 doc.FirstChildElement("node");
1450 if (pRoot == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001451 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001452 BMCWEB_LOG_ERROR << "XML document failed to parse "
1453 << processName << " " << objectPath
1454 << "\n";
1455 res.jsonValue = {{"status", "XML parse error"}};
1456 res.result(boost::beast::http::status::
1457 internal_server_error);
1458 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001459 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001460
1461 BMCWEB_LOG_DEBUG << introspect_xml;
1462 res.jsonValue = {{"status", "ok"},
1463 {"bus_name", processName},
1464 {"object_path", objectPath}};
1465 nlohmann::json &interfacesArray =
1466 res.jsonValue["interfaces"];
1467 interfacesArray = nlohmann::json::array();
1468 tinyxml2::XMLElement *interface =
1469 pRoot->FirstChildElement("interface");
1470
1471 while (interface != nullptr)
1472 {
1473 const char *ifaceName =
1474 interface->Attribute("name");
1475 if (ifaceName != nullptr)
1476 {
1477 interfacesArray.push_back(
1478 {{"name", ifaceName}});
1479 }
1480
1481 interface =
1482 interface->NextSiblingElement("interface");
1483 }
1484
Ed Tanous1abe55e2018-09-05 08:30:59 -07001485 res.end();
1486 },
1487 processName, objectPath,
1488 "org.freedesktop.DBus.Introspectable", "Introspect");
1489 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001490 else if (methodName.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001491 {
1492 crow::connections::systemBus->async_method_call(
1493 [&, processName, objectPath,
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001494 interfaceName{std::move(interfaceName)}](
Ed Tanous1abe55e2018-09-05 08:30:59 -07001495 const boost::system::error_code ec,
1496 const std::string &introspect_xml) {
1497 if (ec)
1498 {
1499 BMCWEB_LOG_ERROR
1500 << "Introspect call failed with error: "
1501 << ec.message()
1502 << " on process: " << processName
1503 << " path: " << objectPath << "\n";
1504 }
1505 else
1506 {
1507 tinyxml2::XMLDocument doc;
1508
1509 doc.Parse(introspect_xml.c_str());
1510 tinyxml2::XMLNode *pRoot =
1511 doc.FirstChildElement("node");
1512 if (pRoot == nullptr)
1513 {
1514 BMCWEB_LOG_ERROR
1515 << "XML document failed to parse "
1516 << processName << " " << objectPath << "\n";
1517 res.result(boost::beast::http::status::
1518 internal_server_error);
1519 }
1520 else
1521 {
1522 tinyxml2::XMLElement *node =
1523 pRoot->FirstChildElement("node");
1524
1525 // if we know we're the only call, build the
1526 // json directly
Ed Tanous1abe55e2018-09-05 08:30:59 -07001527 tinyxml2::XMLElement *interface =
1528 pRoot->FirstChildElement("interface");
1529
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001530 res.jsonValue = {
1531 {"status", "ok"},
1532 {"bus_name", processName},
1533 {"interface", interfaceName},
1534 {"object_path", objectPath},
1535 {"properties", nlohmann::json::object()}};
1536
1537 nlohmann::json &methodsArray =
1538 res.jsonValue["methods"];
1539 methodsArray = nlohmann::json::array();
1540
1541 nlohmann::json &signalsArray =
1542 res.jsonValue["signals"];
1543 signalsArray = nlohmann::json::array();
1544
Ed Tanous1abe55e2018-09-05 08:30:59 -07001545 while (interface != nullptr)
1546 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001547 const char *ifaceName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001548 interface->Attribute("name");
1549
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001550 if (ifaceName != nullptr &&
1551 ifaceName == interfaceName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001552 {
1553 tinyxml2::XMLElement *methods =
1554 interface->FirstChildElement(
1555 "method");
1556 while (methods != nullptr)
1557 {
1558 nlohmann::json argsArray =
1559 nlohmann::json::array();
1560 tinyxml2::XMLElement *arg =
1561 methods->FirstChildElement(
1562 "arg");
1563 while (arg != nullptr)
1564 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001565 nlohmann::json thisArg;
1566 for (const char *fieldName :
1567 std::array<const char *,
1568 3>{"name",
1569 "direction",
1570 "type"})
1571 {
1572 const char *fieldValue =
1573 arg->Attribute(
1574 fieldName);
1575 if (fieldValue != nullptr)
1576 {
1577 thisArg[fieldName] =
1578 fieldValue;
1579 }
1580 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001581 argsArray.push_back(
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001582 std::move(thisArg));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001583 arg = arg->NextSiblingElement(
1584 "arg");
1585 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001586
1587 const char *name =
1588 methods->Attribute("name");
1589 if (name != nullptr)
1590 {
1591 methodsArray.push_back(
1592 {{"name", name},
1593 {"uri", "/bus/system/" +
1594 processName +
1595 objectPath +
1596 "/" +
1597 interfaceName +
1598 "/" + name},
1599 {"args", argsArray}});
1600 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001601 methods =
1602 methods->NextSiblingElement(
1603 "method");
1604 }
1605 tinyxml2::XMLElement *signals =
1606 interface->FirstChildElement(
1607 "signal");
1608 while (signals != nullptr)
1609 {
1610 nlohmann::json argsArray =
1611 nlohmann::json::array();
1612
1613 tinyxml2::XMLElement *arg =
1614 signals->FirstChildElement(
1615 "arg");
1616 while (arg != nullptr)
1617 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001618 const char *name =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001619 arg->Attribute("name");
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001620 const char *type =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001621 arg->Attribute("type");
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001622 if (name != nullptr &&
1623 type != nullptr)
1624 {
1625 argsArray.push_back({
1626 {"name", name},
1627 {"type", type},
1628 });
1629 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001630 arg = arg->NextSiblingElement(
1631 "arg");
1632 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001633 const char *name =
1634 signals->Attribute("name");
1635 if (name != nullptr)
1636 {
1637 signalsArray.push_back(
1638 {{"name", name},
1639 {"args", argsArray}});
1640 }
1641
Ed Tanous1abe55e2018-09-05 08:30:59 -07001642 signals =
1643 signals->NextSiblingElement(
1644 "signal");
1645 }
1646
Ed Tanous1abe55e2018-09-05 08:30:59 -07001647 break;
1648 }
1649
1650 interface = interface->NextSiblingElement(
1651 "interface");
1652 }
1653 if (interface == nullptr)
1654 {
1655 // if we got to the end of the list and
1656 // never found a match, throw 404
1657 res.result(
1658 boost::beast::http::status::not_found);
1659 }
1660 }
1661 }
1662 res.end();
1663 },
1664 processName, objectPath,
1665 "org.freedesktop.DBus.Introspectable", "Introspect");
1666 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001667 else
1668 {
1669 if (req.method() != "POST"_method)
1670 {
1671 res.result(boost::beast::http::status::not_found);
1672 res.end();
1673 return;
1674 }
1675
1676 nlohmann::json requestDbusData =
1677 nlohmann::json::parse(req.body, nullptr, false);
1678
1679 if (requestDbusData.is_discarded())
1680 {
1681 res.result(boost::beast::http::status::bad_request);
1682 res.end();
1683 return;
1684 }
1685 if (!requestDbusData.is_array())
1686 {
1687 res.result(boost::beast::http::status::bad_request);
1688 res.end();
1689 return;
1690 }
1691 auto transaction = std::make_shared<InProgressActionData>(res);
1692
1693 transaction->path = objectPath;
1694 transaction->methodName = methodName;
1695 transaction->arguments = std::move(requestDbusData);
1696
1697 findActionOnInterface(transaction, processName);
1698 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001699 });
1700}
1701} // namespace openbmc_mapper
1702} // namespace crow