| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1 | /* | 
 | 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 Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 17 | #include "EntityManager.hpp" | 
 | 18 |  | 
| James Feist | 481c5d5 | 2019-08-13 14:40:40 -0700 | [diff] [blame^] | 19 | #include "VariantVisitors.hpp" | 
 | 20 |  | 
| James Feist | c95cb14 | 2018-02-26 10:41:42 -0800 | [diff] [blame] | 21 | #include <Overlay.hpp> | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 22 | #include <Utils.hpp> | 
 | 23 | #include <VariantVisitors.hpp> | 
| James Feist | 11be667 | 2018-04-06 14:05:32 -0700 | [diff] [blame] | 24 | #include <boost/algorithm/string/case_conv.hpp> | 
| James Feist | f5125b0 | 2019-06-06 11:27:43 -0700 | [diff] [blame] | 25 | #include <boost/algorithm/string/classification.hpp> | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 26 | #include <boost/algorithm/string/predicate.hpp> | 
 | 27 | #include <boost/algorithm/string/replace.hpp> | 
| James Feist | f5125b0 | 2019-06-06 11:27:43 -0700 | [diff] [blame] | 28 | #include <boost/algorithm/string/split.hpp> | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 29 | #include <boost/container/flat_map.hpp> | 
 | 30 | #include <boost/container/flat_set.hpp> | 
| James Feist | f5125b0 | 2019-06-06 11:27:43 -0700 | [diff] [blame] | 31 | #include <boost/range/iterator_range.hpp> | 
| James Feist | 637b3ef | 2019-04-15 16:35:30 -0700 | [diff] [blame] | 32 | #include <filesystem> | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 33 | #include <fstream> | 
 | 34 | #include <iostream> | 
 | 35 | #include <nlohmann/json.hpp> | 
 | 36 | #include <regex> | 
 | 37 | #include <sdbusplus/asio/connection.hpp> | 
 | 38 | #include <sdbusplus/asio/object_server.hpp> | 
 | 39 | #include <variant> | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 40 |  | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 41 | constexpr const char* configurationDirectory = PACKAGE_DIR "configurations"; | 
 | 42 | constexpr const char* schemaDirectory = PACKAGE_DIR "configurations/schemas"; | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 43 | constexpr const char* tempConfigDir = "/tmp/configuration/"; | 
 | 44 | constexpr const char* lastConfiguration = "/tmp/configuration/last.json"; | 
 | 45 | constexpr const char* currentConfiguration = "/var/configuration/system.json"; | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 46 | constexpr const char* globalSchema = "global.json"; | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 47 | constexpr const int32_t MAX_MAPPER_DEPTH = 0; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 48 |  | 
| James Feist | f1b1414 | 2019-04-10 15:22:09 -0700 | [diff] [blame] | 49 | constexpr const bool DEBUG = false; | 
 | 50 |  | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 51 | struct cmp_str | 
 | 52 | { | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 53 |     bool operator()(const char* a, const char* b) const | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 54 |     { | 
 | 55 |         return std::strcmp(a, b) < 0; | 
 | 56 |     } | 
 | 57 | }; | 
 | 58 |  | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 59 | struct PerformProbe; | 
 | 60 |  | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 61 | // underscore T for collison with dbus c api | 
 | 62 | enum class probe_type_codes | 
 | 63 | { | 
 | 64 |     FALSE_T, | 
 | 65 |     TRUE_T, | 
 | 66 |     AND, | 
 | 67 |     OR, | 
| James Feist | 6bd2a02 | 2018-03-13 12:30:58 -0700 | [diff] [blame] | 68 |     FOUND, | 
 | 69 |     MATCH_ONE | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 70 | }; | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 71 | const static boost::container::flat_map<const char*, probe_type_codes, cmp_str> | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 72 |     PROBE_TYPES{{{"FALSE", probe_type_codes::FALSE_T}, | 
 | 73 |                  {"TRUE", probe_type_codes::TRUE_T}, | 
 | 74 |                  {"AND", probe_type_codes::AND}, | 
 | 75 |                  {"OR", probe_type_codes::OR}, | 
| James Feist | 6bd2a02 | 2018-03-13 12:30:58 -0700 | [diff] [blame] | 76 |                  {"FOUND", probe_type_codes::FOUND}, | 
 | 77 |                  {"MATCH_ONE", probe_type_codes::MATCH_ONE}}}; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 78 |  | 
| James Feist | 4133426 | 2019-03-25 13:30:20 -0700 | [diff] [blame] | 79 | static constexpr std::array<const char*, 5> settableInterfaces = { | 
 | 80 |     "FanProfile", "Pid", "Pid.Zone", "Stepwise", "Thresholds"}; | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 81 | using JsonVariantType = | 
| James Feist | 338b8a7 | 2019-03-01 10:16:45 -0800 | [diff] [blame] | 82 |     std::variant<std::vector<std::string>, std::vector<double>, std::string, | 
 | 83 |                  int64_t, uint64_t, double, int32_t, uint32_t, int16_t, | 
 | 84 |                  uint16_t, uint8_t, bool>; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 85 | using GetSubTreeType = std::vector< | 
 | 86 |     std::pair<std::string, | 
 | 87 |               std::vector<std::pair<std::string, std::vector<std::string>>>>>; | 
 | 88 |  | 
 | 89 | using ManagedObjectType = boost::container::flat_map< | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 90 |     sdbusplus::message::object_path, | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 91 |     boost::container::flat_map< | 
 | 92 |         std::string, | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 93 |         boost::container::flat_map<std::string, BasicVariantType>>>; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 94 |  | 
 | 95 | boost::container::flat_map< | 
 | 96 |     std::string, | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 97 |     std::vector<boost::container::flat_map<std::string, BasicVariantType>>> | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 98 |     DBUS_PROBE_OBJECTS; | 
 | 99 | std::vector<std::string> PASSED_PROBES; | 
 | 100 |  | 
 | 101 | // todo: pass this through nicer | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 102 | std::shared_ptr<sdbusplus::asio::connection> SYSTEM_BUS; | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 103 | static nlohmann::json lastJson; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 104 |  | 
| Johnathan Mantey | 2015f75 | 2019-03-26 15:22:31 -0700 | [diff] [blame] | 105 | const std::regex ILLEGAL_DBUS_PATH_REGEX("[^A-Za-z0-9_.]"); | 
 | 106 | const std::regex ILLEGAL_DBUS_MEMBER_REGEX("[^A-Za-z0-9_]"); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 107 |  | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 108 | void registerCallbacks(boost::asio::io_service& io, | 
 | 109 |                        std::vector<sdbusplus::bus::match::match>& dbusMatches, | 
 | 110 |                        nlohmann::json& systemConfiguration, | 
 | 111 |                        sdbusplus::asio::object_server& objServer); | 
| James Feist | 75fdeeb | 2018-02-20 14:26:16 -0800 | [diff] [blame] | 112 |  | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 113 | // calls the mapper to find all exposed objects of an interface type | 
 | 114 | // and creates a vector<flat_map> that contains all the key value pairs | 
 | 115 | // getManagedObjects | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 116 | void findDbusObjects(std::shared_ptr<PerformProbe> probe, | 
 | 117 |                      std::shared_ptr<sdbusplus::asio::connection> connection, | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 118 |                      std::string& interface) | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 119 | { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 120 |  | 
 | 121 |     // store reference to pending callbacks so we don't overwhelm services | 
 | 122 |     static boost::container::flat_map< | 
 | 123 |         std::string, std::vector<std::shared_ptr<PerformProbe>>> | 
 | 124 |         pendingProbes; | 
 | 125 |  | 
 | 126 |     if (DBUS_PROBE_OBJECTS[interface].size()) | 
 | 127 |     { | 
 | 128 |         return; | 
 | 129 |     } | 
 | 130 |  | 
 | 131 |     // add shared_ptr to vector of Probes waiting for callback from a specific | 
 | 132 |     // interface to keep alive while waiting for response | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 133 |     std::array<const char*, 1> objects = {interface.c_str()}; | 
 | 134 |     std::vector<std::shared_ptr<PerformProbe>>& pending = | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 135 |         pendingProbes[interface]; | 
 | 136 |     auto iter = pending.emplace(pending.end(), probe); | 
 | 137 |     // only allow first call to run to not overwhelm processes | 
 | 138 |     if (iter != pending.begin()) | 
 | 139 |     { | 
 | 140 |         return; | 
 | 141 |     } | 
 | 142 |  | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 143 |     // find all connections in the mapper that expose a specific type | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 144 |     connection->async_method_call( | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 145 |         [connection, interface, probe](boost::system::error_code& ec, | 
 | 146 |                                        const GetSubTreeType& interfaceSubtree) { | 
| James Feist | 0de4015 | 2018-07-25 11:56:12 -0700 | [diff] [blame] | 147 |             boost::container::flat_set<std::string> interfaceConnections; | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 148 |             if (ec) | 
| James Feist | 494155a | 2018-03-14 16:23:24 -0700 | [diff] [blame] | 149 |             { | 
| James Feist | 0de4015 | 2018-07-25 11:56:12 -0700 | [diff] [blame] | 150 |                 pendingProbes[interface].clear(); | 
 | 151 |                 if (ec.value() == ENOENT) | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 152 |                 { | 
| James Feist | 0de4015 | 2018-07-25 11:56:12 -0700 | [diff] [blame] | 153 |                     return; // wasn't found by mapper | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 154 |                 } | 
| James Feist | 0de4015 | 2018-07-25 11:56:12 -0700 | [diff] [blame] | 155 |                 std::cerr << "Error communicating to mapper.\n"; | 
 | 156 |  | 
 | 157 |                 // if we can't communicate to the mapper something is very wrong | 
 | 158 |                 std::exit(EXIT_FAILURE); | 
| James Feist | 494155a | 2018-03-14 16:23:24 -0700 | [diff] [blame] | 159 |             } | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 160 |             else | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 161 |             { | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 162 |                 for (auto& object : interfaceSubtree) | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 163 |                 { | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 164 |                     for (auto& connPair : object.second) | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 165 |                     { | 
| James Feist | 0eb4035 | 2019-04-09 14:44:04 -0700 | [diff] [blame] | 166 |                         interfaceConnections.insert(connPair.first); | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 167 |                     } | 
 | 168 |                 } | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 169 |             } | 
| James Feist | 63845bf | 2019-01-24 12:19:51 -0800 | [diff] [blame] | 170 |             if (interfaceConnections.empty()) | 
 | 171 |             { | 
 | 172 |                 pendingProbes[interface].clear(); | 
 | 173 |                 return; | 
 | 174 |             } | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 175 |             // get managed objects for all interfaces | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 176 |             for (const auto& conn : interfaceConnections) | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 177 |             { | 
 | 178 |                 connection->async_method_call( | 
| James Feist | 0de4015 | 2018-07-25 11:56:12 -0700 | [diff] [blame] | 179 |                     [conn, | 
| James Feist | 9813279 | 2019-07-09 13:29:09 -0700 | [diff] [blame] | 180 |                      interface](boost::system::error_code& errc, | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 181 |                                 const ManagedObjectType& managedInterface) { | 
| James Feist | 9813279 | 2019-07-09 13:29:09 -0700 | [diff] [blame] | 182 |                         if (errc) | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 183 |                         { | 
 | 184 |                             std::cerr | 
 | 185 |                                 << "error getting managed object for device " | 
 | 186 |                                 << conn << "\n"; | 
 | 187 |                             pendingProbes[interface].clear(); | 
 | 188 |                             return; | 
 | 189 |                         } | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 190 |                         for (auto& interfaceManagedObj : managedInterface) | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 191 |                         { | 
 | 192 |                             auto ifaceObjFind = | 
 | 193 |                                 interfaceManagedObj.second.find(interface); | 
 | 194 |                             if (ifaceObjFind != | 
 | 195 |                                 interfaceManagedObj.second.end()) | 
 | 196 |                             { | 
 | 197 |                                 std::vector<boost::container::flat_map< | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 198 |                                     std::string, BasicVariantType>>& | 
 | 199 |                                     dbusObject = DBUS_PROBE_OBJECTS[interface]; | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 200 |                                 dbusObject.emplace_back(ifaceObjFind->second); | 
 | 201 |                             } | 
 | 202 |                         } | 
 | 203 |                         pendingProbes[interface].clear(); | 
 | 204 |                     }, | 
 | 205 |                     conn.c_str(), "/", "org.freedesktop.DBus.ObjectManager", | 
 | 206 |                     "GetManagedObjects"); | 
 | 207 |             } | 
 | 208 |         }, | 
 | 209 |         "xyz.openbmc_project.ObjectMapper", | 
 | 210 |         "/xyz/openbmc_project/object_mapper", | 
| James Feist | 5131ac2 | 2018-10-25 12:22:23 -0700 | [diff] [blame] | 211 |         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", MAX_MAPPER_DEPTH, | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 212 |         objects); | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 213 | } | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 214 | // probes dbus interface dictionary for a key with a value that matches a regex | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 215 | bool probeDbus( | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 216 |     const std::string& interface, | 
 | 217 |     const std::map<std::string, nlohmann::json>& matches, | 
| James Feist | f1b1414 | 2019-04-10 15:22:09 -0700 | [diff] [blame] | 218 |     std::vector<std::optional< | 
 | 219 |         boost::container::flat_map<std::string, BasicVariantType>>>& devices, | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 220 |     bool& foundProbe) | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 221 | { | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 222 |     std::vector<boost::container::flat_map<std::string, BasicVariantType>>& | 
 | 223 |         dbusObject = DBUS_PROBE_OBJECTS[interface]; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 224 |     if (dbusObject.empty()) | 
 | 225 |     { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 226 |         foundProbe = false; | 
 | 227 |         return false; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 228 |     } | 
 | 229 |     foundProbe = true; | 
 | 230 |  | 
 | 231 |     bool foundMatch = false; | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 232 |     for (auto& device : dbusObject) | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 233 |     { | 
 | 234 |         bool deviceMatches = true; | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 235 |         for (auto& match : matches) | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 236 |         { | 
 | 237 |             auto deviceValue = device.find(match.first); | 
 | 238 |             if (deviceValue != device.end()) | 
 | 239 |             { | 
 | 240 |                 switch (match.second.type()) | 
 | 241 |                 { | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 242 |                     case nlohmann::json::value_t::string: | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 243 |                     { | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 244 |                         std::regex search(match.second.get<std::string>()); | 
| James Feist | 9813279 | 2019-07-09 13:29:09 -0700 | [diff] [blame] | 245 |                         std::smatch regMatch; | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 246 |  | 
 | 247 |                         // convert value to string respresentation | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 248 |                         std::string probeValue = std::visit( | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 249 |                             VariantToStringVisitor(), deviceValue->second); | 
| James Feist | 9813279 | 2019-07-09 13:29:09 -0700 | [diff] [blame] | 250 |                         if (!std::regex_search(probeValue, regMatch, search)) | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 251 |                         { | 
 | 252 |                             deviceMatches = false; | 
 | 253 |                             break; | 
 | 254 |                         } | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 255 |                         break; | 
 | 256 |                     } | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 257 |                     case nlohmann::json::value_t::boolean: | 
 | 258 |                     case nlohmann::json::value_t::number_unsigned: | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 259 |                     { | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 260 |                         unsigned int probeValue = std::visit( | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 261 |                             VariantToUnsignedIntVisitor(), deviceValue->second); | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 262 |  | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 263 |                         if (probeValue != match.second.get<unsigned int>()) | 
 | 264 |                         { | 
 | 265 |                             deviceMatches = false; | 
 | 266 |                         } | 
 | 267 |                         break; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 268 |                     } | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 269 |                     case nlohmann::json::value_t::number_integer: | 
 | 270 |                     { | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 271 |                         int probeValue = std::visit(VariantToIntVisitor(), | 
 | 272 |                                                     deviceValue->second); | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 273 |  | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 274 |                         if (probeValue != match.second.get<int>()) | 
 | 275 |                         { | 
 | 276 |                             deviceMatches = false; | 
 | 277 |                         } | 
 | 278 |                         break; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 279 |                     } | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 280 |                     case nlohmann::json::value_t::number_float: | 
 | 281 |                     { | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 282 |                         float probeValue = std::visit(VariantToFloatVisitor(), | 
 | 283 |                                                       deviceValue->second); | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 284 |  | 
 | 285 |                         if (probeValue != match.second.get<float>()) | 
 | 286 |                         { | 
 | 287 |                             deviceMatches = false; | 
 | 288 |                         } | 
 | 289 |                         break; | 
 | 290 |                     } | 
| James Feist | 0eb4035 | 2019-04-09 14:44:04 -0700 | [diff] [blame] | 291 |                     default: | 
 | 292 |                     { | 
 | 293 |                         std::cerr << "unexpected dbus probe type " | 
 | 294 |                                   << match.second.type_name() << "\n"; | 
 | 295 |                     } | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 296 |                 } | 
 | 297 |             } | 
 | 298 |             else | 
 | 299 |             { | 
 | 300 |                 deviceMatches = false; | 
 | 301 |                 break; | 
 | 302 |             } | 
 | 303 |         } | 
 | 304 |         if (deviceMatches) | 
 | 305 |         { | 
| James Feist | f5125b0 | 2019-06-06 11:27:43 -0700 | [diff] [blame] | 306 |             devices.emplace_back(device); | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 307 |             foundMatch = true; | 
 | 308 |             deviceMatches = false; // for next iteration | 
 | 309 |         } | 
 | 310 |     } | 
 | 311 |     return foundMatch; | 
 | 312 | } | 
 | 313 |  | 
 | 314 | // default probe entry point, iterates a list looking for specific types to | 
 | 315 | // call specific probe functions | 
 | 316 | bool probe( | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 317 |     const std::vector<std::string>& probeCommand, | 
| James Feist | f1b1414 | 2019-04-10 15:22:09 -0700 | [diff] [blame] | 318 |     std::vector<std::optional< | 
 | 319 |         boost::container::flat_map<std::string, BasicVariantType>>>& foundDevs) | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 320 | { | 
 | 321 |     const static std::regex command(R"(\((.*)\))"); | 
 | 322 |     std::smatch match; | 
 | 323 |     bool ret = false; | 
| James Feist | 6bd2a02 | 2018-03-13 12:30:58 -0700 | [diff] [blame] | 324 |     bool matchOne = false; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 325 |     bool cur = true; | 
 | 326 |     probe_type_codes lastCommand = probe_type_codes::FALSE_T; | 
| James Feist | 54a0dca | 2019-06-26 10:34:54 -0700 | [diff] [blame] | 327 |     bool first = true; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 328 |  | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 329 |     for (auto& probe : probeCommand) | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 330 |     { | 
 | 331 |         bool foundProbe = false; | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 332 |         boost::container::flat_map<const char*, probe_type_codes, | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 333 |                                    cmp_str>::const_iterator probeType; | 
 | 334 |  | 
 | 335 |         for (probeType = PROBE_TYPES.begin(); probeType != PROBE_TYPES.end(); | 
 | 336 |              probeType++) | 
 | 337 |         { | 
 | 338 |             if (probe.find(probeType->first) != std::string::npos) | 
 | 339 |             { | 
 | 340 |                 foundProbe = true; | 
 | 341 |                 break; | 
 | 342 |             } | 
 | 343 |         } | 
 | 344 |         if (foundProbe) | 
 | 345 |         { | 
 | 346 |             switch (probeType->second) | 
 | 347 |             { | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 348 |                 case probe_type_codes::FALSE_T: | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 349 |                 { | 
| James Feist | e31e00a | 2019-07-24 10:45:43 -0700 | [diff] [blame] | 350 |                     cur = false; | 
 | 351 |                     break; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 352 |                 } | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 353 |                 case probe_type_codes::TRUE_T: | 
 | 354 |                 { | 
| James Feist | e31e00a | 2019-07-24 10:45:43 -0700 | [diff] [blame] | 355 |                     cur = true; | 
 | 356 |                     break; | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 357 |                 } | 
 | 358 |                 case probe_type_codes::MATCH_ONE: | 
 | 359 |                 { | 
 | 360 |                     // set current value to last, this probe type shouldn't | 
 | 361 |                     // affect the outcome | 
 | 362 |                     cur = ret; | 
 | 363 |                     matchOne = true; | 
 | 364 |                     break; | 
 | 365 |                 } | 
 | 366 |                 /*case probe_type_codes::AND: | 
 | 367 |                   break; | 
 | 368 |                 case probe_type_codes::OR: | 
 | 369 |                   break; | 
 | 370 |                   // these are no-ops until the last command switch | 
 | 371 |                   */ | 
 | 372 |                 case probe_type_codes::FOUND: | 
 | 373 |                 { | 
 | 374 |                     if (!std::regex_search(probe, match, command)) | 
 | 375 |                     { | 
| James Feist | 0eb4035 | 2019-04-09 14:44:04 -0700 | [diff] [blame] | 376 |                         std::cerr << "found probe syntax error " << probe | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 377 |                                   << "\n"; | 
 | 378 |                         return false; | 
 | 379 |                     } | 
 | 380 |                     std::string commandStr = *(match.begin() + 1); | 
 | 381 |                     boost::replace_all(commandStr, "'", ""); | 
 | 382 |                     cur = (std::find(PASSED_PROBES.begin(), PASSED_PROBES.end(), | 
 | 383 |                                      commandStr) != PASSED_PROBES.end()); | 
 | 384 |                     break; | 
 | 385 |                 } | 
