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