blob: cb1272be83e4c21f4e96da6d89d110e1e70c9245 [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 Feist41334262019-03-25 13:30:20 -070073static constexpr std::array<const char*, 5> settableInterfaces = {
74 "FanProfile", "Pid", "Pid.Zone", "Stepwise", "Thresholds"};
James Feist68500ff2018-08-08 15:40:42 -070075using JsonVariantType =
James Feist338b8a72019-03-01 10:16:45 -080076 std::variant<std::vector<std::string>, std::vector<double>, std::string,
77 int64_t, uint64_t, double, int32_t, uint32_t, int16_t,
78 uint16_t, uint8_t, bool>;
James Feist8f2710a2018-05-09 17:18:55 -070079using BasicVariantType =
James Feista465ccc2019-02-08 12:51:01 -080080 std::variant<std::string, int64_t, uint64_t, double, int32_t, uint32_t,
81 int16_t, uint16_t, uint8_t, bool>;
James Feist8f2710a2018-05-09 17:18:55 -070082
James Feist3cb5fec2018-01-23 14:41:51 -080083using GetSubTreeType = std::vector<
84 std::pair<std::string,
85 std::vector<std::pair<std::string, std::vector<std::string>>>>>;
86
87using ManagedObjectType = boost::container::flat_map<
James Feist8f2710a2018-05-09 17:18:55 -070088 sdbusplus::message::object_path,
James Feist3cb5fec2018-01-23 14:41:51 -080089 boost::container::flat_map<
90 std::string,
James Feist8f2710a2018-05-09 17:18:55 -070091 boost::container::flat_map<std::string, BasicVariantType>>>;
James Feist3cb5fec2018-01-23 14:41:51 -080092
93boost::container::flat_map<
94 std::string,
James Feist8f2710a2018-05-09 17:18:55 -070095 std::vector<boost::container::flat_map<std::string, BasicVariantType>>>
James Feist3cb5fec2018-01-23 14:41:51 -080096 DBUS_PROBE_OBJECTS;
97std::vector<std::string> PASSED_PROBES;
98
99// todo: pass this through nicer
James Feist8f2710a2018-05-09 17:18:55 -0700100std::shared_ptr<sdbusplus::asio::connection> SYSTEM_BUS;
James Feist3cb5fec2018-01-23 14:41:51 -0800101
James Feista6750242018-07-16 14:12:27 -0700102const std::regex ILLEGAL_DBUS_REGEX("[^A-Za-z0-9_.]");
James Feist1b2e2242018-01-30 13:45:19 -0800103
James Feista465ccc2019-02-08 12:51:01 -0800104void registerCallbacks(boost::asio::io_service& io,
105 std::vector<sdbusplus::bus::match::match>& dbusMatches,
106 nlohmann::json& systemConfiguration,
107 sdbusplus::asio::object_server& objServer);
James Feist75fdeeb2018-02-20 14:26:16 -0800108
James Feist3cb5fec2018-01-23 14:41:51 -0800109// calls the mapper to find all exposed objects of an interface type
110// and creates a vector<flat_map> that contains all the key value pairs
111// getManagedObjects
James Feist8f2710a2018-05-09 17:18:55 -0700112void findDbusObjects(std::shared_ptr<PerformProbe> probe,
113 std::shared_ptr<sdbusplus::asio::connection> connection,
James Feista465ccc2019-02-08 12:51:01 -0800114 std::string& interface)
James Feist3cb5fec2018-01-23 14:41:51 -0800115{
James Feist8f2710a2018-05-09 17:18:55 -0700116
117 // store reference to pending callbacks so we don't overwhelm services
118 static boost::container::flat_map<
119 std::string, std::vector<std::shared_ptr<PerformProbe>>>
120 pendingProbes;
121
122 if (DBUS_PROBE_OBJECTS[interface].size())
123 {
124 return;
125 }
126
127 // add shared_ptr to vector of Probes waiting for callback from a specific
128 // interface to keep alive while waiting for response
James Feista465ccc2019-02-08 12:51:01 -0800129 std::array<const char*, 1> objects = {interface.c_str()};
130 std::vector<std::shared_ptr<PerformProbe>>& pending =
James Feist8f2710a2018-05-09 17:18:55 -0700131 pendingProbes[interface];
132 auto iter = pending.emplace(pending.end(), probe);
133 // only allow first call to run to not overwhelm processes
134 if (iter != pending.begin())
135 {
136 return;
137 }
138
James Feist3cb5fec2018-01-23 14:41:51 -0800139 // find all connections in the mapper that expose a specific type
James Feist8f2710a2018-05-09 17:18:55 -0700140 connection->async_method_call(
James Feista465ccc2019-02-08 12:51:01 -0800141 [connection, interface, probe](boost::system::error_code& ec,
142 const GetSubTreeType& interfaceSubtree) {
James Feist0de40152018-07-25 11:56:12 -0700143 boost::container::flat_set<std::string> interfaceConnections;
James Feist8f2710a2018-05-09 17:18:55 -0700144 if (ec)
James Feist494155a2018-03-14 16:23:24 -0700145 {
James Feist0de40152018-07-25 11:56:12 -0700146 pendingProbes[interface].clear();
147 if (ec.value() == ENOENT)
James Feist8f2710a2018-05-09 17:18:55 -0700148 {
James Feist0de40152018-07-25 11:56:12 -0700149 return; // wasn't found by mapper
James Feist8f2710a2018-05-09 17:18:55 -0700150 }
James Feist0de40152018-07-25 11:56:12 -0700151 std::cerr << "Error communicating to mapper.\n";
152
153 // if we can't communicate to the mapper something is very wrong
154 std::exit(EXIT_FAILURE);
James Feist494155a2018-03-14 16:23:24 -0700155 }
James Feist8f2710a2018-05-09 17:18:55 -0700156 else
James Feist3cb5fec2018-01-23 14:41:51 -0800157 {
James Feista465ccc2019-02-08 12:51:01 -0800158 for (auto& object : interfaceSubtree)
James Feist8f2710a2018-05-09 17:18:55 -0700159 {
James Feista465ccc2019-02-08 12:51:01 -0800160 for (auto& connPair : object.second)
James Feist8f2710a2018-05-09 17:18:55 -0700161 {
162 auto insertPair =
163 interfaceConnections.insert(connPair.first);
164 }
165 }
James Feist3cb5fec2018-01-23 14:41:51 -0800166 }
James Feist63845bf2019-01-24 12:19:51 -0800167 if (interfaceConnections.empty())
168 {
169 pendingProbes[interface].clear();
170 return;
171 }
James Feist8f2710a2018-05-09 17:18:55 -0700172 // get managed objects for all interfaces
James Feista465ccc2019-02-08 12:51:01 -0800173 for (const auto& conn : interfaceConnections)
James Feist8f2710a2018-05-09 17:18:55 -0700174 {
175 connection->async_method_call(
James Feist0de40152018-07-25 11:56:12 -0700176 [conn,
James Feista465ccc2019-02-08 12:51:01 -0800177 interface](boost::system::error_code& ec,
178 const ManagedObjectType& managedInterface) {
James Feist8f2710a2018-05-09 17:18:55 -0700179 if (ec)
180 {
181 std::cerr
182 << "error getting managed object for device "
183 << conn << "\n";
184 pendingProbes[interface].clear();
185 return;
186 }
James Feista465ccc2019-02-08 12:51:01 -0800187 for (auto& interfaceManagedObj : managedInterface)
James Feist8f2710a2018-05-09 17:18:55 -0700188 {
189 auto ifaceObjFind =
190 interfaceManagedObj.second.find(interface);
191 if (ifaceObjFind !=
192 interfaceManagedObj.second.end())
193 {
194 std::vector<boost::container::flat_map<
James Feista465ccc2019-02-08 12:51:01 -0800195 std::string, BasicVariantType>>&
196 dbusObject = DBUS_PROBE_OBJECTS[interface];
James Feist8f2710a2018-05-09 17:18:55 -0700197 dbusObject.emplace_back(ifaceObjFind->second);
198 }
199 }
200 pendingProbes[interface].clear();
201 },
202 conn.c_str(), "/", "org.freedesktop.DBus.ObjectManager",
203 "GetManagedObjects");
204 }
205 },
206 "xyz.openbmc_project.ObjectMapper",
207 "/xyz/openbmc_project/object_mapper",
James Feist5131ac22018-10-25 12:22:23 -0700208 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", MAX_MAPPER_DEPTH,
James Feist8f2710a2018-05-09 17:18:55 -0700209 objects);
James Feist3cb5fec2018-01-23 14:41:51 -0800210}
James Feist8f2710a2018-05-09 17:18:55 -0700211// probes dbus interface dictionary for a key with a value that matches a regex
James Feist3cb5fec2018-01-23 14:41:51 -0800212bool probeDbus(
James Feista465ccc2019-02-08 12:51:01 -0800213 const std::string& interface,
214 const std::map<std::string, nlohmann::json>& matches,
215 std::vector<boost::container::flat_map<std::string, BasicVariantType>>&
216 devices,
217 bool& foundProbe)
James Feist3cb5fec2018-01-23 14:41:51 -0800218{
James Feista465ccc2019-02-08 12:51:01 -0800219 std::vector<boost::container::flat_map<std::string, BasicVariantType>>&
220 dbusObject = DBUS_PROBE_OBJECTS[interface];
James Feist3cb5fec2018-01-23 14:41:51 -0800221 if (dbusObject.empty())
222 {
James Feist8f2710a2018-05-09 17:18:55 -0700223 foundProbe = false;
224 return false;
James Feist3cb5fec2018-01-23 14:41:51 -0800225 }
226 foundProbe = true;
227
228 bool foundMatch = false;
James Feista465ccc2019-02-08 12:51:01 -0800229 for (auto& device : dbusObject)
James Feist3cb5fec2018-01-23 14:41:51 -0800230 {
231 bool deviceMatches = true;
James Feista465ccc2019-02-08 12:51:01 -0800232 for (auto& match : matches)
James Feist3cb5fec2018-01-23 14:41:51 -0800233 {
234 auto deviceValue = device.find(match.first);
235 if (deviceValue != device.end())
236 {
237 switch (match.second.type())
238 {
James Feist9eb0b582018-04-27 12:15:46 -0700239 case nlohmann::json::value_t::string:
James Feist3cb5fec2018-01-23 14:41:51 -0800240 {
James Feist9eb0b582018-04-27 12:15:46 -0700241 std::regex search(match.second.get<std::string>());
242 std::smatch match;
243
244 // convert value to string respresentation
James Feista465ccc2019-02-08 12:51:01 -0800245 std::string probeValue = std::visit(
James Feist8f2710a2018-05-09 17:18:55 -0700246 VariantToStringVisitor(), deviceValue->second);
James Feist9eb0b582018-04-27 12:15:46 -0700247 if (!std::regex_search(probeValue, match, search))
248 {
249 deviceMatches = false;
250 break;
251 }
James Feist3cb5fec2018-01-23 14:41:51 -0800252 break;
253 }
James Feist9eb0b582018-04-27 12:15:46 -0700254 case nlohmann::json::value_t::boolean:
255 case nlohmann::json::value_t::number_unsigned:
James Feist3cb5fec2018-01-23 14:41:51 -0800256 {
James Feista465ccc2019-02-08 12:51:01 -0800257 unsigned int probeValue = std::visit(
James Feist9eb0b582018-04-27 12:15:46 -0700258 VariantToUnsignedIntVisitor(), deviceValue->second);
James Feist3cb5fec2018-01-23 14:41:51 -0800259
James Feist9eb0b582018-04-27 12:15:46 -0700260 if (probeValue != match.second.get<unsigned 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_integer:
267 {
James Feista465ccc2019-02-08 12:51:01 -0800268 int probeValue = std::visit(VariantToIntVisitor(),
269 deviceValue->second);
James Feist3cb5fec2018-01-23 14:41:51 -0800270
James Feist9eb0b582018-04-27 12:15:46 -0700271 if (probeValue != match.second.get<int>())
272 {
273 deviceMatches = false;
274 }
275 break;
James Feist3cb5fec2018-01-23 14:41:51 -0800276 }
James Feist9eb0b582018-04-27 12:15:46 -0700277 case nlohmann::json::value_t::number_float:
278 {
James Feista465ccc2019-02-08 12:51:01 -0800279 float probeValue = std::visit(VariantToFloatVisitor(),
280 deviceValue->second);
James Feist9eb0b582018-04-27 12:15:46 -0700281
282 if (probeValue != match.second.get<float>())
283 {
284 deviceMatches = false;
285 }
286 break;
287 }
James Feist3cb5fec2018-01-23 14:41:51 -0800288 }
289 }
290 else
291 {
292 deviceMatches = false;
293 break;
294 }
295 }
296 if (deviceMatches)
297 {
298 devices.emplace_back(
James Feist8f2710a2018-05-09 17:18:55 -0700299 boost::container::flat_map<std::string, BasicVariantType>(
James Feist3cb5fec2018-01-23 14:41:51 -0800300 device));
301 foundMatch = true;
302 deviceMatches = false; // for next iteration
303 }
304 }
305 return foundMatch;
306}
307
308// default probe entry point, iterates a list looking for specific types to
309// call specific probe functions
310bool probe(
James Feista465ccc2019-02-08 12:51:01 -0800311 const std::vector<std::string>& probeCommand,
312 std::vector<boost::container::flat_map<std::string, BasicVariantType>>&
313 foundDevs)
James Feist3cb5fec2018-01-23 14:41:51 -0800314{
315 const static std::regex command(R"(\((.*)\))");
316 std::smatch match;
317 bool ret = false;
James Feist6bd2a022018-03-13 12:30:58 -0700318 bool matchOne = false;
James Feist3cb5fec2018-01-23 14:41:51 -0800319 bool cur = true;
320 probe_type_codes lastCommand = probe_type_codes::FALSE_T;
321
James Feista465ccc2019-02-08 12:51:01 -0800322 for (auto& probe : probeCommand)
James Feist3cb5fec2018-01-23 14:41:51 -0800323 {
324 bool foundProbe = false;
James Feista465ccc2019-02-08 12:51:01 -0800325 boost::container::flat_map<const char*, probe_type_codes,
James Feist3cb5fec2018-01-23 14:41:51 -0800326 cmp_str>::const_iterator probeType;
327
328 for (probeType = PROBE_TYPES.begin(); probeType != PROBE_TYPES.end();
329 probeType++)
330 {
331 if (probe.find(probeType->first) != std::string::npos)
332 {
333 foundProbe = true;
334 break;
335 }
336 }
337 if (foundProbe)
338 {
339 switch (probeType->second)
340 {
James Feist9eb0b582018-04-27 12:15:46 -0700341 case probe_type_codes::FALSE_T:
James Feist3cb5fec2018-01-23 14:41:51 -0800342 {
James Feist8f2710a2018-05-09 17:18:55 -0700343 return false;
James Feist9eb0b582018-04-27 12:15:46 -0700344 break;
James Feist3cb5fec2018-01-23 14:41:51 -0800345 }
James Feist9eb0b582018-04-27 12:15:46 -0700346 case probe_type_codes::TRUE_T:
347 {
James Feist8f2710a2018-05-09 17:18:55 -0700348 return true;
James Feist9eb0b582018-04-27 12:15:46 -0700349 break;
350 }
351 case probe_type_codes::MATCH_ONE:
352 {
353 // set current value to last, this probe type shouldn't
354 // affect the outcome
355 cur = ret;
356 matchOne = true;
357 break;
358 }
359 /*case probe_type_codes::AND:
360 break;
361 case probe_type_codes::OR:
362 break;
363 // these are no-ops until the last command switch
364 */
365 case probe_type_codes::FOUND:
366 {
367 if (!std::regex_search(probe, match, command))
368 {
369 std::cerr << "found probe sytax error " << probe
370 << "\n";
371 return false;
372 }
373 std::string commandStr = *(match.begin() + 1);
374 boost::replace_all(commandStr, "'", "");
375 cur = (std::find(PASSED_PROBES.begin(), PASSED_PROBES.end(),
376 commandStr) != PASSED_PROBES.end());
377 break;
378 }
James Feist3cb5fec2018-01-23 14:41:51 -0800379 }
380 }
381 // look on dbus for object
382 else
383 {
384 if (!std::regex_search(probe, match, command))
385 {
386 std::cerr << "dbus probe sytax error " << probe << "\n";
387 return false;
388 }
389 std::string commandStr = *(match.begin() + 1);
390 // convert single ticks and single slashes into legal json
Jae Hyun Yoo3936e7a2018-03-23 17:26:16 -0700391 boost::replace_all(commandStr, "'", "\"");
James Feist3f8a2782018-02-12 09:24:42 -0800392 boost::replace_all(commandStr, R"(\)", R"(\\)");
James Feist3cb5fec2018-01-23 14:41:51 -0800393 auto json = nlohmann::json::parse(commandStr, nullptr, false);
394 if (json.is_discarded())
395 {
396 std::cerr << "dbus command sytax error " << commandStr << "\n";
397 return false;
398 }
399 // we can match any (string, variant) property. (string, string)
400 // does a regex
401 std::map<std::string, nlohmann::json> dbusProbeMap =
402 json.get<std::map<std::string, nlohmann::json>>();
403 auto findStart = probe.find("(");
404 if (findStart == std::string::npos)
405 {
406 return false;
407 }
408 std::string probeInterface = probe.substr(0, findStart);
409 cur =
410 probeDbus(probeInterface, dbusProbeMap, foundDevs, foundProbe);
411 }
412
413 // some functions like AND and OR only take affect after the
414 // fact
415 switch (lastCommand)
416 {
James Feist9eb0b582018-04-27 12:15:46 -0700417 case probe_type_codes::AND:
418 ret = cur && ret;
419 break;
420 case probe_type_codes::OR:
421 ret = cur || ret;
422 break;
423 default:
424 ret = cur;
425 break;
James Feist3cb5fec2018-01-23 14:41:51 -0800426 }
427 lastCommand = probeType != PROBE_TYPES.end()
428 ? probeType->second
429 : probe_type_codes::FALSE_T;
James Feist3cb5fec2018-01-23 14:41:51 -0800430 }
431
432 // probe passed, but empty device
James Feist3cb5fec2018-01-23 14:41:51 -0800433 if (ret && foundDevs.size() == 0)
434 {
435 foundDevs.emplace_back(
James Feist8f2710a2018-05-09 17:18:55 -0700436 boost::container::flat_map<std::string, BasicVariantType>());
James Feist3cb5fec2018-01-23 14:41:51 -0800437 }
James Feist6bd2a022018-03-13 12:30:58 -0700438 if (matchOne && foundDevs.size() > 1)
439 {
440 foundDevs.erase(foundDevs.begin() + 1, foundDevs.end());
441 }
James Feist3cb5fec2018-01-23 14:41:51 -0800442 return ret;
443}
James Feist8f2710a2018-05-09 17:18:55 -0700444// this class finds the needed dbus fields and on destruction runs the probe
445struct PerformProbe : std::enable_shared_from_this<PerformProbe>
446{
James Feist3cb5fec2018-01-23 14:41:51 -0800447
James Feist8f2710a2018-05-09 17:18:55 -0700448 PerformProbe(
James Feista465ccc2019-02-08 12:51:01 -0800449 const std::vector<std::string>& probeCommand,
James Feist8f2710a2018-05-09 17:18:55 -0700450 std::function<void(std::vector<boost::container::flat_map<
James Feista465ccc2019-02-08 12:51:01 -0800451 std::string, BasicVariantType>>&)>&& callback) :
James Feist8f2710a2018-05-09 17:18:55 -0700452 _probeCommand(probeCommand),
453 _callback(std::move(callback))
454 {
455 }
456 ~PerformProbe()
457 {
458 if (probe(_probeCommand, _foundDevs))
459 {
460 _callback(_foundDevs);
461 }
462 }
463 void run()
464 {
465 // parse out dbus probes by discarding other probe types
James Feista465ccc2019-02-08 12:51:01 -0800466 boost::container::flat_map<const char*, probe_type_codes,
James Feist8f2710a2018-05-09 17:18:55 -0700467 cmp_str>::const_iterator probeType;
468
469 std::vector<std::string> dbusProbes;
James Feista465ccc2019-02-08 12:51:01 -0800470 for (std::string& probe : _probeCommand)
James Feist8f2710a2018-05-09 17:18:55 -0700471 {
472 bool found = false;
James Feista465ccc2019-02-08 12:51:01 -0800473 boost::container::flat_map<const char*, probe_type_codes,
James Feist8f2710a2018-05-09 17:18:55 -0700474 cmp_str>::const_iterator probeType;
475 for (probeType = PROBE_TYPES.begin();
476 probeType != PROBE_TYPES.end(); probeType++)
477 {
478 if (probe.find(probeType->first) != std::string::npos)
479 {
480 found = true;
481 break;
482 }
483 }
484 if (found)
485 {
486 continue;
487 }
488 // syntax requires probe before first open brace
489 auto findStart = probe.find("(");
490 std::string interface = probe.substr(0, findStart);
491
492 findDbusObjects(shared_from_this(), SYSTEM_BUS, interface);
493 }
494 }
495 std::vector<std::string> _probeCommand;
James Feista465ccc2019-02-08 12:51:01 -0800496 std::function<void(std::vector<boost::container::flat_map<
497 std::string, BasicVariantType>>&)>
James Feist8f2710a2018-05-09 17:18:55 -0700498 _callback;
499 std::vector<boost::container::flat_map<std::string, BasicVariantType>>
500 _foundDevs;
501};
502
503// writes output files to persist data
James Feista465ccc2019-02-08 12:51:01 -0800504bool writeJsonFiles(const nlohmann::json& systemConfiguration)
James Feist1b2e2242018-01-30 13:45:19 -0800505{
Ed Tanous072e25d2018-12-16 21:45:20 -0800506 std::filesystem::create_directory(OUTPUT_DIR);
James Feist1b2e2242018-01-30 13:45:19 -0800507 std::ofstream output(std::string(OUTPUT_DIR) + "system.json");
James Feistbb43d022018-06-12 15:44:33 -0700508 if (!output.good())
509 {
510 return false;
511 }
James Feist1b2e2242018-01-30 13:45:19 -0800512 output << systemConfiguration.dump(4);
513 output.close();
James Feistbb43d022018-06-12 15:44:33 -0700514 return true;
James Feist8f2710a2018-05-09 17:18:55 -0700515}
James Feist1b2e2242018-01-30 13:45:19 -0800516
James Feist8f2710a2018-05-09 17:18:55 -0700517// template function to add array as dbus property
518template <typename PropertyType>
James Feista465ccc2019-02-08 12:51:01 -0800519void addArrayToDbus(const std::string& name, const nlohmann::json& array,
520 sdbusplus::asio::dbus_interface* iface,
James Feistbb43d022018-06-12 15:44:33 -0700521 sdbusplus::asio::PropertyPermission permission)
James Feist8f2710a2018-05-09 17:18:55 -0700522{
523 std::vector<PropertyType> values;
James Feista465ccc2019-02-08 12:51:01 -0800524 for (const auto& property : array)
James Feist1b2e2242018-01-30 13:45:19 -0800525 {
James Feista465ccc2019-02-08 12:51:01 -0800526 auto ptr = property.get_ptr<const PropertyType*>();
James Feist8f2710a2018-05-09 17:18:55 -0700527 if (ptr != nullptr)
James Feist1b2e2242018-01-30 13:45:19 -0800528 {
James Feist8f2710a2018-05-09 17:18:55 -0700529 values.emplace_back(*ptr);
James Feist1b2e2242018-01-30 13:45:19 -0800530 }
531 }
James Feistbb43d022018-06-12 15:44:33 -0700532 // todo(james), currently there are no reason to persist arrays, get around
533 // to it if needed
534
535 iface->register_property(name, values, permission);
James Feist1b2e2242018-01-30 13:45:19 -0800536}
James Feist97a63f12018-05-17 13:50:57 -0700537
538template <typename JsonType>
James Feista465ccc2019-02-08 12:51:01 -0800539bool setJsonFromPointer(const std::string& ptrStr, const JsonType& value,
540 nlohmann::json& systemConfiguration)
James Feist97a63f12018-05-17 13:50:57 -0700541{
542 try
543 {
544 nlohmann::json::json_pointer ptr(ptrStr);
James Feista465ccc2019-02-08 12:51:01 -0800545 nlohmann::json& ref = systemConfiguration[ptr];
James Feist97a63f12018-05-17 13:50:57 -0700546 ref = value;
547 return true;
548 }
549 catch (const std::out_of_range)
550 {
551 return false;
552 }
553}
James Feistbb43d022018-06-12 15:44:33 -0700554
555template <typename PropertyType>
James Feista465ccc2019-02-08 12:51:01 -0800556void addProperty(const std::string& propertyName, const PropertyType& value,
557 sdbusplus::asio::dbus_interface* iface,
558 nlohmann::json& systemConfiguration,
559 const std::string& jsonPointerString,
James Feistbb43d022018-06-12 15:44:33 -0700560 sdbusplus::asio::PropertyPermission permission)
561{
562 if (permission == sdbusplus::asio::PropertyPermission::readOnly)
563 {
564 iface->register_property(propertyName, value);
565 return;
566 }
James Feist68500ff2018-08-08 15:40:42 -0700567 iface->register_property(
568 propertyName, value,
569 [&systemConfiguration,
570 jsonPointerString{std::string(jsonPointerString)}](
James Feista465ccc2019-02-08 12:51:01 -0800571 const PropertyType& newVal, PropertyType& val) {
James Feist68500ff2018-08-08 15:40:42 -0700572 val = newVal;
573 if (!setJsonFromPointer(jsonPointerString, val,
574 systemConfiguration))
575 {
576 std::cerr << "error setting json field\n";
577 return -1;
578 }
James Feistc6248a52018-08-14 10:09:45 -0700579 if (!writeJsonFiles(systemConfiguration))
James Feist68500ff2018-08-08 15:40:42 -0700580 {
581 std::cerr << "error setting json file\n";
James Feistc6248a52018-08-14 10:09:45 -0700582 return -1;
583 }
584 return 1;
585 });
586}
587
588void createDeleteObjectMethod(
James Feista465ccc2019-02-08 12:51:01 -0800589 const std::string& jsonPointerPath,
590 const std::shared_ptr<sdbusplus::asio::dbus_interface>& iface,
591 sdbusplus::asio::object_server& objServer,
592 nlohmann::json& systemConfiguration)
James Feistc6248a52018-08-14 10:09:45 -0700593{
594 std::weak_ptr<sdbusplus::asio::dbus_interface> interface = iface;
595 iface->register_method(
596 "Delete", [&objServer, &systemConfiguration, interface,
597 jsonPointerPath{std::string(jsonPointerPath)}]() {
598 std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
599 interface.lock();
600 if (!iface)
601 {
602 // this technically can't happen as the pointer is pointing to
603 // us
604 throw DBusInternalError();
605 }
606 nlohmann::json::json_pointer ptr(jsonPointerPath);
607 if (!objServer.remove_interface(iface))
608 {
609 std::cerr << "Can't delete interface " << jsonPointerPath
610 << "\n";
611 throw DBusInternalError();
612 }
613 systemConfiguration[ptr] = nullptr;
614
615 if (!writeJsonFiles(systemConfiguration))
616 {
617 std::cerr << "error setting json file\n";
618 throw DBusInternalError();
James Feist68500ff2018-08-08 15:40:42 -0700619 }
James Feistbb43d022018-06-12 15:44:33 -0700620 return -1;
James Feist68500ff2018-08-08 15:40:42 -0700621 });
James Feistbb43d022018-06-12 15:44:33 -0700622}
623
James Feist1b2e2242018-01-30 13:45:19 -0800624// adds simple json types to interface's properties
James Feistbb43d022018-06-12 15:44:33 -0700625void populateInterfaceFromJson(
James Feista465ccc2019-02-08 12:51:01 -0800626 nlohmann::json& systemConfiguration, const std::string& jsonPointerPath,
627 std::shared_ptr<sdbusplus::asio::dbus_interface>& iface,
628 nlohmann::json& dict, sdbusplus::asio::object_server& objServer,
James Feistbb43d022018-06-12 15:44:33 -0700629 sdbusplus::asio::PropertyPermission permission =
630 sdbusplus::asio::PropertyPermission::readOnly)
James Feist1b2e2242018-01-30 13:45:19 -0800631{
James Feista465ccc2019-02-08 12:51:01 -0800632 for (auto& dictPair : dict.items())
James Feist1b2e2242018-01-30 13:45:19 -0800633 {
James Feist8f2710a2018-05-09 17:18:55 -0700634 auto type = dictPair.value().type();
635 bool array = false;
636 if (dictPair.value().type() == nlohmann::json::value_t::array)
637 {
638 array = true;
639 if (!dictPair.value().size())
640 {
641 continue;
642 }
643 type = dictPair.value()[0].type();
644 bool isLegal = true;
James Feista465ccc2019-02-08 12:51:01 -0800645 for (const auto& arrayItem : dictPair.value())
James Feist8f2710a2018-05-09 17:18:55 -0700646 {
647 if (arrayItem.type() != type)
648 {
649 isLegal = false;
650 break;
651 }
652 }
653 if (!isLegal)
654 {
655 std::cerr << "dbus format error" << dictPair.value() << "\n";
656 continue;
657 }
658 if (type == nlohmann::json::value_t::object)
659 {
660 continue; // handled elsewhere
661 }
662 }
James Feist97a63f12018-05-17 13:50:57 -0700663 std::string key = jsonPointerPath + "/" + dictPair.key();
James Feistbb43d022018-06-12 15:44:33 -0700664 if (permission == sdbusplus::asio::PropertyPermission::readWrite)
665 {
666 // all setable numbers are doubles as it is difficult to always
667 // create a configuration file with all whole numbers as decimals
668 // i.e. 1.0
669 if (dictPair.value().is_number())
670 {
671 type = nlohmann::json::value_t::number_float;
672 }
673 }
674
James Feist8f2710a2018-05-09 17:18:55 -0700675 switch (type)
James Feist1b2e2242018-01-30 13:45:19 -0800676 {
James Feist9eb0b582018-04-27 12:15:46 -0700677 case (nlohmann::json::value_t::boolean):
678 {
James Feist8f2710a2018-05-09 17:18:55 -0700679 if (array)
680 {
681 // todo: array of bool isn't detected correctly by
682 // sdbusplus, change it to numbers
683 addArrayToDbus<uint64_t>(dictPair.key(), dictPair.value(),
James Feistc6248a52018-08-14 10:09:45 -0700684 iface.get(), permission);
James Feist8f2710a2018-05-09 17:18:55 -0700685 }
James Feistbb43d022018-06-12 15:44:33 -0700686
James Feist97a63f12018-05-17 13:50:57 -0700687 else
688 {
James Feistbb43d022018-06-12 15:44:33 -0700689 addProperty(dictPair.key(), dictPair.value().get<bool>(),
James Feistc6248a52018-08-14 10:09:45 -0700690 iface.get(), systemConfiguration, key,
691 permission);
James Feist97a63f12018-05-17 13:50:57 -0700692 }
James Feist9eb0b582018-04-27 12:15:46 -0700693 break;
694 }
695 case (nlohmann::json::value_t::number_integer):
696 {
James Feist8f2710a2018-05-09 17:18:55 -0700697 if (array)
698 {
699 addArrayToDbus<int64_t>(dictPair.key(), dictPair.value(),
James Feistc6248a52018-08-14 10:09:45 -0700700 iface.get(), permission);
James Feist97a63f12018-05-17 13:50:57 -0700701 }
702 else
703 {
James Feistbb43d022018-06-12 15:44:33 -0700704 addProperty(dictPair.key(), dictPair.value().get<int64_t>(),
James Feistc6248a52018-08-14 10:09:45 -0700705 iface.get(), systemConfiguration, key,
James Feistbb43d022018-06-12 15:44:33 -0700706 sdbusplus::asio::PropertyPermission::readOnly);
James Feist97a63f12018-05-17 13:50:57 -0700707 }
James Feist9eb0b582018-04-27 12:15:46 -0700708 break;
709 }
710 case (nlohmann::json::value_t::number_unsigned):
711 {
James Feist8f2710a2018-05-09 17:18:55 -0700712 if (array)
713 {
714 addArrayToDbus<uint64_t>(dictPair.key(), dictPair.value(),
James Feistc6248a52018-08-14 10:09:45 -0700715 iface.get(), permission);
James Feist97a63f12018-05-17 13:50:57 -0700716 }
717 else
718 {
James Feistbb43d022018-06-12 15:44:33 -0700719 addProperty(dictPair.key(),
James Feistc6248a52018-08-14 10:09:45 -0700720 dictPair.value().get<uint64_t>(), iface.get(),
James Feistbb43d022018-06-12 15:44:33 -0700721 systemConfiguration, key,
722 sdbusplus::asio::PropertyPermission::readOnly);
James Feist97a63f12018-05-17 13:50:57 -0700723 }
James Feist9eb0b582018-04-27 12:15:46 -0700724 break;
725 }
726 case (nlohmann::json::value_t::number_float):
727 {
James Feist8f2710a2018-05-09 17:18:55 -0700728 if (array)
729 {
730 addArrayToDbus<double>(dictPair.key(), dictPair.value(),
James Feistc6248a52018-08-14 10:09:45 -0700731 iface.get(), permission);
James Feist8f2710a2018-05-09 17:18:55 -0700732 }
James Feistbb43d022018-06-12 15:44:33 -0700733
James Feist97a63f12018-05-17 13:50:57 -0700734 else
735 {
James Feistbb43d022018-06-12 15:44:33 -0700736 addProperty(dictPair.key(), dictPair.value().get<double>(),
James Feistc6248a52018-08-14 10:09:45 -0700737 iface.get(), systemConfiguration, key,
738 permission);
James Feist97a63f12018-05-17 13:50:57 -0700739 }
James Feist9eb0b582018-04-27 12:15:46 -0700740 break;
741 }
742 case (nlohmann::json::value_t::string):
743 {
James Feist8f2710a2018-05-09 17:18:55 -0700744 if (array)
745 {
James Feistc6248a52018-08-14 10:09:45 -0700746 addArrayToDbus<std::string>(dictPair.key(),
747 dictPair.value(), iface.get(),
748 permission);
James Feist97a63f12018-05-17 13:50:57 -0700749 }
750 else
751 {
James Feistc6248a52018-08-14 10:09:45 -0700752 addProperty(
753 dictPair.key(), dictPair.value().get<std::string>(),
754 iface.get(), systemConfiguration, key, permission);
James Feist97a63f12018-05-17 13:50:57 -0700755 }
James Feist9eb0b582018-04-27 12:15:46 -0700756 break;
757 }
James Feist1b2e2242018-01-30 13:45:19 -0800758 }
759 }
James Feistc6248a52018-08-14 10:09:45 -0700760 if (permission == sdbusplus::asio::PropertyPermission::readWrite)
761 {
762 createDeleteObjectMethod(jsonPointerPath, iface, objServer,
763 systemConfiguration);
764 }
James Feist8f2710a2018-05-09 17:18:55 -0700765 iface->initialize();
James Feist1b2e2242018-01-30 13:45:19 -0800766}
767
James Feista465ccc2019-02-08 12:51:01 -0800768sdbusplus::asio::PropertyPermission getPermission(const std::string& interface)
James Feistc6248a52018-08-14 10:09:45 -0700769{
770 return std::find(settableInterfaces.begin(), settableInterfaces.end(),
771 interface) != settableInterfaces.end()
772 ? sdbusplus::asio::PropertyPermission::readWrite
773 : sdbusplus::asio::PropertyPermission::readOnly;
774}
775
James Feista465ccc2019-02-08 12:51:01 -0800776void createAddObjectMethod(const std::string& jsonPointerPath,
777 const std::string& path,
778 nlohmann::json& systemConfiguration,
779 sdbusplus::asio::object_server& objServer)
James Feist68500ff2018-08-08 15:40:42 -0700780{
781 auto iface = objServer.add_interface(path, "xyz.openbmc_project.AddObject");
782
783 iface->register_method(
784 "AddObject",
785 [&systemConfiguration, &objServer,
786 jsonPointerPath{std::string(jsonPointerPath)},
787 path{std::string(path)}](
James Feista465ccc2019-02-08 12:51:01 -0800788 const boost::container::flat_map<std::string, JsonVariantType>&
789 data) {
James Feist68500ff2018-08-08 15:40:42 -0700790 nlohmann::json::json_pointer ptr(jsonPointerPath);
James Feista465ccc2019-02-08 12:51:01 -0800791 nlohmann::json& base = systemConfiguration[ptr];
James Feist68500ff2018-08-08 15:40:42 -0700792 auto findExposes = base.find("Exposes");
793
794 if (findExposes == base.end())
795 {
796 throw std::invalid_argument("Entity must have children.");
797 }
798
799 // this will throw invalid-argument to sdbusplus if invalid json
800 nlohmann::json newData{};
James Feista465ccc2019-02-08 12:51:01 -0800801 for (const auto& item : data)
James Feist68500ff2018-08-08 15:40:42 -0700802 {
James Feista465ccc2019-02-08 12:51:01 -0800803 nlohmann::json& newJson = newData[item.first];
804 std::visit([&newJson](auto&& val) { newJson = std::move(val); },
805 item.second);
James Feist68500ff2018-08-08 15:40:42 -0700806 }
807
808 auto findName = newData.find("Name");
809 auto findType = newData.find("Type");
810 if (findName == newData.end() || findType == newData.end())
811 {
812 throw std::invalid_argument("AddObject missing Name or Type");
813 }
James Feista465ccc2019-02-08 12:51:01 -0800814 const std::string* type = findType->get_ptr<const std::string*>();
815 const std::string* name = findName->get_ptr<const std::string*>();
James Feist68500ff2018-08-08 15:40:42 -0700816 if (type == nullptr || name == nullptr)
817 {
818 throw std::invalid_argument("Type and Name must be a string.");
819 }
820
821 size_t lastIndex = 0;
822 // we add in the "exposes"
823 for (; lastIndex < findExposes->size(); lastIndex++)
824 {
825 if (findExposes->at(lastIndex)["Name"] == *name &&
826 findExposes->at(lastIndex)["Type"] == *type)
827 {
828 throw std::invalid_argument(
829 "Field already in JSON, not adding");
830 }
831 lastIndex++;
832 }
833
834 std::ifstream schemaFile(std::string(schemaDirectory) + "/" +
835 *type + ".json");
836 // todo(james) we might want to also make a list of 'can add'
837 // interfaces but for now I think the assumption if there is a
838 // schema avaliable that it is allowed to update is fine
839 if (!schemaFile.good())
840 {
841 throw std::invalid_argument(
842 "No schema avaliable, cannot validate.");
843 }
844 nlohmann::json schema =
845 nlohmann::json::parse(schemaFile, nullptr, false);
846 if (schema.is_discarded())
847 {
848 std::cerr << "Schema not legal" << *type << ".json\n";
849 throw DBusInternalError();
850 }
851 if (!validateJson(schema, newData))
852 {
853 throw std::invalid_argument("Data does not match schema");
854 }
855
856 if (!writeJsonFiles(systemConfiguration))
857 {
858 std::cerr << "Error writing json files\n";
859 throw DBusInternalError();
860 }
861 std::string dbusName = *name;
862
863 std::regex_replace(dbusName.begin(), dbusName.begin(),
864 dbusName.end(), ILLEGAL_DBUS_REGEX, "_");
865 auto iface = objServer.add_interface(
866 path + "/" + dbusName,
867 "xyz.openbmc_project.Configuration." + *type);
868 // permission is read-write, as since we just created it, must be
869 // runtime modifiable
870 populateInterfaceFromJson(
871 systemConfiguration,
James Feistc6248a52018-08-14 10:09:45 -0700872 jsonPointerPath + "/" + std::to_string(lastIndex), iface,
James Feist68500ff2018-08-08 15:40:42 -0700873 newData, objServer,
874 sdbusplus::asio::PropertyPermission::readWrite);
875 // todo(james) generate patch
876 findExposes->push_back(newData);
877 });
878 iface->initialize();
879}
880
James Feista465ccc2019-02-08 12:51:01 -0800881void postToDbus(const nlohmann::json& newConfiguration,
882 nlohmann::json& systemConfiguration,
883 sdbusplus::asio::object_server& objServer)
James Feist75fdeeb2018-02-20 14:26:16 -0800884
James Feist1b2e2242018-01-30 13:45:19 -0800885{
James Feist97a63f12018-05-17 13:50:57 -0700886 // iterate through boards
James Feista465ccc2019-02-08 12:51:01 -0800887 for (auto& boardPair : newConfiguration.items())
James Feist1b2e2242018-01-30 13:45:19 -0800888 {
889 std::string boardKey = boardPair.key();
James Feist97a63f12018-05-17 13:50:57 -0700890 std::vector<std::string> path;
891 std::string jsonPointerPath = "/" + boardKey;
892 // loop through newConfiguration, but use values from system
893 // configuration to be able to modify via dbus later
894 auto boardValues = systemConfiguration[boardKey];
James Feistd63d18a2018-07-19 15:23:45 -0700895 auto findBoardType = boardValues.find("Type");
James Feist1b2e2242018-01-30 13:45:19 -0800896 std::string boardType;
897 if (findBoardType != boardValues.end() &&
898 findBoardType->type() == nlohmann::json::value_t::string)
899 {
900 boardType = findBoardType->get<std::string>();
901 std::regex_replace(boardType.begin(), boardType.begin(),
902 boardType.end(), ILLEGAL_DBUS_REGEX, "_");
903 }
904 else
905 {
906 std::cerr << "Unable to find type for " << boardKey
907 << " reverting to Chassis.\n";
908 boardType = "Chassis";
909 }
James Feist11be6672018-04-06 14:05:32 -0700910 std::string boardtypeLower = boost::algorithm::to_lower_copy(boardType);
James Feist1b2e2242018-01-30 13:45:19 -0800911
912 std::regex_replace(boardKey.begin(), boardKey.begin(), boardKey.end(),
913 ILLEGAL_DBUS_REGEX, "_");
James Feist11be6672018-04-06 14:05:32 -0700914 std::string boardName = "/xyz/openbmc_project/inventory/system/" +
915 boardtypeLower + "/" + boardKey;
James Feist1b2e2242018-01-30 13:45:19 -0800916
James Feist8f2710a2018-05-09 17:18:55 -0700917 auto inventoryIface = objServer.add_interface(
918 boardName, "xyz.openbmc_project.Inventory.Item");
James Feist68500ff2018-08-08 15:40:42 -0700919
James Feist8f2710a2018-05-09 17:18:55 -0700920 auto boardIface = objServer.add_interface(
921 boardName, "xyz.openbmc_project.Inventory.Item." + boardType);
James Feist11be6672018-04-06 14:05:32 -0700922
James Feist68500ff2018-08-08 15:40:42 -0700923 createAddObjectMethod(jsonPointerPath, boardName, systemConfiguration,
924 objServer);
925
James Feist97a63f12018-05-17 13:50:57 -0700926 populateInterfaceFromJson(systemConfiguration, jsonPointerPath,
James Feistc6248a52018-08-14 10:09:45 -0700927 boardIface, boardValues, objServer);
James Feist97a63f12018-05-17 13:50:57 -0700928 jsonPointerPath += "/";
929 // iterate through board properties
James Feista465ccc2019-02-08 12:51:01 -0800930 for (auto& boardField : boardValues.items())
James Feist11be6672018-04-06 14:05:32 -0700931 {
932 if (boardField.value().type() == nlohmann::json::value_t::object)
933 {
James Feist8f2710a2018-05-09 17:18:55 -0700934 auto iface =
935 objServer.add_interface(boardName, boardField.key());
James Feistc6248a52018-08-14 10:09:45 -0700936 populateInterfaceFromJson(systemConfiguration,
937 jsonPointerPath + boardField.key(),
938 iface, boardField.value(), objServer);
James Feist11be6672018-04-06 14:05:32 -0700939 }
940 }
James Feist97a63f12018-05-17 13:50:57 -0700941
James Feist1e3e6982018-08-03 16:09:28 -0700942 auto exposes = boardValues.find("Exposes");
James Feist1b2e2242018-01-30 13:45:19 -0800943 if (exposes == boardValues.end())
944 {
945 continue;
946 }
James Feist97a63f12018-05-17 13:50:57 -0700947 // iterate through exposes
James Feist1e3e6982018-08-03 16:09:28 -0700948 jsonPointerPath += "Exposes/";
James Feist97a63f12018-05-17 13:50:57 -0700949
950 // store the board level pointer so we can modify it on the way down
951 std::string jsonPointerPathBoard = jsonPointerPath;
952 size_t exposesIndex = -1;
James Feista465ccc2019-02-08 12:51:01 -0800953 for (auto& item : *exposes)
James Feist1b2e2242018-01-30 13:45:19 -0800954 {
James Feist97a63f12018-05-17 13:50:57 -0700955 exposesIndex++;
956 jsonPointerPath = jsonPointerPathBoard;
957 jsonPointerPath += std::to_string(exposesIndex);
958
James Feistd63d18a2018-07-19 15:23:45 -0700959 auto findName = item.find("Name");
James Feist1b2e2242018-01-30 13:45:19 -0800960 if (findName == item.end())
961 {
962 std::cerr << "cannot find name in field " << item << "\n";
963 continue;
964 }
James Feist1e3e6982018-08-03 16:09:28 -0700965 auto findStatus = item.find("Status");
James Feist1b2e2242018-01-30 13:45:19 -0800966 // if status is not found it is assumed to be status = 'okay'
967 if (findStatus != item.end())
968 {
969 if (*findStatus == "disabled")
970 {
971 continue;
972 }
973 }
James Feistd63d18a2018-07-19 15:23:45 -0700974 auto findType = item.find("Type");
James Feist1b2e2242018-01-30 13:45:19 -0800975 std::string itemType;
976 if (findType != item.end())
977 {
978 itemType = findType->get<std::string>();
979 std::regex_replace(itemType.begin(), itemType.begin(),
980 itemType.end(), ILLEGAL_DBUS_REGEX, "_");
981 }
982 else
983 {
984 itemType = "unknown";
985 }
986 std::string itemName = findName->get<std::string>();
987 std::regex_replace(itemName.begin(), itemName.begin(),
988 itemName.end(), ILLEGAL_DBUS_REGEX, "_");
James Feistc6248a52018-08-14 10:09:45 -0700989
James Feist8f2710a2018-05-09 17:18:55 -0700990 auto itemIface = objServer.add_interface(
991 boardName + "/" + itemName,
James Feist1b2e2242018-01-30 13:45:19 -0800992 "xyz.openbmc_project.Configuration." + itemType);
993
James Feist97a63f12018-05-17 13:50:57 -0700994 populateInterfaceFromJson(systemConfiguration, jsonPointerPath,
James Feistc6248a52018-08-14 10:09:45 -0700995 itemIface, item, objServer,
996 getPermission(itemType));
James Feist1b2e2242018-01-30 13:45:19 -0800997
James Feista465ccc2019-02-08 12:51:01 -0800998 for (auto& objectPair : item.items())
James Feist1b2e2242018-01-30 13:45:19 -0800999 {
James Feist97a63f12018-05-17 13:50:57 -07001000 jsonPointerPath = jsonPointerPathBoard +
1001 std::to_string(exposesIndex) + "/" +
1002 objectPair.key();
James Feist1b2e2242018-01-30 13:45:19 -08001003 if (objectPair.value().type() ==
1004 nlohmann::json::value_t::object)
1005 {
James Feist8f2710a2018-05-09 17:18:55 -07001006 auto objectIface = objServer.add_interface(
1007 boardName + "/" + itemName,
James Feist1b2e2242018-01-30 13:45:19 -08001008 "xyz.openbmc_project.Configuration." + itemType + "." +
James Feist8f2710a2018-05-09 17:18:55 -07001009 objectPair.key());
James Feist97a63f12018-05-17 13:50:57 -07001010
1011 populateInterfaceFromJson(
James Feistc6248a52018-08-14 10:09:45 -07001012 systemConfiguration, jsonPointerPath, objectIface,
1013 objectPair.value(), objServer, getPermission(itemType));
James Feist1b2e2242018-01-30 13:45:19 -08001014 }
1015 else if (objectPair.value().type() ==
1016 nlohmann::json::value_t::array)
1017 {
1018 size_t index = 0;
James Feist8f2710a2018-05-09 17:18:55 -07001019 if (!objectPair.value().size())
James Feist1b2e2242018-01-30 13:45:19 -08001020 {
James Feist8f2710a2018-05-09 17:18:55 -07001021 continue;
1022 }
1023 bool isLegal = true;
1024 auto type = objectPair.value()[0].type();
1025 if (type != nlohmann::json::value_t::object)
1026 {
1027 continue;
1028 }
1029
1030 // verify legal json
James Feista465ccc2019-02-08 12:51:01 -08001031 for (const auto& arrayItem : objectPair.value())
James Feist8f2710a2018-05-09 17:18:55 -07001032 {
1033 if (arrayItem.type() != type)
James Feist1b2e2242018-01-30 13:45:19 -08001034 {
James Feist8f2710a2018-05-09 17:18:55 -07001035 isLegal = false;
James Feist1b2e2242018-01-30 13:45:19 -08001036 break;
1037 }
James Feist8f2710a2018-05-09 17:18:55 -07001038 }
1039 if (!isLegal)
1040 {
1041 std::cerr << "dbus format error" << objectPair.value()
1042 << "\n";
1043 break;
1044 }
1045
James Feista465ccc2019-02-08 12:51:01 -08001046 for (auto& arrayItem : objectPair.value())
James Feist8f2710a2018-05-09 17:18:55 -07001047 {
James Feist97a63f12018-05-17 13:50:57 -07001048
James Feist8f2710a2018-05-09 17:18:55 -07001049 auto objectIface = objServer.add_interface(
1050 boardName + "/" + itemName,
James Feist1b2e2242018-01-30 13:45:19 -08001051 "xyz.openbmc_project.Configuration." + itemType +
James Feistbb43d022018-06-12 15:44:33 -07001052 "." + objectPair.key() + std::to_string(index));
James Feistc6248a52018-08-14 10:09:45 -07001053 populateInterfaceFromJson(
1054 systemConfiguration,
1055 jsonPointerPath + "/" + std::to_string(index),
1056 objectIface, arrayItem, objServer,
1057 getPermission(objectPair.key()));
James Feistbb43d022018-06-12 15:44:33 -07001058 index++;
James Feist1b2e2242018-01-30 13:45:19 -08001059 }
1060 }
1061 }
1062 }
1063 }
1064}
1065
1066// finds the template character (currently set to $) and replaces the value with
1067// the field found in a dbus object i.e. $ADDRESS would get populated with the
1068// ADDRESS field from a object on dbus
1069void templateCharReplace(
James Feista465ccc2019-02-08 12:51:01 -08001070 nlohmann::json::iterator& keyPair,
1071 const boost::container::flat_map<std::string, BasicVariantType>&
1072 foundDevice,
1073 size_t& foundDeviceIdx)
James Feist1b2e2242018-01-30 13:45:19 -08001074{
James Feist11be6672018-04-06 14:05:32 -07001075 if (keyPair.value().type() == nlohmann::json::value_t::object)
1076 {
1077 for (auto nextLayer = keyPair.value().begin();
1078 nextLayer != keyPair.value().end(); nextLayer++)
1079 {
1080 templateCharReplace(nextLayer, foundDevice, foundDeviceIdx);
1081 }
1082 return;
1083 }
Ed Tanous12bc7932019-02-26 14:36:20 -08001084
1085 std::string* strPtr = keyPair.value().get_ptr<std::string*>();
1086 if (strPtr == nullptr)
James Feist1b2e2242018-01-30 13:45:19 -08001087 {
1088 return;
1089 }
1090
Ed Tanous12bc7932019-02-26 14:36:20 -08001091 boost::replace_all(*strPtr, "$index", std::to_string(foundDeviceIdx));
1092
1093 std::size_t templateIndex = 0;
1094
1095 for (auto& foundDevicePair : foundDevice)
James Feist1b2e2242018-01-30 13:45:19 -08001096 {
Ed Tanous12bc7932019-02-26 14:36:20 -08001097 std::string templateName = "$" + foundDevicePair.first;
1098 if (boost::iequals(*strPtr, templateName))
James Feist1b2e2242018-01-30 13:45:19 -08001099 {
Ed Tanous12bc7932019-02-26 14:36:20 -08001100 std::visit([&](auto&& val) { keyPair.value() = val; },
1101 foundDevicePair.second);
1102 // We probably just invalidated the pointer above, so set it to null
1103 strPtr = nullptr;
1104 break;
James Feist1b2e2242018-01-30 13:45:19 -08001105 }
Ed Tanous12bc7932019-02-26 14:36:20 -08001106
1107 std::string probeValue =
1108 std::visit(VariantToStringVisitor(), foundDevicePair.second);
1109 boost::replace_all(*strPtr, templateName, probeValue);
1110 }
1111
1112 strPtr = keyPair.value().get_ptr<std::string*>();
1113 if (strPtr == nullptr)
1114 {
1115 return;
James Feist1b2e2242018-01-30 13:45:19 -08001116 }
James Feistc6090822019-01-04 16:02:48 -08001117
1118 // convert hex numbers to ints
Ed Tanous12bc7932019-02-26 14:36:20 -08001119 if (boost::starts_with(*strPtr, "0x"))
James Feist28dc2da2018-10-15 14:47:42 -07001120 {
1121 try
1122 {
James Feistc6090822019-01-04 16:02:48 -08001123 size_t pos = 0;
Ed Tanous12bc7932019-02-26 14:36:20 -08001124 int64_t temp = std::stoul(*strPtr, &pos, 0);
1125 if (pos == strPtr->size())
James Feistc6090822019-01-04 16:02:48 -08001126 {
1127 keyPair.value() = static_cast<uint64_t>(temp);
1128 }
James Feist28dc2da2018-10-15 14:47:42 -07001129 }
1130 catch (std::invalid_argument)
1131 {
1132 }
James Feistc6090822019-01-04 16:02:48 -08001133 catch (std::out_of_range)
1134 {
1135 }
James Feist28dc2da2018-10-15 14:47:42 -07001136 }
James Feist1b2e2242018-01-30 13:45:19 -08001137}
1138
James Feist8f2710a2018-05-09 17:18:55 -07001139// reads json files out of the filesystem
James Feista465ccc2019-02-08 12:51:01 -08001140bool findJsonFiles(std::list<nlohmann::json>& configurations)
James Feist3cb5fec2018-01-23 14:41:51 -08001141{
1142 // find configuration files
Ed Tanous072e25d2018-12-16 21:45:20 -08001143 std::vector<std::filesystem::path> jsonPaths;
1144 if (!findFiles(std::filesystem::path(configurationDirectory),
James Feista3c180a2018-08-09 16:06:04 -07001145 R"(.*\.json)", jsonPaths))
James Feist3cb5fec2018-01-23 14:41:51 -08001146 {
1147 std::cerr << "Unable to find any configuration files in "
James Feistb4383f42018-08-06 16:54:10 -07001148 << configurationDirectory << "\n";
James Feist75fdeeb2018-02-20 14:26:16 -08001149 return false;
James Feist3cb5fec2018-01-23 14:41:51 -08001150 }
James Feistb4383f42018-08-06 16:54:10 -07001151
1152 std::ifstream schemaStream(std::string(schemaDirectory) + "/" +
1153 globalSchema);
1154 if (!schemaStream.good())
1155 {
1156 std::cerr
1157 << "Cannot open schema file, cannot validate JSON, exiting\n\n";
1158 std::exit(EXIT_FAILURE);
Ed Tanous072e25d2018-12-16 21:45:20 -08001159 return false;
James Feistb4383f42018-08-06 16:54:10 -07001160 }
1161 nlohmann::json schema = nlohmann::json::parse(schemaStream, nullptr, false);
1162 if (schema.is_discarded())
1163 {
1164 std::cerr
1165 << "Illegal schema file detected, cannot validate JSON, exiting\n";
1166 std::exit(EXIT_FAILURE);
Ed Tanous072e25d2018-12-16 21:45:20 -08001167 return false;
James Feistb4383f42018-08-06 16:54:10 -07001168 }
1169
James Feista465ccc2019-02-08 12:51:01 -08001170 for (auto& jsonPath : jsonPaths)
James Feist3cb5fec2018-01-23 14:41:51 -08001171 {
1172 std::ifstream jsonStream(jsonPath.c_str());
1173 if (!jsonStream.good())
1174 {
1175 std::cerr << "unable to open " << jsonPath.string() << "\n";
1176 continue;
1177 }
1178 auto data = nlohmann::json::parse(jsonStream, nullptr, false);
1179 if (data.is_discarded())
1180 {
1181 std::cerr << "syntax error in " << jsonPath.string() << "\n";
1182 continue;
1183 }
James Feist8da99192019-01-24 08:20:16 -08001184 /*
1185 * todo(james): reenable this once less things are in flight
1186 *
James Feistb4383f42018-08-06 16:54:10 -07001187 if (!validateJson(schema, data))
1188 {
1189 std::cerr << "Error validating " << jsonPath.string() << "\n";
1190 continue;
1191 }
James Feist8da99192019-01-24 08:20:16 -08001192 */
James Feistb4383f42018-08-06 16:54:10 -07001193
James Feist3cb5fec2018-01-23 14:41:51 -08001194 if (data.type() == nlohmann::json::value_t::array)
1195 {
James Feista465ccc2019-02-08 12:51:01 -08001196 for (auto& d : data)
James Feist3cb5fec2018-01-23 14:41:51 -08001197 {
1198 configurations.emplace_back(d);
1199 }
1200 }
1201 else
1202 {
1203 configurations.emplace_back(data);
1204 }
1205 }
Ed Tanous072e25d2018-12-16 21:45:20 -08001206 return true;
James Feist75fdeeb2018-02-20 14:26:16 -08001207}
James Feist3cb5fec2018-01-23 14:41:51 -08001208
James Feist8f2710a2018-05-09 17:18:55 -07001209struct PerformScan : std::enable_shared_from_this<PerformScan>
James Feist75fdeeb2018-02-20 14:26:16 -08001210{
James Feist75fdeeb2018-02-20 14:26:16 -08001211
James Feista465ccc2019-02-08 12:51:01 -08001212 PerformScan(nlohmann::json& systemConfiguration,
1213 std::list<nlohmann::json>& configurations,
1214 std::function<void(void)>&& callback) :
James Feist8f2710a2018-05-09 17:18:55 -07001215 _systemConfiguration(systemConfiguration),
1216 _configurations(configurations), _callback(std::move(callback))
James Feist3cb5fec2018-01-23 14:41:51 -08001217 {
James Feist8f2710a2018-05-09 17:18:55 -07001218 }
1219 void run()
1220 {
1221 for (auto it = _configurations.begin(); it != _configurations.end();)
James Feist3cb5fec2018-01-23 14:41:51 -08001222 {
James Feist1e3e6982018-08-03 16:09:28 -07001223 auto findProbe = it->find("Probe");
James Feistd63d18a2018-07-19 15:23:45 -07001224 auto findName = it->find("Name");
James Feist3cb5fec2018-01-23 14:41:51 -08001225
James Feist1b2e2242018-01-30 13:45:19 -08001226 nlohmann::json probeCommand;
1227 // check for poorly formatted fields, probe must be an array
1228 if (findProbe == it->end())
James Feist3cb5fec2018-01-23 14:41:51 -08001229 {
1230 std::cerr << "configuration file missing probe:\n " << *it
1231 << "\n";
James Feist8f2710a2018-05-09 17:18:55 -07001232 it = _configurations.erase(it);
1233 continue;
James Feist3cb5fec2018-01-23 14:41:51 -08001234 }
James Feist1b2e2242018-01-30 13:45:19 -08001235 else if ((*findProbe).type() != nlohmann::json::value_t::array)
James Feist3cb5fec2018-01-23 14:41:51 -08001236 {
1237 probeCommand = nlohmann::json::array();
1238 probeCommand.push_back(*findProbe);
1239 }
1240 else
1241 {
1242 probeCommand = *findProbe;
1243 }
James Feist1b2e2242018-01-30 13:45:19 -08001244
1245 if (findName == it->end())
1246 {
1247 std::cerr << "configuration file missing name:\n " << *it
1248 << "\n";
James Feist8f2710a2018-05-09 17:18:55 -07001249 it = _configurations.erase(it);
1250 continue;
James Feist1b2e2242018-01-30 13:45:19 -08001251 }
James Feist8f2710a2018-05-09 17:18:55 -07001252 std::string name = *findName;
James Feist1b2e2242018-01-30 13:45:19 -08001253
James Feist8f2710a2018-05-09 17:18:55 -07001254 if (std::find(PASSED_PROBES.begin(), PASSED_PROBES.end(), name) !=
1255 PASSED_PROBES.end())
James Feist3cb5fec2018-01-23 14:41:51 -08001256 {
James Feist8f2710a2018-05-09 17:18:55 -07001257 it = _configurations.erase(it);
1258 continue;
1259 }
James Feista465ccc2019-02-08 12:51:01 -08001260 nlohmann::json* record = &(*it);
James Feist3cb5fec2018-01-23 14:41:51 -08001261
James Feist8f2710a2018-05-09 17:18:55 -07001262 // store reference to this to children to makes sure we don't get
1263 // destroyed too early
1264 auto thisRef = shared_from_this();
1265 auto p = std::make_shared<PerformProbe>(
1266 probeCommand,
1267 [&, record, name,
1268 thisRef](std::vector<boost::container::flat_map<
James Feista465ccc2019-02-08 12:51:01 -08001269 std::string, BasicVariantType>>& foundDevices) {
James Feist8f2710a2018-05-09 17:18:55 -07001270 _passed = true;
James Feist3cb5fec2018-01-23 14:41:51 -08001271
James Feist8f2710a2018-05-09 17:18:55 -07001272 PASSED_PROBES.push_back(name);
1273 size_t foundDeviceIdx = 0;
1274
James Feistbe5425f2018-06-08 10:30:55 -07001275 // insert into configuration temporarly to be able to
1276 // reference ourselves
1277 _systemConfiguration[name] = *record;
1278
James Feista465ccc2019-02-08 12:51:01 -08001279 for (auto& foundDevice : foundDevices)
James Feist3cb5fec2018-01-23 14:41:51 -08001280 {
James Feist8f2710a2018-05-09 17:18:55 -07001281 for (auto keyPair = record->begin();
1282 keyPair != record->end(); keyPair++)
James Feist3cb5fec2018-01-23 14:41:51 -08001283 {
James Feist1b2e2242018-01-30 13:45:19 -08001284 templateCharReplace(keyPair, foundDevice,
1285 foundDeviceIdx);
James Feist8f2710a2018-05-09 17:18:55 -07001286 }
James Feist1e3e6982018-08-03 16:09:28 -07001287 auto findExpose = record->find("Exposes");
James Feist8f2710a2018-05-09 17:18:55 -07001288 if (findExpose == record->end())
1289 {
1290 continue;
1291 }
James Feista465ccc2019-02-08 12:51:01 -08001292 for (auto& expose : *findExpose)
James Feist8f2710a2018-05-09 17:18:55 -07001293 {
1294 for (auto keyPair = expose.begin();
1295 keyPair != expose.end(); keyPair++)
James Feist3cb5fec2018-01-23 14:41:51 -08001296 {
James Feist1b2e2242018-01-30 13:45:19 -08001297
James Feist8f2710a2018-05-09 17:18:55 -07001298 // fill in template characters with devices
1299 // found
1300 templateCharReplace(keyPair, foundDevice,
1301 foundDeviceIdx);
1302 // special case bind
James Feist1e3e6982018-08-03 16:09:28 -07001303 if (boost::starts_with(keyPair.key(), "Bind"))
James Feist8f2710a2018-05-09 17:18:55 -07001304 {
1305 if (keyPair.value().type() !=
1306 nlohmann::json::value_t::string)
James Feist3cb5fec2018-01-23 14:41:51 -08001307 {
James Feist8f2710a2018-05-09 17:18:55 -07001308 std::cerr << "bind_ value must be of "
1309 "type string "
1310 << keyPair.key() << "\n";
James Feist1b2e2242018-01-30 13:45:19 -08001311 continue;
1312 }
James Feist8f2710a2018-05-09 17:18:55 -07001313 bool foundBind = false;
1314 std::string bind = keyPair.key().substr(
James Feist1e3e6982018-08-03 16:09:28 -07001315 sizeof("Bind") - 1);
James Feistbe5425f2018-06-08 10:30:55 -07001316
James Feista465ccc2019-02-08 12:51:01 -08001317 for (auto& configurationPair :
James Feist8f2710a2018-05-09 17:18:55 -07001318 _systemConfiguration.items())
James Feist1b2e2242018-01-30 13:45:19 -08001319 {
James Feist1b2e2242018-01-30 13:45:19 -08001320
James Feist8f2710a2018-05-09 17:18:55 -07001321 auto configListFind =
1322 configurationPair.value().find(
James Feist1e3e6982018-08-03 16:09:28 -07001323 "Exposes");
James Feist8f2710a2018-05-09 17:18:55 -07001324
1325 if (configListFind ==
1326 configurationPair.value()
1327 .end() ||
1328 configListFind->type() !=
1329 nlohmann::json::value_t::array)
1330 {
1331 continue;
1332 }
James Feista465ccc2019-02-08 12:51:01 -08001333 for (auto& exposedObject :
James Feist8f2710a2018-05-09 17:18:55 -07001334 *configListFind)
1335 {
1336 std::string foundObjectName =
James Feistd63d18a2018-07-19 15:23:45 -07001337 (exposedObject)["Name"];
James Feist8f2710a2018-05-09 17:18:55 -07001338 if (boost::iequals(
1339 foundObjectName,
1340 keyPair.value()
1341 .get<std::string>()))
1342 {
James Feist1e3e6982018-08-03 16:09:28 -07001343 exposedObject["Status"] =
James Feist8f2710a2018-05-09 17:18:55 -07001344 "okay";
1345 expose[bind] = exposedObject;
1346
1347 foundBind = true;
1348 break;
1349 }
1350 }
1351 if (foundBind)
1352 {
James Feist3cb5fec2018-01-23 14:41:51 -08001353 break;
1354 }
1355 }
James Feist8f2710a2018-05-09 17:18:55 -07001356 if (!foundBind)
James Feist3cb5fec2018-01-23 14:41:51 -08001357 {
James Feist8f2710a2018-05-09 17:18:55 -07001358 std::cerr << "configuration file "
1359 "dependency error, "
1360 "could not find bind "
1361 << keyPair.value() << "\n";
James Feist3cb5fec2018-01-23 14:41:51 -08001362 }
1363 }
1364 }
1365 }
1366 }
James Feistbe5425f2018-06-08 10:30:55 -07001367 // overwrite ourselves with cleaned up version
James Feist8f2710a2018-05-09 17:18:55 -07001368 _systemConfiguration[name] = *record;
1369 });
1370 p->run();
1371 it++;
James Feist3cb5fec2018-01-23 14:41:51 -08001372 }
1373 }
James Feist75fdeeb2018-02-20 14:26:16 -08001374
James Feist8f2710a2018-05-09 17:18:55 -07001375 ~PerformScan()
James Feist75fdeeb2018-02-20 14:26:16 -08001376 {
James Feist8f2710a2018-05-09 17:18:55 -07001377 if (_passed)
1378 {
1379 auto nextScan = std::make_shared<PerformScan>(
1380 _systemConfiguration, _configurations, std::move(_callback));
1381 nextScan->run();
1382 }
1383 else
1384 {
1385 _callback();
1386 }
1387 }
James Feista465ccc2019-02-08 12:51:01 -08001388 nlohmann::json& _systemConfiguration;
James Feist8f2710a2018-05-09 17:18:55 -07001389 std::list<nlohmann::json> _configurations;
1390 std::function<void(void)> _callback;
1391 std::vector<std::shared_ptr<PerformProbe>> _probes;
1392 bool _passed = false;
1393};
James Feistc95cb142018-02-26 10:41:42 -08001394
James Feist8f2710a2018-05-09 17:18:55 -07001395// main properties changed entry
1396void propertiesChangedCallback(
James Feista465ccc2019-02-08 12:51:01 -08001397 boost::asio::io_service& io,
1398 std::vector<sdbusplus::bus::match::match>& dbusMatches,
1399 nlohmann::json& systemConfiguration,
1400 sdbusplus::asio::object_server& objServer)
James Feist8f2710a2018-05-09 17:18:55 -07001401{
1402 static boost::asio::deadline_timer timer(io);
1403 timer.expires_from_now(boost::posix_time::seconds(1));
1404
1405 // setup an async wait as we normally get flooded with new requests
James Feista465ccc2019-02-08 12:51:01 -08001406 timer.async_wait([&](const boost::system::error_code& ec) {
James Feist8f2710a2018-05-09 17:18:55 -07001407 if (ec == boost::asio::error::operation_aborted)
1408 {
1409 // we were cancelled
1410 return;
1411 }
1412 else if (ec)
1413 {
1414 std::cerr << "async wait error " << ec << "\n";
1415 return;
1416 }
1417
1418 nlohmann::json oldConfiguration = systemConfiguration;
1419 DBUS_PROBE_OBJECTS.clear();
1420
1421 std::list<nlohmann::json> configurations;
1422 if (!findJsonFiles(configurations))
1423 {
1424 std::cerr << "cannot find json files\n";
1425 return;
1426 }
1427
1428 auto perfScan = std::make_shared<PerformScan>(
1429 systemConfiguration, configurations, [&, oldConfiguration]() {
1430 nlohmann::json newConfiguration = systemConfiguration;
James Feist4131aea2018-03-09 09:47:30 -08001431 for (auto it = newConfiguration.begin();
1432 it != newConfiguration.end();)
1433 {
1434 auto findKey = oldConfiguration.find(it.key());
1435 if (findKey != oldConfiguration.end())
1436 {
1437 it = newConfiguration.erase(it);
1438 }
1439 else
1440 {
1441 it++;
1442 }
1443 }
James Feist8f2710a2018-05-09 17:18:55 -07001444 registerCallbacks(io, dbusMatches, systemConfiguration,
1445 objServer);
1446 io.post([&, newConfiguration]() {
James Feist8f2710a2018-05-09 17:18:55 -07001447 loadOverlays(newConfiguration);
James Feistce4367c2018-10-16 09:19:57 -07001448
James Feistbb43d022018-06-12 15:44:33 -07001449 io.post([&]() {
1450 if (!writeJsonFiles(systemConfiguration))
1451 {
1452 std::cerr << "Error writing json files\n";
1453 }
1454 });
James Feist8f2710a2018-05-09 17:18:55 -07001455 io.post([&, newConfiguration]() {
James Feist97a63f12018-05-17 13:50:57 -07001456 postToDbus(newConfiguration, systemConfiguration,
1457 objServer);
James Feist8f2710a2018-05-09 17:18:55 -07001458 });
1459 });
1460 });
1461 perfScan->run();
1462 });
James Feist75fdeeb2018-02-20 14:26:16 -08001463}
1464
James Feista465ccc2019-02-08 12:51:01 -08001465void registerCallbacks(boost::asio::io_service& io,
1466 std::vector<sdbusplus::bus::match::match>& dbusMatches,
1467 nlohmann::json& systemConfiguration,
1468 sdbusplus::asio::object_server& objServer)
James Feist75fdeeb2018-02-20 14:26:16 -08001469{
1470 static boost::container::flat_set<std::string> watchedObjects;
1471
James Feista465ccc2019-02-08 12:51:01 -08001472 for (const auto& objectMap : DBUS_PROBE_OBJECTS)
James Feist75fdeeb2018-02-20 14:26:16 -08001473 {
1474 auto findObject = watchedObjects.find(objectMap.first);
1475 if (findObject != watchedObjects.end())
1476 {
1477 continue;
1478 }
James Feist8f2710a2018-05-09 17:18:55 -07001479 std::function<void(sdbusplus::message::message & message)>
1480 eventHandler =
James Feist75fdeeb2018-02-20 14:26:16 -08001481
James Feista465ccc2019-02-08 12:51:01 -08001482 [&](sdbusplus::message::message&) {
James Feist8f2710a2018-05-09 17:18:55 -07001483 propertiesChangedCallback(io, dbusMatches,
1484 systemConfiguration, objServer);
1485 };
1486
1487 sdbusplus::bus::match::match match(
James Feista465ccc2019-02-08 12:51:01 -08001488 static_cast<sdbusplus::bus::bus&>(*SYSTEM_BUS),
James Feist8f2710a2018-05-09 17:18:55 -07001489 "type='signal',member='PropertiesChanged',arg0='" +
1490 objectMap.first + "'",
1491 eventHandler);
1492 dbusMatches.emplace_back(std::move(match));
James Feist75fdeeb2018-02-20 14:26:16 -08001493 }
1494}
1495
James Feista465ccc2019-02-08 12:51:01 -08001496int main(int argc, char** argv)
James Feist75fdeeb2018-02-20 14:26:16 -08001497{
1498 // setup connection to dbus
1499 boost::asio::io_service io;
James Feist8f2710a2018-05-09 17:18:55 -07001500 SYSTEM_BUS = std::make_shared<sdbusplus::asio::connection>(io);
James Feist75fdeeb2018-02-20 14:26:16 -08001501 SYSTEM_BUS->request_name("xyz.openbmc_project.EntityManager");
James Feist4131aea2018-03-09 09:47:30 -08001502
James Feist8f2710a2018-05-09 17:18:55 -07001503 sdbusplus::asio::object_server objServer(SYSTEM_BUS);
James Feistfd1264a2018-05-03 12:10:00 -07001504
James Feist8f2710a2018-05-09 17:18:55 -07001505 std::shared_ptr<sdbusplus::asio::dbus_interface> entityIface =
1506 objServer.add_interface("/xyz/openbmc_project/EntityManager",
1507 "xyz.openbmc_project.EntityManager");
James Feistfd1264a2018-05-03 12:10:00 -07001508
James Feist8f2710a2018-05-09 17:18:55 -07001509 std::shared_ptr<sdbusplus::asio::dbus_interface> inventoryIface =
1510 objServer.add_interface("/xyz/openbmc_project/inventory",
1511 "xyz.openbmc_project.Inventory.Manager");
James Feist4131aea2018-03-09 09:47:30 -08001512
1513 // to keep reference to the match / filter objects so they don't get
1514 // destroyed
James Feist8f2710a2018-05-09 17:18:55 -07001515 std::vector<sdbusplus::bus::match::match> dbusMatches;
1516
1517 nlohmann::json systemConfiguration = nlohmann::json::object();
1518
1519 inventoryIface->register_method(
James Feista465ccc2019-02-08 12:51:01 -08001520 "Notify",
1521 [](const boost::container::flat_map<
1522 std::string,
1523 boost::container::flat_map<std::string, BasicVariantType>>&
1524 object) { return; });
James Feist8f2710a2018-05-09 17:18:55 -07001525 inventoryIface->initialize();
1526
1527 io.post([&]() {
James Feistce4367c2018-10-16 09:19:57 -07001528#if OVERLAYS
James Feist8f2710a2018-05-09 17:18:55 -07001529 unloadAllOverlays();
James Feistce4367c2018-10-16 09:19:57 -07001530#endif
James Feist8f2710a2018-05-09 17:18:55 -07001531 propertiesChangedCallback(io, dbusMatches, systemConfiguration,
1532 objServer);
1533 });
James Feist4131aea2018-03-09 09:47:30 -08001534
James Feistfd1264a2018-05-03 12:10:00 -07001535 entityIface->register_method("ReScan", [&]() {
James Feist8f2710a2018-05-09 17:18:55 -07001536 propertiesChangedCallback(io, dbusMatches, systemConfiguration,
1537 objServer);
James Feist75fdeeb2018-02-20 14:26:16 -08001538 });
James Feist8f2710a2018-05-09 17:18:55 -07001539 entityIface->initialize();
1540
James Feist1b2e2242018-01-30 13:45:19 -08001541 io.run();
James Feist3cb5fec2018-01-23 14:41:51 -08001542
1543 return 0;
James Feist75fdeeb2018-02-20 14:26:16 -08001544}