👷 extend zfs manual support

This commit is contained in:
Vladislav Nepogodin 2022-08-09 04:13:25 +04:00
parent a46be398a4
commit a25f3b00e7
No known key found for this signature in database
GPG Key ID: B62C3D10C54D5DA9
6 changed files with 199 additions and 15 deletions

2
.gitignore vendored
View File

@ -47,3 +47,5 @@ subprojects/packagecache
*.exe *.exe
*.out *.out
*.app *.app
compile_commands.json

View File

@ -65,6 +65,12 @@ CPMAddPackage(
GIT_TAG 3d6e6f56e5e1a3ec4befcc7695504ea23e1d52ab GIT_TAG 3d6e6f56e5e1a3ec4befcc7695504ea23e1d52ab
EXCLUDE_FROM_ALL YES EXCLUDE_FROM_ALL YES
) )
CPMAddPackage(
NAME ctre
GITHUB_REPOSITORY hanickadot/compile-time-regular-expressions
GIT_TAG v3.7
EXCLUDE_FROM_ALL YES
)
## ##
## CONFIGURATION ## CONFIGURATION
@ -115,7 +121,7 @@ if(COS_INSTALLER_BUILD_TESTS)
add_subdirectory(tests) add_subdirectory(tests)
endif() endif()
target_link_libraries(${PROJECT_NAME} PRIVATE project_warnings project_options spdlog::spdlog fmt::fmt ftxui::screen ftxui::dom ftxui::component cpr::cpr range-v3::range-v3) target_link_libraries(${PROJECT_NAME} PRIVATE project_warnings project_options spdlog::spdlog fmt::fmt ftxui::screen ftxui::dom ftxui::component cpr::cpr range-v3::range-v3 ctre::ctre)
option(ENABLE_UNITY "Enable Unity builds of projects" OFF) option(ENABLE_UNITY "Enable Unity builds of projects" OFF)
if(ENABLE_UNITY) if(ENABLE_UNITY)

View File