| James Feist | 0eb4035 | 2019-04-09 14:44:04 -0700 | [diff] [blame] | 386 |                 default: | 
 | 387 |                 { | 
 | 388 |                     break; | 
 | 389 |                 } | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 390 |             } | 
 | 391 |         } | 
 | 392 |         // look on dbus for object | 
 | 393 |         else | 
 | 394 |         { | 
 | 395 |             if (!std::regex_search(probe, match, command)) | 
 | 396 |             { | 
| James Feist | 0eb4035 | 2019-04-09 14:44:04 -0700 | [diff] [blame] | 397 |                 std::cerr << "dbus probe syntax error " << probe << "\n"; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 398 |                 return false; | 
 | 399 |             } | 
 | 400 |             std::string commandStr = *(match.begin() + 1); | 
 | 401 |             // convert single ticks and single slashes into legal json | 
| Jae Hyun Yoo | 3936e7a | 2018-03-23 17:26:16 -0700 | [diff] [blame] | 402 |             boost::replace_all(commandStr, "'", "\""); | 
| James Feist | 3f8a278 | 2018-02-12 09:24:42 -0800 | [diff] [blame] | 403 |             boost::replace_all(commandStr, R"(\)", R"(\\)"); | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 404 |             auto json = nlohmann::json::parse(commandStr, nullptr, false); | 
 | 405 |             if (json.is_discarded()) | 
 | 406 |             { | 
| James Feist | 0eb4035 | 2019-04-09 14:44:04 -0700 | [diff] [blame] | 407 |                 std::cerr << "dbus command syntax error " << commandStr << "\n"; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 408 |                 return false; | 
 | 409 |             } | 
 | 410 |             // we can match any (string, variant) property. (string, string) | 
 | 411 |             // does a regex | 
 | 412 |             std::map<std::string, nlohmann::json> dbusProbeMap = | 
 | 413 |                 json.get<std::map<std::string, nlohmann::json>>(); | 
 | 414 |             auto findStart = probe.find("("); | 
 | 415 |             if (findStart == std::string::npos) | 
 | 416 |             { | 
 | 417 |                 return false; | 
 | 418 |             } | 
 | 419 |             std::string probeInterface = probe.substr(0, findStart); | 
 | 420 |             cur = | 
 | 421 |                 probeDbus(probeInterface, dbusProbeMap, foundDevs, foundProbe); | 
 | 422 |         } | 
 | 423 |  | 
 | 424 |         // some functions like AND and OR only take affect after the | 
 | 425 |         // fact | 
