Initial integration with Entity Manager
This commit changes eStoraged so that it doesn't take a specific device
as an argument. Instead, it looks for a config object from Entity
Manager and creates a D-Bus object corresponding to the config object.
The config objects need to expose the following interface:
"xyz.openbmc_project.Configuration.EmmcDevice"
To support more types of storage devices in the future, we can introduce
a new interface for each one.
In addition, eStoraged currently only supports 1 eMMC device. If we want
to support more than one in the future, we will need to add more
information to the Entity Manager config, to distinguish between them.
Assuming the eMMC is located on a FRU-detectable board, an "Exposes"
entry can be added to that board's Entity Manager config, for example:
{
"Name": "example_emmc",
"Type": "EmmcDevice"
}
Doing so will tell Entity Manager to create a config object with the
EmmcDevice interface mentioned above. Then, eStoraged will find the
config object with that interface and create its own D-Bus object that
can be used to manage the eMMC.
Tested:
Updated the Entity Manager config (as described above), started
eStoraged, then tested most of its methods and properties using busctl.
$ busctl call xyz.openbmc_project.eStoraged \
/xyz/openbmc_project/inventory/storage/mmcblk0 \
xyz.openbmc_project.Inventory.Item.Volume FormatLuks ays 3 1 2 3 \
xyz.openbmc_project.Inventory.Item.Volume.FilesystemType.ext4 \
--timeout=60
$ busctl call xyz.openbmc_project.eStoraged \
/xyz/openbmc_project/inventory/storage/mmcblk0 \
xyz.openbmc_project.Inventory.Item.Volume Lock
$ busctl call xyz.openbmc_project.eStoraged \
/xyz/openbmc_project/inventory/storage/mmcblk0 \
xyz.openbmc_project.Inventory.Item.Volume Unlock ay 3 1 2 3
$ busctl get-property xyz.openbmc_project.eStoraged \
/xyz/openbmc_project/inventory/storage/mmcblk0 \
xyz.openbmc_project.Inventory.Item.Volume Locked
$ busctl get-property xyz.openbmc_project.eStoraged \
/xyz/openbmc_project/inventory/storage/mmcblk0 \
xyz.openbmc_project.Inventory.Item.Drive Capacity
$ busctl call xyz.openbmc_project.eStoraged \
/xyz/openbmc_project/inventory/storage/mmcblk0 \
xyz.openbmc_project.Inventory.Item.Volume Erase s \
xyz.openbmc_project.Inventory.Item.Volume.EraseMethod.VerifyGeometry
$ busctl call xyz.openbmc_project.eStoraged \
/xyz/openbmc_project/inventory/storage/mmcblk0 \
xyz.openbmc_project.Inventory.Item.Volume Erase s \
xyz.openbmc_project.Inventory.Item.Volume.EraseMethod.LogicalOverWrite \
--timeout=1200
$ busctl call xyz.openbmc_project.eStoraged \
/xyz/openbmc_project/inventory/storage/mmcblk0 \
xyz.openbmc_project.Inventory.Item.Volume Erase s \
xyz.openbmc_project.Inventory.Item.Volume.EraseMethod.LogicalVerify \
--timeout=1200
Signed-off-by: John Wedig <johnwedig@google.com>
Change-Id: If137d02e185c366f4a1437076512b4883ba6d595
diff --git a/include/getConfig.hpp b/include/getConfig.hpp
new file mode 100644
index 0000000..c833a39
--- /dev/null
+++ b/include/getConfig.hpp
@@ -0,0 +1,77 @@
+#pragma once
+
+#include <boost/container/flat_map.hpp>
+#include <sdbusplus/asio/connection.hpp>
+
+#include <cstdlib>
+#include <functional>
+#include <memory>
+
+namespace estoraged
+{
+
+using BasicVariantType =
+ std::variant<std::vector<std::string>, std::string, int64_t, uint64_t,
+ double, int32_t, uint32_t, int16_t, uint16_t, uint8_t, bool>;
+
+/* Map of properties for the config interface. */
+using StorageData = boost::container::flat_map<std::string, BasicVariantType>;
+using ManagedStorageType =
+ boost::container::flat_map<sdbusplus::message::object_path, StorageData>;
+
+const constexpr char* emmcConfigInterface =
+ "xyz.openbmc_project.Configuration.EmmcDevice";
+
+/** @class GetStorageConfiguration
+ * @brief Object used to find Entity Manager config objects.
+ * @details eStoraged will create a new D-Bus object for each config object.
+ */
+class GetStorageConfiguration :
+ public std::enable_shared_from_this<GetStorageConfiguration>
+{
+ public:
+ /** @brief Constructor for GetStorageConfiguration
+ *
+ * @param[in] connection - shared_ptr to D-Bus connection object.
+ * @param[in] callbackFunc - callback to run after finding the config
+ * objects.
+ */
+ GetStorageConfiguration(
+ std::shared_ptr<sdbusplus::asio::connection> connection,
+ std::function<void(ManagedStorageType& resp)>&& callbackFunc) :
+ dbusConnection(std::move(connection)),
+ callback(std::move(callbackFunc))
+ {}
+
+ GetStorageConfiguration& operator=(const GetStorageConfiguration&) = delete;
+ GetStorageConfiguration(const GetStorageConfiguration&) = delete;
+ GetStorageConfiguration(GetStorageConfiguration&&) = default;
+ GetStorageConfiguration& operator=(GetStorageConfiguration&&) = default;
+
+ /** @brief Destructor for GetStorageConfiguration.
+ * @details This will execute the callback provided to the constructor.
+ */
+ ~GetStorageConfiguration();
+
+ /** @brief Find the Entity Manager config objects for eStoraged. */
+ void getConfiguration();
+
+ /** @brief Get the D-Bus properties from the config object.
+ *
+ * @param[in] path - D-Bus object path of the config object.
+ * @param[in] owner - D-Bus service that owns the config object.
+ */
+ void getStorageInfo(const std::string& path, const std::string& owner);
+
+ /** @brief Map containing config objects with corresponding properties. */
+ ManagedStorageType respData;
+
+ /** @brief Connection to D-Bus. */
+ std::shared_ptr<sdbusplus::asio::connection> dbusConnection;
+
+ private:
+ /** @brief callback to process the config object data in respData. */
+ std::function<void(ManagedStorageType& resp)> callback;
+};
+
+} // namespace estoraged
diff --git a/include/util.hpp b/include/util.hpp
index b0f4970..2834950 100644
--- a/include/util.hpp
+++ b/include/util.hpp
@@ -1,4 +1,7 @@
#pragma once
+#include "getConfig.hpp"
+
+#include <filesystem>
#include <string>
namespace estoraged
@@ -18,6 +21,27 @@
*/
uint8_t findPredictedMediaLifeLeftPercent(const std::string& sysfsPath);
+/** @brief Look for the device described by the provided StorageData.
+ * @details Currently, this function assumes that there's only one eMMC.
+ * When we need to support multiple eMMCs, we will put more information in
+ * the EntityManager config, to differentiate between them. Also, if we
+ * want to support other types of storage devices, this function will need
+ * to be updated.
+ *
+ * @param[in] data - map of properties from the config object.
+ * @param[in] searchDir - directory to search for devices in sysfs, e.g.
+ * /sys/block
+ * @param[out] deviceFile - device file that was found, e.g. /dev/mmcblk0.
+ * @param[out] sysfsDir - directory containing the sysfs entries for this
+ * device.
+ * @param[out] luksName - name of the encrypted LUKS device.
+ *
+ * @return True if the device was found. False otherwise.
+ */
+bool findDevice(const StorageData& data, const std::filesystem::path& searchDir,
+ std::filesystem::path& deviceFile,
+ std::filesystem::path& sysfsDir, std::string& luksName);
+
} // namespace util
} // namespace estoraged
diff --git a/src/getConfig.cpp b/src/getConfig.cpp
new file mode 100644
index 0000000..1046416
--- /dev/null
+++ b/src/getConfig.cpp
@@ -0,0 +1,88 @@
+
+#include "getConfig.hpp"
+
+#include <phosphor-logging/lg2.hpp>
+#include <sdbusplus/asio/connection.hpp>
+
+#include <cstdlib>
+#include <memory>
+#include <string>
+#include <utility>
+#include <variant>
+#include <vector>
+
+namespace estoraged
+{
+
+namespace mapper
+{
+constexpr const char* busName = "xyz.openbmc_project.ObjectMapper";
+constexpr const char* path = "/xyz/openbmc_project/object_mapper";
+constexpr const char* interface = "xyz.openbmc_project.ObjectMapper";
+constexpr const char* subtree = "GetSubTree";
+} // namespace mapper
+
+using GetSubTreeType = std::vector<
+ std::pair<std::string,
+ std::vector<std::pair<std::string, std::vector<std::string>>>>>;
+
+void GetStorageConfiguration::getStorageInfo(const std::string& path,
+ const std::string& owner)
+{
+ std::shared_ptr<GetStorageConfiguration> self = shared_from_this();
+ self->dbusConnection->async_method_call(
+ [self, path, owner](
+ const boost::system::error_code ec,
+ boost::container::flat_map<std::string, BasicVariantType>& data) {
+ if (ec)
+ {
+ lg2::error("Error getting properties for {PATH}", "PATH", path,
+ "REDFISH_MESSAGE_ID",
+ std::string("OpenBMC.0.1.GetStorageInfoFail"));
+ return;
+ }
+
+ self->respData[path] = std::move(data);
+ },
+ owner, path, "org.freedesktop.DBus.Properties", "GetAll",
+ emmcConfigInterface);
+}
+
+void GetStorageConfiguration::getConfiguration()
+{
+ std::shared_ptr<GetStorageConfiguration> self = shared_from_this();
+ dbusConnection->async_method_call(
+ [self](const boost::system::error_code ec, const GetSubTreeType& ret) {
+ if (ec)
+ {
+ lg2::error("Error calling mapper");
+ return;
+ }
+ for (const auto& [objPath, objDict] : ret)
+ {
+ if (objDict.empty())
+ {
+ return;
+ }
+ const std::string& objOwner = objDict.begin()->first;
+ /* Look for the config interface exposed by this object. */
+ for (const std::string& interface : objDict.begin()->second)
+ {
+ if (interface.compare(emmcConfigInterface) == 0)
+ {
+ /* Get the properties exposed by this interface. */
+ self->getStorageInfo(objPath, objOwner);
+ }
+ }
+ }
+ },
+ mapper::busName, mapper::path, mapper::interface, mapper::subtree, "/",
+ 0, std::vector<const char*>(1, emmcConfigInterface));
+}
+
+GetStorageConfiguration::~GetStorageConfiguration()
+{
+ callback(respData);
+}
+
+} // namespace estoraged
diff --git a/src/main.cpp b/src/main.cpp
index 41085eb..5476dbb 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,83 +1,171 @@
#include "estoraged.hpp"
+#include "getConfig.hpp"
+#include "util.hpp"
-#include <unistd.h>
-
+#include <boost/asio/deadline_timer.hpp>
#include <boost/asio/io_context.hpp>
+#include <boost/asio/post.hpp>
+#include <boost/container/flat_map.hpp>
+#include <boost/container/throw_exception.hpp>
#include <phosphor-logging/lg2.hpp>
#include <sdbusplus/asio/connection.hpp>
#include <sdbusplus/asio/object_server.hpp>
#include <sdbusplus/bus.hpp>
+#include <sdbusplus/bus/match.hpp>
#include <util.hpp>
+#include <cstdlib>
#include <filesystem>
#include <iostream>
#include <memory>
#include <string>
-static void usage(std::string_view name)
+/*
+ * Get the configuration objects from Entity Manager and create new D-Bus
+ * objects for each one. This function can be called multiple times, in case
+ * new configuration objects show up later.
+ *
+ * Note: Currently, eStoraged can only support 1 eMMC device.
+ * Additional changes will be needed to support more than 1 eMMC, or to support
+ * more types of storage devices.
+ */
+void createStorageObjects(
+ boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
+ boost::container::flat_map<
+ std::string, std::unique_ptr<estoraged::EStoraged>>& storageObjects,
+ std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
{
- std::cerr
- << "Usage: " << name
- << "eStorageD service on the BMC\n\n"
- " -b <blockDevice> The phyical encrypted device\n"
- " If omitted, default is /dev/mmcblk0.\n"
- " -c <containerName> The LUKS container name to be created\n"
- " If omitted, default is luks-<devName>"
- " -s <sysfsDevice> The interface to kernel data\n"
- " structures dealing with this drive.\n"
- " If omitted, default is\n"
- " /sys/block/mmcblk0/device/\n";
+ auto getter = std::make_shared<estoraged::GetStorageConfiguration>(
+ dbusConnection,
+ [&io, &objectServer, &storageObjects](
+ const estoraged::ManagedStorageType& storageConfigurations) {
+ size_t numConfigObj = storageConfigurations.size();
+ if (numConfigObj > 1)
+ {
+ lg2::error(
+ "eStoraged can only manage 1 eMMC device; found {NUM}",
+ "NUM", numConfigObj, "REDFISH_MESSAGE_ID",
+ std::string("OpenBMC.0.1.CreateStorageObjectsFail"));
+ return;
+ }
+
+ for (const std::pair<sdbusplus::message::object_path,
+ estoraged::StorageData>& storage :
+ storageConfigurations)
+ {
+ const std::string& path = storage.first.str;
+
+ if (storageObjects.find(path) != storageObjects.end())
+ {
+ /*
+ * We've already created this object, or at least
+ * attempted to.
+ */
+ continue;
+ }
+
+ /* Get the properties from the config object. */
+ const estoraged::StorageData& data = storage.second;
+
+ /* Look for the device file. */
+ const std::filesystem::path blockDevDir{"/sys/block"};
+ std::filesystem::path deviceFile, sysfsDir;
+ std::string luksName;
+ bool found = estoraged::util::findDevice(
+ data, blockDevDir, deviceFile, sysfsDir, luksName);
+ if (!found)
+ {
+ lg2::error(
+ "Device not found for path {PATH}", "PATH", path,
+ "REDFISH_MESSAGE_ID",
+ std::string("OpenBMC.0.1.CreateStorageObjectsFail"));
+ /*
+ * Set a NULL pointer as a placeholder, so that we don't
+ * try and fail again later.
+ */
+ storageObjects[path] = nullptr;
+ continue;
+ }
+
+ uint64_t size =
+ estoraged::util::findSizeOfBlockDevice(deviceFile);
+
+ uint8_t lifeleft =
+ estoraged::util::findPredictedMediaLifeLeftPercent(
+ sysfsDir);
+ /* Create the storage object. */
+ storageObjects[path] = std::make_unique<estoraged::EStoraged>(
+ objectServer, deviceFile, luksName, size, lifeleft);
+ lg2::info("Created eStoraged object for path {PATH}", "PATH",
+ path, "REDFISH_MESSAGE_ID",
+ std::string("OpenBMC.0.1.CreateStorageObjects"));
+ }
+ });
+ getter->getConfiguration();
}
-int main(int argc, char** argv)
+int main(void)
{
- std::string physicalBlockDev = "/dev/mmcblk0";
- std::string sysfsDev = "/sys/block/mmcblk0/device";
- std::string containerBlockDev;
- int opt = 0;
- while ((opt = getopt(argc, argv, "b:c:s:")) != -1)
- {
- switch (opt)
- {
- case 'b':
- physicalBlockDev = optarg;
- break;
- case 'c':
- containerBlockDev = optarg;
- break;
- case 's':
- sysfsDev = optarg;
- break;
- default:
- usage(*argv);
- exit(EXIT_FAILURE);
- }
- }
try
{
- /* Get the filename of the device (without "/dev/"). */
- std::string deviceName =
- std::filesystem::path(physicalBlockDev).filename().string();
- /* If containerName arg wasn't provided, create one based on deviceName.
- */
- if (containerBlockDev.empty())
- {
- containerBlockDev = "luks-" + deviceName;
- }
-
// setup connection to dbus
boost::asio::io_context io;
auto conn = std::make_shared<sdbusplus::asio::connection>(io);
// request D-Bus server name.
- std::string busName = "xyz.openbmc_project.eStoraged";
- conn->request_name(busName.c_str());
- auto server = sdbusplus::asio::object_server(conn);
+ conn->request_name("xyz.openbmc_project.eStoraged");
+ sdbusplus::asio::object_server server(conn);
+ boost::container::flat_map<std::string,
+ std::unique_ptr<estoraged::EStoraged>>
+ storageObjects;
- estoraged::EStoraged esObject{
- server, physicalBlockDev, containerBlockDev,
- estoraged::util::findSizeOfBlockDevice(physicalBlockDev),
- estoraged::util::findPredictedMediaLifeLeftPercent(sysfsDev)};
+ boost::asio::post(io, [&]() {
+ createStorageObjects(io, server, storageObjects, conn);
+ });
+
+ /*
+ * Set up an event handler to process any new configuration objects
+ * that show up later.
+ */
+ boost::asio::deadline_timer filterTimer(io);
+ std::function<void(sdbusplus::message::message&)> eventHandler =
+ [&](sdbusplus::message::message& message) {
+ if (message.is_method_error())
+ {
+ lg2::error("eventHandler callback method error");
+ return;
+ }
+ /*
+ * This implicitly cancels the timer, if it's already pending.
+ * If there's a burst of events within a short period, we want
+ * to handle them all at once. So, we will wait this long for no
+ * more events to occur, before processing them.
+ */
+ filterTimer.expires_from_now(boost::posix_time::seconds(1));
+
+ filterTimer.async_wait(
+ [&](const boost::system::error_code& ec) {
+ if (ec == boost::asio::error::operation_aborted)
+ {
+ /* we were canceled */
+ return;
+ }
+ if (ec)
+ {
+ lg2::error("timer error");
+ return;
+ }
+ createStorageObjects(io, server, storageObjects, conn);
+ });
+ };
+
+ auto match = std::make_unique<sdbusplus::bus::match::match>(
+ static_cast<sdbusplus::bus::bus&>(*conn),
+ "type='signal',member='PropertiesChanged',path_namespace='" +
+ std::string("/xyz/openbmc_project/inventory") +
+ "',arg0namespace='" + estoraged::emmcConfigInterface + "'",
+ eventHandler);
+
lg2::info("Storage management service is running", "REDFISH_MESSAGE_ID",
std::string("OpenBMC.1.0.ServiceStarted"));
diff --git a/src/meson.build b/src/meson.build
index d12786f..e34838c 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -34,6 +34,7 @@
'eStoraged-lib',
'estoraged.cpp',
'util.cpp',
+ 'getConfig.cpp',
include_directories : eStoraged_headers,
implicit_include_directories: false,
dependencies: [libeStoraged_deps, libeStoragedErase_dep],
diff --git a/src/test/util_test.cpp b/src/test/util_test.cpp
index 8f53510..a4b796c 100644
--- a/src/test/util_test.cpp
+++ b/src/test/util_test.cpp
@@ -1,5 +1,11 @@
+#include "getConfig.hpp"
+
+#include <unistd.h>
+
+#include <boost/container/flat_map.hpp>
#include <util.hpp>
+#include <filesystem>
#include <fstream>
#include <gmock/gmock-matchers.h>
@@ -49,4 +55,136 @@
EXPECT_EQ(findPredictedMediaLifeLeftPercent(prefixName), 255);
}
+/* Test case where we successfully find the device file. */
+TEST(utilTest, findDevicePass)
+{
+ estoraged::StorageData data;
+
+ /* Set up the map of properties. */
+ data.emplace(std::string("Type"),
+ estoraged::BasicVariantType("EmmcDevice"));
+ data.emplace(std::string("Name"), estoraged::BasicVariantType("emmc"));
+
+ /* Create a dummy device file. */
+ const std::string testDevName("mmcblk0");
+ std::ofstream testFile;
+ testFile.open(testDevName,
+ std::ios::out | std::ios::binary | std::ios::trunc);
+ testFile.close();
+
+ /* Create another dummy file. */
+ const std::string testDummyFilename("abc");
+ testFile.open(testDummyFilename,
+ std::ios::out | std::ios::binary | std::ios::trunc);
+ testFile.close();
+
+ /* Look for the device file. */
+ std::filesystem::path deviceFile, sysfsDir;
+ std::string luksName;
+ EXPECT_TRUE(estoraged::util::findDevice(data, std::filesystem::path("./"),
+ deviceFile, sysfsDir, luksName));
+
+ /* Validate the results. */
+ EXPECT_EQ("/dev/mmcblk0", deviceFile.string());
+ EXPECT_EQ("./mmcblk0/device", sysfsDir.string());
+ EXPECT_EQ("luks-mmcblk0", luksName);
+
+ /* Delete the dummy files. */
+ EXPECT_EQ(0, unlink(testDevName.c_str()));
+ EXPECT_EQ(0, unlink(testDummyFilename.c_str()));
+}
+
+/* Test case where the "Type" property doesn't exist. */
+TEST(utilTest, findDeviceNoTypeFail)
+{
+ estoraged::StorageData data;
+
+ /* Set up the map of properties (with the "Type" property missing). */
+ data.emplace(std::string("Name"), estoraged::BasicVariantType("emmc"));
+
+ /* Create a dummy device file. */
+ const std::string testDevName("mmcblk0");
+ std::ofstream testFile;
+ testFile.open(testDevName,
+ std::ios::out | std::ios::binary | std::ios::trunc);
+ testFile.close();
+
+ /* Create another dummy file. */
+ const std::string testDummyFilename("abc");
+ testFile.open(testDummyFilename,
+ std::ios::out | std::ios::binary | std::ios::trunc);
+ testFile.close();
+
+ /* Look for the device file. */
+ std::filesystem::path deviceFile, sysfsDir;
+ std::string luksName;
+ EXPECT_FALSE(estoraged::util::findDevice(data, std::filesystem::path("./"),
+ deviceFile, sysfsDir, luksName));
+
+ /* Delete the dummy files. */
+ EXPECT_EQ(0, unlink(testDevName.c_str()));
+ EXPECT_EQ(0, unlink(testDummyFilename.c_str()));
+}
+
+/* Test case where the device type is not supported. */
+TEST(utilTest, findDeviceUnsupportedTypeFail)
+{
+ estoraged::StorageData data;
+
+ /* Set up the map of properties (with an unsupported "Type"). */
+ data.emplace(std::string("Type"), estoraged::BasicVariantType("NvmeDrive"));
+ data.emplace(std::string("Name"),
+ estoraged::BasicVariantType("some_drive"));
+
+ /* Create a dummy device file. */
+ const std::string testDevName("mmcblk0");
+ std::ofstream testFile;
+ testFile.open(testDevName,
+ std::ios::out | std::ios::binary | std::ios::trunc);
+ testFile.close();
+
+ /* Create another dummy file. */
+ const std::string testDummyFilename("abc");
+ testFile.open(testDummyFilename,
+ std::ios::out | std::ios::binary | std::ios::trunc);
+ testFile.close();
+
+ /* Look for the device file. */
+ std::filesystem::path deviceFile, sysfsDir;
+ std::string luksName;
+ EXPECT_FALSE(estoraged::util::findDevice(data, std::filesystem::path("./"),
+ deviceFile, sysfsDir, luksName));
+
+ /* Delete the dummy files. */
+ EXPECT_EQ(0, unlink(testDevName.c_str()));
+ EXPECT_EQ(0, unlink(testDummyFilename.c_str()));
+}
+
+/* Test case where we can't find the device file. */
+TEST(utilTest, findDeviceNotFoundFail)
+{
+ estoraged::StorageData data;
+
+ /* Set up the map of properties. */
+ data.emplace(std::string("Type"),
+ estoraged::BasicVariantType("EmmcDevice"));
+ data.emplace(std::string("Name"), estoraged::BasicVariantType("emmc"));
+
+ /* Create a dummy file. */
+ const std::string testDummyFilename("abc");
+ std::ofstream testFile;
+ testFile.open(testDummyFilename,
+ std::ios::out | std::ios::binary | std::ios::trunc);
+ testFile.close();
+
+ /* Look for the device file. */
+ std::filesystem::path deviceFile, sysfsDir;
+ std::string luksName;
+ EXPECT_FALSE(estoraged::util::findDevice(data, std::filesystem::path("./"),
+ deviceFile, sysfsDir, luksName));
+
+ /* Delete the dummy file. */
+ EXPECT_EQ(0, unlink(testDummyFilename.c_str()));
+}
+
} // namespace estoraged_test
diff --git a/src/util.cpp b/src/util.cpp
index acab3d8..4b366bb 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -1,5 +1,7 @@
#include "util.hpp"
+#include "getConfig.hpp"
+
#include <linux/fs.h>
#include <phosphor-logging/lg2.hpp>
@@ -8,6 +10,7 @@
#include <stdplus/handle/managed.hpp>
#include <xyz/openbmc_project/Common/error.hpp>
+#include <filesystem>
#include <fstream>
#include <iostream>
#include <string>
@@ -89,6 +92,58 @@
return static_cast<uint8_t>(11 - maxLifeUsed) * 10;
}
+bool findDevice(const StorageData& data, const std::filesystem::path& searchDir,
+ std::filesystem::path& deviceFile,
+ std::filesystem::path& sysfsDir, std::string& luksName)
+{
+ /* Check what type of storage device this is. */
+ estoraged::BasicVariantType typeVariant;
+ try
+ {
+ /* The EntityManager config should have this property set. */
+ typeVariant = data.at("Type");
+ }
+ catch (const boost::container::out_of_range& e)
+ {
+ lg2::error("Could not read device type", "REDFISH_MESSAGE_ID",
+ std::string("OpenBMC.0.1.FindDeviceFail"));
+ return false;
+ }
+
+ /*
+ * Currently, we only support eMMC, so report an error for any other device
+ * types.
+ */
+ std::string type = std::get<std::string>(typeVariant);
+ if (type.compare("EmmcDevice") != 0)
+ {
+ lg2::error("Unsupported device type {TYPE}", "TYPE", type,
+ "REDFISH_MESSAGE_ID",
+ std::string("OpenBMC.0.1.FindDeviceFail"));
+ return false;
+ }
+
+ /* Look for the eMMC in the specified searchDir directory. */
+ for (auto const& dirEntry : std::filesystem::directory_iterator{searchDir})
+ {
+ std::filesystem::path curDevice(dirEntry.path().filename());
+ if (curDevice.string().starts_with("mmcblk"))
+ {
+ sysfsDir = dirEntry.path();
+ sysfsDir /= "device";
+
+ deviceFile = "/dev";
+ deviceFile /= curDevice;
+
+ luksName = "luks-" + curDevice.string();
+ return true;
+ }
+ }
+
+ /* Device wasn't found. */
+ return false;
+}
+
} // namespace util
} // namespace estoraged