arch-installer/lib/block-device.sh
Daniel Langbein bce90bf7d8 v3.0
mkinitcpio or dracut for initramfs generation
2023-03-22 20:18:08 +01:00

223 lines
7.1 KiB
Bash

#
# 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
}