@ -136,6 +136,15 @@ std::vector<std::string> lvm_show_vg() noexcept {
return res; return res;
} }
// Creates a zfs volume
void zfs_create_zvol(const std::string_view& zsize, const std::string_view& zpath) noexcept {
#ifdef NDEVENV
utils::exec(fmt::format(FMT_COMPILE("zfs create -V {}M {} 2>>/tmp/cachyos-install.log"), zsize, zpath), true);
#else
spdlog::debug("zfs create -V {}M {}", zsize, zpath);
#endif
}
// Creates a zfs filesystem, the first parameter is the ZFS path and the second is the mount path // Creates a zfs filesystem, the first parameter is the ZFS path and the second is the mount path
void zfs_create_dataset(const std::string_view& zpath, const std::string_view& zmount) noexcept { void zfs_create_dataset(const std::string_view& zpath, const std::string_view& zmount) noexcept {
#ifdef NDEVENV #ifdef NDEVENV
@ -153,6 +162,15 @@ void zfs_destroy_dataset(const std::string_view& zdataset) noexcept {
#endif #endif
} }
// returns a list of imported zpools
std::string zfs_list_pools() noexcept {
#ifdef NDEVENV
return utils::exec("zfs list -H -o name 2>/dev/null | grep \"/\"");
#else
return "vol0\nvol1\n";
#endif
}
// returns a list of devices containing zfs members // returns a list of devices containing zfs members
std::string zfs_list_devs() noexcept { std::string zfs_list_devs() noexcept {
std::string list_of_devices{}; std::string list_of_devices{};
@ -177,10 +195,19 @@ std::string zfs_list_datasets(const std::string_view& type) noexcept {
return utils::exec("zfs list -H -o name 2>/dev/null | grep \"/\""); return utils::exec("zfs list -H -o name 2>/dev/null | grep \"/\"");
#else #else
spdlog::debug("type := {}", type);
return "zpcachyos"; return "zpcachyos";
#endif #endif
} }
void zfs_set_property(const std::string_view& property, const std::string_view& dataset) noexcept {
#ifdef NDEVENV
utils::exec(fmt::format(FMT_COMPILE("zfs set {} {} 2>>/tmp/cachyos-install.log"), property, dataset), true);
#else
spdlog::debug("zfs set {} {}", property, dataset);
#endif
}
// Other filesystems // Other filesystems
void select_filesystem(const std::string_view& file_sys) noexcept { void select_filesystem(const std::string_view& file_sys) noexcept {
auto* config_instance = Config::instance(); auto* config_instance = Config::instance();

View File

@ -18,10 +18,13 @@ void mount_existing_subvols(const disk_part& disk) noexcept;
std::vector<std::string> lvm_show_vg() noexcept; std::vector<std::string> lvm_show_vg() noexcept;
// ZFS filesystem // ZFS filesystem
void zfs_create_zvol(const std::string_view& zsize, const std::string_view& zpath) noexcept;
void zfs_create_dataset(const std::string_view& zpath, const std::string_view& zmount) noexcept; void zfs_create_dataset(const std::string_view& zpath, const std::string_view& zmount) noexcept;
void zfs_destroy_dataset(const std::string_view& zdataset) noexcept; void zfs_destroy_dataset(const std::string_view& zdataset) noexcept;
std::string zfs_list_pools() noexcept;
std::string zfs_list_devs() noexcept; std::string zfs_list_devs() noexcept;
std::string zfs_list_datasets(const std::string_view& type = "none") noexcept; std::string zfs_list_datasets(const std::string_view& type = "none") noexcept;
void zfs_set_property(const std::string_view& property, const std::string_view& dataset) noexcept;
// Other filesystems // Other filesystems
void select_filesystem(const std::string_view& fs) noexcept; void select_filesystem(const std::string_view& fs) noexcept;

View File

@ -14,6 +14,7 @@
#include <sys/mount.h> // for mount #include <sys/mount.h> // for mount
#include <fstream> // for ofstream #include <fstream> // for ofstream
#include <algorithm> // for copy #include <algorithm> // for copy
#include <ctre.hpp> // for ctre::match
#include <filesystem> // for exists, is_directory #include <filesystem> // for exists, is_directory
#include <string> // for basic_string #include <string> // for basic_string
#include <ftxui/component/component.hpp> // for Renderer, Button #include <ftxui/component/component.hpp> // for Renderer, Button
@ -1466,10 +1467,132 @@ bool zfs_create_zpool() noexcept {
return true; return true;
} }
void zfs_import_pool() noexcept { bool zfs_import_pool() noexcept {
const auto& zlist = utils::make_multiline(utils::exec("zpool import 2>/dev/null | grep \"^[[:space:]]*pool\" | awk -F : '{print $2}' | awk '{$1=$1};1'"));
if (zlist.empty()) {
// no available datasets
detail::infobox_widget("\nNo pools available\"\n");
std::this_thread::sleep_for(std::chrono::seconds(3));
return false;
}
auto* config_instance = Config::instance();
auto& config_data = config_instance->data();
std::string zfs_zpool_name{};
{
auto screen = ScreenInteractive::Fullscreen();
std::int32_t selected{};
bool success{};
auto ok_callback = [&] {
zfs_zpool_name = zlist[static_cast<std::size_t>(selected)];
success = true;
screen.ExitLoopClosure()();
};
static constexpr auto zfs_menu_body = "\nSelect a zpool from the list\n";
const auto& content_size = size(HEIGHT, LESS_THAN, 10) | size(WIDTH, GREATER_THAN, 40);
detail::menu_widget(zlist, ok_callback, &selected, &screen, zfs_menu_body, {size(HEIGHT, LESS_THAN, 18), content_size});
/* clang-format off */
if (!success) { return false; }
/* clang-format on */
}
#ifdef NDEVENV
const auto& mountpoint = std::get<std::string>(config_data["MOUNTPOINT"]);
utils::exec(fmt::format(FMT_COMPILE("zpool import -R {} {} 2>>/tmp/cachyos-install.log"), mountpoint, zfs_zpool_name), true);
#endif
config_data["ZFS"] = 1;
return true;
} }
void zfs_new_ds() noexcept { bool zfs_new_ds(const std::string_view& zmount = "") noexcept {
const auto& zlist = utils::make_multiline(utils::zfs_list_pools());
if (zlist.empty()) {
// no available datasets
detail::infobox_widget("\nNo pools available\"\n");
std::this_thread::sleep_for(std::chrono::seconds(3));
return false;
}
std::string zfs_zpool_name{};
{
auto screen = ScreenInteractive::Fullscreen();
std::int32_t selected{};
bool success{};
auto ok_callback = [&] {
zfs_zpool_name = zlist[static_cast<std::size_t>(selected)];
success = true;
screen.ExitLoopClosure()();
};
static constexpr auto zfs_menu_body = "\nSelect a zpool from the list\n";
const auto& content_size = size(HEIGHT, LESS_THAN, 10) | size(WIDTH, GREATER_THAN, 40);
detail::menu_widget(zlist, ok_callback, &selected, &screen, zfs_menu_body, {size(HEIGHT, LESS_THAN, 18), content_size});
/* clang-format off */
if (!success) { return false; }
/* clang-format on */
}
static constexpr auto zfs_dataset_body = "\nEnter a name and relative path for the dataset.\n \nFor example, if you want the dataset to be placed at zpool/data/zname, enter 'data/zname'\n";
static constexpr auto zfs_zpoolcvalidation1 = "\nzpool names must start with a letter and are limited to only alphanumeric characters and the special characters : . - _\n";
// We need to get a name for the dataset
std::string zfs_dataset_name{};
auto zfs_menu_text = zfs_dataset_body;
// Loop while zpool name is not valid.
while (true) {
if (!detail::inputbox_widget(zfs_dataset_name, zfs_menu_text, size(HEIGHT, GREATER_THAN, 1))) {
return false;
}
zfs_menu_text = zfs_dataset_body;
// validation
if (zfs_dataset_name.empty() || std::isdigit(zfs_dataset_name[0]) || (ranges::any_of(zfs_dataset_name, [](char ch) { return (!std::isalnum(ch)) && (ch != '/') && (ch != ':') && (ch != '.') && (ch != '-') && (ch != '_'); }))) {
zfs_menu_text = zfs_zpoolcvalidation1;
}
/* clang-format off */
if (zfs_menu_text == zfs_dataset_body) { break; }
/* clang-format on */
}
if (zmount == "legacy") {
utils::zfs_create_dataset(fmt::format(FMT_COMPILE("{}/{}"), zfs_zpool_name, zfs_dataset_name), zmount);
} else if (zmount == "zvol") {
static constexpr auto zvol_size_menu_body = "\nEnter the size of the zvol in megabytes(MB)\n";
static constexpr auto zvol_size_menu_validation = "\nYou must enter a number greater than 0\n";
// We need to get a name for the zvol
std::string zvol_size{};
zfs_menu_text = zvol_size_menu_body;
// Loop while zvol name is not valid.
while (true) {
if (!detail::inputbox_widget(zvol_size, zfs_menu_text, size(HEIGHT, GREATER_THAN, 1))) {
return false;
}
zfs_menu_text = zvol_size_menu_body;
// validation
if (zvol_size.empty() || ranges::any_of(zvol_size, [](char ch) { return !std::isdigit(ch); })) {
zfs_menu_text = zvol_size_menu_validation;
}
/* clang-format off */
if (zfs_menu_text == zvol_size_menu_body) { break; }
/* clang-format on */
}
utils::zfs_create_zvol(zvol_size, fmt::format(FMT_COMPILE("{}/{}"), zfs_zpool_name, zfs_dataset_name));
} else {
spdlog::error("HELLO! IMPLEMENT ME!");
return false;
}
return true;
} }
void zfs_set_property() noexcept { void zfs_set_property() noexcept {
@ -1491,7 +1614,7 @@ void zfs_set_property() noexcept {
success = true; success = true;
screen.ExitLoopClosure()(); screen.ExitLoopClosure()();
}; };
static constexpr auto zfs_menu_body = "\nEnter the property and value you would like to\nset using the format property=mountpoint\n \nFor example, you could enter:\ncompression=lz4\nor\nacltype=posixacl\n"; static constexpr auto zfs_menu_body = "\nSelect the dataset you would like to set a property on\n";
const auto& content_size = size(HEIGHT, LESS_THAN, 10) | size(WIDTH, GREATER_THAN, 40); const auto& content_size = size(HEIGHT, LESS_THAN, 10) | size(WIDTH, GREATER_THAN, 40);
detail::menu_widget(zlist, ok_callback, &selected, &screen, zfs_menu_body, {size(HEIGHT, LESS_THAN, 18), content_size}); detail::menu_widget(zlist, ok_callback, &selected, &screen, zfs_menu_body, {size(HEIGHT, LESS_THAN, 18), content_size});
/* clang-format off */ /* clang-format off */
@ -1499,13 +1622,32 @@ void zfs_set_property() noexcept {
/* clang-format on */ /* clang-format on */
} }
// const auto& content = fmt::format(FMT_COMPILE("\nPlease confirm that you want to irrevocably\ndelete all the data on '{}'\nand the data contained on all of it's children\n"), zdataset); static constexpr auto zfs_mountpoint_body = "\nEnter the property and value you would like to\nset using the format property=mountpoint\n \nFor example, you could enter:\ncompression=lz4\nor\nacltype=posixacl\n\n";
// const auto& do_destroy = detail::yesno_widget(content, size(HEIGHT, LESS_THAN, 20) | size(WIDTH, LESS_THAN, 75)); static constexpr auto zfs_property_invalid = "\nInput must be the format property=mountpoint\n";
/* clang-format off */
//if (!do_destroy) { return; }
/* clang-format on */
// utils::zfs_destroy_dataset(zdataset); // We need to get a valid property
std::string zfs_property_ent{};
auto zfs_menu_text = zfs_mountpoint_body;
// Loop while property is not valid.
while (true) {
if (!detail::inputbox_widget(zfs_property_ent, zfs_menu_text, size(HEIGHT, GREATER_THAN, 1))) {
return;
}
zfs_menu_text = zfs_mountpoint_body;
// validation
if (!ctre::match<"[a-zA-Z]*=[a-zA-Z0-9]*">(zfs_property_ent)) {
zfs_menu_text = zfs_property_invalid;
}
/* clang-format off */
if (zfs_menu_text == zfs_mountpoint_body) { break; }
/* clang-format on */
}
// Set the property
utils::zfs_set_property(zfs_property_ent, zdataset);
} }
void zfs_destroy_dataset() noexcept { void zfs_destroy_dataset() noexcept {
@ -1594,7 +1736,7 @@ void zfs_menu_manual() noexcept {
case 0: case 0:
tui::zfs_create_zpool(); tui::zfs_create_zpool();
break; break;
/*case 1: case 1:
tui::zfs_import_pool(); tui::zfs_import_pool();
break; break;
case 2: case 2:
@ -1605,7 +1747,7 @@ void zfs_menu_manual() noexcept {
break; break;
case 4: case 4:
tui::zfs_new_ds("zvol"); tui::zfs_new_ds("zvol");
break;*/ break;
case 5: case 5:
tui::zfs_set_property(); tui::zfs_set_property();
break; break;

View File

@ -448,11 +448,13 @@ void create_new_user(const std::string_view& user, const std::string_view& passw
if (fs::exists(sudoers_file)) { if (fs::exists(sudoers_file)) {
utils::exec(fmt::format(FMT_COMPILE("sed -i '/NOPASSWD/!s/# %sudo/%sudo/g' {}"), sudoers_file)); utils::exec(fmt::format(FMT_COMPILE("sed -i '/NOPASSWD/!s/# %sudo/%sudo/g' {}"), sudoers_file));
} }
#else
spdlog::debug("user := {}, password := {}", user, password);
#endif #endif
} }
// Set password for root user // Set password for root user
void set_root_password([[maybe_unused]] const std::string_view& password) noexcept { void set_root_password(const std::string_view& password) noexcept {
#ifdef NDEVENV #ifdef NDEVENV
auto* config_instance = Config::instance(); auto* config_instance = Config::instance();
auto& config_data = config_instance->data(); auto& config_data = config_instance->data();
@ -462,6 +464,8 @@ void set_root_password([[maybe_unused]] const std::string_view& password) noexce
utils::exec(fmt::format(FMT_COMPILE("echo -e \"{0}\n{0}\" > /tmp/.passwd"), password)); utils::exec(fmt::format(FMT_COMPILE("echo -e \"{0}\n{0}\" > /tmp/.passwd"), password));
utils::exec(fmt::format(FMT_COMPILE("arch-chroot {} passwd root < /tmp/.passwd &>/dev/null"), mountpoint)); utils::exec(fmt::format(FMT_COMPILE("arch-chroot {} passwd root < /tmp/.passwd &>/dev/null"), mountpoint));
fs::remove("/tmp/.passwd", err); fs::remove("/tmp/.passwd", err);
#else
spdlog::debug("root password := {}", password);
#endif #endif
} }
@ -1204,7 +1208,7 @@ void get_cryptroot() noexcept {
temp_out = utils::exec("lsblk -lno NAME,FSTYPE,TYPE | grep \" crypt$\" | grep -i \"LVM2_member\" | uniq | awk '{print \"/dev/mapper/\"$1}'"); temp_out = utils::exec("lsblk -lno NAME,FSTYPE,TYPE | grep \" crypt$\" | grep -i \"LVM2_member\" | uniq | awk '{print \"/dev/mapper/\"$1}'");
if (!temp_out.empty()) { if (!temp_out.empty()) {
const auto& cryptparts = utils::make_multiline(temp_out); const auto& cryptparts = utils::make_multiline(temp_out);
const auto& check_functor = [&]([[maybe_unused]] const auto cryptpart) { const auto& check_functor = [&]([[maybe_unused]] const auto& cryptpart) {
auto& luks_uuid = std::get<std::string>(config_data["LUKS_UUID"]); auto& luks_uuid = std::get<std::string>(config_data["LUKS_UUID"]);
luks_uuid = utils::exec("lsblk -ino NAME,FSTYPE,TYPE,MOUNTPOINT,UUID | tac | sed -r 's/^[^[:alnum:]]+//' | sed -n -e \"/\\/mnt /,/part/p\" | awk '/crypto_LUKS/ {print $4}'"); luks_uuid = utils::exec("lsblk -ino NAME,FSTYPE,TYPE,MOUNTPOINT,UUID | tac | sed -r 's/^[^[:alnum:]]+//' | sed -n -e \"/\\/mnt /,/part/p\" | awk '/crypto_LUKS/ {print $4}'");
config_data["LUKS_DEV"] = fmt::format(FMT_COMPILE("cryptdevice=UUID={}:{}"), luks_uuid, luks_name); config_data["LUKS_DEV"] = fmt::format(FMT_COMPILE("cryptdevice=UUID={}:{}"), luks_uuid, luks_name);
@ -1218,7 +1222,7 @@ void get_cryptroot() noexcept {
temp_out = utils::exec("lsblk -lno NAME,FSTYPE,TYPE,MOUNTPOINT | grep \"/mnt$\" | grep \"part\" | grep -i \"crypto_luks\" | uniq | awk '{print \"/dev/\"$1}'"); temp_out = utils::exec("lsblk -lno NAME,FSTYPE,TYPE,MOUNTPOINT | grep \"/mnt$\" | grep \"part\" | grep -i \"crypto_luks\" | uniq | awk '{print \"/dev/\"$1}'");
if (!temp_out.empty()) { if (!temp_out.empty()) {
const auto& cryptparts = utils::make_multiline(temp_out); const auto& cryptparts = utils::make_multiline(temp_out);
const auto& check_functor = [&](const auto cryptpart) { const auto& check_functor = [&](const auto& cryptpart) {
auto& luks_uuid = std::get<std::string>(config_data["LUKS_UUID"]); auto& luks_uuid = std::get<std::string>(config_data["LUKS_UUID"]);
luks_uuid = utils::exec(fmt::format(FMT_COMPILE("lsblk -lno UUID,TYPE,FSTYPE {} | grep \"part\" | grep -i \"crypto_luks\" | {}"), cryptpart, "awk '{print $1}'")); luks_uuid = utils::exec(fmt::format(FMT_COMPILE("lsblk -lno UUID,TYPE,FSTYPE {} | grep \"part\" | grep -i \"crypto_luks\" | {}"), cryptpart, "awk '{print $1}'"));
config_data["LUKS_DEV"] = fmt::format(FMT_COMPILE("cryptdevice=UUID={}:{}"), luks_uuid, luks_name); config_data["LUKS_DEV"] = fmt::format(FMT_COMPILE("cryptdevice=UUID={}:{}"), luks_uuid, luks_name);