Skip to content

Commit

Permalink
🧹 move btrfs subvolumes creation into gucc
Browse files Browse the repository at this point in the history
  • Loading branch information
vnepogodin committed Jun 27, 2024
1 parent d4f67e1 commit 9e011fc
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 19 deletions.
1 change: 1 addition & 0 deletions gucc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ add_library(${PROJECT_NAME} SHARED
src/initcpio.cpp include/gucc/initcpio.hpp
src/luks.cpp include/gucc/luks.hpp
src/zfs.cpp include/gucc/zfs.hpp
src/btrfs.cpp include/gucc/btrfs.hpp
#src/chwd_profiles.cpp src/chwd_profiles.hpp
#src/disk.cpp src/disk.hpp
)
Expand Down
22 changes: 22 additions & 0 deletions gucc/include/gucc/btrfs.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#ifndef BTRFS_HPP
#define BTRFS_HPP

#include <string_view> // for string_view
#include <vector> // for vector

namespace gucc::fs {

struct BtrfsSubvolume final {
std::string_view subvolume;
std::string_view mountpoint;
};

// Creates btrfs subvolume
auto btrfs_create_subvol(std::string_view subvolume, std::string_view root_mountpoint) noexcept -> bool;

// Creates btrfs subvolumes and mounts them
auto btrfs_create_subvols(const std::vector<BtrfsSubvolume>& subvols, std::string_view device, std::string_view root_mountpoint, std::string_view mount_opts) noexcept -> bool;

} // namespace gucc::fs

#endif // BTRFS_HPP
1 change: 1 addition & 0 deletions gucc/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ gucc_lib = library('gucc',
'src/initcpio.cpp',
'src/luks.cpp',
'src/zfs.cpp',
'src/btrfs.cpp',
],
include_directories : [include_directories('include')],
dependencies: deps
Expand Down
79 changes: 79 additions & 0 deletions gucc/src/btrfs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#include "gucc/btrfs.hpp"
#include "gucc/io_utils.hpp"

#include <filesystem>

#include <fmt/compile.h>
#include <fmt/format.h>

#include <spdlog/spdlog.h>

namespace fs = std::filesystem;

namespace {

// same behaviour as os.path.dirname from python
constexpr auto get_dirname(std::string_view full_path) noexcept -> std::string_view {
if (full_path == "/") {
return full_path;
}
auto pos = full_path.find_last_of('/');
if (pos == std::string_view::npos) {
return {};
}
return full_path.substr(0, pos);
}

} // namespace

