blob: 35430d8a31133766bd1ba888f185939212bee48d [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_scan.hpp"
5
Christopher Meis26fbbd52025-03-26 14:55:06 +01006#include "perform_probe.hpp"
Christopher Meis59ef1e72025-04-16 08:53:25 +02007#include "utils.hpp"
Andrew Jeffery47af65a2021-12-01 14:16:31 +10308
9#include <boost/algorithm/string/predicate.hpp>
10#include <boost/asio/steady_timer.hpp>
11#include <boost/container/flat_map.hpp>
12#include <boost/container/flat_set.hpp>
Alexander Hansenc3db2c32024-08-20 15:01:38 +020013#include <phosphor-logging/lg2.hpp>
Andrew Jeffery47af65a2021-12-01 14:16:31 +103014
15#include <charconv>
Christopher Meis59ef1e72025-04-16 08:53:25 +020016#include <iostream>
Andrew Jeffery47af65a2021-12-01 14:16:31 +103017
Andrew Jeffery47af65a2021-12-01 14:16:31 +103018using GetSubTreeType = std::vector<
19 std::pair<std::string,
20 std::vector<std::pair<std::string, std::vector<std::string>>>>>;
21
22constexpr const int32_t maxMapperDepth = 0;
23
Andrew Jefferyd9b67842022-04-05 16:44:20 +093024struct DBusInterfaceInstance
25{
26 std::string busName;
27 std::string path;
28 std::string interface;
29};
30
Patrick Williams5a807032025-03-03 11:20:39 -050031void getInterfaces(
32 const DBusInterfaceInstance& instance,
Christopher Meis26fbbd52025-03-26 14:55:06 +010033 const std::vector<std::shared_ptr<probe::PerformProbe>>& probeVector,
Alexander Hansena555acf2025-06-27 11:59:10 +020034 const std::shared_ptr<scan::PerformScan>& scan, boost::asio::io_context& io,
35 size_t retries = 5)
Andrew Jeffery47af65a2021-12-01 14:16:31 +103036{
Ed Tanous3013fb42022-07-09 08:27:06 -070037 if (retries == 0U)
Andrew Jeffery47af65a2021-12-01 14:16:31 +103038 {
Andrew Jefferyd9b67842022-04-05 16:44:20 +093039 std::cerr << "retries exhausted on " << instance.busName << " "
40 << instance.path << " " << instance.interface << "\n";
Andrew Jeffery47af65a2021-12-01 14:16:31 +103041 return;
42 }
43
Christopher Meiscf6a75b2025-06-03 07:53:50 +020044 scan->_em.systemBus->async_method_call(
Alexander Hansena555acf2025-06-27 11:59:10 +020045 [instance, scan, probeVector, retries,
46 &io](boost::system::error_code& errc, const DBusInterface& resp) {
Patrick Williamsb7077432024-08-16 15:22:21 -040047 if (errc)
48 {
49 std::cerr << "error calling getall on " << instance.busName
50 << " " << instance.path << " "
51 << instance.interface << "\n";
Andrew Jeffery47af65a2021-12-01 14:16:31 +103052
Patrick Williamsb7077432024-08-16 15:22:21 -040053 auto timer = std::make_shared<boost::asio::steady_timer>(io);
54 timer->expires_after(std::chrono::seconds(2));
Andrew Jeffery47af65a2021-12-01 14:16:31 +103055
Alexander Hansena555acf2025-06-27 11:59:10 +020056 timer->async_wait([timer, instance, scan, probeVector, retries,
57 &io](const boost::system::error_code&) {
58 getInterfaces(instance, probeVector, scan, io, retries - 1);
Patrick Williamsb7077432024-08-16 15:22:21 -040059 });
60 return;
61 }
Andrew Jeffery47af65a2021-12-01 14:16:31 +103062
Patrick Williamsb7077432024-08-16 15:22:21 -040063 scan->dbusProbeObjects[instance.path][instance.interface] = resp;
64 },
Andrew Jefferyd9b67842022-04-05 16:44:20 +093065 instance.busName, instance.path, "org.freedesktop.DBus.Properties",
66 "GetAll", instance.interface);
Andrew Jeffery47af65a2021-12-01 14:16:31 +103067}
68
Patrick Williams5a807032025-03-03 11:20:39 -050069static void processDbusObjects(
Christopher Meis26fbbd52025-03-26 14:55:06 +010070 std::vector<std::shared_ptr<probe::PerformProbe>>& probeVector,
71 const std::shared_ptr<scan::PerformScan>& scan,
Alexander Hansena555acf2025-06-27 11:59:10 +020072 const GetSubTreeType& interfaceSubtree, boost::asio::io_context& io)
Andrew Jeffery8d2761e2022-04-05 16:26:28 +093073{
Andrew Jeffery8d2761e2022-04-05 16:26:28 +093074 for (const auto& [path, object] : interfaceSubtree)
75 {
Andrew Jeffery47321832022-04-05 16:30:29 +093076 // Get a PropertiesChanged callback for all interfaces on this path.
Christopher Meiscf6a75b2025-06-03 07:53:50 +020077 scan->_em.registerCallback(path);
Andrew Jeffery47321832022-04-05 16:30:29 +093078
Andrew Jeffery8d2761e2022-04-05 16:26:28 +093079 for (const auto& [busname, ifaces] : object)
80 {
81 for (const std::string& iface : ifaces)
82 {
83 // The 3 default org.freedeskstop interfaces (Peer,
84 // Introspectable, and Properties) are returned by
85 // the mapper but don't have properties, so don't bother
86 // with the GetAll call to save some cycles.
87 if (!boost::algorithm::starts_with(iface, "org.freedesktop"))
88 {
Alexander Hansena555acf2025-06-27 11:59:10 +020089 getInterfaces({busname, path, iface}, probeVector, scan,
90 io);
Andrew Jeffery8d2761e2022-04-05 16:26:28 +093091 }
92 }
93 }
Andrew Jeffery8d2761e2022-04-05 16:26:28 +093094 }
95}
96
Andrew Jeffery47af65a2021-12-01 14:16:31 +103097// Populates scan->dbusProbeObjects with all interfaces and properties
98// for the paths that own the interfaces passed in.
Christopher Meis26fbbd52025-03-26 14:55:06 +010099void findDbusObjects(
100 std::vector<std::shared_ptr<probe::PerformProbe>>&& probeVector,
101 boost::container::flat_set<std::string>&& interfaces,
Alexander Hansena555acf2025-06-27 11:59:10 +0200102 const std::shared_ptr<scan::PerformScan>& scan, boost::asio::io_context& io,
103 size_t retries = 5)
Andrew Jeffery47af65a2021-12-01 14:16:31 +1030104{
105 // Filter out interfaces already obtained.
106 for (const auto& [path, probeInterfaces] : scan->dbusProbeObjects)
107 {
108 for (const auto& [interface, _] : probeInterfaces)
109 {
110 interfaces.erase(interface);
111 }
112 }
113 if (interfaces.empty())
114 {
115 return;
116 }
117
118 // find all connections in the mapper that expose a specific type
Christopher Meiscf6a75b2025-06-03 07:53:50 +0200119 scan->_em.systemBus->async_method_call(
Alexander Hansena555acf2025-06-27 11:59:10 +0200120 [interfaces, probeVector{std::move(probeVector)}, scan, retries,
121 &io](boost::system::error_code& ec,
122 const GetSubTreeType& interfaceSubtree) mutable {
Patrick Williamsb7077432024-08-16 15:22:21 -0400123 if (ec)
Andrew Jeffery47af65a2021-12-01 14:16:31 +1030124 {
Patrick Williamsb7077432024-08-16 15:22:21 -0400125 if (ec.value() == ENOENT)
126 {
127 return; // wasn't found by mapper
128 }
129 std::cerr << "Error communicating to mapper.\n";
Andrew Jeffery47af65a2021-12-01 14:16:31 +1030130
Patrick Williamsb7077432024-08-16 15:22:21 -0400131 if (retries == 0U)
132 {
133 // if we can't communicate to the mapper something is very
134 // wrong
135 std::exit(EXIT_FAILURE);
136 }
137
138 auto timer = std::make_shared<boost::asio::steady_timer>(io);
139 timer->expires_after(std::chrono::seconds(10));
140
141 timer->async_wait(
142 [timer, interfaces{std::move(interfaces)}, scan,
Alexander Hansena555acf2025-06-27 11:59:10 +0200143 probeVector{std::move(probeVector)}, retries,
144 &io](const boost::system::error_code&) mutable {
Patrick Williamsb7077432024-08-16 15:22:21 -0400145 findDbusObjects(std::move(probeVector),
Alexander Hansena555acf2025-06-27 11:59:10 +0200146 std::move(interfaces), scan, io,
Patrick Williamsb7077432024-08-16 15:22:21 -0400147 retries - 1);
148 });
149 return;
Andrew Jeffery47af65a2021-12-01 14:16:31 +1030150 }
151
Alexander Hansena555acf2025-06-27 11:59:10 +0200152 processDbusObjects(probeVector, scan, interfaceSubtree, io);
Patrick Williamsb7077432024-08-16 15:22:21 -0400153 },
Andrew Jeffery47af65a2021-12-01 14:16:31 +1030154 "xyz.openbmc_project.ObjectMapper",
155 "/xyz/openbmc_project/object_mapper",
156 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", maxMapperDepth,
157 interfaces);
Andrew Jeffery47af65a2021-12-01 14:16:31 +1030158}
159
Andrew Jeffery09a09a62022-04-12 22:49:57 +0930160static std::string getRecordName(const DBusInterface& probe,
161 const std::string& probeName)
Andrew Jeffery47af65a2021-12-01 14:16:31 +1030162{
163 if (probe.empty())
164 {
165 return probeName;
166 }
167
Andrew Jeffery928c5b22022-04-05 16:57:51 +0930168 // use an array so alphabetical order from the flat_map is maintained
Andrew Jeffery47af65a2021-12-01 14:16:31 +1030169 auto device = nlohmann::json::array();
Ed Tanous3013fb42022-07-09 08:27:06 -0700170 for (const auto& devPair : probe)
Andrew Jeffery47af65a2021-12-01 14:16:31 +1030171 {
172 device.push_back(devPair.first);
173 std::visit([&device](auto&& v) { device.push_back(v); },
174 devPair.second);
175 }
Andrew Jeffery86501872022-04-05 16:58:22 +0930176
Andrew Jeffery928c5b22022-04-05 16:57:51 +0930177 // hashes are hard to distinguish, use the non-hashed version if we want
178 // debug
Alexander Hansenc3db2c32024-08-20 15:01:38 +0200179 // return probeName + device.dump();
Andrew Jeffery1ae4ed62022-04-05 16:55:43 +0930180
Andrew Jeffery86501872022-04-05 16:58:22 +0930181 return std::to_string(std::hash<std::string>{}(probeName + device.dump()));
Andrew Jeffery47af65a2021-12-01 14:16:31 +1030182}
183
Alexander Hansena555acf2025-06-27 11:59:10 +0200184scan::PerformScan::PerformScan(
185 EntityManager& em, nlohmann::json& missingConfigurations,
Christopher Meisf7252572025-06-11 13:22:05 +0200186 std::vector<nlohmann::json>& configurations, boost::asio::io_context& io,
Alexander Hansena555acf2025-06-27 11:59:10 +0200187 std::function<void()>&& callback) :
Christopher Meiscf6a75b2025-06-03 07:53:50 +0200188 _em(em), _missingConfigurations(missingConfigurations),
Alexander Hansena555acf2025-06-27 11:59:10 +0200189 _configurations(configurations), _callback(std::move(callback)), io(io)
Andrew Jeffery47af65a2021-12-01 14:16:31 +1030190{}
Andrew Jefferydb451482022-04-13 16:53:22 +0930191
Andrew Jeffery7a7faed2022-04-13 17:24:56 +0930192static void pruneRecordExposes(nlohmann::json& record)
Andrew Jefferydb451482022-04-13 16:53:22 +0930193{
Andrew Jeffery7a7faed2022-04-13 17:24:56 +0930194 auto findExposes = record.find("Exposes");
Andrew Jeffery5f051452022-04-13 17:11:37 +0930195 if (findExposes == record.end())
Andrew Jefferydb451482022-04-13 16:53:22 +0930196 {
Andrew Jeffery5f051452022-04-13 17:11:37 +0930197 return;
Andrew Jefferydb451482022-04-13 16:53:22 +0930198 }
Andrew Jeffery5f051452022-04-13 17:11:37 +0930199
200 auto copy = nlohmann::json::array();
201 for (auto& expose : *findExposes)
202 {
Andrew Jeffery742a7eb2022-04-13 17:14:46 +0930203 if (!expose.is_null())
Andrew Jeffery5f051452022-04-13 17:11:37 +0930204 {
Andrew Jeffery742a7eb2022-04-13 17:14:46 +0930205 copy.emplace_back(expose);
Andrew Jeffery5f051452022-04-13 17:11:37 +0930206 }
Andrew Jeffery5f051452022-04-13 17:11:37 +0930207 }
208 *findExposes = copy;
Andrew Jefferydb451482022-04-13 16:53:22 +0930209}
210
Patrick Williamsb7077432024-08-16 15:22:21 -0400211static void recordDiscoveredIdentifiers(
212 std::set<nlohmann::json>& usedNames, std::list<size_t>& indexes,
213 const std::string& probeName, const nlohmann::json& record)
Andrew Jeffery6addc022022-04-13 18:08:58 +0930214{
215 size_t indexIdx = probeName.find('$');
Andrew Jefferyba41b622022-04-13 18:13:28 +0930216 if (indexIdx == std::string::npos)
Andrew Jeffery6addc022022-04-13 18:08:58 +0930217 {
218 return;
219 }
220
Andrew Jefferyc0da0cc2022-04-13 18:15:09 +0930221 auto nameIt = record.find("Name");
222 if (nameIt == record.end())
Andrew Jeffery6addc022022-04-13 18:08:58 +0930223 {
224 std::cerr << "Last JSON Illegal\n";
225 return;
226 }
227
228 int index = 0;
229 auto str = nameIt->get<std::string>().substr(indexIdx);
Ed Tanous3013fb42022-07-09 08:27:06 -0700230 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
231 const char* endPtr = str.data() + str.size();
232 auto [p, ec] = std::from_chars(str.data(), endPtr, index);
Andrew Jeffery6addc022022-04-13 18:08:58 +0930233 if (ec != std::errc())
234 {
235 return; // non-numeric replacement
236 }
237
238 usedNames.insert(nameIt.value());
239
240 auto usedIt = std::find(indexes.begin(), indexes.end(), index);
241 if (usedIt != indexes.end())
242 {
243 indexes.erase(usedIt);
244 }
245}
246
Andrew Jeffery6890ae22022-04-14 15:33:01 +0930247static bool extractExposeActionRecordNames(std::vector<std::string>& matches,
248 nlohmann::json::iterator& keyPair)
249{
Andrew Jefferya2449842022-04-14 15:35:51 +0930250 if (keyPair.value().is_string())
Andrew Jeffery6890ae22022-04-14 15:33:01 +0930251 {
252 matches.emplace_back(keyPair.value());
Andrew Jefferyba3c50c2022-04-14 15:34:38 +0930253 return true;
Andrew Jeffery6890ae22022-04-14 15:33:01 +0930254 }
Andrew Jefferyba3c50c2022-04-14 15:34:38 +0930255
Andrew Jefferya2449842022-04-14 15:35:51 +0930256 if (keyPair.value().is_array())
Andrew Jeffery6890ae22022-04-14 15:33:01 +0930257 {
258 for (const auto& value : keyPair.value())
259 {
Andrew Jefferya2449842022-04-14 15:35:51 +0930260 if (!value.is_string())
Andrew Jeffery6890ae22022-04-14 15:33:01 +0930261 {
262 std::cerr << "Value is invalid type " << value << "\n";
263 break;
264 }
265 matches.emplace_back(value);
266 }
Andrew Jeffery6890ae22022-04-14 15:33:01 +0930267
Andrew Jefferyba3c50c2022-04-14 15:34:38 +0930268 return true;
Andrew Jeffery6890ae22022-04-14 15:33:01 +0930269 }
270
Andrew Jefferyba3c50c2022-04-14 15:34:38 +0930271 std::cerr << "Value is invalid type " << keyPair.key() << "\n";
272
273 return false;
Andrew Jeffery6890ae22022-04-14 15:33:01 +0930274}
275
Patrick Williamsb7077432024-08-16 15:22:21 -0400276static std::optional<std::vector<std::string>::iterator> findExposeActionRecord(
277 std::vector<std::string>& matches, const nlohmann::json& record)
Andrew Jeffery6de53fb2022-04-14 15:45:38 +0930278{
Andrew Jeffery1a02da82022-04-14 20:39:06 +0930279 const auto& name = (record)["Name"].get_ref<const std::string&>();
280 auto compare = [&name](const std::string& s) { return s == name; };
281 auto matchIt = std::find_if(matches.begin(), matches.end(), compare);
Andrew Jeffery6de53fb2022-04-14 15:45:38 +0930282
283 if (matchIt == matches.end())
284 {
285 return std::nullopt;
286 }
287
288 return matchIt;
289}
290
Andrew Jefferycf11bd32022-04-14 18:34:31 +0930291static void applyBindExposeAction(nlohmann::json& exposedObject,
292 nlohmann::json& expose,
293 const std::string& propertyName)
294{
295 if (boost::starts_with(propertyName, "Bind"))
296 {
297 std::string bind = propertyName.substr(sizeof("Bind") - 1);
298 exposedObject["Status"] = "okay";
299 expose[bind] = exposedObject;
300 }
301}
302
303static void applyDisableExposeAction(nlohmann::json& exposedObject,
304 const std::string& propertyName)
305{
306 if (propertyName == "DisableNode")
307 {
308 exposedObject["Status"] = "disabled";
309 }
310}
311
Patrick Williamsb7077432024-08-16 15:22:21 -0400312static void applyConfigExposeActions(
313 std::vector<std::string>& matches, nlohmann::json& expose,
314 const std::string& propertyName, nlohmann::json& configExposes)
Andrew Jeffery5468f8e2022-04-14 21:08:31 +0930315{
Andrew Jefferyda45e5e2022-04-14 21:12:02 +0930316 for (auto& exposedObject : configExposes)
Andrew Jeffery5468f8e2022-04-14 21:08:31 +0930317 {
318 auto match = findExposeActionRecord(matches, exposedObject);
Andrew Jeffery060ac9c2022-04-14 21:11:18 +0930319 if (match)
Andrew Jeffery5468f8e2022-04-14 21:08:31 +0930320 {
Andrew Jeffery060ac9c2022-04-14 21:11:18 +0930321 matches.erase(*match);
322 applyBindExposeAction(exposedObject, expose, propertyName);
323 applyDisableExposeAction(exposedObject, propertyName);
Andrew Jeffery5468f8e2022-04-14 21:08:31 +0930324 }
Andrew Jeffery5468f8e2022-04-14 21:08:31 +0930325 }
326}
327
Patrick Williamsb7077432024-08-16 15:22:21 -0400328static void applyExposeActions(
329 nlohmann::json& systemConfiguration, const std::string& recordName,
330 nlohmann::json& expose, nlohmann::json::iterator& keyPair)
Andrew Jefferyb48779d2022-04-14 21:40:31 +0930331{
332 bool isBind = boost::starts_with(keyPair.key(), "Bind");
333 bool isDisable = keyPair.key() == "DisableNode";
334 bool isExposeAction = isBind || isDisable;
335
336 if (!isExposeAction)
337 {
338 return;
339 }
340
341 std::vector<std::string> matches;
342
343 if (!extractExposeActionRecordNames(matches, keyPair))
344 {
345 return;
346 }
347
Patrick Williams2594d362022-09-28 06:46:24 -0500348 for (const auto& [configId, config] : systemConfiguration.items())
Andrew Jefferyb48779d2022-04-14 21:40:31 +0930349 {
350 // don't disable ourselves
351 if (isDisable && configId == recordName)
352 {
353 continue;
354 }
355
356 auto configListFind = config.find("Exposes");
357 if (configListFind == config.end())
358 {
359 continue;
360 }
361
362 if (!configListFind->is_array())
363 {
364 continue;
365 }
366
367 applyConfigExposeActions(matches, expose, keyPair.key(),
368 *configListFind);
369 }
370
371 if (!matches.empty())
372 {
373 std::cerr << "configuration file dependency error, could not find "
374 << keyPair.key() << " " << keyPair.value() << "\n";
375 }
376}
377
Patrick Williamsb7077432024-08-16 15:22:21 -0400378static std::string generateDeviceName(
379 const std::set<nlohmann::json>& usedNames, const DBusObject& dbusObject,
380 size_t foundDeviceIdx, const std::string& nameTemplate,
381 std::optional<std::string>& replaceStr)
Andrew Jefferydabee982022-04-19 13:27:24 +0930382{
383 nlohmann::json copyForName = {{"Name", nameTemplate}};
384 nlohmann::json::iterator copyIt = copyForName.begin();
Christopher Meis59ef1e72025-04-16 08:53:25 +0200385 std::optional<std::string> replaceVal = em_utils::templateCharReplace(
386 copyIt, dbusObject, foundDeviceIdx, replaceStr);
Andrew Jefferydabee982022-04-19 13:27:24 +0930387
388 if (!replaceStr && replaceVal)
389 {
Patrick Williams64599932025-05-14 07:24:20 -0400390 if (usedNames.contains(copyIt.value()))
Andrew Jefferydabee982022-04-19 13:27:24 +0930391 {
392 replaceStr = replaceVal;
393 copyForName = {{"Name", nameTemplate}};
394 copyIt = copyForName.begin();
Christopher Meis59ef1e72025-04-16 08:53:25 +0200395 em_utils::templateCharReplace(copyIt, dbusObject, foundDeviceIdx,
396 replaceStr);
Andrew Jefferydabee982022-04-19 13:27:24 +0930397 }
398 }
399
400 if (replaceStr)
401 {
402 std::cerr << "Duplicates found, replacing " << *replaceStr
403 << " with found device index.\n Consider "
404 "fixing template to not have duplicates\n";
405 }
406
407 return copyIt.value();
408}
409
Christopher Meis26fbbd52025-03-26 14:55:06 +0100410void scan::PerformScan::updateSystemConfiguration(
411 const nlohmann::json& recordRef, const std::string& probeName,
412 FoundDevices& foundDevices)
Andrew Jefferyae6c1a42022-04-19 15:44:42 +0930413{
414 _passed = true;
415 passedProbes.push_back(probeName);
416
417 std::set<nlohmann::json> usedNames;
418 std::list<size_t> indexes(foundDevices.size());
419 std::iota(indexes.begin(), indexes.end(), 1);
420
421 // copy over persisted configurations and make sure we remove
422 // indexes that are already used
423 for (auto itr = foundDevices.begin(); itr != foundDevices.end();)
424 {
425 std::string recordName = getRecordName(itr->interface, probeName);
426
Christopher Meiscf6a75b2025-06-03 07:53:50 +0200427 auto record = _em.systemConfiguration.find(recordName);
428 if (record == _em.systemConfiguration.end())
Andrew Jefferyae6c1a42022-04-19 15:44:42 +0930429 {
Christopher Meiscf6a75b2025-06-03 07:53:50 +0200430 record = _em.lastJson.find(recordName);
431 if (record == _em.lastJson.end())
Zhikui Ren1f77d9c2022-08-29 16:02:37 -0700432 {
433 itr++;
434 continue;
435 }
436
437 pruneRecordExposes(*record);
438
Christopher Meiscf6a75b2025-06-03 07:53:50 +0200439 _em.systemConfiguration[recordName] = *record;
Andrew Jefferyae6c1a42022-04-19 15:44:42 +0930440 }
Andrew Jefferyae6c1a42022-04-19 15:44:42 +0930441 _missingConfigurations.erase(recordName);
442
443 // We've processed the device, remove it and advance the
444 // iterator
445 itr = foundDevices.erase(itr);
JinFuLin8f05a3a2022-11-21 15:33:24 +0800446 recordDiscoveredIdentifiers(usedNames, indexes, probeName, *record);
Andrew Jefferyae6c1a42022-04-19 15:44:42 +0930447 }
448
449 std::optional<std::string> replaceStr;
450
451 DBusObject emptyObject;
452 DBusInterface emptyInterface;
453 emptyObject.emplace(std::string{}, emptyInterface);
454
455 for (const auto& [foundDevice, path] : foundDevices)
456 {
457 // Need all interfaces on this path so that template
458 // substitutions can be done with any of the contained
459 // properties. If the probe that passed didn't use an
460 // interface, such as if it was just TRUE, then
461 // templateCharReplace will just get passed in an empty
462 // map.
Andrew Jefferyaf9b46b2022-04-21 12:34:43 +0930463 auto objectIt = dbusProbeObjects.find(path);
464 const DBusObject& dbusObject = (objectIt == dbusProbeObjects.end())
465 ? emptyObject
466 : objectIt->second;
Andrew Jefferyae6c1a42022-04-19 15:44:42 +0930467
468 nlohmann::json record = recordRef;
469 std::string recordName = getRecordName(foundDevice, probeName);
470 size_t foundDeviceIdx = indexes.front();
471 indexes.pop_front();
472
473 // check name first so we have no duplicate names
474 auto getName = record.find("Name");
475 if (getName == record.end())
476 {
477 std::cerr << "Record Missing Name! " << record.dump();
478 continue; // this should be impossible at this level
479 }
480
481 std::string deviceName = generateDeviceName(
482 usedNames, dbusObject, foundDeviceIdx, getName.value(), replaceStr);
483 getName.value() = deviceName;
484 usedNames.insert(deviceName);
485
486 for (auto keyPair = record.begin(); keyPair != record.end(); keyPair++)
487 {
488 if (keyPair.key() != "Name")
489 {
Christopher Meis59ef1e72025-04-16 08:53:25 +0200490 em_utils::templateCharReplace(keyPair, dbusObject,
491 foundDeviceIdx, replaceStr);
Andrew Jefferyae6c1a42022-04-19 15:44:42 +0930492 }
493 }
494
495 // insert into configuration temporarily to be able to
496 // reference ourselves
497
Christopher Meiscf6a75b2025-06-03 07:53:50 +0200498 _em.systemConfiguration[recordName] = record;
Andrew Jefferyae6c1a42022-04-19 15:44:42 +0930499
500 auto findExpose = record.find("Exposes");
501 if (findExpose == record.end())
502 {
503 continue;
504 }
505
506 for (auto& expose : *findExpose)
507 {
508 for (auto keyPair = expose.begin(); keyPair != expose.end();
509 keyPair++)
510 {
Christopher Meis59ef1e72025-04-16 08:53:25 +0200511 em_utils::templateCharReplace(keyPair, dbusObject,
512 foundDeviceIdx, replaceStr);
Andrew Jefferyae6c1a42022-04-19 15:44:42 +0930513
Christopher Meiscf6a75b2025-06-03 07:53:50 +0200514 applyExposeActions(_em.systemConfiguration, recordName, expose,
Andrew Jefferyae6c1a42022-04-19 15:44:42 +0930515 keyPair);
516 }
517 }
518
519 // overwrite ourselves with cleaned up version
Christopher Meiscf6a75b2025-06-03 07:53:50 +0200520 _em.systemConfiguration[recordName] = record;
Andrew Jefferyae6c1a42022-04-19 15:44:42 +0930521 _missingConfigurations.erase(recordName);
522 }
523}
524
Christopher Meis26fbbd52025-03-26 14:55:06 +0100525void scan::PerformScan::run()
Andrew Jeffery47af65a2021-12-01 14:16:31 +1030526{
527 boost::container::flat_set<std::string> dbusProbeInterfaces;
Christopher Meis26fbbd52025-03-26 14:55:06 +0100528 std::vector<std::shared_ptr<probe::PerformProbe>> dbusProbePointers;
Andrew Jeffery47af65a2021-12-01 14:16:31 +1030529
530 for (auto it = _configurations.begin(); it != _configurations.end();)
531 {
Andrew Jeffery47af65a2021-12-01 14:16:31 +1030532 // check for poorly formatted fields, probe must be an array
Andrew Jeffery38834872022-04-19 15:15:57 +0930533 auto findProbe = it->find("Probe");
Andrew Jeffery47af65a2021-12-01 14:16:31 +1030534 if (findProbe == it->end())
535 {
536 std::cerr << "configuration file missing probe:\n " << *it << "\n";
537 it = _configurations.erase(it);
538 continue;
539 }
Andrew Jeffery47af65a2021-12-01 14:16:31 +1030540
Andrew Jeffery38834872022-04-19 15:15:57 +0930541 auto findName = it->find("Name");
Andrew Jeffery47af65a2021-12-01 14:16:31 +1030542 if (findName == it->end())
543 {
544 std::cerr << "configuration file missing name:\n " << *it << "\n";
545 it = _configurations.erase(it);
546 continue;
547 }
548 std::string probeName = *findName;
549
550 if (std::find(passedProbes.begin(), passedProbes.end(), probeName) !=
551 passedProbes.end())
552 {
553 it = _configurations.erase(it);
554 continue;
555 }
Andrew Jeffery38834872022-04-19 15:15:57 +0930556
Andrew Jeffery98f3d532022-04-19 15:29:22 +0930557 nlohmann::json& recordRef = *it;
Andrew Jeffery38834872022-04-19 15:15:57 +0930558 nlohmann::json probeCommand;
559 if ((*findProbe).type() != nlohmann::json::value_t::array)
560 {
561 probeCommand = nlohmann::json::array();
562 probeCommand.push_back(*findProbe);
563 }
564 else
565 {
566 probeCommand = *findProbe;
567 }
Andrew Jeffery47af65a2021-12-01 14:16:31 +1030568
569 // store reference to this to children to makes sure we don't get
570 // destroyed too early
571 auto thisRef = shared_from_this();
Christopher Meis26fbbd52025-03-26 14:55:06 +0100572 auto probePointer = std::make_shared<probe::PerformProbe>(
Andrew Jefferyea4ff022022-04-21 12:31:40 +0930573 recordRef, probeCommand, probeName, thisRef);
Andrew Jeffery47af65a2021-12-01 14:16:31 +1030574
575 // parse out dbus probes by discarding other probe types, store in a
576 // map
577 for (const nlohmann::json& probeJson : probeCommand)
578 {
579 const std::string* probe = probeJson.get_ptr<const std::string*>();
580 if (probe == nullptr)
581 {
582 std::cerr << "Probe statement wasn't a string, can't parse";
583 continue;
584 }
Christopher Meis26fbbd52025-03-26 14:55:06 +0100585 if (probe::findProbeType(*probe))
Andrew Jeffery47af65a2021-12-01 14:16:31 +1030586 {
587 continue;
588 }
589 // syntax requires probe before first open brace
590 auto findStart = probe->find('(');
591 std::string interface = probe->substr(0, findStart);
592 dbusProbeInterfaces.emplace(interface);
593 dbusProbePointers.emplace_back(probePointer);
594 }
595 it++;
596 }
597
598 // probe vector stores a shared_ptr to each PerformProbe that cares
599 // about a dbus interface
600 findDbusObjects(std::move(dbusProbePointers),
Alexander Hansena555acf2025-06-27 11:59:10 +0200601 std::move(dbusProbeInterfaces), shared_from_this(), io);
Andrew Jeffery47af65a2021-12-01 14:16:31 +1030602}
603
Christopher Meis26fbbd52025-03-26 14:55:06 +0100604scan::PerformScan::~PerformScan()
Andrew Jeffery47af65a2021-12-01 14:16:31 +1030605{
606 if (_passed)
607 {
608 auto nextScan = std::make_shared<PerformScan>(
Alexander Hansena555acf2025-06-27 11:59:10 +0200609 _em, _missingConfigurations, _configurations, io,
610 std::move(_callback));
Andrew Jeffery47af65a2021-12-01 14:16:31 +1030611 nextScan->passedProbes = std::move(passedProbes);
612 nextScan->dbusProbeObjects = std::move(dbusProbeObjects);
613 nextScan->run();
Andrew Jeffery47af65a2021-12-01 14:16:31 +1030614 }
615 else
616 {
617 _callback();
Andrew Jeffery47af65a2021-12-01 14:16:31 +1030618 }
619}