| James Feist | 54a0dca | 2019-06-26 10:34:54 -0700 | [diff] [blame] | 426 |         if (lastCommand == probe_type_codes::AND) | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 427 |         { | 
| James Feist | 54a0dca | 2019-06-26 10:34:54 -0700 | [diff] [blame] | 428 |             ret = cur && ret; | 
 | 429 |         } | 
 | 430 |         else if (lastCommand == probe_type_codes::OR) | 
 | 431 |         { | 
 | 432 |             ret = cur || ret; | 
 | 433 |         } | 
 | 434 |  | 
 | 435 |         if (first) | 
 | 436 |         { | 
 | 437 |             ret = cur; | 
 | 438 |             first = false; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 439 |         } | 
 | 440 |         lastCommand = probeType != PROBE_TYPES.end() | 
 | 441 |                           ? probeType->second | 
 | 442 |                           : probe_type_codes::FALSE_T; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 443 |     } | 
 | 444 |  | 
 | 445 |     // probe passed, but empty device | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 446 |     if (ret && foundDevs.size() == 0) | 
 | 447 |     { | 
| James Feist | f1b1414 | 2019-04-10 15:22:09 -0700 | [diff] [blame] | 448 |         foundDevs.emplace_back(std::nullopt); | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 449 |     } | 
| James Feist | 0eb4035 | 2019-04-09 14:44:04 -0700 | [diff] [blame] | 450 |     if (matchOne && ret) | 
| James Feist | 6bd2a02 | 2018-03-13 12:30:58 -0700 | [diff] [blame] | 451 |     { | 
| James Feist | 71f295f | 2019-06-20 13:35:12 -0700 | [diff] [blame] | 452 |         // match the last one | 
 | 453 |         auto last = foundDevs.back(); | 
| James Feist | 0eb4035 | 2019-04-09 14:44:04 -0700 | [diff] [blame] | 454 |         foundDevs.clear(); | 
| James Feist | 71f295f | 2019-06-20 13:35:12 -0700 | [diff] [blame] | 455 |  | 
 | 456 |         foundDevs.emplace_back(std::move(last)); | 
| James Feist | 6bd2a02 | 2018-03-13 12:30:58 -0700 | [diff] [blame] | 457 |     } | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 458 |     return ret; | 
 | 459 | } | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 460 | // this class finds the needed dbus fields and on destruction runs the probe | 
 | 461 | struct PerformProbe : std::enable_shared_from_this<PerformProbe> | 
 | 462 | { | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 463 |  | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 464 |     PerformProbe( | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 465 |         const std::vector<std::string>& probeCommand, | 
| James Feist | f1b1414 | 2019-04-10 15:22:09 -0700 | [diff] [blame] | 466 |         std::function<void(std::vector<std::optional<boost::container::flat_map< | 
 | 467 |                                std::string, BasicVariantType>>>&)>&& callback) : | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 468 |         _probeCommand(probeCommand), | 
 | 469 |         _callback(std::move(callback)) | 
 | 470 |     { | 
 | 471 |     } | 
 | 472 |     ~PerformProbe() | 
 | 473 |     { | 
| James Feist | f1b1414 | 2019-04-10 15:22:09 -0700 | [diff] [blame] | 474 |         std::vector<std::optional< | 
 | 475 |             boost::container::flat_map<std::string, BasicVariantType>>> | 
| James Feist | 0eb4035 | 2019-04-09 14:44:04 -0700 | [diff] [blame] | 476 |             foundDevs; | 
 | 477 |         if (probe(_probeCommand, foundDevs)) | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 478 |         { | 
| James Feist | 0eb4035 | 2019-04-09 14:44:04 -0700 | [diff] [blame] | 479 |             _callback(foundDevs); | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 480 |         } | 
 | 481 |     } | 
 | 482 |     void run() | 
 | 483 |     { | 
 | 484 |         // parse out dbus probes by discarding other probe types | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 485 |  | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 486 |         for (std::string& probe : _probeCommand) | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 487 |         { | 
 | 488 |             bool found = false; | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 489 |             boost::container::flat_map<const char*, probe_type_codes, | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 490 |                                        cmp_str>::const_iterator probeType; | 
 | 491 |             for (probeType = PROBE_TYPES.begin(); | 
 | 492 |                  probeType != PROBE_TYPES.end(); probeType++) | 
 | 493 |             { | 
 | 494 |                 if (probe.find(probeType->first) != std::string::npos) | 
 | 495 |                 { | 
 | 496 |                     found = true; | 
 | 497 |                     break; | 
 | 498 |                 } | 
 | 499 |             } | 
 | 500 |             if (found) | 
 | 501 |             { | 
 | 502 |                 continue; | 
 | 503 |             } | 
 | 504 |             // syntax requires probe before first open brace | 
 | 505 |             auto findStart = probe.find("("); | 
 | 506 |             std::string interface = probe.substr(0, findStart); | 
 | 507 |  | 
 | 508 |             findDbusObjects(shared_from_this(), SYSTEM_BUS, interface); | 
 | 509 |         } | 
 | 510 |     } | 
 | 511 |     std::vector<std::string> _probeCommand; | 
| James Feist | f1b1414 | 2019-04-10 15:22:09 -0700 | [diff] [blame] | 512 |     std::function<void(std::vector<std::optional<boost::container::flat_map< | 
 | 513 |                            std::string, BasicVariantType>>>&)> | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 514 |         _callback; | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 515 | }; | 
 | 516 |  | 
 | 517 | // writes output files to persist data | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 518 | bool writeJsonFiles(const nlohmann::json& systemConfiguration) | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 519 | { | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 520 |     std::filesystem::create_directory(configurationOutDir); | 
 | 521 |     std::ofstream output(currentConfiguration); | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 522 |     if (!output.good()) | 
 | 523 |     { | 
 | 524 |         return false; | 
 | 525 |     } | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 526 |     output << systemConfiguration.dump(4); | 
 | 527 |     output.close(); | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 528 |     return true; | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 529 | } | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 530 |  | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 531 | template <typename JsonType> | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 532 | bool setJsonFromPointer(const std::string& ptrStr, const JsonType& value, | 
 | 533 |                         nlohmann::json& systemConfiguration) | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 534 | { | 
 | 535 |     try | 
 | 536 |     { | 
 | 537 |         nlohmann::json::json_pointer ptr(ptrStr); | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 538 |         nlohmann::json& ref = systemConfiguration[ptr]; | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 539 |         ref = value; | 
 | 540 |         return true; | 
 | 541 |     } | 
| James Feist | 9813279 | 2019-07-09 13:29:09 -0700 | [diff] [blame] | 542 |     catch (const std::out_of_range&) | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 543 |     { | 
 | 544 |         return false; | 
 | 545 |     } | 
 | 546 | } | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 547 |  | 
