| Alexander Hansen | 4e1142d | 2025-07-25 17:07:27 +0200 | [diff] [blame] | 1 | // SPDX-License-Identifier: Apache-2.0 | 
 | 2 | // SPDX-FileCopyrightText: Copyright 2018 Intel Corporation | 
 | 3 |  | 
| Christopher Meis | 26fbbd5 | 2025-03-26 14:55:06 +0100 | [diff] [blame] | 4 | #include "perform_probe.hpp" | 
 | 5 |  | 
| Christopher Meis | 26fbbd5 | 2025-03-26 14:55:06 +0100 | [diff] [blame] | 6 | #include "perform_scan.hpp" | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 7 |  | 
 | 8 | #include <boost/algorithm/string/replace.hpp> | 
| Alexander Hansen | c3db2c3 | 2024-08-20 15:01:38 +0200 | [diff] [blame] | 9 | #include <phosphor-logging/lg2.hpp> | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 10 |  | 
| Christopher Meis | 59ef1e7 | 2025-04-16 08:53:25 +0200 | [diff] [blame] | 11 | #include <iostream> | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 12 | #include <regex> | 
| Andrew Jeffery | ea4ff02 | 2022-04-21 12:31:40 +0930 | [diff] [blame] | 13 | #include <utility> | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 14 |  | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 15 | // probes dbus interface dictionary for a key with a value that matches a regex | 
 | 16 | // When an interface passes a probe, also save its D-Bus path with it. | 
| Andrew Jeffery | f5772d2 | 2022-04-12 22:05:30 +0930 | [diff] [blame] | 17 | bool probeDbus(const std::string& interfaceName, | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 18 |                const std::map<std::string, nlohmann::json>& matches, | 
| Christopher Meis | 26fbbd5 | 2025-03-26 14:55:06 +0100 | [diff] [blame] | 19 |                scan::FoundDevices& devices, | 
 | 20 |                const std::shared_ptr<scan::PerformScan>& scan, bool& foundProbe) | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 21 | { | 
 | 22 |     bool foundMatch = false; | 
 | 23 |     foundProbe = false; | 
 | 24 |  | 
 | 25 |     for (const auto& [path, interfaces] : scan->dbusProbeObjects) | 
 | 26 |     { | 
| Andrew Jeffery | f5772d2 | 2022-04-12 22:05:30 +0930 | [diff] [blame] | 27 |         auto it = interfaces.find(interfaceName); | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 28 |         if (it == interfaces.end()) | 
 | 29 |         { | 
 | 30 |             continue; | 
 | 31 |         } | 
 | 32 |  | 
 | 33 |         foundProbe = true; | 
 | 34 |  | 
 | 35 |         bool deviceMatches = true; | 
| Andrew Jeffery | f5772d2 | 2022-04-12 22:05:30 +0930 | [diff] [blame] | 36 |         const DBusInterface& interface = it->second; | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 37 |  | 
 | 38 |         for (const auto& [matchProp, matchJSON] : matches) | 
 | 39 |         { | 
| Andrew Jeffery | f5772d2 | 2022-04-12 22:05:30 +0930 | [diff] [blame] | 40 |             auto deviceValue = interface.find(matchProp); | 
 | 41 |             if (deviceValue != interface.end()) | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 42 |             { | 
| Patrick Williams | df19061 | 2023-05-10 07:51:34 -0500 | [diff] [blame] | 43 |                 deviceMatches = deviceMatches && | 
 | 44 |                                 matchProbe(matchJSON, deviceValue->second); | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 45 |             } | 
 | 46 |             else | 
 | 47 |             { | 
 | 48 |                 // Move on to the next DBus path | 
 | 49 |                 deviceMatches = false; | 
 | 50 |                 break; | 
 | 51 |             } | 
 | 52 |         } | 
 | 53 |         if (deviceMatches) | 
 | 54 |         { | 
| Alexander Hansen | c3db2c3 | 2024-08-20 15:01:38 +0200 | [diff] [blame] | 55 |             lg2::debug("Found probe match on {PATH} {IFACE}", "PATH", path, | 
 | 56 |                        "IFACE", interfaceName); | 
| Patrick Williams | d2b7861 | 2023-10-20 17:24:54 -0500 | [diff] [blame] | 57 |             devices.emplace_back(interface, path); | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 58 |             foundMatch = true; | 
 | 59 |         } | 
 | 60 |     } | 
 | 61 |     return foundMatch; | 
 | 62 | } | 
 | 63 |  | 
 | 64 | // default probe entry point, iterates a list looking for specific types to | 
 | 65 | // call specific probe functions | 
