-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ccaa6fd
commit a3ece6c
Showing
4 changed files
with
152 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
#ifndef BLOCK_DEVICES_HPP | ||
#define BLOCK_DEVICES_HPP | ||
|
||
#include <cstdint> // for uint64_t | ||
#include <optional> // for optional | ||
#include <string> // for string | ||
#include <string_view> // for string_view | ||
#include <vector> // for vector | ||
|
||
namespace gucc::disk { | ||
|
||
/// @brief Represents a block device with its properties. | ||
struct BlockDevice { | ||
/// Device name (e.g., /dev/nvme0n1). | ||
std::string name; | ||
/// Device type (e.g., part, crypt, disk). | ||
std::string type; | ||
/// Filesystem type (e.g., ext4, btrfs). | ||
std::string fstype; | ||
/// Device UUID. | ||
std::string uuid; | ||
/// Device model. | ||
std::optional<std::string> model; | ||
/// Mount point. | ||
std::optional<std::string> mountpoint; | ||
/// Parent device name. | ||
std::optional<std::string> pkname; | ||
/// Filesystem label. | ||
std::optional<std::string> label; | ||
/// Partition UUID. | ||
std::optional<std::string> partuuid; | ||
/// Size of the device in bytes. | ||
std::optional<std::uint64_t> size; | ||
|
||
/// @brief Default constructor for BlockDevice. | ||
BlockDevice() = default; | ||
}; | ||
|
||
/// @brief Executes lsblk command and returns a list of block devices. | ||
/// @return An optional vector of BlockDevice objects, std::nullopt otherwise. | ||
auto list_block_devices() -> std::optional<std::vector<BlockDevice>>; | ||
|
||
/// @brief Finds a block device by its name. | ||
/// @param devices A vector of BlockDevice objects. | ||
/// @param device_name A string view containing the name of the device to find. | ||
/// @return An optional BlockDevice object if found, std::nullopt otherwise. | ||
auto find_device_by_name(const std::vector<BlockDevice>& devices, std::string_view device_name) -> std::optional<BlockDevice>; | ||
|
||
} // namespace gucc::disk | ||
|
||
#endif // BLOCK_DEVICES_HPP |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
#include "gucc/block_devices.hpp" | ||
#include "gucc/io_utils.hpp" | ||
|
||
#include <algorithm> // for find_if | ||
#include <ranges> // for ranges::* | ||
#include <utility> // for make_optional, move | ||
|
||
#include <rapidjson/document.h> | ||
#include <rapidjson/error/en.h> | ||
|
||
#include <spdlog/spdlog.h> | ||
|
||
using namespace std::string_view_literals; | ||
|
||
namespace { | ||
|
||
using BlockDevice = gucc::disk::BlockDevice; | ||
|
||
/// Constructs a BlockDevice from a RapidJSON object. | ||
auto get_blockdevice_from_json(const rapidjson::Value& doc) -> BlockDevice { | ||
auto device = BlockDevice{}; | ||
if (doc.HasMember("name") && doc["name"].IsString()) { | ||
device.name = doc["name"].GetString(); | ||
} | ||
if (doc.HasMember("type") && doc["type"].IsString()) { | ||
device.type = doc["type"].GetString(); | ||
} | ||
if (doc.HasMember("fstype") && doc["fstype"].IsString()) { | ||
device.fstype = doc["fstype"].GetString(); | ||
} | ||
if (doc.HasMember("uuid") && doc["uuid"].IsString()) { | ||
device.uuid = doc["uuid"].GetString(); | ||
} | ||
|
||
if (doc.HasMember("model") && doc["model"].IsString()) { | ||
device.model = doc["model"].GetString(); | ||
} | ||
if (doc.HasMember("mountpoint") && doc["mountpoint"].IsString()) { | ||
device.mountpoint = doc["mountpoint"].GetString(); | ||
} | ||
if (doc.HasMember("pkname") && doc["pkname"].IsString()) { | ||
device.pkname = doc["pkname"].GetString(); | ||
} | ||
if (doc.HasMember("label") && doc["label"].IsString()) { | ||
device.label = doc["label"].GetString(); | ||
} | ||
if (doc.HasMember("partuuid") && doc["partuuid"].IsString()) { | ||
device.partuuid = doc["partuuid"].GetString(); | ||
} | ||
if (doc.HasMember("size") && doc["size"].IsInt64()) { | ||
device.size = doc["size"].GetInt64(); | ||
} | ||
|
||
return device; | ||
} | ||
|
||
auto parse_lsblk_json(std::string_view json_output) -> std::vector<BlockDevice> { | ||
rapidjson::Document document; | ||
|
||
document.Parse(json_output.data(), json_output.size()); | ||
if (document.HasParseError()) { | ||
spdlog::error("Failed to parse lsblk output: {}", rapidjson::GetParseError_En(document.GetParseError())); | ||
return {}; | ||
} | ||
|
||
// Extract data from JSON | ||
std::vector<BlockDevice> block_devices{}; | ||
if (document.HasMember("blockdevices") && document["blockdevices"].IsArray()) { | ||
for (const auto& device_json : document["blockdevices"].GetArray()) { | ||
auto block_device = get_blockdevice_from_json(device_json); | ||
block_devices.emplace_back(std::move(block_device)); | ||
} | ||
} | ||
return block_devices; | ||
} | ||
|
||
} // namespace | ||
|
||
namespace gucc::disk { | ||
|
||
auto find_device_by_name(const std::vector<BlockDevice>& devices, std::string_view device_name) -> std::optional<BlockDevice> { | ||
auto it = std::ranges::find_if(devices, [device_name](auto&& dev) { | ||
return dev.name == device_name; | ||
}); | ||
if (it != std::ranges::end(devices)) { | ||
return std::make_optional<BlockDevice>(std::move(*it)); | ||
} | ||
return std::nullopt; | ||
} | ||
|
||
auto list_block_devices() -> std::optional<std::vector<BlockDevice>> { | ||
const auto& lsblk_output = utils::exec(R"(lsblk -f -o NAME,TYPE,FSTYPE,UUID,PARTUUID,PKNAME,LABEL,SIZE,MOUNTPOINT,MODEL -b -p -a -J -Q "type=='part' || type=='crypt' && fstype")"); | ||
if (lsblk_output.empty()) { | ||
return std::nullopt; | ||
} | ||
return std::make_optional<std::vector<BlockDevice>>(parse_lsblk_json(lsblk_output)); | ||
} | ||
|
||
} // namespace gucc::disk |