blob: 50943c7259066b62eb8e15b3fa2c0649cdfc79ed [file] [log] [blame]
Alexander Hansen4e1142d2025-07-25 17:07:27 +02001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright 2018 Intel Corporation
3
Christopher Meis26fbbd52025-03-26 14:55:06 +01004#include "perform_probe.hpp"
5
Christopher Meis26fbbd52025-03-26 14:55:06 +01006#include "perform_scan.hpp"
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +10307
8#include <boost/algorithm/string/replace.hpp>
Alexander Hansenc3db2c32024-08-20 15:01:38 +02009#include <phosphor-logging/lg2.hpp>
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103010
Christopher Meis59ef1e72025-04-16 08:53:25 +020011#include <iostream>
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103012#include <regex>
Andrew Jefferyea4ff022022-04-21 12:31:40 +093013#include <utility>
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103014
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103015// 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 Jefferyf5772d22022-04-12 22:05:30 +093017bool probeDbus(const std::string& interfaceName,
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103018 const std::map<std::string, nlohmann::json>& matches,
Christopher Meis26fbbd52025-03-26 14:55:06 +010019 scan::FoundDevices& devices,
20 const std::shared_ptr<scan::PerformScan>& scan, bool& foundProbe)
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103021{
22 bool foundMatch = false;
23 foundProbe = false;
24
25 for (const auto& [path, interfaces] : scan->dbusProbeObjects)
26 {
Andrew Jefferyf5772d22022-04-12 22:05:30 +093027 auto it = interfaces.find(interfaceName);
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103028 if (it == interfaces.end())
29 {
30 continue;
31 }
32
33 foundProbe = true;
34
35 bool deviceMatches = true;
Andrew Jefferyf5772d22022-04-12 22:05:30 +093036 const DBusInterface& interface = it->second;
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103037
38 for (const auto& [matchProp, matchJSON] : matches)
39 {
Andrew Jefferyf5772d22022-04-12 22:05:30 +093040 auto deviceValue = interface.find(matchProp);
41 if (deviceValue != interface.end())
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103042 {
Patrick Williamsdf190612023-05-10 07:51:34 -050043 deviceMatches = deviceMatches &&
44 matchProbe(matchJSON, deviceValue->second);
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103045 }
46 else
47 {
48 // Move on to the next DBus path
49 deviceMatches = false;
50 break;
51 }
52 }
53 if (deviceMatches)
54 {
Alexander Hansenc3db2c32024-08-20 15:01:38 +020055 lg2::debug("Found probe match on {PATH} {IFACE}", "PATH", path,
56 "IFACE", interfaceName);
Patrick Williamsd2b78612023-10-20 17:24:54 -050057 devices.emplace_back(interface, path);
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103058 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 Meis26fbbd52025-03-26 14:55:06 +010066bool doProbe(const std::vector<std::string>& probeCommand,
67 const std::shared_ptr<scan::PerformScan>& scan,
68 scan::FoundDevices& foundDevs)
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103069{
70 const static std::regex command(R"(\((.*)\))");
71 std::smatch match;
72 bool ret = false;
73 bool matchOne = false;
74 bool cur = true;
Christopher Meis26fbbd52025-03-26 14:55:06 +010075 probe::probe_type_codes lastCommand = probe::probe_type_codes::FALSE_T;
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103076 bool first = true;
77
Ed Tanous3013fb42022-07-09 08:27:06 -070078 for (const auto& probe : probeCommand)
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103079 {
Christopher Meis26fbbd52025-03-26 14:55:06 +010080 probe::FoundProbeTypeT probeType = probe::findProbeType(probe);
Andrew Jeffery666583b2021-12-01 15:50:12 +103081 if (probeType)
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103082 {
Amithash Prasad60618a72025-05-13 11:03:02 -070083 switch (*probeType)
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103084 {
Christopher Meis26fbbd52025-03-26 14:55:06 +010085 case probe::probe_type_codes::FALSE_T:
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103086 {
87 cur = false;
88 break;
89 }
Christopher Meis26fbbd52025-03-26 14:55:06 +010090 case probe::probe_type_codes::TRUE_T:
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103091 {
92 cur = true;
93 break;
94 }
Christopher Meis26fbbd52025-03-26 14:55:06 +010095 case probe::probe_type_codes::MATCH_ONE:
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103096 {
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 Meis26fbbd52025-03-26 14:55:06 +0100103 /*case probe::probe_type_codes::AND:
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030104 break;
Christopher Meis26fbbd52025-03-26 14:55:06 +0100105 case probe::probe_type_codes::OR:
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030106 break;
107 // these are no-ops until the last command switch
108 */
Christopher Meis26fbbd52025-03-26 14:55:06 +0100109 case probe::probe_type_codes::FOUND:
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030110 {
111 if (!std::regex_search(probe, match, command))
112 {
Patrick Williamsb7077432024-08-16 15:22:21 -0400113 std::cerr
114 << "found probe syntax error " << probe << "\n";
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030115 return false;
116 }
117 std::string commandStr = *(match.begin() + 1);
118 boost::replace_all(commandStr, "'", "");
119 cur = (std::find(scan->passedProbes.begin(),
Patrick Williamsb7077432024-08-16 15:22:21 -0400120 scan->passedProbes.end(), commandStr) !=
121 scan->passedProbes.end());
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030122 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 Lai0f3a4d92023-12-05 00:13:55 +0800142 auto json = nlohmann::json::parse(commandStr, nullptr, false, true);
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030143 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 Jeffery666583b2021-12-01 15:50:12 +1030157 bool foundProbe = !!probeType;
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030158 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 Meis26fbbd52025-03-26 14:55:06 +0100165 if (lastCommand == probe::probe_type_codes::AND)
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030166 {
167 ret = cur && ret;
168 }
Christopher Meis26fbbd52025-03-26 14:55:06 +0100169 else if (lastCommand == probe::probe_type_codes::OR)
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030170 {
171 ret = cur || ret;
172 }
173
174 if (first)
175 {
176 ret = cur;
177 first = false;
178 }
Amithash Prasad60618a72025-05-13 11:03:02 -0700179 lastCommand = probeType.value_or(probe::probe_type_codes::FALSE_T);
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030180 }
181
182 // probe passed, but empty device
Ed Tanous3013fb42022-07-09 08:27:06 -0700183 if (ret && foundDevs.empty())
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030184 {
Patrick Williamsd2b78612023-10-20 17:24:54 -0500185 foundDevs.emplace_back(
186 boost::container::flat_map<std::string, DBusValueVariant>{},
187 std::string{});
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030188 }
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 Meis26fbbd52025-03-26 14:55:06 +0100200namespace probe
201{
202
Andrew Jefferyea4ff022022-04-21 12:31:40 +0930203PerformProbe::PerformProbe(nlohmann::json& recordRef,
204 const std::vector<std::string>& probeCommand,
205 std::string probeName,
Christopher Meis26fbbd52025-03-26 14:55:06 +0100206 std::shared_ptr<scan::PerformScan>& scanPtr) :
Patrick Williamsb7077432024-08-16 15:22:21 -0400207 recordRef(recordRef), _probeCommand(probeCommand),
208 probeName(std::move(probeName)), scan(scanPtr)
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030209{}
Christopher Meis26fbbd52025-03-26 14:55:06 +0100210
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030211PerformProbe::~PerformProbe()
212{
Christopher Meis26fbbd52025-03-26 14:55:06 +0100213 scan::FoundDevices foundDevs;
214 if (doProbe(_probeCommand, scan, foundDevs))
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030215 {
Andrew Jefferyaf9b46b2022-04-21 12:34:43 +0930216 scan->updateSystemConfiguration(recordRef, probeName, foundDevs);
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030217 }
218}
Christopher Meis26fbbd52025-03-26 14:55:06 +0100219
220FoundProbeTypeT findProbeType(const std::string& probe)
221{
Peter Yin2ae2b812025-05-08 15:59:39 +0800222 static const boost::container::flat_map<const char*, probe_type_codes,
223 CmpStr>
Christopher Meis26fbbd52025-03-26 14:55:06 +0100224 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 Prasad60618a72025-05-13 11:03:02 -0700238 return probeType->second;
Christopher Meis26fbbd52025-03-26 14:55:06 +0100239 }
240 }
241
242 return std::nullopt;
243}
244
245} // namespace probe