👷 disk: refactor handling of btrfs information

cache partition information into partition scheme
This commit is contained in:
Vladislav Nepogodin 2024-07-27 02:20:29 +04:00
parent 756d87610f
commit 1ca45defa7
No known key found for this signature in database
GPG Key ID: B62C3D10C54D5DA9
4 changed files with 99 additions and 37 deletions

View File

@ -10,7 +10,10 @@
#include "gucc/string_utils.hpp"
#include "gucc/zfs.hpp"
#include <filesystem> // for exists, is_directory
#include <algorithm> // for find_if
#include <filesystem> // for exists, is_directory
#include <ranges> // for ranges::*
#include <ftxui/component/component.hpp> // for Renderer, Button
#include <ftxui/component/component_options.hpp> // for ButtonOption
#include <ftxui/component/screen_interactive.hpp> // for Component, ScreenI...
@ -24,13 +27,40 @@ using namespace std::string_view_literals;
using namespace std::string_literals;
namespace fs = std::filesystem;
namespace {
constexpr auto is_root_btrfs_part(const gucc::fs::Partition& part) noexcept -> bool {
return (part.mountpoint == "/"sv) && (part.fstype == "btrfs"sv);
}
// TODO(vnepogodin): refactor that out of this file
constexpr auto find_root_btrfs_part(auto&& parts) noexcept {
return std::ranges::find_if(parts,
[](auto&& part) { return is_root_btrfs_part(part); });
}
} // namespace
namespace utils {
void btrfs_create_subvols([[maybe_unused]] const disk_part& disk, const std::string_view& mode, bool ignore_note) noexcept {
void btrfs_create_subvols(std::vector<gucc::fs::Partition>& partitions, const std::string_view& mode, bool ignore_note) noexcept {
/* clang-format off */
if (mode.empty()) { return; }
/* clang-format on */
const std::vector<gucc::fs::BtrfsSubvolume> default_subvolumes{
gucc::fs::BtrfsSubvolume{.subvolume = "/@"s, .mountpoint = "/"s},
gucc::fs::BtrfsSubvolume{.subvolume = "/@home"s, .mountpoint = "/home"s},
gucc::fs::BtrfsSubvolume{.subvolume = "/@cache"s, .mountpoint = "/var/cache"s},
// gucc::fs::BtrfsSubvolume{.subvolume = "/@snapshots"sv, .mountpoint = "/.snapshots"sv},
};
auto root_part = find_root_btrfs_part(partitions);
if (root_part == std::ranges::end(partitions)) {
spdlog::error("btrfs_create_subvols: unable to find btrfs root part");
return;
}
#ifdef NDEVENV
const auto root_mountpoint = "/mnt"sv;
@ -68,9 +98,12 @@ void btrfs_create_subvols([[maybe_unused]] const disk_part& disk, const std::str
}
// Create subvolumes
if (!gucc::fs::btrfs_create_subvols(subvolumes, disk.root, root_mountpoint, disk.mount_opts)) {
if (!gucc::fs::btrfs_create_subvols(subvolumes, root_part->device, root_mountpoint, root_part->mount_opts)) {
spdlog::error("Failed to create subvolumes");
}
if (!gucc::fs::btrfs_append_subvolumes(partitions, subvolumes)) {
spdlog::error("Failed to append btrfs subvolumes into partition scheme");
}
return;
}
if (!ignore_note) {
@ -82,35 +115,35 @@ void btrfs_create_subvols([[maybe_unused]] const disk_part& disk, const std::str
}
// Create subvolumes automatically
const std::vector<gucc::fs::BtrfsSubvolume> subvolumes{
gucc::fs::BtrfsSubvolume{.subvolume = "/@"s, .mountpoint = "/"s},
gucc::fs::BtrfsSubvolume{.subvolume = "/@home"s, .mountpoint = "/home"s},
gucc::fs::BtrfsSubvolume{.subvolume = "/@cache"s, .mountpoint = "/var/cache"s},
// gucc::fs::BtrfsSubvolume{.subvolume = "/@snapshots"sv, .mountpoint = "/.snapshots"sv},
};
if (!gucc::fs::btrfs_create_subvols(subvolumes, disk.root, root_mountpoint, disk.mount_opts)) {
if (!gucc::fs::btrfs_create_subvols(default_subvolumes, root_part->device, root_mountpoint, root_part->mount_opts)) {
spdlog::error("Failed to create subvolumes automatically");
}
gucc::fs::Partition partition{};
partition.fstype = "btrfs"s;
partition.mountpoint = subvolumes[0].mountpoint;
// partition.uuid_str = "";
partition.device = disk.root;
partition.mount_opts = disk.mount_opts;
partition.subvolume = std::make_optional<std::string>(subvolumes[0].subvolume);
spdlog::debug("partition: fs='{}';mountpoint='{}';uuid_str='{}';device='{}';mount_opts='{}';subvolume='{}'",
partition.fstype, partition.mountpoint, partition.uuid_str, partition.device, partition.mount_opts, *partition.subvolume);
if (!gucc::fs::btrfs_append_subvolumes(partitions, default_subvolumes)) {
spdlog::error("Failed to append btrfs subvolumes into partition scheme");
}
#else
spdlog::info("Do we ignore note? {}", ignore_note);
#endif
// need to find it again, due to modifying the parts
root_part = find_root_btrfs_part(partitions);
spdlog::debug("root partition: fs='{}';mountpoint='{}';uuid_str='{}';device='{}';mount_opts='{}';subvolume='{}'",
root_part->fstype, root_part->mountpoint, root_part->uuid_str, root_part->device, root_part->mount_opts, *root_part->subvolume);
}
void mount_existing_subvols(const disk_part& disk) noexcept {
void mount_existing_subvols(std::vector<gucc::fs::Partition>& partitions) noexcept {
auto root_part = find_root_btrfs_part(partitions);
if (root_part == std::ranges::end(partitions)) {
spdlog::error("mount_existing_subvols: unable to find btrfs root part");
return;
}
// Set mount options
const auto& format_name = gucc::utils::exec(fmt::format(FMT_COMPILE("echo {} | rev | cut -d/ -f1 | rev"), disk.part));
const auto& format_device = gucc::utils::exec(fmt::format(FMT_COMPILE("lsblk -i | tac | sed -r 's/^[^[:alnum:]]+//' | sed -n -e '/{}/,/disk/p' | {}"), format_name, "awk '/disk/ {print $1}'"sv));
const auto& rotational_queue = (gucc::utils::exec(fmt::format(FMT_COMPILE("cat /sys/block/{}/queue/rotational"), format_device)) == "1"sv);
const auto& part_dev_name = gucc::utils::exec(fmt::format(FMT_COMPILE("echo {} | rev | cut -d/ -f1 | rev"), root_part->device));
const auto& device_name = gucc::utils::exec(fmt::format(FMT_COMPILE("lsblk -i | tac | sed -r 's/^[^[:alnum:]]+//' | sed -n -e '/{}/,/disk/p' | {}"), part_dev_name, "awk '/disk/ {print $1}'"sv));
const auto& rotational_queue = (gucc::utils::exec(fmt::format(FMT_COMPILE("cat /sys/block/{}/queue/rotational"), device_name)) == "1"sv);
std::string fs_opts{};
if (rotational_queue) {
@ -144,9 +177,19 @@ void mount_existing_subvols(const disk_part& disk) noexcept {
// TODO(vnepogodin): add confirmation for selected mountpoint for particular subvolume
// Mount subvolumes
if (!gucc::fs::btrfs_mount_subvols(subvolumes, disk.root, root_mountpoint, fs_opts)) {
if (!gucc::fs::btrfs_mount_subvols(subvolumes, root_part->device, root_mountpoint, fs_opts)) {
spdlog::error("Failed to mount btrfs subvolumes");
}
if (!gucc::fs::btrfs_append_subvolumes(partitions, subvolumes)) {
spdlog::error("Failed to append btrfs subvolumes into partition scheme");
}
// need to find it again, due to modifying the parts
root_part = find_root_btrfs_part(partitions);
spdlog::debug("root partition: fs='{}';mountpoint='{}';uuid_str='{}';device='{}';mount_opts='{}';subvolume='{}'",
root_part->fstype, root_part->mountpoint, root_part->uuid_str, root_part->device, root_part->mount_opts, *root_part->subvolume);
#endif
}

View File

@ -1,20 +1,16 @@
#ifndef DISK_HPP
#define DISK_HPP
#include "gucc/partition.hpp"
#include <string> // for string
#include <string_view> // for string_view
#include <vector> // for vector
namespace utils {
struct disk_part {
const std::string_view root{};
const std::string_view part{};
const std::string_view mount_opts{};
};
void btrfs_create_subvols(const disk_part& disk, const std::string_view& mode, bool ignore_note = false) noexcept;
void mount_existing_subvols(const disk_part& disk) noexcept;
void btrfs_create_subvols(std::vector<gucc::fs::Partition>& partitions, const std::string_view& mode, bool ignore_note = false) noexcept;
void mount_existing_subvols(std::vector<gucc::fs::Partition>& partitions) noexcept;
auto lvm_show_vg() noexcept -> std::vector<std::string>;
// ZFS filesystem

View File

@ -156,6 +156,8 @@ auto make_partitions_prepared(std::string_view bootloader, std::string_view root
if (ready_parts.empty()) { spdlog::error("Invalid use! ready parts empty."); return false; }
/* clang-format on */
std::vector<gucc::fs::Partition> partitions{};
std::string root_part{};
for (auto&& ready_part : ready_parts) {
auto part_info = gucc::utils::make_multiline(ready_part, false, '\t');
@ -193,11 +195,14 @@ auto make_partitions_prepared(std::string_view bootloader, std::string_view root
const auto& subvolumes = fmt::format(FMT_COMPILE("btrfs subvolume list \"{}\" 2>/dev/null"), part_mountpoint);
const auto& subvolumes_count = gucc::utils::exec(fmt::format(FMT_COMPILE("{} | wc -l"), subvolumes));
const auto& lines_count = utils::to_int(subvolumes_count);
auto part_struct = gucc::fs::Partition{.fstype = part_fs, .mountpoint = part_mountpoint, .device = root_part, .mount_opts = std::string{mount_opts_info}};
partitions.emplace_back(std::move(part_struct));
if (lines_count > 1) {
// Pre-existing subvolumes and user wants to mount them
utils::mount_existing_subvols({root_part, root_part});
utils::mount_existing_subvols(partitions);
} else {
utils::btrfs_create_subvols({.root = part_name, .mount_opts = mount_opts_info}, "automatic"sv, true);
utils::btrfs_create_subvols(partitions, "automatic"sv, true);
}
}
continue;

View File

@ -14,6 +14,7 @@
#include "gucc/io_utils.hpp"
#include "gucc/locale.hpp"
#include "gucc/mount_partitions.hpp"
#include "gucc/partition.hpp"
#include "gucc/string_utils.hpp"
#include "gucc/zfs.hpp"
@ -42,6 +43,7 @@ namespace fs = std::filesystem;
#include "follow_process_log.hpp"
#endif
using namespace std::string_literals;
using namespace std::string_view_literals;
namespace tui {
@ -108,7 +110,12 @@ void btrfs_subvolumes() noexcept {
const auto& mount_opts_info = std::get<std::string>(config_data["MOUNT_OPTS"]);
const auto& root_part = std::get<std::string>(config_data["ROOT_PART"]);
utils::btrfs_create_subvols({.root = root_part, .mount_opts = mount_opts_info}, btrfsvols_mode);
std::vector<gucc::fs::Partition> partitions{
gucc::fs::Partition{.fstype = "btrfs"s, .mountpoint = "/"s, .device = root_part, .mount_opts = mount_opts_info},
};
utils::btrfs_create_subvols(partitions, btrfsvols_mode);
}
// Function will not allow incorrect UUID type for installed system.
@ -1710,6 +1717,8 @@ void mount_partitions() noexcept {
utils::delete_partition_in_list(part);
}*/
std::vector<gucc::fs::Partition> partitions{};
// check to see if we already have a zfs root mounted
const auto& mountpoint_info = std::get<std::string>(config_data["MOUNTPOINT"]);
if (gucc::fs::utils::get_mountpoint_fs(mountpoint_info) == "zfs"sv) {
@ -1752,11 +1761,20 @@ void mount_partitions() noexcept {
// utils::delete_partition_in_list(std::get<std::string>(config_data["ROOT_PART"]));
// TODO(vnepogodin): parse luks information
const auto& mount_opts_info = std::get<std::string>(config_data["MOUNT_OPTS"]);
const auto& part_fs = gucc::fs::utils::get_mountpoint_fs(mountpoint_info);
auto root_part_struct = gucc::fs::Partition{.fstype = part_fs, .mountpoint = "/"s, .device = root_part, .mount_opts = mount_opts_info};
// insert root partition
partitions.emplace_back(std::move(root_part_struct));
// Extra check if root is on LUKS or lvm
// get_cryptroot
// echo "$LUKS_DEV" > /tmp/.luks_dev
// If the root partition is btrfs, offer to create subvolumes
if (gucc::fs::utils::get_mountpoint_fs(mountpoint_info) == "btrfs"sv) {
if (part_fs == "btrfs"sv) {
// Check if there are subvolumes already on the btrfs partition
const auto& subvolumes = fmt::format(FMT_COMPILE("btrfs subvolume list '{}' 2>/dev/null"), mountpoint_info);
const auto& subvolumes_count = gucc::utils::exec(fmt::format(FMT_COMPILE("{} | wc -l"), subvolumes));
@ -1766,7 +1784,7 @@ void mount_partitions() noexcept {
const auto& existing_subvolumes = detail::yesno_widget(fmt::format(FMT_COMPILE("\nFound subvolumes {}\n \nWould you like to mount them?\n "), subvolumes_formated), size(HEIGHT, LESS_THAN, 15) | size(WIDTH, LESS_THAN, 75));
// Pre-existing subvolumes and user wants to mount them
/* clang-format off */
if (existing_subvolumes) { utils::mount_existing_subvols({root_part, part}); }
if (existing_subvolumes) { utils::mount_existing_subvols(partitions); }
/* clang-format on */
} else {
// No subvolumes present. Make some new ones