diff --git a/gucc/CMakeLists.txt b/gucc/CMakeLists.txt index 344fdfd..ce2d0b0 100644 --- a/gucc/CMakeLists.txt +++ b/gucc/CMakeLists.txt @@ -35,6 +35,7 @@ add_library(${PROJECT_NAME} #SHARED src/autologin.cpp include/gucc/autologin.hpp src/mtab.cpp include/gucc/mtab.hpp src/umount_partitions.cpp include/gucc/umount_partitions.hpp + src/mount_partitions.cpp include/gucc/mount_partitions.hpp src/hwclock.cpp include/gucc/hwclock.hpp src/package_profiles.cpp include/gucc/package_profiles.hpp src/fetch_file.cpp include/gucc/fetch_file.hpp diff --git a/gucc/include/gucc/mount_partitions.hpp b/gucc/include/gucc/mount_partitions.hpp new file mode 100644 index 0000000..2edbbe9 --- /dev/null +++ b/gucc/include/gucc/mount_partitions.hpp @@ -0,0 +1,18 @@ +#ifndef MOUNT_PARTITIONS_HPP +#define MOUNT_PARTITIONS_HPP + +#include // for int32_t + +#include // for string +#include // for string_view + +namespace gucc::mount { + +// Mount partition +auto mount_partition(std::string_view partition, std::string_view mount_dir, std::string_view mount_opts) noexcept -> bool; +// Query partition +auto query_partition(std::string_view partition, std::int32_t& is_luks, std::int32_t& is_lvm, std::string& luks_name, std::string& luks_dev, std::string& luks_uuid) noexcept -> bool; + +} // namespace gucc::mount + +#endif // MOUNT_PARTITIONS_HPP diff --git a/gucc/meson.build b/gucc/meson.build index 7421064..21923ad 100644 --- a/gucc/meson.build +++ b/gucc/meson.build @@ -19,6 +19,7 @@ gucc_lib = library('gucc', 'src/autologin.cpp', 'src/mtab.cpp', 'src/umount_partitions.cpp', + 'src/mount_partitions.cpp', 'src/hwclock.cpp', 'src/package_profiles.cpp', 'src/logger.cpp', diff --git a/gucc/src/mount_partitions.cpp b/gucc/src/mount_partitions.cpp new file mode 100644 index 0000000..b5980d5 --- /dev/null +++ b/gucc/src/mount_partitions.cpp @@ -0,0 +1,96 @@ +#include "gucc/mount_partitions.hpp" +#include "gucc/io_utils.hpp" +#include "gucc/string_utils.hpp" + +#include +#include + +using namespace std::string_view_literals; + +namespace gucc::mount { + +auto mount_partition(std::string_view partition, std::string_view mount_dir, std::string_view mount_opts) noexcept -> bool { + if (!mount_opts.empty()) { + return utils::exec(fmt::format(FMT_COMPILE("mount -o {} {} {}"), mount_opts, partition, mount_dir)) == "0"; + } + return utils::exec(fmt::format(FMT_COMPILE("mount {} {}"), partition, mount_dir)) == "0"; +} + +auto query_partition(std::string_view partition, std::int32_t& is_luks, std::int32_t& is_lvm, std::string& luks_name, std::string& luks_dev, std::string& luks_uuid) noexcept -> bool { + // Identify if mounted partition is type "crypt" (LUKS on LVM, or LUKS alone) + if (utils::exec(fmt::format(FMT_COMPILE("lsblk -lno TYPE {} | grep -q 'crypt'"), partition), true) == "0") { + // cryptname for bootloader configuration either way + is_luks = true; + luks_name = utils::exec(fmt::format(FMT_COMPILE("echo {} | sed \"s~^/dev/mapper/~~g\""), partition)); + + const auto& check_cryptparts = [&](auto&& cryptparts, const auto& functor) { + for (const auto& cryptpart : cryptparts) { + if (utils::exec(fmt::format(FMT_COMPILE("lsblk -lno NAME {} | grep -q '{}'"), cryptpart, luks_name)) == "0") { + functor(cryptpart); + return true; + } + } + return false; + }; + + // Check if LUKS on LVM (parent = lvm /dev/mapper/...) + auto check_functor = [&](auto&& cryptpart) { + luks_dev = fmt::format(FMT_COMPILE("{} cryptdevice={}:{}"), luks_dev, cryptpart, luks_name); + is_lvm = true; + }; + auto cryptparts = utils::make_multiline(utils::exec(R"(lsblk -lno NAME,FSTYPE,TYPE | grep 'lvm' | grep -i 'crypto_luks' | uniq | awk '{print "/dev/mapper/"$1}')")); + if (check_cryptparts(cryptparts, check_functor)) { + return true; + } + + // Check if LVM on LUKS + cryptparts = utils::make_multiline(utils::exec(R"(lsblk -lno NAME,FSTYPE,TYPE | grep ' crypt$' | grep -i 'LVM2_member' | uniq | awk '{print "/dev/mapper/"$1}')")); + if (check_cryptparts(cryptparts, check_functor)) { + return true; + } + + // Check if LUKS alone (parent = part /dev/...) + const auto& check_func_dev = [&](auto&& cryptpart) { + luks_uuid = utils::exec(fmt::format(FMT_COMPILE("lsblk -lno UUID,TYPE,FSTYPE {} | grep 'part' | grep -i 'crypto_luks' | {}"), cryptpart, "awk '{print $1}'")); + luks_dev = fmt::format(FMT_COMPILE("{} cryptdevice=UUID={}:{}"), luks_dev, luks_uuid, luks_name); + }; + cryptparts = utils::make_multiline(utils::exec(R"(lsblk -lno NAME,FSTYPE,TYPE | grep 'part' | grep -i 'crypto_luks' | uniq | awk '{print "/dev/"$1}')")); + if (check_cryptparts(cryptparts, check_func_dev)) { + return true; + } + } + /* + + // If LVM logical volume.... + elif [[ $(lsblk -lno TYPE ${PARTITION} | grep "lvm") != "" ]]; then + LVM=1 + + // First get crypt name (code above would get lv name) + cryptparts=$(lsblk -lno NAME,TYPE,FSTYPE | grep "crypt" | grep -i "lvm2_member" | uniq | awk '{print "/dev/mapper/"$1}') + for i in ${cryptparts}; do + if [[ $(lsblk -lno NAME ${i} | grep $(echo $PARTITION | sed "s~^/dev/mapper/~~g")) != "" ]]; then + LUKS_NAME=$(echo ${i} | sed s~/dev/mapper/~~g) + return 0; + fi + done + + // Now get the device (/dev/...) for the crypt name + cryptparts=$(lsblk -lno NAME,FSTYPE,TYPE | grep "part" | grep -i "crypto_luks" | uniq | awk '{print "/dev/"$1}') + for i in ${cryptparts}; do + if [[ $(lsblk -lno NAME ${i} | grep $LUKS_NAME) != "" ]]; then + # Create UUID for comparison + LUKS_UUID=$(lsblk -lno UUID,TYPE,FSTYPE ${i} | grep "part" | grep -i "crypto_luks" | awk '{print $1}') + + # Check if not already added as a LUKS DEVICE (i.e. multiple LVs on one crypt). If not, add. + if [[ $(echo $LUKS_DEV | grep $LUKS_UUID) == "" ]]; then + LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME" + LUKS=1 + fi + + return 0; + fi + fi*/ + return true; +} + +} // namespace gucc::mount diff --git a/src/misc.cpp b/src/misc.cpp index 0b22bbc..9fe844c 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -77,7 +77,7 @@ namespace tui { // Revised to deal with partition sizes now being displayed to the user bool confirm_mount([[maybe_unused]] const std::string_view& part_user, bool quite) { #ifdef NDEVENV - const auto& ret_status = gucc::utils::exec(fmt::format(FMT_COMPILE("mount | grep {}"), part_user), true); + const auto& ret_status = gucc::utils::exec(fmt::format(FMT_COMPILE("mount | grep -q {}"), part_user), true); if (!quite && (ret_status != "0"sv)) { detail::infobox_widget("\nMount Failed!\n"sv); std::this_thread::sleep_for(std::chrono::seconds(2)); diff --git a/src/tui.cpp b/src/tui.cpp index 182f3f9..7ff31be 100644 --- a/src/tui.cpp +++ b/src/tui.cpp @@ -13,6 +13,7 @@ #include "gucc/fs_utils.hpp" #include "gucc/io_utils.hpp" #include "gucc/locale.hpp" +#include "gucc/mount_partitions.hpp" #include "gucc/string_utils.hpp" #include "gucc/zfs.hpp" @@ -977,10 +978,10 @@ bool mount_current_partition(bool force) noexcept { const auto& partition = std::get(config_data["PARTITION"]); const auto& mount_dev = std::get(config_data["MOUNT"]); + // Make the mount directory + const auto& mount_dir = fmt::format(FMT_COMPILE("{}{}"), mountpoint, mount_dev); #ifdef NDEVENV std::error_code err{}; - // Make the mount directory - const fs::path mount_dir(fmt::format(FMT_COMPILE("{}{}"), mountpoint, mount_dev)); fs::create_directories(mount_dir, err); #endif @@ -995,96 +996,28 @@ bool mount_current_partition(bool force) noexcept { // see https://github.com/util-linux/util-linux/blob/master/sys-utils/mount.c#L734 #ifdef NDEVENV const auto& mount_opts_info = std::get(config_data["MOUNT_OPTS"]); - if (!mount_opts_info.empty()) { - // check_for_error "mount ${PARTITION} $(cat ${MOUNT_OPTS})" - const auto& mount_status = gucc::utils::exec(fmt::format(FMT_COMPILE("mount -o {} {} {}{}"), mount_opts_info, partition, mountpoint, mount_dev)); - spdlog::info("{}", mount_status); - } else { - // check_for_error "mount ${PARTITION}" - const auto& mount_status = gucc::utils::exec(fmt::format(FMT_COMPILE("mount {} {}{}"), partition, mountpoint, mount_dev)); - spdlog::info("{}", mount_status); + if (!gucc::mount::mount_partition(partition, mount_dir, mount_opts_info)) { + spdlog::error("Failed to mount partition {} at {} with {}", partition, mount_dir, mount_opts_info); } #endif /* clang-format off */ - confirm_mount(fmt::format(FMT_COMPILE("{}{}"), mountpoint, mount_dev), force); + confirm_mount(mount_dir, force); /* clang-format on */ - // Identify if mounted partition is type "crypt" (LUKS on LVM, or LUKS alone) - if (!gucc::utils::exec(fmt::format(FMT_COMPILE("lsblk -lno TYPE {} | grep \"crypt\""), partition)).empty()) { - // cryptname for bootloader configuration either way - config_data["LUKS"] = 1; - auto& luks_name = std::get(config_data["LUKS_NAME"]); - const auto& luks_dev = std::get(config_data["LUKS_DEV"]); - luks_name = gucc::utils::exec(fmt::format(FMT_COMPILE("echo {} | sed \"s~^/dev/mapper/~~g\""), partition)); - const auto& check_cryptparts = [&](const auto cryptparts, auto functor) { - for (const auto& cryptpart : cryptparts) { - if (!gucc::utils::exec(fmt::format(FMT_COMPILE("lsblk -lno NAME {} | grep \"{}\""), cryptpart, luks_name)).empty()) { - functor(cryptpart); - return true; - } - } - return false; - }; + auto& luks_name = std::get(config_data["LUKS_NAME"]); + auto& luks_dev = std::get(config_data["LUKS_DEV"]); + auto& luks_uuid = std::get(config_data["LUKS_UUID"]); - // Check if LUKS on LVM (parent = lvm /dev/mapper/...) - auto cryptparts = gucc::utils::make_multiline(gucc::utils::exec(R"(lsblk -lno NAME,FSTYPE,TYPE | grep "lvm" | grep -i "crypto_luks" | uniq | awk '{print "/dev/mapper/"$1}')")); - auto check_functor = [&](const auto cryptpart) { - config_data["LUKS_DEV"] = fmt::format(FMT_COMPILE("{} cryptdevice={}:{}"), luks_dev, cryptpart, luks_name); - config_data["LVM"] = 1; - }; - if (check_cryptparts(cryptparts, check_functor)) { - return true; - } + auto& is_luks = std::get(config_data["LUKS"]); + auto& is_lvm = std::get(config_data["LVM"]); - // Check if LVM on LUKS - cryptparts = gucc::utils::make_multiline(gucc::utils::exec(R"(lsblk -lno NAME,FSTYPE,TYPE | grep " crypt$" | grep -i "LVM2_member" | uniq | awk '{print "/dev/mapper/"$1}')")); - if (check_cryptparts(cryptparts, check_functor)) { - return true; - } - - // Check if LUKS alone (parent = part /dev/...) - cryptparts = gucc::utils::make_multiline(gucc::utils::exec(R"(lsblk -lno NAME,FSTYPE,TYPE | grep "part" | grep -i "crypto_luks" | uniq | awk '{print "/dev/"$1}')")); - const auto& check_func_dev = [&](const auto cryptpart) { - auto& luks_uuid = std::get(config_data["LUKS_UUID"]); - luks_uuid = gucc::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_dev, luks_uuid, luks_name); - }; - if (check_cryptparts(cryptparts, check_func_dev)) { - return true; - } + if (!gucc::mount::query_partition(partition, is_luks, is_lvm, luks_name, luks_dev, luks_uuid)) { + spdlog::error("Failed to query partition: {}", partition); + return false; } - /* - // If LVM logical volume.... - elif [[ $(lsblk -lno TYPE ${PARTITION} | grep "lvm") != "" ]]; then - LVM=1 - - // First get crypt name (code above would get lv name) - cryptparts=$(lsblk -lno NAME,TYPE,FSTYPE | grep "crypt" | grep -i "lvm2_member" | uniq | awk '{print "/dev/mapper/"$1}') - for i in ${cryptparts}; do - if [[ $(lsblk -lno NAME ${i} | grep $(echo $PARTITION | sed "s~^/dev/mapper/~~g")) != "" ]]; then - LUKS_NAME=$(echo ${i} | sed s~/dev/mapper/~~g) - return 0; - fi - done - - // Now get the device (/dev/...) for the crypt name - cryptparts=$(lsblk -lno NAME,FSTYPE,TYPE | grep "part" | grep -i "crypto_luks" | uniq | awk '{print "/dev/"$1}') - for i in ${cryptparts}; do - if [[ $(lsblk -lno NAME ${i} | grep $LUKS_NAME) != "" ]]; then - # Create UUID for comparison - LUKS_UUID=$(lsblk -lno UUID,TYPE,FSTYPE ${i} | grep "part" | grep -i "crypto_luks" | awk '{print $1}') - - # Check if not already added as a LUKS DEVICE (i.e. multiple LVs on one crypt). If not, add. - if [[ $(echo $LUKS_DEV | grep $LUKS_UUID) == "" ]]; then - LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME" - LUKS=1 - fi - - return 0; - fi - fi*/ + spdlog::debug("partition '{}': is_luks:={};is_lvm:={};luks_name:='{}';luks_dev:='{}';luks_uuid:='{}'", partition, is_luks, is_lvm, luks_name, luks_dev, luks_uuid); return true; }