blob: 2e338bbff37b8b7463c979587b8dc940653a3ab5 [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 Spinler2df1e7d2018-12-05 15:53:16 -060099void getPropertiesForEnumerate(const std::string &objectPath,
100 const std::string &service,
101 const std::string &interface,
102 std::shared_ptr<bmcweb::AsyncResp> asyncResp)
103{
104 BMCWEB_LOG_DEBUG << "getPropertiesForEnumerate " << objectPath << " "
105 << service << " " << interface;
106
107 crow::connections::systemBus->async_method_call(
108 [asyncResp, objectPath, service,
109 interface](const boost::system::error_code ec,
110 const std::vector<
111 std::pair<std::string, dbus::utility::DbusVariantType>>
112 &propertiesList) {
113 if (ec)
114 {
115 BMCWEB_LOG_ERROR << "GetAll on path " << objectPath << " iface "
116 << interface << " service " << service
117 << " failed with code " << ec;
118 return;
119 }
120
121 nlohmann::json &dataJson = asyncResp->res.jsonValue["data"];
122 nlohmann::json &objectJson = dataJson[objectPath];
123 if (objectJson.is_null())
124 {
125 objectJson = nlohmann::json::object();
126 }
127
128 for (const auto &[name, value] : propertiesList)
129 {
130 nlohmann::json &propertyJson = objectJson[name];
131 sdbusplus::message::variant_ns::visit(
132 [&propertyJson](auto &&val) { propertyJson = val; }, value);
133 }
134 },
135 service, objectPath, "org.freedesktop.DBus.Properties", "GetAll",
136 interface);
137}
138
139// Find any results that weren't picked up by ObjectManagers, to be
140// called after all ObjectManagers are searched for and called.
141void findRemainingObjectsForEnumerate(
142 const std::string &objectPath, std::shared_ptr<GetSubTreeType> subtree,
143 std::shared_ptr<bmcweb::AsyncResp> asyncResp)
144{
145 BMCWEB_LOG_DEBUG << "findRemainingObjectsForEnumerate";
146 const nlohmann::json &dataJson = asyncResp->res.jsonValue["data"];
147
148 for (const auto &[path, interface_map] : *subtree)
149 {
150 if (path == objectPath)
151 {
152 // An enumerate does not return the target path's properties
153 continue;
154 }
155 if (dataJson.find(path) == dataJson.end())
156 {
157 for (const auto &[service, interfaces] : interface_map)
158 {
159 for (const auto &interface : interfaces)
160 {
161 if (!boost::starts_with(interface, "org.freedesktop.DBus"))
162 {
163 getPropertiesForEnumerate(path, service, interface,
164 asyncResp);
165 }
166 }
167 }
168 }
169 }
170}
171
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600172struct InProgressEnumerateData
173{
174 InProgressEnumerateData(const std::string &objectPath,
175 std::shared_ptr<bmcweb::AsyncResp> asyncResp) :
176 objectPath(objectPath),
177 asyncResp(asyncResp)
178 {
179 }
180
181 ~InProgressEnumerateData()
182 {
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600183 findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600184 }
185
186 const std::string objectPath;
187 std::shared_ptr<GetSubTreeType> subtree;
188 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
189};
190
191void getManagedObjectsForEnumerate(
192 const std::string &object_name, const std::string &object_manager_path,
193 const std::string &connection_name,
194 std::shared_ptr<InProgressEnumerateData> transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700195{
Ed Tanous049a0512018-11-01 13:58:42 -0700196 BMCWEB_LOG_DEBUG << "getManagedObjectsForEnumerate " << object_name
197 << " object_manager_path " << object_manager_path
198 << " connection_name " << connection_name;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700199 crow::connections::systemBus->async_method_call(
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600200 [transaction, object_name,
Ed Tanous049a0512018-11-01 13:58:42 -0700201 connection_name](const boost::system::error_code ec,
202 const dbus::utility::ManagedObjectType &objects) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700203 if (ec)
204 {
Ed Tanous049a0512018-11-01 13:58:42 -0700205 BMCWEB_LOG_ERROR << "GetManagedObjects on path " << object_name
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600206 << " on connection " << connection_name
Ed Tanous049a0512018-11-01 13:58:42 -0700207 << " failed with code " << ec;
208 return;
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700209 }
Ed Tanous64530012018-02-06 17:08:16 -0800210
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600211 nlohmann::json &dataJson =
212 transaction->asyncResp->res.jsonValue["data"];
Ed Tanous049a0512018-11-01 13:58:42 -0700213
214 for (const auto &objectPath : objects)
215 {
216 if (boost::starts_with(objectPath.first.str, object_name))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700217 {
Ed Tanous049a0512018-11-01 13:58:42 -0700218 BMCWEB_LOG_DEBUG << "Reading object "
219 << objectPath.first.str;
220 nlohmann::json &objectJson = dataJson[objectPath.first.str];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700221 if (objectJson.is_null())
222 {
223 objectJson = nlohmann::json::object();
224 }
225 for (const auto &interface : objectPath.second)
226 {
227 for (const auto &property : interface.second)
228 {
229 nlohmann::json &propertyJson =
230 objectJson[property.first];
William A. Kennington III0a63b1c2018-10-18 13:37:19 -0700231 sdbusplus::message::variant_ns::visit(
Ed Tanous1abe55e2018-09-05 08:30:59 -0700232 [&propertyJson](auto &&val) {
233 propertyJson = val;
234 },
235 property.second);
236 }
237 }
238 }
Ed Tanous049a0512018-11-01 13:58:42 -0700239 for (const auto &interface : objectPath.second)
240 {
241 if (interface.first == "org.freedesktop.DBus.ObjectManager")
242 {
243 getManagedObjectsForEnumerate(
244 objectPath.first.str, objectPath.first.str,
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600245 connection_name, transaction);
Ed Tanous049a0512018-11-01 13:58:42 -0700246 }
247 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700248 }
249 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700250 connection_name, object_manager_path,
251 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
252}
253
254void findObjectManagerPathForEnumerate(
255 const std::string &object_name, const std::string &connection_name,
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600256 std::shared_ptr<InProgressEnumerateData> transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700257{
Ed Tanous049a0512018-11-01 13:58:42 -0700258 BMCWEB_LOG_DEBUG << "Finding objectmanager for path " << object_name
259 << " on connection:" << connection_name;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700260 crow::connections::systemBus->async_method_call(
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600261 [transaction, object_name, connection_name](
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700262 const boost::system::error_code ec,
263 const boost::container::flat_map<
264 std::string, boost::container::flat_map<
265 std::string, std::vector<std::string>>>
266 &objects) {
267 if (ec)
268 {
Ed Tanous049a0512018-11-01 13:58:42 -0700269 BMCWEB_LOG_ERROR << "GetAncestors on path " << object_name
270 << " failed with code " << ec;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700271 return;
272 }
273
Ed Tanousf254ba72018-10-12 13:40:35 -0700274 for (const auto &pathGroup : objects)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700275 {
Ed Tanousf254ba72018-10-12 13:40:35 -0700276 for (const auto &connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700277 {
278 if (connectionGroup.first == connection_name)
279 {
280 // Found the object manager path for this resource.
281 getManagedObjectsForEnumerate(
Ed Tanous049a0512018-11-01 13:58:42 -0700282 object_name, pathGroup.first, connection_name,
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600283 transaction);
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700284 return;
285 }
286 }
287 }
288 },
289 "xyz.openbmc_project.ObjectMapper",
290 "/xyz/openbmc_project/object_mapper",
291 "xyz.openbmc_project.ObjectMapper", "GetAncestors", object_name,
292 std::array<const char *, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700293}
Ed Tanous64530012018-02-06 17:08:16 -0800294
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600295// Uses GetObject to add the object info about the target /enumerate path to the
296// results of GetSubTree, as GetSubTree will not return info for the
297// target path, and then continues on enumerating the rest of the tree.
298void getObjectAndEnumerate(std::shared_ptr<InProgressEnumerateData> transaction)
299{
300 using GetObjectType =
301 std::vector<std::pair<std::string, std::vector<std::string>>>;
302
303 crow::connections::systemBus->async_method_call(
304 [transaction](const boost::system::error_code ec,
305 const GetObjectType &objects) {
306 if (ec)
307 {
308 BMCWEB_LOG_ERROR << "GetObject for path "
309 << transaction->objectPath
310 << " failed with code " << ec;
311 return;
312 }
313
314 BMCWEB_LOG_DEBUG << "GetObject for " << transaction->objectPath
315 << " has " << objects.size() << " entries";
316 if (!objects.empty())
317 {
318 transaction->subtree->emplace_back(transaction->objectPath,
319 objects);
320 }
321
322 // Map indicating connection name, and the path where the object
323 // manager exists
324 boost::container::flat_map<std::string, std::string> connections;
325
326 for (const auto &object : *(transaction->subtree))
327 {
328 for (const auto &connection : object.second)
329 {
330 std::string &objectManagerPath =
331 connections[connection.first];
332 for (const auto &interface : connection.second)
333 {
334 BMCWEB_LOG_DEBUG << connection.first
335 << " has interface " << interface;
336 if (interface == "org.freedesktop.DBus.ObjectManager")
337 {
338 BMCWEB_LOG_DEBUG << "found object manager path "
339 << object.first;
340 objectManagerPath = object.first;
341 }
342 }
343 }
344 }
345 BMCWEB_LOG_DEBUG << "Got " << connections.size() << " connections";
346
347 for (const auto &connection : connections)
348 {
349 // If we already know where the object manager is, we don't need
350 // to search for it, we can call directly in to
351 // getManagedObjects
352 if (!connection.second.empty())
353 {
354 getManagedObjectsForEnumerate(
355 transaction->objectPath, connection.second,
356 connection.first, transaction);
357 }
358 else
359 {
360 // otherwise we need to find the object manager path before
361 // we can continue
362 findObjectManagerPathForEnumerate(
363 transaction->objectPath, connection.first, transaction);
364 }
365 }
366 },
367 "xyz.openbmc_project.ObjectMapper",
368 "/xyz/openbmc_project/object_mapper",
369 "xyz.openbmc_project.ObjectMapper", "GetObject",
370 transaction->objectPath, std::array<const char *, 0>());
371}
Ed Tanous64530012018-02-06 17:08:16 -0800372
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700373// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700374struct InProgressActionData
375{
376 InProgressActionData(crow::Response &res) : res(res){};
377 ~InProgressActionData()
378 {
379 if (res.result() == boost::beast::http::status::internal_server_error)
380 {
381 // Reset the json object to clear out any data that made it in
382 // before the error happened todo(ed) handle error condition with
383 // proper code
384 res.jsonValue = nlohmann::json::object();
385 }
386 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700387 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700388
Ed Tanous1abe55e2018-09-05 08:30:59 -0700389 void setErrorStatus()
390 {
391 res.result(boost::beast::http::status::internal_server_error);
392 }
393 crow::Response &res;
394 std::string path;
395 std::string methodName;
396 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700397};
398
Ed Tanous1abe55e2018-09-05 08:30:59 -0700399std::vector<std::string> dbusArgSplit(const std::string &string)
400{
401 std::vector<std::string> ret;
402 if (string.empty())
403 {
404 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700405 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700406 ret.push_back("");
407 int containerDepth = 0;
408
409 for (std::string::const_iterator character = string.begin();
410 character != string.end(); character++)
411 {
412 ret.back() += *character;
413 switch (*character)
414 {
415 case ('a'):
416 break;
417 case ('('):
418 case ('{'):
419 containerDepth++;
420 break;
421 case ('}'):
422 case (')'):
423 containerDepth--;
424 if (containerDepth == 0)
425 {
426 if (character + 1 != string.end())
427 {
428 ret.push_back("");
429 }
430 }
431 break;
432 default:
433 if (containerDepth == 0)
434 {
435 if (character + 1 != string.end())
436 {
437 ret.push_back("");
438 }
439 }
440 break;
441 }
442 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700443}
444
Ed Tanousd76323e2018-08-07 14:35:40 -0700445int convertJsonToDbus(sd_bus_message *m, const std::string &arg_type,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700446 const nlohmann::json &input_json)
447{
448 int r = 0;
449 BMCWEB_LOG_DEBUG << "Converting " << input_json.dump()
450 << " to type: " << arg_type;
451 const std::vector<std::string> argTypes = dbusArgSplit(arg_type);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700452
Ed Tanous1abe55e2018-09-05 08:30:59 -0700453 // Assume a single object for now.
454 const nlohmann::json *j = &input_json;
455 nlohmann::json::const_iterator jIt = input_json.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700456
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700457 for (const std::string &argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700458 {
459 // If we are decoding multiple objects, grab the pointer to the
460 // iterator, and increment it for the next loop
461 if (argTypes.size() > 1)
462 {
463 if (jIt == input_json.end())
464 {
465 return -2;
466 }
467 j = &*jIt;
468 jIt++;
469 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700470 const int64_t *intValue = j->get_ptr<const int64_t *>();
471 const uint64_t *uintValue = j->get_ptr<const uint64_t *>();
472 const std::string *stringValue = j->get_ptr<const std::string *>();
473 const double *doubleValue = j->get_ptr<const double *>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700474 const bool *b = j->get_ptr<const bool *>();
475 int64_t v = 0;
476 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700477
Ed Tanous1abe55e2018-09-05 08:30:59 -0700478 // Do some basic type conversions that make sense. uint can be
479 // converted to int. int and uint can be converted to double
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700480 if (uintValue != nullptr && intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700481 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700482 v = static_cast<int64_t>(*uintValue);
483 intValue = &v;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700484 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700485 if (uintValue != nullptr && doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700486 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700487 d = static_cast<double>(*uintValue);
488 doubleValue = &d;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700489 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700490 if (intValue != nullptr && doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700491 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700492 d = static_cast<double>(*intValue);
493 doubleValue = &d;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700494 }
495
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700496 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700497 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700498 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700499 {
500 return -1;
501 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700502 r = sd_bus_message_append_basic(m, argCode[0],
503 (void *)stringValue->c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700504 if (r < 0)
505 {
506 return r;
507 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700508 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700509 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700510 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700511 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700512 {
513 return -1;
514 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700515 int32_t i = static_cast<int32_t>(*intValue);
516 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700517 if (r < 0)
518 {
519 return r;
520 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700521 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700522 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700523 {
524 // lots of ways bool could be represented here. Try them all
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700525 int boolInt = false;
526 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700527 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700528 boolInt = *intValue > 0 ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700529 }
530 else if (b != nullptr)
531 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700532 boolInt = b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700533 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700534 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700535 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700536 boolInt = boost::istarts_with(*stringValue, "t") ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700537 }
538 else
539 {
540 return -1;
541 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700542 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700543 if (r < 0)
544 {
545 return r;
546 }
547 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700548 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700549 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700550 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700551 {
552 return -1;
553 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700554 int16_t n = static_cast<int16_t>(*intValue);
555 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700556 if (r < 0)
557 {
558 return r;
559 }
560 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700561 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700562 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700563 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700564 {
565 return -1;
566 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700567 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700568 if (r < 0)
569 {
570 return r;
571 }
572 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700573 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700574 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700575 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700576 {
577 return -1;
578 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700579 uint8_t y = static_cast<uint8_t>(*uintValue);
580 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700581 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700582 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700583 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700584 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700585 {
586 return -1;
587 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700588 uint16_t q = static_cast<uint16_t>(*uintValue);
589 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700590 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700591 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700592 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700593 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700594 {
595 return -1;
596 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700597 uint32_t u = static_cast<uint32_t>(*uintValue);
598 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700599 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700600 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700601 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700602 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700603 {
604 return -1;
605 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700606 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700607 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700608 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700609 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700610 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700611 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700612 else if (boost::starts_with(argCode, "a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700613 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700614 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700615 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700616 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700617 if (r < 0)
618 {
619 return r;
620 }
621
622 for (nlohmann::json::const_iterator it = j->begin(); it != j->end();
623 ++it)
624 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700625 r = convertJsonToDbus(m, containedType, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700626 if (r < 0)
627 {
628 return r;
629 }
630
631 it++;
632 }
633 sd_bus_message_close_container(m);
634 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700635 else if (boost::starts_with(argCode, "v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700636 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700637 std::string containedType = argCode.substr(1);
638 BMCWEB_LOG_DEBUG << "variant type: " << argCode
639 << " appending variant of type: " << containedType;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700640 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700641 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700642 if (r < 0)
643 {
644 return r;
645 }
646
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700647 r = convertJsonToDbus(m, containedType, input_json);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700648 if (r < 0)
649 {
650 return r;
651 }
652
653 r = sd_bus_message_close_container(m);
654 if (r < 0)
655 {
656 return r;
657 }
658 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700659 else if (boost::starts_with(argCode, "(") &&
660 boost::ends_with(argCode, ")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700661 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700662 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700663 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700664 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700665 nlohmann::json::const_iterator it = j->begin();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700666 for (const std::string &argCode : dbusArgSplit(arg_type))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700667 {
668 if (it == j->end())
669 {
670 return -1;
671 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700672 r = convertJsonToDbus(m, argCode, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700673 if (r < 0)
674 {
675 return r;
676 }
677 it++;
678 }
679 r = sd_bus_message_close_container(m);
680 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700681 else if (boost::starts_with(argCode, "{") &&
682 boost::ends_with(argCode, "}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700683 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700684 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700685 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700686 containedType.c_str());
687 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700688 if (codes.size() != 2)
689 {
690 return -1;
691 }
692 const std::string &key_type = codes[0];
693 const std::string &value_type = codes[1];
694 for (auto it : j->items())
695 {
696 r = convertJsonToDbus(m, key_type, it.key());
697 if (r < 0)
698 {
699 return r;
700 }
701
702 r = convertJsonToDbus(m, value_type, it.value());
703 if (r < 0)
704 {
705 return r;
706 }
707 }
708 r = sd_bus_message_close_container(m);
709 }
710 else
711 {
712 return -2;
713 }
714 if (r < 0)
715 {
716 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700717 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700718
Ed Tanous1abe55e2018-09-05 08:30:59 -0700719 if (argTypes.size() > 1)
720 {
721 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700722 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700723 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700724}
725
Ed Tanousd76323e2018-08-07 14:35:40 -0700726void findActionOnInterface(std::shared_ptr<InProgressActionData> transaction,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700727 const std::string &connectionName)
728{
729 BMCWEB_LOG_DEBUG << "findActionOnInterface for connection "
730 << connectionName;
731 crow::connections::systemBus->async_method_call(
732 [transaction, connectionName{std::string(connectionName)}](
733 const boost::system::error_code ec,
734 const std::string &introspect_xml) {
735 BMCWEB_LOG_DEBUG << "got xml:\n " << introspect_xml;
736 if (ec)
737 {
738 BMCWEB_LOG_ERROR
739 << "Introspect call failed with error: " << ec.message()
740 << " on process: " << connectionName << "\n";
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700741 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700742 else
743 {
744 tinyxml2::XMLDocument doc;
745
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700746 doc.Parse(introspect_xml.data(), introspect_xml.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700747 tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
748 if (pRoot == nullptr)
749 {
750 BMCWEB_LOG_ERROR << "XML document failed to parse "
751 << connectionName << "\n";
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700752 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700753 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700754 tinyxml2::XMLElement *interfaceNode =
755 pRoot->FirstChildElement("interface");
756 while (interfaceNode != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700757 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700758 const char *thisInterfaceName =
759 interfaceNode->Attribute("name");
760 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700761 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700762 tinyxml2::XMLElement *methodNode =
763 interfaceNode->FirstChildElement("method");
764 while (methodNode != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700765 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700766 const char *thisMethodName =
767 methodNode->Attribute("name");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700768 BMCWEB_LOG_DEBUG << "Found method: "
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700769 << thisMethodName;
770 if (thisMethodName != nullptr &&
771 thisMethodName == transaction->methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700772 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700773 BMCWEB_LOG_DEBUG
774 << "Found method named " << thisMethodName
775 << " on interface " << thisInterfaceName;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700776 sdbusplus::message::message m =
777 crow::connections::systemBus
778 ->new_method_call(
779 connectionName.c_str(),
780 transaction->path.c_str(),
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700781 thisInterfaceName,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700782 transaction->methodName.c_str());
783
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700784 tinyxml2::XMLElement *argumentNode =
785 methodNode->FirstChildElement("arg");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700786
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700787 nlohmann::json::const_iterator argIt =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700788 transaction->arguments.begin();
789
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700790 while (argumentNode != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700791 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700792 const char *argDirection =
793 argumentNode->Attribute("direction");
794 const char *argType =
795 argumentNode->Attribute("type");
796 if (argDirection != nullptr &&
797 argType != nullptr &&
798 std::string(argDirection) == "in")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700799 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700800
801 if (argIt ==
Ed Tanous1abe55e2018-09-05 08:30:59 -0700802 transaction->arguments.end())
803 {
804 transaction->setErrorStatus();
805 return;
806 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700807 if (convertJsonToDbus(
808 m.get(), std::string(argType),
809 *argIt) < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700810 {
811 transaction->setErrorStatus();
812 return;
813 }
814
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700815 argIt++;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700816 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700817 argumentNode =
818 methodNode->NextSiblingElement("arg");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700819 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700820
Ed Tanous1abe55e2018-09-05 08:30:59 -0700821 crow::connections::systemBus->async_send(
822 m, [transaction](
823 boost::system::error_code ec,
824 sdbusplus::message::message &m) {
825 if (ec)
826 {
827 transaction->setErrorStatus();
828 return;
829 }
830 transaction->res.jsonValue = {
831 {"status", "ok"},
832 {"message", "200 OK"},
833 {"data", nullptr}};
834 });
835 break;
836 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700837 methodNode =
838 methodNode->NextSiblingElement("method");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700839 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700840 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700841 interfaceNode =
842 interfaceNode->NextSiblingElement("interface");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700843 }
844 }
845 },
846 connectionName, transaction->path,
847 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700848}
849
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700850void handleAction(const crow::Request &req, crow::Response &res,
851 const std::string &objectPath, const std::string &methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700852{
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700853 BMCWEB_LOG_DEBUG << "handleAction on path: " << objectPath << " and method "
854 << methodName;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700855 nlohmann::json requestDbusData =
856 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700857
Ed Tanous1abe55e2018-09-05 08:30:59 -0700858 if (requestDbusData.is_discarded())
859 {
860 res.result(boost::beast::http::status::bad_request);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700861 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700862 return;
863 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700864 nlohmann::json::iterator data = requestDbusData.find("data");
865 if (data == requestDbusData.end())
866 {
867 res.result(boost::beast::http::status::bad_request);
868 res.end();
869 return;
870 }
871
872 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700873 {
874 res.result(boost::beast::http::status::bad_request);
875 res.end();
876 return;
877 }
878 auto transaction = std::make_shared<InProgressActionData>(res);
879
880 transaction->path = objectPath;
881 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700882 transaction->arguments = std::move(*data);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700883 crow::connections::systemBus->async_method_call(
884 [transaction](
885 const boost::system::error_code ec,
886 const std::vector<std::pair<std::string, std::vector<std::string>>>
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700887 &interfaceNames) {
888 if (ec || interfaceNames.size() <= 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700889 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700890 BMCWEB_LOG_ERROR << "Can't find object";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700891 transaction->setErrorStatus();
892 return;
893 }
894
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700895 BMCWEB_LOG_DEBUG << "GetObject returned " << interfaceNames.size()
896 << " object(s)";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700897
898 for (const std::pair<std::string, std::vector<std::string>>
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700899 &object : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700900 {
901 findActionOnInterface(transaction, object.first);
902 }
903 },
904 "xyz.openbmc_project.ObjectMapper",
905 "/xyz/openbmc_project/object_mapper",
906 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
907 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700908}
909
Ed Tanousf839dfe2018-11-12 11:11:15 -0800910void handleList(crow::Response &res, const std::string &objectPath,
911 int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700912{
913 crow::connections::systemBus->async_method_call(
914 [&res](const boost::system::error_code ec,
915 std::vector<std::string> &objectPaths) {
916 if (ec)
917 {
918 res.result(boost::beast::http::status::internal_server_error);
919 }
920 else
921 {
922 res.jsonValue = {{"status", "ok"},
923 {"message", "200 OK"},
924 {"data", std::move(objectPaths)}};
925 }
926 res.end();
927 },
928 "xyz.openbmc_project.ObjectMapper",
929 "/xyz/openbmc_project/object_mapper",
930 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", objectPath,
Ed Tanousf839dfe2018-11-12 11:11:15 -0800931 depth, std::array<std::string, 0>());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700932}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700933
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700934void handleEnumerate(crow::Response &res, const std::string &objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700935{
Ed Tanous049a0512018-11-01 13:58:42 -0700936 BMCWEB_LOG_DEBUG << "Doing enumerate on " << objectPath;
937 auto asyncResp = std::make_shared<bmcweb::AsyncResp>(res);
938
939 asyncResp->res.jsonValue = {{"message", "200 OK"},
940 {"status", "ok"},
941 {"data", nlohmann::json::object()}};
942
Ed Tanous1abe55e2018-09-05 08:30:59 -0700943 crow::connections::systemBus->async_method_call(
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600944 [objectPath, asyncResp](const boost::system::error_code ec,
945 GetSubTreeType &object_names) {
946 auto transaction = std::make_shared<InProgressEnumerateData>(
947 objectPath, asyncResp);
948
949 transaction->subtree =
950 std::make_shared<GetSubTreeType>(std::move(object_names));
951
Ed Tanous1abe55e2018-09-05 08:30:59 -0700952 if (ec)
953 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700954 return;
955 }
Ed Tanous64530012018-02-06 17:08:16 -0800956
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600957 // Add the data for the path passed in to the results
958 // as if GetSubTree returned it, and continue on enumerating
959 getObjectAndEnumerate(transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700960 },
961 "xyz.openbmc_project.ObjectMapper",
962 "/xyz/openbmc_project/object_mapper",
963 "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath,
Ed Tanous049a0512018-11-01 13:58:42 -0700964 static_cast<int32_t>(0), std::array<const char *, 0>());
Ed Tanous64530012018-02-06 17:08:16 -0800965}
Ed Tanous911ac312017-08-15 09:37:42 -0700966
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700967void handleGet(crow::Response &res, std::string &objectPath,
968 std::string &destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700969{
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700970 BMCWEB_LOG_DEBUG << "handleGet: " << objectPath << " prop:" << destProperty;
971 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700972 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -0700973
Ed Tanous1abe55e2018-09-05 08:30:59 -0700974 std::shared_ptr<std::string> path =
975 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -0700976
Ed Tanous1abe55e2018-09-05 08:30:59 -0700977 using GetObjectType =
978 std::vector<std::pair<std::string, std::vector<std::string>>>;
979 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700980 [&res, path, propertyName](const boost::system::error_code ec,
981 const GetObjectType &object_names) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700982 if (ec || object_names.size() <= 0)
983 {
984 res.result(boost::beast::http::status::not_found);
985 res.end();
986 return;
987 }
988 std::shared_ptr<nlohmann::json> response =
989 std::make_shared<nlohmann::json>(nlohmann::json::object());
990 // The mapper should never give us an empty interface names list,
991 // but check anyway
992 for (const std::pair<std::string, std::vector<std::string>>
993 connection : object_names)
994 {
995 const std::vector<std::string> &interfaceNames =
996 connection.second;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700997
Ed Tanous1abe55e2018-09-05 08:30:59 -0700998 if (interfaceNames.size() <= 0)
999 {
1000 res.result(boost::beast::http::status::not_found);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001001 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001002 return;
1003 }
1004
1005 for (const std::string &interface : interfaceNames)
1006 {
1007 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001008 [&res, response, propertyName](
Ed Tanous1abe55e2018-09-05 08:30:59 -07001009 const boost::system::error_code ec,
James Feist5b4aa862018-08-16 14:07:01 -07001010 const std::vector<std::pair<
1011 std::string, dbus::utility::DbusVariantType>>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001012 &properties) {
1013 if (ec)
1014 {
1015 BMCWEB_LOG_ERROR << "Bad dbus request error: "
1016 << ec;
1017 }
1018 else
1019 {
James Feist5b4aa862018-08-16 14:07:01 -07001020 for (const std::pair<
1021 std::string,
1022 dbus::utility::DbusVariantType>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001023 &property : properties)
1024 {
1025 // if property name is empty, or matches our
1026 // search query, add it to the response json
1027
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001028 if (propertyName->empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001029 {
William A. Kennington III0a63b1c2018-10-18 13:37:19 -07001030 sdbusplus::message::variant_ns::visit(
Ed Tanous1abe55e2018-09-05 08:30:59 -07001031 [&response, &property](auto &&val) {
1032 (*response)[property.first] =
1033 val;
1034 },
1035 property.second);
1036 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001037 else if (property.first == *propertyName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001038 {
William A. Kennington III0a63b1c2018-10-18 13:37:19 -07001039 sdbusplus::message::variant_ns::visit(
Ed Tanous1abe55e2018-09-05 08:30:59 -07001040 [&response](auto &&val) {
1041 (*response) = val;
1042 },
1043 property.second);
1044 }
1045 }
1046 }
1047 if (response.use_count() == 1)
1048 {
1049 res.jsonValue = {{"status", "ok"},
1050 {"message", "200 OK"},
1051 {"data", *response}};
1052
1053 res.end();
1054 }
1055 },
1056 connection.first, *path,
1057 "org.freedesktop.DBus.Properties", "GetAll", interface);
1058 }
1059 }
1060 },
1061 "xyz.openbmc_project.ObjectMapper",
1062 "/xyz/openbmc_project/object_mapper",
1063 "xyz.openbmc_project.ObjectMapper", "GetObject", *path,
1064 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001065}
1066
Ed Tanous1abe55e2018-09-05 08:30:59 -07001067struct AsyncPutRequest
1068{
1069 AsyncPutRequest(crow::Response &res) : res(res)
1070 {
1071 res.jsonValue = {
1072 {"status", "ok"}, {"message", "200 OK"}, {"data", nullptr}};
1073 }
1074 ~AsyncPutRequest()
1075 {
1076 if (res.result() == boost::beast::http::status::internal_server_error)
1077 {
1078 // Reset the json object to clear out any data that made it in
1079 // before the error happened todo(ed) handle error condition with
1080 // proper code
1081 res.jsonValue = nlohmann::json::object();
1082 }
1083
1084 if (res.jsonValue.empty())
1085 {
1086 res.result(boost::beast::http::status::forbidden);
1087 res.jsonValue = {
1088 {"status", "error"},
1089 {"message", "403 Forbidden"},
1090 {"data",
1091 {{"message", "The specified property cannot be created: " +
1092 propertyName}}}};
1093 }
1094
1095 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001096 }
1097
Ed Tanous1abe55e2018-09-05 08:30:59 -07001098 void setErrorStatus()
1099 {
1100 res.result(boost::beast::http::status::internal_server_error);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001101 }
1102
Ed Tanous1abe55e2018-09-05 08:30:59 -07001103 crow::Response &res;
1104 std::string objectPath;
1105 std::string propertyName;
1106 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001107};
1108
Ed Tanousd76323e2018-08-07 14:35:40 -07001109void handlePut(const crow::Request &req, crow::Response &res,
Ed Tanous1abe55e2018-09-05 08:30:59 -07001110 const std::string &objectPath, const std::string &destProperty)
1111{
1112 nlohmann::json requestDbusData =
1113 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001114
Ed Tanous1abe55e2018-09-05 08:30:59 -07001115 if (requestDbusData.is_discarded())
1116 {
1117 res.result(boost::beast::http::status::bad_request);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001118 res.end();
1119 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001120 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001121
Ed Tanous1abe55e2018-09-05 08:30:59 -07001122 nlohmann::json::const_iterator propertyIt = requestDbusData.find("data");
1123 if (propertyIt == requestDbusData.end())
1124 {
1125 res.result(boost::beast::http::status::bad_request);
1126 res.end();
1127 return;
1128 }
1129 const nlohmann::json &propertySetValue = *propertyIt;
1130 auto transaction = std::make_shared<AsyncPutRequest>(res);
1131 transaction->objectPath = objectPath;
1132 transaction->propertyName = destProperty;
1133 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001134
Ed Tanous1abe55e2018-09-05 08:30:59 -07001135 using GetObjectType =
1136 std::vector<std::pair<std::string, std::vector<std::string>>>;
Ed Tanous911ac312017-08-15 09:37:42 -07001137
Ed Tanous1abe55e2018-09-05 08:30:59 -07001138 crow::connections::systemBus->async_method_call(
1139 [transaction](const boost::system::error_code ec,
1140 const GetObjectType &object_names) {
1141 if (!ec && object_names.size() <= 0)
1142 {
1143 transaction->res.result(boost::beast::http::status::not_found);
1144 return;
1145 }
Ed Tanous911ac312017-08-15 09:37:42 -07001146
Ed Tanous1abe55e2018-09-05 08:30:59 -07001147 for (const std::pair<std::string, std::vector<std::string>>
1148 connection : object_names)
1149 {
1150 const std::string &connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001151
Ed Tanous1abe55e2018-09-05 08:30:59 -07001152 crow::connections::systemBus->async_method_call(
1153 [connectionName{std::string(connectionName)},
1154 transaction](const boost::system::error_code ec,
1155 const std::string &introspectXml) {
1156 if (ec)
1157 {
1158 BMCWEB_LOG_ERROR
1159 << "Introspect call failed with error: "
1160 << ec.message()
1161 << " on process: " << connectionName;
1162 transaction->setErrorStatus();
1163 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001164 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001165 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001166
Ed Tanous1abe55e2018-09-05 08:30:59 -07001167 doc.Parse(introspectXml.c_str());
1168 tinyxml2::XMLNode *pRoot =
1169 doc.FirstChildElement("node");
1170 if (pRoot == nullptr)
1171 {
1172 BMCWEB_LOG_ERROR << "XML document failed to parse: "
1173 << introspectXml;
1174 transaction->setErrorStatus();
1175 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001176 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001177 tinyxml2::XMLElement *ifaceNode =
1178 pRoot->FirstChildElement("interface");
1179 while (ifaceNode != nullptr)
1180 {
1181 const char *interfaceName =
1182 ifaceNode->Attribute("name");
1183 BMCWEB_LOG_DEBUG << "found interface "
1184 << interfaceName;
1185 tinyxml2::XMLElement *propNode =
1186 ifaceNode->FirstChildElement("property");
1187 while (propNode != nullptr)
1188 {
1189 const char *propertyName =
1190 propNode->Attribute("name");
1191 BMCWEB_LOG_DEBUG << "Found property "
1192 << propertyName;
1193 if (propertyName == transaction->propertyName)
1194 {
1195 const char *argType =
1196 propNode->Attribute("type");
1197 if (argType != nullptr)
1198 {
1199 sdbusplus::message::message m =
1200 crow::connections::systemBus
1201 ->new_method_call(
1202 connectionName.c_str(),
1203 transaction->objectPath
1204 .c_str(),
1205 "org.freedesktop.DBus."
1206 "Properties",
1207 "Set");
1208 m.append(interfaceName,
1209 transaction->propertyName);
1210 int r = sd_bus_message_open_container(
1211 m.get(), SD_BUS_TYPE_VARIANT,
1212 argType);
1213 if (r < 0)
1214 {
1215 transaction->setErrorStatus();
1216 return;
1217 }
1218 r = convertJsonToDbus(
1219 m.get(), argType,
1220 transaction->propertyValue);
1221 if (r < 0)
1222 {
1223 transaction->setErrorStatus();
1224 return;
1225 }
1226 r = sd_bus_message_close_container(
1227 m.get());
1228 if (r < 0)
1229 {
1230 transaction->setErrorStatus();
1231 return;
1232 }
Ed Tanous911ac312017-08-15 09:37:42 -07001233
Ed Tanous1abe55e2018-09-05 08:30:59 -07001234 crow::connections::systemBus
1235 ->async_send(
1236 m,
1237 [transaction](
1238 boost::system::error_code
1239 ec,
1240 sdbusplus::message::message
1241 &m) {
1242 BMCWEB_LOG_DEBUG << "sent";
1243 if (ec)
1244 {
1245 transaction->res
1246 .jsonValue
1247 ["status"] =
1248 "error";
1249 transaction->res
1250 .jsonValue
1251 ["message"] =
1252 ec.message();
1253 }
1254 });
1255 }
1256 }
1257 propNode =
1258 propNode->NextSiblingElement("property");
1259 }
1260 ifaceNode =
1261 ifaceNode->NextSiblingElement("interface");
1262 }
1263 },
1264 connectionName, transaction->objectPath,
1265 "org.freedesktop.DBus.Introspectable", "Introspect");
1266 }
1267 },
1268 "xyz.openbmc_project.ObjectMapper",
1269 "/xyz/openbmc_project/object_mapper",
1270 "xyz.openbmc_project.ObjectMapper", "GetObject",
1271 transaction->objectPath, std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001272}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001273
Ed Tanous049a0512018-11-01 13:58:42 -07001274inline void handleDBusUrl(const crow::Request &req, crow::Response &res,
1275 std::string &objectPath)
1276{
Ed Tanous049a0512018-11-01 13:58:42 -07001277
1278 // If accessing a single attribute, fill in and update objectPath,
1279 // otherwise leave destProperty blank
1280 std::string destProperty = "";
1281 const char *attrSeperator = "/attr/";
1282 size_t attrPosition = objectPath.find(attrSeperator);
1283 if (attrPosition != objectPath.npos)
1284 {
1285 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
1286 objectPath.length());
1287 objectPath = objectPath.substr(0, attrPosition);
1288 }
1289
1290 if (req.method() == "POST"_method)
1291 {
1292 constexpr const char *actionSeperator = "/action/";
1293 size_t actionPosition = objectPath.find(actionSeperator);
1294 if (actionPosition != objectPath.npos)
1295 {
1296 std::string postProperty =
1297 objectPath.substr((actionPosition + strlen(actionSeperator)),
1298 objectPath.length());
1299 objectPath = objectPath.substr(0, actionPosition);
1300 handleAction(req, res, objectPath, postProperty);
1301 return;
1302 }
1303 }
1304 else if (req.method() == "GET"_method)
1305 {
1306 if (boost::ends_with(objectPath, "/enumerate"))
1307 {
1308 objectPath.erase(objectPath.end() - sizeof("enumerate"),
1309 objectPath.end());
1310 handleEnumerate(res, objectPath);
1311 }
1312 else if (boost::ends_with(objectPath, "/list"))
1313 {
1314 objectPath.erase(objectPath.end() - sizeof("list"),
1315 objectPath.end());
1316 handleList(res, objectPath);
1317 }
1318 else
1319 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08001320 // Trim any trailing "/" at the end
1321 if (boost::ends_with(objectPath, "/"))
1322 {
1323 objectPath.pop_back();
1324 handleList(res, objectPath, 1);
1325 }
1326 else
1327 {
1328 handleGet(res, objectPath, destProperty);
1329 }
Ed Tanous049a0512018-11-01 13:58:42 -07001330 }
1331 return;
1332 }
1333 else if (req.method() == "PUT"_method)
1334 {
1335 handlePut(req, res, objectPath, destProperty);
1336 return;
1337 }
1338
1339 res.result(boost::beast::http::status::method_not_allowed);
1340 res.end();
1341}
1342
Ed Tanous1abe55e2018-09-05 08:30:59 -07001343template <typename... Middlewares> void requestRoutes(Crow<Middlewares...> &app)
1344{
1345 BMCWEB_ROUTE(app, "/bus/")
1346 .methods("GET"_method)(
1347 [](const crow::Request &req, crow::Response &res) {
1348 res.jsonValue = {{"busses", {{{"name", "system"}}}},
1349 {"status", "ok"}};
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001350 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001351 });
1352
1353 BMCWEB_ROUTE(app, "/bus/system/")
1354 .methods("GET"_method)(
1355 [](const crow::Request &req, crow::Response &res) {
1356 auto myCallback = [&res](const boost::system::error_code ec,
1357 std::vector<std::string> &names) {
1358 if (ec)
1359 {
1360 BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
1361 res.result(
1362 boost::beast::http::status::internal_server_error);
1363 }
1364 else
1365 {
1366 std::sort(names.begin(), names.end());
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001367 res.jsonValue = {{"status", "ok"}};
1368 auto &objectsSub = res.jsonValue["objects"];
Ed Tanous1abe55e2018-09-05 08:30:59 -07001369 for (auto &name : names)
1370 {
1371 objectsSub.push_back({{"name", name}});
1372 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001373 }
1374 res.end();
1375 };
1376 crow::connections::systemBus->async_method_call(
1377 std::move(myCallback), "org.freedesktop.DBus", "/",
1378 "org.freedesktop.DBus", "ListNames");
1379 });
1380
1381 BMCWEB_ROUTE(app, "/list/")
1382 .methods("GET"_method)(
1383 [](const crow::Request &req, crow::Response &res) {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001384 handleList(res, "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001385 });
1386
1387 BMCWEB_ROUTE(app, "/xyz/<path>")
Ed Tanous049a0512018-11-01 13:58:42 -07001388 .methods("GET"_method, "PUT"_method, "POST"_method)(
1389 [](const crow::Request &req, crow::Response &res,
1390 const std::string &path) {
1391 std::string objectPath = "/xyz/" + path;
1392 handleDBusUrl(req, res, objectPath);
1393 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001394
Ed Tanous049a0512018-11-01 13:58:42 -07001395 BMCWEB_ROUTE(app, "/org/<path>")
1396 .methods("GET"_method, "PUT"_method, "POST"_method)(
1397 [](const crow::Request &req, crow::Response &res,
1398 const std::string &path) {
1399 std::string objectPath = "/org/" + path;
1400 handleDBusUrl(req, res, objectPath);
1401 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001402
Ed Tanous1abe55e2018-09-05 08:30:59 -07001403 BMCWEB_ROUTE(app, "/download/dump/<str>/")
1404 .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
1405 const std::string &dumpId) {
1406 std::regex validFilename("^[\\w\\- ]+(\\.?[\\w\\- ]+)$");
1407 if (!std::regex_match(dumpId, validFilename))
1408 {
1409 res.result(boost::beast::http::status::not_found);
1410 res.end();
1411 return;
1412 }
1413 std::experimental::filesystem::path loc(
1414 "/var/lib/phosphor-debug-collector/dumps");
1415
1416 loc += dumpId;
1417
1418 if (!std::experimental::filesystem::exists(loc) ||
1419 !std::experimental::filesystem::is_directory(loc))
1420 {
1421 res.result(boost::beast::http::status::not_found);
1422 res.end();
1423 return;
1424 }
1425 std::experimental::filesystem::directory_iterator files(loc);
1426 for (auto &file : files)
1427 {
1428 std::ifstream readFile(file.path());
1429 if (readFile.good())
1430 {
1431 continue;
1432 }
1433 res.addHeader("Content-Type", "application/octet-stream");
1434 res.body() = {std::istreambuf_iterator<char>(readFile),
1435 std::istreambuf_iterator<char>()};
1436 res.end();
1437 }
1438 res.result(boost::beast::http::status::not_found);
1439 res.end();
1440 return;
1441 });
1442
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001443 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous1abe55e2018-09-05 08:30:59 -07001444 .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001445 const std::string &Connection) {
1446 introspectObjects(Connection, "/",
1447 std::make_shared<bmcweb::AsyncResp>(res));
1448 });
1449
1450 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
1451 .methods("GET"_method,
1452 "POST"_method)([](const crow::Request &req,
1453 crow::Response &res,
1454 const std::string &processName,
1455 const std::string &requestedPath) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001456 std::vector<std::string> strs;
1457 boost::split(strs, requestedPath, boost::is_any_of("/"));
1458 std::string objectPath;
1459 std::string interfaceName;
1460 std::string methodName;
1461 auto it = strs.begin();
1462 if (it == strs.end())
1463 {
1464 objectPath = "/";
1465 }
1466 while (it != strs.end())
1467 {
1468 // Check if segment contains ".". If it does, it must be an
1469 // interface
1470 if (it->find(".") != std::string::npos)
1471 {
1472 break;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001473 // This check is neccesary as the trailing slash gets parsed
Ed Tanous1abe55e2018-09-05 08:30:59 -07001474 // as part of our <path> specifier above, which causes the
1475 // normal trailing backslash redirector to fail.
1476 }
1477 else if (!it->empty())
1478 {
1479 objectPath += "/" + *it;
1480 }
1481 it++;
1482 }
1483 if (it != strs.end())
1484 {
1485 interfaceName = *it;
1486 it++;
1487
1488 // after interface, we might have a method name
1489 if (it != strs.end())
1490 {
1491 methodName = *it;
1492 it++;
1493 }
1494 }
1495 if (it != strs.end())
1496 {
1497 // if there is more levels past the method name, something went
1498 // wrong, return not found
1499 res.result(boost::beast::http::status::not_found);
1500 res.end();
1501 return;
1502 }
1503 if (interfaceName.empty())
1504 {
1505 crow::connections::systemBus->async_method_call(
1506 [&, processName,
1507 objectPath](const boost::system::error_code ec,
1508 const std::string &introspect_xml) {
1509 if (ec)
1510 {
1511 BMCWEB_LOG_ERROR
1512 << "Introspect call failed with error: "
1513 << ec.message()
1514 << " on process: " << processName
1515 << " path: " << objectPath << "\n";
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001516 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001517 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001518 tinyxml2::XMLDocument doc;
1519
1520 doc.Parse(introspect_xml.c_str());
1521 tinyxml2::XMLNode *pRoot =
1522 doc.FirstChildElement("node");
1523 if (pRoot == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001524 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001525 BMCWEB_LOG_ERROR << "XML document failed to parse "
1526 << processName << " " << objectPath
1527 << "\n";
1528 res.jsonValue = {{"status", "XML parse error"}};
1529 res.result(boost::beast::http::status::
1530 internal_server_error);
1531 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001532 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001533
1534 BMCWEB_LOG_DEBUG << introspect_xml;
1535 res.jsonValue = {{"status", "ok"},
1536 {"bus_name", processName},
1537 {"object_path", objectPath}};
1538 nlohmann::json &interfacesArray =
1539 res.jsonValue["interfaces"];
1540 interfacesArray = nlohmann::json::array();
1541 tinyxml2::XMLElement *interface =
1542 pRoot->FirstChildElement("interface");
1543
1544 while (interface != nullptr)
1545 {
1546 const char *ifaceName =
1547 interface->Attribute("name");
1548 if (ifaceName != nullptr)
1549 {
1550 interfacesArray.push_back(
1551 {{"name", ifaceName}});
1552 }
1553
1554 interface =
1555 interface->NextSiblingElement("interface");
1556 }
1557
Ed Tanous1abe55e2018-09-05 08:30:59 -07001558 res.end();
1559 },
1560 processName, objectPath,
1561 "org.freedesktop.DBus.Introspectable", "Introspect");
1562 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001563 else if (methodName.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001564 {
1565 crow::connections::systemBus->async_method_call(
1566 [&, processName, objectPath,
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001567 interfaceName{std::move(interfaceName)}](
Ed Tanous1abe55e2018-09-05 08:30:59 -07001568 const boost::system::error_code ec,
1569 const std::string &introspect_xml) {
1570 if (ec)
1571 {
1572 BMCWEB_LOG_ERROR
1573 << "Introspect call failed with error: "
1574 << ec.message()
1575 << " on process: " << processName
1576 << " path: " << objectPath << "\n";
1577 }
1578 else
1579 {
1580 tinyxml2::XMLDocument doc;
1581
1582 doc.Parse(introspect_xml.c_str());
1583 tinyxml2::XMLNode *pRoot =
1584 doc.FirstChildElement("node");
1585 if (pRoot == nullptr)
1586 {
1587 BMCWEB_LOG_ERROR
1588 << "XML document failed to parse "
1589 << processName << " " << objectPath << "\n";
1590 res.result(boost::beast::http::status::
1591 internal_server_error);
1592 }
1593 else
1594 {
1595 tinyxml2::XMLElement *node =
1596 pRoot->FirstChildElement("node");
1597
1598 // if we know we're the only call, build the
1599 // json directly
Ed Tanous1abe55e2018-09-05 08:30:59 -07001600 tinyxml2::XMLElement *interface =
1601 pRoot->FirstChildElement("interface");
1602
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001603 res.jsonValue = {
1604 {"status", "ok"},
1605 {"bus_name", processName},
1606 {"interface", interfaceName},
1607 {"object_path", objectPath},
1608 {"properties", nlohmann::json::object()}};
1609
1610 nlohmann::json &methodsArray =
1611 res.jsonValue["methods"];
1612 methodsArray = nlohmann::json::array();
1613
1614 nlohmann::json &signalsArray =
1615 res.jsonValue["signals"];
1616 signalsArray = nlohmann::json::array();
1617
Ed Tanous1abe55e2018-09-05 08:30:59 -07001618 while (interface != nullptr)
1619 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001620 const char *ifaceName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001621 interface->Attribute("name");
1622
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001623 if (ifaceName != nullptr &&
1624 ifaceName == interfaceName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001625 {
1626 tinyxml2::XMLElement *methods =
1627 interface->FirstChildElement(
1628 "method");
1629 while (methods != nullptr)
1630 {
1631 nlohmann::json argsArray =
1632 nlohmann::json::array();
1633 tinyxml2::XMLElement *arg =
1634 methods->FirstChildElement(
1635 "arg");
1636 while (arg != nullptr)
1637 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001638 nlohmann::json thisArg;
1639 for (const char *fieldName :
1640 std::array<const char *,
1641 3>{"name",
1642 "direction",
1643 "type"})
1644 {
1645 const char *fieldValue =
1646 arg->Attribute(
1647 fieldName);
1648 if (fieldValue != nullptr)
1649 {
1650 thisArg[fieldName] =
1651 fieldValue;
1652 }
1653 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001654 argsArray.push_back(
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001655 std::move(thisArg));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001656 arg = arg->NextSiblingElement(
1657 "arg");
1658 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001659
1660 const char *name =
1661 methods->Attribute("name");
1662 if (name != nullptr)
1663 {
1664 methodsArray.push_back(
1665 {{"name", name},
1666 {"uri", "/bus/system/" +
1667 processName +
1668 objectPath +
1669 "/" +
1670 interfaceName +
1671 "/" + name},
1672 {"args", argsArray}});
1673 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001674 methods =
1675 methods->NextSiblingElement(
1676 "method");
1677 }
1678 tinyxml2::XMLElement *signals =
1679 interface->FirstChildElement(
1680 "signal");
1681 while (signals != nullptr)
1682 {
1683 nlohmann::json argsArray =
1684 nlohmann::json::array();
1685
1686 tinyxml2::XMLElement *arg =
1687 signals->FirstChildElement(
1688 "arg");
1689 while (arg != nullptr)
1690 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001691 const char *name =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001692 arg->Attribute("name");
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001693 const char *type =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001694 arg->Attribute("type");
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001695 if (name != nullptr &&
1696 type != nullptr)
1697 {
1698 argsArray.push_back({
1699 {"name", name},
1700 {"type", type},
1701 });
1702 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001703 arg = arg->NextSiblingElement(
1704 "arg");
1705 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001706 const char *name =
1707 signals->Attribute("name");
1708 if (name != nullptr)
1709 {
1710 signalsArray.push_back(
1711 {{"name", name},
1712 {"args", argsArray}});
1713 }
1714
Ed Tanous1abe55e2018-09-05 08:30:59 -07001715 signals =
1716 signals->NextSiblingElement(
1717 "signal");
1718 }
1719
Ed Tanous1abe55e2018-09-05 08:30:59 -07001720 break;
1721 }
1722
1723 interface = interface->NextSiblingElement(
1724 "interface");
1725 }
1726 if (interface == nullptr)
1727 {
1728 // if we got to the end of the list and
1729 // never found a match, throw 404
1730 res.result(
1731 boost::beast::http::status::not_found);
1732 }
1733 }
1734 }
1735 res.end();
1736 },
1737 processName, objectPath,
1738 "org.freedesktop.DBus.Introspectable", "Introspect");
1739 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001740 else
1741 {
1742 if (req.method() != "POST"_method)
1743 {
1744 res.result(boost::beast::http::status::not_found);
1745 res.end();
1746 return;
1747 }
1748
1749 nlohmann::json requestDbusData =
1750 nlohmann::json::parse(req.body, nullptr, false);
1751
1752 if (requestDbusData.is_discarded())
1753 {
1754 res.result(boost::beast::http::status::bad_request);
1755 res.end();
1756 return;
1757 }
1758 if (!requestDbusData.is_array())
1759 {
1760 res.result(boost::beast::http::status::bad_request);
1761 res.end();
1762 return;
1763 }
1764 auto transaction = std::make_shared<InProgressActionData>(res);
1765
1766 transaction->path = objectPath;
1767 transaction->methodName = methodName;
1768 transaction->arguments = std::move(requestDbusData);
1769
1770 findActionOnInterface(transaction, processName);
1771 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001772 });
1773}
1774} // namespace openbmc_mapper
1775} // namespace crow