blob: 4257127c81a1e5846106420ea3ef657242807e3d [file] [log] [blame]
Ed Tanous911ac312017-08-15 09:37:42 -07001#include <crow/app.h>
2
3#include <tinyxml2.h>
Ed Tanous911ac312017-08-15 09:37:42 -07004#include <dbus_singleton.hpp>
Ed Tanous64530012018-02-06 17:08:16 -08005#include <boost/container/flat_set.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -07006
7namespace crow {
8namespace openbmc_mapper {
Ed Tanousba9f9a62017-10-11 16:40:35 -07009
Ed Tanous911ac312017-08-15 09:37:42 -070010void introspect_objects(crow::response &res, std::string process_name,
Ed Tanous64530012018-02-06 17:08:16 -080011 std::string path,
12 std::shared_ptr<nlohmann::json> transaction) {
Ed Tanous911ac312017-08-15 09:37:42 -070013 crow::connections::system_bus->async_method_call(
Ed Tanousaa2e59c2018-04-12 12:17:20 -070014 [
15 &res, transaction, process_name{std::move(process_name)},
16 object_path{std::move(path)}
17 ](const boost::system::error_code ec, const std::string &introspect_xml) {
Ed Tanous911ac312017-08-15 09:37:42 -070018 if (ec) {
Ed Tanous64530012018-02-06 17:08:16 -080019 CROW_LOG_ERROR << "Introspect call failed with error: "
20 << ec.message() << " on process: " << process_name
21 << " path: " << object_path << "\n";
Ed Tanous911ac312017-08-15 09:37:42 -070022
23 } else {
Ed Tanous64530012018-02-06 17:08:16 -080024 transaction->push_back({{"path", object_path}});
Ed Tanous911ac312017-08-15 09:37:42 -070025
26 tinyxml2::XMLDocument doc;
27
28 doc.Parse(introspect_xml.c_str());
29 tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
30 if (pRoot == nullptr) {
Ed Tanous64530012018-02-06 17:08:16 -080031 CROW_LOG_ERROR << "XML document failed to parse " << process_name
Ed Tanousaa2e59c2018-04-12 12:17:20 -070032 << " " << object_path << "\n";
Ed Tanous911ac312017-08-15 09:37:42 -070033
34 } else {
35 tinyxml2::XMLElement *node = pRoot->FirstChildElement("node");
36 while (node != nullptr) {
37 std::string child_path = node->Attribute("name");
38 std::string newpath;
39 if (object_path != "/") {
40 newpath += object_path;
41 }
42 newpath += "/" + child_path;
Ed Tanous64530012018-02-06 17:08:16 -080043 // introspect the subobjects as well
44 introspect_objects(res, process_name, newpath, transaction);
Ed Tanous911ac312017-08-15 09:37:42 -070045
46 node = node->NextSiblingElement("node");
47 }
48 }
49 }
50 // if we're the last outstanding caller, finish the request
Ed Tanous64530012018-02-06 17:08:16 -080051 if (transaction.use_count() == 1) {
52 res.json_value = {{"status", "ok"},
53 {"bus_name", process_name},
54 {"objects", *transaction}};
Ed Tanous911ac312017-08-15 09:37:42 -070055 res.end();
56 }
57 },
Ed Tanousaa2e59c2018-04-12 12:17:20 -070058 process_name, path, "org.freedesktop.DBus.Introspectable", "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -070059}
Ed Tanous64530012018-02-06 17:08:16 -080060
Ed Tanousaa2e59c2018-04-12 12:17:20 -070061// A smattering of common types to unpack. TODO(ed) this should really iterate
62// the sdbusplus object directly and build the json response
63using DbusRestVariantType = sdbusplus::message::variant<
64 std::vector<std::tuple<std::string, std::string, std::string>>, std::string,
65 int64_t, uint64_t, double, int32_t, uint32_t, int16_t, uint16_t, uint8_t,
66 bool>;
67
68using ManagedObjectType = std::vector<std::pair<
69 sdbusplus::message::object_path,
70 boost::container::flat_map<
71 std::string,
72 boost::container::flat_map<std::string, DbusRestVariantType>>>>;
73
74void get_managed_objects_for_enumerate(
Ed Tanous64530012018-02-06 17:08:16 -080075 const std::string &object_name, const std::string &connection_name,
76 crow::response &res, std::shared_ptr<nlohmann::json> transaction) {
77 crow::connections::system_bus->async_method_call(
78 [&res, transaction](const boost::system::error_code ec,
79 const ManagedObjectType &objects) {
80 if (ec) {
81 CROW_LOG_ERROR << ec;
82 } else {
83 nlohmann::json &data_json = *transaction;
Ed Tanousaa2e59c2018-04-12 12:17:20 -070084
Ed Tanous64530012018-02-06 17:08:16 -080085 for (auto &object_path : objects) {
Ed Tanousaa2e59c2018-04-12 12:17:20 -070086 CROW_LOG_DEBUG << "Reading object "
87 << static_cast<const std::string&>(object_path.first);
88 nlohmann::json &object_json =
89 data_json[static_cast<const std::string&>(object_path.first)];
90 if (object_json.is_null()) {
91 object_json = nlohmann::json::object();
92 }
Ed Tanous64530012018-02-06 17:08:16 -080093 for (const auto &interface : object_path.second) {
94 for (const auto &property : interface.second) {
Ed Tanousaa2e59c2018-04-12 12:17:20 -070095 nlohmann::json &property_json = object_json[property.first];
96 mapbox::util::apply_visitor(
97 [&property_json](auto &&val) { property_json = val; },
Ed Tanous64530012018-02-06 17:08:16 -080098 property.second);
Ed Tanousaa2e59c2018-04-12 12:17:20 -070099
100 // dbus-rest represents booleans as 1 or 0, implement to match
101 // TODO(ed) see if dbus-rest should be changed
102 const bool *property_bool =
103 property_json.get_ptr<const bool *>();
104 if (property_bool != nullptr) {
105 property_json = *property_bool ? 1 : 0;
106 }
Ed Tanous64530012018-02-06 17:08:16 -0800107 }
108 }
109 }
110 }
111
112 if (transaction.use_count() == 1) {
113 res.json_value = {{"message", "200 OK"},
114 {"status", "ok"},
115 {"data", std::move(*transaction)}};
116 res.end();
117 }
118 },
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700119 connection_name, object_name, "org.freedesktop.DBus.ObjectManager",
120 "GetManagedObjects");
121}
Ed Tanous64530012018-02-06 17:08:16 -0800122
123using GetSubTreeType = std::vector<
124 std::pair<std::string,
125 std::vector<std::pair<std::string, std::vector<std::string>>>>>;
126
127void handle_enumerate(crow::response &res, const std::string &object_path) {
128 crow::connections::system_bus->async_method_call(
129 [&res, object_path{std::string(object_path)} ](
130 const boost::system::error_code ec,
131 const GetSubTreeType &object_names) {
132 if (ec) {
133 res.code = 500;
134 res.end();
135 return;
136 }
137
138 boost::container::flat_set<std::string> connections;
139
140 for (const auto &object : object_names) {
141 for (const auto &connection : object.second) {
142 connections.insert(connection.first);
143 }
144 }
145
146 if (connections.size() <= 0) {
147 res.code = 404;
148 res.end();
149 return;
150 }
151 auto transaction =
152 std::make_shared<nlohmann::json>(nlohmann::json::object());
153 for (const std::string &connection : connections) {
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700154 get_managed_objects_for_enumerate(object_path, connection, res,
155 transaction);
Ed Tanous64530012018-02-06 17:08:16 -0800156 }
157
158 },
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700159 "xyz.openbmc_project.ObjectMapper", "/xyz/openbmc_project/object_mapper",
160 "xyz.openbmc_project.ObjectMapper", "GetSubTree", object_path, (int32_t)0,
161 std::array<std::string, 0>());
Ed Tanous64530012018-02-06 17:08:16 -0800162}
Ed Tanous911ac312017-08-15 09:37:42 -0700163
164template <typename... Middlewares>
165void request_routes(Crow<Middlewares...> &app) {
166 CROW_ROUTE(app, "/bus/").methods("GET"_method)([](const crow::request &req) {
167 return nlohmann::json{{"busses", {{{"name", "system"}}}}, {"status", "ok"}};
168
169 });
170
171 CROW_ROUTE(app, "/bus/system/")
172 .methods("GET"_method)([](const crow::request &req, crow::response &res) {
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700173
174 auto myCallback = [&res](const boost::system::error_code ec,
175 std::vector<std::string> &names) {
176 if (ec) {
177 res.code = 500;
178 } else {
179 std::sort(names.begin(), names.end());
180 nlohmann::json j{{"status", "ok"}};
181 auto &objects_sub = j["objects"];
182 for (auto &name : names) {
183 objects_sub.push_back({{"name", name}});
184 }
185 res.json_value = std::move(j);
186 }
187 res.end();
188 };
Ed Tanous911ac312017-08-15 09:37:42 -0700189 crow::connections::system_bus->async_method_call(
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700190 std::move(myCallback), "org.freedesktop.DBus", "/",
191 "org.freedesktop.DBus", "ListNames");
Ed Tanous911ac312017-08-15 09:37:42 -0700192 });
193
Ed Tanousba9f9a62017-10-11 16:40:35 -0700194 CROW_ROUTE(app, "/list/")
195 .methods("GET"_method)([](const crow::request &req, crow::response &res) {
196 crow::connections::system_bus->async_method_call(
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700197 [&res](const boost::system::error_code ec,
198 const std::vector<std::string> &object_paths) {
Ed Tanousba9f9a62017-10-11 16:40:35 -0700199 if (ec) {
200 res.code = 500;
201 } else {
Ed Tanous64530012018-02-06 17:08:16 -0800202 res.json_value = {{"status", "ok"},
203 {"message", "200 OK"},
204 {"data", std::move(object_paths)}};
Ed Tanousba9f9a62017-10-11 16:40:35 -0700205 }
206 res.end();
207 },
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700208 "xyz.openbmc_project.ObjectMapper",
209 "/xyz/openbmc_project/object_mapper",
210 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "",
211 static_cast<int32_t>(99), std::array<std::string, 0>());
Ed Tanousba9f9a62017-10-11 16:40:35 -0700212 });
213
Ed Tanous64530012018-02-06 17:08:16 -0800214 CROW_ROUTE(app, "/xyz/<path>")
shiyilei00b92f72017-11-12 16:21:16 +0800215 .methods("GET"_method,
216 "PUT"_method)([](const crow::request &req, crow::response &res,
Ed Tanousba9f9a62017-10-11 16:40:35 -0700217 const std::string &path) {
Ed Tanous64530012018-02-06 17:08:16 -0800218 std::shared_ptr<nlohmann::json> transaction =
219 std::make_shared<nlohmann::json>(nlohmann::json::object());
Ed Tanousba9f9a62017-10-11 16:40:35 -0700220 using GetObjectType =
221 std::vector<std::pair<std::string, std::vector<std::string>>>;
shiyilei00b92f72017-11-12 16:21:16 +0800222 std::string object_path;
223 std::string dest_property;
224 std::string property_set_value;
225 size_t attr_position = path.find("/attr/");
Ed Tanous64530012018-02-06 17:08:16 -0800226 if (attr_position == path.npos) {
shiyilei00b92f72017-11-12 16:21:16 +0800227 object_path = "/xyz/" + path;
Ed Tanous64530012018-02-06 17:08:16 -0800228 } else {
shiyilei00b92f72017-11-12 16:21:16 +0800229 object_path = "/xyz/" + path.substr(0, attr_position);
230 dest_property =
231 path.substr((attr_position + strlen("/attr/")), path.length());
232 auto request_dbus_data =
233 nlohmann::json::parse(req.body, nullptr, false);
234 if (request_dbus_data.is_discarded()) {
235 res.code = 400;
236 res.end();
237 return;
238 }
Ed Tanousba9f9a62017-10-11 16:40:35 -0700239
shiyilei00b92f72017-11-12 16:21:16 +0800240 auto property_value_it = request_dbus_data.find("data");
241 if (property_value_it == request_dbus_data.end()) {
242 res.code = 400;
243 res.end();
244 return;
245 }
246
247 property_set_value = property_value_it->get<const std::string>();
248 if (property_set_value.empty()) {
249 res.code = 400;
250 res.end();
251 return;
252 }
253 }
254
Ed Tanous64530012018-02-06 17:08:16 -0800255 if (boost::ends_with(object_path, "/enumerate")) {
256 object_path.erase(object_path.end() - 10, object_path.end());
257 handle_enumerate(res, object_path);
258 return;
259 }
260
Ed Tanousba9f9a62017-10-11 16:40:35 -0700261 crow::connections::system_bus->async_method_call(
shiyilei00b92f72017-11-12 16:21:16 +0800262 [
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700263 &res, &req, object_path{std::move(object_path)},
264 dest_property{std::move(dest_property)},
265 property_set_value{std::move(property_set_value)}, transaction
shiyilei00b92f72017-11-12 16:21:16 +0800266 ](const boost::system::error_code ec,
267 const GetObjectType &object_names) {
Ed Tanousba9f9a62017-10-11 16:40:35 -0700268 if (ec) {
269 res.code = 500;
270 res.end();
271 return;
272 }
273 if (object_names.size() != 1) {
274 res.code = 404;
275 res.end();
276 return;
277 }
shiyilei00b92f72017-11-12 16:21:16 +0800278 if (req.method == "GET"_method) {
279 for (auto &interface : object_names[0].second) {
shiyilei00b92f72017-11-12 16:21:16 +0800280 crow::connections::system_bus->async_method_call(
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700281 [&res, transaction](
282 const boost::system::error_code ec,
shiyilei00b92f72017-11-12 16:21:16 +0800283 const std::vector<std::pair<
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700284 std::string, DbusRestVariantType>> &properties) {
shiyilei00b92f72017-11-12 16:21:16 +0800285 if (ec) {
Ed Tanous64530012018-02-06 17:08:16 -0800286 CROW_LOG_ERROR << "Bad dbus request error: " << ec;
shiyilei00b92f72017-11-12 16:21:16 +0800287 } else {
288 for (auto &property : properties) {
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700289 nlohmann::json &it = (*transaction)[property.first];
290 mapbox::util::apply_visitor(
291 [&it](auto &&val) { it = val; },
shiyilei00b92f72017-11-12 16:21:16 +0800292 property.second);
293 }
294 }
Ed Tanous64530012018-02-06 17:08:16 -0800295 if (transaction.use_count() == 1) {
296 res.json_value = {{"status", "ok"},
297 {"message", "200 OK"},
298 {"data", *transaction}};
299
shiyilei00b92f72017-11-12 16:21:16 +0800300 res.end();
shiyilei00b92f72017-11-12 16:21:16 +0800301 }
302 },
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700303 object_names[0].first, object_path,
304 "org.freedesktop.DBus.Properties", "GetAll", interface);
shiyilei00b92f72017-11-12 16:21:16 +0800305 }
306 } else if (req.method == "PUT"_method) {
307 for (auto &interface : object_names[0].second) {
shiyilei00b92f72017-11-12 16:21:16 +0800308 crow::connections::system_bus->async_method_call(
309 [
310 &, interface{std::move(interface)},
311 object_names{std::move(object_names)},
312 object_path{std::move(object_path)},
313 dest_property{std::move(dest_property)},
Ed Tanous64530012018-02-06 17:08:16 -0800314 property_set_value{std::move(property_set_value)},
315 transaction
shiyilei00b92f72017-11-12 16:21:16 +0800316 ](const boost::system::error_code ec,
Ed Tanous64530012018-02-06 17:08:16 -0800317 const boost::container::flat_map<
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700318 std::string, DbusRestVariantType> &properties) {
shiyilei00b92f72017-11-12 16:21:16 +0800319 if (ec) {
Ed Tanous64530012018-02-06 17:08:16 -0800320 CROW_LOG_ERROR << "Bad dbus request error: " << ec;
shiyilei00b92f72017-11-12 16:21:16 +0800321 } else {
Ed Tanous64530012018-02-06 17:08:16 -0800322 auto it = properties.find(dest_property);
323 if (it != properties.end()) {
324 // find the matched property in the interface
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700325 DbusRestVariantType property_value(
326 property_set_value);
327 // create the dbus variant for dbus call
Ed Tanous64530012018-02-06 17:08:16 -0800328 crow::connections::system_bus->async_method_call(
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700329 [transaction](
330 const boost::system::error_code ec) {
Ed Tanous64530012018-02-06 17:08:16 -0800331 // use the method "Set" to set the property
332 // value
333 if (ec) {
334 CROW_LOG_ERROR << "Bad dbus request error: "
335 << ec;
336 }
337 // find the matched property and send the
338 // response
339 *transaction = {{"status", "ok"},
340 {"message", "200 OK"},
341 {"data", nullptr}};
342
343 },
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700344 object_names[0].first, object_path,
345 "org.freedesktop.DBus.Properties", "Set",
Ed Tanous64530012018-02-06 17:08:16 -0800346 interface, dest_property, property_value);
shiyilei00b92f72017-11-12 16:21:16 +0800347 }
Ed Tanous64530012018-02-06 17:08:16 -0800348 }
349 // if we are the last caller, finish the transaction
350 if (transaction.use_count() == 1) {
351 // if nobody filled in the property, all calls either
352 // errored, or failed
353 if (transaction == nullptr) {
354 res.code = 403;
355 res.json_value = {{"status", "error"},
356 {"message", "403 Forbidden"},
357 {"data",
358 {{"message",
359 "The specified property "
360 "cannot be created: " +
361 dest_property}}}};
362
363 } else {
364 res.json_value = *transaction;
shiyilei00b92f72017-11-12 16:21:16 +0800365 }
Ed Tanous64530012018-02-06 17:08:16 -0800366
367 res.end();
368 return;
Ed Tanousba9f9a62017-10-11 16:40:35 -0700369 }
shiyilei00b92f72017-11-12 16:21:16 +0800370 },
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700371 object_names[0].first, object_path,
372 "org.freedesktop.DBus.Properties", "GetAll", interface);
shiyilei00b92f72017-11-12 16:21:16 +0800373 }
Ed Tanousba9f9a62017-10-11 16:40:35 -0700374 }
375 },
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700376 "xyz.openbmc_project.ObjectMapper",
377 "/xyz/openbmc_project/object_mapper",
378 "xyz.openbmc_project.ObjectMapper", "GetObject", object_path,
379 std::array<std::string, 0>());
Ed Tanousba9f9a62017-10-11 16:40:35 -0700380 });
shiyilei00b92f72017-11-12 16:21:16 +0800381
Ed Tanous911ac312017-08-15 09:37:42 -0700382 CROW_ROUTE(app, "/bus/system/<str>/")
383 .methods("GET"_method)([](const crow::request &req, crow::response &res,
384 const std::string &connection) {
Ed Tanous64530012018-02-06 17:08:16 -0800385 std::shared_ptr<nlohmann::json> transaction;
386 introspect_objects(res, connection, "/", transaction);
Ed Tanous911ac312017-08-15 09:37:42 -0700387 });
388
389 CROW_ROUTE(app, "/bus/system/<str>/<path>")
390 .methods("GET"_method)([](const crow::request &req, crow::response &res,
391 const std::string &process_name,
392 const std::string &requested_path) {
393
394 std::vector<std::string> strs;
395 boost::split(strs, requested_path, boost::is_any_of("/"));
396 std::string object_path;
397 std::string interface_name;
398 std::string method_name;
399 auto it = strs.begin();
400 if (it == strs.end()) {
401 object_path = "/";
402 }
403 while (it != strs.end()) {
404 // Check if segment contains ".". If it does, it must be an
405 // interface
406 if ((*it).find(".") != std::string::npos) {
407 break;
Ed Tanousba9f9a62017-10-11 16:40:35 -0700408 // THis check is neccesary as the trailing slash gets parsed as
Ed Tanous64530012018-02-06 17:08:16 -0800409 // part of our <path> specifier above, which causes the normal
410 // trailing backslash redirector to fail.
Ed Tanous911ac312017-08-15 09:37:42 -0700411 } else if (!it->empty()) {
412 object_path += "/" + *it;
413 }
414 it++;
415 }
416 if (it != strs.end()) {
417 interface_name = *it;
418 it++;
419
420 // after interface, we might have a method name
421 if (it != strs.end()) {
422 method_name = *it;
423 it++;
424 }
425 }
426 if (it != strs.end()) {
427 // if there is more levels past the method name, something went
428 // wrong, throw an error
429 res.code = 404;
430 res.end();
431 return;
432 }
Ed Tanous911ac312017-08-15 09:37:42 -0700433 if (interface_name.empty()) {
434 crow::connections::system_bus->async_method_call(
435 [
436 &, process_name{std::move(process_name)},
437 object_path{std::move(object_path)}
438 ](const boost::system::error_code ec,
439 const std::string &introspect_xml) {
440 if (ec) {
Ed Tanous64530012018-02-06 17:08:16 -0800441 CROW_LOG_ERROR
Ed Tanous911ac312017-08-15 09:37:42 -0700442 << "Introspect call failed with error: " << ec.message()
443 << " on process: " << process_name
444 << " path: " << object_path << "\n";
445
446 } else {
447 tinyxml2::XMLDocument doc;
448
449 doc.Parse(introspect_xml.c_str());
450 tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
451 if (pRoot == nullptr) {
Ed Tanous64530012018-02-06 17:08:16 -0800452 CROW_LOG_ERROR << "XML document failed to parse "
453 << process_name << " " << object_path
454 << "\n";
Ed Tanous911ac312017-08-15 09:37:42 -0700455 res.write(nlohmann::json{{"status", "XML parse error"}});
456 res.code = 500;
457 } else {
458 nlohmann::json interfaces_array = nlohmann::json::array();
459 tinyxml2::XMLElement *interface =
460 pRoot->FirstChildElement("interface");
461
462 while (interface != nullptr) {
463 std::string iface_name = interface->Attribute("name");
464 interfaces_array.push_back({{"name", iface_name}});
465
466 interface = interface->NextSiblingElement("interface");
467 }
Ed Tanous64530012018-02-06 17:08:16 -0800468 res.json_value = {{"status", "ok"},
469 {"bus_name", process_name},
470 {"interfaces", interfaces_array},
471 {"object_path", object_path}};
Ed Tanous911ac312017-08-15 09:37:42 -0700472 }
473 }
474 res.end();
475 },
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700476 process_name, object_path, "org.freedesktop.DBus.Introspectable",
477 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -0700478 } else {
479 crow::connections::system_bus->async_method_call(
480 [
481 &, process_name{std::move(process_name)},
482 interface_name{std::move(interface_name)},
483 object_path{std::move(object_path)}
484 ](const boost::system::error_code ec,
485 const std::string &introspect_xml) {
486 if (ec) {
Ed Tanous64530012018-02-06 17:08:16 -0800487 CROW_LOG_ERROR
Ed Tanous911ac312017-08-15 09:37:42 -0700488 << "Introspect call failed with error: " << ec.message()
489 << " on process: " << process_name
490 << " path: " << object_path << "\n";
491
492 } else {
493 tinyxml2::XMLDocument doc;
494
495 doc.Parse(introspect_xml.c_str());
496 tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
497 if (pRoot == nullptr) {
Ed Tanous64530012018-02-06 17:08:16 -0800498 CROW_LOG_ERROR << "XML document failed to parse "
499 << process_name << " " << object_path
500 << "\n";
Ed Tanous911ac312017-08-15 09:37:42 -0700501 res.code = 500;
502
503 } else {
504 tinyxml2::XMLElement *node =
505 pRoot->FirstChildElement("node");
506
507 // if we know we're the only call, build the json directly
508 nlohmann::json methods_array = nlohmann::json::array();
509 nlohmann::json signals_array = nlohmann::json::array();
510 tinyxml2::XMLElement *interface =
511 pRoot->FirstChildElement("interface");
512
513 while (interface != nullptr) {
514 std::string iface_name = interface->Attribute("name");
515
516 if (iface_name == interface_name) {
517 tinyxml2::XMLElement *methods =
518 interface->FirstChildElement("method");
519 while (methods != nullptr) {
520 nlohmann::json args_array = nlohmann::json::array();
521 tinyxml2::XMLElement *arg =
522 methods->FirstChildElement("arg");
523 while (arg != nullptr) {
524 args_array.push_back(
525 {{"name", arg->Attribute("name")},
526 {"type", arg->Attribute("type")},
527 {"direction", arg->Attribute("direction")}});
528 arg = arg->NextSiblingElement("arg");
529 }
530 methods_array.push_back(
531 {{"name", methods->Attribute("name")},
Ed Tanous64530012018-02-06 17:08:16 -0800532 {"uri", "/bus/system/" + process_name +
533 object_path + "/" + interface_name +
534 "/" + methods->Attribute("name")},
Ed Tanous911ac312017-08-15 09:37:42 -0700535 {"args", args_array}});
536 methods = methods->NextSiblingElement("method");
537 }
538 tinyxml2::XMLElement *signals =
539 interface->FirstChildElement("signal");
540 while (signals != nullptr) {
541 nlohmann::json args_array = nlohmann::json::array();
542
543 tinyxml2::XMLElement *arg =
544 signals->FirstChildElement("arg");
545 while (arg != nullptr) {
546 std::string name = arg->Attribute("name");
547 std::string type = arg->Attribute("type");
548 args_array.push_back({
Ed Tanous64530012018-02-06 17:08:16 -0800549 {"name", name},
550 {"type", type},
Ed Tanous911ac312017-08-15 09:37:42 -0700551 });
552 arg = arg->NextSiblingElement("arg");
553 }
554 signals_array.push_back(
555 {{"name", signals->Attribute("name")},
556 {"args", args_array}});
557 signals = signals->NextSiblingElement("signal");
558 }
559
560 nlohmann::json j{
561 {"status", "ok"},
562 {"bus_name", process_name},
563 {"interface", interface_name},
564 {"methods", methods_array},
565 {"object_path", object_path},
566 {"properties", nlohmann::json::object()},
567 {"signals", signals_array}};
568
569 res.write(j.dump());
570 break;
571 }
572
573 interface = interface->NextSiblingElement("interface");
574 }
575 if (interface == nullptr) {
576 // if we got to the end of the list and never found a
577 // match, throw 404
578 res.code = 404;
579 }
580 }
581 }
582 res.end();
583 },
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700584 process_name, object_path, "org.freedesktop.DBus.Introspectable",
585 "Introspect");
Ed Tanous911ac312017-08-15 09:37:42 -0700586 }
587
588 });
Ed Tanousaa2e59c2018-04-12 12:17:20 -0700589} // namespace openbmc_mapper
Ed Tanous911ac312017-08-15 09:37:42 -0700590} // namespace openbmc_mapper
591} // namespace crow