frudevice: add i2c bus blacklist json
The fru-device daemon contained a black list internally of buses to not
rescan in the future. This list was generated automatically by talking
to each bus. On a system where scanning the devices on a specific bus
can cause problems, extend that blacklist to be something that can be
specified for a machine.
This adds a file blacklist.json, which currently contains one field. An
array of bus integers named "buses." This file can be overwritten by a
platform recipe to drop in a list of buses to avoid scanning.
Tested: Verified that an empty, but valid json file (the default file
has no effect).
Tested: Verified that the array with an invalid type of entry is caught,
reported and the program exited.
Tested: Verified that the array with three valid entries prevents the
daemon from scanning the devices on those buses.
Signed-off-by: Patrick Venture <venture@google.com>
Change-Id: I1c426ebed2f7ac073ee45ed8b205e4a176a519ab
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 497f886..c57956c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -133,6 +133,7 @@
add_dependencies (entity-manager nlohmann-json)
add_dependencies (entity-manager sdbusplus-project)
add_dependencies (entity-manager valijson)
+ add_dependencies (fru-device nlohmann-json)
add_dependencies (fru-device valijson)
add_dependencies (fru-device sdbusplus-project)
add_dependencies (valijson nlohmann-json)
@@ -147,8 +148,10 @@
set (PACKAGE_DIR /usr/share/entity-manager/)
target_compile_definitions (entity-manager PRIVATE PACKAGE_DIR="${PACKAGE_DIR}"
-DBOOST_ASIO_DISABLE_THREADS)
+target_compile_definitions (fru-device PRIVATE PACKAGE_DIR="${PACKAGE_DIR}")
install (TARGETS fru-device entity-manager DESTINATION bin)
install (DIRECTORY configurations DESTINATION ${PACKAGE_DIR})
install (DIRECTORY overlay_templates DESTINATION ${PACKAGE_DIR})
install (DIRECTORY schemas DESTINATION ${PACKAGE_DIR}/configurations)
install (FILES ${SERVICE_FILES} DESTINATION /lib/systemd/system/)
+install (FILES blacklist.json DESTINATION ${PACKAGE_DIR})
diff --git a/blacklist.json b/blacklist.json
new file mode 100644
index 0000000..f112a7b
--- /dev/null
+++ b/blacklist.json
@@ -0,0 +1,3 @@
+{
+ "buses": []
+}
diff --git a/src/FruDevice.cpp b/src/FruDevice.cpp
index 0f1350c..0ef0e94 100644
--- a/src/FruDevice.cpp
+++ b/src/FruDevice.cpp
@@ -27,9 +27,11 @@
#include <fstream>
#include <future>
#include <iostream>
+#include <nlohmann/json.hpp>
#include <regex>
#include <sdbusplus/asio/connection.hpp>
#include <sdbusplus/asio/object_server.hpp>
+#include <string>
#include <thread>
#include <variant>
@@ -45,6 +47,8 @@
constexpr size_t MAX_EEPROM_PAGE_INDEX = 255;
constexpr size_t busTimeoutSeconds = 5;
+constexpr const char* blacklistPath = PACKAGE_DIR "blacklist.json";
+
const static constexpr char* BASEBOARD_FRU_LOCATION =
"/etc/fru/baseboard.fru.bin";
@@ -275,6 +279,69 @@
return future.get();
}
+void loadBlacklist(const char* path)
+{
+ std::ifstream blacklistStream(path);
+ if (!blacklistStream.good())
+ {
+ // File is optional.
+ std::cerr << "Cannot open blacklist file.\n\n";
+ return;
+ }
+
+ nlohmann::json data =
+ nlohmann::json::parse(blacklistStream, nullptr, false);
+ if (data.is_discarded())
+ {
+ std::cerr << "Illegal blacklist file detected, cannot validate JSON, "
+ "exiting\n";
+ std::exit(EXIT_FAILURE);
+ return;
+ }
+
+ // It's expected to have at least one field, "buses" that is an array of the
+ // buses by integer. Allow for future options to exclude further aspects,
+ // such as specific addresses or ranges.
+ if (data.type() != nlohmann::json::value_t::object)
+ {
+ std::cerr << "Illegal blacklist, expected to read dictionary\n";
+ std::exit(EXIT_FAILURE);
+ return;
+ }
+
+ // If buses field is missing, that's fine.
+ if (data.count("buses") == 1)
+ {
+ // Parse the buses array after a little validation.
+ auto buses = data.at("buses");
+ if (buses.type() != nlohmann::json::value_t::array)
+ {
+ // Buses field present but invalid, therefore this is an error.
+ std::cerr << "Invalid contents for blacklist buses field\n";
+ std::exit(EXIT_FAILURE);
+ return;
+ }
+
+ // Catch exception here for type mis-match.
+ try
+ {
+ for (const auto& bus : buses)
+ {
+ busBlacklist.insert(bus.get<size_t>());
+ }
+ }
+ catch (const nlohmann::detail::type_error& e)
+ {
+ // Type mis-match is a critical error.
+ std::cerr << "Invalid bus type: " << e.what() << "\n";
+ std::exit(EXIT_FAILURE);
+ return;
+ }
+ }
+
+ return;
+}
+
static void FindI2CDevices(const std::vector<fs::path>& i2cBuses,
BusMap& busmap)
{
@@ -818,6 +885,9 @@
return 1;
}
+ // check for and load blacklist with initial buses.
+ loadBlacklist(blacklistPath);
+
boost::asio::io_service io;
auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
auto objServer = sdbusplus::asio::object_server(systemBus);