| Christopher Meis | 26fbbd5 | 2025-03-26 14:55:06 +0100 | [diff] [blame] | 66 | bool doProbe(const std::vector<std::string>& probeCommand, | 
 | 67 |              const std::shared_ptr<scan::PerformScan>& scan, | 
 | 68 |              scan::FoundDevices& foundDevs) | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 69 | { | 
 | 70 |     const static std::regex command(R"(\((.*)\))"); | 
 | 71 |     std::smatch match; | 
 | 72 |     bool ret = false; | 
 | 73 |     bool matchOne = false; | 
 | 74 |     bool cur = true; | 
| Christopher Meis | 26fbbd5 | 2025-03-26 14:55:06 +0100 | [diff] [blame] | 75 |     probe::probe_type_codes lastCommand = probe::probe_type_codes::FALSE_T; | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 76 |     bool first = true; | 
 | 77 |  | 
| Ed Tanous | 3013fb4 | 2022-07-09 08:27:06 -0700 | [diff] [blame] | 78 |     for (const auto& probe : probeCommand) | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 79 |     { | 
| Christopher Meis | 26fbbd5 | 2025-03-26 14:55:06 +0100 | [diff] [blame] | 80 |         probe::FoundProbeTypeT probeType = probe::findProbeType(probe); | 
| Andrew Jeffery | 666583b | 2021-12-01 15:50:12 +1030 | [diff] [blame] | 81 |         if (probeType) | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 82 |         { | 
| Amithash Prasad | 60618a7 | 2025-05-13 11:03:02 -0700 | [diff] [blame] | 83 |             switch (*probeType) | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 84 |             { | 
| Christopher Meis | 26fbbd5 | 2025-03-26 14:55:06 +0100 | [diff] [blame] | 85 |                 case probe::probe_type_codes::FALSE_T: | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 86 |                 { | 
 | 87 |                     cur = false; | 
 | 88 |                     break; | 
 | 89 |                 } | 
| Christopher Meis | 26fbbd5 | 2025-03-26 14:55:06 +0100 | [diff] [blame] | 90 |                 case probe::probe_type_codes::TRUE_T: | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 91 |                 { | 
 | 92 |                     cur = true; | 
 | 93 |                     break; | 
 | 94 |                 } | 
| Christopher Meis | 26fbbd5 | 2025-03-26 14:55:06 +0100 | [diff] [blame] | 95 |                 case probe::probe_type_codes::MATCH_ONE: | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 96 |                 { | 
 | 97 |                     // set current value to last, this probe type shouldn't | 
 | 98 |                     // affect the outcome | 
 | 99 |                     cur = ret; | 
 | 100 |                     matchOne = true; | 
 | 101 |                     break; | 
 | 102 |                 } | 
| Christopher Meis | 26fbbd5 | 2025-03-26 14:55:06 +0100 | [diff] [blame] | 103 |                 /*case probe::probe_type_codes::AND: | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 104 |                   break; | 
| Christopher Meis | 26fbbd5 | 2025-03-26 14:55:06 +0100 | [diff] [blame] | 105 |                 case probe::probe_type_codes::OR: | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 106 |                   break; | 
 | 107 |                   // these are no-ops until the last command switch | 
 | 108 |                   */ | 
| Christopher Meis | 26fbbd5 | 2025-03-26 14:55:06 +0100 | [diff] [blame] | 109 |                 case probe::probe_type_codes::FOUND: | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 110 |                 { | 
 | 111 |                     if (!std::regex_search(probe, match, command)) | 
 | 112 |                     { | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 113 |                         std::cerr | 
 | 114 |                             << "found probe syntax error " << probe << "\n"; | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 115 |                         return false; | 
 | 116 |                     } | 
 | 117 |                     std::string commandStr = *(match.begin() + 1); | 
 | 118 |                     boost::replace_all(commandStr, "'", ""); | 
 | 119 |                     cur = (std::find(scan->passedProbes.begin(), | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 120 |                                      scan->passedProbes.end(), commandStr) != | 
 | 121 |                            scan->passedProbes.end()); | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 122 |                     break; | 
 | 123 |                 } | 
 | 124 |                 default: | 
 | 125 |                 { | 
 | 126 |                     break; | 
 | 127 |                 } | 
 | 128 |             } | 
 | 129 |         } | 
 | 130 |         // look on dbus for object | 
 | 131 |         else | 
 | 132 |         { | 
 | 133 |             if (!std::regex_search(probe, match, command)) | 
 | 134 |             { | 
 | 135 |                 std::cerr << "dbus probe syntax error " << probe << "\n"; | 
 | 136 |                 return false; | 
 | 137 |             } | 
 | 138 |             std::string commandStr = *(match.begin() + 1); | 
 | 139 |             // convert single ticks and single slashes into legal json | 
 | 140 |             boost::replace_all(commandStr, "'", "\""); | 
 | 141 |             boost::replace_all(commandStr, R"(\)", R"(\\)"); | 
| Potin Lai | 0f3a4d9 | 2023-12-05 00:13:55 +0800 | [diff] [blame] | 142 |             auto json = nlohmann::json::parse(commandStr, nullptr, false, true); | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 143 |             if (json.is_discarded()) | 
 | 144 |             { | 
 | 145 |                 std::cerr << "dbus command syntax error " << commandStr << "\n"; | 
 | 146 |                 return false; | 
 | 147 |             } | 
 | 148 |             // we can match any (string, variant) property. (string, string) | 
 | 149 |             // does a regex | 
 | 150 |             std::map<std::string, nlohmann::json> dbusProbeMap = | 
 | 151 |                 json.get<std::map<std::string, nlohmann::json>>(); | 
 | 152 |             auto findStart = probe.find('('); | 
 | 153 |             if (findStart == std::string::npos) | 
 | 154 |             { | 
 | 155 |                 return false; | 
 | 156 |             } | 
| Andrew Jeffery | 666583b | 2021-12-01 15:50:12 +1030 | [diff] [blame] | 157 |             bool foundProbe = !!probeType; | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 158 |             std::string probeInterface = probe.substr(0, findStart); | 
 | 159 |             cur = probeDbus(probeInterface, dbusProbeMap, foundDevs, scan, | 
 | 160 |                             foundProbe); | 
 | 161 |         } | 
 | 162 |  | 
 | 163 |         // some functions like AND and OR only take affect after the | 
 | 164 |         // fact | 
| Christopher Meis | 26fbbd5 | 2025-03-26 14:55:06 +0100 | [diff] [blame] | 165 |         if (lastCommand == probe::probe_type_codes::AND) | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 166 |         { | 
 | 167 |             ret = cur && ret; | 
 | 168 |         } | 
| Christopher Meis | 26fbbd5 | 2025-03-26 14:55:06 +0100 | [diff] [blame] | 169 |         else if (lastCommand == probe::probe_type_codes::OR) | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 170 |         { | 
 | 171 |             ret = cur || ret; | 
 | 172 |         } | 
 | 173 |  | 
 | 174 |         if (first) | 
 | 175 |         { | 
 | 176 |             ret = cur; | 
 | 177 |             first = false; | 
 | 178 |         } | 
| Amithash Prasad | 60618a7 | 2025-05-13 11:03:02 -0700 | [diff] [blame] | 179 |         lastCommand = probeType.value_or(probe::probe_type_codes::FALSE_T); | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 180 |     } | 
 | 181 |  | 
 | 182 |     // probe passed, but empty device | 
| Ed Tanous | 3013fb4 | 2022-07-09 08:27:06 -0700 | [diff] [blame] | 183 |     if (ret && foundDevs.empty()) | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 184 |     { | 
| Patrick Williams | d2b7861 | 2023-10-20 17:24:54 -0500 | [diff] [blame] | 185 |         foundDevs.emplace_back( | 
 | 186 |             boost::container::flat_map<std::string, DBusValueVariant>{}, | 
 | 187 |             std::string{}); | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 188 |     } | 
 | 189 |     if (matchOne && ret) | 
 | 190 |     { | 
 | 191 |         // match the last one | 
 | 192 |         auto last = foundDevs.back(); | 
 | 193 |         foundDevs.clear(); | 
 | 194 |  | 
 | 195 |         foundDevs.emplace_back(std::move(last)); | 
 | 196 |     } | 
 | 197 |     return ret; | 
 | 198 | } | 
 | 199 |  | 