| James Feist | ebcc26b | 2019-03-22 12:30:43 -0700 | [diff] [blame] | 548 | // template function to add array as dbus property | 
 | 549 | template <typename PropertyType> | 
 | 550 | void addArrayToDbus(const std::string& name, const nlohmann::json& array, | 
 | 551 |                     sdbusplus::asio::dbus_interface* iface, | 
 | 552 |                     sdbusplus::asio::PropertyPermission permission, | 
 | 553 |                     nlohmann::json& systemConfiguration, | 
 | 554 |                     const std::string& jsonPointerString) | 
 | 555 | { | 
 | 556 |     std::vector<PropertyType> values; | 
 | 557 |     for (const auto& property : array) | 
 | 558 |     { | 
 | 559 |         auto ptr = property.get_ptr<const PropertyType*>(); | 
 | 560 |         if (ptr != nullptr) | 
 | 561 |         { | 
 | 562 |             values.emplace_back(*ptr); | 
 | 563 |         } | 
 | 564 |     } | 
 | 565 |  | 
 | 566 |     if (permission == sdbusplus::asio::PropertyPermission::readOnly) | 
 | 567 |     { | 
 | 568 |         iface->register_property(name, values); | 
 | 569 |     } | 
 | 570 |     else | 
 | 571 |     { | 
 | 572 |         iface->register_property( | 
 | 573 |             name, values, | 
 | 574 |             [&systemConfiguration, | 
 | 575 |              jsonPointerString{std::string(jsonPointerString)}]( | 
 | 576 |                 const std::vector<PropertyType>& newVal, | 
 | 577 |                 std::vector<PropertyType>& val) { | 
 | 578 |                 val = newVal; | 
 | 579 |                 if (!setJsonFromPointer(jsonPointerString, val, | 
 | 580 |                                         systemConfiguration)) | 
 | 581 |                 { | 
 | 582 |                     std::cerr << "error setting json field\n"; | 
 | 583 |                     return -1; | 
 | 584 |                 } | 
 | 585 |                 if (!writeJsonFiles(systemConfiguration)) | 
 | 586 |                 { | 
 | 587 |                     std::cerr << "error setting json file\n"; | 
 | 588 |                     return -1; | 
 | 589 |                 } | 
 | 590 |                 return 1; | 
 | 591 |             }); | 
 | 592 |     } | 
 | 593 | } | 
 | 594 |  | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 595 | template <typename PropertyType> | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 596 | void addProperty(const std::string& propertyName, const PropertyType& value, | 
 | 597 |                  sdbusplus::asio::dbus_interface* iface, | 
 | 598 |                  nlohmann::json& systemConfiguration, | 
 | 599 |                  const std::string& jsonPointerString, | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 600 |                  sdbusplus::asio::PropertyPermission permission) | 
 | 601 | { | 
 | 602 |     if (permission == sdbusplus::asio::PropertyPermission::readOnly) | 
 | 603 |     { | 
 | 604 |         iface->register_property(propertyName, value); | 
 | 605 |         return; | 
 | 606 |     } | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 607 |     iface->register_property( | 
 | 608 |         propertyName, value, | 
 | 609 |         [&systemConfiguration, | 
 | 610 |          jsonPointerString{std::string(jsonPointerString)}]( | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 611 |             const PropertyType& newVal, PropertyType& val) { | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 612 |             val = newVal; | 
 | 613 |             if (!setJsonFromPointer(jsonPointerString, val, | 
 | 614 |                                     systemConfiguration)) | 
 | 615 |             { | 
 | 616 |                 std::cerr << "error setting json field\n"; | 
 | 617 |                 return -1; | 
 | 618 |             } | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 619 |             if (!writeJsonFiles(systemConfiguration)) | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 620 |             { | 
 | 621 |                 std::cerr << "error setting json file\n"; | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 622 |                 return -1; | 
 | 623 |             } | 
 | 624 |             return 1; | 
 | 625 |         }); | 
 | 626 | } | 
 | 627 |  | 
 | 628 | void createDeleteObjectMethod( | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 629 |     const std::string& jsonPointerPath, | 
 | 630 |     const std::shared_ptr<sdbusplus::asio::dbus_interface>& iface, | 
 | 631 |     sdbusplus::asio::object_server& objServer, | 
 | 632 |     nlohmann::json& systemConfiguration) | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 633 | { | 
 | 634 |     std::weak_ptr<sdbusplus::asio::dbus_interface> interface = iface; | 
 | 635 |     iface->register_method( | 
 | 636 |         "Delete", [&objServer, &systemConfiguration, interface, | 
 | 637 |                    jsonPointerPath{std::string(jsonPointerPath)}]() { | 
| James Feist | 9813279 | 2019-07-09 13:29:09 -0700 | [diff] [blame] | 638 |             std::shared_ptr<sdbusplus::asio::dbus_interface> dbusInterface = | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 639 |                 interface.lock(); | 
| James Feist | 9813279 | 2019-07-09 13:29:09 -0700 | [diff] [blame] | 640 |             if (!dbusInterface) | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 641 |             { | 
 | 642 |                 // this technically can't happen as the pointer is pointing to | 
 | 643 |                 // us | 
 | 644 |                 throw DBusInternalError(); | 
 | 645 |             } | 
 | 646 |             nlohmann::json::json_pointer ptr(jsonPointerPath); | 
| James Feist | 9813279 | 2019-07-09 13:29:09 -0700 | [diff] [blame] | 647 |             if (!objServer.remove_interface(dbusInterface)) | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 648 |             { | 
 | 649 |                 std::cerr << "Can't delete interface " << jsonPointerPath | 
 | 650 |                           << "\n"; | 
 | 651 |                 throw DBusInternalError(); | 
 | 652 |             } | 
 | 653 |             systemConfiguration[ptr] = nullptr; | 
 | 654 |  | 
 | 655 |             if (!writeJsonFiles(systemConfiguration)) | 
 | 656 |             { | 
 | 657 |                 std::cerr << "error setting json file\n"; | 
 | 658 |                 throw DBusInternalError(); | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 659 |             } | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 660 |             return -1; | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 661 |         }); | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 662 | } | 
 | 663 |  | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 664 | // adds simple json types to interface's properties | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 665 | void populateInterfaceFromJson( | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 666 |     nlohmann::json& systemConfiguration, const std::string& jsonPointerPath, | 
 | 667 |     std::shared_ptr<sdbusplus::asio::dbus_interface>& iface, | 
 | 668 |     nlohmann::json& dict, sdbusplus::asio::object_server& objServer, | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 669 |     sdbusplus::asio::PropertyPermission permission = | 
 | 670 |         sdbusplus::asio::PropertyPermission::readOnly) | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 671 | { | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 672 |     for (auto& dictPair : dict.items()) | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 673 |     { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 674 |         auto type = dictPair.value().type(); | 
 | 675 |         bool array = false; | 
 | 676 |         if (dictPair.value().type() == nlohmann::json::value_t::array) | 
 | 677 |         { | 
 | 678 |             array = true; | 
 | 679 |             if (!dictPair.value().size()) | 
 | 680 |             { | 
 | 681 |                 continue; | 
 | 682 |             } | 
 | 683 |             type = dictPair.value()[0].type(); | 
 | 684 |             bool isLegal = true; | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 685 |             for (const auto& arrayItem : dictPair.value()) | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 686 |             { | 
 | 687 |                 if (arrayItem.type() != type) | 
 | 688 |                 { | 
 | 689 |                     isLegal = false; | 
 | 690 |                     break; | 
 | 691 |                 } | 
 | 692 |             } | 
 | 693 |             if (!isLegal) | 
 | 694 |             { | 
 | 695 |                 std::cerr << "dbus format error" << dictPair.value() << "\n"; | 
 | 696 |                 continue; | 
 | 697 |             } | 
| James Feist | a218ddb | 2019-04-11 14:01:31 -0700 | [diff] [blame] | 698 |         } | 
 | 699 |         if (type == nlohmann::json::value_t::object) | 
 | 700 |         { | 
 | 701 |             continue; // handled elsewhere | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 702 |         } | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 703 |         std::string key = jsonPointerPath + "/" + dictPair.key(); | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 704 |         if (permission == sdbusplus::asio::PropertyPermission::readWrite) | 
 | 705 |         { | 
 | 706 |             // all setable numbers are doubles as it is difficult to always | 
 | 707 |             // create a configuration file with all whole numbers as decimals | 
 | 708 |             // i.e. 1.0 | 
| James Feist | ebcc26b | 2019-03-22 12:30:43 -0700 | [diff] [blame] | 709 |             if (array) | 
 | 710 |             { | 
 | 711 |                 if (dictPair.value()[0].is_number()) | 
 | 712 |                 { | 
 | 713 |                     type = nlohmann::json::value_t::number_float; | 
 | 714 |                 } | 
 | 715 |             } | 
 | 716 |             else if (dictPair.value().is_number()) | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 717 |             { | 
 | 718 |                 type = nlohmann::json::value_t::number_float; | 
 | 719 |             } | 
 | 720 |         } | 
 | 721 |  | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 722 |         switch (type) | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 723 |         { | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 724 |             case (nlohmann::json::value_t::boolean): | 
 | 725 |             { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 726 |                 if (array) | 
 | 727 |                 { | 
 | 728 |                     // todo: array of bool isn't detected correctly by | 
 | 729 |                     // sdbusplus, change it to numbers | 
 | 730 |                     addArrayToDbus<uint64_t>(dictPair.key(), dictPair.value(), | 
| James Feist | ebcc26b | 2019-03-22 12:30:43 -0700 | [diff] [blame] | 731 |                                              iface.get(), permission, | 
 | 732 |                                              systemConfiguration, key); | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 733 |                 } | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 734 |  | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 735 |                 else | 
 | 736 |                 { | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 737 |                     addProperty(dictPair.key(), dictPair.value().get<bool>(), | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 738 |                                 iface.get(), systemConfiguration, key, | 
 | 739 |                                 permission); | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 740 |                 } | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 741 |                 break; | 
 | 742 |             } | 
 | 743 |             case (nlohmann::json::value_t::number_integer): | 
 | 744 |             { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 745 |                 if (array) | 
 | 746 |                 { | 
 | 747 |                     addArrayToDbus<int64_t>(dictPair.key(), dictPair.value(), | 
| James Feist | ebcc26b | 2019-03-22 12:30:43 -0700 | [diff] [blame] | 748 |                                             iface.get(), permission, | 
 | 749 |                                             systemConfiguration, key); | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 750 |                 } | 
 | 751 |                 else | 
 | 752 |                 { | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 753 |                     addProperty(dictPair.key(), dictPair.value().get<int64_t>(), | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 754 |                                 iface.get(), systemConfiguration, key, | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 755 |                                 sdbusplus::asio::PropertyPermission::readOnly); | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 756 |                 } | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 757 |                 break; | 
 | 758 |             } | 
 | 759 |             case (nlohmann::json::value_t::number_unsigned): | 
 | 760 |             { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 761 |                 if (array) | 
 | 762 |                 { | 
 | 763 |                     addArrayToDbus<uint64_t>(dictPair.key(), dictPair.value(), | 
| James Feist | ebcc26b | 2019-03-22 12:30:43 -0700 | [diff] [blame] | 764 |                                              iface.get(), permission, | 
 | 765 |                                              systemConfiguration, key); | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 766 |                 } | 
 | 767 |                 else | 
 | 768 |                 { | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 769 |                     addProperty(dictPair.key(), | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 770 |                                 dictPair.value().get<uint64_t>(), iface.get(), | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 771 |                                 systemConfiguration, key, | 
 | 772 |                                 sdbusplus::asio::PropertyPermission::readOnly); | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 773 |                 } | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 774 |                 break; | 
 | 775 |             } | 
 | 776 |             case (nlohmann::json::value_t::number_float): | 
 | 777 |             { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 778 |                 if (array) | 
 | 779 |                 { | 
 | 780 |                     addArrayToDbus<double>(dictPair.key(), dictPair.value(), | 
| James Feist | ebcc26b | 2019-03-22 12:30:43 -0700 | [diff] [blame] | 781 |                                            iface.get(), permission, | 
 | 782 |                                            systemConfiguration, key); | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 783 |                 } | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 784 |  | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 785 |                 else | 
 | 786 |                 { | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 787 |                     addProperty(dictPair.key(), dictPair.value().get<double>(), | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 788 |                                 iface.get(), systemConfiguration, key, | 
 | 789 |                                 permission); | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 790 |                 } | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 791 |                 break; | 
 | 792 |             } | 
 | 793 |             case (nlohmann::json::value_t::string): | 
 | 794 |             { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 795 |                 if (array) | 
 | 796 |                 { | 
| James Feist | ebcc26b | 2019-03-22 12:30:43 -0700 | [diff] [blame] | 797 |                     addArrayToDbus<std::string>( | 
 | 798 |                         dictPair.key(), dictPair.value(), iface.get(), | 
 | 799 |                         permission, systemConfiguration, key); | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 800 |                 } | 
 | 801 |                 else | 
 | 802 |                 { | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 803 |                     addProperty( | 
 | 804 |                         dictPair.key(), dictPair.value().get<std::string>(), | 
 | 805 |                         iface.get(), systemConfiguration, key, permission); | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 806 |                 } | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 807 |                 break; | 
 | 808 |             } | 
| James Feist | 0eb4035 | 2019-04-09 14:44:04 -0700 | [diff] [blame] | 809 |             default: | 
 | 810 |             { | 
| James Feist | a218ddb | 2019-04-11 14:01:31 -0700 | [diff] [blame] | 811 |                 std::cerr << "Unexpected json type in system configuration " | 
 | 812 |                           << dictPair.key() << ": " | 
 | 813 |                           << dictPair.value().type_name() << "\n"; | 
| James Feist | 0eb4035 | 2019-04-09 14:44:04 -0700 | [diff] [blame] | 814 |                 break; | 
 | 815 |             } | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 816 |         } | 
 | 817 |     } | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 818 |     if (permission == sdbusplus::asio::PropertyPermission::readWrite) | 
 | 819 |     { | 
 | 820 |         createDeleteObjectMethod(jsonPointerPath, iface, objServer, | 
 | 821 |                                  systemConfiguration); | 
 | 822 |     } | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 823 |     iface->initialize(); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 824 | } | 
 | 825 |  | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 826 | sdbusplus::asio::PropertyPermission getPermission(const std::string& interface) | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 827 | { | 
 | 828 |     return std::find(settableInterfaces.begin(), settableInterfaces.end(), | 
 | 829 |                      interface) != settableInterfaces.end() | 
 | 830 |                ? sdbusplus::asio::PropertyPermission::readWrite | 
 | 831 |                : sdbusplus::asio::PropertyPermission::readOnly; | 
 | 832 | } | 
 | 833 |  | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 834 | void createAddObjectMethod(const std::string& jsonPointerPath, | 
 | 835 |                            const std::string& path, | 
 | 836 |                            nlohmann::json& systemConfiguration, | 
 | 837 |                            sdbusplus::asio::object_server& objServer) | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 838 | { | 
 | 839 |     auto iface = objServer.add_interface(path, "xyz.openbmc_project.AddObject"); | 
 | 840 |  | 
 | 841 |     iface->register_method( | 
 | 842 |         "AddObject", | 
 | 843 |         [&systemConfiguration, &objServer, | 
 | 844 |          jsonPointerPath{std::string(jsonPointerPath)}, | 
 | 845 |          path{std::string(path)}]( | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 846 |             const boost::container::flat_map<std::string, JsonVariantType>& | 
 | 847 |                 data) { | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 848 |             nlohmann::json::json_pointer ptr(jsonPointerPath); | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 849 |             nlohmann::json& base = systemConfiguration[ptr]; | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 850 |             auto findExposes = base.find("Exposes"); | 
 | 851 |  | 
 | 852 |             if (findExposes == base.end()) | 
 | 853 |             { | 
 | 854 |                 throw std::invalid_argument("Entity must have children."); | 
 | 855 |             } | 
 | 856 |  | 
 | 857 |             // this will throw invalid-argument to sdbusplus if invalid json | 
 | 858 |             nlohmann::json newData{}; | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 859 |             for (const auto& item : data) | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 860 |             { | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 861 |                 nlohmann::json& newJson = newData[item.first]; | 
 | 862 |                 std::visit([&newJson](auto&& val) { newJson = std::move(val); }, | 
 | 863 |                            item.second); | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 864 |             } | 
 | 865 |  | 
 | 866 |             auto findName = newData.find("Name"); | 
 | 867 |             auto findType = newData.find("Type"); | 
 | 868 |             if (findName == newData.end() || findType == newData.end()) | 
 | 869 |             { | 
 | 870 |                 throw std::invalid_argument("AddObject missing Name or Type"); | 
 | 871 |             } | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 872 |             const std::string* type = findType->get_ptr<const std::string*>(); | 
 | 873 |             const std::string* name = findName->get_ptr<const std::string*>(); | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 874 |             if (type == nullptr || name == nullptr) | 
 | 875 |             { | 
 | 876 |                 throw std::invalid_argument("Type and Name must be a string."); | 
 | 877 |             } | 
 | 878 |  | 
 | 879 |             size_t lastIndex = 0; | 
 | 880 |             // we add in the "exposes" | 
 | 881 |             for (; lastIndex < findExposes->size(); lastIndex++) | 
 | 882 |             { | 
 | 883 |                 if (findExposes->at(lastIndex)["Name"] == *name && | 
 | 884 |                     findExposes->at(lastIndex)["Type"] == *type) | 
 | 885 |                 { | 
 | 886 |                     throw std::invalid_argument( | 
 | 887 |                         "Field already in JSON, not adding"); | 
 | 888 |                 } | 
 | 889 |                 lastIndex++; | 
 | 890 |             } | 
 | 891 |  | 
 | 892 |             std::ifstream schemaFile(std::string(schemaDirectory) + "/" + | 
 | 893 |                                      *type + ".json"); | 
 | 894 |             // todo(james) we might want to also make a list of 'can add' | 
 | 895 |             // interfaces but for now I think the assumption if there is a | 
 | 896 |             // schema avaliable that it is allowed to update is fine | 
 | 897 |             if (!schemaFile.good()) | 
 | 898 |             { | 
 | 899 |                 throw std::invalid_argument( | 
 | 900 |                     "No schema avaliable, cannot validate."); | 
 | 901 |             } | 
 | 902 |             nlohmann::json schema = | 
 | 903 |                 nlohmann::json::parse(schemaFile, nullptr, false); | 
 | 904 |             if (schema.is_discarded()) | 
 | 905 |             { | 
 | 906 |                 std::cerr << "Schema not legal" << *type << ".json\n"; | 
 | 907 |                 throw DBusInternalError(); | 
 | 908 |             } | 
 | 909 |             if (!validateJson(schema, newData)) | 
 | 910 |             { | 
 | 911 |                 throw std::invalid_argument("Data does not match schema"); | 
 | 912 |             } | 
 | 913 |  | 
| James Feist | 16a02f2 | 2019-05-13 15:21:37 -0700 | [diff] [blame] | 914 |             findExposes->push_back(newData); | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 915 |             if (!writeJsonFiles(systemConfiguration)) | 
 | 916 |             { | 
 | 917 |                 std::cerr << "Error writing json files\n"; | 
 | 918 |                 throw DBusInternalError(); | 
 | 919 |             } | 
 | 920 |             std::string dbusName = *name; | 
 | 921 |  | 
 | 922 |             std::regex_replace(dbusName.begin(), dbusName.begin(), | 
| Johnathan Mantey | 2015f75 | 2019-03-26 15:22:31 -0700 | [diff] [blame] | 923 |                                dbusName.end(), ILLEGAL_DBUS_MEMBER_REGEX, "_"); | 
| James Feist | 9813279 | 2019-07-09 13:29:09 -0700 | [diff] [blame] | 924 |             auto interface = objServer.add_interface( | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 925 |                 path + "/" + dbusName, | 
 | 926 |                 "xyz.openbmc_project.Configuration." + *type); | 
 | 927 |             // permission is read-write, as since we just created it, must be | 
 | 928 |             // runtime modifiable | 
 | 929 |             populateInterfaceFromJson( | 
 | 930 |                 systemConfiguration, | 
| James Feist | 16a02f2 | 2019-05-13 15:21:37 -0700 | [diff] [blame] | 931 |                 jsonPointerPath + "/Exposes/" + std::to_string(lastIndex), | 
| James Feist | 9813279 | 2019-07-09 13:29:09 -0700 | [diff] [blame] | 932 |                 interface, newData, objServer, | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 933 |                 sdbusplus::asio::PropertyPermission::readWrite); | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 934 |         }); | 
 | 935 |     iface->initialize(); | 
 | 936 | } | 
 | 937 |  | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 938 | void postToDbus(const nlohmann::json& newConfiguration, | 
 | 939 |                 nlohmann::json& systemConfiguration, | 
 | 940 |                 sdbusplus::asio::object_server& objServer) | 
| James Feist | 75fdeeb | 2018-02-20 14:26:16 -0800 | [diff] [blame] | 941 |  | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 942 | { | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 943 |     // iterate through boards | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 944 |     for (auto& boardPair : newConfiguration.items()) | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 945 |     { | 
| James Feist | f1b1414 | 2019-04-10 15:22:09 -0700 | [diff] [blame] | 946 |         std::string boardKey = boardPair.value()["Name"]; | 
 | 947 |         std::string jsonPointerPath = "/" + boardPair.key(); | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 948 |         // loop through newConfiguration, but use values from system | 
 | 949 |         // configuration to be able to modify via dbus later | 
| James Feist | f1b1414 | 2019-04-10 15:22:09 -0700 | [diff] [blame] | 950 |         auto boardValues = systemConfiguration[boardPair.key()]; | 
| James Feist | d63d18a | 2018-07-19 15:23:45 -0700 | [diff] [blame] | 951 |         auto findBoardType = boardValues.find("Type"); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 952 |         std::string boardType; | 
 | 953 |         if (findBoardType != boardValues.end() && | 
 | 954 |             findBoardType->type() == nlohmann::json::value_t::string) | 
 | 955 |         { | 
 | 956 |             boardType = findBoardType->get<std::string>(); | 
 | 957 |             std::regex_replace(boardType.begin(), boardType.begin(), | 
| Johnathan Mantey | 2015f75 | 2019-03-26 15:22:31 -0700 | [diff] [blame] | 958 |                                boardType.end(), ILLEGAL_DBUS_MEMBER_REGEX, "_"); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 959 |         } | 
 | 960 |         else | 
 | 961 |         { | 
 | 962 |             std::cerr << "Unable to find type for " << boardKey | 
 | 963 |                       << " reverting to Chassis.\n"; | 
 | 964 |             boardType = "Chassis"; | 
 | 965 |         } | 
| James Feist | 11be667 | 2018-04-06 14:05:32 -0700 | [diff] [blame] | 966 |         std::string boardtypeLower = boost::algorithm::to_lower_copy(boardType); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 967 |  | 
 | 968 |         std::regex_replace(boardKey.begin(), boardKey.begin(), boardKey.end(), | 
| Johnathan Mantey | 2015f75 | 2019-03-26 15:22:31 -0700 | [diff] [blame] | 969 |                            ILLEGAL_DBUS_MEMBER_REGEX, "_"); | 
| James Feist | 11be667 | 2018-04-06 14:05:32 -0700 | [diff] [blame] | 970 |         std::string boardName = "/xyz/openbmc_project/inventory/system/" + | 
 | 971 |                                 boardtypeLower + "/" + boardKey; | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 972 |  | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 973 |         auto inventoryIface = objServer.add_interface( | 
 | 974 |             boardName, "xyz.openbmc_project.Inventory.Item"); | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 975 |  | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 976 |         auto boardIface = objServer.add_interface( | 
 | 977 |             boardName, "xyz.openbmc_project.Inventory.Item." + boardType); | 
| James Feist | 11be667 | 2018-04-06 14:05:32 -0700 | [diff] [blame] | 978 |  | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 979 |         createAddObjectMethod(jsonPointerPath, boardName, systemConfiguration, | 
 | 980 |                               objServer); | 
 | 981 |  | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 982 |         populateInterfaceFromJson(systemConfiguration, jsonPointerPath, | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 983 |                                   boardIface, boardValues, objServer); | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 984 |         jsonPointerPath += "/"; | 
 | 985 |         // iterate through board properties | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 986 |         for (auto& boardField : boardValues.items()) | 
| James Feist | 11be667 | 2018-04-06 14:05:32 -0700 | [diff] [blame] | 987 |         { | 
 | 988 |             if (boardField.value().type() == nlohmann::json::value_t::object) | 
 | 989 |             { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 990 |                 auto iface = | 
 | 991 |                     objServer.add_interface(boardName, boardField.key()); | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 992 |                 populateInterfaceFromJson(systemConfiguration, | 
 | 993 |                                           jsonPointerPath + boardField.key(), | 
 | 994 |                                           iface, boardField.value(), objServer); | 
| James Feist | 11be667 | 2018-04-06 14:05:32 -0700 | [diff] [blame] | 995 |             } | 
 | 996 |         } | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 997 |  | 
| James Feist | 1e3e698 | 2018-08-03 16:09:28 -0700 | [diff] [blame] | 998 |         auto exposes = boardValues.find("Exposes"); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 999 |         if (exposes == boardValues.end()) | 
 | 1000 |         { | 
 | 1001 |             continue; | 
 | 1002 |         } | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 1003 |         // iterate through exposes | 
| James Feist | 1e3e698 | 2018-08-03 16:09:28 -0700 | [diff] [blame] | 1004 |         jsonPointerPath += "Exposes/"; | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 1005 |  | 
 | 1006 |         // store the board level pointer so we can modify it on the way down | 
 | 1007 |         std::string jsonPointerPathBoard = jsonPointerPath; | 
 | 1008 |         size_t exposesIndex = -1; | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 1009 |         for (auto& item : *exposes) | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1010 |         { | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 1011 |             exposesIndex++; | 
 | 1012 |             jsonPointerPath = jsonPointerPathBoard; | 
 | 1013 |             jsonPointerPath += std::to_string(exposesIndex); | 
 | 1014 |  | 
| James Feist | d63d18a | 2018-07-19 15:23:45 -0700 | [diff] [blame] | 1015 |             auto findName = item.find("Name"); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1016 |             if (findName == item.end()) | 
 | 1017 |             { | 
 | 1018 |                 std::cerr << "cannot find name in field " << item << "\n"; | 
 | 1019 |                 continue; | 
 | 1020 |             } | 
| James Feist | 1e3e698 | 2018-08-03 16:09:28 -0700 | [diff] [blame] | 1021 |             auto findStatus = item.find("Status"); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1022 |             // if status is not found it is assumed to be status = 'okay' | 
 | 1023 |             if (findStatus != item.end()) | 
 | 1024 |             { | 
 | 1025 |                 if (*findStatus == "disabled") | 
 | 1026 |                 { | 
 | 1027 |                     continue; | 
 | 1028 |                 } | 
 | 1029 |             } | 
| James Feist | d63d18a | 2018-07-19 15:23:45 -0700 | [diff] [blame] | 1030 |             auto findType = item.find("Type"); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1031 |             std::string itemType; | 
 | 1032 |             if (findType != item.end()) | 
 | 1033 |             { | 
 | 1034 |                 itemType = findType->get<std::string>(); | 
 | 1035 |                 std::regex_replace(itemType.begin(), itemType.begin(), | 
| Johnathan Mantey | 2015f75 | 2019-03-26 15:22:31 -0700 | [diff] [blame] | 1036 |                                    itemType.end(), ILLEGAL_DBUS_PATH_REGEX, | 
 | 1037 |                                    "_"); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1038 |             } | 
 | 1039 |             else | 
 | 1040 |             { | 
 | 1041 |                 itemType = "unknown"; | 
 | 1042 |             } | 
 | 1043 |             std::string itemName = findName->get<std::string>(); | 
 | 1044 |             std::regex_replace(itemName.begin(), itemName.begin(), | 
| Johnathan Mantey | 2015f75 | 2019-03-26 15:22:31 -0700 | [diff] [blame] | 1045 |                                itemName.end(), ILLEGAL_DBUS_MEMBER_REGEX, "_"); | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 1046 |  | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1047 |             auto itemIface = objServer.add_interface( | 
 | 1048 |                 boardName + "/" + itemName, | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1049 |                 "xyz.openbmc_project.Configuration." + itemType); | 
 | 1050 |  | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 1051 |             populateInterfaceFromJson(systemConfiguration, jsonPointerPath, | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 1052 |                                       itemIface, item, objServer, | 
 | 1053 |                                       getPermission(itemType)); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1054 |  | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 1055 |             for (auto& objectPair : item.items()) | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1056 |             { | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 1057 |                 jsonPointerPath = jsonPointerPathBoard + | 
 | 1058 |                                   std::to_string(exposesIndex) + "/" + | 
 | 1059 |                                   objectPair.key(); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1060 |                 if (objectPair.value().type() == | 
 | 1061 |                     nlohmann::json::value_t::object) | 
 | 1062 |                 { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1063 |                     auto objectIface = objServer.add_interface( | 
 | 1064 |                         boardName + "/" + itemName, | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1065 |                         "xyz.openbmc_project.Configuration." + itemType + "." + | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1066 |                             objectPair.key()); | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 1067 |  | 
 | 1068 |                     populateInterfaceFromJson( | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 1069 |                         systemConfiguration, jsonPointerPath, objectIface, | 
 | 1070 |                         objectPair.value(), objServer, getPermission(itemType)); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1071 |                 } | 
 | 1072 |                 else if (objectPair.value().type() == | 
 | 1073 |                          nlohmann::json::value_t::array) | 
 | 1074 |                 { | 
 | 1075 |                     size_t index = 0; | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1076 |                     if (!objectPair.value().size()) | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1077 |                     { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1078 |                         continue; | 
 | 1079 |                     } | 
 | 1080 |                     bool isLegal = true; | 
 | 1081 |                     auto type = objectPair.value()[0].type(); | 
 | 1082 |                     if (type != nlohmann::json::value_t::object) | 
 | 1083 |                     { | 
 | 1084 |                         continue; | 
 | 1085 |                     } | 
 | 1086 |  | 
 | 1087 |                     // verify legal json | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 1088 |                     for (const auto& arrayItem : objectPair.value()) | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1089 |                     { | 
 | 1090 |                         if (arrayItem.type() != type) | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1091 |                         { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1092 |                             isLegal = false; | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1093 |                             break; | 
 | 1094 |                         } | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1095 |                     } | 
 | 1096 |                     if (!isLegal) | 
 | 1097 |                     { | 
 | 1098 |                         std::cerr << "dbus format error" << objectPair.value() | 
 | 1099 |                                   << "\n"; | 
 | 1100 |                         break; | 
 | 1101 |                     } | 
 | 1102 |  | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 1103 |                     for (auto& arrayItem : objectPair.value()) | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1104 |                     { | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 1105 |  | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1106 |                         auto objectIface = objServer.add_interface( | 
 | 1107 |                             boardName + "/" + itemName, | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1108 |                             "xyz.openbmc_project.Configuration." + itemType + | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 1109 |                                 "." + objectPair.key() + std::to_string(index)); | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 1110 |                         populateInterfaceFromJson( | 
 | 1111 |                             systemConfiguration, | 
 | 1112 |                             jsonPointerPath + "/" + std::to_string(index), | 
 | 1113 |                             objectIface, arrayItem, objServer, | 
 | 1114 |                             getPermission(objectPair.key())); | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 1115 |                         index++; | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1116 |                     } | 
 | 1117 |                 } | 
 | 1118 |             } | 
 | 1119 |         } | 
 | 1120 |     } | 
 | 1121 | } | 
 | 1122 |  | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1123 | // reads json files out of the filesystem | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 1124 | bool findJsonFiles(std::list<nlohmann::json>& configurations) | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1125 | { | 
 | 1126 |     // find configuration files | 
