diff --git a/extensions/fs-cryptroot-support.sh b/extensions/fs-cryptroot-support.sh index 8e829d575..95e70f95e 100644 --- a/extensions/fs-cryptroot-support.sh +++ b/extensions/fs-cryptroot-support.sh @@ -15,6 +15,23 @@ function add_host_dependencies__add_cryptroot_tooling() { fi } +function extension_prepare_config__prepare_cryptroot() { + # Config for cryptroot, a boot partition is required. + declare -g BOOTPART_REQUIRED=yes + EXTRA_IMAGE_SUFFIXES+=("-crypt") +} + +function prepare_root_device__encrypt_root_device(){ + # We encrypt the rootdevice (currently a loop device) and return the new mapped rootdevice + check_loop_device "$rootdevice" + display_alert "Encrypting root partition with LUKS..." "cryptsetup luksFormat $rootdevice" "" + echo -n $CRYPTROOT_PASSPHRASE | cryptsetup luksFormat $CRYPTROOT_PARAMETERS $rootdevice - + echo -n $CRYPTROOT_PASSPHRASE | cryptsetup luksOpen $rootdevice $ROOT_MAPPER - + display_alert "Root partition encryption complete." "" "ext" + # TODO: pass /dev/mapper to Docker + rootdevice=/dev/mapper/$ROOT_MAPPER # used by `mkfs` and `mount` commands +} + function pre_install_kernel_debs__adjust_dropbear_configuration() { # Adjust initramfs dropbear configuration # Needs to be done before kernel installation, else it won't be in the initrd image diff --git a/extensions/lvm.sh b/extensions/lvm.sh new file mode 100644 index 000000000..f3e26de44 --- /dev/null +++ b/extensions/lvm.sh @@ -0,0 +1,94 @@ +# +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2024 Rafel del Valle +# This file is a part of the Armbian Build Framework https://github.com/armbian/build/ +# + +# This extension will place the root partition on an LVM volume. +# It is possible to customise the volume group name and the image is extended to allow +# for LVM headers + +# In case of failed builds check for leaked logical volumes with "dmsetup list" and +# remove them with "dmsetup remove" + +# Additional log infomration will be created on lvm.log + + +# We will need to create several LVM objects: PV VG VOL on the image from the host +function add_host_dependencies__lvm_host_deps() { + declare -g EXTRA_BUILD_DEPS="${EXTRA_BUILD_DEPS} lvm2" +} + +function extension_prepare_config__lvm_image_suffix() { + # Add to image suffix. + EXTRA_IMAGE_SUFFIXES+=("-lvm") +} + +function extension_prepare_config__prepare_lvm() { + # Config for lvm, boot partition is required, many bootloaders do not support LVM. + declare -g BOOTPART_REQUIRED=yes + declare -g LVM_VG_NAME="${LVM_VG_NAME:-armbivg}" + declare -g EXTRA_ROOTFS_MIB_SIZE=256 + add_packages_to_image lvm2 +} + +function post_create_partitions__setup_lvm(){ + + LOOP=$(losetup -f) + [[ -z $LOOP ]] && exit_with_error "Unable to find free loop device" + check_loop_device "$LOOP" + losetup $LOOP ${SDCARD}.raw + partprobe $LOOP + + # the partition to setup LVM on is defined as rootpart + local lvmpart=${rootpart} + local lvmdev=${LOOP}p${lvmpart} + display_alert "LVM will be on Partition ${lvmpart}, thats ${lvmdev}" "${EXTENSION}" "info" + + # Setup LVM on the partition, ROOTFS + parted -s ${SDCARD}.raw -- set ${lvmpart} lvm on + display_alert "LVM Partition table created" "${EXTENSION}" "info" + parted -s ${SDCARD}.raw -- print >> "${DEST}"/${LOG_SUBPATH}/lvm.log 2>&1 + + # Caculate the required volume size + declare -g -i rootfs_size + rootfs_size=$(du --apparent-size -sm "${SDCARD}"/ | cut -f1) # MiB + display_alert "Current rootfs size" "$rootfs_size MiB" "info" + volsize=$(bc -l <<< "scale=0; ((($rootfs_size * 1.30) / 1 + 0) / 4 + 1) * 4") + display_alert "Root volume size" "$volsize MiB" "info" + + # Create the PV VG and VOL + display_alert "LVM Creating VG" "${SDCARD}.raw" "info" + check_loop_device ${lvmdev} + pvcreate ${lvmdev} + vgcreate ${LVM_VG_NAME} ${lvmdev} + # Note that devices wont come up automatically inside docker + lvcreate -Zn --name root --size ${volsize}M ${LVM_VG_NAME} + vgmknodes + lvs >> "${DEST}"/${LOG_SUBPATH}/lvm.log 2>&1 + vgchange -a n ${LVM_VG_NAME} + losetup -d ${LOOP} + display_alert "LVM created volume group" "${EXTENSION}" "info" +} + +function prepare_root_device__create_volume_group(){ + display_alert "Using LVM root" "${EXTENSION}" "info" + vgscan + vgchange -a y ${LVM_VG_NAME} + + rootdevice=/dev/mapper/${LVM_VG_NAME}-root + display_alert "Root device is ${rootdevice}" "${EXTENSION}" "info" +} + +function format_partitions__format_lvm(){ + # Label the root volume + e2label /dev/mapper/${LVM_VG_NAME}-root armbi_root + blkid | grep ${LVM_VG_NAME} >> "${DEST}"/${LOG_SUBPATH}/lvm.log 2>&1 + display_alert "LVM labeled partitions" "${EXTENSION}" "info" +} + +function post_umount_final_image__close_lvm(){ + # Deactivat the Volume Group + vgchange -a n ${LVM_VG_NAME} + display_alert "LVM deactivated volume group" "${EXTENSION}" "info" +} \ No newline at end of file diff --git a/lib/functions/image/partitioning.sh b/lib/functions/image/partitioning.sh index 94e64eb90..03cffa0e8 100644 --- a/lib/functions/image/partitioning.sh +++ b/lib/functions/image/partitioning.sh @@ -98,7 +98,8 @@ function prepare_partitions() { local uefipart=$((next++)) fi # Check if we need boot partition - if [[ $BOOTSIZE != "0" && ( -n $BOOTFS_TYPE || $ROOTFS_TYPE != ext4 || $CRYPTROOT_ENABLE == yes ) ]]; then + # Specialized storage extensions like cryptroot or lvm may require a boot partition + if [[ $BOOTSIZE != "0" && ( -n $BOOTFS_TYPE || $ROOTFS_TYPE != ext4 || $BOOTPART_REQUIRED == yes ) ]]; then local bootpart=$((next++)) local bootfs=${BOOTFS_TYPE:-ext4} [[ -z $BOOTSIZE || $BOOTSIZE -le 8 ]] && BOOTSIZE=${DEFAULT_BOOTSIZE} @@ -239,15 +240,10 @@ function prepare_partitions() { if [[ -n $rootpart ]]; then local rootdevice="${LOOP}p${rootpart}" - if [[ $CRYPTROOT_ENABLE == yes ]]; then - check_loop_device "$rootdevice" - display_alert "Encrypting root partition with LUKS..." "cryptsetup luksFormat $rootdevice" "" - echo -n $CRYPTROOT_PASSPHRASE | cryptsetup luksFormat $CRYPTROOT_PARAMETERS $rootdevice - - echo -n $CRYPTROOT_PASSPHRASE | cryptsetup luksOpen $rootdevice $ROOT_MAPPER - - display_alert "Root partition encryption complete." "" "ext" - # TODO: pass /dev/mapper to Docker - rootdevice=/dev/mapper/$ROOT_MAPPER # used by `mkfs` and `mount` commands - fi + call_extension_method "prepare_root_device" <<- 'PREPARE_ROOT_DEVICE' + *Specialized storage extensions typically transform the root device into a mapped device and should hook in here * + At this stage ${rootdevice} has been defined pointing to a loop device partition. Extensions that map the root device must update rootdevice accordingly. + PREPARE_ROOT_DEVICE check_loop_device "$rootdevice" display_alert "Creating rootfs" "$ROOTFS_TYPE on $rootdevice"