| Christopher Meis | 26fbbd5 | 2025-03-26 14:55:06 +0100 | [diff] [blame] | 200 | namespace probe | 
 | 201 | { | 
 | 202 |  | 
| Andrew Jeffery | ea4ff02 | 2022-04-21 12:31:40 +0930 | [diff] [blame] | 203 | PerformProbe::PerformProbe(nlohmann::json& recordRef, | 
 | 204 |                            const std::vector<std::string>& probeCommand, | 
 | 205 |                            std::string probeName, | 
| Christopher Meis | 26fbbd5 | 2025-03-26 14:55:06 +0100 | [diff] [blame] | 206 |                            std::shared_ptr<scan::PerformScan>& scanPtr) : | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 207 |     recordRef(recordRef), _probeCommand(probeCommand), | 
 | 208 |     probeName(std::move(probeName)), scan(scanPtr) | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 209 | {} | 
| Christopher Meis | 26fbbd5 | 2025-03-26 14:55:06 +0100 | [diff] [blame] | 210 |  | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 211 | PerformProbe::~PerformProbe() | 
 | 212 | { | 
| Christopher Meis | 26fbbd5 | 2025-03-26 14:55:06 +0100 | [diff] [blame] | 213 |     scan::FoundDevices foundDevs; | 
 | 214 |     if (doProbe(_probeCommand, scan, foundDevs)) | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 215 |     { | 
| Andrew Jeffery | af9b46b | 2022-04-21 12:34:43 +0930 | [diff] [blame] | 216 |         scan->updateSystemConfiguration(recordRef, probeName, foundDevs); | 
| Andrew Jeffery | f07c5ed | 2021-12-01 14:22:04 +1030 | [diff] [blame] | 217 |     } | 
 | 218 | } | 
| Christopher Meis | 26fbbd5 | 2025-03-26 14:55:06 +0100 | [diff] [blame] | 219 |  | 
 | 220 | FoundProbeTypeT findProbeType(const std::string& probe) | 
 | 221 | { | 
| Peter Yin | 2ae2b81 | 2025-05-08 15:59:39 +0800 | [diff] [blame] | 222 |     static const boost::container::flat_map<const char*, probe_type_codes, | 
 | 223 |                                             CmpStr> | 
| Christopher Meis | 26fbbd5 | 2025-03-26 14:55:06 +0100 | [diff] [blame] | 224 |         probeTypes{{{"FALSE", probe_type_codes::FALSE_T}, | 
 | 225 |                     {"TRUE", probe_type_codes::TRUE_T}, | 
 | 226 |                     {"AND", probe_type_codes::AND}, | 
 | 227 |                     {"OR", probe_type_codes::OR}, | 
 | 228 |                     {"FOUND", probe_type_codes::FOUND}, | 
 | 229 |                     {"MATCH_ONE", probe_type_codes::MATCH_ONE}}}; | 
 | 230 |  | 
 | 231 |     boost::container::flat_map<const char*, probe_type_codes, | 
 | 232 |                                CmpStr>::const_iterator probeType; | 
 | 233 |     for (probeType = probeTypes.begin(); probeType != probeTypes.end(); | 
 | 234 |          ++probeType) | 
 | 235 |     { | 
 | 236 |         if (probe.find(probeType->first) != std::string::npos) | 
 | 237 |         { | 
| Amithash Prasad | 60618a7 | 2025-05-13 11:03:02 -0700 | [diff] [blame] | 238 |             return probeType->second; | 
| Christopher Meis | 26fbbd5 | 2025-03-26 14:55:06 +0100 | [diff] [blame] | 239 |         } | 
 | 240 |     } | 
 | 241 |  | 
 | 242 |     return std::nullopt; | 
 | 243 | } | 
 | 244 |  | 
 | 245 | } // namespace probe |