| Ed Tanous | 072e25d | 2018-12-16 21:45:20 -0800 | [diff] [blame] | 1127 |     std::vector<std::filesystem::path> jsonPaths; | 
| Johnathan Mantey | 2015f75 | 2019-03-26 15:22:31 -0700 | [diff] [blame] | 1128 |     if (!findFiles(std::filesystem::path(configurationDirectory), R"(.*\.json)", | 
 | 1129 |                    jsonPaths)) | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1130 |     { | 
 | 1131 |         std::cerr << "Unable to find any configuration files in " | 
| James Feist | b4383f4 | 2018-08-06 16:54:10 -0700 | [diff] [blame] | 1132 |                   << configurationDirectory << "\n"; | 
| James Feist | 75fdeeb | 2018-02-20 14:26:16 -0800 | [diff] [blame] | 1133 |         return false; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1134 |     } | 
| James Feist | b4383f4 | 2018-08-06 16:54:10 -0700 | [diff] [blame] | 1135 |  | 
 | 1136 |     std::ifstream schemaStream(std::string(schemaDirectory) + "/" + | 
 | 1137 |                                globalSchema); | 
 | 1138 |     if (!schemaStream.good()) | 
 | 1139 |     { | 
 | 1140 |         std::cerr | 
 | 1141 |             << "Cannot open schema file,  cannot validate JSON, exiting\n\n"; | 
 | 1142 |         std::exit(EXIT_FAILURE); | 
| Ed Tanous | 072e25d | 2018-12-16 21:45:20 -0800 | [diff] [blame] | 1143 |         return false; | 
| James Feist | b4383f4 | 2018-08-06 16:54:10 -0700 | [diff] [blame] | 1144 |     } | 
 | 1145 |     nlohmann::json schema = nlohmann::json::parse(schemaStream, nullptr, false); | 
 | 1146 |     if (schema.is_discarded()) | 
 | 1147 |     { | 
 | 1148 |         std::cerr | 
 | 1149 |             << "Illegal schema file detected, cannot validate JSON, exiting\n"; | 
 | 1150 |         std::exit(EXIT_FAILURE); | 
| Ed Tanous | 072e25d | 2018-12-16 21:45:20 -0800 | [diff] [blame] | 1151 |         return false; | 
| James Feist | b4383f4 | 2018-08-06 16:54:10 -0700 | [diff] [blame] | 1152 |     } | 
 | 1153 |  | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 1154 |     for (auto& jsonPath : jsonPaths) | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1155 |     { | 
 | 1156 |         std::ifstream jsonStream(jsonPath.c_str()); | 
 | 1157 |         if (!jsonStream.good()) | 
 | 1158 |         { | 
 | 1159 |             std::cerr << "unable to open " << jsonPath.string() << "\n"; | 
 | 1160 |             continue; | 
 | 1161 |         } | 
 | 1162 |         auto data = nlohmann::json::parse(jsonStream, nullptr, false); | 
 | 1163 |         if (data.is_discarded()) | 
 | 1164 |         { | 
 | 1165 |             std::cerr << "syntax error in " << jsonPath.string() << "\n"; | 
 | 1166 |             continue; | 
 | 1167 |         } | 
| James Feist | 8da9919 | 2019-01-24 08:20:16 -0800 | [diff] [blame] | 1168 |         /* | 
 | 1169 |          * todo(james): reenable this once less things are in flight | 
 | 1170 |          * | 
| James Feist | b4383f4 | 2018-08-06 16:54:10 -0700 | [diff] [blame] | 1171 |         if (!validateJson(schema, data)) | 
 | 1172 |         { | 
 | 1173 |             std::cerr << "Error validating " << jsonPath.string() << "\n"; | 
 | 1174 |             continue; | 
 | 1175 |         } | 
| James Feist | 8da9919 | 2019-01-24 08:20:16 -0800 | [diff] [blame] | 1176 |         */ | 
| James Feist | b4383f4 | 2018-08-06 16:54:10 -0700 | [diff] [blame] | 1177 |  | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1178 |         if (data.type() == nlohmann::json::value_t::array) | 
 | 1179 |         { | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 1180 |             for (auto& d : data) | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1181 |             { | 
 | 1182 |                 configurations.emplace_back(d); | 
 | 1183 |             } | 
 | 1184 |         } | 
 | 1185 |         else | 
 | 1186 |         { | 
 | 1187 |             configurations.emplace_back(data); | 
 | 1188 |         } | 
 | 1189 |     } | 
