blob: b27b7f2181bab7a1526d49f8ff273ede035063eb [file] [log] [blame]
James Feist3cb5fec2018-01-23 14:41:51 -08001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
17#include <Utils.hpp>
18#include <dbus/properties.hpp>
19#include <nlohmann/json.hpp>
20#include <fstream>
21#include <regex>
22#include <boost/algorithm/string/predicate.hpp>
23#include <boost/algorithm/string/replace.hpp>
24#include <boost/variant/apply_visitor.hpp>
25#include <boost/lexical_cast.hpp>
26#include <boost/container/flat_map.hpp>
27#include <boost/container/flat_set.hpp>
James Feist1b2e2242018-01-30 13:45:19 -080028#include <dbus/connection.hpp>
James Feist3cb5fec2018-01-23 14:41:51 -080029#include <VariantVisitors.hpp>
James Feist7b7e4e82018-01-24 14:56:00 -080030#include <experimental/filesystem>
James Feist3cb5fec2018-01-23 14:41:51 -080031
32constexpr const char *OUTPUT_DIR = "/var/configuration/";
33constexpr const char *CONFIGURATION_DIR = "/usr/share/configurations";
34constexpr const char *TEMPLATE_CHAR = "$";
James Feist1b2e2242018-01-30 13:45:19 -080035constexpr const size_t PROPERTIES_CHANGED_UNTIL_FLUSH = 20;
James Feist3cb5fec2018-01-23 14:41:51 -080036constexpr const size_t MAX_MAPPER_DEPTH = 99;
37
38namespace fs = std::experimental::filesystem;
39struct cmp_str
40{
41 bool operator()(const char *a, const char *b) const
42 {
43 return std::strcmp(a, b) < 0;
44 }
45};
46
47// underscore T for collison with dbus c api
48enum class probe_type_codes
49{
50 FALSE_T,
51 TRUE_T,
52 AND,
53 OR,
54 FOUND
55};
56const static boost::container::flat_map<const char *, probe_type_codes, cmp_str>
57 PROBE_TYPES{{{"FALSE", probe_type_codes::FALSE_T},
58 {"TRUE", probe_type_codes::TRUE_T},
59 {"AND", probe_type_codes::AND},
60 {"OR", probe_type_codes::OR},
61 {"FOUND", probe_type_codes::FOUND}}};
62
63using GetSubTreeType = std::vector<
64 std::pair<std::string,
65 std::vector<std::pair<std::string, std::vector<std::string>>>>>;
66
67using ManagedObjectType = boost::container::flat_map<
68 dbus::object_path,
69 boost::container::flat_map<
70 std::string,
71 boost::container::flat_map<std::string, dbus::dbus_variant>>>;
72
73boost::container::flat_map<
74 std::string,
75 std::vector<boost::container::flat_map<std::string, dbus::dbus_variant>>>
76 DBUS_PROBE_OBJECTS;
77std::vector<std::string> PASSED_PROBES;
78
79// todo: pass this through nicer
80std::shared_ptr<dbus::connection> SYSTEM_BUS;
81
James Feist1b2e2242018-01-30 13:45:19 -080082std::regex ILLEGAL_DBUS_REGEX("[^A-Za-z0-9_]");
83
James Feist3cb5fec2018-01-23 14:41:51 -080084// calls the mapper to find all exposed objects of an interface type
85// and creates a vector<flat_map> that contains all the key value pairs
86// getManagedObjects
87bool findDbusObjects(
88 std::shared_ptr<dbus::connection> connection,
89 std::vector<boost::container::flat_map<std::string, dbus::dbus_variant>>
90 &interfaceDevices,
91 std::string interface)
92{
93 // find all connections in the mapper that expose a specific type
94 static const dbus::endpoint mapper("xyz.openbmc_project.ObjectMapper",
95 "/xyz/openbmc_project/object_mapper",
96 "xyz.openbmc_project.ObjectMapper",
97 "GetSubTree");
98 dbus::message getMap = dbus::message::new_call(mapper);
99 std::vector<std::string> objects = {interface};
100 if (!getMap.pack("", MAX_MAPPER_DEPTH, objects))
101 {
102 std::cerr << "Pack Failed GetSensorSubtree\n";
103 return false;
104 }
105 dbus::message getMapResp = connection->send(getMap);
106 GetSubTreeType interfaceSubtree;
107 if (!getMapResp.unpack(interfaceSubtree))
108 {
109 std::cerr << "Error communicating to mapper\n";
110 return false;
111 }
112 boost::container::flat_set<std::string> connections;
113 for (auto &object : interfaceSubtree)
114 {
115 for (auto &connPair : object.second)
116 {
117 connections.insert(connPair.first);
118 }
119 }
120 // iterate through the connections, adding creating individual device
121 // dictionaries
122 for (auto &conn : connections)
123 {
124 auto managedObj =
125 dbus::endpoint(conn, "/", "org.freedesktop.DBus.ObjectManager",
126 "GetManagedObjects");
127 dbus::message getManagedObj = dbus::message::new_call(managedObj);
128 dbus::message getManagedObjResp = connection->send(getManagedObj);
129 ManagedObjectType managedInterface;
130 if (!getManagedObjResp.unpack(managedInterface))
131 {
132 std::cerr << "error getting managed object for device " << conn
133 << "\n";
134 continue;
135 }
136 for (auto &interfaceManagedObj : managedInterface)
137 {
138 auto ifaceObjFind = interfaceManagedObj.second.find(interface);
139 if (ifaceObjFind != interfaceManagedObj.second.end())
140 {
141 interfaceDevices.emplace_back(ifaceObjFind->second);
142 }
143 }
144 }
145 return true;
146}
147
148// probes interface dictionary for a key with a value that matches a regex
149bool probeDbus(
150 const std::string &interface,
151 const std::map<std::string, nlohmann::json> &matches,
152 std::vector<boost::container::flat_map<std::string, dbus::dbus_variant>>
153 &devices,
154 bool &foundProbe)
155{
156 auto &dbusObject = DBUS_PROBE_OBJECTS[interface];
157 if (dbusObject.empty())
158 {
159 if (!findDbusObjects(SYSTEM_BUS, dbusObject, interface))
160 {
161 std::cerr << "Found no dbus objects with interface "
162 << interface << "\n";
163 foundProbe = false;
164 return false;
165 }
166 }
167 foundProbe = true;
168
169 bool foundMatch = false;
170 for (auto &device : dbusObject)
171 {
172 bool deviceMatches = true;
173 for (auto &match : matches)
174 {
175 auto deviceValue = device.find(match.first);
176 if (deviceValue != device.end())
177 {
178 switch (match.second.type())
179 {
180 case nlohmann::json::value_t::string:
181 {
182 std::regex search(match.second.get<std::string>());
183 std::smatch match;
184
185 // convert value to string respresentation
186 std::string probeValue = boost::apply_visitor(
187 [](const auto &x) {
188 return boost::lexical_cast<std::string>(x);
189 },
190 deviceValue->second);
191 if (!std::regex_search(probeValue, match, search))
192 {
193 deviceMatches = false;
194 break;
195 }
196 break;
197 }
198 case nlohmann::json::value_t::boolean:
199 case nlohmann::json::value_t::number_unsigned:
200 {
201 unsigned int probeValue = boost::apply_visitor(
202 VariantToUnsignedIntVisitor(), deviceValue->second);
203
204 if (probeValue != match.second.get<unsigned int>())
205 {
206 deviceMatches = false;
207 }
208 break;
209 }
210 case nlohmann::json::value_t::number_integer:
211 {
212 int probeValue = boost::apply_visitor(VariantToIntVisitor(),
213 deviceValue->second);
214
215 if (probeValue != match.second.get<int>())
216 {
217 deviceMatches = false;
218 }
219 break;
220 }
221 case nlohmann::json::value_t::number_float:
222 {
223 float probeValue = boost::apply_visitor(
224 VariantToFloatVisitor(), deviceValue->second);
225
226 if (probeValue != match.second.get<float>())
227 {
228 deviceMatches = false;
229 }
230 break;
231 }
232 }
233 }
234 else
235 {
236 deviceMatches = false;
237 break;
238 }
239 }
240 if (deviceMatches)
241 {
242 devices.emplace_back(
243 boost::container::flat_map<std::string, dbus::dbus_variant>(
244 device));
245 foundMatch = true;
246 deviceMatches = false; // for next iteration
247 }
248 }
249 return foundMatch;
250}
251
252// default probe entry point, iterates a list looking for specific types to
253// call specific probe functions
254bool probe(
255 const std::vector<std::string> probeCommand,
256 std::vector<boost::container::flat_map<std::string, dbus::dbus_variant>>
257 &foundDevs)
258{
259 const static std::regex command(R"(\((.*)\))");
260 std::smatch match;
261 bool ret = false;
262 bool cur = true;
263 probe_type_codes lastCommand = probe_type_codes::FALSE_T;
264
265 for (auto &probe : probeCommand)
266 {
267 bool foundProbe = false;
268 boost::container::flat_map<const char *, probe_type_codes,
269 cmp_str>::const_iterator probeType;
270
271 for (probeType = PROBE_TYPES.begin(); probeType != PROBE_TYPES.end();
272 probeType++)
273 {
274 if (probe.find(probeType->first) != std::string::npos)
275 {
276 foundProbe = true;
277 break;
278 }
279 }
280 if (foundProbe)
281 {
282 switch (probeType->second)
283 {
284 case probe_type_codes::FALSE_T:
285 {
286 return false; // todo, actually evaluate?
287 break;
288 }
289 case probe_type_codes::TRUE_T:
290 {
291 return true; // todo, actually evaluate?
292 break;
293 }
294 /*case probe_type_codes::AND:
295 break;
296 case probe_type_codes::OR:
297 break;
298 // these are no-ops until the last command switch
299 */
300 case probe_type_codes::FOUND:
301 {
302 if (!std::regex_search(probe, match, command))
303 {
304 std::cerr << "found probe sytax error " << probe << "\n";
305 return false;
306 }
307 std::string commandStr = *(match.begin() + 1);
James Feist3f8a2782018-02-12 09:24:42 -0800308 boost::replace_all(commandStr, "'", "");
James Feist3cb5fec2018-01-23 14:41:51 -0800309 cur = (std::find(PASSED_PROBES.begin(), PASSED_PROBES.end(),
310 commandStr) != PASSED_PROBES.end());
311 break;
312 }
313 }
314 }
315 // look on dbus for object
316 else
317 {
318 if (!std::regex_search(probe, match, command))
319 {
320 std::cerr << "dbus probe sytax error " << probe << "\n";
321 return false;
322 }
323 std::string commandStr = *(match.begin() + 1);
324 // convert single ticks and single slashes into legal json
James Feist3f8a2782018-02-12 09:24:42 -0800325 boost::replace_all(commandStr, "'", R"(")");
326 boost::replace_all(commandStr, R"(\)", R"(\\)");
James Feist3cb5fec2018-01-23 14:41:51 -0800327 auto json = nlohmann::json::parse(commandStr, nullptr, false);
328 if (json.is_discarded())
329 {
330 std::cerr << "dbus command sytax error " << commandStr << "\n";
331 return false;
332 }
333 // we can match any (string, variant) property. (string, string)
334 // does a regex
335 std::map<std::string, nlohmann::json> dbusProbeMap =
336 json.get<std::map<std::string, nlohmann::json>>();
337 auto findStart = probe.find("(");
338 if (findStart == std::string::npos)
339 {
340 return false;
341 }
342 std::string probeInterface = probe.substr(0, findStart);
343 cur =
344 probeDbus(probeInterface, dbusProbeMap, foundDevs, foundProbe);
345 }
346
347 // some functions like AND and OR only take affect after the
348 // fact
349 switch (lastCommand)
350 {
351 case probe_type_codes::AND:
352 ret = cur && ret;
353 break;
354 case probe_type_codes::OR:
355 ret = cur || ret;
356 break;
357 default:
358 ret = cur;
359 break;
360 }
361 lastCommand = probeType != PROBE_TYPES.end()
362 ? probeType->second
363 : probe_type_codes::FALSE_T;
364
365 if (!foundProbe)
366 {
367 std::cerr << "Illegal probe type " << probe << "\n";
368 return false;
369 }
370 }
371
372 // probe passed, but empty device
373 // todo: should this be done in main?
374 if (ret && foundDevs.size() == 0)
375 {
376 foundDevs.emplace_back(
377 boost::container::flat_map<std::string, dbus::dbus_variant>());
378 }
379 return ret;
380}
381
James Feist1b2e2242018-01-30 13:45:19 -0800382// this function is temporary, no need to have once dbus is solified.
383void writeJsonFiles(nlohmann::json &systemConfiguration)
384{
385 std::experimental::filesystem::create_directory(OUTPUT_DIR);
386 std::ofstream output(std::string(OUTPUT_DIR) + "system.json");
387 output << systemConfiguration.dump(4);
388 output.close();
389
390 auto flat = nlohmann::json::array();
391 for (auto &pair : nlohmann::json::iterator_wrapper(systemConfiguration))
392 {
393 auto value = pair.value();
394 auto exposes = value.find("exposes");
395 if (exposes != value.end())
396 {
397 for (auto &item : *exposes)
398 {
399 flat.push_back(item);
400 }
401 }
402 }
403 output = std::ofstream(std::string(OUTPUT_DIR) + "flattened.json");
404 output << flat.dump(4);
405 output.close();
406}
407// adds simple json types to interface's properties
408void populateInterfaceFromJson(dbus::DbusInterface *iface, nlohmann::json dict,
409 dbus::DbusObjectServer &objServer)
410{
411 std::vector<std::pair<std::string, dbus::dbus_variant>> properties;
412 static size_t flushCount = 0;
413
414 for (auto &dictPair : nlohmann::json::iterator_wrapper(dict))
415 {
416 switch (dictPair.value().type())
417 {
418 case (nlohmann::json::value_t::boolean):
419 {
420 properties.emplace_back(std::string(dictPair.key()),
421 dictPair.value().get<bool>());
422 break;
423 }
424 case (nlohmann::json::value_t::number_integer):
425 {
426 properties.emplace_back(std::string(dictPair.key()),
427 dictPair.value().get<int64_t>());
428 break;
429 }
430 case (nlohmann::json::value_t::number_unsigned):
431 {
432 properties.emplace_back(std::string(dictPair.key()),
433 dictPair.value().get<uint64_t>());
434 break;
435 }
436 case (nlohmann::json::value_t::number_float):
437 {
438 properties.emplace_back(std::string(dictPair.key()),
439 dictPair.value().get<float>());
440 break;
441 }
442 case (nlohmann::json::value_t::string):
443 {
444 properties.emplace_back(std::string(dictPair.key()),
445 dictPair.value().get<std::string>());
446 break;
447 }
448 }
449 }
450 if (!properties.empty())
451 {
452 iface->set_properties(properties);
453
454 // flush the queue after adding an amount of properties so we don't hang
455 if (flushCount++ > PROPERTIES_CHANGED_UNTIL_FLUSH)
456 {
457 objServer.flush();
458 flushCount = 0;
459 }
460 }
461}
462
463void postToDbus(const nlohmann::json &systemConfiguration,
464 dbus::DbusObjectServer &objServer,
465 std::vector<std::shared_ptr<dbus::DbusObject>> &objects)
466{
467 for (auto &boardPair :
468 nlohmann::json::iterator_wrapper(systemConfiguration))
469 {
470 std::string boardKey = boardPair.key();
471 auto boardValues = boardPair.value();
472 auto findBoardType = boardValues.find("type");
473 std::string boardType;
474 if (findBoardType != boardValues.end() &&
475 findBoardType->type() == nlohmann::json::value_t::string)
476 {
477 boardType = findBoardType->get<std::string>();
478 std::regex_replace(boardType.begin(), boardType.begin(),
479 boardType.end(), ILLEGAL_DBUS_REGEX, "_");
480 }
481 else
482 {
483 std::cerr << "Unable to find type for " << boardKey
484 << " reverting to Chassis.\n";
485 boardType = "Chassis";
486 }
487
488 std::regex_replace(boardKey.begin(), boardKey.begin(), boardKey.end(),
489 ILLEGAL_DBUS_REGEX, "_");
490 std::string boardName =
491 "/xyz/openbmc_project/Inventory/Item/" + boardType + "/" + boardKey;
492 auto boardObject = objServer.add_object(boardName);
493
494 auto boardIface = boardObject->add_interface(
495 "xyz.openbmc_project.Configuration." + boardType);
496 populateInterfaceFromJson(boardIface.get(), boardValues, objServer);
497 auto exposes = boardValues.find("exposes");
498 if (exposes == boardValues.end())
499 {
500 continue;
501 }
502 for (auto &item : *exposes)
503 {
504 auto findName = item.find("name");
505 if (findName == item.end())
506 {
507 std::cerr << "cannot find name in field " << item << "\n";
508 continue;
509 }
510 auto findStatus = item.find("status");
511 // if status is not found it is assumed to be status = 'okay'
512 if (findStatus != item.end())
513 {
514 if (*findStatus == "disabled")
515 {
516 continue;
517 }
518 }
519 auto findType = item.find("type");
520 std::string itemType;
521 if (findType != item.end())
522 {
523 itemType = findType->get<std::string>();
524 std::regex_replace(itemType.begin(), itemType.begin(),
525 itemType.end(), ILLEGAL_DBUS_REGEX, "_");
526 }
527 else
528 {
529 itemType = "unknown";
530 }
531 std::string itemName = findName->get<std::string>();
532 std::regex_replace(itemName.begin(), itemName.begin(),
533 itemName.end(), ILLEGAL_DBUS_REGEX, "_");
534 auto itemObject = objServer.add_object(boardName + "/" + itemName);
535 auto itemIface = itemObject->add_interface(
536 "xyz.openbmc_project.Configuration." + itemType);
537
538 populateInterfaceFromJson(itemIface.get(), item, objServer);
539
540 for (auto &objectPair : nlohmann::json::iterator_wrapper(item))
541 {
542 if (objectPair.value().type() ==
543 nlohmann::json::value_t::object)
544 {
545 auto objectIface = itemObject->add_interface(
546 "xyz.openbmc_project.Configuration." + itemType + "." +
547 objectPair.key());
548 populateInterfaceFromJson(objectIface.get(),
549 objectPair.value(), objServer);
550 }
551 else if (objectPair.value().type() ==
552 nlohmann::json::value_t::array)
553 {
554 size_t index = 0;
555 for (auto &arrayItem : objectPair.value())
556 {
557 if (arrayItem.type() != nlohmann::json::value_t::object)
558 {
559 std::cerr << "dbus format error" << arrayItem
560 << "\n";
561 break;
562 }
563 auto objectIface = itemObject->add_interface(
564 "xyz.openbmc_project.Configuration." + itemType +
565 "." + objectPair.key() + "." +
566 std::to_string(index));
567 index++;
568 populateInterfaceFromJson(objectIface.get(), arrayItem,
569 objServer);
570 }
571 }
572 }
573 }
574 }
575}
576
577// finds the template character (currently set to $) and replaces the value with
578// the field found in a dbus object i.e. $ADDRESS would get populated with the
579// ADDRESS field from a object on dbus
580void templateCharReplace(
581 nlohmann::json::iterator &keyPair,
582 const boost::container::flat_map<std::string, dbus::dbus_variant>
583 &foundDevice,
584 size_t &foundDeviceIdx)
585{
586 if (keyPair.value().type() != nlohmann::json::value_t::string)
587 {
588 return;
589 }
590
591 std::string value = keyPair.value();
592 if (value.find(TEMPLATE_CHAR) != std::string::npos)
593 {
594 std::string templateValue = value;
595
596 templateValue.erase(0, 1); // remove template character
597
598 // special case index
599 if ("index" == templateValue)
600 {
601 keyPair.value() = foundDeviceIdx;
602 }
603 else
604 {
605 std::string subsitute;
606 for (auto &foundDevicePair : foundDevice)
607 {
608 if (boost::iequals(foundDevicePair.first, templateValue))
609 {
610 // convert value to string
611 // respresentation
612 subsitute = boost::apply_visitor(
613 [](const auto &x) {
614 return boost::lexical_cast<std::string>(x);
615 },
616 foundDevicePair.second);
617 break;
618 }
619 }
620 if (!subsitute.size())
621 {
622 std::cerr << "could not find symbol " << templateValue << "\n";
623 }
624 else
625 {
626 keyPair.value() = subsitute;
627 }
628 }
629 }
630}
631
James Feist3cb5fec2018-01-23 14:41:51 -0800632int main(int argc, char **argv)
633{
634 // find configuration files
635 std::vector<fs::path> jsonPaths;
636 if (!find_files(fs::path(CONFIGURATION_DIR), R"(.*\.json)", jsonPaths, 0))
637 {
638 std::cerr << "Unable to find any configuration files in "
639 << CONFIGURATION_DIR << "\n";
640 return 1;
641 }
642 // setup connection to dbus
643 boost::asio::io_service io;
644 SYSTEM_BUS = std::make_shared<dbus::connection>(io, dbus::bus::system);
645 dbus::DbusObjectServer objServer(SYSTEM_BUS);
646 SYSTEM_BUS->request_name("xyz.openbmc_project.EntityManager");
647
648 std::vector<nlohmann::json> configurations;
649 for (auto &jsonPath : jsonPaths)
650 {
651 std::ifstream jsonStream(jsonPath.c_str());
652 if (!jsonStream.good())
653 {
654 std::cerr << "unable to open " << jsonPath.string() << "\n";
655 continue;
656 }
657 auto data = nlohmann::json::parse(jsonStream, nullptr, false);
658 if (data.is_discarded())
659 {
660 std::cerr << "syntax error in " << jsonPath.string() << "\n";
661 continue;
662 }
663 if (data.type() == nlohmann::json::value_t::array)
664 {
665 for (auto &d : data)
666 {
667 configurations.emplace_back(d);
668 }
669 }
670 else
671 {
672 configurations.emplace_back(data);
673 }
674 }
675
676 // keep looping as long as at least 1 new probe passed, removing
677 // configurations from the memory store once the probe passes
678 bool probePassed = true;
James Feist7b7e4e82018-01-24 14:56:00 -0800679 nlohmann::json systemConfiguration = nlohmann::json::object();
James Feist3cb5fec2018-01-23 14:41:51 -0800680 while (probePassed)
681 {
682 probePassed = false;
683 for (auto it = configurations.begin(); it != configurations.end();)
684 {
685 bool eraseConfig = false;
James Feist1b2e2242018-01-30 13:45:19 -0800686 auto findProbe = it->find("probe");
687 auto findName = it->find("name");
James Feist3cb5fec2018-01-23 14:41:51 -0800688
James Feist1b2e2242018-01-30 13:45:19 -0800689 nlohmann::json probeCommand;
690 // check for poorly formatted fields, probe must be an array
691 if (findProbe == it->end())
James Feist3cb5fec2018-01-23 14:41:51 -0800692 {
693 std::cerr << "configuration file missing probe:\n " << *it
694 << "\n";
695 eraseConfig = true;
696 }
James Feist1b2e2242018-01-30 13:45:19 -0800697 else if ((*findProbe).type() != nlohmann::json::value_t::array)
James Feist3cb5fec2018-01-23 14:41:51 -0800698 {
699 probeCommand = nlohmann::json::array();
700 probeCommand.push_back(*findProbe);
701 }
702 else
703 {
704 probeCommand = *findProbe;
705 }
James Feist1b2e2242018-01-30 13:45:19 -0800706
707 if (findName == it->end())
708 {
709 std::cerr << "configuration file missing name:\n " << *it
710 << "\n";
711 eraseConfig = true;
712 }
713
James Feist3cb5fec2018-01-23 14:41:51 -0800714 std::vector<
715 boost::container::flat_map<std::string, dbus::dbus_variant>>
716 foundDevices;
James Feist1b2e2242018-01-30 13:45:19 -0800717 if (!eraseConfig && probe(probeCommand, foundDevices))
James Feist3cb5fec2018-01-23 14:41:51 -0800718 {
719 eraseConfig = true;
720 probePassed = true;
James Feist7b7e4e82018-01-24 14:56:00 -0800721 std::string name = *findName;
722 PASSED_PROBES.push_back(name);
James Feist3cb5fec2018-01-23 14:41:51 -0800723
724 size_t foundDeviceIdx = 0;
725
726 for (auto &foundDevice : foundDevices)
727 {
James Feist1b2e2242018-01-30 13:45:19 -0800728 for (auto keyPair = it->begin(); keyPair != it->end();
729 keyPair++)
James Feist3cb5fec2018-01-23 14:41:51 -0800730 {
James Feist1b2e2242018-01-30 13:45:19 -0800731 templateCharReplace(keyPair, foundDevice,
732 foundDeviceIdx);
733 }
734 auto findExpose = it->find("exposes");
735 if (findExpose == it->end())
736 {
James Feist3cb5fec2018-01-23 14:41:51 -0800737 continue;
738 }
739 for (auto &expose : *findExpose)
740 {
741 for (auto keyPair = expose.begin();
742 keyPair != expose.end(); keyPair++)
743 {
James Feist1b2e2242018-01-30 13:45:19 -0800744
James Feist3cb5fec2018-01-23 14:41:51 -0800745 // fill in template characters with devices
746 // found
James Feist1b2e2242018-01-30 13:45:19 -0800747 templateCharReplace(keyPair, foundDevice,
748 foundDeviceIdx);
749 // special case bind
750 if (boost::starts_with(keyPair.key(), "bind_"))
James Feist3cb5fec2018-01-23 14:41:51 -0800751 {
James Feist1b2e2242018-01-30 13:45:19 -0800752 if (keyPair.value().type() !=
753 nlohmann::json::value_t::string)
James Feist3cb5fec2018-01-23 14:41:51 -0800754 {
James Feist1b2e2242018-01-30 13:45:19 -0800755 std::cerr
756 << "bind_ value must be of type string "
757 << keyPair.key() << "\n";
758 continue;
James Feist3cb5fec2018-01-23 14:41:51 -0800759 }
James Feist1b2e2242018-01-30 13:45:19 -0800760 bool foundBind = false;
761 std::string bind =
762 keyPair.key().substr(sizeof("bind_") - 1);
763 for (auto &configurationPair :
764 nlohmann::json::iterator_wrapper(
765 systemConfiguration))
James Feist3cb5fec2018-01-23 14:41:51 -0800766 {
James Feist1b2e2242018-01-30 13:45:19 -0800767
768 auto configListFind =
769 configurationPair.value().find(
770 "exposes");
771
772 if (configListFind ==
773 configurationPair.value().end() ||
774 configListFind->type() !=
775 nlohmann::json::value_t::array)
James Feist3cb5fec2018-01-23 14:41:51 -0800776 {
James Feist1b2e2242018-01-30 13:45:19 -0800777 continue;
778 }
779 for (auto &exposedObject : *configListFind)
780 {
781 std::string foundObjectName =
782 (exposedObject)["name"];
783 if (boost::iequals(
784 foundObjectName,
785 keyPair.value()
786 .get<std::string>()))
James Feist3cb5fec2018-01-23 14:41:51 -0800787 {
James Feist1b2e2242018-01-30 13:45:19 -0800788 expose[bind] = exposedObject;
789 expose[bind]["status"] = "okay";
790
791 foundBind = true;
James Feist3cb5fec2018-01-23 14:41:51 -0800792 break;
793 }
794 }
James Feist1b2e2242018-01-30 13:45:19 -0800795 if (foundBind)
James Feist3cb5fec2018-01-23 14:41:51 -0800796 {
James Feist1b2e2242018-01-30 13:45:19 -0800797 break;
James Feist3cb5fec2018-01-23 14:41:51 -0800798 }
799 }
James Feist1b2e2242018-01-30 13:45:19 -0800800 if (!foundBind)
801 {
802 std::cerr << "configuration file "
803 "dependency error, "
804 "could not find bind "
805 << keyPair.value() << "\n";
806 }
James Feist3cb5fec2018-01-23 14:41:51 -0800807 }
808 }
809 }
James Feist3cb5fec2018-01-23 14:41:51 -0800810 }
James Feist1b2e2242018-01-30 13:45:19 -0800811 systemConfiguration[name] = (*it);
812 foundDeviceIdx++;
James Feist3cb5fec2018-01-23 14:41:51 -0800813 }
814
815 if (eraseConfig)
816 {
817 it = configurations.erase(it);
818 }
819 else
820 {
821 it++;
822 }
823 }
824 }
James Feist1b2e2242018-01-30 13:45:19 -0800825 // this line to be removed in future
826 writeJsonFiles(systemConfiguration);
827 std::vector<std::shared_ptr<dbus::DbusObject>> busObjects;
828 postToDbus(systemConfiguration, objServer, busObjects);
829 io.run();
James Feist3cb5fec2018-01-23 14:41:51 -0800830
831 return 0;
832}