-
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.
👷 gucc: add function to partition device using sfdisk command
- Loading branch information
1 parent
3600729
commit a6d4bbe
Showing
6 changed files
with
221 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
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,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 |
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,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 |
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,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 | ||
} |