blob: 8b9bd05e941f64e2e65bf4ca3b73f523fc0be29d [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
James Feistf6150402019-01-08 10:36:20 -080016#include "filesystem.hpp"
17
Ed Tanous911ac312017-08-15 09:37:42 -070018#include <crow/app.h>
Ed Tanous911ac312017-08-15 09:37:42 -070019#include <tinyxml2.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -070020
Ed Tanouse3cb5a32018-08-08 14:16:49 -070021#include <async_resp.hpp>
Ed Tanous1abe55e2018-09-05 08:30:59 -070022#include <boost/algorithm/string.hpp>
23#include <boost/container/flat_set.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -070024#include <dbus_singleton.hpp>
James Feist5b4aa862018-08-16 14:07:01 -070025#include <dbus_utility.hpp>
Ed Tanousd4bb9bb2018-05-16 13:36:42 -070026#include <fstream>
William A. Kennington III0a63b1c2018-10-18 13:37:19 -070027#include <sdbusplus/message/types.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -070028
Ed Tanous1abe55e2018-09-05 08:30:59 -070029namespace crow
30{
31namespace openbmc_mapper
32{
Ed Tanousba9f9a62017-10-11 16:40:35 -070033
Matt Spinler3ae4ba72018-12-05 14:01:22 -060034using GetSubTreeType = std::vector<
35 std::pair<std::string,
36 std::vector<std::pair<std::string, std::vector<std::string>>>>>;
37
Matt Spinler2ae60092018-12-06 10:35:36 -060038const std::string notFoundMsg = "404 Not Found";
Matt Spinler6db06242018-12-11 11:21:22 -060039const std::string badReqMsg = "400 Bad Request";
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -060040const std::string methodNotAllowedMsg = "405 Method Not Allowed";
Matt Spinlerfbc19ea2018-12-11 14:03:42 -060041const std::string forbiddenMsg = "403 Forbidden";
Matt Spinler6db06242018-12-11 11:21:22 -060042
Matt Spinler2ae60092018-12-06 10:35:36 -060043const std::string notFoundDesc =
44 "org.freedesktop.DBus.Error.FileNotFound: path or object not found";
Matt Spinlerdc2f9f12018-12-06 13:53:53 -060045const std::string propNotFoundDesc = "The specified property cannot be found";
Matt Spinler6db06242018-12-11 11:21:22 -060046const std::string noJsonDesc = "No JSON object could be decoded";
47const std::string methodNotFoundDesc = "The specified method cannot be found";
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -060048const std::string methodNotAllowedDesc = "Method not allowed";
Matt Spinlerfbc19ea2018-12-11 14:03:42 -060049const std::string forbiddenPropDesc =
50 "The specified property cannot be created";
51const std::string forbiddenResDesc = "The specified resource cannot be created";
Matt Spinler2ae60092018-12-06 10:35:36 -060052
53void setErrorResponse(crow::Response &res, boost::beast::http::status result,
54 const std::string &desc, const std::string &msg)
55{
56 res.result(result);
57 res.jsonValue = {{"data", {{"description", desc}}},
58 {"message", msg},
59 {"status", "error"}};
60}
61
Ed Tanouse3cb5a32018-08-08 14:16:49 -070062void introspectObjects(const std::string &processName,
63 const std::string &objectPath,
64 std::shared_ptr<bmcweb::AsyncResp> transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -070065{
Ed Tanouse3cb5a32018-08-08 14:16:49 -070066 if (transaction->res.jsonValue.is_null())
67 {
68 transaction->res.jsonValue = {{"status", "ok"},
69 {"bus_name", processName},
70 {"objects", nlohmann::json::array()}};
71 }
72
Ed Tanous1abe55e2018-09-05 08:30:59 -070073 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -070074 [transaction, processName{std::string(processName)},
75 objectPath{std::string(objectPath)}](
76 const boost::system::error_code ec,
77 const std::string &introspect_xml) {
Ed Tanous1abe55e2018-09-05 08:30:59 -070078 if (ec)
79 {
80 BMCWEB_LOG_ERROR
81 << "Introspect call failed with error: " << ec.message()
82 << " on process: " << processName << " path: " << objectPath
83 << "\n";
Ed Tanouse3cb5a32018-08-08 14:16:49 -070084 return;
85 }
86 transaction->res.jsonValue["objects"].push_back(
87 {{"path", objectPath}});
88
89 tinyxml2::XMLDocument doc;
90
91 doc.Parse(introspect_xml.c_str());
92 tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
93 if (pRoot == nullptr)
94 {
95 BMCWEB_LOG_ERROR << "XML document failed to parse "
96 << processName << " " << objectPath << "\n";
Ed Tanous911ac312017-08-15 09:37:42 -070097 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070098 else
99 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700100 tinyxml2::XMLElement *node = pRoot->FirstChildElement("node");
101 while (node != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700102 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700103 const char *childPath = node->Attribute("name");
104 if (childPath != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700105 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700106 std::string newpath;
107 if (objectPath != "/")
108 {
109 newpath += objectPath;
110 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700111 newpath += std::string("/") + childPath;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700112 // introspect the subobjects as well
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700113 introspectObjects(processName, newpath, transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700114 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700115
116 node = node->NextSiblingElement("node");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700117 }
118 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700119 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700120 processName, objectPath, "org.freedesktop.DBus.Introspectable",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700121 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -0700122}
Ed Tanous64530012018-02-06 17:08:16 -0800123
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600124void getPropertiesForEnumerate(const std::string &objectPath,
125 const std::string &service,
126 const std::string &interface,
127 std::shared_ptr<bmcweb::AsyncResp> asyncResp)
128{
129 BMCWEB_LOG_DEBUG << "getPropertiesForEnumerate " << objectPath << " "
130 << service << " " << interface;
131
132 crow::connections::systemBus->async_method_call(
133 [asyncResp, objectPath, service,
134 interface](const boost::system::error_code ec,
135 const std::vector<
136 std::pair<std::string, dbus::utility::DbusVariantType>>
137 &propertiesList) {
138 if (ec)
139 {
140 BMCWEB_LOG_ERROR << "GetAll on path " << objectPath << " iface "
141 << interface << " service " << service
142 << " failed with code " << ec;
143 return;
144 }
145
146 nlohmann::json &dataJson = asyncResp->res.jsonValue["data"];
147 nlohmann::json &objectJson = dataJson[objectPath];
148 if (objectJson.is_null())
149 {
150 objectJson = nlohmann::json::object();
151 }
152
153 for (const auto &[name, value] : propertiesList)
154 {
155 nlohmann::json &propertyJson = objectJson[name];
156 sdbusplus::message::variant_ns::visit(
157 [&propertyJson](auto &&val) { propertyJson = val; }, value);
158 }
159 },
160 service, objectPath, "org.freedesktop.DBus.Properties", "GetAll",
161 interface);
162}
163
164// Find any results that weren't picked up by ObjectManagers, to be
165// called after all ObjectManagers are searched for and called.
166void findRemainingObjectsForEnumerate(
167 const std::string &objectPath, std::shared_ptr<GetSubTreeType> subtree,
168 std::shared_ptr<bmcweb::AsyncResp> asyncResp)
169{
170 BMCWEB_LOG_DEBUG << "findRemainingObjectsForEnumerate";
171 const nlohmann::json &dataJson = asyncResp->res.jsonValue["data"];
172
173 for (const auto &[path, interface_map] : *subtree)
174 {
175 if (path == objectPath)
176 {
177 // An enumerate does not return the target path's properties
178 continue;
179 }
180 if (dataJson.find(path) == dataJson.end())
181 {
182 for (const auto &[service, interfaces] : interface_map)
183 {
184 for (const auto &interface : interfaces)
185 {
186 if (!boost::starts_with(interface, "org.freedesktop.DBus"))
187 {
188 getPropertiesForEnumerate(path, service, interface,
189 asyncResp);
190 }
191 }
192 }
193 }
194 }
195}
196
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600197struct InProgressEnumerateData
198{
199 InProgressEnumerateData(const std::string &objectPath,
200 std::shared_ptr<bmcweb::AsyncResp> asyncResp) :
201 objectPath(objectPath),
202 asyncResp(asyncResp)
203 {
204 }
205
206 ~InProgressEnumerateData()
207 {
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600208 findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600209 }
210
211 const std::string objectPath;
212 std::shared_ptr<GetSubTreeType> subtree;
213 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
214};
215
216void getManagedObjectsForEnumerate(
217 const std::string &object_name, const std::string &object_manager_path,
218 const std::string &connection_name,
219 std::shared_ptr<InProgressEnumerateData> transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700220{
Ed Tanous049a0512018-11-01 13:58:42 -0700221 BMCWEB_LOG_DEBUG << "getManagedObjectsForEnumerate " << object_name
222 << " object_manager_path " << object_manager_path
223 << " connection_name " << connection_name;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700224 crow::connections::systemBus->async_method_call(
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600225 [transaction, object_name,
Ed Tanous049a0512018-11-01 13:58:42 -0700226 connection_name](const boost::system::error_code ec,
227 const dbus::utility::ManagedObjectType &objects) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700228 if (ec)
229 {
Ed Tanous049a0512018-11-01 13:58:42 -0700230 BMCWEB_LOG_ERROR << "GetManagedObjects on path " << object_name
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600231 << " on connection " << connection_name
Ed Tanous049a0512018-11-01 13:58:42 -0700232 << " failed with code " << ec;
233 return;
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700234 }
Ed Tanous64530012018-02-06 17:08:16 -0800235
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600236 nlohmann::json &dataJson =
237 transaction->asyncResp->res.jsonValue["data"];
Ed Tanous049a0512018-11-01 13:58:42 -0700238
239 for (const auto &objectPath : objects)
240 {
241 if (boost::starts_with(objectPath.first.str, object_name))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700242 {
Ed Tanous049a0512018-11-01 13:58:42 -0700243 BMCWEB_LOG_DEBUG << "Reading object "
244 << objectPath.first.str;
245 nlohmann::json &objectJson = dataJson[objectPath.first.str];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700246 if (objectJson.is_null())
247 {
248 objectJson = nlohmann::json::object();
249 }
250 for (const auto &interface : objectPath.second)
251 {
252 for (const auto &property : interface.second)
253 {
254 nlohmann::json &propertyJson =
255 objectJson[property.first];
William A. Kennington III0a63b1c2018-10-18 13:37:19 -0700256 sdbusplus::message::variant_ns::visit(
Ed Tanous1abe55e2018-09-05 08:30:59 -0700257 [&propertyJson](auto &&val) {
258 propertyJson = val;
259 },
260 property.second);
261 }
262 }
263 }
Ed Tanous049a0512018-11-01 13:58:42 -0700264 for (const auto &interface : objectPath.second)
265 {
266 if (interface.first == "org.freedesktop.DBus.ObjectManager")
267 {
268 getManagedObjectsForEnumerate(
269 objectPath.first.str, objectPath.first.str,
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600270 connection_name, transaction);
Ed Tanous049a0512018-11-01 13:58:42 -0700271 }
272 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700273 }
274 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700275 connection_name, object_manager_path,
276 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
277}
278
279void findObjectManagerPathForEnumerate(
280 const std::string &object_name, const std::string &connection_name,
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600281 std::shared_ptr<InProgressEnumerateData> transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700282{
Ed Tanous049a0512018-11-01 13:58:42 -0700283 BMCWEB_LOG_DEBUG << "Finding objectmanager for path " << object_name
284 << " on connection:" << connection_name;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700285 crow::connections::systemBus->async_method_call(
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600286 [transaction, object_name, connection_name](
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700287 const boost::system::error_code ec,
288 const boost::container::flat_map<
289 std::string, boost::container::flat_map<
290 std::string, std::vector<std::string>>>
291 &objects) {
292 if (ec)
293 {
Ed Tanous049a0512018-11-01 13:58:42 -0700294 BMCWEB_LOG_ERROR << "GetAncestors on path " << object_name
295 << " failed with code " << ec;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700296 return;
297 }
298
Ed Tanousf254ba72018-10-12 13:40:35 -0700299 for (const auto &pathGroup : objects)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700300 {
Ed Tanousf254ba72018-10-12 13:40:35 -0700301 for (const auto &connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700302 {
303 if (connectionGroup.first == connection_name)
304 {
305 // Found the object manager path for this resource.
306 getManagedObjectsForEnumerate(
Ed Tanous049a0512018-11-01 13:58:42 -0700307 object_name, pathGroup.first, connection_name,
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600308 transaction);
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700309 return;
310 }
311 }
312 }
313 },
314 "xyz.openbmc_project.ObjectMapper",
315 "/xyz/openbmc_project/object_mapper",
316 "xyz.openbmc_project.ObjectMapper", "GetAncestors", object_name,
317 std::array<const char *, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700318}
Ed Tanous64530012018-02-06 17:08:16 -0800319
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600320// Uses GetObject to add the object info about the target /enumerate path to the
321// results of GetSubTree, as GetSubTree will not return info for the
322// target path, and then continues on enumerating the rest of the tree.
323void getObjectAndEnumerate(std::shared_ptr<InProgressEnumerateData> transaction)
324{
325 using GetObjectType =
326 std::vector<std::pair<std::string, std::vector<std::string>>>;
327
328 crow::connections::systemBus->async_method_call(
329 [transaction](const boost::system::error_code ec,
330 const GetObjectType &objects) {
331 if (ec)
332 {
333 BMCWEB_LOG_ERROR << "GetObject for path "
334 << transaction->objectPath
335 << " failed with code " << ec;
336 return;
337 }
338
339 BMCWEB_LOG_DEBUG << "GetObject for " << transaction->objectPath
340 << " has " << objects.size() << " entries";
341 if (!objects.empty())
342 {
343 transaction->subtree->emplace_back(transaction->objectPath,
344 objects);
345 }
346
347 // Map indicating connection name, and the path where the object
348 // manager exists
349 boost::container::flat_map<std::string, std::string> connections;
350
351 for (const auto &object : *(transaction->subtree))
352 {
353 for (const auto &connection : object.second)
354 {
355 std::string &objectManagerPath =
356 connections[connection.first];
357 for (const auto &interface : connection.second)
358 {
359 BMCWEB_LOG_DEBUG << connection.first
360 << " has interface " << interface;
361 if (interface == "org.freedesktop.DBus.ObjectManager")
362 {
363 BMCWEB_LOG_DEBUG << "found object manager path "
364 << object.first;
365 objectManagerPath = object.first;
366 }
367 }
368 }
369 }
370 BMCWEB_LOG_DEBUG << "Got " << connections.size() << " connections";
371
372 for (const auto &connection : connections)
373 {
374 // If we already know where the object manager is, we don't need
375 // to search for it, we can call directly in to
376 // getManagedObjects
377 if (!connection.second.empty())
378 {
379 getManagedObjectsForEnumerate(
380 transaction->objectPath, connection.second,
381 connection.first, transaction);
382 }
383 else
384 {
385 // otherwise we need to find the object manager path before
386 // we can continue
387 findObjectManagerPathForEnumerate(
388 transaction->objectPath, connection.first, transaction);
389 }
390 }
391 },
392 "xyz.openbmc_project.ObjectMapper",
393 "/xyz/openbmc_project/object_mapper",
394 "xyz.openbmc_project.ObjectMapper", "GetObject",
395 transaction->objectPath, std::array<const char *, 0>());
396}
Ed Tanous64530012018-02-06 17:08:16 -0800397
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700398// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700399struct InProgressActionData
400{
401 InProgressActionData(crow::Response &res) : res(res){};
402 ~InProgressActionData()
403 {
Matt Spinler6db06242018-12-11 11:21:22 -0600404 // If still no JSON filled in, then we never found the method.
405 if (res.jsonValue.is_null())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700406 {
Matt Spinler6db06242018-12-11 11:21:22 -0600407 setErrorResponse(res, boost::beast::http::status::not_found,
408 methodNotFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700409 }
410 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700411 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700412
Matt Spinler6db06242018-12-11 11:21:22 -0600413 void setErrorStatus(const std::string &desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700414 {
Matt Spinler6db06242018-12-11 11:21:22 -0600415 setErrorResponse(res, boost::beast::http::status::internal_server_error,
416 desc, badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700417 }
418 crow::Response &res;
419 std::string path;
420 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600421 std::string interfaceName;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700422 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700423};
424
Ed Tanous1abe55e2018-09-05 08:30:59 -0700425std::vector<std::string> dbusArgSplit(const std::string &string)
426{
427 std::vector<std::string> ret;
428 if (string.empty())
429 {
430 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700431 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700432 ret.push_back("");
433 int containerDepth = 0;
434
435 for (std::string::const_iterator character = string.begin();
436 character != string.end(); character++)
437 {
438 ret.back() += *character;
439 switch (*character)
440 {
441 case ('a'):
442 break;
443 case ('('):
444 case ('{'):
445 containerDepth++;
446 break;
447 case ('}'):
448 case (')'):
449 containerDepth--;
450 if (containerDepth == 0)
451 {
452 if (character + 1 != string.end())
453 {
454 ret.push_back("");
455 }
456 }
457 break;
458 default:
459 if (containerDepth == 0)
460 {
461 if (character + 1 != string.end())
462 {
463 ret.push_back("");
464 }
465 }
466 break;
467 }
468 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700469}
470
Ed Tanousd76323e2018-08-07 14:35:40 -0700471int convertJsonToDbus(sd_bus_message *m, const std::string &arg_type,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700472 const nlohmann::json &input_json)
473{
474 int r = 0;
475 BMCWEB_LOG_DEBUG << "Converting " << input_json.dump()
476 << " to type: " << arg_type;
477 const std::vector<std::string> argTypes = dbusArgSplit(arg_type);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700478
Ed Tanous1abe55e2018-09-05 08:30:59 -0700479 // Assume a single object for now.
480 const nlohmann::json *j = &input_json;
481 nlohmann::json::const_iterator jIt = input_json.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700482
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700483 for (const std::string &argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700484 {
485 // If we are decoding multiple objects, grab the pointer to the
486 // iterator, and increment it for the next loop
487 if (argTypes.size() > 1)
488 {
489 if (jIt == input_json.end())
490 {
491 return -2;
492 }
493 j = &*jIt;
494 jIt++;
495 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700496 const int64_t *intValue = j->get_ptr<const int64_t *>();
497 const uint64_t *uintValue = j->get_ptr<const uint64_t *>();
498 const std::string *stringValue = j->get_ptr<const std::string *>();
499 const double *doubleValue = j->get_ptr<const double *>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700500 const bool *b = j->get_ptr<const bool *>();
501 int64_t v = 0;
502 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700503
Ed Tanous1abe55e2018-09-05 08:30:59 -0700504 // Do some basic type conversions that make sense. uint can be
505 // converted to int. int and uint can be converted to double
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700506 if (uintValue != nullptr && intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700507 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700508 v = static_cast<int64_t>(*uintValue);
509 intValue = &v;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700510 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700511 if (uintValue != nullptr && doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700512 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700513 d = static_cast<double>(*uintValue);
514 doubleValue = &d;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700515 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700516 if (intValue != nullptr && doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700517 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700518 d = static_cast<double>(*intValue);
519 doubleValue = &d;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700520 }
521
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700522 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700523 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700524 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700525 {
526 return -1;
527 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700528 r = sd_bus_message_append_basic(m, argCode[0],
529 (void *)stringValue->c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700530 if (r < 0)
531 {
532 return r;
533 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700534 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700535 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700536 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700537 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700538 {
539 return -1;
540 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700541 int32_t i = static_cast<int32_t>(*intValue);
542 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700543 if (r < 0)
544 {
545 return r;
546 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700547 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700548 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700549 {
550 // lots of ways bool could be represented here. Try them all
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700551 int boolInt = false;
552 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700553 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700554 boolInt = *intValue > 0 ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700555 }
556 else if (b != nullptr)
557 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700558 boolInt = b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700559 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700560 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700561 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700562 boolInt = boost::istarts_with(*stringValue, "t") ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700563 }
564 else
565 {
566 return -1;
567 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700568 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
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 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700575 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700576 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700577 {
578 return -1;
579 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700580 int16_t n = static_cast<int16_t>(*intValue);
581 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700582 if (r < 0)
583 {
584 return r;
585 }
586 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700587 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700588 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700589 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700590 {
591 return -1;
592 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700593 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700594 if (r < 0)
595 {
596 return r;
597 }
598 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700599 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700600 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700601 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700602 {
603 return -1;
604 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700605 uint8_t y = static_cast<uint8_t>(*uintValue);
606 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700607 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700608 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700609 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700610 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700611 {
612 return -1;
613 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700614 uint16_t q = static_cast<uint16_t>(*uintValue);
615 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700616 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700617 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700618 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700619 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700620 {
621 return -1;
622 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700623 uint32_t u = static_cast<uint32_t>(*uintValue);
624 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700625 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700626 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700627 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700628 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700629 {
630 return -1;
631 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700632 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700633 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700634 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700635 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700636 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700637 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700638 else if (boost::starts_with(argCode, "a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700639 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700640 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700641 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700642 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700643 if (r < 0)
644 {
645 return r;
646 }
647
648 for (nlohmann::json::const_iterator it = j->begin(); it != j->end();
649 ++it)
650 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700651 r = convertJsonToDbus(m, containedType, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700652 if (r < 0)
653 {
654 return r;
655 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700656 }
657 sd_bus_message_close_container(m);
658 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700659 else if (boost::starts_with(argCode, "v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700660 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700661 std::string containedType = argCode.substr(1);
662 BMCWEB_LOG_DEBUG << "variant type: " << argCode
663 << " appending variant of type: " << containedType;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700664 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700665 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700666 if (r < 0)
667 {
668 return r;
669 }
670
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700671 r = convertJsonToDbus(m, containedType, input_json);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700672 if (r < 0)
673 {
674 return r;
675 }
676
677 r = sd_bus_message_close_container(m);
678 if (r < 0)
679 {
680 return r;
681 }
682 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700683 else if (boost::starts_with(argCode, "(") &&
684 boost::ends_with(argCode, ")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700685 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700686 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700687 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700688 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700689 nlohmann::json::const_iterator it = j->begin();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700690 for (const std::string &argCode : dbusArgSplit(arg_type))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700691 {
692 if (it == j->end())
693 {
694 return -1;
695 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700696 r = convertJsonToDbus(m, argCode, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700697 if (r < 0)
698 {
699 return r;
700 }
701 it++;
702 }
703 r = sd_bus_message_close_container(m);
704 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700705 else if (boost::starts_with(argCode, "{") &&
706 boost::ends_with(argCode, "}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700707 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700708 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700709 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700710 containedType.c_str());
711 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700712 if (codes.size() != 2)
713 {
714 return -1;
715 }
716 const std::string &key_type = codes[0];
717 const std::string &value_type = codes[1];
718 for (auto it : j->items())
719 {
720 r = convertJsonToDbus(m, key_type, it.key());
721 if (r < 0)
722 {
723 return r;
724 }
725
726 r = convertJsonToDbus(m, value_type, it.value());
727 if (r < 0)
728 {
729 return r;
730 }
731 }
732 r = sd_bus_message_close_container(m);
733 }
734 else
735 {
736 return -2;
737 }
738 if (r < 0)
739 {
740 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700741 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700742
Ed Tanous1abe55e2018-09-05 08:30:59 -0700743 if (argTypes.size() > 1)
744 {
745 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700746 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700747 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700748}
749
Ed Tanousd76323e2018-08-07 14:35:40 -0700750void findActionOnInterface(std::shared_ptr<InProgressActionData> transaction,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700751 const std::string &connectionName)
752{
753 BMCWEB_LOG_DEBUG << "findActionOnInterface for connection "
754 << connectionName;
755 crow::connections::systemBus->async_method_call(
756 [transaction, connectionName{std::string(connectionName)}](
757 const boost::system::error_code ec,
758 const std::string &introspect_xml) {
759 BMCWEB_LOG_DEBUG << "got xml:\n " << introspect_xml;
760 if (ec)
761 {
762 BMCWEB_LOG_ERROR
763 << "Introspect call failed with error: " << ec.message()
764 << " on process: " << connectionName << "\n";
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700765 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700766 else
767 {
768 tinyxml2::XMLDocument doc;
769
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700770 doc.Parse(introspect_xml.data(), introspect_xml.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700771 tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
772 if (pRoot == nullptr)
773 {
774 BMCWEB_LOG_ERROR << "XML document failed to parse "
775 << connectionName << "\n";
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700776 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700777 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700778 tinyxml2::XMLElement *interfaceNode =
779 pRoot->FirstChildElement("interface");
780 while (interfaceNode != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700781 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700782 const char *thisInterfaceName =
783 interfaceNode->Attribute("name");
784 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700785 {
Matt Spinlerde818812018-12-11 16:39:20 -0600786 if (!transaction->interfaceName.empty() &&
787 (transaction->interfaceName != thisInterfaceName))
788 {
789 interfaceNode =
790 interfaceNode->NextSiblingElement("interface");
791 continue;
792 }
793
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700794 tinyxml2::XMLElement *methodNode =
795 interfaceNode->FirstChildElement("method");
796 while (methodNode != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700797 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700798 const char *thisMethodName =
799 methodNode->Attribute("name");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700800 BMCWEB_LOG_DEBUG << "Found method: "
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700801 << thisMethodName;
802 if (thisMethodName != nullptr &&
803 thisMethodName == transaction->methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700804 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700805 BMCWEB_LOG_DEBUG
806 << "Found method named " << thisMethodName
807 << " on interface " << thisInterfaceName;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700808 sdbusplus::message::message m =
809 crow::connections::systemBus
810 ->new_method_call(
811 connectionName.c_str(),
812 transaction->path.c_str(),
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700813 thisInterfaceName,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700814 transaction->methodName.c_str());
815
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700816 tinyxml2::XMLElement *argumentNode =
817 methodNode->FirstChildElement("arg");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700818
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700819 nlohmann::json::const_iterator argIt =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700820 transaction->arguments.begin();
821
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700822 while (argumentNode != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700823 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700824 const char *argDirection =
825 argumentNode->Attribute("direction");
826 const char *argType =
827 argumentNode->Attribute("type");
828 if (argDirection != nullptr &&
829 argType != nullptr &&
830 std::string(argDirection) == "in")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700831 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700832 if (argIt ==
Ed Tanous1abe55e2018-09-05 08:30:59 -0700833 transaction->arguments.end())
834 {
Matt Spinler6db06242018-12-11 11:21:22 -0600835 transaction->setErrorStatus(
836 "Invalid method args");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700837 return;
838 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700839 if (convertJsonToDbus(
840 m.get(), std::string(argType),
841 *argIt) < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700842 {
Matt Spinler6db06242018-12-11 11:21:22 -0600843 transaction->setErrorStatus(
844 "Invalid method arg type");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700845 return;
846 }
847
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700848 argIt++;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700849 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700850 argumentNode =
AppaRao Puli4d72dcc2018-12-26 20:26:22 +0530851 argumentNode->NextSiblingElement("arg");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700852 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700853
Ed Tanous1abe55e2018-09-05 08:30:59 -0700854 crow::connections::systemBus->async_send(
855 m, [transaction](
856 boost::system::error_code ec,
857 sdbusplus::message::message &m) {
858 if (ec)
859 {
Matt Spinler6db06242018-12-11 11:21:22 -0600860 transaction->setErrorStatus(
861 "Method call failed");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700862 return;
863 }
864 transaction->res.jsonValue = {
865 {"status", "ok"},
866 {"message", "200 OK"},
867 {"data", nullptr}};
868 });
869 break;
870 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700871 methodNode =
872 methodNode->NextSiblingElement("method");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700873 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700874 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700875 interfaceNode =
876 interfaceNode->NextSiblingElement("interface");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700877 }
878 }
879 },
880 connectionName, transaction->path,
881 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700882}
883
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700884void handleAction(const crow::Request &req, crow::Response &res,
885 const std::string &objectPath, const std::string &methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700886{
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700887 BMCWEB_LOG_DEBUG << "handleAction on path: " << objectPath << " and method "
888 << methodName;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700889 nlohmann::json requestDbusData =
890 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700891
Ed Tanous1abe55e2018-09-05 08:30:59 -0700892 if (requestDbusData.is_discarded())
893 {
Matt Spinler6db06242018-12-11 11:21:22 -0600894 setErrorResponse(res, boost::beast::http::status::bad_request,
895 noJsonDesc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700896 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700897 return;
898 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700899 nlohmann::json::iterator data = requestDbusData.find("data");
900 if (data == requestDbusData.end())
901 {
Matt Spinler6db06242018-12-11 11:21:22 -0600902 setErrorResponse(res, boost::beast::http::status::bad_request,
903 noJsonDesc, badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700904 res.end();
905 return;
906 }
907
908 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700909 {
Matt Spinler6db06242018-12-11 11:21:22 -0600910 setErrorResponse(res, boost::beast::http::status::bad_request,
911 noJsonDesc, badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700912 res.end();
913 return;
914 }
915 auto transaction = std::make_shared<InProgressActionData>(res);
916
917 transaction->path = objectPath;
918 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700919 transaction->arguments = std::move(*data);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700920 crow::connections::systemBus->async_method_call(
921 [transaction](
922 const boost::system::error_code ec,
923 const std::vector<std::pair<std::string, std::vector<std::string>>>
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700924 &interfaceNames) {
925 if (ec || interfaceNames.size() <= 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700926 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700927 BMCWEB_LOG_ERROR << "Can't find object";
Matt Spinler6db06242018-12-11 11:21:22 -0600928 setErrorResponse(transaction->res,
929 boost::beast::http::status::not_found,
930 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700931 return;
932 }
933
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700934 BMCWEB_LOG_DEBUG << "GetObject returned " << interfaceNames.size()
935 << " object(s)";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700936
937 for (const std::pair<std::string, std::vector<std::string>>
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700938 &object : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700939 {
940 findActionOnInterface(transaction, object.first);
941 }
942 },
943 "xyz.openbmc_project.ObjectMapper",
944 "/xyz/openbmc_project/object_mapper",
945 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
946 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700947}
948
Matt Spinlerde818812018-12-11 16:39:20 -0600949void handleDelete(const crow::Request &req, crow::Response &res,
950 const std::string &objectPath)
951{
952 BMCWEB_LOG_DEBUG << "handleDelete on path: " << objectPath;
953
954 crow::connections::systemBus->async_method_call(
955 [&res, objectPath](
956 const boost::system::error_code ec,
957 const std::vector<std::pair<std::string, std::vector<std::string>>>
958 &interfaceNames) {
959 if (ec || interfaceNames.size() <= 0)
960 {
961 BMCWEB_LOG_ERROR << "Can't find object";
962 setErrorResponse(res, boost::beast::http::status::not_found,
963 notFoundDesc, notFoundMsg);
964 res.end();
965 return;
966 }
967
968 auto transaction = std::make_shared<InProgressActionData>(res);
969 transaction->path = objectPath;
970 transaction->methodName = "Delete";
971 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
972
973 for (const std::pair<std::string, std::vector<std::string>>
974 &object : interfaceNames)
975 {
976 findActionOnInterface(transaction, object.first);
977 }
978 },
979 "xyz.openbmc_project.ObjectMapper",
980 "/xyz/openbmc_project/object_mapper",
981 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
982 std::array<const char *, 0>());
983}
984
Ed Tanousf839dfe2018-11-12 11:11:15 -0800985void handleList(crow::Response &res, const std::string &objectPath,
986 int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700987{
988 crow::connections::systemBus->async_method_call(
989 [&res](const boost::system::error_code ec,
990 std::vector<std::string> &objectPaths) {
991 if (ec)
992 {
Matt Spinlerd6091dd2018-12-06 14:08:27 -0600993 setErrorResponse(res, boost::beast::http::status::not_found,
994 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700995 }
996 else
997 {
998 res.jsonValue = {{"status", "ok"},
999 {"message", "200 OK"},
1000 {"data", std::move(objectPaths)}};
1001 }
1002 res.end();
1003 },
1004 "xyz.openbmc_project.ObjectMapper",
1005 "/xyz/openbmc_project/object_mapper",
1006 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", objectPath,
Ed Tanousf839dfe2018-11-12 11:11:15 -08001007 depth, std::array<std::string, 0>());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001008}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001009
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001010void handleEnumerate(crow::Response &res, const std::string &objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001011{
Ed Tanous049a0512018-11-01 13:58:42 -07001012 BMCWEB_LOG_DEBUG << "Doing enumerate on " << objectPath;
1013 auto asyncResp = std::make_shared<bmcweb::AsyncResp>(res);
1014
1015 asyncResp->res.jsonValue = {{"message", "200 OK"},
1016 {"status", "ok"},
1017 {"data", nlohmann::json::object()}};
1018
Ed Tanous1abe55e2018-09-05 08:30:59 -07001019 crow::connections::systemBus->async_method_call(
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001020 [objectPath, asyncResp](const boost::system::error_code ec,
1021 GetSubTreeType &object_names) {
1022 auto transaction = std::make_shared<InProgressEnumerateData>(
1023 objectPath, asyncResp);
1024
1025 transaction->subtree =
1026 std::make_shared<GetSubTreeType>(std::move(object_names));
1027
Ed Tanous1abe55e2018-09-05 08:30:59 -07001028 if (ec)
1029 {
Matt Spinler2ae60092018-12-06 10:35:36 -06001030 BMCWEB_LOG_ERROR << "GetSubTree failed on "
1031 << transaction->objectPath;
1032 setErrorResponse(transaction->asyncResp->res,
1033 boost::beast::http::status::not_found,
1034 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001035 return;
1036 }
Ed Tanous64530012018-02-06 17:08:16 -08001037
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001038 // Add the data for the path passed in to the results
1039 // as if GetSubTree returned it, and continue on enumerating
1040 getObjectAndEnumerate(transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001041 },
1042 "xyz.openbmc_project.ObjectMapper",
1043 "/xyz/openbmc_project/object_mapper",
1044 "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath,
Ed Tanous049a0512018-11-01 13:58:42 -07001045 static_cast<int32_t>(0), std::array<const char *, 0>());
Ed Tanous64530012018-02-06 17:08:16 -08001046}
Ed Tanous911ac312017-08-15 09:37:42 -07001047
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001048void handleGet(crow::Response &res, std::string &objectPath,
1049 std::string &destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001050{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001051 BMCWEB_LOG_DEBUG << "handleGet: " << objectPath << " prop:" << destProperty;
1052 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001053 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001054
Ed Tanous1abe55e2018-09-05 08:30:59 -07001055 std::shared_ptr<std::string> path =
1056 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001057
Ed Tanous1abe55e2018-09-05 08:30:59 -07001058 using GetObjectType =
1059 std::vector<std::pair<std::string, std::vector<std::string>>>;
1060 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001061 [&res, path, propertyName](const boost::system::error_code ec,
1062 const GetObjectType &object_names) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001063 if (ec || object_names.size() <= 0)
1064 {
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001065 setErrorResponse(res, boost::beast::http::status::not_found,
1066 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001067 res.end();
1068 return;
1069 }
1070 std::shared_ptr<nlohmann::json> response =
1071 std::make_shared<nlohmann::json>(nlohmann::json::object());
1072 // The mapper should never give us an empty interface names list,
1073 // but check anyway
1074 for (const std::pair<std::string, std::vector<std::string>>
1075 connection : object_names)
1076 {
1077 const std::vector<std::string> &interfaceNames =
1078 connection.second;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001079
Ed Tanous1abe55e2018-09-05 08:30:59 -07001080 if (interfaceNames.size() <= 0)
1081 {
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001082 setErrorResponse(res, boost::beast::http::status::not_found,
1083 notFoundDesc, notFoundMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001084 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001085 return;
1086 }
1087
1088 for (const std::string &interface : interfaceNames)
1089 {
1090 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001091 [&res, response, propertyName](
Ed Tanous1abe55e2018-09-05 08:30:59 -07001092 const boost::system::error_code ec,
James Feist5b4aa862018-08-16 14:07:01 -07001093 const std::vector<std::pair<
1094 std::string, dbus::utility::DbusVariantType>>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001095 &properties) {
1096 if (ec)
1097 {
1098 BMCWEB_LOG_ERROR << "Bad dbus request error: "
1099 << ec;
1100 }
1101 else
1102 {
James Feist5b4aa862018-08-16 14:07:01 -07001103 for (const std::pair<
1104 std::string,
1105 dbus::utility::DbusVariantType>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001106 &property : properties)
1107 {
1108 // if property name is empty, or matches our
1109 // search query, add it to the response json
1110
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001111 if (propertyName->empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001112 {
William A. Kennington III0a63b1c2018-10-18 13:37:19 -07001113 sdbusplus::message::variant_ns::visit(
Ed Tanous1abe55e2018-09-05 08:30:59 -07001114 [&response, &property](auto &&val) {
1115 (*response)[property.first] =
1116 val;
1117 },
1118 property.second);
1119 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001120 else if (property.first == *propertyName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001121 {
William A. Kennington III0a63b1c2018-10-18 13:37:19 -07001122 sdbusplus::message::variant_ns::visit(
Ed Tanous1abe55e2018-09-05 08:30:59 -07001123 [&response](auto &&val) {
1124 (*response) = val;
1125 },
1126 property.second);
1127 }
1128 }
1129 }
1130 if (response.use_count() == 1)
1131 {
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001132 if (!propertyName->empty() && response->empty())
1133 {
1134 setErrorResponse(
1135 res,
1136 boost::beast::http::status::not_found,
1137 propNotFoundDesc, notFoundMsg);
1138 }
1139 else
1140 {
1141 res.jsonValue = {{"status", "ok"},
1142 {"message", "200 OK"},
1143 {"data", *response}};
1144 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001145 res.end();
1146 }
1147 },
1148 connection.first, *path,
1149 "org.freedesktop.DBus.Properties", "GetAll", interface);
1150 }
1151 }
1152 },
1153 "xyz.openbmc_project.ObjectMapper",
1154 "/xyz/openbmc_project/object_mapper",
1155 "xyz.openbmc_project.ObjectMapper", "GetObject", *path,
1156 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001157}
1158
Ed Tanous1abe55e2018-09-05 08:30:59 -07001159struct AsyncPutRequest
1160{
1161 AsyncPutRequest(crow::Response &res) : res(res)
1162 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001163 }
1164 ~AsyncPutRequest()
1165 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001166 if (res.jsonValue.empty())
1167 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001168 setErrorResponse(res, boost::beast::http::status::forbidden,
1169 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001170 }
1171
1172 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001173 }
1174
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001175 void setErrorStatus(const std::string &desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001176 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001177 setErrorResponse(res, boost::beast::http::status::internal_server_error,
1178 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001179 }
1180
Ed Tanous1abe55e2018-09-05 08:30:59 -07001181 crow::Response &res;
1182 std::string objectPath;
1183 std::string propertyName;
1184 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001185};
1186
Ed Tanousd76323e2018-08-07 14:35:40 -07001187void handlePut(const crow::Request &req, crow::Response &res,
Ed Tanous1abe55e2018-09-05 08:30:59 -07001188 const std::string &objectPath, const std::string &destProperty)
1189{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001190 if (destProperty.empty())
1191 {
1192 setErrorResponse(res, boost::beast::http::status::forbidden,
1193 forbiddenResDesc, forbiddenMsg);
1194 res.end();
1195 return;
1196 }
1197
Ed Tanous1abe55e2018-09-05 08:30:59 -07001198 nlohmann::json requestDbusData =
1199 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001200
Ed Tanous1abe55e2018-09-05 08:30:59 -07001201 if (requestDbusData.is_discarded())
1202 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001203 setErrorResponse(res, boost::beast::http::status::bad_request,
1204 noJsonDesc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001205 res.end();
1206 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001207 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001208
Ed Tanous1abe55e2018-09-05 08:30:59 -07001209 nlohmann::json::const_iterator propertyIt = requestDbusData.find("data");
1210 if (propertyIt == requestDbusData.end())
1211 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001212 setErrorResponse(res, boost::beast::http::status::bad_request,
1213 noJsonDesc, badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001214 res.end();
1215 return;
1216 }
1217 const nlohmann::json &propertySetValue = *propertyIt;
1218 auto transaction = std::make_shared<AsyncPutRequest>(res);
1219 transaction->objectPath = objectPath;
1220 transaction->propertyName = destProperty;
1221 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001222
Ed Tanous1abe55e2018-09-05 08:30:59 -07001223 using GetObjectType =
1224 std::vector<std::pair<std::string, std::vector<std::string>>>;
Ed Tanous911ac312017-08-15 09:37:42 -07001225
Ed Tanous1abe55e2018-09-05 08:30:59 -07001226 crow::connections::systemBus->async_method_call(
1227 [transaction](const boost::system::error_code ec,
1228 const GetObjectType &object_names) {
1229 if (!ec && object_names.size() <= 0)
1230 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001231 setErrorResponse(transaction->res,
1232 boost::beast::http::status::not_found,
1233 propNotFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001234 return;
1235 }
Ed Tanous911ac312017-08-15 09:37:42 -07001236
Ed Tanous1abe55e2018-09-05 08:30:59 -07001237 for (const std::pair<std::string, std::vector<std::string>>
1238 connection : object_names)
1239 {
1240 const std::string &connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001241
Ed Tanous1abe55e2018-09-05 08:30:59 -07001242 crow::connections::systemBus->async_method_call(
1243 [connectionName{std::string(connectionName)},
1244 transaction](const boost::system::error_code ec,
1245 const std::string &introspectXml) {
1246 if (ec)
1247 {
1248 BMCWEB_LOG_ERROR
1249 << "Introspect call failed with error: "
1250 << ec.message()
1251 << " on process: " << connectionName;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001252 transaction->setErrorStatus("Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001253 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001254 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001255 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001256
Ed Tanous1abe55e2018-09-05 08:30:59 -07001257 doc.Parse(introspectXml.c_str());
1258 tinyxml2::XMLNode *pRoot =
1259 doc.FirstChildElement("node");
1260 if (pRoot == nullptr)
1261 {
1262 BMCWEB_LOG_ERROR << "XML document failed to parse: "
1263 << introspectXml;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001264 transaction->setErrorStatus("Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001265 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001266 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001267 tinyxml2::XMLElement *ifaceNode =
1268 pRoot->FirstChildElement("interface");
1269 while (ifaceNode != nullptr)
1270 {
1271 const char *interfaceName =
1272 ifaceNode->Attribute("name");
1273 BMCWEB_LOG_DEBUG << "found interface "
1274 << interfaceName;
1275 tinyxml2::XMLElement *propNode =
1276 ifaceNode->FirstChildElement("property");
1277 while (propNode != nullptr)
1278 {
1279 const char *propertyName =
1280 propNode->Attribute("name");
1281 BMCWEB_LOG_DEBUG << "Found property "
1282 << propertyName;
1283 if (propertyName == transaction->propertyName)
1284 {
1285 const char *argType =
1286 propNode->Attribute("type");
1287 if (argType != nullptr)
1288 {
1289 sdbusplus::message::message m =
1290 crow::connections::systemBus
1291 ->new_method_call(
1292 connectionName.c_str(),
1293 transaction->objectPath
1294 .c_str(),
1295 "org.freedesktop.DBus."
1296 "Properties",
1297 "Set");
1298 m.append(interfaceName,
1299 transaction->propertyName);
1300 int r = sd_bus_message_open_container(
1301 m.get(), SD_BUS_TYPE_VARIANT,
1302 argType);
1303 if (r < 0)
1304 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001305 transaction->setErrorStatus(
1306 "Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001307 return;
1308 }
1309 r = convertJsonToDbus(
1310 m.get(), argType,
1311 transaction->propertyValue);
1312 if (r < 0)
1313 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001314 transaction->setErrorStatus(
1315 "Invalid arg type");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001316 return;
1317 }
1318 r = sd_bus_message_close_container(
1319 m.get());
1320 if (r < 0)
1321 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001322 transaction->setErrorStatus(
1323 "Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001324 return;
1325 }
Ed Tanous911ac312017-08-15 09:37:42 -07001326
Ed Tanous1abe55e2018-09-05 08:30:59 -07001327 crow::connections::systemBus
1328 ->async_send(
1329 m,
1330 [transaction](
1331 boost::system::error_code
1332 ec,
1333 sdbusplus::message::message
1334 &m) {
1335 BMCWEB_LOG_DEBUG << "sent";
1336 if (ec)
1337 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001338 setErrorResponse(
1339 transaction->res,
1340 boost::beast::http::
1341 status::
1342 forbidden,
1343 forbiddenPropDesc,
1344 ec.message());
1345 }
1346 else
1347 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001348 transaction->res
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001349 .jsonValue = {
1350 {"status", "ok"},
1351 {"message",
1352 "200 OK"},
1353 {"data", nullptr}};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001354 }
1355 });
1356 }
1357 }
1358 propNode =
1359 propNode->NextSiblingElement("property");
1360 }
1361 ifaceNode =
1362 ifaceNode->NextSiblingElement("interface");
1363 }
1364 },
1365 connectionName, transaction->objectPath,
1366 "org.freedesktop.DBus.Introspectable", "Introspect");
1367 }
1368 },
1369 "xyz.openbmc_project.ObjectMapper",
1370 "/xyz/openbmc_project/object_mapper",
1371 "xyz.openbmc_project.ObjectMapper", "GetObject",
1372 transaction->objectPath, std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001373}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001374
Ed Tanous049a0512018-11-01 13:58:42 -07001375inline void handleDBusUrl(const crow::Request &req, crow::Response &res,
1376 std::string &objectPath)
1377{
Ed Tanous049a0512018-11-01 13:58:42 -07001378
1379 // If accessing a single attribute, fill in and update objectPath,
1380 // otherwise leave destProperty blank
1381 std::string destProperty = "";
1382 const char *attrSeperator = "/attr/";
1383 size_t attrPosition = objectPath.find(attrSeperator);
1384 if (attrPosition != objectPath.npos)
1385 {
1386 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
1387 objectPath.length());
1388 objectPath = objectPath.substr(0, attrPosition);
1389 }
1390
1391 if (req.method() == "POST"_method)
1392 {
1393 constexpr const char *actionSeperator = "/action/";
1394 size_t actionPosition = objectPath.find(actionSeperator);
1395 if (actionPosition != objectPath.npos)
1396 {
1397 std::string postProperty =
1398 objectPath.substr((actionPosition + strlen(actionSeperator)),
1399 objectPath.length());
1400 objectPath = objectPath.substr(0, actionPosition);
1401 handleAction(req, res, objectPath, postProperty);
1402 return;
1403 }
1404 }
1405 else if (req.method() == "GET"_method)
1406 {
1407 if (boost::ends_with(objectPath, "/enumerate"))
1408 {
1409 objectPath.erase(objectPath.end() - sizeof("enumerate"),
1410 objectPath.end());
1411 handleEnumerate(res, objectPath);
1412 }
1413 else if (boost::ends_with(objectPath, "/list"))
1414 {
1415 objectPath.erase(objectPath.end() - sizeof("list"),
1416 objectPath.end());
1417 handleList(res, objectPath);
1418 }
1419 else
1420 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08001421 // Trim any trailing "/" at the end
1422 if (boost::ends_with(objectPath, "/"))
1423 {
1424 objectPath.pop_back();
1425 handleList(res, objectPath, 1);
1426 }
1427 else
1428 {
1429 handleGet(res, objectPath, destProperty);
1430 }
Ed Tanous049a0512018-11-01 13:58:42 -07001431 }
1432 return;
1433 }
1434 else if (req.method() == "PUT"_method)
1435 {
1436 handlePut(req, res, objectPath, destProperty);
1437 return;
1438 }
Matt Spinlerde818812018-12-11 16:39:20 -06001439 else if (req.method() == "DELETE"_method)
1440 {
1441 handleDelete(req, res, objectPath);
1442 return;
1443 }
Ed Tanous049a0512018-11-01 13:58:42 -07001444
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06001445 setErrorResponse(res, boost::beast::http::status::method_not_allowed,
1446 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07001447 res.end();
1448}
1449
Ed Tanous1abe55e2018-09-05 08:30:59 -07001450template <typename... Middlewares> void requestRoutes(Crow<Middlewares...> &app)
1451{
1452 BMCWEB_ROUTE(app, "/bus/")
1453 .methods("GET"_method)(
1454 [](const crow::Request &req, crow::Response &res) {
1455 res.jsonValue = {{"busses", {{{"name", "system"}}}},
1456 {"status", "ok"}};
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001457 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001458 });
1459
1460 BMCWEB_ROUTE(app, "/bus/system/")
1461 .methods("GET"_method)(
1462 [](const crow::Request &req, crow::Response &res) {
1463 auto myCallback = [&res](const boost::system::error_code ec,
1464 std::vector<std::string> &names) {
1465 if (ec)
1466 {
1467 BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
1468 res.result(
1469 boost::beast::http::status::internal_server_error);
1470 }
1471 else
1472 {
1473 std::sort(names.begin(), names.end());
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001474 res.jsonValue = {{"status", "ok"}};
1475 auto &objectsSub = res.jsonValue["objects"];
Ed Tanous1abe55e2018-09-05 08:30:59 -07001476 for (auto &name : names)
1477 {
1478 objectsSub.push_back({{"name", name}});
1479 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001480 }
1481 res.end();
1482 };
1483 crow::connections::systemBus->async_method_call(
1484 std::move(myCallback), "org.freedesktop.DBus", "/",
1485 "org.freedesktop.DBus", "ListNames");
1486 });
1487
1488 BMCWEB_ROUTE(app, "/list/")
1489 .methods("GET"_method)(
1490 [](const crow::Request &req, crow::Response &res) {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001491 handleList(res, "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001492 });
1493
1494 BMCWEB_ROUTE(app, "/xyz/<path>")
Matt Spinlerde818812018-12-11 16:39:20 -06001495 .methods("GET"_method, "PUT"_method, "POST"_method, "DELETE"_method)(
Ed Tanous049a0512018-11-01 13:58:42 -07001496 [](const crow::Request &req, crow::Response &res,
1497 const std::string &path) {
1498 std::string objectPath = "/xyz/" + path;
1499 handleDBusUrl(req, res, objectPath);
1500 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001501
Ed Tanous049a0512018-11-01 13:58:42 -07001502 BMCWEB_ROUTE(app, "/org/<path>")
Matt Spinlerde818812018-12-11 16:39:20 -06001503 .methods("GET"_method, "PUT"_method, "POST"_method, "DELETE"_method)(
Ed Tanous049a0512018-11-01 13:58:42 -07001504 [](const crow::Request &req, crow::Response &res,
1505 const std::string &path) {
1506 std::string objectPath = "/org/" + path;
1507 handleDBusUrl(req, res, objectPath);
1508 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001509
Ed Tanous1abe55e2018-09-05 08:30:59 -07001510 BMCWEB_ROUTE(app, "/download/dump/<str>/")
1511 .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
1512 const std::string &dumpId) {
Ed Tanousad18f072018-11-14 14:07:48 -08001513 std::regex validFilename("^[\\w\\- ]+(\\.?[\\w\\- ]*)$");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001514 if (!std::regex_match(dumpId, validFilename))
1515 {
Ed Tanousad18f072018-11-14 14:07:48 -08001516 res.result(boost::beast::http::status::bad_request);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001517 res.end();
1518 return;
1519 }
James Feistf6150402019-01-08 10:36:20 -08001520 std::filesystem::path loc(
Ed Tanous1abe55e2018-09-05 08:30:59 -07001521 "/var/lib/phosphor-debug-collector/dumps");
1522
Ed Tanousad18f072018-11-14 14:07:48 -08001523 loc /= dumpId;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001524
James Feistf6150402019-01-08 10:36:20 -08001525 if (!std::filesystem::exists(loc) ||
1526 !std::filesystem::is_directory(loc))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001527 {
Ed Tanousad18f072018-11-14 14:07:48 -08001528 BMCWEB_LOG_ERROR << loc << "Not found";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001529 res.result(boost::beast::http::status::not_found);
1530 res.end();
1531 return;
1532 }
James Feistf6150402019-01-08 10:36:20 -08001533 std::filesystem::directory_iterator files(loc);
Ed Tanousad18f072018-11-14 14:07:48 -08001534
Ed Tanous1abe55e2018-09-05 08:30:59 -07001535 for (auto &file : files)
1536 {
1537 std::ifstream readFile(file.path());
Ed Tanousad18f072018-11-14 14:07:48 -08001538 if (!readFile.good())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001539 {
1540 continue;
1541 }
1542 res.addHeader("Content-Type", "application/octet-stream");
1543 res.body() = {std::istreambuf_iterator<char>(readFile),
1544 std::istreambuf_iterator<char>()};
1545 res.end();
Ed Tanousad18f072018-11-14 14:07:48 -08001546 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001547 }
1548 res.result(boost::beast::http::status::not_found);
1549 res.end();
1550 return;
1551 });
1552
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001553 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous1abe55e2018-09-05 08:30:59 -07001554 .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001555 const std::string &Connection) {
1556 introspectObjects(Connection, "/",
1557 std::make_shared<bmcweb::AsyncResp>(res));
1558 });
1559
1560 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
1561 .methods("GET"_method,
1562 "POST"_method)([](const crow::Request &req,
1563 crow::Response &res,
1564 const std::string &processName,
1565 const std::string &requestedPath) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001566 std::vector<std::string> strs;
1567 boost::split(strs, requestedPath, boost::is_any_of("/"));
1568 std::string objectPath;
1569 std::string interfaceName;
1570 std::string methodName;
1571 auto it = strs.begin();
1572 if (it == strs.end())
1573 {
1574 objectPath = "/";
1575 }
1576 while (it != strs.end())
1577 {
1578 // Check if segment contains ".". If it does, it must be an
1579 // interface
1580 if (it->find(".") != std::string::npos)
1581 {
1582 break;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001583 // This check is neccesary as the trailing slash gets parsed
Ed Tanous1abe55e2018-09-05 08:30:59 -07001584 // as part of our <path> specifier above, which causes the
1585 // normal trailing backslash redirector to fail.
1586 }
1587 else if (!it->empty())
1588 {
1589 objectPath += "/" + *it;
1590 }
1591 it++;
1592 }
1593 if (it != strs.end())
1594 {
1595 interfaceName = *it;
1596 it++;
1597
1598 // after interface, we might have a method name
1599 if (it != strs.end())
1600 {
1601 methodName = *it;
1602 it++;
1603 }
1604 }
1605 if (it != strs.end())
1606 {
1607 // if there is more levels past the method name, something went
1608 // wrong, return not found
1609 res.result(boost::beast::http::status::not_found);
1610 res.end();
1611 return;
1612 }
1613 if (interfaceName.empty())
1614 {
1615 crow::connections::systemBus->async_method_call(
1616 [&, processName,
1617 objectPath](const boost::system::error_code ec,
1618 const std::string &introspect_xml) {
1619 if (ec)
1620 {
1621 BMCWEB_LOG_ERROR
1622 << "Introspect call failed with error: "
1623 << ec.message()
1624 << " on process: " << processName
1625 << " path: " << objectPath << "\n";
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001626 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001627 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001628 tinyxml2::XMLDocument doc;
1629
1630 doc.Parse(introspect_xml.c_str());
1631 tinyxml2::XMLNode *pRoot =
1632 doc.FirstChildElement("node");
1633 if (pRoot == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001634 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001635 BMCWEB_LOG_ERROR << "XML document failed to parse "
1636 << processName << " " << objectPath
1637 << "\n";
1638 res.jsonValue = {{"status", "XML parse error"}};
1639 res.result(boost::beast::http::status::
1640 internal_server_error);
1641 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001642 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001643
1644 BMCWEB_LOG_DEBUG << introspect_xml;
1645 res.jsonValue = {{"status", "ok"},
1646 {"bus_name", processName},
1647 {"object_path", objectPath}};
1648 nlohmann::json &interfacesArray =
1649 res.jsonValue["interfaces"];
1650 interfacesArray = nlohmann::json::array();
1651 tinyxml2::XMLElement *interface =
1652 pRoot->FirstChildElement("interface");
1653
1654 while (interface != nullptr)
1655 {
1656 const char *ifaceName =
1657 interface->Attribute("name");
1658 if (ifaceName != nullptr)
1659 {
1660 interfacesArray.push_back(
1661 {{"name", ifaceName}});
1662 }
1663
1664 interface =
1665 interface->NextSiblingElement("interface");
1666 }
1667
Ed Tanous1abe55e2018-09-05 08:30:59 -07001668 res.end();
1669 },
1670 processName, objectPath,
1671 "org.freedesktop.DBus.Introspectable", "Introspect");
1672 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001673 else if (methodName.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001674 {
1675 crow::connections::systemBus->async_method_call(
1676 [&, processName, objectPath,
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001677 interfaceName{std::move(interfaceName)}](
Ed Tanous1abe55e2018-09-05 08:30:59 -07001678 const boost::system::error_code ec,
1679 const std::string &introspect_xml) {
1680 if (ec)
1681 {
1682 BMCWEB_LOG_ERROR
1683 << "Introspect call failed with error: "
1684 << ec.message()
1685 << " on process: " << processName
1686 << " path: " << objectPath << "\n";
1687 }
1688 else
1689 {
1690 tinyxml2::XMLDocument doc;
1691
1692 doc.Parse(introspect_xml.c_str());
1693 tinyxml2::XMLNode *pRoot =
1694 doc.FirstChildElement("node");
1695 if (pRoot == nullptr)
1696 {
1697 BMCWEB_LOG_ERROR
1698 << "XML document failed to parse "
1699 << processName << " " << objectPath << "\n";
1700 res.result(boost::beast::http::status::
1701 internal_server_error);
1702 }
1703 else
1704 {
1705 tinyxml2::XMLElement *node =
1706 pRoot->FirstChildElement("node");
1707
1708 // if we know we're the only call, build the
1709 // json directly
Ed Tanous1abe55e2018-09-05 08:30:59 -07001710 tinyxml2::XMLElement *interface =
1711 pRoot->FirstChildElement("interface");
1712
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001713 res.jsonValue = {
1714 {"status", "ok"},
1715 {"bus_name", processName},
1716 {"interface", interfaceName},
1717 {"object_path", objectPath},
1718 {"properties", nlohmann::json::object()}};
1719
1720 nlohmann::json &methodsArray =
1721 res.jsonValue["methods"];
1722 methodsArray = nlohmann::json::array();
1723
1724 nlohmann::json &signalsArray =
1725 res.jsonValue["signals"];
1726 signalsArray = nlohmann::json::array();
1727
Ed Tanous1abe55e2018-09-05 08:30:59 -07001728 while (interface != nullptr)
1729 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001730 const char *ifaceName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001731 interface->Attribute("name");
1732
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001733 if (ifaceName != nullptr &&
1734 ifaceName == interfaceName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001735 {
1736 tinyxml2::XMLElement *methods =
1737 interface->FirstChildElement(
1738 "method");
1739 while (methods != nullptr)
1740 {
1741 nlohmann::json argsArray =
1742 nlohmann::json::array();
1743 tinyxml2::XMLElement *arg =
1744 methods->FirstChildElement(
1745 "arg");
1746 while (arg != nullptr)
1747 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001748 nlohmann::json thisArg;
1749 for (const char *fieldName :
1750 std::array<const char *,
1751 3>{"name",
1752 "direction",
1753 "type"})
1754 {
1755 const char *fieldValue =
1756 arg->Attribute(
1757 fieldName);
1758 if (fieldValue != nullptr)
1759 {
1760 thisArg[fieldName] =
1761 fieldValue;
1762 }
1763 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001764 argsArray.push_back(
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001765 std::move(thisArg));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001766 arg = arg->NextSiblingElement(
1767 "arg");
1768 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001769
1770 const char *name =
1771 methods->Attribute("name");
1772 if (name != nullptr)
1773 {
1774 methodsArray.push_back(
1775 {{"name", name},
1776 {"uri", "/bus/system/" +
1777 processName +
1778 objectPath +
1779 "/" +
1780 interfaceName +
1781 "/" + name},
1782 {"args", argsArray}});
1783 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001784 methods =
1785 methods->NextSiblingElement(
1786 "method");
1787 }
1788 tinyxml2::XMLElement *signals =
1789 interface->FirstChildElement(
1790 "signal");
1791 while (signals != nullptr)
1792 {
1793 nlohmann::json argsArray =
1794 nlohmann::json::array();
1795
1796 tinyxml2::XMLElement *arg =
1797 signals->FirstChildElement(
1798 "arg");
1799 while (arg != nullptr)
1800 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001801 const char *name =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001802 arg->Attribute("name");
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001803 const char *type =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001804 arg->Attribute("type");
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001805 if (name != nullptr &&
1806 type != nullptr)
1807 {
1808 argsArray.push_back({
1809 {"name", name},
1810 {"type", type},
1811 });
1812 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001813 arg = arg->NextSiblingElement(
1814 "arg");
1815 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001816 const char *name =
1817 signals->Attribute("name");
1818 if (name != nullptr)
1819 {
1820 signalsArray.push_back(
1821 {{"name", name},
1822 {"args", argsArray}});
1823 }
1824
Ed Tanous1abe55e2018-09-05 08:30:59 -07001825 signals =
1826 signals->NextSiblingElement(
1827 "signal");
1828 }
1829
Ed Tanous1abe55e2018-09-05 08:30:59 -07001830 break;
1831 }
1832
1833 interface = interface->NextSiblingElement(
1834 "interface");
1835 }
1836 if (interface == nullptr)
1837 {
1838 // if we got to the end of the list and
1839 // never found a match, throw 404
1840 res.result(
1841 boost::beast::http::status::not_found);
1842 }
1843 }
1844 }
1845 res.end();
1846 },
1847 processName, objectPath,
1848 "org.freedesktop.DBus.Introspectable", "Introspect");
1849 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001850 else
1851 {
1852 if (req.method() != "POST"_method)
1853 {
1854 res.result(boost::beast::http::status::not_found);
1855 res.end();
1856 return;
1857 }
1858
1859 nlohmann::json requestDbusData =
1860 nlohmann::json::parse(req.body, nullptr, false);
1861
1862 if (requestDbusData.is_discarded())
1863 {
1864 res.result(boost::beast::http::status::bad_request);
1865 res.end();
1866 return;
1867 }
1868 if (!requestDbusData.is_array())
1869 {
1870 res.result(boost::beast::http::status::bad_request);
1871 res.end();
1872 return;
1873 }
1874 auto transaction = std::make_shared<InProgressActionData>(res);
1875
1876 transaction->path = objectPath;
1877 transaction->methodName = methodName;
1878 transaction->arguments = std::move(requestDbusData);
1879
1880 findActionOnInterface(transaction, processName);
1881 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001882 });
1883}
1884} // namespace openbmc_mapper
1885} // namespace crow