blob: f1dbdafd1206946f6e0694177a222584c999442f [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 Spinlerc0eb9bd2019-01-09 15:22:30 -060042const std::string methodFailedMsg = "500 Method Call Failed";
Matt Spinler6db06242018-12-11 11:21:22 -060043
Matt Spinler2ae60092018-12-06 10:35:36 -060044const std::string notFoundDesc =
45 "org.freedesktop.DBus.Error.FileNotFound: path or object not found";
Matt Spinlerdc2f9f12018-12-06 13:53:53 -060046const std::string propNotFoundDesc = "The specified property cannot be found";
Matt Spinler6db06242018-12-11 11:21:22 -060047const std::string noJsonDesc = "No JSON object could be decoded";
48const std::string methodNotFoundDesc = "The specified method cannot be found";
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -060049const std::string methodNotAllowedDesc = "Method not allowed";
Matt Spinlerfbc19ea2018-12-11 14:03:42 -060050const std::string forbiddenPropDesc =
51 "The specified property cannot be created";
52const std::string forbiddenResDesc = "The specified resource cannot be created";
Matt Spinler2ae60092018-12-06 10:35:36 -060053
54void setErrorResponse(crow::Response &res, boost::beast::http::status result,
55 const std::string &desc, const std::string &msg)
56{
57 res.result(result);
58 res.jsonValue = {{"data", {{"description", desc}}},
59 {"message", msg},
60 {"status", "error"}};
61}
62
Ed Tanouse3cb5a32018-08-08 14:16:49 -070063void introspectObjects(const std::string &processName,
64 const std::string &objectPath,
65 std::shared_ptr<bmcweb::AsyncResp> transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -070066{
Ed Tanouse3cb5a32018-08-08 14:16:49 -070067 if (transaction->res.jsonValue.is_null())
68 {
69 transaction->res.jsonValue = {{"status", "ok"},
70 {"bus_name", processName},
71 {"objects", nlohmann::json::array()}};
72 }
73
Ed Tanous1abe55e2018-09-05 08:30:59 -070074 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -070075 [transaction, processName{std::string(processName)},
76 objectPath{std::string(objectPath)}](
77 const boost::system::error_code ec,
78 const std::string &introspect_xml) {
Ed Tanous1abe55e2018-09-05 08:30:59 -070079 if (ec)
80 {
81 BMCWEB_LOG_ERROR
82 << "Introspect call failed with error: " << ec.message()
83 << " on process: " << processName << " path: " << objectPath
84 << "\n";
Ed Tanouse3cb5a32018-08-08 14:16:49 -070085 return;
86 }
87 transaction->res.jsonValue["objects"].push_back(
88 {{"path", objectPath}});
89
90 tinyxml2::XMLDocument doc;
91
92 doc.Parse(introspect_xml.c_str());
93 tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
94 if (pRoot == nullptr)
95 {
96 BMCWEB_LOG_ERROR << "XML document failed to parse "
97 << processName << " " << objectPath << "\n";
Ed Tanous911ac312017-08-15 09:37:42 -070098 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070099 else
100 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700101 tinyxml2::XMLElement *node = pRoot->FirstChildElement("node");
102 while (node != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700103 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700104 const char *childPath = node->Attribute("name");
105 if (childPath != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700106 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700107 std::string newpath;
108 if (objectPath != "/")
109 {
110 newpath += objectPath;
111 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700112 newpath += std::string("/") + childPath;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700113 // introspect the subobjects as well
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700114 introspectObjects(processName, newpath, transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700115 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700116
117 node = node->NextSiblingElement("node");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700118 }
119 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700120 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700121 processName, objectPath, "org.freedesktop.DBus.Introspectable",
Ed Tanous1abe55e2018-09-05 08:30:59 -0700122 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -0700123}
Ed Tanous64530012018-02-06 17:08:16 -0800124
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600125void getPropertiesForEnumerate(const std::string &objectPath,
126 const std::string &service,
127 const std::string &interface,
128 std::shared_ptr<bmcweb::AsyncResp> asyncResp)
129{
130 BMCWEB_LOG_DEBUG << "getPropertiesForEnumerate " << objectPath << " "
131 << service << " " << interface;
132
133 crow::connections::systemBus->async_method_call(
134 [asyncResp, objectPath, service,
135 interface](const boost::system::error_code ec,
136 const std::vector<
137 std::pair<std::string, dbus::utility::DbusVariantType>>
138 &propertiesList) {
139 if (ec)
140 {
141 BMCWEB_LOG_ERROR << "GetAll on path " << objectPath << " iface "
142 << interface << " service " << service
143 << " failed with code " << ec;
144 return;
145 }
146
147 nlohmann::json &dataJson = asyncResp->res.jsonValue["data"];
148 nlohmann::json &objectJson = dataJson[objectPath];
149 if (objectJson.is_null())
150 {
151 objectJson = nlohmann::json::object();
152 }
153
154 for (const auto &[name, value] : propertiesList)
155 {
156 nlohmann::json &propertyJson = objectJson[name];
157 sdbusplus::message::variant_ns::visit(
158 [&propertyJson](auto &&val) { propertyJson = val; }, value);
159 }
160 },
161 service, objectPath, "org.freedesktop.DBus.Properties", "GetAll",
162 interface);
163}
164
165// Find any results that weren't picked up by ObjectManagers, to be
166// called after all ObjectManagers are searched for and called.
167void findRemainingObjectsForEnumerate(
168 const std::string &objectPath, std::shared_ptr<GetSubTreeType> subtree,
169 std::shared_ptr<bmcweb::AsyncResp> asyncResp)
170{
171 BMCWEB_LOG_DEBUG << "findRemainingObjectsForEnumerate";
172 const nlohmann::json &dataJson = asyncResp->res.jsonValue["data"];
173
174 for (const auto &[path, interface_map] : *subtree)
175 {
176 if (path == objectPath)
177 {
178 // An enumerate does not return the target path's properties
179 continue;
180 }
181 if (dataJson.find(path) == dataJson.end())
182 {
183 for (const auto &[service, interfaces] : interface_map)
184 {
185 for (const auto &interface : interfaces)
186 {
187 if (!boost::starts_with(interface, "org.freedesktop.DBus"))
188 {
189 getPropertiesForEnumerate(path, service, interface,
190 asyncResp);
191 }
192 }
193 }
194 }
195 }
196}
197
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600198struct InProgressEnumerateData
199{
200 InProgressEnumerateData(const std::string &objectPath,
201 std::shared_ptr<bmcweb::AsyncResp> asyncResp) :
202 objectPath(objectPath),
203 asyncResp(asyncResp)
204 {
205 }
206
207 ~InProgressEnumerateData()
208 {
Matt Spinler2df1e7d2018-12-05 15:53:16 -0600209 findRemainingObjectsForEnumerate(objectPath, subtree, asyncResp);
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600210 }
211
212 const std::string objectPath;
213 std::shared_ptr<GetSubTreeType> subtree;
214 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
215};
216
217void getManagedObjectsForEnumerate(
218 const std::string &object_name, const std::string &object_manager_path,
219 const std::string &connection_name,
220 std::shared_ptr<InProgressEnumerateData> transaction)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700221{
Ed Tanous049a0512018-11-01 13:58:42 -0700222 BMCWEB_LOG_DEBUG << "getManagedObjectsForEnumerate " << object_name
223 << " object_manager_path " << object_manager_path
224 << " connection_name " << connection_name;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700225 crow::connections::systemBus->async_method_call(
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600226 [transaction, object_name,
Ed Tanous049a0512018-11-01 13:58:42 -0700227 connection_name](const boost::system::error_code ec,
228 const dbus::utility::ManagedObjectType &objects) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700229 if (ec)
230 {
Ed Tanous049a0512018-11-01 13:58:42 -0700231 BMCWEB_LOG_ERROR << "GetManagedObjects on path " << object_name
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600232 << " on connection " << connection_name
Ed Tanous049a0512018-11-01 13:58:42 -0700233 << " failed with code " << ec;
234 return;
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700235 }
Ed Tanous64530012018-02-06 17:08:16 -0800236
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600237 nlohmann::json &dataJson =
238 transaction->asyncResp->res.jsonValue["data"];
Ed Tanous049a0512018-11-01 13:58:42 -0700239
240 for (const auto &objectPath : objects)
241 {
242 if (boost::starts_with(objectPath.first.str, object_name))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700243 {
Ed Tanous049a0512018-11-01 13:58:42 -0700244 BMCWEB_LOG_DEBUG << "Reading object "
245 << objectPath.first.str;
246 nlohmann::json &objectJson = dataJson[objectPath.first.str];
Ed Tanous1abe55e2018-09-05 08:30:59 -0700247 if (objectJson.is_null())
248 {
249 objectJson = nlohmann::json::object();
250 }
251 for (const auto &interface : objectPath.second)
252 {
253 for (const auto &property : interface.second)
254 {
255 nlohmann::json &propertyJson =
256 objectJson[property.first];
William A. Kennington III0a63b1c2018-10-18 13:37:19 -0700257 sdbusplus::message::variant_ns::visit(
Ed Tanous1abe55e2018-09-05 08:30:59 -0700258 [&propertyJson](auto &&val) {
259 propertyJson = val;
260 },
261 property.second);
262 }
263 }
264 }
Ed Tanous049a0512018-11-01 13:58:42 -0700265 for (const auto &interface : objectPath.second)
266 {
267 if (interface.first == "org.freedesktop.DBus.ObjectManager")
268 {
269 getManagedObjectsForEnumerate(
270 objectPath.first.str, objectPath.first.str,
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600271 connection_name, transaction);
Ed Tanous049a0512018-11-01 13:58:42 -0700272 }
273 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700274 }
275 },
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700276 connection_name, object_manager_path,
277 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
278}
279
280void findObjectManagerPathForEnumerate(
281 const std::string &object_name, const std::string &connection_name,
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600282 std::shared_ptr<InProgressEnumerateData> transaction)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700283{
Ed Tanous049a0512018-11-01 13:58:42 -0700284 BMCWEB_LOG_DEBUG << "Finding objectmanager for path " << object_name
285 << " on connection:" << connection_name;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700286 crow::connections::systemBus->async_method_call(
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600287 [transaction, object_name, connection_name](
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700288 const boost::system::error_code ec,
289 const boost::container::flat_map<
290 std::string, boost::container::flat_map<
291 std::string, std::vector<std::string>>>
292 &objects) {
293 if (ec)
294 {
Ed Tanous049a0512018-11-01 13:58:42 -0700295 BMCWEB_LOG_ERROR << "GetAncestors on path " << object_name
296 << " failed with code " << ec;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700297 return;
298 }
299
Ed Tanousf254ba72018-10-12 13:40:35 -0700300 for (const auto &pathGroup : objects)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700301 {
Ed Tanousf254ba72018-10-12 13:40:35 -0700302 for (const auto &connectionGroup : pathGroup.second)
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700303 {
304 if (connectionGroup.first == connection_name)
305 {
306 // Found the object manager path for this resource.
307 getManagedObjectsForEnumerate(
Ed Tanous049a0512018-11-01 13:58:42 -0700308 object_name, pathGroup.first, connection_name,
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600309 transaction);
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700310 return;
311 }
312 }
313 }
314 },
315 "xyz.openbmc_project.ObjectMapper",
316 "/xyz/openbmc_project/object_mapper",
317 "xyz.openbmc_project.ObjectMapper", "GetAncestors", object_name,
318 std::array<const char *, 1>{"org.freedesktop.DBus.ObjectManager"});
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700319}
Ed Tanous64530012018-02-06 17:08:16 -0800320
Matt Spinler3ae4ba72018-12-05 14:01:22 -0600321// Uses GetObject to add the object info about the target /enumerate path to the
322// results of GetSubTree, as GetSubTree will not return info for the
323// target path, and then continues on enumerating the rest of the tree.
324void getObjectAndEnumerate(std::shared_ptr<InProgressEnumerateData> transaction)
325{
326 using GetObjectType =
327 std::vector<std::pair<std::string, std::vector<std::string>>>;
328
329 crow::connections::systemBus->async_method_call(
330 [transaction](const boost::system::error_code ec,
331 const GetObjectType &objects) {
332 if (ec)
333 {
334 BMCWEB_LOG_ERROR << "GetObject for path "
335 << transaction->objectPath
336 << " failed with code " << ec;
337 return;
338 }
339
340 BMCWEB_LOG_DEBUG << "GetObject for " << transaction->objectPath
341 << " has " << objects.size() << " entries";
342 if (!objects.empty())
343 {
344 transaction->subtree->emplace_back(transaction->objectPath,
345 objects);
346 }
347
348 // Map indicating connection name, and the path where the object
349 // manager exists
350 boost::container::flat_map<std::string, std::string> connections;
351
352 for (const auto &object : *(transaction->subtree))
353 {
354 for (const auto &connection : object.second)
355 {
356 std::string &objectManagerPath =
357 connections[connection.first];
358 for (const auto &interface : connection.second)
359 {
360 BMCWEB_LOG_DEBUG << connection.first
361 << " has interface " << interface;
362 if (interface == "org.freedesktop.DBus.ObjectManager")
363 {
364 BMCWEB_LOG_DEBUG << "found object manager path "
365 << object.first;
366 objectManagerPath = object.first;
367 }
368 }
369 }
370 }
371 BMCWEB_LOG_DEBUG << "Got " << connections.size() << " connections";
372
373 for (const auto &connection : connections)
374 {
375 // If we already know where the object manager is, we don't need
376 // to search for it, we can call directly in to
377 // getManagedObjects
378 if (!connection.second.empty())
379 {
380 getManagedObjectsForEnumerate(
381 transaction->objectPath, connection.second,
382 connection.first, transaction);
383 }
384 else
385 {
386 // otherwise we need to find the object manager path before
387 // we can continue
388 findObjectManagerPathForEnumerate(
389 transaction->objectPath, connection.first, transaction);
390 }
391 }
392 },
393 "xyz.openbmc_project.ObjectMapper",
394 "/xyz/openbmc_project/object_mapper",
395 "xyz.openbmc_project.ObjectMapper", "GetObject",
396 transaction->objectPath, std::array<const char *, 0>());
397}
Ed Tanous64530012018-02-06 17:08:16 -0800398
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700399// Structure for storing data on an in progress action
Ed Tanous1abe55e2018-09-05 08:30:59 -0700400struct InProgressActionData
401{
402 InProgressActionData(crow::Response &res) : res(res){};
403 ~InProgressActionData()
404 {
Matt Spinler6db06242018-12-11 11:21:22 -0600405 // If still no JSON filled in, then we never found the method.
406 if (res.jsonValue.is_null())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700407 {
Matt Spinler6db06242018-12-11 11:21:22 -0600408 setErrorResponse(res, boost::beast::http::status::not_found,
409 methodNotFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700410 }
411 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700412 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700413
Matt Spinler6db06242018-12-11 11:21:22 -0600414 void setErrorStatus(const std::string &desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700415 {
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600416 setErrorResponse(res, boost::beast::http::status::bad_request, desc,
417 badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700418 }
419 crow::Response &res;
420 std::string path;
421 std::string methodName;
Matt Spinlerde818812018-12-11 16:39:20 -0600422 std::string interfaceName;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700423 nlohmann::json arguments;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700424};
425
Ed Tanous1abe55e2018-09-05 08:30:59 -0700426std::vector<std::string> dbusArgSplit(const std::string &string)
427{
428 std::vector<std::string> ret;
429 if (string.empty())
430 {
431 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700432 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700433 ret.push_back("");
434 int containerDepth = 0;
435
436 for (std::string::const_iterator character = string.begin();
437 character != string.end(); character++)
438 {
439 ret.back() += *character;
440 switch (*character)
441 {
442 case ('a'):
443 break;
444 case ('('):
445 case ('{'):
446 containerDepth++;
447 break;
448 case ('}'):
449 case (')'):
450 containerDepth--;
451 if (containerDepth == 0)
452 {
453 if (character + 1 != string.end())
454 {
455 ret.push_back("");
456 }
457 }
458 break;
459 default:
460 if (containerDepth == 0)
461 {
462 if (character + 1 != string.end())
463 {
464 ret.push_back("");
465 }
466 }
467 break;
468 }
469 }
Matt Spinler4ae611d2019-01-11 15:37:06 -0600470
471 return ret;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700472}
473
Ed Tanousd76323e2018-08-07 14:35:40 -0700474int convertJsonToDbus(sd_bus_message *m, const std::string &arg_type,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700475 const nlohmann::json &input_json)
476{
477 int r = 0;
478 BMCWEB_LOG_DEBUG << "Converting " << input_json.dump()
479 << " to type: " << arg_type;
480 const std::vector<std::string> argTypes = dbusArgSplit(arg_type);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700481
Ed Tanous1abe55e2018-09-05 08:30:59 -0700482 // Assume a single object for now.
483 const nlohmann::json *j = &input_json;
484 nlohmann::json::const_iterator jIt = input_json.begin();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700485
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700486 for (const std::string &argCode : argTypes)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700487 {
488 // If we are decoding multiple objects, grab the pointer to the
489 // iterator, and increment it for the next loop
490 if (argTypes.size() > 1)
491 {
492 if (jIt == input_json.end())
493 {
494 return -2;
495 }
496 j = &*jIt;
497 jIt++;
498 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700499 const int64_t *intValue = j->get_ptr<const int64_t *>();
500 const uint64_t *uintValue = j->get_ptr<const uint64_t *>();
501 const std::string *stringValue = j->get_ptr<const std::string *>();
502 const double *doubleValue = j->get_ptr<const double *>();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700503 const bool *b = j->get_ptr<const bool *>();
504 int64_t v = 0;
505 double d = 0.0;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700506
Ed Tanous1abe55e2018-09-05 08:30:59 -0700507 // Do some basic type conversions that make sense. uint can be
508 // converted to int. int and uint can be converted to double
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700509 if (uintValue != nullptr && intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700510 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700511 v = static_cast<int64_t>(*uintValue);
512 intValue = &v;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700513 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700514 if (uintValue != nullptr && doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700515 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700516 d = static_cast<double>(*uintValue);
517 doubleValue = &d;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700518 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700519 if (intValue != nullptr && doubleValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700520 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700521 d = static_cast<double>(*intValue);
522 doubleValue = &d;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700523 }
524
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700525 if (argCode == "s")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700526 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700527 if (stringValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700528 {
529 return -1;
530 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700531 r = sd_bus_message_append_basic(m, argCode[0],
532 (void *)stringValue->c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700533 if (r < 0)
534 {
535 return r;
536 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700537 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700538 else if (argCode == "i")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700539 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700540 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700541 {
542 return -1;
543 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700544 int32_t i = static_cast<int32_t>(*intValue);
545 r = sd_bus_message_append_basic(m, argCode[0], &i);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700546 if (r < 0)
547 {
548 return r;
549 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700550 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700551 else if (argCode == "b")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700552 {
553 // lots of ways bool could be represented here. Try them all
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700554 int boolInt = false;
555 if (intValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700556 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700557 boolInt = *intValue > 0 ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700558 }
559 else if (b != nullptr)
560 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700561 boolInt = b ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700562 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700563 else if (stringValue != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700564 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700565 boolInt = boost::istarts_with(*stringValue, "t") ? 1 : 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700566 }
567 else
568 {
569 return -1;
570 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700571 r = sd_bus_message_append_basic(m, argCode[0], &boolInt);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700572 if (r < 0)
573 {
574 return r;
575 }
576 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700577 else if (argCode == "n")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700578 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700579 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700580 {
581 return -1;
582 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700583 int16_t n = static_cast<int16_t>(*intValue);
584 r = sd_bus_message_append_basic(m, argCode[0], &n);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700585 if (r < 0)
586 {
587 return r;
588 }
589 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700590 else if (argCode == "x")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700591 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700592 if (intValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700593 {
594 return -1;
595 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700596 r = sd_bus_message_append_basic(m, argCode[0], intValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700597 if (r < 0)
598 {
599 return r;
600 }
601 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700602 else if (argCode == "y")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700603 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700604 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700605 {
606 return -1;
607 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700608 uint8_t y = static_cast<uint8_t>(*uintValue);
609 r = sd_bus_message_append_basic(m, argCode[0], &y);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700610 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700611 else if (argCode == "q")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700612 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700613 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700614 {
615 return -1;
616 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700617 uint16_t q = static_cast<uint16_t>(*uintValue);
618 r = sd_bus_message_append_basic(m, argCode[0], &q);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700619 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700620 else if (argCode == "u")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700621 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700622 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700623 {
624 return -1;
625 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700626 uint32_t u = static_cast<uint32_t>(*uintValue);
627 r = sd_bus_message_append_basic(m, argCode[0], &u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700628 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700629 else if (argCode == "t")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700630 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700631 if (uintValue == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700632 {
633 return -1;
634 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700635 r = sd_bus_message_append_basic(m, argCode[0], uintValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700636 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700637 else if (argCode == "d")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700638 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700639 sd_bus_message_append_basic(m, argCode[0], doubleValue);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700640 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700641 else if (boost::starts_with(argCode, "a"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700642 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700643 std::string containedType = argCode.substr(1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700644 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700645 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700646 if (r < 0)
647 {
648 return r;
649 }
650
651 for (nlohmann::json::const_iterator it = j->begin(); it != j->end();
652 ++it)
653 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700654 r = convertJsonToDbus(m, containedType, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700655 if (r < 0)
656 {
657 return r;
658 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700659 }
660 sd_bus_message_close_container(m);
661 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700662 else if (boost::starts_with(argCode, "v"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700663 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700664 std::string containedType = argCode.substr(1);
665 BMCWEB_LOG_DEBUG << "variant type: " << argCode
666 << " appending variant of type: " << containedType;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700667 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700668 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700669 if (r < 0)
670 {
671 return r;
672 }
673
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700674 r = convertJsonToDbus(m, containedType, input_json);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700675 if (r < 0)
676 {
677 return r;
678 }
679
680 r = sd_bus_message_close_container(m);
681 if (r < 0)
682 {
683 return r;
684 }
685 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700686 else if (boost::starts_with(argCode, "(") &&
687 boost::ends_with(argCode, ")"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700688 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700689 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700690 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700691 containedType.c_str());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700692 nlohmann::json::const_iterator it = j->begin();
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700693 for (const std::string &argCode : dbusArgSplit(arg_type))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700694 {
695 if (it == j->end())
696 {
697 return -1;
698 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700699 r = convertJsonToDbus(m, argCode, *it);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700700 if (r < 0)
701 {
702 return r;
703 }
704 it++;
705 }
706 r = sd_bus_message_close_container(m);
707 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700708 else if (boost::starts_with(argCode, "{") &&
709 boost::ends_with(argCode, "}"))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700710 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700711 std::string containedType = argCode.substr(1, argCode.size() - 1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700712 r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700713 containedType.c_str());
714 std::vector<std::string> codes = dbusArgSplit(containedType);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700715 if (codes.size() != 2)
716 {
717 return -1;
718 }
719 const std::string &key_type = codes[0];
720 const std::string &value_type = codes[1];
721 for (auto it : j->items())
722 {
723 r = convertJsonToDbus(m, key_type, it.key());
724 if (r < 0)
725 {
726 return r;
727 }
728
729 r = convertJsonToDbus(m, value_type, it.value());
730 if (r < 0)
731 {
732 return r;
733 }
734 }
735 r = sd_bus_message_close_container(m);
736 }
737 else
738 {
739 return -2;
740 }
741 if (r < 0)
742 {
743 return r;
Ed Tanous75db20e2018-07-27 13:44:44 -0700744 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700745
Ed Tanous1abe55e2018-09-05 08:30:59 -0700746 if (argTypes.size() > 1)
747 {
748 jIt++;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700749 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700750 }
Matt Spinler127ea542019-01-14 11:04:28 -0600751
752 return r;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700753}
754
Ed Tanousd76323e2018-08-07 14:35:40 -0700755void findActionOnInterface(std::shared_ptr<InProgressActionData> transaction,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700756 const std::string &connectionName)
757{
758 BMCWEB_LOG_DEBUG << "findActionOnInterface for connection "
759 << connectionName;
760 crow::connections::systemBus->async_method_call(
761 [transaction, connectionName{std::string(connectionName)}](
762 const boost::system::error_code ec,
763 const std::string &introspect_xml) {
764 BMCWEB_LOG_DEBUG << "got xml:\n " << introspect_xml;
765 if (ec)
766 {
767 BMCWEB_LOG_ERROR
768 << "Introspect call failed with error: " << ec.message()
769 << " on process: " << connectionName << "\n";
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700770 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700771 else
772 {
773 tinyxml2::XMLDocument doc;
774
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700775 doc.Parse(introspect_xml.data(), introspect_xml.size());
Ed Tanous1abe55e2018-09-05 08:30:59 -0700776 tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
777 if (pRoot == nullptr)
778 {
779 BMCWEB_LOG_ERROR << "XML document failed to parse "
780 << connectionName << "\n";
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700781 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700782 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700783 tinyxml2::XMLElement *interfaceNode =
784 pRoot->FirstChildElement("interface");
785 while (interfaceNode != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700786 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700787 const char *thisInterfaceName =
788 interfaceNode->Attribute("name");
789 if (thisInterfaceName != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700790 {
Matt Spinlerde818812018-12-11 16:39:20 -0600791 if (!transaction->interfaceName.empty() &&
792 (transaction->interfaceName != thisInterfaceName))
793 {
794 interfaceNode =
795 interfaceNode->NextSiblingElement("interface");
796 continue;
797 }
798
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700799 tinyxml2::XMLElement *methodNode =
800 interfaceNode->FirstChildElement("method");
801 while (methodNode != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700802 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700803 const char *thisMethodName =
804 methodNode->Attribute("name");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700805 BMCWEB_LOG_DEBUG << "Found method: "
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700806 << thisMethodName;
807 if (thisMethodName != nullptr &&
808 thisMethodName == transaction->methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700809 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700810 BMCWEB_LOG_DEBUG
811 << "Found method named " << thisMethodName
812 << " on interface " << thisInterfaceName;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700813 sdbusplus::message::message m =
814 crow::connections::systemBus
815 ->new_method_call(
816 connectionName.c_str(),
817 transaction->path.c_str(),
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700818 thisInterfaceName,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700819 transaction->methodName.c_str());
820
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700821 tinyxml2::XMLElement *argumentNode =
822 methodNode->FirstChildElement("arg");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700823
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700824 nlohmann::json::const_iterator argIt =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700825 transaction->arguments.begin();
826
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700827 while (argumentNode != nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700828 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700829 const char *argDirection =
830 argumentNode->Attribute("direction");
831 const char *argType =
832 argumentNode->Attribute("type");
833 if (argDirection != nullptr &&
834 argType != nullptr &&
835 std::string(argDirection) == "in")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700836 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700837 if (argIt ==
Ed Tanous1abe55e2018-09-05 08:30:59 -0700838 transaction->arguments.end())
839 {
Matt Spinler6db06242018-12-11 11:21:22 -0600840 transaction->setErrorStatus(
841 "Invalid method args");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700842 return;
843 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700844 if (convertJsonToDbus(
845 m.get(), std::string(argType),
846 *argIt) < 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700847 {
Matt Spinler6db06242018-12-11 11:21:22 -0600848 transaction->setErrorStatus(
849 "Invalid method arg type");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700850 return;
851 }
852
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700853 argIt++;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700854 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700855 argumentNode =
AppaRao Puli4d72dcc2018-12-26 20:26:22 +0530856 argumentNode->NextSiblingElement("arg");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700857 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700858
Ed Tanous1abe55e2018-09-05 08:30:59 -0700859 crow::connections::systemBus->async_send(
860 m, [transaction](
861 boost::system::error_code ec,
862 sdbusplus::message::message &m) {
863 if (ec)
864 {
Matt Spinlerc0eb9bd2019-01-09 15:22:30 -0600865 setErrorResponse(
866 transaction->res,
867 boost::beast::http::status::
868 internal_server_error,
869 "Method call failed",
870 methodFailedMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700871 return;
872 }
873 transaction->res.jsonValue = {
874 {"status", "ok"},
875 {"message", "200 OK"},
876 {"data", nullptr}};
877 });
878 break;
879 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700880 methodNode =
881 methodNode->NextSiblingElement("method");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700882 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700883 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700884 interfaceNode =
885 interfaceNode->NextSiblingElement("interface");
Ed Tanous1abe55e2018-09-05 08:30:59 -0700886 }
887 }
888 },
889 connectionName, transaction->path,
890 "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700891}
892
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700893void handleAction(const crow::Request &req, crow::Response &res,
894 const std::string &objectPath, const std::string &methodName)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700895{
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700896 BMCWEB_LOG_DEBUG << "handleAction on path: " << objectPath << " and method "
897 << methodName;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700898 nlohmann::json requestDbusData =
899 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700900
Ed Tanous1abe55e2018-09-05 08:30:59 -0700901 if (requestDbusData.is_discarded())
902 {
Matt Spinler6db06242018-12-11 11:21:22 -0600903 setErrorResponse(res, boost::beast::http::status::bad_request,
904 noJsonDesc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700905 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700906 return;
907 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700908 nlohmann::json::iterator data = requestDbusData.find("data");
909 if (data == requestDbusData.end())
910 {
Matt Spinler6db06242018-12-11 11:21:22 -0600911 setErrorResponse(res, boost::beast::http::status::bad_request,
912 noJsonDesc, badReqMsg);
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700913 res.end();
914 return;
915 }
916
917 if (!data->is_array())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700918 {
Matt Spinler6db06242018-12-11 11:21:22 -0600919 setErrorResponse(res, boost::beast::http::status::bad_request,
920 noJsonDesc, badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700921 res.end();
922 return;
923 }
924 auto transaction = std::make_shared<InProgressActionData>(res);
925
926 transaction->path = objectPath;
927 transaction->methodName = methodName;
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700928 transaction->arguments = std::move(*data);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700929 crow::connections::systemBus->async_method_call(
930 [transaction](
931 const boost::system::error_code ec,
932 const std::vector<std::pair<std::string, std::vector<std::string>>>
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700933 &interfaceNames) {
934 if (ec || interfaceNames.size() <= 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700935 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700936 BMCWEB_LOG_ERROR << "Can't find object";
Matt Spinler6db06242018-12-11 11:21:22 -0600937 setErrorResponse(transaction->res,
938 boost::beast::http::status::not_found,
939 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700940 return;
941 }
942
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700943 BMCWEB_LOG_DEBUG << "GetObject returned " << interfaceNames.size()
944 << " object(s)";
Ed Tanous1abe55e2018-09-05 08:30:59 -0700945
946 for (const std::pair<std::string, std::vector<std::string>>
Ed Tanouse3cb5a32018-08-08 14:16:49 -0700947 &object : interfaceNames)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700948 {
949 findActionOnInterface(transaction, object.first);
950 }
951 },
952 "xyz.openbmc_project.ObjectMapper",
953 "/xyz/openbmc_project/object_mapper",
954 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
955 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -0700956}
957
Matt Spinlerde818812018-12-11 16:39:20 -0600958void handleDelete(const crow::Request &req, crow::Response &res,
959 const std::string &objectPath)
960{
961 BMCWEB_LOG_DEBUG << "handleDelete on path: " << objectPath;
962
963 crow::connections::systemBus->async_method_call(
964 [&res, objectPath](
965 const boost::system::error_code ec,
966 const std::vector<std::pair<std::string, std::vector<std::string>>>
967 &interfaceNames) {
968 if (ec || interfaceNames.size() <= 0)
969 {
970 BMCWEB_LOG_ERROR << "Can't find object";
971 setErrorResponse(res, boost::beast::http::status::not_found,
972 notFoundDesc, notFoundMsg);
973 res.end();
974 return;
975 }
976
977 auto transaction = std::make_shared<InProgressActionData>(res);
978 transaction->path = objectPath;
979 transaction->methodName = "Delete";
980 transaction->interfaceName = "xyz.openbmc_project.Object.Delete";
981
982 for (const std::pair<std::string, std::vector<std::string>>
983 &object : interfaceNames)
984 {
985 findActionOnInterface(transaction, object.first);
986 }
987 },
988 "xyz.openbmc_project.ObjectMapper",
989 "/xyz/openbmc_project/object_mapper",
990 "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
991 std::array<const char *, 0>());
992}
993
Ed Tanousf839dfe2018-11-12 11:11:15 -0800994void handleList(crow::Response &res, const std::string &objectPath,
995 int32_t depth = 0)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700996{
997 crow::connections::systemBus->async_method_call(
998 [&res](const boost::system::error_code ec,
999 std::vector<std::string> &objectPaths) {
1000 if (ec)
1001 {
Matt Spinlerd6091dd2018-12-06 14:08:27 -06001002 setErrorResponse(res, boost::beast::http::status::not_found,
1003 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001004 }
1005 else
1006 {
1007 res.jsonValue = {{"status", "ok"},
1008 {"message", "200 OK"},
1009 {"data", std::move(objectPaths)}};
1010 }
1011 res.end();
1012 },
1013 "xyz.openbmc_project.ObjectMapper",
1014 "/xyz/openbmc_project/object_mapper",
1015 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", objectPath,
Ed Tanousf839dfe2018-11-12 11:11:15 -08001016 depth, std::array<std::string, 0>());
Ed Tanous1abe55e2018-09-05 08:30:59 -07001017}
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001018
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001019void handleEnumerate(crow::Response &res, const std::string &objectPath)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001020{
Ed Tanous049a0512018-11-01 13:58:42 -07001021 BMCWEB_LOG_DEBUG << "Doing enumerate on " << objectPath;
1022 auto asyncResp = std::make_shared<bmcweb::AsyncResp>(res);
1023
1024 asyncResp->res.jsonValue = {{"message", "200 OK"},
1025 {"status", "ok"},
1026 {"data", nlohmann::json::object()}};
1027
Ed Tanous1abe55e2018-09-05 08:30:59 -07001028 crow::connections::systemBus->async_method_call(
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001029 [objectPath, asyncResp](const boost::system::error_code ec,
1030 GetSubTreeType &object_names) {
1031 auto transaction = std::make_shared<InProgressEnumerateData>(
1032 objectPath, asyncResp);
1033
1034 transaction->subtree =
1035 std::make_shared<GetSubTreeType>(std::move(object_names));
1036
Ed Tanous1abe55e2018-09-05 08:30:59 -07001037 if (ec)
1038 {
Matt Spinler2ae60092018-12-06 10:35:36 -06001039 BMCWEB_LOG_ERROR << "GetSubTree failed on "
1040 << transaction->objectPath;
1041 setErrorResponse(transaction->asyncResp->res,
1042 boost::beast::http::status::not_found,
1043 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001044 return;
1045 }
Ed Tanous64530012018-02-06 17:08:16 -08001046
Matt Spinler3ae4ba72018-12-05 14:01:22 -06001047 // Add the data for the path passed in to the results
1048 // as if GetSubTree returned it, and continue on enumerating
1049 getObjectAndEnumerate(transaction);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001050 },
1051 "xyz.openbmc_project.ObjectMapper",
1052 "/xyz/openbmc_project/object_mapper",
1053 "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath,
Ed Tanous049a0512018-11-01 13:58:42 -07001054 static_cast<int32_t>(0), std::array<const char *, 0>());
Ed Tanous64530012018-02-06 17:08:16 -08001055}
Ed Tanous911ac312017-08-15 09:37:42 -07001056
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001057void handleGet(crow::Response &res, std::string &objectPath,
1058 std::string &destProperty)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001059{
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001060 BMCWEB_LOG_DEBUG << "handleGet: " << objectPath << " prop:" << destProperty;
1061 std::shared_ptr<std::string> propertyName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001062 std::make_shared<std::string>(std::move(destProperty));
Ed Tanous75db20e2018-07-27 13:44:44 -07001063
Ed Tanous1abe55e2018-09-05 08:30:59 -07001064 std::shared_ptr<std::string> path =
1065 std::make_shared<std::string>(std::move(objectPath));
Ed Tanous75db20e2018-07-27 13:44:44 -07001066
Ed Tanous1abe55e2018-09-05 08:30:59 -07001067 using GetObjectType =
1068 std::vector<std::pair<std::string, std::vector<std::string>>>;
1069 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001070 [&res, path, propertyName](const boost::system::error_code ec,
1071 const GetObjectType &object_names) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001072 if (ec || object_names.size() <= 0)
1073 {
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001074 setErrorResponse(res, boost::beast::http::status::not_found,
1075 notFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001076 res.end();
1077 return;
1078 }
1079 std::shared_ptr<nlohmann::json> response =
1080 std::make_shared<nlohmann::json>(nlohmann::json::object());
1081 // The mapper should never give us an empty interface names list,
1082 // but check anyway
1083 for (const std::pair<std::string, std::vector<std::string>>
1084 connection : object_names)
1085 {
1086 const std::vector<std::string> &interfaceNames =
1087 connection.second;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001088
Ed Tanous1abe55e2018-09-05 08:30:59 -07001089 if (interfaceNames.size() <= 0)
1090 {
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001091 setErrorResponse(res, boost::beast::http::status::not_found,
1092 notFoundDesc, notFoundMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001093 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001094 return;
1095 }
1096
1097 for (const std::string &interface : interfaceNames)
1098 {
1099 crow::connections::systemBus->async_method_call(
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001100 [&res, response, propertyName](
Ed Tanous1abe55e2018-09-05 08:30:59 -07001101 const boost::system::error_code ec,
James Feist5b4aa862018-08-16 14:07:01 -07001102 const std::vector<std::pair<
1103 std::string, dbus::utility::DbusVariantType>>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001104 &properties) {
1105 if (ec)
1106 {
1107 BMCWEB_LOG_ERROR << "Bad dbus request error: "
1108 << ec;
1109 }
1110 else
1111 {
James Feist5b4aa862018-08-16 14:07:01 -07001112 for (const std::pair<
1113 std::string,
1114 dbus::utility::DbusVariantType>
Ed Tanous1abe55e2018-09-05 08:30:59 -07001115 &property : properties)
1116 {
1117 // if property name is empty, or matches our
1118 // search query, add it to the response json
1119
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001120 if (propertyName->empty())
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, &property](auto &&val) {
1124 (*response)[property.first] =
1125 val;
1126 },
1127 property.second);
1128 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001129 else if (property.first == *propertyName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001130 {
William A. Kennington III0a63b1c2018-10-18 13:37:19 -07001131 sdbusplus::message::variant_ns::visit(
Ed Tanous1abe55e2018-09-05 08:30:59 -07001132 [&response](auto &&val) {
1133 (*response) = val;
1134 },
1135 property.second);
1136 }
1137 }
1138 }
1139 if (response.use_count() == 1)
1140 {
Matt Spinlerdc2f9f12018-12-06 13:53:53 -06001141 if (!propertyName->empty() && response->empty())
1142 {
1143 setErrorResponse(
1144 res,
1145 boost::beast::http::status::not_found,
1146 propNotFoundDesc, notFoundMsg);
1147 }
1148 else
1149 {
1150 res.jsonValue = {{"status", "ok"},
1151 {"message", "200 OK"},
1152 {"data", *response}};
1153 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001154 res.end();
1155 }
1156 },
1157 connection.first, *path,
1158 "org.freedesktop.DBus.Properties", "GetAll", interface);
1159 }
1160 }
1161 },
1162 "xyz.openbmc_project.ObjectMapper",
1163 "/xyz/openbmc_project/object_mapper",
1164 "xyz.openbmc_project.ObjectMapper", "GetObject", *path,
1165 std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001166}
1167
Ed Tanous1abe55e2018-09-05 08:30:59 -07001168struct AsyncPutRequest
1169{
1170 AsyncPutRequest(crow::Response &res) : res(res)
1171 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001172 }
1173 ~AsyncPutRequest()
1174 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001175 if (res.jsonValue.empty())
1176 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001177 setErrorResponse(res, boost::beast::http::status::forbidden,
1178 forbiddenMsg, forbiddenPropDesc);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001179 }
1180
1181 res.end();
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001182 }
1183
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001184 void setErrorStatus(const std::string &desc)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001185 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001186 setErrorResponse(res, boost::beast::http::status::internal_server_error,
1187 desc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001188 }
1189
Ed Tanous1abe55e2018-09-05 08:30:59 -07001190 crow::Response &res;
1191 std::string objectPath;
1192 std::string propertyName;
1193 nlohmann::json propertyValue;
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001194};
1195
Ed Tanousd76323e2018-08-07 14:35:40 -07001196void handlePut(const crow::Request &req, crow::Response &res,
Ed Tanous1abe55e2018-09-05 08:30:59 -07001197 const std::string &objectPath, const std::string &destProperty)
1198{
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001199 if (destProperty.empty())
1200 {
1201 setErrorResponse(res, boost::beast::http::status::forbidden,
1202 forbiddenResDesc, forbiddenMsg);
1203 res.end();
1204 return;
1205 }
1206
Ed Tanous1abe55e2018-09-05 08:30:59 -07001207 nlohmann::json requestDbusData =
1208 nlohmann::json::parse(req.body, nullptr, false);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001209
Ed Tanous1abe55e2018-09-05 08:30:59 -07001210 if (requestDbusData.is_discarded())
1211 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001212 setErrorResponse(res, boost::beast::http::status::bad_request,
1213 noJsonDesc, badReqMsg);
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001214 res.end();
1215 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001216 }
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001217
Ed Tanous1abe55e2018-09-05 08:30:59 -07001218 nlohmann::json::const_iterator propertyIt = requestDbusData.find("data");
1219 if (propertyIt == requestDbusData.end())
1220 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001221 setErrorResponse(res, boost::beast::http::status::bad_request,
1222 noJsonDesc, badReqMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001223 res.end();
1224 return;
1225 }
1226 const nlohmann::json &propertySetValue = *propertyIt;
1227 auto transaction = std::make_shared<AsyncPutRequest>(res);
1228 transaction->objectPath = objectPath;
1229 transaction->propertyName = destProperty;
1230 transaction->propertyValue = propertySetValue;
Ed Tanous911ac312017-08-15 09:37:42 -07001231
Ed Tanous1abe55e2018-09-05 08:30:59 -07001232 using GetObjectType =
1233 std::vector<std::pair<std::string, std::vector<std::string>>>;
Ed Tanous911ac312017-08-15 09:37:42 -07001234
Ed Tanous1abe55e2018-09-05 08:30:59 -07001235 crow::connections::systemBus->async_method_call(
1236 [transaction](const boost::system::error_code ec,
1237 const GetObjectType &object_names) {
1238 if (!ec && object_names.size() <= 0)
1239 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001240 setErrorResponse(transaction->res,
1241 boost::beast::http::status::not_found,
1242 propNotFoundDesc, notFoundMsg);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001243 return;
1244 }
Ed Tanous911ac312017-08-15 09:37:42 -07001245
Ed Tanous1abe55e2018-09-05 08:30:59 -07001246 for (const std::pair<std::string, std::vector<std::string>>
1247 connection : object_names)
1248 {
1249 const std::string &connectionName = connection.first;
Ed Tanous911ac312017-08-15 09:37:42 -07001250
Ed Tanous1abe55e2018-09-05 08:30:59 -07001251 crow::connections::systemBus->async_method_call(
1252 [connectionName{std::string(connectionName)},
1253 transaction](const boost::system::error_code ec,
1254 const std::string &introspectXml) {
1255 if (ec)
1256 {
1257 BMCWEB_LOG_ERROR
1258 << "Introspect call failed with error: "
1259 << ec.message()
1260 << " on process: " << connectionName;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001261 transaction->setErrorStatus("Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001262 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001263 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001264 tinyxml2::XMLDocument doc;
Ed Tanous911ac312017-08-15 09:37:42 -07001265
Ed Tanous1abe55e2018-09-05 08:30:59 -07001266 doc.Parse(introspectXml.c_str());
1267 tinyxml2::XMLNode *pRoot =
1268 doc.FirstChildElement("node");
1269 if (pRoot == nullptr)
1270 {
1271 BMCWEB_LOG_ERROR << "XML document failed to parse: "
1272 << introspectXml;
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001273 transaction->setErrorStatus("Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001274 return;
Ed Tanous911ac312017-08-15 09:37:42 -07001275 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001276 tinyxml2::XMLElement *ifaceNode =
1277 pRoot->FirstChildElement("interface");
1278 while (ifaceNode != nullptr)
1279 {
1280 const char *interfaceName =
1281 ifaceNode->Attribute("name");
1282 BMCWEB_LOG_DEBUG << "found interface "
1283 << interfaceName;
1284 tinyxml2::XMLElement *propNode =
1285 ifaceNode->FirstChildElement("property");
1286 while (propNode != nullptr)
1287 {
1288 const char *propertyName =
1289 propNode->Attribute("name");
1290 BMCWEB_LOG_DEBUG << "Found property "
1291 << propertyName;
1292 if (propertyName == transaction->propertyName)
1293 {
1294 const char *argType =
1295 propNode->Attribute("type");
1296 if (argType != nullptr)
1297 {
1298 sdbusplus::message::message m =
1299 crow::connections::systemBus
1300 ->new_method_call(
1301 connectionName.c_str(),
1302 transaction->objectPath
1303 .c_str(),
1304 "org.freedesktop.DBus."
1305 "Properties",
1306 "Set");
1307 m.append(interfaceName,
1308 transaction->propertyName);
1309 int r = sd_bus_message_open_container(
1310 m.get(), SD_BUS_TYPE_VARIANT,
1311 argType);
1312 if (r < 0)
1313 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001314 transaction->setErrorStatus(
1315 "Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001316 return;
1317 }
1318 r = convertJsonToDbus(
1319 m.get(), argType,
1320 transaction->propertyValue);
1321 if (r < 0)
1322 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001323 transaction->setErrorStatus(
1324 "Invalid arg type");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001325 return;
1326 }
1327 r = sd_bus_message_close_container(
1328 m.get());
1329 if (r < 0)
1330 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001331 transaction->setErrorStatus(
1332 "Unexpected Error");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001333 return;
1334 }
Ed Tanous911ac312017-08-15 09:37:42 -07001335
Ed Tanous1abe55e2018-09-05 08:30:59 -07001336 crow::connections::systemBus
1337 ->async_send(
1338 m,
1339 [transaction](
1340 boost::system::error_code
1341 ec,
1342 sdbusplus::message::message
1343 &m) {
1344 BMCWEB_LOG_DEBUG << "sent";
1345 if (ec)
1346 {
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001347 setErrorResponse(
1348 transaction->res,
1349 boost::beast::http::
1350 status::
1351 forbidden,
1352 forbiddenPropDesc,
1353 ec.message());
1354 }
1355 else
1356 {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001357 transaction->res
Matt Spinlerfbc19ea2018-12-11 14:03:42 -06001358 .jsonValue = {
1359 {"status", "ok"},
1360 {"message",
1361 "200 OK"},
1362 {"data", nullptr}};
Ed Tanous1abe55e2018-09-05 08:30:59 -07001363 }
1364 });
1365 }
1366 }
1367 propNode =
1368 propNode->NextSiblingElement("property");
1369 }
1370 ifaceNode =
1371 ifaceNode->NextSiblingElement("interface");
1372 }
1373 },
1374 connectionName, transaction->objectPath,
1375 "org.freedesktop.DBus.Introspectable", "Introspect");
1376 }
1377 },
1378 "xyz.openbmc_project.ObjectMapper",
1379 "/xyz/openbmc_project/object_mapper",
1380 "xyz.openbmc_project.ObjectMapper", "GetObject",
1381 transaction->objectPath, std::array<std::string, 0>());
Ed Tanousd4bb9bb2018-05-16 13:36:42 -07001382}
Ed Tanous1abe55e2018-09-05 08:30:59 -07001383
Ed Tanous049a0512018-11-01 13:58:42 -07001384inline void handleDBusUrl(const crow::Request &req, crow::Response &res,
1385 std::string &objectPath)
1386{
Ed Tanous049a0512018-11-01 13:58:42 -07001387
1388 // If accessing a single attribute, fill in and update objectPath,
1389 // otherwise leave destProperty blank
1390 std::string destProperty = "";
1391 const char *attrSeperator = "/attr/";
1392 size_t attrPosition = objectPath.find(attrSeperator);
1393 if (attrPosition != objectPath.npos)
1394 {
1395 destProperty = objectPath.substr(attrPosition + strlen(attrSeperator),
1396 objectPath.length());
1397 objectPath = objectPath.substr(0, attrPosition);
1398 }
1399
1400 if (req.method() == "POST"_method)
1401 {
1402 constexpr const char *actionSeperator = "/action/";
1403 size_t actionPosition = objectPath.find(actionSeperator);
1404 if (actionPosition != objectPath.npos)
1405 {
1406 std::string postProperty =
1407 objectPath.substr((actionPosition + strlen(actionSeperator)),
1408 objectPath.length());
1409 objectPath = objectPath.substr(0, actionPosition);
1410 handleAction(req, res, objectPath, postProperty);
1411 return;
1412 }
1413 }
1414 else if (req.method() == "GET"_method)
1415 {
1416 if (boost::ends_with(objectPath, "/enumerate"))
1417 {
1418 objectPath.erase(objectPath.end() - sizeof("enumerate"),
1419 objectPath.end());
1420 handleEnumerate(res, objectPath);
1421 }
1422 else if (boost::ends_with(objectPath, "/list"))
1423 {
1424 objectPath.erase(objectPath.end() - sizeof("list"),
1425 objectPath.end());
1426 handleList(res, objectPath);
1427 }
1428 else
1429 {
Ed Tanousf839dfe2018-11-12 11:11:15 -08001430 // Trim any trailing "/" at the end
1431 if (boost::ends_with(objectPath, "/"))
1432 {
1433 objectPath.pop_back();
1434 handleList(res, objectPath, 1);
1435 }
1436 else
1437 {
1438 handleGet(res, objectPath, destProperty);
1439 }
Ed Tanous049a0512018-11-01 13:58:42 -07001440 }
1441 return;
1442 }
1443 else if (req.method() == "PUT"_method)
1444 {
1445 handlePut(req, res, objectPath, destProperty);
1446 return;
1447 }
Matt Spinlerde818812018-12-11 16:39:20 -06001448 else if (req.method() == "DELETE"_method)
1449 {
1450 handleDelete(req, res, objectPath);
1451 return;
1452 }
Ed Tanous049a0512018-11-01 13:58:42 -07001453
Matt Spinlerc4e8d21d62018-12-11 11:47:17 -06001454 setErrorResponse(res, boost::beast::http::status::method_not_allowed,
1455 methodNotAllowedDesc, methodNotAllowedMsg);
Ed Tanous049a0512018-11-01 13:58:42 -07001456 res.end();
1457}
1458
Ed Tanous1abe55e2018-09-05 08:30:59 -07001459template <typename... Middlewares> void requestRoutes(Crow<Middlewares...> &app)
1460{
1461 BMCWEB_ROUTE(app, "/bus/")
1462 .methods("GET"_method)(
1463 [](const crow::Request &req, crow::Response &res) {
1464 res.jsonValue = {{"busses", {{{"name", "system"}}}},
1465 {"status", "ok"}};
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001466 res.end();
Ed Tanous1abe55e2018-09-05 08:30:59 -07001467 });
1468
1469 BMCWEB_ROUTE(app, "/bus/system/")
1470 .methods("GET"_method)(
1471 [](const crow::Request &req, crow::Response &res) {
1472 auto myCallback = [&res](const boost::system::error_code ec,
1473 std::vector<std::string> &names) {
1474 if (ec)
1475 {
1476 BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
1477 res.result(
1478 boost::beast::http::status::internal_server_error);
1479 }
1480 else
1481 {
1482 std::sort(names.begin(), names.end());
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001483 res.jsonValue = {{"status", "ok"}};
1484 auto &objectsSub = res.jsonValue["objects"];
Ed Tanous1abe55e2018-09-05 08:30:59 -07001485 for (auto &name : names)
1486 {
1487 objectsSub.push_back({{"name", name}});
1488 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001489 }
1490 res.end();
1491 };
1492 crow::connections::systemBus->async_method_call(
1493 std::move(myCallback), "org.freedesktop.DBus", "/",
1494 "org.freedesktop.DBus", "ListNames");
1495 });
1496
1497 BMCWEB_ROUTE(app, "/list/")
1498 .methods("GET"_method)(
1499 [](const crow::Request &req, crow::Response &res) {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001500 handleList(res, "/");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001501 });
1502
1503 BMCWEB_ROUTE(app, "/xyz/<path>")
Matt Spinlerde818812018-12-11 16:39:20 -06001504 .methods("GET"_method, "PUT"_method, "POST"_method, "DELETE"_method)(
Ed Tanous049a0512018-11-01 13:58:42 -07001505 [](const crow::Request &req, crow::Response &res,
1506 const std::string &path) {
1507 std::string objectPath = "/xyz/" + path;
1508 handleDBusUrl(req, res, objectPath);
1509 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001510
Ed Tanous049a0512018-11-01 13:58:42 -07001511 BMCWEB_ROUTE(app, "/org/<path>")
Matt Spinlerde818812018-12-11 16:39:20 -06001512 .methods("GET"_method, "PUT"_method, "POST"_method, "DELETE"_method)(
Ed Tanous049a0512018-11-01 13:58:42 -07001513 [](const crow::Request &req, crow::Response &res,
1514 const std::string &path) {
1515 std::string objectPath = "/org/" + path;
1516 handleDBusUrl(req, res, objectPath);
1517 });
Ed Tanous1abe55e2018-09-05 08:30:59 -07001518
Ed Tanous1abe55e2018-09-05 08:30:59 -07001519 BMCWEB_ROUTE(app, "/download/dump/<str>/")
1520 .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
1521 const std::string &dumpId) {
Ed Tanousad18f072018-11-14 14:07:48 -08001522 std::regex validFilename("^[\\w\\- ]+(\\.?[\\w\\- ]*)$");
Ed Tanous1abe55e2018-09-05 08:30:59 -07001523 if (!std::regex_match(dumpId, validFilename))
1524 {
Ed Tanousad18f072018-11-14 14:07:48 -08001525 res.result(boost::beast::http::status::bad_request);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001526 res.end();
1527 return;
1528 }
James Feistf6150402019-01-08 10:36:20 -08001529 std::filesystem::path loc(
Ed Tanous1abe55e2018-09-05 08:30:59 -07001530 "/var/lib/phosphor-debug-collector/dumps");
1531
Ed Tanousad18f072018-11-14 14:07:48 -08001532 loc /= dumpId;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001533
James Feistf6150402019-01-08 10:36:20 -08001534 if (!std::filesystem::exists(loc) ||
1535 !std::filesystem::is_directory(loc))
Ed Tanous1abe55e2018-09-05 08:30:59 -07001536 {
Ed Tanousad18f072018-11-14 14:07:48 -08001537 BMCWEB_LOG_ERROR << loc << "Not found";
Ed Tanous1abe55e2018-09-05 08:30:59 -07001538 res.result(boost::beast::http::status::not_found);
1539 res.end();
1540 return;
1541 }
James Feistf6150402019-01-08 10:36:20 -08001542 std::filesystem::directory_iterator files(loc);
Ed Tanousad18f072018-11-14 14:07:48 -08001543
Ed Tanous1abe55e2018-09-05 08:30:59 -07001544 for (auto &file : files)
1545 {
1546 std::ifstream readFile(file.path());
Ed Tanousad18f072018-11-14 14:07:48 -08001547 if (!readFile.good())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001548 {
1549 continue;
1550 }
1551 res.addHeader("Content-Type", "application/octet-stream");
1552 res.body() = {std::istreambuf_iterator<char>(readFile),
1553 std::istreambuf_iterator<char>()};
1554 res.end();
Ed Tanousad18f072018-11-14 14:07:48 -08001555 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001556 }
1557 res.result(boost::beast::http::status::not_found);
1558 res.end();
1559 return;
1560 });
1561
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001562 BMCWEB_ROUTE(app, "/bus/system/<str>/")
Ed Tanous1abe55e2018-09-05 08:30:59 -07001563 .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001564 const std::string &Connection) {
1565 introspectObjects(Connection, "/",
1566 std::make_shared<bmcweb::AsyncResp>(res));
1567 });
1568
1569 BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
1570 .methods("GET"_method,
1571 "POST"_method)([](const crow::Request &req,
1572 crow::Response &res,
1573 const std::string &processName,
1574 const std::string &requestedPath) {
Ed Tanous1abe55e2018-09-05 08:30:59 -07001575 std::vector<std::string> strs;
1576 boost::split(strs, requestedPath, boost::is_any_of("/"));
1577 std::string objectPath;
1578 std::string interfaceName;
1579 std::string methodName;
1580 auto it = strs.begin();
1581 if (it == strs.end())
1582 {
1583 objectPath = "/";
1584 }
1585 while (it != strs.end())
1586 {
1587 // Check if segment contains ".". If it does, it must be an
1588 // interface
1589 if (it->find(".") != std::string::npos)
1590 {
1591 break;
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001592 // This check is neccesary as the trailing slash gets parsed
Ed Tanous1abe55e2018-09-05 08:30:59 -07001593 // as part of our <path> specifier above, which causes the
1594 // normal trailing backslash redirector to fail.
1595 }
1596 else if (!it->empty())
1597 {
1598 objectPath += "/" + *it;
1599 }
1600 it++;
1601 }
1602 if (it != strs.end())
1603 {
1604 interfaceName = *it;
1605 it++;
1606
1607 // after interface, we might have a method name
1608 if (it != strs.end())
1609 {
1610 methodName = *it;
1611 it++;
1612 }
1613 }
1614 if (it != strs.end())
1615 {
1616 // if there is more levels past the method name, something went
1617 // wrong, return not found
1618 res.result(boost::beast::http::status::not_found);
1619 res.end();
1620 return;
1621 }
1622 if (interfaceName.empty())
1623 {
1624 crow::connections::systemBus->async_method_call(
1625 [&, processName,
1626 objectPath](const boost::system::error_code ec,
1627 const std::string &introspect_xml) {
1628 if (ec)
1629 {
1630 BMCWEB_LOG_ERROR
1631 << "Introspect call failed with error: "
1632 << ec.message()
1633 << " on process: " << processName
1634 << " path: " << objectPath << "\n";
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001635 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001636 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001637 tinyxml2::XMLDocument doc;
1638
1639 doc.Parse(introspect_xml.c_str());
1640 tinyxml2::XMLNode *pRoot =
1641 doc.FirstChildElement("node");
1642 if (pRoot == nullptr)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001643 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001644 BMCWEB_LOG_ERROR << "XML document failed to parse "
1645 << processName << " " << objectPath
1646 << "\n";
1647 res.jsonValue = {{"status", "XML parse error"}};
1648 res.result(boost::beast::http::status::
1649 internal_server_error);
1650 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001651 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001652
1653 BMCWEB_LOG_DEBUG << introspect_xml;
1654 res.jsonValue = {{"status", "ok"},
1655 {"bus_name", processName},
1656 {"object_path", objectPath}};
1657 nlohmann::json &interfacesArray =
1658 res.jsonValue["interfaces"];
1659 interfacesArray = nlohmann::json::array();
1660 tinyxml2::XMLElement *interface =
1661 pRoot->FirstChildElement("interface");
1662
1663 while (interface != nullptr)
1664 {
1665 const char *ifaceName =
1666 interface->Attribute("name");
1667 if (ifaceName != nullptr)
1668 {
1669 interfacesArray.push_back(
1670 {{"name", ifaceName}});
1671 }
1672
1673 interface =
1674 interface->NextSiblingElement("interface");
1675 }
1676
Ed Tanous1abe55e2018-09-05 08:30:59 -07001677 res.end();
1678 },
1679 processName, objectPath,
1680 "org.freedesktop.DBus.Introspectable", "Introspect");
1681 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001682 else if (methodName.empty())
Ed Tanous1abe55e2018-09-05 08:30:59 -07001683 {
1684 crow::connections::systemBus->async_method_call(
1685 [&, processName, objectPath,
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001686 interfaceName{std::move(interfaceName)}](
Ed Tanous1abe55e2018-09-05 08:30:59 -07001687 const boost::system::error_code ec,
1688 const std::string &introspect_xml) {
1689 if (ec)
1690 {
1691 BMCWEB_LOG_ERROR
1692 << "Introspect call failed with error: "
1693 << ec.message()
1694 << " on process: " << processName
1695 << " path: " << objectPath << "\n";
1696 }
1697 else
1698 {
1699 tinyxml2::XMLDocument doc;
1700
1701 doc.Parse(introspect_xml.c_str());
1702 tinyxml2::XMLNode *pRoot =
1703 doc.FirstChildElement("node");
1704 if (pRoot == nullptr)
1705 {
1706 BMCWEB_LOG_ERROR
1707 << "XML document failed to parse "
1708 << processName << " " << objectPath << "\n";
1709 res.result(boost::beast::http::status::
1710 internal_server_error);
1711 }
1712 else
1713 {
1714 tinyxml2::XMLElement *node =
1715 pRoot->FirstChildElement("node");
1716
1717 // if we know we're the only call, build the
1718 // json directly
Ed Tanous1abe55e2018-09-05 08:30:59 -07001719 tinyxml2::XMLElement *interface =
1720 pRoot->FirstChildElement("interface");
1721
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001722 res.jsonValue = {
1723 {"status", "ok"},
1724 {"bus_name", processName},
1725 {"interface", interfaceName},
1726 {"object_path", objectPath},
1727 {"properties", nlohmann::json::object()}};
1728
1729 nlohmann::json &methodsArray =
1730 res.jsonValue["methods"];
1731 methodsArray = nlohmann::json::array();
1732
1733 nlohmann::json &signalsArray =
1734 res.jsonValue["signals"];
1735 signalsArray = nlohmann::json::array();
1736
Ed Tanous1abe55e2018-09-05 08:30:59 -07001737 while (interface != nullptr)
1738 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001739 const char *ifaceName =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001740 interface->Attribute("name");
1741
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001742 if (ifaceName != nullptr &&
1743 ifaceName == interfaceName)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001744 {
1745 tinyxml2::XMLElement *methods =
1746 interface->FirstChildElement(
1747 "method");
1748 while (methods != nullptr)
1749 {
1750 nlohmann::json argsArray =
1751 nlohmann::json::array();
1752 tinyxml2::XMLElement *arg =
1753 methods->FirstChildElement(
1754 "arg");
1755 while (arg != nullptr)
1756 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001757 nlohmann::json thisArg;
1758 for (const char *fieldName :
1759 std::array<const char *,
1760 3>{"name",
1761 "direction",
1762 "type"})
1763 {
1764 const char *fieldValue =
1765 arg->Attribute(
1766 fieldName);
1767 if (fieldValue != nullptr)
1768 {
1769 thisArg[fieldName] =
1770 fieldValue;
1771 }
1772 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001773 argsArray.push_back(
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001774 std::move(thisArg));
Ed Tanous1abe55e2018-09-05 08:30:59 -07001775 arg = arg->NextSiblingElement(
1776 "arg");
1777 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001778
1779 const char *name =
1780 methods->Attribute("name");
1781 if (name != nullptr)
1782 {
1783 methodsArray.push_back(
1784 {{"name", name},
1785 {"uri", "/bus/system/" +
1786 processName +
1787 objectPath +
1788 "/" +
1789 interfaceName +
1790 "/" + name},
1791 {"args", argsArray}});
1792 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001793 methods =
1794 methods->NextSiblingElement(
1795 "method");
1796 }
1797 tinyxml2::XMLElement *signals =
1798 interface->FirstChildElement(
1799 "signal");
1800 while (signals != nullptr)
1801 {
1802 nlohmann::json argsArray =
1803 nlohmann::json::array();
1804
1805 tinyxml2::XMLElement *arg =
1806 signals->FirstChildElement(
1807 "arg");
1808 while (arg != nullptr)
1809 {
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001810 const char *name =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001811 arg->Attribute("name");
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001812 const char *type =
Ed Tanous1abe55e2018-09-05 08:30:59 -07001813 arg->Attribute("type");
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001814 if (name != nullptr &&
1815 type != nullptr)
1816 {
1817 argsArray.push_back({
1818 {"name", name},
1819 {"type", type},
1820 });
1821 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001822 arg = arg->NextSiblingElement(
1823 "arg");
1824 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001825 const char *name =
1826 signals->Attribute("name");
1827 if (name != nullptr)
1828 {
1829 signalsArray.push_back(
1830 {{"name", name},
1831 {"args", argsArray}});
1832 }
1833
Ed Tanous1abe55e2018-09-05 08:30:59 -07001834 signals =
1835 signals->NextSiblingElement(
1836 "signal");
1837 }
1838
Ed Tanous1abe55e2018-09-05 08:30:59 -07001839 break;
1840 }
1841
1842 interface = interface->NextSiblingElement(
1843 "interface");
1844 }
1845 if (interface == nullptr)
1846 {
1847 // if we got to the end of the list and
1848 // never found a match, throw 404
1849 res.result(
1850 boost::beast::http::status::not_found);
1851 }
1852 }
1853 }
1854 res.end();
1855 },
1856 processName, objectPath,
1857 "org.freedesktop.DBus.Introspectable", "Introspect");
1858 }
Ed Tanouse3cb5a32018-08-08 14:16:49 -07001859 else
1860 {
1861 if (req.method() != "POST"_method)
1862 {
1863 res.result(boost::beast::http::status::not_found);
1864 res.end();
1865 return;
1866 }
1867
1868 nlohmann::json requestDbusData =
1869 nlohmann::json::parse(req.body, nullptr, false);
1870
1871 if (requestDbusData.is_discarded())
1872 {
1873 res.result(boost::beast::http::status::bad_request);
1874 res.end();
1875 return;
1876 }
1877 if (!requestDbusData.is_array())
1878 {
1879 res.result(boost::beast::http::status::bad_request);
1880 res.end();
1881 return;
1882 }
1883 auto transaction = std::make_shared<InProgressActionData>(res);
1884
1885 transaction->path = objectPath;
1886 transaction->methodName = methodName;
1887 transaction->arguments = std::move(requestDbusData);
1888
1889 findActionOnInterface(transaction, processName);
1890 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001891 });
1892}
1893} // namespace openbmc_mapper
1894} // namespace crow