| Ed Tanous | 072e25d | 2018-12-16 21:45:20 -0800 | [diff] [blame] | 1190 |     return true; | 
| James Feist | 75fdeeb | 2018-02-20 14:26:16 -0800 | [diff] [blame] | 1191 | } | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1192 |  | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1193 | struct PerformScan : std::enable_shared_from_this<PerformScan> | 
| James Feist | 75fdeeb | 2018-02-20 14:26:16 -0800 | [diff] [blame] | 1194 | { | 
| James Feist | 75fdeeb | 2018-02-20 14:26:16 -0800 | [diff] [blame] | 1195 |  | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 1196 |     PerformScan(nlohmann::json& systemConfiguration, | 
 | 1197 |                 std::list<nlohmann::json>& configurations, | 
 | 1198 |                 std::function<void(void)>&& callback) : | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1199 |         _systemConfiguration(systemConfiguration), | 
 | 1200 |         _configurations(configurations), _callback(std::move(callback)) | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1201 |     { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1202 |     } | 
 | 1203 |     void run() | 
 | 1204 |     { | 
 | 1205 |         for (auto it = _configurations.begin(); it != _configurations.end();) | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1206 |         { | 
| James Feist | 1e3e698 | 2018-08-03 16:09:28 -0700 | [diff] [blame] | 1207 |             auto findProbe = it->find("Probe"); | 
| James Feist | d63d18a | 2018-07-19 15:23:45 -0700 | [diff] [blame] | 1208 |             auto findName = it->find("Name"); | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1209 |  | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1210 |             nlohmann::json probeCommand; | 
 | 1211 |             // check for poorly formatted fields, probe must be an array | 
 | 1212 |             if (findProbe == it->end()) | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1213 |             { | 
 | 1214 |                 std::cerr << "configuration file missing probe:\n " << *it | 
 | 1215 |                           << "\n"; | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1216 |                 it = _configurations.erase(it); | 
 | 1217 |                 continue; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1218 |             } | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1219 |             else if ((*findProbe).type() != nlohmann::json::value_t::array) | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1220 |             { | 
 | 1221 |                 probeCommand = nlohmann::json::array(); | 
 | 1222 |                 probeCommand.push_back(*findProbe); | 
 | 1223 |             } | 
 | 1224 |             else | 
 | 1225 |             { | 
 | 1226 |                 probeCommand = *findProbe; | 
 | 1227 |             } | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1228 |  | 
 | 1229 |             if (findName == it->end()) | 
 | 1230 |             { | 
 | 1231 |                 std::cerr << "configuration file missing name:\n " << *it | 
 | 1232 |                           << "\n"; | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1233 |                 it = _configurations.erase(it); | 
 | 1234 |                 continue; | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1235 |             } | 
| James Feist | f1b1414 | 2019-04-10 15:22:09 -0700 | [diff] [blame] | 1236 |             std::string probeName = *findName; | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1237 |  | 
| James Feist | f1b1414 | 2019-04-10 15:22:09 -0700 | [diff] [blame] | 1238 |             if (std::find(PASSED_PROBES.begin(), PASSED_PROBES.end(), | 
 | 1239 |                           probeName) != PASSED_PROBES.end()) | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1240 |             { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1241 |                 it = _configurations.erase(it); | 
 | 1242 |                 continue; | 
 | 1243 |             } | 
| James Feist | f1b1414 | 2019-04-10 15:22:09 -0700 | [diff] [blame] | 1244 |             nlohmann::json* recordPtr = &(*it); | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1245 |  | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1246 |             // store reference to this to children to makes sure we don't get | 
 | 1247 |             // destroyed too early | 
 | 1248 |             auto thisRef = shared_from_this(); | 
 | 1249 |             auto p = std::make_shared<PerformProbe>( | 
 | 1250 |                 probeCommand, | 
| James Feist | f1b1414 | 2019-04-10 15:22:09 -0700 | [diff] [blame] | 1251 |                 [&, recordPtr, probeName, | 
 | 1252 |                  thisRef](std::vector<std::optional<boost::container::flat_map< | 
 | 1253 |                               std::string, BasicVariantType>>>& foundDevices) { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1254 |                     _passed = true; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1255 |  | 
| James Feist | f1b1414 | 2019-04-10 15:22:09 -0700 | [diff] [blame] | 1256 |                     PASSED_PROBES.push_back(probeName); | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1257 |                     size_t foundDeviceIdx = 0; | 
 | 1258 |  | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 1259 |                     for (auto& foundDevice : foundDevices) | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1260 |                     { | 
| James Feist | f5125b0 | 2019-06-06 11:27:43 -0700 | [diff] [blame] | 1261 |                         nlohmann::json record = *recordPtr; | 
| James Feist | f1b1414 | 2019-04-10 15:22:09 -0700 | [diff] [blame] | 1262 |                         std::string recordName; | 
 | 1263 |                         size_t hash = 0; | 
 | 1264 |                         if (foundDevice) | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1265 |                         { | 
| James Feist | f1b1414 | 2019-04-10 15:22:09 -0700 | [diff] [blame] | 1266 |                             // use an array so alphabetical order from the | 
 | 1267 |                             // flat_map is maintained | 
 | 1268 |                             auto device = nlohmann::json::array(); | 
 | 1269 |                             for (auto& devPair : *foundDevice) | 
 | 1270 |                             { | 
 | 1271 |                                 device.push_back(devPair.first); | 
 | 1272 |                                 std::visit( | 
 | 1273 |                                     [&device](auto&& v) { | 
 | 1274 |                                         device.push_back(v); | 
 | 1275 |                                     }, | 
 | 1276 |                                     devPair.second); | 
 | 1277 |                             } | 
 | 1278 |                             hash = std::hash<std::string>{}(probeName + | 
 | 1279 |                                                             device.dump()); | 
 | 1280 |                             // hashes are hard to distinguish, use the | 
 | 1281 |                             // non-hashed version if we want debug | 
 | 1282 |                             if constexpr (DEBUG) | 
 | 1283 |                             { | 
 | 1284 |                                 recordName = probeName + device.dump(); | 
 | 1285 |                             } | 
 | 1286 |                             else | 
 | 1287 |                             { | 
 | 1288 |                                 recordName = std::to_string(hash); | 
 | 1289 |                             } | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1290 |                         } | 
| James Feist | f1b1414 | 2019-04-10 15:22:09 -0700 | [diff] [blame] | 1291 |                         else | 
 | 1292 |                         { | 
 | 1293 |                             recordName = probeName; | 
 | 1294 |                         } | 
 | 1295 |  | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 1296 |                         auto fromLastJson = lastJson.find(recordName); | 
 | 1297 |                         if (fromLastJson != lastJson.end()) | 
 | 1298 |                         { | 
 | 1299 |                             // keep user changes | 
 | 1300 |                             _systemConfiguration[recordName] = *fromLastJson; | 
 | 1301 |                             continue; | 
 | 1302 |                         } | 
 | 1303 |  | 
| James Feist | f1b1414 | 2019-04-10 15:22:09 -0700 | [diff] [blame] | 1304 |                         // insert into configuration temporarily to be able to | 
 | 1305 |                         // reference ourselves | 
 | 1306 |  | 
 | 1307 |                         _systemConfiguration[recordName] = record; | 
 | 1308 |  | 
 | 1309 |                         if (foundDevice) | 
 | 1310 |                         { | 
 | 1311 |                             for (auto keyPair = record.begin(); | 
 | 1312 |                                  keyPair != record.end(); keyPair++) | 
 | 1313 |                             { | 
 | 1314 |                                 templateCharReplace(keyPair, *foundDevice, | 
 | 1315 |                                                     foundDeviceIdx); | 
 | 1316 |                             } | 
 | 1317 |                         } | 
| Patrick Venture | b8293c0 | 2019-08-09 14:12:47 -0700 | [diff] [blame] | 1318 |  | 
| James Feist | f1b1414 | 2019-04-10 15:22:09 -0700 | [diff] [blame] | 1319 |                         auto findExpose = record.find("Exposes"); | 
 | 1320 |                         if (findExpose == record.end()) | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1321 |                         { | 
| Patrick Venture | b8293c0 | 2019-08-09 14:12:47 -0700 | [diff] [blame] | 1322 |                             _systemConfiguration[recordName] = record; | 
 | 1323 |                             logDeviceAdded(record); | 
 | 1324 |                             foundDeviceIdx++; | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1325 |                             continue; | 
 | 1326 |                         } | 
| Patrick Venture | b8293c0 | 2019-08-09 14:12:47 -0700 | [diff] [blame] | 1327 |  | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 1328 |                         for (auto& expose : *findExpose) | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1329 |                         { | 
 | 1330 |                             for (auto keyPair = expose.begin(); | 
 | 1331 |                                  keyPair != expose.end(); keyPair++) | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1332 |                             { | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1333 |  | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1334 |                                 // fill in template characters with devices | 
 | 1335 |                                 // found | 
| James Feist | f1b1414 | 2019-04-10 15:22:09 -0700 | [diff] [blame] | 1336 |                                 if (foundDevice) | 
 | 1337 |                                 { | 
 | 1338 |                                     templateCharReplace(keyPair, *foundDevice, | 
 | 1339 |                                                         foundDeviceIdx); | 
 | 1340 |                                 } | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1341 |                                 // special case bind | 
| James Feist | 1e3e698 | 2018-08-03 16:09:28 -0700 | [diff] [blame] | 1342 |                                 if (boost::starts_with(keyPair.key(), "Bind")) | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1343 |                                 { | 
 | 1344 |                                     if (keyPair.value().type() != | 
 | 1345 |                                         nlohmann::json::value_t::string) | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1346 |                                     { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1347 |                                         std::cerr << "bind_ value must be of " | 
 | 1348 |                                                      "type string " | 
 | 1349 |                                                   << keyPair.key() << "\n"; | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1350 |                                         continue; | 
 | 1351 |                                     } | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1352 |                                     bool foundBind = false; | 
 | 1353 |                                     std::string bind = keyPair.key().substr( | 
| James Feist | 1e3e698 | 2018-08-03 16:09:28 -0700 | [diff] [blame] | 1354 |                                         sizeof("Bind") - 1); | 
| James Feist | be5425f | 2018-06-08 10:30:55 -0700 | [diff] [blame] | 1355 |  | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 1356 |                                     for (auto& configurationPair : | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1357 |                                          _systemConfiguration.items()) | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1358 |                                     { | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1359 |  | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1360 |                                         auto configListFind = | 
 | 1361 |                                             configurationPair.value().find( | 
| James Feist | 1e3e698 | 2018-08-03 16:09:28 -0700 | [diff] [blame] | 1362 |                                                 "Exposes"); | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1363 |  | 
 | 1364 |                                         if (configListFind == | 
 | 1365 |                                                 configurationPair.value() | 
 | 1366 |                                                     .end() || | 
 | 1367 |                                             configListFind->type() != | 
 | 1368 |                                                 nlohmann::json::value_t::array) | 
 | 1369 |                                         { | 
 | 1370 |                                             continue; | 
 | 1371 |                                         } | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 1372 |                                         for (auto& exposedObject : | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1373 |                                              *configListFind) | 
 | 1374 |                                         { | 
 | 1375 |                                             std::string foundObjectName = | 
| James Feist | d63d18a | 2018-07-19 15:23:45 -0700 | [diff] [blame] | 1376 |                                                 (exposedObject)["Name"]; | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1377 |                                             if (boost::iequals( | 
 | 1378 |                                                     foundObjectName, | 
 | 1379 |                                                     keyPair.value() | 
 | 1380 |                                                         .get<std::string>())) | 
 | 1381 |                                             { | 
| James Feist | 1e3e698 | 2018-08-03 16:09:28 -0700 | [diff] [blame] | 1382 |                                                 exposedObject["Status"] = | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1383 |                                                     "okay"; | 
 | 1384 |                                                 expose[bind] = exposedObject; | 
 | 1385 |  | 
 | 1386 |                                                 foundBind = true; | 
 | 1387 |                                                 break; | 
 | 1388 |                                             } | 
 | 1389 |                                         } | 
 | 1390 |                                         if (foundBind) | 
 | 1391 |                                         { | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1392 |                                             break; | 
 | 1393 |                                         } | 
 | 1394 |                                     } | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1395 |                                     if (!foundBind) | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1396 |                                     { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1397 |                                         std::cerr << "configuration file " | 
 | 1398 |                                                      "dependency error, " | 
 | 1399 |                                                      "could not find bind " | 
 | 1400 |                                                   << keyPair.value() << "\n"; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1401 |                                     } | 
 | 1402 |                                 } | 
 | 1403 |                             } | 
 | 1404 |                         } | 
| James Feist | f1b1414 | 2019-04-10 15:22:09 -0700 | [diff] [blame] | 1405 |                         // overwrite ourselves with cleaned up version | 
 | 1406 |                         _systemConfiguration[recordName] = record; | 
| James Feist | 1a99658 | 2019-05-14 15:10:06 -0700 | [diff] [blame] | 1407 |  | 
 | 1408 |                         logDeviceAdded(record); | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 1409 |  | 
| James Feist | f1b1414 | 2019-04-10 15:22:09 -0700 | [diff] [blame] | 1410 |                         foundDeviceIdx++; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1411 |                     } | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1412 |                 }); | 
 | 1413 |             p->run(); | 
 | 1414 |             it++; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1415 |         } | 
 | 1416 |     } | 
| James Feist | 75fdeeb | 2018-02-20 14:26:16 -0800 | [diff] [blame] | 1417 |  | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1418 |     ~PerformScan() | 
| James Feist | 75fdeeb | 2018-02-20 14:26:16 -0800 | [diff] [blame] | 1419 |     { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1420 |         if (_passed) | 
 | 1421 |         { | 
 | 1422 |             auto nextScan = std::make_shared<PerformScan>( | 
 | 1423 |                 _systemConfiguration, _configurations, std::move(_callback)); | 
 | 1424 |             nextScan->run(); | 
 | 1425 |         } | 
 | 1426 |         else | 
 | 1427 |         { | 
 | 1428 |             _callback(); | 
 | 1429 |         } | 
 | 1430 |     } | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 1431 |     nlohmann::json& _systemConfiguration; | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1432 |     std::list<nlohmann::json> _configurations; | 
 | 1433 |     std::function<void(void)> _callback; | 
 | 1434 |     std::vector<std::shared_ptr<PerformProbe>> _probes; | 
 | 1435 |     bool _passed = false; | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 1436 |     bool powerWasOn = isPowerOn(); | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1437 | }; | 