namespace gucc::fs {

auto btrfs_create_subvol(std::string_view subvolume, std::string_view root_mountpoint) noexcept -> bool {

Check failure on line 31 in gucc/src/btrfs.cpp

View workflow job for this annotation

GitHub Actions / cpp-linter

/gucc/src/btrfs.cpp:31:26 [bugprone-easily-swappable-parameters

2 adjacent parameters of 'btrfs_create_subvol' of similar type ('std::string_view') are easily swapped by mistake
const auto& subvol_dirs_path = fmt::format(FMT_COMPILE("{}{}"), root_mountpoint, get_dirname(subvolume));
std::error_code err{};
::fs::create_directories(subvol_dirs_path, err);
if (err) {
spdlog::error("Failed to create directories for btrfs subvolume {}: {}", subvol_dirs_path, err.message());
return false;
}
auto cmd = fmt::format(FMT_COMPILE("btrfs subvolume create {}{} 2>>/tmp/cachyos-install.log"), root_mountpoint, subvolume);
return utils::exec(cmd, true) == "0";
}

auto btrfs_create_subvols(const std::vector<BtrfsSubvolume>& subvols, std::string_view device, std::string_view root_mountpoint, std::string_view mount_opts) noexcept -> bool {

Check failure on line 43 in gucc/src/btrfs.cpp

View workflow job for this annotation

GitHub Actions / cpp-linter

/gucc/src/btrfs.cpp:43:71 [bugprone-easily-swappable-parameters

3 adjacent parameters of 'btrfs_create_subvols' of similar type ('std::string_view') are easily swapped by mistake
// Create subvolumes
for (const auto& subvol : subvols) {
if (subvol.subvolume.empty()) {
continue;
}
if (!fs::btrfs_create_subvol(subvol.subvolume, root_mountpoint)) {
spdlog::error("Failed to create btrfs subvolume {} on root mountpoint {}", subvol.subvolume, root_mountpoint);
return false;
}
}
// TODO(vnepogodin): handle exit code
utils::exec(fmt::format(FMT_COMPILE("umount -v {} &>>/tmp/cachyos-install.log"), root_mountpoint));

// Mount subvolumes
for (const auto& subvol : subvols) {
auto mount_option = fmt::format(FMT_COMPILE("subvol={},{}"), subvol.subvolume, mount_opts);
if (subvol.subvolume.empty()) {
mount_option = mount_opts;
}

const auto& subvolume_mountpoint = fmt::format(FMT_COMPILE("{}{}"), root_mountpoint, subvol.subvolume);

// TODO(vnepogodin): refactor create dir and mount into own function
std::error_code err{};
::fs::create_directories(subvolume_mountpoint, err);
if (err) {
spdlog::error("Failed to create directories for btrfs subvols mountpoint {}: {}", subvolume_mountpoint, err.message());
return false;
}
// TODO(vnepogodin): handle exit code
utils::exec(fmt::format(FMT_COMPILE("mount -o {} \"{}\" {}"), mount_option, device, subvolume_mountpoint));
}
return true;
}

} // namespace gucc::fs
36 changes: 17 additions & 19 deletions src/disk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "widgets.hpp"

// import gucc
#include "gucc/btrfs.hpp"
#include "gucc/io_utils.hpp"
#include "gucc/string_utils.hpp"
#include "gucc/zfs.hpp"
Expand All @@ -29,26 +30,28 @@ void btrfs_create_subvols([[maybe_unused]] const disk_part& disk, const std::str
/* clang-format on */

#ifdef NDEVENV
const auto root_mountpoint = "/mnt"sv;

// save mount options and name of the root partition
gucc::utils::exec(R"(mount | grep 'on /mnt ' | grep -Po '(?<=\().*(?=\))' > /tmp/.root_mount_options)"sv);
// gucc::utils::exec("lsblk -lno MOUNTPOINT,NAME | awk '/^\\/mnt / {print $2}' > /tmp/.root_partition"sv);

if (mode == "manual"sv) {
// Create subvolumes manually
std::string subvols{"@ @home @cache"};
std::string subvols{"/@ /@home /@cache"};
static constexpr auto subvols_body = "\nInput names of the subvolumes separated by spaces.\nThe first one will be used for mounting /.\n"sv;
if (!tui::detail::inputbox_widget(subvols, subvols_body, size(ftxui::HEIGHT, ftxui::GREATER_THAN, 4))) {
return;
}
const auto& saved_path = fs::current_path();
fs::current_path("/mnt");
fs::current_path(root_mountpoint);
auto subvol_list = gucc::utils::make_multiline(subvols, false, ' ');
for (const auto& subvol : subvol_list) {
gucc::utils::exec(fmt::format(FMT_COMPILE("btrfs subvolume create {} 2>>/tmp/cachyos-install.log"), subvol), true);
}
fs::current_path(saved_path);
// Mount subvolumes
umount("/mnt");
umount(root_mountpoint.data());
// Mount the first subvolume as /
gucc::utils::exec(fmt::format(FMT_COMPILE("mount -o {},subvol=\"{}\" \"{}\" /mnt"), disk.mount_opts, subvol_list[0], disk.root));
// Remove the first subvolume from the subvolume list
Expand All @@ -62,35 +65,30 @@ void btrfs_create_subvols([[maybe_unused]] const disk_part& disk, const std::str
return;
}

const auto& mountp_formatted = fmt::format(FMT_COMPILE("/mnt{}"), mountp);
const auto& mountp_formatted = fmt::format(FMT_COMPILE("{}{}"), root_mountpoint, mountp);
fs::create_directories(mountp_formatted);
gucc::utils::exec(fmt::format(FMT_COMPILE("mount -o {},subvol=\"{}\" \"{}\" \"{}\""), disk.mount_opts, subvol, disk.root, mountp_formatted));
}
return;
}
if (!ignore_note) {
static constexpr auto content = "\nThis creates subvolumes:\n@ for /,\n@home for /home,\n@cache for /var/cache.\n"sv;
static constexpr auto content = "\nThis creates subvolumes:\n/@ for /,\n/@home for /home,\n/@cache for /var/cache.\n"sv;
const auto& do_create = tui::detail::yesno_widget(content, size(ftxui::HEIGHT, ftxui::LESS_THAN, 15) | size(ftxui::WIDTH, ftxui::LESS_THAN, 75));
/* clang-format off */
if (!do_create) { return; }
/* clang-format on */
}

// Create subvolumes automatically
const auto& saved_path = fs::current_path();
fs::current_path("/mnt");
gucc::utils::exec("btrfs subvolume create @ 2>>/tmp/cachyos-install.log"sv, true);
gucc::utils::exec("btrfs subvolume create @home 2>>/tmp/cachyos-install.log"sv, true);
gucc::utils::exec("btrfs subvolume create @cache 2>>/tmp/cachyos-install.log"sv, true);
// gucc::utils::exec("btrfs subvolume create @snapshots 2>>/tmp/cachyos-install.log"sv, true);
fs::current_path(saved_path);
// Mount subvolumes
umount("/mnt");
gucc::utils::exec(fmt::format(FMT_COMPILE("mount -o {},subvol=@ \"{}\" /mnt"), disk.mount_opts, disk.root));
fs::create_directories("/mnt/home");
fs::create_directories("/mnt/var/cache");
gucc::utils::exec(fmt::format(FMT_COMPILE("mount -o {},subvol=@home \"{}\" /mnt/home"), disk.mount_opts, disk.root));
gucc::utils::exec(fmt::format(FMT_COMPILE("mount -o {},subvol=@cache \"{}\" /mnt/var/cache"), disk.mount_opts, disk.root));
const std::vector<gucc::fs::BtrfsSubvolume> subvolumes{
gucc::fs::BtrfsSubvolume{.subvolume = "/@"sv, .mountpoint = "/"sv},
gucc::fs::BtrfsSubvolume{.subvolume = "/@home"sv, .mountpoint = "/home"sv},
gucc::fs::BtrfsSubvolume{.subvolume = "/@cache"sv, .mountpoint = "/var/cache"sv},
// gucc::fs::BtrfsSubvolume{.subvolume = "/@snapshots"sv, .mountpoint = "/.snapshots"sv},
};
if (!gucc::fs::btrfs_create_subvols(subvolumes, disk.root, root_mountpoint, disk.mount_opts)) {
spdlog::error("Failed to create subvolumes automatically");
}
#else
spdlog::info("Do we ignore note? {}", ignore_note);
#endif
Expand Down

0 comments on commit 9e011fc

Please sign in to comment.