/* // Copyright (c) 2018 Intel Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ /// \file perform_probe.cpp #include "entity_manager.hpp" #include #include #include #include // probes dbus interface dictionary for a key with a value that matches a regex // When an interface passes a probe, also save its D-Bus path with it. bool probeDbus(const std::string& interfaceName, const std::map& matches, FoundDevices& devices, const std::shared_ptr& scan, bool& foundProbe) { bool foundMatch = false; foundProbe = false; for (const auto& [path, interfaces] : scan->dbusProbeObjects) { auto it = interfaces.find(interfaceName); if (it == interfaces.end()) { continue; } foundProbe = true; bool deviceMatches = true; const DBusInterface& interface = it->second; for (const auto& [matchProp, matchJSON] : matches) { auto deviceValue = interface.find(matchProp); if (deviceValue != interface.end()) { deviceMatches = deviceMatches && matchProbe(matchJSON, deviceValue->second); } else { // Move on to the next DBus path deviceMatches = false; break; } } if (deviceMatches) { lg2::debug("Found probe match on {PATH} {IFACE}", "PATH", path, "IFACE", interfaceName); devices.emplace_back(interface, path); foundMatch = true; } } return foundMatch; } // default probe entry point, iterates a list looking for specific types to // call specific probe functions bool probe(const std::vector& probeCommand, const std::shared_ptr& scan, FoundDevices& foundDevs) { const static std::regex command(R"(\((.*)\))"); std::smatch match; bool ret = false; bool matchOne = false; bool cur = true; probe_type_codes lastCommand = probe_type_codes::FALSE_T; bool first = true; for (const auto& probe : probeCommand) { FoundProbeTypeT probeType = findProbeType(probe); if (probeType) { switch ((*probeType)->second) { case probe_type_codes::FALSE_T: { cur = false; break; } case probe_type_codes::TRUE_T: { cur = true; break; } case probe_type_codes::MATCH_ONE: { // set current value to last, this probe type shouldn't // affect the outcome cur = ret; matchOne = true; break; } /*case probe_type_codes::AND: break; case probe_type_codes::OR: break; // these are no-ops until the last command switch */ case probe_type_codes::FOUND: { if (!std::regex_search(probe, match, command)) { std::cerr << "found probe syntax error " << probe << "\n"; return false; } std::string commandStr = *(match.begin() + 1); boost::replace_all(commandStr, "'", ""); cur = (std::find(scan->passedProbes.begin(), scan->passedProbes.end(), commandStr) != scan->passedProbes.end()); break; } default: { break; } } } // look on dbus for object else { if (!std::regex_search(probe, match, command)) { std::cerr << "dbus probe syntax error " << probe << "\n"; return false; } std::string commandStr = *(match.begin() + 1); // convert single ticks and single slashes into legal json boost::replace_all(commandStr, "'", "\""); boost::replace_all(commandStr, R"(\)", R"(\\)"); auto json = nlohmann::json::parse(commandStr, nullptr, false, true); if (json.is_discarded()) { std::cerr << "dbus command syntax error " << commandStr << "\n"; return false; } // we can match any (string, variant) property. (string, string) // does a regex std::map dbusProbeMap = json.get>(); auto findStart = probe.find('('); if (findStart == std::string::npos) { return false; } bool foundProbe = !!probeType; std::string probeInterface = probe.substr(0, findStart); cur = probeDbus(probeInterface, dbusProbeMap, foundDevs, scan, foundProbe); } // some functions like AND and OR only take affect after the // fact if (lastCommand == probe_type_codes::AND) { ret = cur && ret; } else if (lastCommand == probe_type_codes::OR) { ret = cur || ret; } if (first) { ret = cur; first = false; } lastCommand = probeType ? (*probeType)->second : probe_type_codes::FALSE_T; } // probe passed, but empty device if (ret && foundDevs.empty()) { foundDevs.emplace_back( boost::container::flat_map{}, std::string{}); } if (matchOne && ret) { // match the last one auto last = foundDevs.back(); foundDevs.clear(); foundDevs.emplace_back(std::move(last)); } return ret; } PerformProbe::PerformProbe(nlohmann::json& recordRef, const std::vector& probeCommand, std::string probeName, std::shared_ptr& scanPtr) : recordRef(recordRef), _probeCommand(probeCommand), probeName(std::move(probeName)), scan(scanPtr) {} PerformProbe::~PerformProbe() { FoundDevices foundDevs; if (probe(_probeCommand, scan, foundDevs)) { scan->updateSystemConfiguration(recordRef, probeName, foundDevs); } }