mirror of
https://github.com/CachyOS/New-Cli-Installer.git
synced 2025-01-23 14:32:22 +08:00
👷 gucc: add function to partition device using sfdisk command
This commit is contained in:
parent
36007299a6
commit
a6d4bbe5c3
@ -24,6 +24,7 @@ add_library(${PROJECT_NAME} #SHARED
|
|||||||
src/pacmanconf_repo.cpp include/gucc/pacmanconf_repo.hpp
|
src/pacmanconf_repo.cpp include/gucc/pacmanconf_repo.hpp
|
||||||
src/initcpio.cpp include/gucc/initcpio.hpp
|
src/initcpio.cpp include/gucc/initcpio.hpp
|
||||||
src/block_devices.cpp include/gucc/block_devices.hpp
|
src/block_devices.cpp include/gucc/block_devices.hpp
|
||||||
|
src/partitioning.cpp include/gucc/partitioning.hpp
|
||||||
src/luks.cpp include/gucc/luks.hpp
|
src/luks.cpp include/gucc/luks.hpp
|
||||||
src/zfs.cpp include/gucc/zfs.hpp
|
src/zfs.cpp include/gucc/zfs.hpp
|
||||||
src/btrfs.cpp include/gucc/btrfs.hpp
|
src/btrfs.cpp include/gucc/btrfs.hpp
|
||||||
|
@ -12,6 +12,10 @@ struct Partition final {
|
|||||||
std::string uuid_str{};
|
std::string uuid_str{};
|
||||||
std::string device{};
|
std::string device{};
|
||||||
|
|
||||||
|
// partition size,
|
||||||
|
// e.g 2G, 512G
|
||||||
|
std::string size{};
|
||||||
|
|
||||||
// mount points that will be written in fstab,
|
// mount points that will be written in fstab,
|
||||||
// excluding subvol={subvol name}
|
// excluding subvol={subvol name}
|
||||||
// if device is ssd, mount options for ssd should be appended
|
// if device is ssd, mount options for ssd should be appended
|
||||||
|
19
gucc/include/gucc/partitioning.hpp
Normal file
19
gucc/include/gucc/partitioning.hpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef PARTITIONING_HPP
|
||||||
|
#define PARTITIONING_HPP
|
||||||
|
|
||||||
|
#include "gucc/partition.hpp"
|
||||||
|
|
||||||
|
#include <string> // for string
|
||||||
|
#include <string_view> // for string_view
|
||||||
|
#include <vector> // for vector
|
||||||
|
|
||||||
|
namespace gucc::disk {
|
||||||
|
|
||||||
|
// Generates sfdisk commands from Partition scheme
|
||||||
|
auto gen_sfdisk_command(const std::vector<fs::Partition>& partitions, bool is_efi) noexcept -> std::string;
|
||||||
|
|
||||||
|
// Runs disk partitioning using sfdisk command on device
|
||||||
|
auto run_sfdisk_part(std::string_view commands, std::string_view device) noexcept -> bool;
|
||||||
|
} // namespace gucc::disk
|
||||||
|
|
||||||
|
#endif // PARTITIONING_HPP
|
@ -8,6 +8,7 @@ gucc_lib = library('gucc',
|
|||||||
'src/pacmanconf_repo.cpp',
|
'src/pacmanconf_repo.cpp',
|
||||||
'src/initcpio.cpp',
|
'src/initcpio.cpp',
|
||||||
'src/block_devices.cpp',
|
'src/block_devices.cpp',
|
||||||
|
'src/partitioning.cpp',
|
||||||
'src/luks.cpp',
|
'src/luks.cpp',
|
||||||
'src/zfs.cpp',
|
'src/zfs.cpp',
|
||||||
'src/btrfs.cpp',
|
'src/btrfs.cpp',
|
||||||
|
104
gucc/src/partitioning.cpp
Normal file
104
gucc/src/partitioning.cpp
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
#include "gucc/partitioning.hpp"
|
||||||
|
#include "gucc/io_utils.hpp"
|
||||||
|
|
||||||
|
#include <algorithm> // for sort, unique_copy
|
||||||
|
#include <ranges> // for ranges::*
|
||||||
|
#include <string_view> // for string_view
|
||||||
|
|
||||||
|
#include <fmt/compile.h>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
using namespace std::string_view_literals;
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto convert_fsname(std::string_view fsname) noexcept -> std::string_view {
|
||||||
|
if (fsname == "fat16"sv || fsname == "fat32"sv) {
|
||||||
|
return "vfat"sv;
|
||||||
|
} else if (fsname == "linuxswap"sv) {
|
||||||
|
return "swap"sv;
|
||||||
|
}
|
||||||
|
return fsname;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr auto get_part_type_alias(std::string_view fsname) noexcept -> std::string_view {
|
||||||
|
if (fsname == "vfat"sv) {
|
||||||
|
return "U"sv;
|
||||||
|
} else if (fsname == "swap"sv) {
|
||||||
|
return "S"sv;
|
||||||
|
}
|
||||||
|
return "L"sv;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace gucc::disk {
|
||||||
|
|
||||||
|
auto gen_sfdisk_command(const std::vector<fs::Partition>& partitions, bool is_efi) noexcept -> std::string {
|
||||||
|
// sfdisk does not create partition table without partitions by default. The lines with partitions are expected in the script by default.
|
||||||
|
std::string sfdisk_commands{"label: gpt\n"s};
|
||||||
|
if (!is_efi) {
|
||||||
|
sfdisk_commands = "label: msdos\n"s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort by mountpoint & device
|
||||||
|
auto partitions_sorted{partitions};
|
||||||
|
std::ranges::sort(partitions_sorted, {}, &fs::Partition::mountpoint);
|
||||||
|
std::ranges::sort(partitions_sorted, {}, &fs::Partition::device);
|
||||||
|
|
||||||
|
// filter duplicates
|
||||||
|
std::vector<fs::Partition> partitions_filtered{};
|
||||||
|
std::ranges::unique_copy(
|
||||||
|
partitions_sorted, std::back_inserter(partitions_filtered),
|
||||||
|
{},
|
||||||
|
&fs::Partition::device);
|
||||||
|
|
||||||
|
for (const auto& part : partitions_filtered) {
|
||||||
|
const auto& fsname = convert_fsname(part.fstype);
|
||||||
|
const auto& fs_alias = get_part_type_alias(fsname);
|
||||||
|
|
||||||
|
// L - alias 'linux'. Linux
|
||||||
|
// U - alias 'uefi'. EFI System partition
|
||||||
|
sfdisk_commands += fmt::format(FMT_COMPILE(",type={}"), fs_alias);
|
||||||
|
|
||||||
|
// The field size= support '+' and '-' in the same way as Unnamed-fields
|
||||||
|
// format. The default value of size indicates "as much as possible";
|
||||||
|
// i.e., until the next partition or end-of-device. A numerical argument is
|
||||||
|
// by default interpreted as a number of sectors, however if the size
|
||||||
|
// is followed by one of the multiplicative suffixes (KiB, MiB, GiB,
|
||||||
|
// TiB, PiB, EiB, ZiB and YiB) then the number is interpreted
|
||||||
|
// as the size of the partition in bytes and it is then aligned
|
||||||
|
// according to the device I/O limits. A '+' can be used instead of a
|
||||||
|
// number to enlarge the partition as much as possible. Note '+' is
|
||||||
|
// equivalent to the default behaviour for a new partition; existing
|
||||||
|
// partitions will be resized as required.
|
||||||
|
if (!part.size.empty()) {
|
||||||
|
sfdisk_commands += fmt::format(FMT_COMPILE(",size={}"), part.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set boot flag
|
||||||
|
if (fsname == "vfat"sv) {
|
||||||
|
// bootable is specified as [*|-], with as default not-bootable.
|
||||||
|
// The value of this field is irrelevant for Linux
|
||||||
|
// - when Linux runs it has been booted already
|
||||||
|
// - but it might play a role for certain boot loaders and for other operating systems.
|
||||||
|
sfdisk_commands += ",bootable"s;
|
||||||
|
}
|
||||||
|
sfdisk_commands += "\n"s;
|
||||||
|
}
|
||||||
|
return sfdisk_commands;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto run_sfdisk_part(std::string_view commands, std::string_view device) noexcept -> bool {
|
||||||
|
const auto& sfdisk_cmd = fmt::format(FMT_COMPILE("echo -e '{}' | sfdisk '{}' 2>>/tmp/cachyos-install.log &>/dev/null"), commands, device);
|
||||||
|
if (!utils::exec_checked(sfdisk_cmd)) {
|
||||||
|
spdlog::error("Failed to run partitioning with sfdisk: {}", sfdisk_cmd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace gucc::disk
|
92
gucc/tests/unit-partitioning_gen.cpp
Normal file
92
gucc/tests/unit-partitioning_gen.cpp
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#include "doctest_compatibility.h"
|
||||||
|
|
||||||
|
#include "gucc/partitioning.hpp"
|
||||||
|
#include "gucc/logger.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <spdlog/sinks/callback_sink.h>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
using namespace std::string_literals;
|
||||||
|
using namespace std::string_view_literals;
|
||||||
|
|
||||||
|
static constexpr auto PART_TEST = R"(label: gpt
|
||||||
|
,type=L
|
||||||
|
,type=U,size=2G,bootable
|
||||||
|
)"sv;
|
||||||
|
|
||||||
|
static constexpr auto PART_BIOS_TEST = R"(label: msdos
|
||||||
|
,type=L
|
||||||
|
,type=L,size=2G
|
||||||
|
)"sv;
|
||||||
|
|
||||||
|
static constexpr auto PART_SWAP_TEST = R"(label: gpt
|
||||||
|
,type=L
|
||||||
|
,type=U,size=2G,bootable
|
||||||
|
,type=S,size=16G
|
||||||
|
)"sv;
|
||||||
|
|
||||||
|
TEST_CASE("partitioning gen test")
|
||||||
|
{
|
||||||
|
auto callback_sink = std::make_shared<spdlog::sinks::callback_sink_mt>([](const spdlog::details::log_msg&) {
|
||||||
|
// noop
|
||||||
|
});
|
||||||
|
auto logger = std::make_shared<spdlog::logger>("default", callback_sink);
|
||||||
|
spdlog::set_default_logger(logger);
|
||||||
|
gucc::logger::set_logger(logger);
|
||||||
|
|
||||||
|
SECTION("btrfs with subvolumes")
|
||||||
|
{
|
||||||
|
const std::vector<gucc::fs::Partition> partitions{
|
||||||
|
gucc::fs::Partition{.fstype = "btrfs"s, .mountpoint = "/"s, .uuid_str = "6bdb3301-8efb-4b84-b0b7-4caeef26fd6f"s, .device = "/dev/nvme0n1p1"s, .mount_opts = "defaults,noatime,compress=zstd,space_cache=v2,commit=120"s, .subvolume = "/@"s},
|
||||||
|
gucc::fs::Partition{.fstype = "btrfs"s, .mountpoint = "/home"s, .uuid_str = "6bdb3301-8efb-4b84-b0b7-4caeef26fd6f"s, .device = "/dev/nvme0n1p1"s, .mount_opts = "defaults,noatime,compress=zstd,space_cache=v2,commit=120"s, .subvolume = "/@home"s},
|
||||||
|
gucc::fs::Partition{.fstype = "btrfs"s, .mountpoint = "/var/cache"s, .uuid_str = "6bdb3301-8efb-4b84-b0b7-4caeef26fd6f"s, .device = "/dev/nvme0n1p1"s, .mount_opts = "defaults,noatime,compress=zstd,space_cache=v2,commit=120"s, .subvolume = "/@cache"s},
|
||||||
|
gucc::fs::Partition{.fstype = "fat32"s, .mountpoint = "/boot"s, .uuid_str = "8EFB-4B84"s, .device = "/dev/nvme0n1p2"s, .size = "2G", .mount_opts = "defaults,noatime"s},
|
||||||
|
};
|
||||||
|
const auto& sfdisk_content = gucc::disk::gen_sfdisk_command(partitions, true);
|
||||||
|
REQUIRE_EQ(sfdisk_content, PART_TEST);
|
||||||
|
}
|
||||||
|
SECTION("basic xfs")
|
||||||
|
{
|
||||||
|
const std::vector<gucc::fs::Partition> partitions{
|
||||||
|
gucc::fs::Partition{.fstype = "xfs"s, .mountpoint = "/"s, .uuid_str = "6bdb3301-8efb-4b84-b0b7-4caeef26fd6f"s, .device = "/dev/nvme0n1p1"s, .mount_opts = "defaults,lazytime,noatime,attr2,inode64,logbsize=256k,noquota"s},
|
||||||
|
gucc::fs::Partition{.fstype = "fat16"s, .mountpoint = "/boot"s, .uuid_str = "8EFB-4B84"s, .device = "/dev/nvme0n1p2"s, .size = "2G", .mount_opts = "defaults,noatime"s},
|
||||||
|
};
|
||||||
|
const auto& sfdisk_content = gucc::disk::gen_sfdisk_command(partitions, true);
|
||||||
|
REQUIRE_EQ(sfdisk_content, PART_TEST);
|
||||||
|
}
|
||||||
|
SECTION("basic xfs bios")
|
||||||
|
{
|
||||||
|
const std::vector<gucc::fs::Partition> partitions{
|
||||||
|
gucc::fs::Partition{.fstype = "xfs"s, .mountpoint = "/"s, .uuid_str = "6bdb3301-8efb-4b84-b0b7-4caeef26fd6f"s, .device = "/dev/nvme0n1p1"s, .mount_opts = "defaults,lazytime,noatime,attr2,inode64,logbsize=256k,noquota"s},
|
||||||
|
gucc::fs::Partition{.fstype = "ext4"s, .mountpoint = "/boot"s, .uuid_str = "8EFB-4B84"s, .device = "/dev/nvme0n1p2"s, .size = "2G", .mount_opts = "defaults,noatime"s},
|
||||||
|
};
|
||||||
|
const auto& sfdisk_content = gucc::disk::gen_sfdisk_command(partitions, false);
|
||||||
|
REQUIRE_EQ(sfdisk_content, PART_BIOS_TEST);
|
||||||
|
}
|
||||||
|
SECTION("swap xfs")
|
||||||
|
{
|
||||||
|
const std::vector<gucc::fs::Partition> partitions{
|
||||||
|
gucc::fs::Partition{.fstype = "xfs"s, .mountpoint = "/"s, .uuid_str = "6bdb3301-8efb-4b84-b0b7-4caeef26fd6f"s, .device = "/dev/nvme0n1p1"s, .mount_opts = "defaults,lazytime,noatime,attr2,inode64,logbsize=256k,noquota"s, .luks_mapper_name = "luks_device"s, .luks_uuid = "00e1b836-81b6-433f-83ca-0fd373e3cd50"s},
|
||||||
|
gucc::fs::Partition{.fstype = "linuxswap"s, .mountpoint = ""s, .uuid_str = ""s, .device = "/dev/nvme0n1p3"s, .size = "16G", .mount_opts = "defaults,noatime"s},
|
||||||
|
gucc::fs::Partition{.fstype = "vfat"s, .mountpoint = "/boot"s, .uuid_str = "8EFB-4B84"s, .device = "/dev/nvme0n1p2"s, .size = "2G", .mount_opts = "defaults,noatime"s},
|
||||||
|
};
|
||||||
|
const auto& sfdisk_content = gucc::disk::gen_sfdisk_command(partitions, true);
|
||||||
|
REQUIRE_EQ(sfdisk_content, PART_SWAP_TEST);
|
||||||
|
}
|
||||||
|
SECTION("zfs")
|
||||||
|
{
|
||||||
|
const std::vector<gucc::fs::Partition> partitions{
|
||||||
|
gucc::fs::Partition{.fstype = "zfs"s, .mountpoint = "/"s, .uuid_str = "6bdb3301-8efb-4b84-b0b7-4caeef26fd6f"s, .device = "/dev/nvme0n1p1"s, .mount_opts = "defaults,noatime,compress=zstd,space_cache=v2,commit=120"s},
|
||||||
|
gucc::fs::Partition{.fstype = "zfs"s, .mountpoint = "/home"s, .uuid_str = "6bdb3301-8efb-4b84-b0b7-4caeef26fd6f"s, .device = "/dev/nvme0n1p1"s, .mount_opts = "defaults,noatime,compress=zstd,space_cache=v2,commit=120"s},
|
||||||
|
gucc::fs::Partition{.fstype = "zfs"s, .mountpoint = "/var/cache"s, .uuid_str = "6bdb3301-8efb-4b84-b0b7-4caeef26fd6f"s, .device = "/dev/nvme0n1p1"s, .mount_opts = "defaults,noatime,compress=zstd,space_cache=v2,commit=120"s},
|
||||||
|
gucc::fs::Partition{.fstype = "vfat"s, .mountpoint = "/boot"s, .uuid_str = "8EFB-4B84"s, .device = "/dev/nvme0n1p2"s, .size = "2G", .mount_opts = "defaults,noatime"s},
|
||||||
|
};
|
||||||
|
const auto& sfdisk_content = gucc::disk::gen_sfdisk_command(partitions, true);
|
||||||
|
REQUIRE_EQ(sfdisk_content, PART_TEST);
|
||||||
|
}
|
||||||
|
// TODO(vnepogodin): add tests for raid and lvm
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user