# # lsblk # # -d, --nodeps Do not print holder devices or slaves. # -p, --paths Print full device paths. # -l, --list Produce output in the form of a list. # -n, --noheadings # -x, --sort column # # lsblk --tree=PATH -o PATH,TYPE,PARTUUID function get_uuid() { # arg $1: Partition # arg $2: Variable name to store UUID validate_args 2 "$@" || return $? local partition="${1}" local -n uuid_ptr=$2 # shellcheck disable=SC2034 uuid_ptr="$(blkid -o value -s UUID "${partition}")" || return $? } function get_partitions(){ # arg $1: block device # arg $2: name of variable to store partitions validate_args 2 "$@" || return $? local block_device="$1" local -n partitions_ptr=$2 # Remove first line of output (which is just the block device itself) # with sed: `sed 1d` # shellcheck disable=SC2034 partitions_ptr="$(lsblk -pln -o name "${block_device}" | sed 1d)" || return $? newline_separated_to_array partitions_ptr partitions_ptr || return $? } function get_block_devices() { # arg $1: name of variable to store block devices validate_args 1 "$@" || return $? local -n block_devices_ptr=$1 # Get list of devices, one per line # shellcheck disable=SC2034 block_devices_ptr="$(lsblk -dplnx size -o name | grep -Ev 'boot|rpmb|loop' | tac)" || return $? newline_separated_to_array block_devices_ptr block_devices_ptr || return $? } function get_block_devices_with_size() { # Example: variable with name $1 has content ('/dev/nvme0n1' '1,9T') # # arg $1: name of variable to store block device paths and their sizes validate_args 1 "$@" || return $? local -n block_device_sizes_ptr=$1 # Get list of devices and their sizes, one pair per line. # Use sed to remove multiple white spaces: sed 's|\s\s*| |' # shellcheck disable=SC2034 block_device_sizes_ptr="$(lsblk -dplnx size -o name,size | grep -Ev 'boot|rpmb|loop' | sed 's|\s\s*| |' | tac)" || return $? newline_to_space block_device_sizes_ptr || return $? space_separated_to_array block_device_sizes_ptr block_device_sizes_ptr || return $? } function partition() { # Creates two partitions: # - boot partition, by default 260MiB # - luks partition, rest of the device for (encrypted) data # # arg $1: target block device # arg $2: boot firmware: 'uefi' | 'bios' # arg $3: boot partition size in MiB: >=260 | 'none' # arg $4: name of variable to store boot partition # arg $5: name of variable to store luks partition validate_args 5 "$@" || return $? local target_block_device="${1}" local boot_firmware="${2}" local boot_part_size="${3}" local -n boot_part=$4 local -n luks_part=$5 local minimum=260 # Check if too small if [ "${boot_part_size}" -lt "${minimum}" ]; then printf '%s\n' "boot_part_size should be >= ${minimum}" return 1 fi # As our data partition is encrypted, # we need a separate boot partition! case "${boot_firmware}" in uefi) # EFI boot partition # # Create a partition with fat32 as the file system type and set the # esp flag on it. sudo parted --script "${target_block_device}" -- mklabel gpt \ mkpart ESP fat32 2Mib "${boot_part_size}MiB" \ set 1 esp on \ mkpart primary "${boot_part_size}MiB" 100% || return $? get_partitions "${target_block_device}" PARTITIONS || return $? boot_part="${PARTITIONS[0]}" luks_part="${PARTITIONS[1]}" ;; bios) # > On a BIOS/GPT configuration, a BIOS boot partition is required. GRUB embeds its `core.img` # > into this partition. # > For parted set/activate the flag bios_grub on the partition. # # archwiki -> GRUB#GUID_Partition_Table_(GPT)_specific_instructions # https://www.gnu.org/software/grub/manual/grub/html_node/BIOS-installation.html#BIOS-installation sudo parted --script "${target_block_device}" -- mklabel gpt \ mkpart primary 1MiB 2MiB \ set 1 bios_grub on \ mkpart primary 2MiB "${boot_part_size}MiB" \ mkpart primary "${boot_part_size}MiB" 100% || return $? get_partitions "${target_block_device}" PARTITIONS || return $? boot_part="${PARTITIONS[2]}" luks_part="${PARTITIONS[3]}" ;; *) printf '%s\n' "Expected uefi or bios but got ${boot_firmware} instead!" return 1 ;; esac printf '%s\n' "boot partition: ${boot_part}" printf '%s\n' "luks partition: ${luks_part}" } function format() { # Formats the `boot` and `luks` partitions. # # If FDE is enabled ('true'), # then $2 will be encrypted with password $3 and opened at $7. # # If FDE is disabled, # then $7 is identical with $2. # # arg $1: boot partition # arg $2: (encrypted) luks partition # arg $3: password of luks partition # arg $4: full-disk-encryption (FDE): 'true' | 'false' # arg $5: filesystem: 'BTRFS' | 'EXT4' | 'F2FS' # arg $6: name of variable to store partition of encrypted luks partition (if FDE='true'). # Set to /dev/mapper/$(basename $LUKS_PART) # arg $7: name of variable to store data partition # # @post # boot partition formatted # luks partition formatted and accessible under $7 validate_args 7 "$@" || return $? local boot_part="${1}" local luks_part="${2}" local luks_pwd="${3}" local fde="${4}" local fs="${5}" # shellcheck disable=SC2034 local -n luks_part_uuid=$6 local -n data_part=$7 printf '%s\n' 'Wiping old signatures from partitions ...' sudo wipefs --all "${boot_part}" || return $? sudo wipefs --all "${luks_part}" || return $? printf '%s\n' "Formatting boot partition ${boot_part} ..." sudo mkfs.fat -F32 "${boot_part}" || return $? case "${fde}" in true) # FDE: # GRUB does support LUKS2 since this commit: # https://git.savannah.gnu.org/cgit/grub.git/commit/?id=365e0cc3e7e44151c14dd29514c2f870b49f9755 # Using "--type luks1" is no longer required. printf '%s\n' "Creating encrypted luks partition ${luks_part} ..." printf '%s' "${luks_pwd}" | sudo cryptsetup luksFormat \ --cipher aes-xts-plain64 --key-size 512 --hash sha512 \ --iter-time 10000 --use-random "${luks_part}" || return $? get_uuid "${luks_part}" luks_part_uuid || return $? local luks_name luks_name="$(basename "${luks_part}")" data_part="/dev/mapper/${luks_name}" # Open luks partition printf '%s' "${luks_pwd}" | sudo cryptsetup luksOpen "${luks_part}" "${luks_name}" || return $? ;; false) data_part="${luks_part}" ;; *) printf '%s\n' "Invalid option: ${fde}" return 1 ;; esac printf '%s\n' "Formatting the data partition ${data_part} ..." case "${fs}" in BTRFS) sudo mkfs.btrfs "${data_part}" || return $? ;; EXT4) # https://wiki.archlinux.org/index.php/Ext4 # If the CPU supports SSE 4.2, make sure the crc32c_intel kernel module is loaded sudo mkfs.ext4 -O metadata_csum "${data_part}" || return $? ;; F2FS) # archwiki -> F2FS#Creating_a_F2FS_file_system # - requires f2fs-tools # - compression: "-O compression" and when mounting the filesystem, specify compress_algorithm=(lzo|lz4|zstd|lzo-rle) sudo mkfs.f2fs -O extra_attr,inode_checksum,sb_checksum,compression "${data_part}" || return $? ;; *) printf '%s\n' "Filesystem ${fs} is not yet supported!" return 1 ;; esac }