blob: 94708b84a37207565dd126ba561adfea9ff0f2ea [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
James Feista465ccc2019-02-08 12:51:01 -080017#include "filesystem.hpp"
18
James Feistc95cb142018-02-26 10:41:42 -080019#include <Overlay.hpp>
James Feista465ccc2019-02-08 12:51:01 -080020#include <Utils.hpp>
21#include <VariantVisitors.hpp>
James Feist11be6672018-04-06 14:05:32 -070022#include <boost/algorithm/string/case_conv.hpp>
James Feist3cb5fec2018-01-23 14:41:51 -080023#include <boost/algorithm/string/predicate.hpp>
24#include <boost/algorithm/string/replace.hpp>
James Feist3cb5fec2018-01-23 14:41:51 -080025#include <boost/container/flat_map.hpp>
26#include <boost/container/flat_set.hpp>
James Feista465ccc2019-02-08 12:51:01 -080027#include <boost/lexical_cast.hpp>
28#include <fstream>
29#include <iostream>
30#include <nlohmann/json.hpp>
31#include <regex>
32#include <sdbusplus/asio/connection.hpp>
33#include <sdbusplus/asio/object_server.hpp>
34#include <variant>
James Feist3cb5fec2018-01-23 14:41:51 -080035
James Feista465ccc2019-02-08 12:51:01 -080036constexpr const char* OUTPUT_DIR = "/var/configuration/";
37constexpr const char* configurationDirectory = PACKAGE_DIR "configurations";
38constexpr const char* schemaDirectory = PACKAGE_DIR "configurations/schemas";
39constexpr const char* globalSchema = "global.json";
40constexpr const char* TEMPLATE_CHAR = "$";
James Feistc95cb142018-02-26 10:41:42 -080041constexpr const size_t PROPERTIES_CHANGED_UNTIL_FLUSH_COUNT = 20;
James Feist8f2710a2018-05-09 17:18:55 -070042constexpr const int32_t MAX_MAPPER_DEPTH = 0;
James Feist4131aea2018-03-09 09:47:30 -080043constexpr const size_t SLEEP_AFTER_PROPERTIES_CHANGE_SECONDS = 5;
James Feist3cb5fec2018-01-23 14:41:51 -080044
James Feist3cb5fec2018-01-23 14:41:51 -080045struct cmp_str
46{
James Feista465ccc2019-02-08 12:51:01 -080047 bool operator()(const char* a, const char* b) const
James Feist3cb5fec2018-01-23 14:41:51 -080048 {
49 return std::strcmp(a, b) < 0;
50 }
51};
52
James Feist8f2710a2018-05-09 17:18:55 -070053struct PerformProbe;
54
James Feist3cb5fec2018-01-23 14:41:51 -080055// underscore T for collison with dbus c api
56enum class probe_type_codes
57{
58 FALSE_T,
59 TRUE_T,
60 AND,
61 OR,
James Feist6bd2a022018-03-13 12:30:58 -070062 FOUND,
63 MATCH_ONE
James Feist3cb5fec2018-01-23 14:41:51 -080064};
James Feista465ccc2019-02-08 12:51:01 -080065const static boost::container::flat_map<const char*, probe_type_codes, cmp_str>
James Feist3cb5fec2018-01-23 14:41:51 -080066 PROBE_TYPES{{{"FALSE", probe_type_codes::FALSE_T},
67 {"TRUE", probe_type_codes::TRUE_T},
68 {"AND", probe_type_codes::AND},
69 {"OR", probe_type_codes::OR},
James Feist6bd2a022018-03-13 12:30:58 -070070 {"FOUND", probe_type_codes::FOUND},
71 {"MATCH_ONE", probe_type_codes::MATCH_ONE}}};
James Feist3cb5fec2018-01-23 14:41:51 -080072
James Feista465ccc2019-02-08 12:51:01 -080073static constexpr std::array<const char*, 4> settableInterfaces = {
James Feist3cab7872018-12-11 15:20:00 -080074 "Thresholds", "Pid", "Pid.Zone", "Stepwise"};
James Feist68500ff2018-08-08 15:40:42 -070075using JsonVariantType =
James Feista465ccc2019-02-08 12:51:01 -080076 std::variant<std::vector<std::string>, std::string, int64_t, uint64_t,
77 double, int32_t, uint32_t, int16_t, uint16_t, uint8_t, bool>;
James Feist8f2710a2018-05-09 17:18:55 -070078using BasicVariantType =
James Feista465ccc2019-02-08 12:51:01 -080079 std::variant<std::string, int64_t, uint64_t, double, int32_t, uint32_t,
80 int16_t, uint16_t, uint8_t, bool>;
James Feist8f2710a2018-05-09 17:18:55 -070081
James Feist3cb5fec2018-01-23 14:41:51 -080082using GetSubTreeType = std::vector<
83 std::pair<std::string,
84 std::vector<std::pair<std::string, std::vector<std::string>>>>>;
85
86using ManagedObjectType = boost::container::flat_map<
James Feist8f2710a2018-05-09 17:18:55 -070087 sdbusplus::message::object_path,
James Feist3cb5fec2018-01-23 14:41:51 -080088 boost::container::flat_map<
89 std::string,
James Feist8f2710a2018-05-09 17:18:55 -070090 boost::container::flat_map<std::string, BasicVariantType>>>;
James Feist3cb5fec2018-01-23 14:41:51 -080091
92boost::container::flat_map<
93 std::string,
James Feist8f2710a2018-05-09 17:18:55 -070094 std::vector<boost::container::flat_map<std::string, BasicVariantType>>>
James Feist3cb5fec2018-01-23 14:41:51 -080095 DBUS_PROBE_OBJECTS;
96std::vector<std::string> PASSED_PROBES;
97
98// todo: pass this through nicer
James Feist8f2710a2018-05-09 17:18:55 -070099std::shared_ptr<sdbusplus::asio::connection> SYSTEM_BUS;
James Feist3cb5fec2018-01-23 14:41:51 -0800100
James Feista6750242018-07-16 14:12:27 -0700101const std::regex ILLEGAL_DBUS_REGEX("[^A-Za-z0-9_.]");
James Feist1b2e2242018-01-30 13:45:19 -0800102
James Feista465ccc2019-02-08 12:51:01 -0800103void registerCallbacks(boost::asio::io_service& io,
104 std::vector<sdbusplus::bus::match::match>& dbusMatches,
105 nlohmann::json& systemConfiguration,
106 sdbusplus::asio::object_server& objServer);
James Feist75fdeeb2018-02-20 14:26:16 -0800107
James Feist3cb5fec2018-01-23 14:41:51 -0800108// calls the mapper to find all exposed objects of an interface type
109// and creates a vector<flat_map> that contains all the key value pairs
110// getManagedObjects
James Feist8f2710a2018-05-09 17:18:55 -0700111void findDbusObjects(std::shared_ptr<PerformProbe> probe,
112 std::shared_ptr<sdbusplus::asio::connection> connection,
James Feista465ccc2019-02-08 12:51:01 -0800113 std::string& interface)
James Feist3cb5fec2018-01-23 14:41:51 -0800114{
James Feist8f2710a2018-05-09 17:18:55 -0700115
116 // store reference to pending callbacks so we don't overwhelm services
117 static boost::container::flat_map<
118 std::string, std::vector<std::shared_ptr<PerformProbe>>>
119 pendingProbes;
120
121 if (DBUS_PROBE_OBJECTS[interface].size())
122 {
123 return;
124 }
125
126 // add shared_ptr to vector of Probes waiting for callback from a specific
127 // interface to keep alive while waiting for response
James Feista465ccc2019-02-08 12:51:01 -0800128 std::array<const char*, 1> objects = {interface.c_str()};
129 std::vector<std::shared_ptr<PerformProbe>>& pending =
James Feist8f2710a2018-05-09 17:18:55 -0700130 pendingProbes[interface];
131 auto iter = pending.emplace(pending.end(), probe);
132 // only allow first call to run to not overwhelm processes
133 if (iter != pending.begin())
134 {
135 return;
136 }
137
James Feist3cb5fec2018-01-23 14:41:51 -0800138 // find all connections in the mapper that expose a specific type
James Feist8f2710a2018-05-09 17:18:55 -0700139 connection->async_method_call(
James Feista465ccc2019-02-08 12:51:01 -0800140 [connection, interface, probe](boost::system::error_code& ec,
141 const GetSubTreeType& interfaceSubtree) {
James Feist0de40152018-07-25 11:56:12 -0700142 boost::container::flat_set<std::string> interfaceConnections;
James Feist8f2710a2018-05-09 17:18:55 -0700143 if (ec)
James Feist494155a2018-03-14 16:23:24 -0700144 {
James Feist0de40152018-07-25 11:56:12 -0700145 pendingProbes[interface].clear();
146 if (ec.value() == ENOENT)
James Feist8f2710a2018-05-09 17:18:55 -0700147 {
James Feist0de40152018-07-25 11:56:12 -0700148 return; // wasn't found by mapper
James Feist8f2710a2018-05-09 17:18:55 -0700149 }
James Feist0de40152018-07-25 11:56:12 -0700150 std::cerr << "Error communicating to mapper.\n";
151
152 // if we can't communicate to the mapper something is very wrong
153 std::exit(EXIT_FAILURE);
James Feist494155a2018-03-14 16:23:24 -0700154 }
James Feist8f2710a2018-05-09 17:18:55 -0700155 else
James Feist3cb5fec2018-01-23 14:41:51 -0800156 {
James Feista465ccc2019-02-08 12:51:01 -0800157 for (auto& object : interfaceSubtree)
James Feist8f2710a2018-05-09 17:18:55 -0700158 {
James Feista465ccc2019-02-08 12:51:01 -0800159 for (auto& connPair : object.second)
James Feist8f2710a2018-05-09 17:18:55 -0700160 {
161 auto insertPair =
162 interfaceConnections.insert(connPair.first);
163 }
164 }
James Feist3cb5fec2018-01-23 14:41:51 -0800165 }
James Feist63845bf2019-01-24 12:19:51 -0800166 if (interfaceConnections.empty())
167 {
168 pendingProbes[interface].clear();
169 return;
170 }
James Feist8f2710a2018-05-09 17:18:55 -0700171 // get managed objects for all interfaces
James Feista465ccc2019-02-08 12:51:01 -0800172 for (const auto& conn : interfaceConnections)
James Feist8f2710a2018-05-09 17:18:55 -0700173 {
174 connection->async_method_call(
James Feist0de40152018-07-25 11:56:12 -0700175 [conn,
James Feista465ccc2019-02-08 12:51:01 -0800176 interface](boost::system::error_code& ec,
177 const ManagedObjectType& managedInterface) {
James Feist8f2710a2018-05-09 17:18:55 -0700178 if (ec)
179 {
180 std::cerr
181 << "error getting managed object for device "
182 << conn << "\n";
183 pendingProbes[interface].clear();
184 return;
185 }
James Feista465ccc2019-02-08 12:51:01 -0800186 for (auto& interfaceManagedObj : managedInterface)
James Feist8f2710a2018-05-09 17:18:55 -0700187 {
188 auto ifaceObjFind =
189 interfaceManagedObj.second.find(interface);
190 if (ifaceObjFind !=
191 interfaceManagedObj.second.end())
192 {
193 std::vector<boost::container::flat_map<
James Feista465ccc2019-02-08 12:51:01 -0800194 std::string, BasicVariantType>>&
195 dbusObject = DBUS_PROBE_OBJECTS[interface];
James Feist8f2710a2018-05-09 17:18:55 -0700196 dbusObject.emplace_back(ifaceObjFind->second);
197 }
198 }
199 pendingProbes[interface].clear();
200 },
201 conn.c_str(), "/", "org.freedesktop.DBus.ObjectManager",
202 "GetManagedObjects");
203 }
204 },
205 "xyz.openbmc_project.ObjectMapper",
206 "/xyz/openbmc_project/object_mapper",
James Feist5131ac22018-10-25 12:22:23 -0700207 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", MAX_MAPPER_DEPTH,
James Feist8f2710a2018-05-09 17:18:55 -0700208 objects);
James Feist3cb5fec2018-01-23 14:41:51 -0800209}
James Feist8f2710a2018-05-09 17:18:55 -0700210// probes dbus interface dictionary for a key with a value that matches a regex
James Feist3cb5fec2018-01-23 14:41:51 -0800211bool probeDbus(
James Feista465ccc2019-02-08 12:51:01 -0800212 const std::string& interface,
213 const std::map<std::string, nlohmann::json>& matches,
214 std::vector<boost::container::flat_map<std::string, BasicVariantType>>&
215 devices,
216 bool& foundProbe)
James Feist3cb5fec2018-01-23 14:41:51 -0800217{
James Feista465ccc2019-02-08 12:51:01 -0800218 std::vector<boost::container::flat_map<std::string, BasicVariantType>>&
219 dbusObject = DBUS_PROBE_OBJECTS[interface];
James Feist3cb5fec2018-01-23 14:41:51 -0800220 if (dbusObject.empty())
221 {
James Feist8f2710a2018-05-09 17:18:55 -0700222 foundProbe = false;
223 return false;
James Feist3cb5fec2018-01-23 14:41:51 -0800224 }
225 foundProbe = true;
226
227 bool foundMatch = false;
James Feista465ccc2019-02-08 12:51:01 -0800228 for (auto& device : dbusObject)
James Feist3cb5fec2018-01-23 14:41:51 -0800229 {
230 bool deviceMatches = true;
James Feista465ccc2019-02-08 12:51:01 -0800231 for (auto& match : matches)
James Feist3cb5fec2018-01-23 14:41:51 -0800232 {
233 auto deviceValue = device.find(match.first);
234 if (deviceValue != device.end())
235 {
236 switch (match.second.type())
237 {
James Feist9eb0b582018-04-27 12:15:46 -0700238 case nlohmann::json::value_t::string:
James Feist3cb5fec2018-01-23 14:41:51 -0800239 {
James Feist9eb0b582018-04-27 12:15:46 -0700240 std::regex search(match.second.get<std::string>());
241 std::smatch match;
242
243 // convert value to string respresentation
James Feista465ccc2019-02-08 12:51:01 -0800244 std::string probeValue = std::visit(
James Feist8f2710a2018-05-09 17:18:55 -0700245 VariantToStringVisitor(), deviceValue->second);
James Feist9eb0b582018-04-27 12:15:46 -0700246 if (!std::regex_search(probeValue, match, search))
247 {
248 deviceMatches = false;
249 break;
250 }
James Feist3cb5fec2018-01-23 14:41:51 -0800251 break;
252 }
James Feist9eb0b582018-04-27 12:15:46 -0700253 case nlohmann::json::value_t::boolean:
254 case nlohmann::json::value_t::number_unsigned:
James Feist3cb5fec2018-01-23 14:41:51 -0800255 {
James Feista465ccc2019-02-08 12:51:01 -0800256 unsigned int probeValue = std::visit(
James Feist9eb0b582018-04-27 12:15:46 -0700257 VariantToUnsignedIntVisitor(), deviceValue->second);
James Feist3cb5fec2018-01-23 14:41:51 -0800258
James Feist9eb0b582018-04-27 12:15:46 -0700259 if (probeValue != match.second.get<unsigned int>())
260 {
261 deviceMatches = false;
262 }
263 break;
James Feist3cb5fec2018-01-23 14:41:51 -0800264 }
James Feist9eb0b582018-04-27 12:15:46 -0700265 case nlohmann::json::value_t::number_integer:
266 {
James Feista465ccc2019-02-08 12:51:01 -0800267 int probeValue = std::visit(VariantToIntVisitor(),
268 deviceValue->second);
James Feist3cb5fec2018-01-23 14:41:51 -0800269
James Feist9eb0b582018-04-27 12:15:46 -0700270 if (probeValue != match.second.get<int>())
271 {
272 deviceMatches = false;
273 }
274 break;
James Feist3cb5fec2018-01-23 14:41:51 -0800275 }
James Feist9eb0b582018-04-27 12:15:46 -0700276 case nlohmann::json::value_t::number_float:
277 {
James Feista465ccc2019-02-08 12:51:01 -0800278 float probeValue = std::visit(VariantToFloatVisitor(),
279 deviceValue->second);
James Feist9eb0b582018-04-27 12:15:46 -0700280
281 if (probeValue != match.second.get<float>())
282 {
283 deviceMatches = false;
284 }
285 break;
286 }
James Feist3cb5fec2018-01-23 14:41:51 -0800287 }
288 }
289 else
290 {
291 deviceMatches = false;
292 break;
293 }
294 }
295 if (deviceMatches)
296 {
297 devices.emplace_back(
James Feist8f2710a2018-05-09 17:18:55 -0700298 boost::container::flat_map<std::string, BasicVariantType>(
James Feist3cb5fec2018-01-23 14:41:51 -0800299 device));
300 foundMatch = true;
301 deviceMatches = false; // for next iteration
302 }
303 }
304 return foundMatch;
305}
306
307// default probe entry point, iterates a list looking for specific types to
308// call specific probe functions
309bool probe(
James Feista465ccc2019-02-08 12:51:01 -0800310 const std::vector<std::string>& probeCommand,
311 std::vector<boost::container::flat_map<std::string, BasicVariantType>>&
312 foundDevs)
James Feist3cb5fec2018-01-23 14:41:51 -0800313{
314 const static std::regex command(R"(\((.*)\))");
315 std::smatch match;
316 bool ret = false;
James Feist6bd2a022018-03-13 12:30:58 -0700317 bool matchOne = false;
James Feist3cb5fec2018-01-23 14:41:51 -0800318 bool cur = true;
319 probe_type_codes lastCommand = probe_type_codes::FALSE_T;
320
James Feista465ccc2019-02-08 12:51:01 -0800321 for (auto& probe : probeCommand)
James Feist3cb5fec2018-01-23 14:41:51 -0800322 {
323 bool foundProbe = false;
James Feista465ccc2019-02-08 12:51:01 -0800324 boost::container::flat_map<const char*, probe_type_codes,
James Feist3cb5fec2018-01-23 14:41:51 -0800325 cmp_str>::const_iterator probeType;
326
327 for (probeType = PROBE_TYPES.begin(); probeType != PROBE_TYPES.end();
328 probeType++)
329 {
330 if (probe.find(probeType->first) != std::string::npos)
331 {
332 foundProbe = true;
333 break;
334 }
335 }
336 if (foundProbe)
337 {
338 switch (probeType->second)
339 {
James Feist9eb0b582018-04-27 12:15:46 -0700340 case probe_type_codes::FALSE_T:
James Feist3cb5fec2018-01-23 14:41:51 -0800341 {
James Feist8f2710a2018-05-09 17:18:55 -0700342 return false;
James Feist9eb0b582018-04-27 12:15:46 -0700343 break;
James Feist3cb5fec2018-01-23 14:41:51 -0800344 }
James Feist9eb0b582018-04-27 12:15:46 -0700345 case probe_type_codes::TRUE_T:
346 {
James Feist8f2710a2018-05-09 17:18:55 -0700347 return true;
James Feist9eb0b582018-04-27 12:15:46 -0700348 break;
349 }
350 case probe_type_codes::MATCH_ONE:
351 {
352 // set current value to last, this probe type shouldn't
353 // affect the outcome
354 cur = ret;
355 matchOne = true;
356 break;
357 }
358 /*case probe_type_codes::AND:
359 break;
360 case probe_type_codes::OR:
361 break;
362 // these are no-ops until the last command switch
363 */
364 case probe_type_codes::FOUND:
365 {
366 if (!std::regex_search(probe, match, command))
367 {
368 std::cerr << "found probe sytax error " << probe
369 << "\n";
370 return false;
371 }
372 std::string commandStr = *(match.begin() + 1);
373 boost::replace_all(commandStr, "'", "");
374 cur = (std::find(PASSED_PROBES.begin(), PASSED_PROBES.end(),
375 commandStr) != PASSED_PROBES.end());
376 break;
377 }
James Feist3cb5fec2018-01-23 14:41:51 -0800378 }
379 }
380 // look on dbus for object
381 else
382 {
383 if (!std::regex_search(probe, match, command))
384 {
385 std::cerr << "dbus probe sytax error " << probe << "\n";
386 return false;
387 }
388 std::string commandStr = *(match.begin() + 1);
389 // convert single ticks and single slashes into legal json
Jae Hyun Yoo3936e7a2018-03-23 17:26:16 -0700390 boost::replace_all(commandStr, "'", "\"");
James Feist3f8a2782018-02-12 09:24:42 -0800391 boost::replace_all(commandStr, R"(\)", R"(\\)");
James Feist3cb5fec2018-01-23 14:41:51 -0800392 auto json = nlohmann::json::parse(commandStr, nullptr, false);
393 if (json.is_discarded())
394 {
395 std::cerr << "dbus command sytax error " << commandStr << "\n";
396 return false;
397 }
398 // we can match any (string, variant) property. (string, string)
399 // does a regex
400 std::map<std::string, nlohmann::json> dbusProbeMap =
401 json.get<std::map<std::string, nlohmann::json>>();
402 auto findStart = probe.find("(");
403 if (findStart == std::string::npos)
404 {
405 return false;
406 }
407 std::string probeInterface = probe.substr(0, findStart);
408 cur =
409 probeDbus(probeInterface, dbusProbeMap, foundDevs, foundProbe);
410 }
411
412 // some functions like AND and OR only take affect after the
413 // fact
414 switch (lastCommand)
415 {
James Feist9eb0b582018-04-27 12:15:46 -0700416 case probe_type_codes::AND:
417 ret = cur && ret;
418 break;
419 case probe_type_codes::OR:
420 ret = cur || ret;
421 break;
422 default:
423 ret = cur;
424 break;
James Feist3cb5fec2018-01-23 14:41:51 -0800425 }
426 lastCommand = probeType != PROBE_TYPES.end()
427 ? probeType->second
428 : probe_type_codes::FALSE_T;
James Feist3cb5fec2018-01-23 14:41:51 -0800429 }
430
431 // probe passed, but empty device
James Feist3cb5fec2018-01-23 14:41:51 -0800432 if (ret && foundDevs.size() == 0)
433 {
434 foundDevs.emplace_back(
James Feist8f2710a2018-05-09 17:18:55 -0700435 boost::container::flat_map<std::string, BasicVariantType>());
James Feist3cb5fec2018-01-23 14:41:51 -0800436 }
James Feist6bd2a022018-03-13 12:30:58 -0700437 if (matchOne && foundDevs.size() > 1)
438 {
439 foundDevs.erase(foundDevs.begin() + 1, foundDevs.end());
440 }
James Feist3cb5fec2018-01-23 14:41:51 -0800441 return ret;
442}
James Feist8f2710a2018-05-09 17:18:55 -0700443// this class finds the needed dbus fields and on destruction runs the probe
444struct PerformProbe : std::enable_shared_from_this<PerformProbe>
445{
James Feist3cb5fec2018-01-23 14:41:51 -0800446
James Feist8f2710a2018-05-09 17:18:55 -0700447 PerformProbe(
James Feista465ccc2019-02-08 12:51:01 -0800448 const std::vector<std::string>& probeCommand,
James Feist8f2710a2018-05-09 17:18:55 -0700449 std::function<void(std::vector<boost::container::flat_map<
James Feista465ccc2019-02-08 12:51:01 -0800450 std::string, BasicVariantType>>&)>&& callback) :
James Feist8f2710a2018-05-09 17:18:55 -0700451 _probeCommand(probeCommand),
452 _callback(std::move(callback))
453 {
454 }
455 ~PerformProbe()
456 {
457 if (probe(_probeCommand, _foundDevs))
458 {
459 _callback(_foundDevs);
460 }
461 }
462 void run()
463 {
464 // parse out dbus probes by discarding other probe types
James Feista465ccc2019-02-08 12:51:01 -0800465 boost::container::flat_map<const char*, probe_type_codes,
James Feist8f2710a2018-05-09 17:18:55 -0700466 cmp_str>::const_iterator probeType;
467
468 std::vector<std::string> dbusProbes;
James Feista465ccc2019-02-08 12:51:01 -0800469 for (std::string& probe : _probeCommand)
James Feist8f2710a2018-05-09 17:18:55 -0700470 {
471 bool found = false;
James Feista465ccc2019-02-08 12:51:01 -0800472 boost::container::flat_map<const char*, probe_type_codes,
James Feist8f2710a2018-05-09 17:18:55 -0700473 cmp_str>::const_iterator probeType;
474 for (probeType = PROBE_TYPES.begin();
475 probeType != PROBE_TYPES.end(); probeType++)
476 {
477 if (probe.find(probeType->first) != std::string::npos)
478 {
479 found = true;
480 break;
481 }
482 }
483 if (found)
484 {
485 continue;
486 }
487 // syntax requires probe before first open brace
488 auto findStart = probe.find("(");
489 std::string interface = probe.substr(0, findStart);
490
491 findDbusObjects(shared_from_this(), SYSTEM_BUS, interface);
492 }
493 }
494 std::vector<std::string> _probeCommand;
James Feista465ccc2019-02-08 12:51:01 -0800495 std::function<void(std::vector<boost::container::flat_map<
496 std::string, BasicVariantType>>&)>
James Feist8f2710a2018-05-09 17:18:55 -0700497 _callback;
498 std::vector<boost::container::flat_map<std::string, BasicVariantType>>
499 _foundDevs;
500};
501
502// writes output files to persist data
James Feista465ccc2019-02-08 12:51:01 -0800503bool writeJsonFiles(const nlohmann::json& systemConfiguration)
James Feist1b2e2242018-01-30 13:45:19 -0800504{
Ed Tanous072e25d2018-12-16 21:45:20 -0800505 std::filesystem::create_directory(OUTPUT_DIR);
James Feist1b2e2242018-01-30 13:45:19 -0800506 std::ofstream output(std::string(OUTPUT_DIR) + "system.json");
James Feistbb43d022018-06-12 15:44:33 -0700507 if (!output.good())
508 {
509 return false;
510 }
James Feist1b2e2242018-01-30 13:45:19 -0800511 output << systemConfiguration.dump(4);
512 output.close();
James Feistbb43d022018-06-12 15:44:33 -0700513 return true;
James Feist8f2710a2018-05-09 17:18:55 -0700514}
James Feist1b2e2242018-01-30 13:45:19 -0800515
James Feist8f2710a2018-05-09 17:18:55 -0700516// template function to add array as dbus property
517template <typename PropertyType>
James Feista465ccc2019-02-08 12:51:01 -0800518void addArrayToDbus(const std::string& name, const nlohmann::json& array,
519 sdbusplus::asio::dbus_interface* iface,
James Feistbb43d022018-06-12 15:44:33 -0700520 sdbusplus::asio::PropertyPermission permission)
James Feist8f2710a2018-05-09 17:18:55 -0700521{
522 std::vector<PropertyType> values;
James Feista465ccc2019-02-08 12:51:01 -0800523 for (const auto& property : array)
James Feist1b2e2242018-01-30 13:45:19 -0800524 {
James Feista465ccc2019-02-08 12:51:01 -0800525 auto ptr = property.get_ptr<const PropertyType*>();
James Feist8f2710a2018-05-09 17:18:55 -0700526 if (ptr != nullptr)
James Feist1b2e2242018-01-30 13:45:19 -0800527 {
James Feist8f2710a2018-05-09 17:18:55 -0700528 values.emplace_back(*ptr);
James Feist1b2e2242018-01-30 13:45:19 -0800529 }
530 }
James Feistbb43d022018-06-12 15:44:33 -0700531 // todo(james), currently there are no reason to persist arrays, get around
532 // to it if needed
533
534 iface->register_property(name, values, permission);
James Feist1b2e2242018-01-30 13:45:19 -0800535}
James Feist97a63f12018-05-17 13:50:57 -0700536
537template <typename JsonType>
James Feista465ccc2019-02-08 12:51:01 -0800538bool setJsonFromPointer(const std::string& ptrStr, const JsonType& value,
539 nlohmann::json& systemConfiguration)
James Feist97a63f12018-05-17 13:50:57 -0700540{
541 try
542 {
543 nlohmann::json::json_pointer ptr(ptrStr);
James Feista465ccc2019-02-08 12:51:01 -0800544 nlohmann::json& ref = systemConfiguration[ptr];
James Feist97a63f12018-05-17 13:50:57 -0700545 ref = value;
546 return true;
547 }
548 catch (const std::out_of_range)
549 {
550 return false;
551 }
552}
James Feistbb43d022018-06-12 15:44:33 -0700553
554template <typename PropertyType>
James Feista465ccc2019-02-08 12:51:01 -0800555void addProperty(const std::string& propertyName, const PropertyType& value,
556 sdbusplus::asio::dbus_interface* iface,
557 nlohmann::json& systemConfiguration,
558 const std::string& jsonPointerString,
James Feistbb43d022018-06-12 15:44:33 -0700559 sdbusplus::asio::PropertyPermission permission)
560{
561 if (permission == sdbusplus::asio::PropertyPermission::readOnly)
562 {
563 iface->register_property(propertyName, value);
564 return;
565 }
James Feist68500ff2018-08-08 15:40:42 -0700566 iface->register_property(
567 propertyName, value,
568 [&systemConfiguration,
569 jsonPointerString{std::string(jsonPointerString)}](
James Feista465ccc2019-02-08 12:51:01 -0800570 const PropertyType& newVal, PropertyType& val) {
James Feist68500ff2018-08-08 15:40:42 -0700571 val = newVal;
572 if (!setJsonFromPointer(jsonPointerString, val,
573 systemConfiguration))
574 {
575 std::cerr << "error setting json field\n";
576 return -1;
577 }
James Feistc6248a52018-08-14 10:09:45 -0700578 if (!writeJsonFiles(systemConfiguration))
James Feist68500ff2018-08-08 15:40:42 -0700579 {
580 std::cerr << "error setting json file\n";
James Feistc6248a52018-08-14 10:09:45 -0700581 return -1;
582 }
583 return 1;
584 });
585}
586
587void createDeleteObjectMethod(
James Feista465ccc2019-02-08 12:51:01 -0800588 const std::string& jsonPointerPath,
589 const std::shared_ptr<sdbusplus::asio::dbus_interface>& iface,
590 sdbusplus::asio::object_server& objServer,
591 nlohmann::json& systemConfiguration)
James Feistc6248a52018-08-14 10:09:45 -0700592{
593 std::weak_ptr<sdbusplus::asio::dbus_interface> interface = iface;
594 iface->register_method(
595 "Delete", [&objServer, &systemConfiguration, interface,
596 jsonPointerPath{std::string(jsonPointerPath)}]() {
597 std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
598 interface.lock();
599 if (!iface)
600 {
601 // this technically can't happen as the pointer is pointing to
602 // us
603 throw DBusInternalError();
604 }
605 nlohmann::json::json_pointer ptr(jsonPointerPath);
606 if (!objServer.remove_interface(iface))
607 {
608 std::cerr << "Can't delete interface " << jsonPointerPath
609 << "\n";
610 throw DBusInternalError();
611 }
612 systemConfiguration[ptr] = nullptr;
613
614 if (!writeJsonFiles(systemConfiguration))
615 {
616 std::cerr << "error setting json file\n";
617 throw DBusInternalError();
James Feist68500ff2018-08-08 15:40:42 -0700618 }
James Feistbb43d022018-06-12 15:44:33 -0700619 return -1;
James Feist68500ff2018-08-08 15:40:42 -0700620 });
James Feistbb43d022018-06-12 15:44:33 -0700621}
622
James Feist1b2e2242018-01-30 13:45:19 -0800623// adds simple json types to interface's properties
James Feistbb43d022018-06-12 15:44:33 -0700624void populateInterfaceFromJson(
James Feista465ccc2019-02-08 12:51:01 -0800625 nlohmann::json& systemConfiguration, const std::string& jsonPointerPath,
626 std::shared_ptr<sdbusplus::asio::dbus_interface>& iface,
627 nlohmann::json& dict, sdbusplus::asio::object_server& objServer,
James Feistbb43d022018-06-12 15:44:33 -0700628 sdbusplus::asio::PropertyPermission permission =
629 sdbusplus::asio::PropertyPermission::readOnly)
James Feist1b2e2242018-01-30 13:45:19 -0800630{
James Feista465ccc2019-02-08 12:51:01 -0800631 for (auto& dictPair : dict.items())
James Feist1b2e2242018-01-30 13:45:19 -0800632 {
James Feist8f2710a2018-05-09 17:18:55 -0700633 auto type = dictPair.value().type();
634 bool array = false;
635 if (dictPair.value().type() == nlohmann::json::value_t::array)
636 {
637 array = true;
638 if (!dictPair.value().size())
639 {
640 continue;
641 }
642 type = dictPair.value()[0].type();
643 bool isLegal = true;
James Feista465ccc2019-02-08 12:51:01 -0800644 for (const auto& arrayItem : dictPair.value())
James Feist8f2710a2018-05-09 17:18:55 -0700645 {
646 if (arrayItem.type() != type)
647 {
648 isLegal = false;
649 break;
650 }
651 }
652 if (!isLegal)
653 {
654 std::cerr << "dbus format error" << dictPair.value() << "\n";
655 continue;
656 }
657 if (type == nlohmann::json::value_t::object)
658 {
659 continue; // handled elsewhere
660 }
661 }
James Feist97a63f12018-05-17 13:50:57 -0700662 std::string key = jsonPointerPath + "/" + dictPair.key();
James Feistbb43d022018-06-12 15:44:33 -0700663 if (permission == sdbusplus::asio::PropertyPermission::readWrite)
664 {
665 // all setable numbers are doubles as it is difficult to always
666 // create a configuration file with all whole numbers as decimals
667 // i.e. 1.0
668 if (dictPair.value().is_number())
669 {
670 type = nlohmann::json::value_t::number_float;
671 }
672 }
673
James Feist8f2710a2018-05-09 17:18:55 -0700674 switch (type)
James Feist1b2e2242018-01-30 13:45:19 -0800675 {
James Feist9eb0b582018-04-27 12:15:46 -0700676 case (nlohmann::json::value_t::boolean):
677 {
James Feist8f2710a2018-05-09 17:18:55 -0700678 if (array)
679 {
680 // todo: array of bool isn't detected correctly by
681 // sdbusplus, change it to numbers
682 addArrayToDbus<uint64_t>(dictPair.key(), dictPair.value(),
James Feistc6248a52018-08-14 10:09:45 -0700683 iface.get(), permission);
James Feist8f2710a2018-05-09 17:18:55 -0700684 }
James Feistbb43d022018-06-12 15:44:33 -0700685
James Feist97a63f12018-05-17 13:50:57 -0700686 else
687 {
James Feistbb43d022018-06-12 15:44:33 -0700688 addProperty(dictPair.key(), dictPair.value().get<bool>(),
James Feistc6248a52018-08-14 10:09:45 -0700689 iface.get(), systemConfiguration, key,
690 permission);
James Feist97a63f12018-05-17 13:50:57 -0700691 }
James Feist9eb0b582018-04-27 12:15:46 -0700692 break;
693 }
694 case (nlohmann::json::value_t::number_integer):
695 {
James Feist8f2710a2018-05-09 17:18:55 -0700696 if (array)
697 {
698 addArrayToDbus<int64_t>(dictPair.key(), dictPair.value(),
James Feistc6248a52018-08-14 10:09:45 -0700699 iface.get(), permission);
James Feist97a63f12018-05-17 13:50:57 -0700700 }
701 else
702 {
James Feistbb43d022018-06-12 15:44:33 -0700703 addProperty(dictPair.key(), dictPair.value().get<int64_t>(),
James Feistc6248a52018-08-14 10:09:45 -0700704 iface.get(), systemConfiguration, key,
James Feistbb43d022018-06-12 15:44:33 -0700705 sdbusplus::asio::PropertyPermission::readOnly);
James Feist97a63f12018-05-17 13:50:57 -0700706 }
James Feist9eb0b582018-04-27 12:15:46 -0700707 break;
708 }
709 case (nlohmann::json::value_t::number_unsigned):
710 {
James Feist8f2710a2018-05-09 17:18:55 -0700711 if (array)
712 {
713 addArrayToDbus<uint64_t>(dictPair.key(), dictPair.value(),
James Feistc6248a52018-08-14 10:09:45 -0700714 iface.get(), permission);
James Feist97a63f12018-05-17 13:50:57 -0700715 }
716 else
717 {
James Feistbb43d022018-06-12 15:44:33 -0700718 addProperty(dictPair.key(),
James Feistc6248a52018-08-14 10:09:45 -0700719 dictPair.value().get<uint64_t>(), iface.get(),
James Feistbb43d022018-06-12 15:44:33 -0700720 systemConfiguration, key,
721 sdbusplus::asio::PropertyPermission::readOnly);
James Feist97a63f12018-05-17 13:50:57 -0700722 }
James Feist9eb0b582018-04-27 12:15:46 -0700723 break;
724 }
725 case (nlohmann::json::value_t::number_float):
726 {
James Feist8f2710a2018-05-09 17:18:55 -0700727 if (array)
728 {
729 addArrayToDbus<double>(dictPair.key(), dictPair.value(),
James Feistc6248a52018-08-14 10:09:45 -0700730 iface.get(), permission);
James Feist8f2710a2018-05-09 17:18:55 -0700731 }
James Feistbb43d022018-06-12 15:44:33 -0700732
James Feist97a63f12018-05-17 13:50:57 -0700733 else
734 {
James Feistbb43d022018-06-12 15:44:33 -0700735 addProperty(dictPair.key(), dictPair.value().get<double>(),
James Feistc6248a52018-08-14 10:09:45 -0700736 iface.get(), systemConfiguration, key,
737 permission);
James Feist97a63f12018-05-17 13:50:57 -0700738 }
James Feist9eb0b582018-04-27 12:15:46 -0700739 break;
740 }
741 case (nlohmann::json::value_t::string):
742 {
James Feist8f2710a2018-05-09 17:18:55 -0700743 if (array)
744 {
James Feistc6248a52018-08-14 10:09:45 -0700745 addArrayToDbus<std::string>(dictPair.key(),
746 dictPair.value(), iface.get(),
747 permission);
James Feist97a63f12018-05-17 13:50:57 -0700748 }
749 else
750 {
James Feistc6248a52018-08-14 10:09:45 -0700751 addProperty(
752 dictPair.key(), dictPair.value().get<std::string>(),
753 iface.get(), systemConfiguration, key, permission);
James Feist97a63f12018-05-17 13:50:57 -0700754 }
James Feist9eb0b582018-04-27 12:15:46 -0700755 break;
756 }
James Feist1b2e2242018-01-30 13:45:19 -0800757 }
758 }
James Feistc6248a52018-08-14 10:09:45 -0700759 if (permission == sdbusplus::asio::PropertyPermission::readWrite)
760 {
761 createDeleteObjectMethod(jsonPointerPath, iface, objServer,
762 systemConfiguration);
763 }
James Feist8f2710a2018-05-09 17:18:55 -0700764 iface->initialize();
James Feist1b2e2242018-01-30 13:45:19 -0800765}
766
James Feista465ccc2019-02-08 12:51:01 -0800767sdbusplus::asio::PropertyPermission getPermission(const std::string& interface)
James Feistc6248a52018-08-14 10:09:45 -0700768{
769 return std::find(settableInterfaces.begin(), settableInterfaces.end(),
770 interface) != settableInterfaces.end()
771 ? sdbusplus::asio::PropertyPermission::readWrite
772 : sdbusplus::asio::PropertyPermission::readOnly;
773}
774
James Feista465ccc2019-02-08 12:51:01 -0800775void createAddObjectMethod(const std::string& jsonPointerPath,
776 const std::string& path,
777 nlohmann::json& systemConfiguration,
778 sdbusplus::asio::object_server& objServer)
James Feist68500ff2018-08-08 15:40:42 -0700779{
780 auto iface = objServer.add_interface(path, "xyz.openbmc_project.AddObject");
781
782 iface->register_method(
783 "AddObject",
784 [&systemConfiguration, &objServer,
785 jsonPointerPath{std::string(jsonPointerPath)},
786 path{std::string(path)}](
James Feista465ccc2019-02-08 12:51:01 -0800787 const boost::container::flat_map<std::string, JsonVariantType>&
788 data) {
James Feist68500ff2018-08-08 15:40:42 -0700789 nlohmann::json::json_pointer ptr(jsonPointerPath);
James Feista465ccc2019-02-08 12:51:01 -0800790 nlohmann::json& base = systemConfiguration[ptr];
James Feist68500ff2018-08-08 15:40:42 -0700791 auto findExposes = base.find("Exposes");
792
793 if (findExposes == base.end())
794 {
795 throw std::invalid_argument("Entity must have children.");
796 }
797
798 // this will throw invalid-argument to sdbusplus if invalid json
799 nlohmann::json newData{};
James Feista465ccc2019-02-08 12:51:01 -0800800 for (const auto& item : data)
James Feist68500ff2018-08-08 15:40:42 -0700801 {
James Feista465ccc2019-02-08 12:51:01 -0800802 nlohmann::json& newJson = newData[item.first];
803 std::visit([&newJson](auto&& val) { newJson = std::move(val); },
804 item.second);
James Feist68500ff2018-08-08 15:40:42 -0700805 }
806
807 auto findName = newData.find("Name");
808 auto findType = newData.find("Type");
809 if (findName == newData.end() || findType == newData.end())
810 {
811 throw std::invalid_argument("AddObject missing Name or Type");
812 }
James Feista465ccc2019-02-08 12:51:01 -0800813 const std::string* type = findType->get_ptr<const std::string*>();
814 const std::string* name = findName->get_ptr<const std::string*>();
James Feist68500ff2018-08-08 15:40:42 -0700815 if (type == nullptr || name == nullptr)
816 {
817 throw std::invalid_argument("Type and Name must be a string.");
818 }
819
820 size_t lastIndex = 0;
821 // we add in the "exposes"
822 for (; lastIndex < findExposes->size(); lastIndex++)
823 {
824 if (findExposes->at(lastIndex)["Name"] == *name &&
825 findExposes->at(lastIndex)["Type"] == *type)
826 {
827 throw std::invalid_argument(
828 "Field already in JSON, not adding");
829 }
830 lastIndex++;
831 }
832
833 std::ifstream schemaFile(std::string(schemaDirectory) + "/" +
834 *type + ".json");
835 // todo(james) we might want to also make a list of 'can add'
836 // interfaces but for now I think the assumption if there is a
837 // schema avaliable that it is allowed to update is fine
838 if (!schemaFile.good())
839 {
840 throw std::invalid_argument(
841 "No schema avaliable, cannot validate.");
842 }
843 nlohmann::json schema =
844 nlohmann::json::parse(schemaFile, nullptr, false);
845 if (schema.is_discarded())
846 {
847 std::cerr << "Schema not legal" << *type << ".json\n";
848 throw DBusInternalError();
849 }
850 if (!validateJson(schema, newData))
851 {
852 throw std::invalid_argument("Data does not match schema");
853 }
854
855 if (!writeJsonFiles(systemConfiguration))
856 {
857 std::cerr << "Error writing json files\n";
858 throw DBusInternalError();
859 }
860 std::string dbusName = *name;
861
862 std::regex_replace(dbusName.begin(), dbusName.begin(),
863 dbusName.end(), ILLEGAL_DBUS_REGEX, "_");
864 auto iface = objServer.add_interface(
865 path + "/" + dbusName,
866 "xyz.openbmc_project.Configuration." + *type);
867 // permission is read-write, as since we just created it, must be
868 // runtime modifiable
869 populateInterfaceFromJson(
870 systemConfiguration,
James Feistc6248a52018-08-14 10:09:45 -0700871 jsonPointerPath + "/" + std::to_string(lastIndex), iface,
James Feist68500ff2018-08-08 15:40:42 -0700872 newData, objServer,
873 sdbusplus::asio::PropertyPermission::readWrite);
874 // todo(james) generate patch
875 findExposes->push_back(newData);
876 });
877 iface->initialize();
878}
879
James Feista465ccc2019-02-08 12:51:01 -0800880void postToDbus(const nlohmann::json& newConfiguration,
881 nlohmann::json& systemConfiguration,
882 sdbusplus::asio::object_server& objServer)
James Feist75fdeeb2018-02-20 14:26:16 -0800883
James Feist1b2e2242018-01-30 13:45:19 -0800884{
James Feist97a63f12018-05-17 13:50:57 -0700885 // iterate through boards
James Feista465ccc2019-02-08 12:51:01 -0800886 for (auto& boardPair : newConfiguration.items())
James Feist1b2e2242018-01-30 13:45:19 -0800887 {
888 std::string boardKey = boardPair.key();
James Feist97a63f12018-05-17 13:50:57 -0700889 std::vector<std::string> path;
890 std::string jsonPointerPath = "/" + boardKey;
891 // loop through newConfiguration, but use values from system
892 // configuration to be able to modify via dbus later
893 auto boardValues = systemConfiguration[boardKey];
James Feistd63d18a2018-07-19 15:23:45 -0700894 auto findBoardType = boardValues.find("Type");
James Feist1b2e2242018-01-30 13:45:19 -0800895 std::string boardType;
896 if (findBoardType != boardValues.end() &&
897 findBoardType->type() == nlohmann::json::value_t::string)
898 {
899 boardType = findBoardType->get<std::string>();
900 std::regex_replace(boardType.begin(), boardType.begin(),
901 boardType.end(), ILLEGAL_DBUS_REGEX, "_");
902 }
903 else
904 {
905 std::cerr << "Unable to find type for " << boardKey
906 << " reverting to Chassis.\n";
907 boardType = "Chassis";
908 }
James Feist11be6672018-04-06 14:05:32 -0700909 std::string boardtypeLower = boost::algorithm::to_lower_copy(boardType);
James Feist1b2e2242018-01-30 13:45:19 -0800910
911 std::regex_replace(boardKey.begin(), boardKey.begin(), boardKey.end(),
912 ILLEGAL_DBUS_REGEX, "_");
James Feist11be6672018-04-06 14:05:32 -0700913 std::string boardName = "/xyz/openbmc_project/inventory/system/" +
914 boardtypeLower + "/" + boardKey;
James Feist1b2e2242018-01-30 13:45:19 -0800915
James Feist8f2710a2018-05-09 17:18:55 -0700916 auto inventoryIface = objServer.add_interface(
917 boardName, "xyz.openbmc_project.Inventory.Item");
James Feist68500ff2018-08-08 15:40:42 -0700918
James Feist8f2710a2018-05-09 17:18:55 -0700919 auto boardIface = objServer.add_interface(
920 boardName, "xyz.openbmc_project.Inventory.Item." + boardType);
James Feist11be6672018-04-06 14:05:32 -0700921
James Feist68500ff2018-08-08 15:40:42 -0700922 createAddObjectMethod(jsonPointerPath, boardName, systemConfiguration,
923 objServer);
924
James Feist97a63f12018-05-17 13:50:57 -0700925 populateInterfaceFromJson(systemConfiguration, jsonPointerPath,
James Feistc6248a52018-08-14 10:09:45 -0700926 boardIface, boardValues, objServer);
James Feist97a63f12018-05-17 13:50:57 -0700927 jsonPointerPath += "/";
928 // iterate through board properties
James Feista465ccc2019-02-08 12:51:01 -0800929 for (auto& boardField : boardValues.items())
James Feist11be6672018-04-06 14:05:32 -0700930 {
931 if (boardField.value().type() == nlohmann::json::value_t::object)
932 {
James Feist8f2710a2018-05-09 17:18:55 -0700933 auto iface =
934 objServer.add_interface(boardName, boardField.key());
James Feistc6248a52018-08-14 10:09:45 -0700935 populateInterfaceFromJson(systemConfiguration,
936 jsonPointerPath + boardField.key(),
937 iface, boardField.value(), objServer);
James Feist11be6672018-04-06 14:05:32 -0700938 }
939 }
James Feist97a63f12018-05-17 13:50:57 -0700940
James Feist1e3e6982018-08-03 16:09:28 -0700941 auto exposes = boardValues.find("Exposes");
James Feist1b2e2242018-01-30 13:45:19 -0800942 if (exposes == boardValues.end())
943 {
944 continue;
945 }
James Feist97a63f12018-05-17 13:50:57 -0700946 // iterate through exposes
James Feist1e3e6982018-08-03 16:09:28 -0700947 jsonPointerPath += "Exposes/";
James Feist97a63f12018-05-17 13:50:57 -0700948
949 // store the board level pointer so we can modify it on the way down
950 std::string jsonPointerPathBoard = jsonPointerPath;
951 size_t exposesIndex = -1;
James Feista465ccc2019-02-08 12:51:01 -0800952 for (auto& item : *exposes)
James Feist1b2e2242018-01-30 13:45:19 -0800953 {
James Feist97a63f12018-05-17 13:50:57 -0700954 exposesIndex++;
955 jsonPointerPath = jsonPointerPathBoard;
956 jsonPointerPath += std::to_string(exposesIndex);
957
James Feistd63d18a2018-07-19 15:23:45 -0700958 auto findName = item.find("Name");
James Feist1b2e2242018-01-30 13:45:19 -0800959 if (findName == item.end())
960 {
961 std::cerr << "cannot find name in field " << item << "\n";
962 continue;
963 }
James Feist1e3e6982018-08-03 16:09:28 -0700964 auto findStatus = item.find("Status");
James Feist1b2e2242018-01-30 13:45:19 -0800965 // if status is not found it is assumed to be status = 'okay'
966 if (findStatus != item.end())
967 {
968 if (*findStatus == "disabled")
969 {
970 continue;
971 }
972 }
James Feistd63d18a2018-07-19 15:23:45 -0700973 auto findType = item.find("Type");
James Feist1b2e2242018-01-30 13:45:19 -0800974 std::string itemType;
975 if (findType != item.end())
976 {
977 itemType = findType->get<std::string>();
978 std::regex_replace(itemType.begin(), itemType.begin(),
979 itemType.end(), ILLEGAL_DBUS_REGEX, "_");
980 }
981 else
982 {
983 itemType = "unknown";
984 }
985 std::string itemName = findName->get<std::string>();
986 std::regex_replace(itemName.begin(), itemName.begin(),
987 itemName.end(), ILLEGAL_DBUS_REGEX, "_");
James Feistc6248a52018-08-14 10:09:45 -0700988
James Feist8f2710a2018-05-09 17:18:55 -0700989 auto itemIface = objServer.add_interface(
990 boardName + "/" + itemName,
James Feist1b2e2242018-01-30 13:45:19 -0800991 "xyz.openbmc_project.Configuration." + itemType);
992
James Feist97a63f12018-05-17 13:50:57 -0700993 populateInterfaceFromJson(systemConfiguration, jsonPointerPath,
James Feistc6248a52018-08-14 10:09:45 -0700994 itemIface, item, objServer,
995 getPermission(itemType));
James Feist1b2e2242018-01-30 13:45:19 -0800996
James Feista465ccc2019-02-08 12:51:01 -0800997 for (auto& objectPair : item.items())
James Feist1b2e2242018-01-30 13:45:19 -0800998 {
James Feist97a63f12018-05-17 13:50:57 -0700999 jsonPointerPath = jsonPointerPathBoard +
1000 std::to_string(exposesIndex) + "/" +
1001 objectPair.key();
James Feist1b2e2242018-01-30 13:45:19 -08001002 if (objectPair.value().type() ==
1003 nlohmann::json::value_t::object)
1004 {
James Feist8f2710a2018-05-09 17:18:55 -07001005 auto objectIface = objServer.add_interface(
1006 boardName + "/" + itemName,
James Feist1b2e2242018-01-30 13:45:19 -08001007 "xyz.openbmc_project.Configuration." + itemType + "." +
James Feist8f2710a2018-05-09 17:18:55 -07001008 objectPair.key());
James Feist97a63f12018-05-17 13:50:57 -07001009
1010 populateInterfaceFromJson(
James Feistc6248a52018-08-14 10:09:45 -07001011 systemConfiguration, jsonPointerPath, objectIface,
1012 objectPair.value(), objServer, getPermission(itemType));
James Feist1b2e2242018-01-30 13:45:19 -08001013 }
1014 else if (objectPair.value().type() ==
1015 nlohmann::json::value_t::array)
1016 {
1017 size_t index = 0;
James Feist8f2710a2018-05-09 17:18:55 -07001018 if (!objectPair.value().size())
James Feist1b2e2242018-01-30 13:45:19 -08001019 {
James Feist8f2710a2018-05-09 17:18:55 -07001020 continue;
1021 }
1022 bool isLegal = true;
1023 auto type = objectPair.value()[0].type();
1024 if (type != nlohmann::json::value_t::object)
1025 {
1026 continue;
1027 }
1028
1029 // verify legal json
James Feista465ccc2019-02-08 12:51:01 -08001030 for (const auto& arrayItem : objectPair.value())
James Feist8f2710a2018-05-09 17:18:55 -07001031 {
1032 if (arrayItem.type() != type)
James Feist1b2e2242018-01-30 13:45:19 -08001033 {
James Feist8f2710a2018-05-09 17:18:55 -07001034 isLegal = false;
James Feist1b2e2242018-01-30 13:45:19 -08001035 break;
1036 }
James Feist8f2710a2018-05-09 17:18:55 -07001037 }
1038 if (!isLegal)
1039 {
1040 std::cerr << "dbus format error" << objectPair.value()
1041 << "\n";
1042 break;
1043 }
1044
James Feista465ccc2019-02-08 12:51:01 -08001045 for (auto& arrayItem : objectPair.value())
James Feist8f2710a2018-05-09 17:18:55 -07001046 {
James Feist97a63f12018-05-17 13:50:57 -07001047
James Feist8f2710a2018-05-09 17:18:55 -07001048 auto objectIface = objServer.add_interface(
1049 boardName + "/" + itemName,
James Feist1b2e2242018-01-30 13:45:19 -08001050 "xyz.openbmc_project.Configuration." + itemType +
James Feistbb43d022018-06-12 15:44:33 -07001051 "." + objectPair.key() + std::to_string(index));
James Feistc6248a52018-08-14 10:09:45 -07001052 populateInterfaceFromJson(
1053 systemConfiguration,
1054 jsonPointerPath + "/" + std::to_string(index),
1055 objectIface, arrayItem, objServer,
1056 getPermission(objectPair.key()));
James Feistbb43d022018-06-12 15:44:33 -07001057 index++;
James Feist1b2e2242018-01-30 13:45:19 -08001058 }
1059 }
1060 }
1061 }
1062 }
1063}
1064
1065// finds the template character (currently set to $) and replaces the value with
1066// the field found in a dbus object i.e. $ADDRESS would get populated with the
1067// ADDRESS field from a object on dbus
1068void templateCharReplace(
James Feista465ccc2019-02-08 12:51:01 -08001069 nlohmann::json::iterator& keyPair,
1070 const boost::container::flat_map<std::string, BasicVariantType>&
1071 foundDevice,
1072 size_t& foundDeviceIdx)
James Feist1b2e2242018-01-30 13:45:19 -08001073{
James Feist11be6672018-04-06 14:05:32 -07001074 if (keyPair.value().type() == nlohmann::json::value_t::object)
1075 {
1076 for (auto nextLayer = keyPair.value().begin();
1077 nextLayer != keyPair.value().end(); nextLayer++)
1078 {
1079 templateCharReplace(nextLayer, foundDevice, foundDeviceIdx);
1080 }
1081 return;
1082 }
Ed Tanous12bc7932019-02-26 14:36:20 -08001083
1084 std::string* strPtr = keyPair.value().get_ptr<std::string*>();
1085 if (strPtr == nullptr)
James Feist1b2e2242018-01-30 13:45:19 -08001086 {
1087 return;
1088 }
1089
Ed Tanous12bc7932019-02-26 14:36:20 -08001090 boost::replace_all(*strPtr, "$index", std::to_string(foundDeviceIdx));
1091
1092 std::size_t templateIndex = 0;
1093
1094 for (auto& foundDevicePair : foundDevice)
James Feist1b2e2242018-01-30 13:45:19 -08001095 {
Ed Tanous12bc7932019-02-26 14:36:20 -08001096 std::string templateName = "$" + foundDevicePair.first;
1097 if (boost::iequals(*strPtr, templateName))
James Feist1b2e2242018-01-30 13:45:19 -08001098 {
Ed Tanous12bc7932019-02-26 14:36:20 -08001099 std::visit([&](auto&& val) { keyPair.value() = val; },
1100 foundDevicePair.second);
1101 // We probably just invalidated the pointer above, so set it to null
1102 strPtr = nullptr;
1103 break;
James Feist1b2e2242018-01-30 13:45:19 -08001104 }
Ed Tanous12bc7932019-02-26 14:36:20 -08001105
1106 std::string probeValue =
1107 std::visit(VariantToStringVisitor(), foundDevicePair.second);
1108 boost::replace_all(*strPtr, templateName, probeValue);
1109 }
1110
1111 strPtr = keyPair.value().get_ptr<std::string*>();
1112 if (strPtr == nullptr)
1113 {
1114 return;
James Feist1b2e2242018-01-30 13:45:19 -08001115 }
James Feistc6090822019-01-04 16:02:48 -08001116
1117 // convert hex numbers to ints
Ed Tanous12bc7932019-02-26 14:36:20 -08001118 if (boost::starts_with(*strPtr, "0x"))
James Feist28dc2da2018-10-15 14:47:42 -07001119 {
1120 try
1121 {
James Feistc6090822019-01-04 16:02:48 -08001122 size_t pos = 0;
Ed Tanous12bc7932019-02-26 14:36:20 -08001123 int64_t temp = std::stoul(*strPtr, &pos, 0);
1124 if (pos == strPtr->size())
James Feistc6090822019-01-04 16:02:48 -08001125 {
1126 keyPair.value() = static_cast<uint64_t>(temp);
1127 }
James Feist28dc2da2018-10-15 14:47:42 -07001128 }
1129 catch (std::invalid_argument)
1130 {
1131 }
James Feistc6090822019-01-04 16:02:48 -08001132 catch (std::out_of_range)
1133 {
1134 }
James Feist28dc2da2018-10-15 14:47:42 -07001135 }
James Feist1b2e2242018-01-30 13:45:19 -08001136}
1137
James Feist8f2710a2018-05-09 17:18:55 -07001138// reads json files out of the filesystem
James Feista465ccc2019-02-08 12:51:01 -08001139bool findJsonFiles(std::list<nlohmann::json>& configurations)
James Feist3cb5fec2018-01-23 14:41:51 -08001140{
1141 // find configuration files
Ed Tanous072e25d2018-12-16 21:45:20 -08001142 std::vector<std::filesystem::path> jsonPaths;
1143 if (!findFiles(std::filesystem::path(configurationDirectory),
James Feista3c180a2018-08-09 16:06:04 -07001144 R"(.*\.json)", jsonPaths))
James Feist3cb5fec2018-01-23 14:41:51 -08001145 {
1146 std::cerr << "Unable to find any configuration files in "
James Feistb4383f42018-08-06 16:54:10 -07001147 << configurationDirectory << "\n";
James Feist75fdeeb2018-02-20 14:26:16 -08001148 return false;
James Feist3cb5fec2018-01-23 14:41:51 -08001149 }
James Feistb4383f42018-08-06 16:54:10 -07001150
1151 std::ifstream schemaStream(std::string(schemaDirectory) + "/" +
1152 globalSchema);
1153 if (!schemaStream.good())
1154 {
1155 std::cerr
1156 << "Cannot open schema file, cannot validate JSON, exiting\n\n";
1157 std::exit(EXIT_FAILURE);
Ed Tanous072e25d2018-12-16 21:45:20 -08001158 return false;
James Feistb4383f42018-08-06 16:54:10 -07001159 }
1160 nlohmann::json schema = nlohmann::json::parse(schemaStream, nullptr, false);
1161 if (schema.is_discarded())
1162 {
1163 std::cerr
1164 << "Illegal schema file detected, cannot validate JSON, exiting\n";
1165 std::exit(EXIT_FAILURE);
Ed Tanous072e25d2018-12-16 21:45:20 -08001166 return false;
James Feistb4383f42018-08-06 16:54:10 -07001167 }
1168
James Feista465ccc2019-02-08 12:51:01 -08001169 for (auto& jsonPath : jsonPaths)
James Feist3cb5fec2018-01-23 14:41:51 -08001170 {
1171 std::ifstream jsonStream(jsonPath.c_str());
1172 if (!jsonStream.good())
1173 {
1174 std::cerr << "unable to open " << jsonPath.string() << "\n";
1175 continue;
1176 }
1177 auto data = nlohmann::json::parse(jsonStream, nullptr, false);
1178 if (data.is_discarded())
1179 {
1180 std::cerr << "syntax error in " << jsonPath.string() << "\n";
1181 continue;
1182 }
James Feist8da99192019-01-24 08:20:16 -08001183 /*
1184 * todo(james): reenable this once less things are in flight
1185 *
James Feistb4383f42018-08-06 16:54:10 -07001186 if (!validateJson(schema, data))
1187 {
1188 std::cerr << "Error validating " << jsonPath.string() << "\n";
1189 continue;
1190 }
James Feist8da99192019-01-24 08:20:16 -08001191 */
James Feistb4383f42018-08-06 16:54:10 -07001192
James Feist3cb5fec2018-01-23 14:41:51 -08001193 if (data.type() == nlohmann::json::value_t::array)
1194 {
James Feista465ccc2019-02-08 12:51:01 -08001195 for (auto& d : data)
James Feist3cb5fec2018-01-23 14:41:51 -08001196 {
1197 configurations.emplace_back(d);
1198 }
1199 }
1200 else
1201 {
1202 configurations.emplace_back(data);
1203 }
1204 }
Ed Tanous072e25d2018-12-16 21:45:20 -08001205 return true;
James Feist75fdeeb2018-02-20 14:26:16 -08001206}
James Feist3cb5fec2018-01-23 14:41:51 -08001207
James Feist8f2710a2018-05-09 17:18:55 -07001208struct PerformScan : std::enable_shared_from_this<PerformScan>
James Feist75fdeeb2018-02-20 14:26:16 -08001209{
James Feist75fdeeb2018-02-20 14:26:16 -08001210
James Feista465ccc2019-02-08 12:51:01 -08001211 PerformScan(nlohmann::json& systemConfiguration,
1212 std::list<nlohmann::json>& configurations,
1213 std::function<void(void)>&& callback) :
James Feist8f2710a2018-05-09 17:18:55 -07001214 _systemConfiguration(systemConfiguration),
1215 _configurations(configurations), _callback(std::move(callback))
James Feist3cb5fec2018-01-23 14:41:51 -08001216 {
James Feist8f2710a2018-05-09 17:18:55 -07001217 }
1218 void run()
1219 {
1220 for (auto it = _configurations.begin(); it != _configurations.end();)
James Feist3cb5fec2018-01-23 14:41:51 -08001221 {
James Feist1e3e6982018-08-03 16:09:28 -07001222 auto findProbe = it->find("Probe");
James Feistd63d18a2018-07-19 15:23:45 -07001223 auto findName = it->find("Name");
James Feist3cb5fec2018-01-23 14:41:51 -08001224
James Feist1b2e2242018-01-30 13:45:19 -08001225 nlohmann::json probeCommand;
1226 // check for poorly formatted fields, probe must be an array
1227 if (findProbe == it->end())
James Feist3cb5fec2018-01-23 14:41:51 -08001228 {
1229 std::cerr << "configuration file missing probe:\n " << *it
1230 << "\n";
James Feist8f2710a2018-05-09 17:18:55 -07001231 it = _configurations.erase(it);
1232 continue;
James Feist3cb5fec2018-01-23 14:41:51 -08001233 }
James Feist1b2e2242018-01-30 13:45:19 -08001234 else if ((*findProbe).type() != nlohmann::json::value_t::array)
James Feist3cb5fec2018-01-23 14:41:51 -08001235 {
1236 probeCommand = nlohmann::json::array();
1237 probeCommand.push_back(*findProbe);
1238 }
1239 else
1240 {
1241 probeCommand = *findProbe;
1242 }
James Feist1b2e2242018-01-30 13:45:19 -08001243
1244 if (findName == it->end())
1245 {
1246 std::cerr << "configuration file missing name:\n " << *it
1247 << "\n";
James Feist8f2710a2018-05-09 17:18:55 -07001248 it = _configurations.erase(it);
1249 continue;
James Feist1b2e2242018-01-30 13:45:19 -08001250 }
James Feist8f2710a2018-05-09 17:18:55 -07001251 std::string name = *findName;
James Feist1b2e2242018-01-30 13:45:19 -08001252
James Feist8f2710a2018-05-09 17:18:55 -07001253 if (std::find(PASSED_PROBES.begin(), PASSED_PROBES.end(), name) !=
1254 PASSED_PROBES.end())
James Feist3cb5fec2018-01-23 14:41:51 -08001255 {
James Feist8f2710a2018-05-09 17:18:55 -07001256 it = _configurations.erase(it);
1257 continue;
1258 }
James Feista465ccc2019-02-08 12:51:01 -08001259 nlohmann::json* record = &(*it);
James Feist3cb5fec2018-01-23 14:41:51 -08001260
James Feist8f2710a2018-05-09 17:18:55 -07001261 // store reference to this to children to makes sure we don't get
1262 // destroyed too early
1263 auto thisRef = shared_from_this();
1264 auto p = std::make_shared<PerformProbe>(
1265 probeCommand,
1266 [&, record, name,
1267 thisRef](std::vector<boost::container::flat_map<
James Feista465ccc2019-02-08 12:51:01 -08001268 std::string, BasicVariantType>>& foundDevices) {
James Feist8f2710a2018-05-09 17:18:55 -07001269 _passed = true;
James Feist3cb5fec2018-01-23 14:41:51 -08001270
James Feist8f2710a2018-05-09 17:18:55 -07001271 PASSED_PROBES.push_back(name);
1272 size_t foundDeviceIdx = 0;
1273
James Feistbe5425f2018-06-08 10:30:55 -07001274 // insert into configuration temporarly to be able to
1275 // reference ourselves
1276 _systemConfiguration[name] = *record;
1277
James Feista465ccc2019-02-08 12:51:01 -08001278 for (auto& foundDevice : foundDevices)
James Feist3cb5fec2018-01-23 14:41:51 -08001279 {
James Feist8f2710a2018-05-09 17:18:55 -07001280 for (auto keyPair = record->begin();
1281 keyPair != record->end(); keyPair++)
James Feist3cb5fec2018-01-23 14:41:51 -08001282 {
James Feist1b2e2242018-01-30 13:45:19 -08001283 templateCharReplace(keyPair, foundDevice,
1284 foundDeviceIdx);
James Feist8f2710a2018-05-09 17:18:55 -07001285 }
James Feist1e3e6982018-08-03 16:09:28 -07001286 auto findExpose = record->find("Exposes");
James Feist8f2710a2018-05-09 17:18:55 -07001287 if (findExpose == record->end())
1288 {
1289 continue;
1290 }
James Feista465ccc2019-02-08 12:51:01 -08001291 for (auto& expose : *findExpose)
James Feist8f2710a2018-05-09 17:18:55 -07001292 {
1293 for (auto keyPair = expose.begin();
1294 keyPair != expose.end(); keyPair++)
James Feist3cb5fec2018-01-23 14:41:51 -08001295 {
James Feist1b2e2242018-01-30 13:45:19 -08001296
James Feist8f2710a2018-05-09 17:18:55 -07001297 // fill in template characters with devices
1298 // found
1299 templateCharReplace(keyPair, foundDevice,
1300 foundDeviceIdx);
1301 // special case bind
James Feist1e3e6982018-08-03 16:09:28 -07001302 if (boost::starts_with(keyPair.key(), "Bind"))
James Feist8f2710a2018-05-09 17:18:55 -07001303 {
1304 if (keyPair.value().type() !=
1305 nlohmann::json::value_t::string)
James Feist3cb5fec2018-01-23 14:41:51 -08001306 {
James Feist8f2710a2018-05-09 17:18:55 -07001307 std::cerr << "bind_ value must be of "
1308 "type string "
1309 << keyPair.key() << "\n";
James Feist1b2e2242018-01-30 13:45:19 -08001310 continue;
1311 }
James Feist8f2710a2018-05-09 17:18:55 -07001312 bool foundBind = false;
1313 std::string bind = keyPair.key().substr(
James Feist1e3e6982018-08-03 16:09:28 -07001314 sizeof("Bind") - 1);
James Feistbe5425f2018-06-08 10:30:55 -07001315
James Feista465ccc2019-02-08 12:51:01 -08001316 for (auto& configurationPair :
James Feist8f2710a2018-05-09 17:18:55 -07001317 _systemConfiguration.items())
James Feist1b2e2242018-01-30 13:45:19 -08001318 {
James Feist1b2e2242018-01-30 13:45:19 -08001319
James Feist8f2710a2018-05-09 17:18:55 -07001320 auto configListFind =
1321 configurationPair.value().find(
James Feist1e3e6982018-08-03 16:09:28 -07001322 "Exposes");
James Feist8f2710a2018-05-09 17:18:55 -07001323
1324 if (configListFind ==
1325 configurationPair.value()
1326 .end() ||
1327 configListFind->type() !=
1328 nlohmann::json::value_t::array)
1329 {
1330 continue;
1331 }
James Feista465ccc2019-02-08 12:51:01 -08001332 for (auto& exposedObject :
James Feist8f2710a2018-05-09 17:18:55 -07001333 *configListFind)
1334 {
1335 std::string foundObjectName =
James Feistd63d18a2018-07-19 15:23:45 -07001336 (exposedObject)["Name"];
James Feist8f2710a2018-05-09 17:18:55 -07001337 if (boost::iequals(
1338 foundObjectName,
1339 keyPair.value()
1340 .get<std::string>()))
1341 {
James Feist1e3e6982018-08-03 16:09:28 -07001342 exposedObject["Status"] =
James Feist8f2710a2018-05-09 17:18:55 -07001343 "okay";
1344 expose[bind] = exposedObject;
1345
1346 foundBind = true;
1347 break;
1348 }
1349 }
1350 if (foundBind)
1351 {
James Feist3cb5fec2018-01-23 14:41:51 -08001352 break;
1353 }
1354 }
James Feist8f2710a2018-05-09 17:18:55 -07001355 if (!foundBind)
James Feist3cb5fec2018-01-23 14:41:51 -08001356 {
James Feist8f2710a2018-05-09 17:18:55 -07001357 std::cerr << "configuration file "
1358 "dependency error, "
1359 "could not find bind "
1360 << keyPair.value() << "\n";
James Feist3cb5fec2018-01-23 14:41:51 -08001361 }
1362 }
1363 }
1364 }
1365 }
James Feistbe5425f2018-06-08 10:30:55 -07001366 // overwrite ourselves with cleaned up version
James Feist8f2710a2018-05-09 17:18:55 -07001367 _systemConfiguration[name] = *record;
1368 });
1369 p->run();
1370 it++;
James Feist3cb5fec2018-01-23 14:41:51 -08001371 }
1372 }
James Feist75fdeeb2018-02-20 14:26:16 -08001373
James Feist8f2710a2018-05-09 17:18:55 -07001374 ~PerformScan()
James Feist75fdeeb2018-02-20 14:26:16 -08001375 {
James Feist8f2710a2018-05-09 17:18:55 -07001376 if (_passed)
1377 {
1378 auto nextScan = std::make_shared<PerformScan>(
1379 _systemConfiguration, _configurations, std::move(_callback));
1380 nextScan->run();
1381 }
1382 else
1383 {
1384 _callback();
1385 }
1386 }
James Feista465ccc2019-02-08 12:51:01 -08001387 nlohmann::json& _systemConfiguration;
James Feist8f2710a2018-05-09 17:18:55 -07001388 std::list<nlohmann::json> _configurations;
1389 std::function<void(void)> _callback;
1390 std::vector<std::shared_ptr<PerformProbe>> _probes;
1391 bool _passed = false;
1392};
James Feistc95cb142018-02-26 10:41:42 -08001393
James Feist8f2710a2018-05-09 17:18:55 -07001394// main properties changed entry
1395void propertiesChangedCallback(
James Feista465ccc2019-02-08 12:51:01 -08001396 boost::asio::io_service& io,
1397 std::vector<sdbusplus::bus::match::match>& dbusMatches,
1398 nlohmann::json& systemConfiguration,
1399 sdbusplus::asio::object_server& objServer)
James Feist8f2710a2018-05-09 17:18:55 -07001400{
1401 static boost::asio::deadline_timer timer(io);
1402 timer.expires_from_now(boost::posix_time::seconds(1));
1403
1404 // setup an async wait as we normally get flooded with new requests
James Feista465ccc2019-02-08 12:51:01 -08001405 timer.async_wait([&](const boost::system::error_code& ec) {
James Feist8f2710a2018-05-09 17:18:55 -07001406 if (ec == boost::asio::error::operation_aborted)
1407 {
1408 // we were cancelled
1409 return;
1410 }
1411 else if (ec)
1412 {
1413 std::cerr << "async wait error " << ec << "\n";
1414 return;
1415 }
1416
1417 nlohmann::json oldConfiguration = systemConfiguration;
1418 DBUS_PROBE_OBJECTS.clear();
1419
1420 std::list<nlohmann::json> configurations;
1421 if (!findJsonFiles(configurations))
1422 {
1423 std::cerr << "cannot find json files\n";
1424 return;
1425 }
1426
1427 auto perfScan = std::make_shared<PerformScan>(
1428 systemConfiguration, configurations, [&, oldConfiguration]() {
1429 nlohmann::json newConfiguration = systemConfiguration;
James Feist4131aea2018-03-09 09:47:30 -08001430 for (auto it = newConfiguration.begin();
1431 it != newConfiguration.end();)
1432 {
1433 auto findKey = oldConfiguration.find(it.key());
1434 if (findKey != oldConfiguration.end())
1435 {
1436 it = newConfiguration.erase(it);
1437 }
1438 else
1439 {
1440 it++;
1441 }
1442 }
James Feist8f2710a2018-05-09 17:18:55 -07001443 registerCallbacks(io, dbusMatches, systemConfiguration,
1444 objServer);
1445 io.post([&, newConfiguration]() {
James Feist8f2710a2018-05-09 17:18:55 -07001446 loadOverlays(newConfiguration);
James Feistce4367c2018-10-16 09:19:57 -07001447
James Feistbb43d022018-06-12 15:44:33 -07001448 io.post([&]() {
1449 if (!writeJsonFiles(systemConfiguration))
1450 {
1451 std::cerr << "Error writing json files\n";
1452 }
1453 });
James Feist8f2710a2018-05-09 17:18:55 -07001454 io.post([&, newConfiguration]() {
James Feist97a63f12018-05-17 13:50:57 -07001455 postToDbus(newConfiguration, systemConfiguration,
1456 objServer);
James Feist8f2710a2018-05-09 17:18:55 -07001457 });
1458 });
1459 });
1460 perfScan->run();
1461 });
James Feist75fdeeb2018-02-20 14:26:16 -08001462}
1463
James Feista465ccc2019-02-08 12:51:01 -08001464void registerCallbacks(boost::asio::io_service& io,
1465 std::vector<sdbusplus::bus::match::match>& dbusMatches,
1466 nlohmann::json& systemConfiguration,
1467 sdbusplus::asio::object_server& objServer)
James Feist75fdeeb2018-02-20 14:26:16 -08001468{
1469 static boost::container::flat_set<std::string> watchedObjects;
1470
James Feista465ccc2019-02-08 12:51:01 -08001471 for (const auto& objectMap : DBUS_PROBE_OBJECTS)
James Feist75fdeeb2018-02-20 14:26:16 -08001472 {
1473 auto findObject = watchedObjects.find(objectMap.first);
1474 if (findObject != watchedObjects.end())
1475 {
1476 continue;
1477 }
James Feist8f2710a2018-05-09 17:18:55 -07001478 std::function<void(sdbusplus::message::message & message)>
1479 eventHandler =
James Feist75fdeeb2018-02-20 14:26:16 -08001480
James Feista465ccc2019-02-08 12:51:01 -08001481 [&](sdbusplus::message::message&) {
James Feist8f2710a2018-05-09 17:18:55 -07001482 propertiesChangedCallback(io, dbusMatches,
1483 systemConfiguration, objServer);
1484 };
1485
1486 sdbusplus::bus::match::match match(
James Feista465ccc2019-02-08 12:51:01 -08001487 static_cast<sdbusplus::bus::bus&>(*SYSTEM_BUS),
James Feist8f2710a2018-05-09 17:18:55 -07001488 "type='signal',member='PropertiesChanged',arg0='" +
1489 objectMap.first + "'",
1490 eventHandler);
1491 dbusMatches.emplace_back(std::move(match));
James Feist75fdeeb2018-02-20 14:26:16 -08001492 }
1493}
1494
James Feista465ccc2019-02-08 12:51:01 -08001495int main(int argc, char** argv)
James Feist75fdeeb2018-02-20 14:26:16 -08001496{
1497 // setup connection to dbus
1498 boost::asio::io_service io;
James Feist8f2710a2018-05-09 17:18:55 -07001499 SYSTEM_BUS = std::make_shared<sdbusplus::asio::connection>(io);
James Feist75fdeeb2018-02-20 14:26:16 -08001500 SYSTEM_BUS->request_name("xyz.openbmc_project.EntityManager");
James Feist4131aea2018-03-09 09:47:30 -08001501
James Feist8f2710a2018-05-09 17:18:55 -07001502 sdbusplus::asio::object_server objServer(SYSTEM_BUS);
James Feistfd1264a2018-05-03 12:10:00 -07001503
James Feist8f2710a2018-05-09 17:18:55 -07001504 std::shared_ptr<sdbusplus::asio::dbus_interface> entityIface =
1505 objServer.add_interface("/xyz/openbmc_project/EntityManager",
1506 "xyz.openbmc_project.EntityManager");
James Feistfd1264a2018-05-03 12:10:00 -07001507
James Feist8f2710a2018-05-09 17:18:55 -07001508 std::shared_ptr<sdbusplus::asio::dbus_interface> inventoryIface =
1509 objServer.add_interface("/xyz/openbmc_project/inventory",
1510 "xyz.openbmc_project.Inventory.Manager");
James Feist4131aea2018-03-09 09:47:30 -08001511
1512 // to keep reference to the match / filter objects so they don't get
1513 // destroyed
James Feist8f2710a2018-05-09 17:18:55 -07001514 std::vector<sdbusplus::bus::match::match> dbusMatches;
1515
1516 nlohmann::json systemConfiguration = nlohmann::json::object();
1517
1518 inventoryIface->register_method(
James Feista465ccc2019-02-08 12:51:01 -08001519 "Notify",
1520 [](const boost::container::flat_map<
1521 std::string,
1522 boost::container::flat_map<std::string, BasicVariantType>>&
1523 object) { return; });
James Feist8f2710a2018-05-09 17:18:55 -07001524 inventoryIface->initialize();
1525
1526 io.post([&]() {
James Feistce4367c2018-10-16 09:19:57 -07001527#if OVERLAYS
James Feist8f2710a2018-05-09 17:18:55 -07001528 unloadAllOverlays();
James Feistce4367c2018-10-16 09:19:57 -07001529#endif
James Feist8f2710a2018-05-09 17:18:55 -07001530 propertiesChangedCallback(io, dbusMatches, systemConfiguration,
1531 objServer);
1532 });
James Feist4131aea2018-03-09 09:47:30 -08001533
James Feistfd1264a2018-05-03 12:10:00 -07001534 entityIface->register_method("ReScan", [&]() {
James Feist8f2710a2018-05-09 17:18:55 -07001535 propertiesChangedCallback(io, dbusMatches, systemConfiguration,
1536 objServer);
James Feist75fdeeb2018-02-20 14:26:16 -08001537 });
James Feist8f2710a2018-05-09 17:18:55 -07001538 entityIface->initialize();
1539
James Feist1b2e2242018-01-30 13:45:19 -08001540 io.run();
James Feist3cb5fec2018-01-23 14:41:51 -08001541
1542 return 0;
James Feist75fdeeb2018-02-20 14:26:16 -08001543}