mirror of
https://github.com/CachyOS/New-Cli-Installer.git
synced 2025-02-02 22:07:13 +08:00
👷 gucc: add crypttab generation based on provided partitions
This commit is contained in:
parent
f5f8886e00
commit
3facb2a41c
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -39,6 +39,7 @@ jobs:
|
||||
./gucc/tests/test-initcpio
|
||||
./gucc/tests/test-pacmanconf
|
||||
./gucc/tests/test-fstab_gen
|
||||
./gucc/tests/test-crypttab_gen
|
||||
shell: bash
|
||||
build-cmake_withoutdev:
|
||||
name: Build with CMake (DEVENV OFF)
|
||||
@ -84,6 +85,7 @@ jobs:
|
||||
./gucc/tests/test-initcpio
|
||||
./gucc/tests/test-pacmanconf
|
||||
./gucc/tests/test-fstab_gen
|
||||
./gucc/tests/test-crypttab_gen
|
||||
shell: bash
|
||||
build-meson_withoutdev:
|
||||
name: Build with Meson (DEVENV OFF)
|
||||
|
@ -23,6 +23,7 @@ add_library(${PROJECT_NAME} SHARED
|
||||
src/user.cpp include/gucc/user.hpp
|
||||
src/locale.cpp include/gucc/locale.hpp
|
||||
src/fstab.cpp include/gucc/fstab.hpp
|
||||
src/crypttab.cpp include/gucc/crypttab.hpp
|
||||
#src/chwd_profiles.cpp src/chwd_profiles.hpp
|
||||
#src/disk.cpp src/disk.hpp
|
||||
)
|
||||
|
20
gucc/include/gucc/crypttab.hpp
Normal file
20
gucc/include/gucc/crypttab.hpp
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef CRYPTTAB_HPP
|
||||
#define CRYPTTAB_HPP
|
||||
|
||||
#include "gucc/partition.hpp"
|
||||
|
||||
#include <string> // for string
|
||||
#include <string_view> // for string_view
|
||||
#include <vector> // for vector
|
||||
|
||||
namespace gucc::fs {
|
||||
|
||||
// Generate crypttab
|
||||
auto generate_crypttab(const std::vector<Partition>& partitions, std::string_view root_mountpoint, std::string_view crypttab_opts) noexcept -> bool;
|
||||
|
||||
// Generate crypttab into string
|
||||
auto generate_crypttab_content(const std::vector<Partition>& partitions, std::string_view crypttab_opts) noexcept -> std::string;
|
||||
|
||||
} // namespace gucc::fs
|
||||
|
||||
#endif // CRYPTTAB_HPP
|
@ -13,6 +13,7 @@ gucc_lib = library('gucc',
|
||||
'src/user.cpp',
|
||||
'src/locale.cpp',
|
||||
'src/fstab.cpp',
|
||||
'src/crypttab.cpp',
|
||||
],
|
||||
include_directories : [include_directories('include')],
|
||||
dependencies: deps
|
||||
|
118
gucc/src/crypttab.cpp
Normal file
118
gucc/src/crypttab.cpp
Normal file
@ -0,0 +1,118 @@
|
||||
#include "gucc/crypttab.hpp"
|
||||
#include "gucc/partition.hpp"
|
||||
|
||||
#include <algorithm> // for any_of, sort, unique_copy
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
#include <fmt/compile.h>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wold-style-cast"
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wuseless-cast"
|
||||
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||
#endif
|
||||
|
||||
#include <range/v3/algorithm/any_of.hpp>
|
||||
#include <range/v3/algorithm/sort.hpp>
|
||||
#include <range/v3/algorithm/unique_copy.hpp>
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
using namespace std::string_literals;
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
namespace {
|
||||
|
||||
// NOLINTNEXTLINE
|
||||
static constexpr auto CRYPTTAB_HEADER = R"(# Configuration for encrypted block devices
|
||||
# See crypttab(5) for details.
|
||||
|
||||
# NOTE: Do not list your root (/) partition here, it must be set up
|
||||
# beforehand by the initramfs (/etc/mkinitcpio.conf).
|
||||
|
||||
# <name> <device> <password> <options>
|
||||
)"sv;
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace gucc::fs {
|
||||
|
||||
auto gen_crypttab_entry(const Partition& partition, std::string_view crypttab_opts, bool is_root_encrypted, bool is_boot_encrypted) noexcept -> std::optional<std::string> {
|
||||
// skip if partition is not encypted
|
||||
if (!partition.luks_mapper_name || !partition.luks_uuid) {
|
||||
return std::nullopt;
|
||||
}
|
||||
// skip invalid usage
|
||||
if (partition.luks_mapper_name->empty() || partition.luks_uuid->empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto crypt_password = "/crypto_keyfile.bin"s;
|
||||
auto crypt_options = fmt::format(FMT_COMPILE(" {}"), crypttab_opts);
|
||||
|
||||
// 1. if root partition is not encrypted
|
||||
// 2. if root partition is encrypted, but boot partition is not encrypted
|
||||
if (!is_root_encrypted || (partition.mountpoint == "/"sv && !is_boot_encrypted)) {
|
||||
crypt_password = "none"s;
|
||||
crypt_options = ""s;
|
||||
}
|
||||
|
||||
const auto& device_str = fmt::format(FMT_COMPILE("UUID={}"), *partition.luks_uuid);
|
||||
return std::make_optional<std::string>(fmt::format(FMT_COMPILE("{:21} {:<45} {}{}\n"), *partition.luks_mapper_name, device_str, crypt_password, crypt_options));
|
||||
}
|
||||
|
||||
auto generate_crypttab_content(const std::vector<Partition>& partitions, std::string_view crypttab_opts) noexcept -> std::string {
|
||||
std::string crypttab_content{CRYPTTAB_HEADER};
|
||||
|
||||
// sort by mountpoint & device
|
||||
auto partitions_sorted{partitions};
|
||||
ranges::sort(partitions_sorted, {}, &Partition::mountpoint);
|
||||
ranges::sort(partitions_sorted, {}, &Partition::device);
|
||||
|
||||
// filter duplicates
|
||||
std::vector<Partition> partitions_filtered{};
|
||||
ranges::unique_copy(
|
||||
partitions_sorted, std::back_inserter(partitions_filtered),
|
||||
{},
|
||||
&Partition::device);
|
||||
|
||||
const bool is_root_encrypted = ranges::any_of(partitions, [](auto&& part) { return part.mountpoint == "/"sv && part.luks_mapper_name; });
|
||||
const bool is_boot_encrypted = ranges::any_of(partitions, [](auto&& part) { return part.mountpoint == "/bool"sv && part.luks_mapper_name; });
|
||||
|
||||
for (auto&& partition : partitions_filtered) {
|
||||
auto crypttab_entry = gen_crypttab_entry(partition, crypttab_opts, is_root_encrypted, is_boot_encrypted);
|
||||
if (!crypttab_entry) {
|
||||
continue;
|
||||
}
|
||||
crypttab_content += *crypttab_entry;
|
||||
}
|
||||
|
||||
return crypttab_content;
|
||||
}
|
||||
|
||||
auto generate_crypttab(const std::vector<Partition>& partitions, std::string_view root_mountpoint, std::string_view crypttab_opts) noexcept -> bool {
|
||||
const auto& crypttab_filepath = fmt::format(FMT_COMPILE("{}/etc/crypttab"), root_mountpoint);
|
||||
|
||||
std::ofstream crypttab_file{crypttab_filepath, std::ios::out | std::ios::trunc};
|
||||
if (!crypttab_file.is_open()) {
|
||||
spdlog::error("Failed to open crypttab for writing {}", crypttab_filepath);
|
||||
return false;
|
||||
}
|
||||
crypttab_file << fs::generate_crypttab_content(partitions, crypttab_opts);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace gucc::fs
|
@ -21,3 +21,11 @@ executable(
|
||||
link_with: [gucc_lib],
|
||||
include_directories: [include_directories('../include')],
|
||||
install: false)
|
||||
|
||||
executable(
|
||||
'test-crypttab_gen',
|
||||
files('unit-crypttab_gen.cpp'),
|
||||
dependencies: deps,
|
||||
link_with: [gucc_lib],
|
||||
include_directories: [include_directories('../include')],
|
||||
install: false)
|
||||
|
117
gucc/tests/unit-crypttab_gen.cpp
Normal file
117
gucc/tests/unit-crypttab_gen.cpp
Normal file
@ -0,0 +1,117 @@
|
||||
#include "gucc/crypttab.hpp"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#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 CRYPTTAB_EMPTY_TEST = R"(# Configuration for encrypted block devices
|
||||
# See crypttab(5) for details.
|
||||
|
||||
# NOTE: Do not list your root (/) partition here, it must be set up
|
||||
# beforehand by the initramfs (/etc/mkinitcpio.conf).
|
||||
|
||||
# <name> <device> <password> <options>
|
||||
)"sv;
|
||||
|
||||
static constexpr auto CRYPTTAB_UNENCR_BOOT_TEST = R"(# Configuration for encrypted block devices
|
||||
# See crypttab(5) for details.
|
||||
|
||||
# NOTE: Do not list your root (/) partition here, it must be set up
|
||||
# beforehand by the initramfs (/etc/mkinitcpio.conf).
|
||||
|
||||
# <name> <device> <password> <options>
|
||||
luks-6bdb3301-8efb-4b84-b0b7-4caeef26fd6f UUID=6bdb3301-8efb-4b84-b0b7-4caeef26fd6f none
|
||||
)"sv;
|
||||
|
||||
int main() {
|
||||
auto callback_sink = std::make_shared<spdlog::sinks::callback_sink_mt>([](const spdlog::details::log_msg& msg) {
|
||||
// noop
|
||||
});
|
||||
spdlog::set_default_logger(std::make_shared<spdlog::logger>("default", callback_sink));
|
||||
|
||||
const auto& uuid_str = "6bdb3301-8efb-4b84-b0b7-4caeef26fd6f"s;
|
||||
const auto& btrfs_mountopts = "defaults,noatime,compress=zstd,space_cache=v2,commit=120"s;
|
||||
const auto& xfs_mountopts = "defaults,lazytime,noatime,attr2,inode64,logbsize=256k,noquota"s;
|
||||
|
||||
// btrfs with subvolumes
|
||||
{
|
||||
const std::vector<gucc::fs::Partition> partitions{
|
||||
gucc::fs::Partition{.fstype = "btrfs"s, .mountpoint = "/"s, .uuid_str = uuid_str, .device = "/dev/nvme0n1p1"s, .mount_opts = btrfs_mountopts, .luks_mapper_name = {}, .subvolume = "/@"s},
|
||||
gucc::fs::Partition{.fstype = "btrfs"s, .mountpoint = "/home"s, .uuid_str = uuid_str, .device = "/dev/nvme0n1p1"s, .mount_opts = btrfs_mountopts, .luks_mapper_name = {}, .subvolume = "/@home"s},
|
||||
gucc::fs::Partition{.fstype = "btrfs"s, .mountpoint = "/var/cache"s, .uuid_str = uuid_str, .device = "/dev/nvme0n1p1"s, .mount_opts = btrfs_mountopts, .luks_mapper_name = {}, .subvolume = "/@cache"s},
|
||||
gucc::fs::Partition{.fstype = "fat32"s, .mountpoint = "/boot"s, .uuid_str = "8EFB-4B84"s, .device = "/dev/nvme0n1p2"s, .mount_opts = "defaults,noatime"s},
|
||||
};
|
||||
const auto& crypttab_content = gucc::fs::generate_crypttab_content(partitions, "luks"sv);
|
||||
assert(crypttab_content == CRYPTTAB_EMPTY_TEST);
|
||||
}
|
||||
// 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 = xfs_mountopts},
|
||||
gucc::fs::Partition{.fstype = "fat16"s, .mountpoint = "/boot"s, .uuid_str = "8EFB-4B84"s, .device = "/dev/nvme0n1p2"s, .mount_opts = "defaults,noatime"s},
|
||||
};
|
||||
const auto& crypttab_content = gucc::fs::generate_crypttab_content(partitions, "luks"sv);
|
||||
assert(crypttab_content == CRYPTTAB_EMPTY_TEST);
|
||||
}
|
||||
// luks 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 = xfs_mountopts, .luks_mapper_name = "luks-6bdb3301-8efb-4b84-b0b7-4caeef26fd6f"s, .luks_uuid = "6bdb3301-8efb-4b84-b0b7-4caeef26fd6f"s},
|
||||
gucc::fs::Partition{.fstype = "linuxswap"s, .mountpoint = ""s, .uuid_str = ""s, .device = "/dev/nvme0n1p3"s, .mount_opts = "defaults,noatime"s},
|
||||
gucc::fs::Partition{.fstype = "vfat"s, .mountpoint = "/boot"s, .uuid_str = "8EFB-4B84"s, .device = "/dev/nvme0n1p2"s, .mount_opts = "defaults,noatime"s},
|
||||
};
|
||||
const auto& crypttab_content = gucc::fs::generate_crypttab_content(partitions, "luks"sv);
|
||||
assert(crypttab_content == CRYPTTAB_UNENCR_BOOT_TEST);
|
||||
}
|
||||
// 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, .mount_opts = "defaults,noatime"s},
|
||||
};
|
||||
const auto& crypttab_content = gucc::fs::generate_crypttab_content(partitions, "luks"sv);
|
||||
assert(crypttab_content == CRYPTTAB_EMPTY_TEST);
|
||||
}
|
||||
// luks btrfs with subvolumes
|
||||
{
|
||||
const std::vector<gucc::fs::Partition> partitions{
|
||||
gucc::fs::Partition{.fstype = "btrfs"s, .mountpoint = "/"s, .device = "/dev/nvme0n1p1"s, .mount_opts = btrfs_mountopts, .luks_mapper_name = "luks-6bdb3301-8efb-4b84-b0b7-4caeef26fd6f"s, .luks_uuid = "6bdb3301-8efb-4b84-b0b7-4caeef26fd6f"s, .subvolume = "/@"s},
|
||||
gucc::fs::Partition{.fstype = "btrfs"s, .mountpoint = "/home"s, .device = "/dev/nvme0n1p1"s, .mount_opts = btrfs_mountopts, .luks_mapper_name = "luks-6bdb3301-8efb-4b84-b0b7-4caeef26fd6f"s, .luks_uuid = "6bdb3301-8efb-4b84-b0b7-4caeef26fd6f"s, .subvolume = "/@home"s},
|
||||
gucc::fs::Partition{.fstype = "btrfs"s, .mountpoint = "/var/cache"s, .device = "/dev/nvme0n1p1"s, .mount_opts = btrfs_mountopts, .luks_mapper_name = "luks-6bdb3301-8efb-4b84-b0b7-4caeef26fd6f"s, .luks_uuid = "6bdb3301-8efb-4b84-b0b7-4caeef26fd6f"s, .subvolume = "/@cache"s},
|
||||
gucc::fs::Partition{.fstype = "fat32"s, .mountpoint = "/boot"s, .uuid_str = "8EFB-4B84"s, .device = "/dev/nvme0n1p2"s, .mount_opts = "defaults,noatime"s},
|
||||
};
|
||||
const auto& crypttab_content = gucc::fs::generate_crypttab_content(partitions, "luks"sv);
|
||||
assert(crypttab_content == CRYPTTAB_UNENCR_BOOT_TEST);
|
||||
}
|
||||
// luks btrfs with subvolumes {shuffled}
|
||||
{
|
||||
const std::vector<gucc::fs::Partition> partitions{
|
||||
gucc::fs::Partition{.fstype = "btrfs"s, .mountpoint = "/home"s, .device = "/dev/nvme0n1p1"s, .mount_opts = btrfs_mountopts, .luks_mapper_name = "luks-6bdb3301-8efb-4b84-b0b7-4caeef26fd6f"s, .luks_uuid = "6bdb3301-8efb-4b84-b0b7-4caeef26fd6f"s, .subvolume = "/@home"s},
|
||||
gucc::fs::Partition{.fstype = "btrfs"s, .mountpoint = "/"s, .device = "/dev/nvme0n1p1"s, .mount_opts = btrfs_mountopts, .luks_mapper_name = "luks-6bdb3301-8efb-4b84-b0b7-4caeef26fd6f"s, .luks_uuid = "6bdb3301-8efb-4b84-b0b7-4caeef26fd6f"s, .subvolume = "/@"s},
|
||||
gucc::fs::Partition{.fstype = "fat32"s, .mountpoint = "/boot"s, .uuid_str = "8EFB-4B84"s, .device = "/dev/nvme0n1p2"s, .mount_opts = "defaults,noatime"s},
|
||||
gucc::fs::Partition{.fstype = "btrfs"s, .mountpoint = "/var/cache"s, .device = "/dev/nvme0n1p1"s, .mount_opts = btrfs_mountopts, .luks_mapper_name = "luks-6bdb3301-8efb-4b84-b0b7-4caeef26fd6f"s, .luks_uuid = "6bdb3301-8efb-4b84-b0b7-4caeef26fd6f"s, .subvolume = "/@cache"s},
|
||||
};
|
||||
const auto& crypttab_content = gucc::fs::generate_crypttab_content(partitions, "luks"sv);
|
||||
assert(crypttab_content == CRYPTTAB_UNENCR_BOOT_TEST);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
|
||||
{'claimed': False, 'device': '', 'features': {}, 'fs': 'unknown', 'fsName': 'unknown', 'mountPoint': '', 'partattrs': 0, 'partlabel': '', 'parttype': '', 'partuuid': '', 'uuid': ''} None
|
||||
{'claimed': True, 'device': '/dev/sda1', 'features': {}, 'fs': 'fat32', 'fsName': 'fat32', 'mountPoint': '/boot', 'partattrs': 0, 'partlabel': '', 'parttype': '', 'partuuid': '57F0553F-8C12-46DC-BDA7-868728368EEF', 'uuid': '86F8-2CD4'} None
|
||||
{'claimed': True, 'device': '/dev/sda2', 'features': {}, 'fs': 'btrfs', 'fsName': 'luks2', 'luksMapperName': 'luks-6363636e-bc94-46fa-8ede-86cb57295161', 'luksPassphrase': '123456789', 'luksUuid': '6363636e-bc94-46fa-8ede-86cb57295161', 'mountPoint': '/', 'partattrs': 0, 'partlabel': 'root', 'parttype': '', 'partuuid': '2B6DA8D5-9A95-4917-B736-8F204E393488', 'uuid': '6363636e-bc94-46fa-8ede-86cb57295161'} {'name': 'luks-6363636e-bc94-46fa-8ede-86cb57295161', 'device': 'UUID=6363636e-bc94-46fa-8ede-86cb57295161', 'password': 'none', 'options': ''}
|
||||
|
||||
|
||||
*/
|
||||
}
|
Loading…
Reference in New Issue
Block a user