blob: 1755e469f4edec81e3f9b13539e0ff194ddddc0a [file] [log] [blame]
James Feist3cb5fec2018-01-23 14:41:51 -08001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
17#include <Utils.hpp>
James Feistc95cb142018-02-26 10:41:42 -080018#include <Overlay.hpp>
James Feist3cb5fec2018-01-23 14:41:51 -080019#include <nlohmann/json.hpp>
20#include <fstream>
21#include <regex>
James Feist8f2710a2018-05-09 17:18:55 -070022#include <iostream>
23#include <sdbusplus/asio/connection.hpp>
24#include <sdbusplus/asio/object_server.hpp>
James Feist11be6672018-04-06 14:05:32 -070025#include <boost/algorithm/string/case_conv.hpp>
James Feist3cb5fec2018-01-23 14:41:51 -080026#include <boost/algorithm/string/predicate.hpp>
27#include <boost/algorithm/string/replace.hpp>
28#include <boost/variant/apply_visitor.hpp>
29#include <boost/lexical_cast.hpp>
30#include <boost/container/flat_map.hpp>
31#include <boost/container/flat_set.hpp>
32#include <VariantVisitors.hpp>
James Feist7b7e4e82018-01-24 14:56:00 -080033#include <experimental/filesystem>
James Feist3cb5fec2018-01-23 14:41:51 -080034
35constexpr const char *OUTPUT_DIR = "/var/configuration/";
36constexpr const char *CONFIGURATION_DIR = "/usr/share/configurations";
37constexpr const char *TEMPLATE_CHAR = "$";
James Feistc95cb142018-02-26 10:41:42 -080038constexpr const size_t PROPERTIES_CHANGED_UNTIL_FLUSH_COUNT = 20;
James Feist8f2710a2018-05-09 17:18:55 -070039constexpr const int32_t MAX_MAPPER_DEPTH = 0;
James Feist4131aea2018-03-09 09:47:30 -080040constexpr const size_t SLEEP_AFTER_PROPERTIES_CHANGE_SECONDS = 5;
James Feist3cb5fec2018-01-23 14:41:51 -080041
42namespace fs = std::experimental::filesystem;
43struct cmp_str
44{
45 bool operator()(const char *a, const char *b) const
46 {
47 return std::strcmp(a, b) < 0;
48 }
49};
50
James Feist8f2710a2018-05-09 17:18:55 -070051struct PerformProbe;
52
James Feist3cb5fec2018-01-23 14:41:51 -080053// underscore T for collison with dbus c api
54enum class probe_type_codes
55{
56 FALSE_T,
57 TRUE_T,
58 AND,
59 OR,
James Feist6bd2a022018-03-13 12:30:58 -070060 FOUND,
61 MATCH_ONE
James Feist3cb5fec2018-01-23 14:41:51 -080062};
63const static boost::container::flat_map<const char *, probe_type_codes, cmp_str>
64 PROBE_TYPES{{{"FALSE", probe_type_codes::FALSE_T},
65 {"TRUE", probe_type_codes::TRUE_T},
66 {"AND", probe_type_codes::AND},
67 {"OR", probe_type_codes::OR},
James Feist6bd2a022018-03-13 12:30:58 -070068 {"FOUND", probe_type_codes::FOUND},
69 {"MATCH_ONE", probe_type_codes::MATCH_ONE}}};
James Feist3cb5fec2018-01-23 14:41:51 -080070
James Feist8f2710a2018-05-09 17:18:55 -070071using BasicVariantType =
72 sdbusplus::message::variant<std::string, int64_t, uint64_t, double, int32_t,
73 uint32_t, int16_t, uint16_t, uint8_t, bool>;
74
James Feist3cb5fec2018-01-23 14:41:51 -080075using GetSubTreeType = std::vector<
76 std::pair<std::string,
77 std::vector<std::pair<std::string, std::vector<std::string>>>>>;
78
79using ManagedObjectType = boost::container::flat_map<
James Feist8f2710a2018-05-09 17:18:55 -070080 sdbusplus::message::object_path,
James Feist3cb5fec2018-01-23 14:41:51 -080081 boost::container::flat_map<
82 std::string,
James Feist8f2710a2018-05-09 17:18:55 -070083 boost::container::flat_map<std::string, BasicVariantType>>>;
James Feist3cb5fec2018-01-23 14:41:51 -080084
85boost::container::flat_map<
86 std::string,
James Feist8f2710a2018-05-09 17:18:55 -070087 std::vector<boost::container::flat_map<std::string, BasicVariantType>>>
James Feist3cb5fec2018-01-23 14:41:51 -080088 DBUS_PROBE_OBJECTS;
89std::vector<std::string> PASSED_PROBES;
90
91// todo: pass this through nicer
James Feist8f2710a2018-05-09 17:18:55 -070092std::shared_ptr<sdbusplus::asio::connection> SYSTEM_BUS;
James Feist3cb5fec2018-01-23 14:41:51 -080093
James Feist8f2710a2018-05-09 17:18:55 -070094const std::regex ILLEGAL_DBUS_REGEX("[^A-Za-z0-9_]");
James Feist1b2e2242018-01-30 13:45:19 -080095
James Feist8f2710a2018-05-09 17:18:55 -070096void registerCallbacks(boost::asio::io_service &io,
97 std::vector<sdbusplus::bus::match::match> &dbusMatches,
98 nlohmann::json &systemConfiguration,
99 sdbusplus::asio::object_server &objServer);
James Feist75fdeeb2018-02-20 14:26:16 -0800100
James Feist3cb5fec2018-01-23 14:41:51 -0800101// calls the mapper to find all exposed objects of an interface type
102// and creates a vector<flat_map> that contains all the key value pairs
103// getManagedObjects
James Feist8f2710a2018-05-09 17:18:55 -0700104void findDbusObjects(std::shared_ptr<PerformProbe> probe,
105 std::shared_ptr<sdbusplus::asio::connection> connection,
106 std::string &interface)
James Feist3cb5fec2018-01-23 14:41:51 -0800107{
James Feist494155a2018-03-14 16:23:24 -0700108 // todo: this is only static because the mapper is unreliable as of today
109 static boost::container::flat_map<std::string,
110 boost::container::flat_set<std::string>>
111 connections;
James Feist8f2710a2018-05-09 17:18:55 -0700112
113 // store reference to pending callbacks so we don't overwhelm services
114 static boost::container::flat_map<
115 std::string, std::vector<std::shared_ptr<PerformProbe>>>
116 pendingProbes;
117
118 if (DBUS_PROBE_OBJECTS[interface].size())
119 {
120 return;
121 }
122
123 // add shared_ptr to vector of Probes waiting for callback from a specific
124 // interface to keep alive while waiting for response
125 std::array<const char *, 1> objects = {interface.c_str()};
126 std::vector<std::shared_ptr<PerformProbe>> &pending =
127 pendingProbes[interface];
128 auto iter = pending.emplace(pending.end(), probe);
129 // only allow first call to run to not overwhelm processes
130 if (iter != pending.begin())
131 {
132 return;
133 }
134
James Feist3cb5fec2018-01-23 14:41:51 -0800135 // find all connections in the mapper that expose a specific type
James Feist8f2710a2018-05-09 17:18:55 -0700136 connection->async_method_call(
137 [&, connection, interface](boost::system::error_code &ec,
138 const GetSubTreeType &interfaceSubtree) {
139 auto &interfaceConnections = connections[interface];
140 if (ec)
James Feist494155a2018-03-14 16:23:24 -0700141 {
James Feist8f2710a2018-05-09 17:18:55 -0700142 std::cerr
143 << "Error communicating to mapper, using cached data if "
144 "available\n";
145 if (interfaceConnections.empty())
146 {
147 return;
148 }
James Feist494155a2018-03-14 16:23:24 -0700149 }
James Feist8f2710a2018-05-09 17:18:55 -0700150 else
James Feist3cb5fec2018-01-23 14:41:51 -0800151 {
James Feist8f2710a2018-05-09 17:18:55 -0700152 for (auto &object : interfaceSubtree)
153 {
154 for (auto &connPair : object.second)
155 {
156 auto insertPair =
157 interfaceConnections.insert(connPair.first);
158 }
159 }
James Feist3cb5fec2018-01-23 14:41:51 -0800160 }
James Feist8f2710a2018-05-09 17:18:55 -0700161 // get managed objects for all interfaces
162 for (const auto &conn : interfaceConnections)
163 {
164 connection->async_method_call(
165 [&, conn,
166 interface](boost::system::error_code &ec,
167 const ManagedObjectType &managedInterface) {
168 if (ec)
169 {
170 std::cerr
171 << "error getting managed object for device "
172 << conn << "\n";
173 pendingProbes[interface].clear();
174 return;
175 }
176 for (auto &interfaceManagedObj : managedInterface)
177 {
178 auto ifaceObjFind =
179 interfaceManagedObj.second.find(interface);
180 if (ifaceObjFind !=
181 interfaceManagedObj.second.end())
182 {
183 std::vector<boost::container::flat_map<
184 std::string, BasicVariantType>>
185 &dbusObject = DBUS_PROBE_OBJECTS[interface];
186 dbusObject.emplace_back(ifaceObjFind->second);
187 }
188 }
189 pendingProbes[interface].clear();
190 },
191 conn.c_str(), "/", "org.freedesktop.DBus.ObjectManager",
192 "GetManagedObjects");
193 }
194 },
195 "xyz.openbmc_project.ObjectMapper",
196 "/xyz/openbmc_project/object_mapper",
197 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "", MAX_MAPPER_DEPTH,
198 objects);
James Feist3cb5fec2018-01-23 14:41:51 -0800199}
James Feist8f2710a2018-05-09 17:18:55 -0700200// probes dbus interface dictionary for a key with a value that matches a regex
James Feist3cb5fec2018-01-23 14:41:51 -0800201bool probeDbus(
202 const std::string &interface,
203 const std::map<std::string, nlohmann::json> &matches,
James Feist8f2710a2018-05-09 17:18:55 -0700204 std::vector<boost::container::flat_map<std::string, BasicVariantType>>
James Feist3cb5fec2018-01-23 14:41:51 -0800205 &devices,
206 bool &foundProbe)
207{
James Feist8f2710a2018-05-09 17:18:55 -0700208 std::vector<boost::container::flat_map<std::string, BasicVariantType>>
209 &dbusObject = DBUS_PROBE_OBJECTS[interface];
James Feist3cb5fec2018-01-23 14:41:51 -0800210 if (dbusObject.empty())
211 {
James Feist8f2710a2018-05-09 17:18:55 -0700212 foundProbe = false;
213 return false;
James Feist3cb5fec2018-01-23 14:41:51 -0800214 }
215 foundProbe = true;
216
217 bool foundMatch = false;
218 for (auto &device : dbusObject)
219 {
220 bool deviceMatches = true;
221 for (auto &match : matches)
222 {
223 auto deviceValue = device.find(match.first);
224 if (deviceValue != device.end())
225 {
226 switch (match.second.type())
227 {
James Feist9eb0b582018-04-27 12:15:46 -0700228 case nlohmann::json::value_t::string:
James Feist3cb5fec2018-01-23 14:41:51 -0800229 {
James Feist9eb0b582018-04-27 12:15:46 -0700230 std::regex search(match.second.get<std::string>());
231 std::smatch match;
232
233 // convert value to string respresentation
James Feist8f2710a2018-05-09 17:18:55 -0700234 std::string probeValue = mapbox::util::apply_visitor(
235 VariantToStringVisitor(), deviceValue->second);
James Feist9eb0b582018-04-27 12:15:46 -0700236 if (!std::regex_search(probeValue, match, search))
237 {
238 deviceMatches = false;
239 break;
240 }
James Feist3cb5fec2018-01-23 14:41:51 -0800241 break;
242 }
James Feist9eb0b582018-04-27 12:15:46 -0700243 case nlohmann::json::value_t::boolean:
244 case nlohmann::json::value_t::number_unsigned:
James Feist3cb5fec2018-01-23 14:41:51 -0800245 {
James Feist8f2710a2018-05-09 17:18:55 -0700246 unsigned int probeValue = mapbox::util::apply_visitor(
James Feist9eb0b582018-04-27 12:15:46 -0700247 VariantToUnsignedIntVisitor(), deviceValue->second);
James Feist3cb5fec2018-01-23 14:41:51 -0800248
James Feist9eb0b582018-04-27 12:15:46 -0700249 if (probeValue != match.second.get<unsigned int>())
250 {
251 deviceMatches = false;
252 }
253 break;
James Feist3cb5fec2018-01-23 14:41:51 -0800254 }
James Feist9eb0b582018-04-27 12:15:46 -0700255 case nlohmann::json::value_t::number_integer:
256 {
James Feist8f2710a2018-05-09 17:18:55 -0700257 int probeValue = mapbox::util::apply_visitor(
James Feist9eb0b582018-04-27 12:15:46 -0700258 VariantToIntVisitor(), deviceValue->second);
James Feist3cb5fec2018-01-23 14:41:51 -0800259
James Feist9eb0b582018-04-27 12:15:46 -0700260 if (probeValue != match.second.get<int>())
261 {
262 deviceMatches = false;
263 }
264 break;
James Feist3cb5fec2018-01-23 14:41:51 -0800265 }
James Feist9eb0b582018-04-27 12:15:46 -0700266 case nlohmann::json::value_t::number_float:
267 {
James Feist8f2710a2018-05-09 17:18:55 -0700268 float probeValue = mapbox::util::apply_visitor(
James Feist9eb0b582018-04-27 12:15:46 -0700269 VariantToFloatVisitor(), deviceValue->second);
270
271 if (probeValue != match.second.get<float>())
272 {
273 deviceMatches = false;
274 }
275 break;
276 }
James Feist3cb5fec2018-01-23 14:41:51 -0800277 }
278 }
279 else
280 {
281 deviceMatches = false;
282 break;
283 }
284 }
285 if (deviceMatches)
286 {
287 devices.emplace_back(
James Feist8f2710a2018-05-09 17:18:55 -0700288 boost::container::flat_map<std::string, BasicVariantType>(
James Feist3cb5fec2018-01-23 14:41:51 -0800289 device));
290 foundMatch = true;
291 deviceMatches = false; // for next iteration
292 }
293 }
294 return foundMatch;
295}
296
297// default probe entry point, iterates a list looking for specific types to
298// call specific probe functions
299bool probe(
James Feist8f2710a2018-05-09 17:18:55 -0700300 const std::vector<std::string> &probeCommand,
301 std::vector<boost::container::flat_map<std::string, BasicVariantType>>
James Feist3cb5fec2018-01-23 14:41:51 -0800302 &foundDevs)
303{
304 const static std::regex command(R"(\((.*)\))");
305 std::smatch match;
306 bool ret = false;
James Feist6bd2a022018-03-13 12:30:58 -0700307 bool matchOne = false;
James Feist3cb5fec2018-01-23 14:41:51 -0800308 bool cur = true;
309 probe_type_codes lastCommand = probe_type_codes::FALSE_T;
310
311 for (auto &probe : probeCommand)
312 {
313 bool foundProbe = false;
314 boost::container::flat_map<const char *, probe_type_codes,
315 cmp_str>::const_iterator probeType;
316
317 for (probeType = PROBE_TYPES.begin(); probeType != PROBE_TYPES.end();
318 probeType++)
319 {
320 if (probe.find(probeType->first) != std::string::npos)
321 {
322 foundProbe = true;
323 break;
324 }
325 }
326 if (foundProbe)
327 {
328 switch (probeType->second)
329 {
James Feist9eb0b582018-04-27 12:15:46 -0700330 case probe_type_codes::FALSE_T:
James Feist3cb5fec2018-01-23 14:41:51 -0800331 {
James Feist8f2710a2018-05-09 17:18:55 -0700332 return false;
James Feist9eb0b582018-04-27 12:15:46 -0700333 break;
James Feist3cb5fec2018-01-23 14:41:51 -0800334 }
James Feist9eb0b582018-04-27 12:15:46 -0700335 case probe_type_codes::TRUE_T:
336 {
James Feist8f2710a2018-05-09 17:18:55 -0700337 return true;
James Feist9eb0b582018-04-27 12:15:46 -0700338 break;
339 }
340 case probe_type_codes::MATCH_ONE:
341 {
342 // set current value to last, this probe type shouldn't
343 // affect the outcome
344 cur = ret;
345 matchOne = true;
346 break;
347 }
348 /*case probe_type_codes::AND:
349 break;
350 case probe_type_codes::OR:
351 break;
352 // these are no-ops until the last command switch
353 */
354 case probe_type_codes::FOUND:
355 {
356 if (!std::regex_search(probe, match, command))
357 {
358 std::cerr << "found probe sytax error " << probe
359 << "\n";
360 return false;
361 }
362 std::string commandStr = *(match.begin() + 1);
363 boost::replace_all(commandStr, "'", "");
364 cur = (std::find(PASSED_PROBES.begin(), PASSED_PROBES.end(),
365 commandStr) != PASSED_PROBES.end());
366 break;
367 }
James Feist3cb5fec2018-01-23 14:41:51 -0800368 }
369 }
370 // look on dbus for object
371 else
372 {
373 if (!std::regex_search(probe, match, command))
374 {
375 std::cerr << "dbus probe sytax error " << probe << "\n";
376 return false;
377 }
378 std::string commandStr = *(match.begin() + 1);
379 // convert single ticks and single slashes into legal json
Jae Hyun Yoo3936e7a2018-03-23 17:26:16 -0700380 boost::replace_all(commandStr, "'", "\"");
James Feist3f8a2782018-02-12 09:24:42 -0800381 boost::replace_all(commandStr, R"(\)", R"(\\)");
James Feist3cb5fec2018-01-23 14:41:51 -0800382 auto json = nlohmann::json::parse(commandStr, nullptr, false);
383 if (json.is_discarded())
384 {
385 std::cerr << "dbus command sytax error " << commandStr << "\n";
386 return false;
387 }
388 // we can match any (string, variant) property. (string, string)
389 // does a regex
390 std::map<std::string, nlohmann::json> dbusProbeMap =
391 json.get<std::map<std::string, nlohmann::json>>();
392 auto findStart = probe.find("(");
393 if (findStart == std::string::npos)
394 {
395 return false;
396 }
397 std::string probeInterface = probe.substr(0, findStart);
398 cur =
399 probeDbus(probeInterface, dbusProbeMap, foundDevs, foundProbe);
400 }
401
402 // some functions like AND and OR only take affect after the
403 // fact
404 switch (lastCommand)
405 {
James Feist9eb0b582018-04-27 12:15:46 -0700406 case probe_type_codes::AND:
407 ret = cur && ret;
408 break;
409 case probe_type_codes::OR:
410 ret = cur || ret;
411 break;
412 default:
413 ret = cur;
414 break;
James Feist3cb5fec2018-01-23 14:41:51 -0800415 }
416 lastCommand = probeType != PROBE_TYPES.end()
417 ? probeType->second
418 : probe_type_codes::FALSE_T;
419
420 if (!foundProbe)
421 {
422 std::cerr << "Illegal probe type " << probe << "\n";
423 return false;
424 }
425 }
426
427 // probe passed, but empty device
James Feist3cb5fec2018-01-23 14:41:51 -0800428 if (ret && foundDevs.size() == 0)
429 {
430 foundDevs.emplace_back(
James Feist8f2710a2018-05-09 17:18:55 -0700431 boost::container::flat_map<std::string, BasicVariantType>());
James Feist3cb5fec2018-01-23 14:41:51 -0800432 }
James Feist6bd2a022018-03-13 12:30:58 -0700433 if (matchOne && foundDevs.size() > 1)
434 {
435 foundDevs.erase(foundDevs.begin() + 1, foundDevs.end());
436 }
James Feist3cb5fec2018-01-23 14:41:51 -0800437 return ret;
438}
James Feist8f2710a2018-05-09 17:18:55 -0700439// this class finds the needed dbus fields and on destruction runs the probe
440struct PerformProbe : std::enable_shared_from_this<PerformProbe>
441{
James Feist3cb5fec2018-01-23 14:41:51 -0800442
James Feist8f2710a2018-05-09 17:18:55 -0700443 PerformProbe(
444 const std::vector<std::string> &probeCommand,
445 std::function<void(std::vector<boost::container::flat_map<
446 std::string, BasicVariantType>> &)> &&callback) :
447 _probeCommand(probeCommand),
448 _callback(std::move(callback))
449 {
450 }
451 ~PerformProbe()
452 {
453 if (probe(_probeCommand, _foundDevs))
454 {
455 _callback(_foundDevs);
456 }
457 }
458 void run()
459 {
460 // parse out dbus probes by discarding other probe types
461 boost::container::flat_map<const char *, probe_type_codes,
462 cmp_str>::const_iterator probeType;
463
464 std::vector<std::string> dbusProbes;
465 for (std::string &probe : _probeCommand)
466 {
467 bool found = false;
468 boost::container::flat_map<const char *, probe_type_codes,
469 cmp_str>::const_iterator probeType;
470 for (probeType = PROBE_TYPES.begin();
471 probeType != PROBE_TYPES.end(); probeType++)
472 {
473 if (probe.find(probeType->first) != std::string::npos)
474 {
475 found = true;
476 break;
477 }
478 }
479 if (found)
480 {
481 continue;
482 }
483 // syntax requires probe before first open brace
484 auto findStart = probe.find("(");
485 std::string interface = probe.substr(0, findStart);
486
487 findDbusObjects(shared_from_this(), SYSTEM_BUS, interface);
488 }
489 }
490 std::vector<std::string> _probeCommand;
491 std::function<void(
492 std::vector<boost::container::flat_map<std::string, BasicVariantType>>
493 &)>
494 _callback;
495 std::vector<boost::container::flat_map<std::string, BasicVariantType>>
496 _foundDevs;
497};
498
499// writes output files to persist data
500void writeJsonFiles(const nlohmann::json &systemConfiguration)
James Feist1b2e2242018-01-30 13:45:19 -0800501{
502 std::experimental::filesystem::create_directory(OUTPUT_DIR);
503 std::ofstream output(std::string(OUTPUT_DIR) + "system.json");
504 output << systemConfiguration.dump(4);
505 output.close();
James Feist8f2710a2018-05-09 17:18:55 -0700506}
James Feist1b2e2242018-01-30 13:45:19 -0800507
James Feist8f2710a2018-05-09 17:18:55 -0700508// template function to add array as dbus property
509template <typename PropertyType>
510void addArrayToDbus(const std::string &name, const nlohmann::json &array,
511 sdbusplus::asio::dbus_interface *iface)
512{
513 std::vector<PropertyType> values;
514 for (const auto &property : array)
James Feist1b2e2242018-01-30 13:45:19 -0800515 {
James Feist8f2710a2018-05-09 17:18:55 -0700516 auto ptr = property.get_ptr<const PropertyType *>();
517 if (ptr != nullptr)
James Feist1b2e2242018-01-30 13:45:19 -0800518 {
James Feist8f2710a2018-05-09 17:18:55 -0700519 values.emplace_back(*ptr);
James Feist1b2e2242018-01-30 13:45:19 -0800520 }
521 }
James Feist8f2710a2018-05-09 17:18:55 -0700522 iface->register_property(name, values);
James Feist1b2e2242018-01-30 13:45:19 -0800523}
524// adds simple json types to interface's properties
James Feist8f2710a2018-05-09 17:18:55 -0700525void populateInterfaceFromJson(const nlohmann::json &systemConfiguration,
526 sdbusplus::asio::dbus_interface *iface,
527 nlohmann::json &dict,
528 sdbusplus::asio::object_server &objServer)
James Feist1b2e2242018-01-30 13:45:19 -0800529{
James Feist9eb0b582018-04-27 12:15:46 -0700530 for (auto &dictPair : dict.items())
James Feist1b2e2242018-01-30 13:45:19 -0800531 {
James Feist8f2710a2018-05-09 17:18:55 -0700532 auto type = dictPair.value().type();
533 bool array = false;
534 if (dictPair.value().type() == nlohmann::json::value_t::array)
535 {
536 array = true;
537 if (!dictPair.value().size())
538 {
539 continue;
540 }
541 type = dictPair.value()[0].type();
542 bool isLegal = true;
543 for (const auto &arrayItem : dictPair.value())
544 {
545 if (arrayItem.type() != type)
546 {
547 isLegal = false;
548 break;
549 }
550 }
551 if (!isLegal)
552 {
553 std::cerr << "dbus format error" << dictPair.value() << "\n";
554 continue;
555 }
556 if (type == nlohmann::json::value_t::object)
557 {
558 continue; // handled elsewhere
559 }
560 }
561 switch (type)
James Feist1b2e2242018-01-30 13:45:19 -0800562 {
James Feist9eb0b582018-04-27 12:15:46 -0700563 case (nlohmann::json::value_t::boolean):
564 {
James Feist8f2710a2018-05-09 17:18:55 -0700565 if (array)
566 {
567 // todo: array of bool isn't detected correctly by
568 // sdbusplus, change it to numbers
569 addArrayToDbus<uint64_t>(dictPair.key(), dictPair.value(),
570 iface);
571 break;
572 }
573 iface->register_property(
574 std::string(dictPair.key()), dictPair.value().get<bool>(),
575 [&, dictPair](const bool &newVal, bool &val) {
576 val = newVal;
577 return 1;
578 });
James Feist9eb0b582018-04-27 12:15:46 -0700579 break;
580 }
581 case (nlohmann::json::value_t::number_integer):
582 {
James Feist8f2710a2018-05-09 17:18:55 -0700583 if (array)
584 {
585 addArrayToDbus<int64_t>(dictPair.key(), dictPair.value(),
586 iface);
587 break;
588 }
589 iface->register_property(
590 std::string(dictPair.key()),
591 dictPair.value().get<int64_t>(),
592 [&, dictPair](const int64_t &newVal, int64_t &val) {
593 val = newVal;
594 return 1;
595 });
James Feist9eb0b582018-04-27 12:15:46 -0700596 break;
597 }
598 case (nlohmann::json::value_t::number_unsigned):
599 {
James Feist8f2710a2018-05-09 17:18:55 -0700600 if (array)
601 {
602 addArrayToDbus<uint64_t>(dictPair.key(), dictPair.value(),
603 iface);
604 break;
605 }
606 iface->register_property(
607 std::string(dictPair.key()),
608 dictPair.value().get<uint64_t>(),
609 [&, dictPair](const uint64_t &newVal, uint64_t &val) {
610 val = newVal;
611 return 1;
612 });
James Feist9eb0b582018-04-27 12:15:46 -0700613 break;
614 }
615 case (nlohmann::json::value_t::number_float):
616 {
James Feist8f2710a2018-05-09 17:18:55 -0700617 if (array)
618 {
619 addArrayToDbus<double>(dictPair.key(), dictPair.value(),
620 iface);
621 break;
622 }
623 iface->register_property(
624 std::string(dictPair.key()), dictPair.value().get<double>(),
625 [&, dictPair](const double &newVal, double &val) {
626 val = newVal;
627 return 1;
628 });
James Feist9eb0b582018-04-27 12:15:46 -0700629 break;
630 }
631 case (nlohmann::json::value_t::string):
632 {
James Feist8f2710a2018-05-09 17:18:55 -0700633 if (array)
634 {
635 addArrayToDbus<std::string>(dictPair.key(),
636 dictPair.value(), iface);
637 break;
638 }
639 iface->register_property(
640 std::string(dictPair.key()),
641 dictPair.value().get<std::string>(),
642 [&, dictPair](const std::string &newVal, std::string &val) {
643 val = newVal;
644 return 1;
645 });
James Feist9eb0b582018-04-27 12:15:46 -0700646 break;
647 }
James Feist1b2e2242018-01-30 13:45:19 -0800648 }
649 }
James Feist1b2e2242018-01-30 13:45:19 -0800650
James Feist8f2710a2018-05-09 17:18:55 -0700651 iface->initialize();
James Feist1b2e2242018-01-30 13:45:19 -0800652}
653
654void postToDbus(const nlohmann::json &systemConfiguration,
James Feist8f2710a2018-05-09 17:18:55 -0700655 sdbusplus::asio::object_server &objServer)
James Feist75fdeeb2018-02-20 14:26:16 -0800656
James Feist1b2e2242018-01-30 13:45:19 -0800657{
James Feist9eb0b582018-04-27 12:15:46 -0700658 for (auto &boardPair : systemConfiguration.items())
James Feist1b2e2242018-01-30 13:45:19 -0800659 {
660 std::string boardKey = boardPair.key();
661 auto boardValues = boardPair.value();
662 auto findBoardType = boardValues.find("type");
663 std::string boardType;
664 if (findBoardType != boardValues.end() &&
665 findBoardType->type() == nlohmann::json::value_t::string)
666 {
667 boardType = findBoardType->get<std::string>();
668 std::regex_replace(boardType.begin(), boardType.begin(),
669 boardType.end(), ILLEGAL_DBUS_REGEX, "_");
670 }
671 else
672 {
673 std::cerr << "Unable to find type for " << boardKey
674 << " reverting to Chassis.\n";
675 boardType = "Chassis";
676 }
James Feist11be6672018-04-06 14:05:32 -0700677 std::string boardtypeLower = boost::algorithm::to_lower_copy(boardType);
James Feist1b2e2242018-01-30 13:45:19 -0800678
679 std::regex_replace(boardKey.begin(), boardKey.begin(), boardKey.end(),
680 ILLEGAL_DBUS_REGEX, "_");
James Feist11be6672018-04-06 14:05:32 -0700681 std::string boardName = "/xyz/openbmc_project/inventory/system/" +
682 boardtypeLower + "/" + boardKey;
James Feist1b2e2242018-01-30 13:45:19 -0800683
James Feist8f2710a2018-05-09 17:18:55 -0700684 auto inventoryIface = objServer.add_interface(
685 boardName, "xyz.openbmc_project.Inventory.Item");
686 auto boardIface = objServer.add_interface(
687 boardName, "xyz.openbmc_project.Inventory.Item." + boardType);
James Feist11be6672018-04-06 14:05:32 -0700688
James Feist8f2710a2018-05-09 17:18:55 -0700689 populateInterfaceFromJson(systemConfiguration, boardIface.get(),
690 boardValues, objServer);
James Feist9eb0b582018-04-27 12:15:46 -0700691 for (auto &boardField : boardValues.items())
James Feist11be6672018-04-06 14:05:32 -0700692 {
693 if (boardField.value().type() == nlohmann::json::value_t::object)
694 {
James Feist8f2710a2018-05-09 17:18:55 -0700695 auto iface =
696 objServer.add_interface(boardName, boardField.key());
697 populateInterfaceFromJson(systemConfiguration, iface.get(),
698 boardField.value(), objServer);
James Feist11be6672018-04-06 14:05:32 -0700699 }
700 }
James Feist1b2e2242018-01-30 13:45:19 -0800701 auto exposes = boardValues.find("exposes");
702 if (exposes == boardValues.end())
703 {
704 continue;
705 }
706 for (auto &item : *exposes)
707 {
708 auto findName = item.find("name");
709 if (findName == item.end())
710 {
711 std::cerr << "cannot find name in field " << item << "\n";
712 continue;
713 }
714 auto findStatus = item.find("status");
715 // if status is not found it is assumed to be status = 'okay'
716 if (findStatus != item.end())
717 {
718 if (*findStatus == "disabled")
719 {
720 continue;
721 }
722 }
723 auto findType = item.find("type");
724 std::string itemType;
725 if (findType != item.end())
726 {
727 itemType = findType->get<std::string>();
728 std::regex_replace(itemType.begin(), itemType.begin(),
729 itemType.end(), ILLEGAL_DBUS_REGEX, "_");
730 }
731 else
732 {
733 itemType = "unknown";
734 }
735 std::string itemName = findName->get<std::string>();
736 std::regex_replace(itemName.begin(), itemName.begin(),
737 itemName.end(), ILLEGAL_DBUS_REGEX, "_");
James Feist8f2710a2018-05-09 17:18:55 -0700738 auto itemIface = objServer.add_interface(
739 boardName + "/" + itemName,
James Feist1b2e2242018-01-30 13:45:19 -0800740 "xyz.openbmc_project.Configuration." + itemType);
741
James Feist8f2710a2018-05-09 17:18:55 -0700742 populateInterfaceFromJson(systemConfiguration, itemIface.get(),
743 item, objServer);
James Feist1b2e2242018-01-30 13:45:19 -0800744
James Feist9eb0b582018-04-27 12:15:46 -0700745 for (auto &objectPair : item.items())
James Feist1b2e2242018-01-30 13:45:19 -0800746 {
747 if (objectPair.value().type() ==
748 nlohmann::json::value_t::object)
749 {
James Feist8f2710a2018-05-09 17:18:55 -0700750 auto objectIface = objServer.add_interface(
751 boardName + "/" + itemName,
James Feist1b2e2242018-01-30 13:45:19 -0800752 "xyz.openbmc_project.Configuration." + itemType + "." +
James Feist8f2710a2018-05-09 17:18:55 -0700753 objectPair.key());
754 populateInterfaceFromJson(systemConfiguration,
755 objectIface.get(),
James Feist1b2e2242018-01-30 13:45:19 -0800756 objectPair.value(), objServer);
757 }
758 else if (objectPair.value().type() ==
759 nlohmann::json::value_t::array)
760 {
761 size_t index = 0;
James Feist8f2710a2018-05-09 17:18:55 -0700762 if (!objectPair.value().size())
James Feist1b2e2242018-01-30 13:45:19 -0800763 {
James Feist8f2710a2018-05-09 17:18:55 -0700764 continue;
765 }
766 bool isLegal = true;
767 auto type = objectPair.value()[0].type();
768 if (type != nlohmann::json::value_t::object)
769 {
770 continue;
771 }
772
773 // verify legal json
774 for (const auto &arrayItem : objectPair.value())
775 {
776 if (arrayItem.type() != type)
James Feist1b2e2242018-01-30 13:45:19 -0800777 {
James Feist8f2710a2018-05-09 17:18:55 -0700778 isLegal = false;
James Feist1b2e2242018-01-30 13:45:19 -0800779 break;
780 }
James Feist8f2710a2018-05-09 17:18:55 -0700781 }
782 if (!isLegal)
783 {
784 std::cerr << "dbus format error" << objectPair.value()
785 << "\n";
786 break;
787 }
788
789 for (auto &arrayItem : objectPair.value())
790 {
791 auto objectIface = objServer.add_interface(
792 boardName + "/" + itemName,
James Feist1b2e2242018-01-30 13:45:19 -0800793 "xyz.openbmc_project.Configuration." + itemType +
James Feist8f2710a2018-05-09 17:18:55 -0700794 "." + objectPair.key() + "." +
795 std::to_string(index++));
796 populateInterfaceFromJson(systemConfiguration,
797 objectIface.get(), arrayItem,
James Feist1b2e2242018-01-30 13:45:19 -0800798 objServer);
799 }
800 }
801 }
802 }
803 }
804}
805
806// finds the template character (currently set to $) and replaces the value with
807// the field found in a dbus object i.e. $ADDRESS would get populated with the
808// ADDRESS field from a object on dbus
809void templateCharReplace(
810 nlohmann::json::iterator &keyPair,
James Feist8f2710a2018-05-09 17:18:55 -0700811 const boost::container::flat_map<std::string, BasicVariantType>
James Feist1b2e2242018-01-30 13:45:19 -0800812 &foundDevice,
813 size_t &foundDeviceIdx)
814{
James Feist11be6672018-04-06 14:05:32 -0700815 if (keyPair.value().type() == nlohmann::json::value_t::object)
816 {
817 for (auto nextLayer = keyPair.value().begin();
818 nextLayer != keyPair.value().end(); nextLayer++)
819 {
820 templateCharReplace(nextLayer, foundDevice, foundDeviceIdx);
821 }
822 return;
823 }
824 else if (keyPair.value().type() != nlohmann::json::value_t::string)
James Feist1b2e2242018-01-30 13:45:19 -0800825 {
826 return;
827 }
828
829 std::string value = keyPair.value();
830 if (value.find(TEMPLATE_CHAR) != std::string::npos)
831 {
832 std::string templateValue = value;
833
834 templateValue.erase(0, 1); // remove template character
835
836 // special case index
837 if ("index" == templateValue)
838 {
839 keyPair.value() = foundDeviceIdx;
840 }
841 else
842 {
James Feist13b86d62018-05-29 11:24:35 -0700843 bool found = false;
James Feist1b2e2242018-01-30 13:45:19 -0800844 for (auto &foundDevicePair : foundDevice)
845 {
846 if (boost::iequals(foundDevicePair.first, templateValue))
847 {
James Feist13b86d62018-05-29 11:24:35 -0700848 mapbox::util::apply_visitor(
849 [&](auto &&val) { keyPair.value() = val; },
850 foundDevicePair.second);
851 found = true;
James Feist1b2e2242018-01-30 13:45:19 -0800852 break;
853 }
854 }
James Feist13b86d62018-05-29 11:24:35 -0700855 if (!found)
James Feist1b2e2242018-01-30 13:45:19 -0800856 {
857 std::cerr << "could not find symbol " << templateValue << "\n";
858 }
James Feist1b2e2242018-01-30 13:45:19 -0800859 }
860 }
861}
862
James Feist8f2710a2018-05-09 17:18:55 -0700863// reads json files out of the filesystem
864bool findJsonFiles(std::list<nlohmann::json> &configurations)
James Feist3cb5fec2018-01-23 14:41:51 -0800865{
866 // find configuration files
867 std::vector<fs::path> jsonPaths;
868 if (!find_files(fs::path(CONFIGURATION_DIR), R"(.*\.json)", jsonPaths, 0))
869 {
870 std::cerr << "Unable to find any configuration files in "
871 << CONFIGURATION_DIR << "\n";
James Feist75fdeeb2018-02-20 14:26:16 -0800872 return false;
James Feist3cb5fec2018-01-23 14:41:51 -0800873 }
James Feist3cb5fec2018-01-23 14:41:51 -0800874 for (auto &jsonPath : jsonPaths)
875 {
876 std::ifstream jsonStream(jsonPath.c_str());
877 if (!jsonStream.good())
878 {
879 std::cerr << "unable to open " << jsonPath.string() << "\n";
880 continue;
881 }
882 auto data = nlohmann::json::parse(jsonStream, nullptr, false);
883 if (data.is_discarded())
884 {
885 std::cerr << "syntax error in " << jsonPath.string() << "\n";
886 continue;
887 }
888 if (data.type() == nlohmann::json::value_t::array)
889 {
890 for (auto &d : data)
891 {
892 configurations.emplace_back(d);
893 }
894 }
895 else
896 {
897 configurations.emplace_back(data);
898 }
899 }
James Feist75fdeeb2018-02-20 14:26:16 -0800900}
James Feist3cb5fec2018-01-23 14:41:51 -0800901
James Feist8f2710a2018-05-09 17:18:55 -0700902struct PerformScan : std::enable_shared_from_this<PerformScan>
James Feist75fdeeb2018-02-20 14:26:16 -0800903{
James Feist75fdeeb2018-02-20 14:26:16 -0800904
James Feist8f2710a2018-05-09 17:18:55 -0700905 PerformScan(nlohmann::json &systemConfiguration,
906 std::list<nlohmann::json> &configurations,
907 std::function<void(void)> &&callback) :
908 _systemConfiguration(systemConfiguration),
909 _configurations(configurations), _callback(std::move(callback))
James Feist3cb5fec2018-01-23 14:41:51 -0800910 {
James Feist8f2710a2018-05-09 17:18:55 -0700911 }
912 void run()
913 {
914 for (auto it = _configurations.begin(); it != _configurations.end();)
James Feist3cb5fec2018-01-23 14:41:51 -0800915 {
James Feist1b2e2242018-01-30 13:45:19 -0800916 auto findProbe = it->find("probe");
917 auto findName = it->find("name");
James Feist3cb5fec2018-01-23 14:41:51 -0800918
James Feist1b2e2242018-01-30 13:45:19 -0800919 nlohmann::json probeCommand;
920 // check for poorly formatted fields, probe must be an array
921 if (findProbe == it->end())
James Feist3cb5fec2018-01-23 14:41:51 -0800922 {
923 std::cerr << "configuration file missing probe:\n " << *it
924 << "\n";
James Feist8f2710a2018-05-09 17:18:55 -0700925 it = _configurations.erase(it);
926 continue;
James Feist3cb5fec2018-01-23 14:41:51 -0800927 }
James Feist1b2e2242018-01-30 13:45:19 -0800928 else if ((*findProbe).type() != nlohmann::json::value_t::array)
James Feist3cb5fec2018-01-23 14:41:51 -0800929 {
930 probeCommand = nlohmann::json::array();
931 probeCommand.push_back(*findProbe);
932 }
933 else
934 {
935 probeCommand = *findProbe;
936 }
James Feist1b2e2242018-01-30 13:45:19 -0800937
938 if (findName == it->end())
939 {
940 std::cerr << "configuration file missing name:\n " << *it
941 << "\n";
James Feist8f2710a2018-05-09 17:18:55 -0700942 it = _configurations.erase(it);
943 continue;
James Feist1b2e2242018-01-30 13:45:19 -0800944 }
James Feist8f2710a2018-05-09 17:18:55 -0700945 std::string name = *findName;
James Feist1b2e2242018-01-30 13:45:19 -0800946
James Feist8f2710a2018-05-09 17:18:55 -0700947 if (std::find(PASSED_PROBES.begin(), PASSED_PROBES.end(), name) !=
948 PASSED_PROBES.end())
James Feist3cb5fec2018-01-23 14:41:51 -0800949 {
James Feist8f2710a2018-05-09 17:18:55 -0700950 it = _configurations.erase(it);
951 continue;
952 }
953 nlohmann::json *record = &(*it);
James Feist3cb5fec2018-01-23 14:41:51 -0800954
James Feist8f2710a2018-05-09 17:18:55 -0700955 // store reference to this to children to makes sure we don't get
956 // destroyed too early
957 auto thisRef = shared_from_this();
958 auto p = std::make_shared<PerformProbe>(
959 probeCommand,
960 [&, record, name,
961 thisRef](std::vector<boost::container::flat_map<
962 std::string, BasicVariantType>> &foundDevices) {
963 _passed = true;
James Feist3cb5fec2018-01-23 14:41:51 -0800964
James Feist8f2710a2018-05-09 17:18:55 -0700965 PASSED_PROBES.push_back(name);
966 size_t foundDeviceIdx = 0;
967
968 for (auto &foundDevice : foundDevices)
James Feist3cb5fec2018-01-23 14:41:51 -0800969 {
James Feist8f2710a2018-05-09 17:18:55 -0700970 for (auto keyPair = record->begin();
971 keyPair != record->end(); keyPair++)
James Feist3cb5fec2018-01-23 14:41:51 -0800972 {
James Feist1b2e2242018-01-30 13:45:19 -0800973 templateCharReplace(keyPair, foundDevice,
974 foundDeviceIdx);
James Feist8f2710a2018-05-09 17:18:55 -0700975 }
976 auto findExpose = record->find("exposes");
977 if (findExpose == record->end())
978 {
979 continue;
980 }
981 for (auto &expose : *findExpose)
982 {
983 for (auto keyPair = expose.begin();
984 keyPair != expose.end(); keyPair++)
James Feist3cb5fec2018-01-23 14:41:51 -0800985 {
James Feist1b2e2242018-01-30 13:45:19 -0800986
James Feist8f2710a2018-05-09 17:18:55 -0700987 // fill in template characters with devices
988 // found
989 templateCharReplace(keyPair, foundDevice,
990 foundDeviceIdx);
991 // special case bind
992 if (boost::starts_with(keyPair.key(), "bind_"))
993 {
994 if (keyPair.value().type() !=
995 nlohmann::json::value_t::string)
James Feist3cb5fec2018-01-23 14:41:51 -0800996 {
James Feist8f2710a2018-05-09 17:18:55 -0700997 std::cerr << "bind_ value must be of "
998 "type string "
999 << keyPair.key() << "\n";
James Feist1b2e2242018-01-30 13:45:19 -08001000 continue;
1001 }
James Feist8f2710a2018-05-09 17:18:55 -07001002 bool foundBind = false;
1003 std::string bind = keyPair.key().substr(
1004 sizeof("bind_") - 1);
1005 for (auto &configurationPair :
1006 _systemConfiguration.items())
James Feist1b2e2242018-01-30 13:45:19 -08001007 {
James Feist1b2e2242018-01-30 13:45:19 -08001008
James Feist8f2710a2018-05-09 17:18:55 -07001009 auto configListFind =
1010 configurationPair.value().find(
1011 "exposes");
1012
1013 if (configListFind ==
1014 configurationPair.value()
1015 .end() ||
1016 configListFind->type() !=
1017 nlohmann::json::value_t::array)
1018 {
1019 continue;
1020 }
1021 for (auto &exposedObject :
1022 *configListFind)
1023 {
1024 std::string foundObjectName =
1025 (exposedObject)["name"];
1026 if (boost::iequals(
1027 foundObjectName,
1028 keyPair.value()
1029 .get<std::string>()))
1030 {
1031 exposedObject["status"] =
1032 "okay";
1033 expose[bind] = exposedObject;
1034
1035 foundBind = true;
1036 break;
1037 }
1038 }
1039 if (foundBind)
1040 {
James Feist3cb5fec2018-01-23 14:41:51 -08001041 break;
1042 }
1043 }
James Feist8f2710a2018-05-09 17:18:55 -07001044 if (!foundBind)
James Feist3cb5fec2018-01-23 14:41:51 -08001045 {
James Feist8f2710a2018-05-09 17:18:55 -07001046 std::cerr << "configuration file "
1047 "dependency error, "
1048 "could not find bind "
1049 << keyPair.value() << "\n";
James Feist3cb5fec2018-01-23 14:41:51 -08001050 }
1051 }
1052 }
1053 }
1054 }
James Feist8f2710a2018-05-09 17:18:55 -07001055 _systemConfiguration[name] = *record;
1056 });
1057 p->run();
1058 it++;
James Feist3cb5fec2018-01-23 14:41:51 -08001059 }
1060 }
James Feist75fdeeb2018-02-20 14:26:16 -08001061
James Feist8f2710a2018-05-09 17:18:55 -07001062 ~PerformScan()
James Feist75fdeeb2018-02-20 14:26:16 -08001063 {
James Feist8f2710a2018-05-09 17:18:55 -07001064 if (_passed)
1065 {
1066 auto nextScan = std::make_shared<PerformScan>(
1067 _systemConfiguration, _configurations, std::move(_callback));
1068 nextScan->run();
1069 }
1070 else
1071 {
1072 _callback();
1073 }
1074 }
1075 nlohmann::json &_systemConfiguration;
1076 std::list<nlohmann::json> _configurations;
1077 std::function<void(void)> _callback;
1078 std::vector<std::shared_ptr<PerformProbe>> _probes;
1079 bool _passed = false;
1080};
James Feistc95cb142018-02-26 10:41:42 -08001081
James Feist8f2710a2018-05-09 17:18:55 -07001082// main properties changed entry
1083void propertiesChangedCallback(
1084 boost::asio::io_service &io,
1085 std::vector<sdbusplus::bus::match::match> &dbusMatches,
1086 nlohmann::json &systemConfiguration,
1087 sdbusplus::asio::object_server &objServer)
1088{
1089 static boost::asio::deadline_timer timer(io);
1090 timer.expires_from_now(boost::posix_time::seconds(1));
1091
1092 // setup an async wait as we normally get flooded with new requests
1093 timer.async_wait([&](const boost::system::error_code &ec) {
1094
1095 if (ec == boost::asio::error::operation_aborted)
1096 {
1097 // we were cancelled
1098 return;
1099 }
1100 else if (ec)
1101 {
1102 std::cerr << "async wait error " << ec << "\n";
1103 return;
1104 }
1105
1106 nlohmann::json oldConfiguration = systemConfiguration;
1107 DBUS_PROBE_OBJECTS.clear();
1108
1109 std::list<nlohmann::json> configurations;
1110 if (!findJsonFiles(configurations))
1111 {
1112 std::cerr << "cannot find json files\n";
1113 return;
1114 }
1115
1116 auto perfScan = std::make_shared<PerformScan>(
1117 systemConfiguration, configurations, [&, oldConfiguration]() {
1118 nlohmann::json newConfiguration = systemConfiguration;
James Feist4131aea2018-03-09 09:47:30 -08001119 for (auto it = newConfiguration.begin();
1120 it != newConfiguration.end();)
1121 {
1122 auto findKey = oldConfiguration.find(it.key());
1123 if (findKey != oldConfiguration.end())
1124 {
1125 it = newConfiguration.erase(it);
1126 }
1127 else
1128 {
1129 it++;
1130 }
1131 }
James Feist8f2710a2018-05-09 17:18:55 -07001132 registerCallbacks(io, dbusMatches, systemConfiguration,
1133 objServer);
1134 io.post([&, newConfiguration]() {
1135 // todo: for now, only add new configurations,
1136 // unload to come later unloadOverlays();
1137 loadOverlays(newConfiguration);
1138 io.post([&]() { writeJsonFiles(systemConfiguration); });
1139 io.post([&, newConfiguration]() {
1140 postToDbus(newConfiguration, objServer);
1141 });
1142 });
1143 });
1144 perfScan->run();
1145 });
James Feist75fdeeb2018-02-20 14:26:16 -08001146}
1147
James Feist8f2710a2018-05-09 17:18:55 -07001148void registerCallbacks(boost::asio::io_service &io,
1149 std::vector<sdbusplus::bus::match::match> &dbusMatches,
1150 nlohmann::json &systemConfiguration,
1151 sdbusplus::asio::object_server &objServer)
James Feist75fdeeb2018-02-20 14:26:16 -08001152{
1153 static boost::container::flat_set<std::string> watchedObjects;
1154
1155 for (const auto &objectMap : DBUS_PROBE_OBJECTS)
1156 {
1157 auto findObject = watchedObjects.find(objectMap.first);
1158 if (findObject != watchedObjects.end())
1159 {
1160 continue;
1161 }
James Feist8f2710a2018-05-09 17:18:55 -07001162 std::function<void(sdbusplus::message::message & message)>
1163 eventHandler =
James Feist75fdeeb2018-02-20 14:26:16 -08001164
James Feist8f2710a2018-05-09 17:18:55 -07001165 [&](sdbusplus::message::message &) {
1166 propertiesChangedCallback(io, dbusMatches,
1167 systemConfiguration, objServer);
1168 };
1169
1170 sdbusplus::bus::match::match match(
1171 static_cast<sdbusplus::bus::bus &>(*SYSTEM_BUS),
1172 "type='signal',member='PropertiesChanged',arg0='" +
1173 objectMap.first + "'",
1174 eventHandler);
1175 dbusMatches.emplace_back(std::move(match));
James Feist75fdeeb2018-02-20 14:26:16 -08001176 }
1177}
1178
1179int main(int argc, char **argv)
1180{
1181 // setup connection to dbus
1182 boost::asio::io_service io;
James Feist8f2710a2018-05-09 17:18:55 -07001183 SYSTEM_BUS = std::make_shared<sdbusplus::asio::connection>(io);
James Feist75fdeeb2018-02-20 14:26:16 -08001184 SYSTEM_BUS->request_name("xyz.openbmc_project.EntityManager");
James Feist4131aea2018-03-09 09:47:30 -08001185
James Feist8f2710a2018-05-09 17:18:55 -07001186 sdbusplus::asio::object_server objServer(SYSTEM_BUS);
James Feistfd1264a2018-05-03 12:10:00 -07001187
James Feist8f2710a2018-05-09 17:18:55 -07001188 std::shared_ptr<sdbusplus::asio::dbus_interface> entityIface =
1189 objServer.add_interface("/xyz/openbmc_project/EntityManager",
1190 "xyz.openbmc_project.EntityManager");
James Feistfd1264a2018-05-03 12:10:00 -07001191
James Feist8f2710a2018-05-09 17:18:55 -07001192 std::shared_ptr<sdbusplus::asio::dbus_interface> inventoryIface =
1193 objServer.add_interface("/xyz/openbmc_project/inventory",
1194 "xyz.openbmc_project.Inventory.Manager");
James Feist4131aea2018-03-09 09:47:30 -08001195
1196 // to keep reference to the match / filter objects so they don't get
1197 // destroyed
James Feist8f2710a2018-05-09 17:18:55 -07001198 std::vector<sdbusplus::bus::match::match> dbusMatches;
1199
1200 nlohmann::json systemConfiguration = nlohmann::json::object();
1201
1202 inventoryIface->register_method(
1203 "Notify", [](const boost::container::flat_map<
1204 std::string,
1205 boost::container::flat_map<std::string, BasicVariantType>>
1206 &object) { return; });
1207 inventoryIface->initialize();
1208
1209 io.post([&]() {
1210 unloadAllOverlays();
1211 propertiesChangedCallback(io, dbusMatches, systemConfiguration,
1212 objServer);
1213 });
James Feist4131aea2018-03-09 09:47:30 -08001214
James Feistfd1264a2018-05-03 12:10:00 -07001215 entityIface->register_method("ReScan", [&]() {
James Feist8f2710a2018-05-09 17:18:55 -07001216 propertiesChangedCallback(io, dbusMatches, systemConfiguration,
1217 objServer);
James Feist75fdeeb2018-02-20 14:26:16 -08001218 });
James Feist8f2710a2018-05-09 17:18:55 -07001219 entityIface->initialize();
1220
1221 objServer.add_manager("/xyz/openbmc_project/inventory");
James Feist75fdeeb2018-02-20 14:26:16 -08001222
James Feist1b2e2242018-01-30 13:45:19 -08001223 io.run();
James Feist3cb5fec2018-01-23 14:41:51 -08001224
1225 return 0;
James Feist75fdeeb2018-02-20 14:26:16 -08001226}