| James Feist | c95cb14 | 2018-02-26 10:41:42 -0800 | [diff] [blame] | 1438 |  | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 1439 | void startRemovedTimer(boost::asio::deadline_timer& timer, | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 1440 |                        nlohmann::json& systemConfiguration) | 
 | 1441 | { | 
 | 1442 |     static bool scannedPowerOff = false; | 
 | 1443 |     static bool scannedPowerOn = false; | 
 | 1444 |  | 
| James Feist | fb00f39 | 2019-06-25 14:16:48 -0700 | [diff] [blame] | 1445 |     if (systemConfiguration.empty() || lastJson.empty()) | 
 | 1446 |     { | 
 | 1447 |         return; // not ready yet | 
 | 1448 |     } | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 1449 |     if (scannedPowerOn) | 
 | 1450 |     { | 
 | 1451 |         return; | 
 | 1452 |     } | 
 | 1453 |  | 
 | 1454 |     if (!isPowerOn() && scannedPowerOff) | 
 | 1455 |     { | 
 | 1456 |         return; | 
 | 1457 |     } | 
 | 1458 |  | 
 | 1459 |     timer.expires_from_now(boost::posix_time::seconds(10)); | 
| James Feist | 1a99658 | 2019-05-14 15:10:06 -0700 | [diff] [blame] | 1460 |     timer.async_wait( | 
 | 1461 |         [&systemConfiguration](const boost::system::error_code& ec) { | 
 | 1462 |             if (ec == boost::asio::error::operation_aborted) | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 1463 |             { | 
| James Feist | 1a99658 | 2019-05-14 15:10:06 -0700 | [diff] [blame] | 1464 |                 // we were cancelled | 
 | 1465 |                 return; | 
 | 1466 |             } | 
 | 1467 |  | 
 | 1468 |             bool powerOff = !isPowerOn(); | 
 | 1469 |             for (const auto& item : lastJson.items()) | 
 | 1470 |             { | 
 | 1471 |                 if (systemConfiguration.find(item.key()) == | 
 | 1472 |                     systemConfiguration.end()) | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 1473 |                 { | 
| James Feist | 1a99658 | 2019-05-14 15:10:06 -0700 | [diff] [blame] | 1474 |                     bool isDetectedPowerOn = false; | 
 | 1475 |                     auto powerState = item.value().find("PowerState"); | 
 | 1476 |                     if (powerState != item.value().end()) | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 1477 |                     { | 
| James Feist | 1a99658 | 2019-05-14 15:10:06 -0700 | [diff] [blame] | 1478 |                         auto ptr = powerState->get_ptr<const std::string*>(); | 
 | 1479 |                         if (ptr) | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 1480 |                         { | 
| James Feist | 1a99658 | 2019-05-14 15:10:06 -0700 | [diff] [blame] | 1481 |                             if (*ptr == "On" || *ptr == "BiosPost") | 
 | 1482 |                             { | 
 | 1483 |                                 isDetectedPowerOn = true; | 
 | 1484 |                             } | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 1485 |                         } | 
 | 1486 |                     } | 
| James Feist | 1a99658 | 2019-05-14 15:10:06 -0700 | [diff] [blame] | 1487 |                     if (powerOff && isDetectedPowerOn) | 
 | 1488 |                     { | 
 | 1489 |                         // power not on yet, don't know if it's there or not | 
 | 1490 |                         continue; | 
 | 1491 |                     } | 
 | 1492 |                     if (!powerOff && scannedPowerOff && isDetectedPowerOn) | 
 | 1493 |                     { | 
 | 1494 |                         // already logged it when power was off | 
 | 1495 |                         continue; | 
 | 1496 |                     } | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 1497 |  | 
| James Feist | 1a99658 | 2019-05-14 15:10:06 -0700 | [diff] [blame] | 1498 |                     logDeviceRemoved(item.value()); | 
 | 1499 |                 } | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 1500 |             } | 
| James Feist | 1a99658 | 2019-05-14 15:10:06 -0700 | [diff] [blame] | 1501 |             scannedPowerOff = true; | 
 | 1502 |             if (!powerOff) | 
 | 1503 |             { | 
 | 1504 |                 scannedPowerOn = true; | 
 | 1505 |             } | 
 | 1506 |         }); | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 1507 | } | 
 | 1508 |  | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1509 | // main properties changed entry | 
 | 1510 | void propertiesChangedCallback( | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 1511 |     boost::asio::io_service& io, | 
 | 1512 |     std::vector<sdbusplus::bus::match::match>& dbusMatches, | 
 | 1513 |     nlohmann::json& systemConfiguration, | 
 | 1514 |     sdbusplus::asio::object_server& objServer) | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1515 | { | 
 | 1516 |     static boost::asio::deadline_timer timer(io); | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 1517 |     static bool timerRunning; | 
 | 1518 |  | 
 | 1519 |     timerRunning = true; | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1520 |     timer.expires_from_now(boost::posix_time::seconds(1)); | 
 | 1521 |  | 
 | 1522 |     // setup an async wait as we normally get flooded with new requests | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 1523 |     timer.async_wait([&](const boost::system::error_code& ec) { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1524 |         if (ec == boost::asio::error::operation_aborted) | 
 | 1525 |         { | 
 | 1526 |             // we were cancelled | 
 | 1527 |             return; | 
 | 1528 |         } | 
 | 1529 |         else if (ec) | 
 | 1530 |         { | 
 | 1531 |             std::cerr << "async wait error " << ec << "\n"; | 
 | 1532 |             return; | 
 | 1533 |         } | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 1534 |         timerRunning = false; | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1535 |  | 
 | 1536 |         nlohmann::json oldConfiguration = systemConfiguration; | 
 | 1537 |         DBUS_PROBE_OBJECTS.clear(); | 
 | 1538 |  | 
 | 1539 |         std::list<nlohmann::json> configurations; | 
 | 1540 |         if (!findJsonFiles(configurations)) | 
 | 1541 |         { | 
 | 1542 |             std::cerr << "cannot find json files\n"; | 
 | 1543 |             return; | 
 | 1544 |         } | 
 | 1545 |  | 
 | 1546 |         auto perfScan = std::make_shared<PerformScan>( | 
 | 1547 |             systemConfiguration, configurations, [&, oldConfiguration]() { | 
 | 1548 |                 nlohmann::json newConfiguration = systemConfiguration; | 
| James Feist | 4131aea | 2018-03-09 09:47:30 -0800 | [diff] [blame] | 1549 |                 for (auto it = newConfiguration.begin(); | 
 | 1550 |                      it != newConfiguration.end();) | 
 | 1551 |                 { | 
 | 1552 |                     auto findKey = oldConfiguration.find(it.key()); | 
 | 1553 |                     if (findKey != oldConfiguration.end()) | 
 | 1554 |                     { | 
 | 1555 |                         it = newConfiguration.erase(it); | 
 | 1556 |                     } | 
 | 1557 |                     else | 
 | 1558 |                     { | 
 | 1559 |                         it++; | 
 | 1560 |                     } | 
 | 1561 |                 } | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1562 |                 registerCallbacks(io, dbusMatches, systemConfiguration, | 
 | 1563 |                                   objServer); | 
 | 1564 |                 io.post([&, newConfiguration]() { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1565 |                     loadOverlays(newConfiguration); | 
| James Feist | ce4367c | 2018-10-16 09:19:57 -0700 | [diff] [blame] | 1566 |  | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 1567 |                     io.post([&]() { | 
 | 1568 |                         if (!writeJsonFiles(systemConfiguration)) | 
 | 1569 |                         { | 
 | 1570 |                             std::cerr << "Error writing json files\n"; | 
 | 1571 |                         } | 
 | 1572 |                     }); | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1573 |                     io.post([&, newConfiguration]() { | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 1574 |                         postToDbus(newConfiguration, systemConfiguration, | 
 | 1575 |                                    objServer); | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 1576 |                         if (!timerRunning) | 
 | 1577 |                         { | 
| James Feist | 9813279 | 2019-07-09 13:29:09 -0700 | [diff] [blame] | 1578 |                             startRemovedTimer(timer, systemConfiguration); | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 1579 |                         } | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1580 |                     }); | 
 | 1581 |                 }); | 
 | 1582 |             }); | 
 | 1583 |         perfScan->run(); | 
 | 1584 |     }); | 
