blob: c88ed5a88e89e9fbb86963ec826f30b54f135718 [file] [log] [blame]
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +10301/*
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*/
Brad Bishope45d8c72022-05-25 15:12:53 -040016/// \file perform_probe.cpp
17#include "entity_manager.hpp"
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103018
19#include <boost/algorithm/string/replace.hpp>
Alexander Hansenc3db2c32024-08-20 15:01:38 +020020#include <phosphor-logging/lg2.hpp>
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103021
22#include <regex>
Andrew Jefferyea4ff022022-04-21 12:31:40 +093023#include <utility>
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103024
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103025// probes dbus interface dictionary for a key with a value that matches a regex
26// When an interface passes a probe, also save its D-Bus path with it.
Andrew Jefferyf5772d22022-04-12 22:05:30 +093027bool probeDbus(const std::string& interfaceName,
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103028 const std::map<std::string, nlohmann::json>& matches,
Andrew Jefferyf5772d22022-04-12 22:05:30 +093029 FoundDevices& devices, const std::shared_ptr<PerformScan>& scan,
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103030 bool& foundProbe)
31{
32 bool foundMatch = false;
33 foundProbe = false;
34
35 for (const auto& [path, interfaces] : scan->dbusProbeObjects)
36 {
Andrew Jefferyf5772d22022-04-12 22:05:30 +093037 auto it = interfaces.find(interfaceName);
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103038 if (it == interfaces.end())
39 {
40 continue;
41 }
42
43 foundProbe = true;
44
45 bool deviceMatches = true;
Andrew Jefferyf5772d22022-04-12 22:05:30 +093046 const DBusInterface& interface = it->second;
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103047
48 for (const auto& [matchProp, matchJSON] : matches)
49 {
Andrew Jefferyf5772d22022-04-12 22:05:30 +093050 auto deviceValue = interface.find(matchProp);
51 if (deviceValue != interface.end())
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103052 {
Patrick Williamsdf190612023-05-10 07:51:34 -050053 deviceMatches = deviceMatches &&
54 matchProbe(matchJSON, deviceValue->second);
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103055 }
56 else
57 {
58 // Move on to the next DBus path
59 deviceMatches = false;
60 break;
61 }
62 }
63 if (deviceMatches)
64 {
Alexander Hansenc3db2c32024-08-20 15:01:38 +020065 lg2::debug("Found probe match on {PATH} {IFACE}", "PATH", path,
66 "IFACE", interfaceName);
Patrick Williamsd2b78612023-10-20 17:24:54 -050067 devices.emplace_back(interface, path);
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103068 foundMatch = true;
69 }
70 }
71 return foundMatch;
72}
73
74// default probe entry point, iterates a list looking for specific types to
75// call specific probe functions
76bool probe(const std::vector<std::string>& probeCommand,
Andrew Jefferyf5772d22022-04-12 22:05:30 +093077 const std::shared_ptr<PerformScan>& scan, FoundDevices& foundDevs)
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103078{
79 const static std::regex command(R"(\((.*)\))");
80 std::smatch match;
81 bool ret = false;
82 bool matchOne = false;
83 bool cur = true;
84 probe_type_codes lastCommand = probe_type_codes::FALSE_T;
85 bool first = true;
86
Ed Tanous3013fb42022-07-09 08:27:06 -070087 for (const auto& probe : probeCommand)
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103088 {
Andrew Jeffery666583b2021-12-01 15:50:12 +103089 FoundProbeTypeT probeType = findProbeType(probe);
90 if (probeType)
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103091 {
Andrew Jeffery666583b2021-12-01 15:50:12 +103092 switch ((*probeType)->second)
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +103093 {
94 case probe_type_codes::FALSE_T:
95 {
96 cur = false;
97 break;
98 }
99 case probe_type_codes::TRUE_T:
100 {
101 cur = true;
102 break;
103 }
104 case probe_type_codes::MATCH_ONE:
105 {
106 // set current value to last, this probe type shouldn't
107 // affect the outcome
108 cur = ret;
109 matchOne = true;
110 break;
111 }
112 /*case probe_type_codes::AND:
113 break;
114 case probe_type_codes::OR:
115 break;
116 // these are no-ops until the last command switch
117 */
118 case probe_type_codes::FOUND:
119 {
120 if (!std::regex_search(probe, match, command))
121 {
Patrick Williamsb7077432024-08-16 15:22:21 -0400122 std::cerr
123 << "found probe syntax error " << probe << "\n";
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030124 return false;
125 }
126 std::string commandStr = *(match.begin() + 1);
127 boost::replace_all(commandStr, "'", "");
128 cur = (std::find(scan->passedProbes.begin(),
Patrick Williamsb7077432024-08-16 15:22:21 -0400129 scan->passedProbes.end(), commandStr) !=
130 scan->passedProbes.end());
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030131 break;
132 }
133 default:
134 {
135 break;
136 }
137 }
138 }
139 // look on dbus for object
140 else
141 {
142 if (!std::regex_search(probe, match, command))
143 {
144 std::cerr << "dbus probe syntax error " << probe << "\n";
145 return false;
146 }
147 std::string commandStr = *(match.begin() + 1);
148 // convert single ticks and single slashes into legal json
149 boost::replace_all(commandStr, "'", "\"");
150 boost::replace_all(commandStr, R"(\)", R"(\\)");
Potin Lai0f3a4d92023-12-05 00:13:55 +0800151 auto json = nlohmann::json::parse(commandStr, nullptr, false, true);
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030152 if (json.is_discarded())
153 {
154 std::cerr << "dbus command syntax error " << commandStr << "\n";
155 return false;
156 }
157 // we can match any (string, variant) property. (string, string)
158 // does a regex
159 std::map<std::string, nlohmann::json> dbusProbeMap =
160 json.get<std::map<std::string, nlohmann::json>>();
161 auto findStart = probe.find('(');
162 if (findStart == std::string::npos)
163 {
164 return false;
165 }
Andrew Jeffery666583b2021-12-01 15:50:12 +1030166 bool foundProbe = !!probeType;
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030167 std::string probeInterface = probe.substr(0, findStart);
168 cur = probeDbus(probeInterface, dbusProbeMap, foundDevs, scan,
169 foundProbe);
170 }
171
172 // some functions like AND and OR only take affect after the
173 // fact
174 if (lastCommand == probe_type_codes::AND)
175 {
176 ret = cur && ret;
177 }
178 else if (lastCommand == probe_type_codes::OR)
179 {
180 ret = cur || ret;
181 }
182
183 if (first)
184 {
185 ret = cur;
186 first = false;
187 }
Patrick Williamsdf190612023-05-10 07:51:34 -0500188 lastCommand = probeType ? (*probeType)->second
189 : probe_type_codes::FALSE_T;
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030190 }
191
192 // probe passed, but empty device
Ed Tanous3013fb42022-07-09 08:27:06 -0700193 if (ret && foundDevs.empty())
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030194 {
Patrick Williamsd2b78612023-10-20 17:24:54 -0500195 foundDevs.emplace_back(
196 boost::container::flat_map<std::string, DBusValueVariant>{},
197 std::string{});
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030198 }
199 if (matchOne && ret)
200 {
201 // match the last one
202 auto last = foundDevs.back();
203 foundDevs.clear();
204
205 foundDevs.emplace_back(std::move(last));
206 }
207 return ret;
208}
209
Andrew Jefferyea4ff022022-04-21 12:31:40 +0930210PerformProbe::PerformProbe(nlohmann::json& recordRef,
211 const std::vector<std::string>& probeCommand,
212 std::string probeName,
213 std::shared_ptr<PerformScan>& scanPtr) :
Patrick Williamsb7077432024-08-16 15:22:21 -0400214 recordRef(recordRef), _probeCommand(probeCommand),
215 probeName(std::move(probeName)), scan(scanPtr)
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030216{}
217PerformProbe::~PerformProbe()
218{
Andrew Jefferyf5772d22022-04-12 22:05:30 +0930219 FoundDevices foundDevs;
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030220 if (probe(_probeCommand, scan, foundDevs))
221 {
Andrew Jefferyaf9b46b2022-04-21 12:34:43 +0930222 scan->updateSystemConfiguration(recordRef, probeName, foundDevs);
Andrew Jefferyf07c5ed2021-12-01 14:22:04 +1030223 }
224}