| James Feist | 75fdeeb | 2018-02-20 14:26:16 -0800 | [diff] [blame] | 1585 | } | 
 | 1586 |  | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 1587 | void registerCallbacks(boost::asio::io_service& io, | 
 | 1588 |                        std::vector<sdbusplus::bus::match::match>& dbusMatches, | 
 | 1589 |                        nlohmann::json& systemConfiguration, | 
 | 1590 |                        sdbusplus::asio::object_server& objServer) | 
| James Feist | 75fdeeb | 2018-02-20 14:26:16 -0800 | [diff] [blame] | 1591 | { | 
 | 1592 |     static boost::container::flat_set<std::string> watchedObjects; | 
 | 1593 |  | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 1594 |     for (const auto& objectMap : DBUS_PROBE_OBJECTS) | 
| James Feist | 75fdeeb | 2018-02-20 14:26:16 -0800 | [diff] [blame] | 1595 |     { | 
 | 1596 |         auto findObject = watchedObjects.find(objectMap.first); | 
 | 1597 |         if (findObject != watchedObjects.end()) | 
 | 1598 |         { | 
 | 1599 |             continue; | 
 | 1600 |         } | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1601 |         std::function<void(sdbusplus::message::message & message)> | 
 | 1602 |             eventHandler = | 
| James Feist | 75fdeeb | 2018-02-20 14:26:16 -0800 | [diff] [blame] | 1603 |  | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 1604 |                 [&](sdbusplus::message::message&) { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1605 |                     propertiesChangedCallback(io, dbusMatches, | 
 | 1606 |                                               systemConfiguration, objServer); | 
 | 1607 |                 }; | 
 | 1608 |  | 
 | 1609 |         sdbusplus::bus::match::match match( | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 1610 |             static_cast<sdbusplus::bus::bus&>(*SYSTEM_BUS), | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1611 |             "type='signal',member='PropertiesChanged',arg0='" + | 
 | 1612 |                 objectMap.first + "'", | 
 | 1613 |             eventHandler); | 
 | 1614 |         dbusMatches.emplace_back(std::move(match)); | 
| James Feist | 75fdeeb | 2018-02-20 14:26:16 -0800 | [diff] [blame] | 1615 |     } | 
 | 1616 | } | 
 | 1617 |  | 
| James Feist | 9813279 | 2019-07-09 13:29:09 -0700 | [diff] [blame] | 1618 | int main() | 
| James Feist | 75fdeeb | 2018-02-20 14:26:16 -0800 | [diff] [blame] | 1619 | { | 
 | 1620 |     // setup connection to dbus | 
 | 1621 |     boost::asio::io_service io; | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1622 |     SYSTEM_BUS = std::make_shared<sdbusplus::asio::connection>(io); | 
| James Feist | 75fdeeb | 2018-02-20 14:26:16 -0800 | [diff] [blame] | 1623 |     SYSTEM_BUS->request_name("xyz.openbmc_project.EntityManager"); | 
| James Feist | 4131aea | 2018-03-09 09:47:30 -0800 | [diff] [blame] | 1624 |  | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1625 |     sdbusplus::asio::object_server objServer(SYSTEM_BUS); | 
| James Feist | fd1264a | 2018-05-03 12:10:00 -0700 | [diff] [blame] | 1626 |  | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1627 |     std::shared_ptr<sdbusplus::asio::dbus_interface> entityIface = | 
 | 1628 |         objServer.add_interface("/xyz/openbmc_project/EntityManager", | 
 | 1629 |                                 "xyz.openbmc_project.EntityManager"); | 
| James Feist | fd1264a | 2018-05-03 12:10:00 -0700 | [diff] [blame] | 1630 |  | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1631 |     std::shared_ptr<sdbusplus::asio::dbus_interface> inventoryIface = | 
 | 1632 |         objServer.add_interface("/xyz/openbmc_project/inventory", | 
 | 1633 |                                 "xyz.openbmc_project.Inventory.Manager"); | 
| James Feist | 4131aea | 2018-03-09 09:47:30 -0800 | [diff] [blame] | 1634 |  | 
 | 1635 |     // to keep reference to the match / filter objects so they don't get | 
 | 1636 |     // destroyed | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1637 |     std::vector<sdbusplus::bus::match::match> dbusMatches; | 
 | 1638 |  | 
 | 1639 |     nlohmann::json systemConfiguration = nlohmann::json::object(); | 
 | 1640 |  | 
 | 1641 |     inventoryIface->register_method( | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 1642 |         "Notify", | 
 | 1643 |         [](const boost::container::flat_map< | 
 | 1644 |             std::string, | 
| James Feist | 9813279 | 2019-07-09 13:29:09 -0700 | [diff] [blame] | 1645 |             boost::container::flat_map<std::string, BasicVariantType>>&) { | 
 | 1646 |             return; | 
 | 1647 |         }); | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1648 |     inventoryIface->initialize(); | 
 | 1649 |  | 
 | 1650 |     io.post([&]() { | 
| James Feist | ce4367c | 2018-10-16 09:19:57 -0700 | [diff] [blame] | 1651 | #if OVERLAYS | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1652 |         unloadAllOverlays(); | 
| James Feist | ce4367c | 2018-10-16 09:19:57 -0700 | [diff] [blame] | 1653 | #endif | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1654 |         propertiesChangedCallback(io, dbusMatches, systemConfiguration, | 
 | 1655 |                                   objServer); | 
 | 1656 |     }); | 
| James Feist | 4131aea | 2018-03-09 09:47:30 -0800 | [diff] [blame] | 1657 |  | 
| James Feist | fd1264a | 2018-05-03 12:10:00 -0700 | [diff] [blame] | 1658 |     entityIface->register_method("ReScan", [&]() { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1659 |         propertiesChangedCallback(io, dbusMatches, systemConfiguration, | 
 | 1660 |                                   objServer); | 
| James Feist | 75fdeeb | 2018-02-20 14:26:16 -0800 | [diff] [blame] | 1661 |     }); | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1662 |     entityIface->initialize(); | 
 | 1663 |  | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 1664 |     if (fwVersionIsSame()) | 
 | 1665 |     { | 
 | 1666 |         if (std::filesystem::is_regular_file(currentConfiguration)) | 
 | 1667 |         { | 
 | 1668 |             // this file could just be deleted, but it's nice for debug | 
 | 1669 |             std::filesystem::create_directory(tempConfigDir); | 
 | 1670 |             std::filesystem::remove(lastConfiguration); | 
 | 1671 |             std::filesystem::copy(currentConfiguration, lastConfiguration); | 
 | 1672 |             std::filesystem::remove(currentConfiguration); | 
 | 1673 |  | 
 | 1674 |             std::ifstream jsonStream(lastConfiguration); | 
 | 1675 |             if (jsonStream.good()) | 
 | 1676 |             { | 
 | 1677 |                 auto data = nlohmann::json::parse(jsonStream, nullptr, false); | 
 | 1678 |                 if (data.is_discarded()) | 
 | 1679 |                 { | 
 | 1680 |                     std::cerr << "syntax error in " << lastConfiguration | 
 | 1681 |                               << "\n"; | 
 | 1682 |                 } | 
 | 1683 |                 else | 
 | 1684 |                 { | 
 | 1685 |                     lastJson = std::move(data); | 
 | 1686 |                 } | 
 | 1687 |             } | 
 | 1688 |             else | 
 | 1689 |             { | 
 | 1690 |                 std::cerr << "unable to open " << lastConfiguration << "\n"; | 
 | 1691 |             } | 
 | 1692 |         } | 
 | 1693 |     } | 
 | 1694 |     else | 
 | 1695 |     { | 
 | 1696 |         // not an error, just logging at this level to make it in the journal | 
 | 1697 |         std::cerr << "Clearing previous configuration\n"; | 
 | 1698 |         std::filesystem::remove(currentConfiguration); | 
 | 1699 |     } | 
 | 1700 |  | 
 | 1701 |     // some boards only show up after power is on, we want to not say they are | 
 | 1702 |     // removed until the same state happens | 
 | 1703 |     setupPowerMatch(SYSTEM_BUS); | 
 | 1704 |  | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1705 |     io.run(); | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1706 |  | 
 | 1707 |     return 0; | 
| James Feist | 75fdeeb | 2018-02-20 14:26:16 -0800 | [diff] [blame] | 1708 | } |