# shellcheck source=./scripts/protection.shsource "$GENTOO_INSTALL_REPO_DIR/scripts/protection.sh" || exit 1 ################################################# Functions function sync_time() { einfo "Syncing time" try ntpd -g -q einfo "Current date: $(LANG=C date)" einfo "Writing time to hardware clock" hwclock --systohc --utc \ || die "Could not save time to hardware clock"} function check_config() { [[ $KEYMAP =~ ^[0-9A-Za-z-]*$ ]] \ || die "KEYMAP contains invalid characters" if [[ "$SYSTEMD" == "true" ]]; then [[ "$STAGE3_BASENAME" == *systemd* ]] \ || die "Using systemd requires a systemd stage3 archive!" else [[ "$STAGE3_BASENAME" != *systemd* ]] \ || die "Using OpenRC requires a non-systemd stage3 archive!" fi # Check hostname per RFC1123 local hostname_regex='^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$' [[ $HOSTNAME =~ $hostname_regex ]] \ || die "'$HOSTNAME' is not a valid hostname" [[ -v "DISK_ID_ROOT" && -n $DISK_ID_ROOT ]] \ || die "You must assign DISK_ID_ROOT" [[ -v "DISK_ID_EFI" && -n $DISK_ID_EFI ]] || [[ -v "DISK_ID_BIOS" && -n $DISK_ID_BIOS ]] \ || die "You must assign DISK_ID_EFI or DISK_ID_BIOS" [[ -v "DISK_ID_BIOS" ]] && [[ ! -v "DISK_ID_TO_UUID[$DISK_ID_BIOS]" ]] \ && die "Missing uuid for DISK_ID_BIOS, have you made sure it is used?" [[ -v "DISK_ID_EFI" ]] && [[ ! -v "DISK_ID_TO_UUID[$DISK_ID_EFI]" ]] \ && die "Missing uuid for DISK_ID_EFI, have you made sure it is used?" [[ -v "DISK_ID_SWAP" ]] && [[ ! -v "DISK_ID_TO_UUID[$DISK_ID_SWAP]" ]] \ && die "Missing uuid for DISK_ID_SWAP, have you made sure it is used?" [[ -v "DISK_ID_ROOT" ]] && [[ ! -v "DISK_ID_TO_UUID[$DISK_ID_ROOT]" ]] \ && die "Missing uuid for DISK_ID_ROOT, have you made sure it is used?" if [[ -v "DISK_ID_EFI" ]]; then IS_EFI=true else IS_EFI=false fi} function preprocess_config() { disk_configuration # Check encryption key if used [[ $USED_ENCRYPTION == "true" ]] \ && check_encryption_key check_config} function prepare_installation_environment() { maybe_exec 'before_prepare_environment' einfo "Preparing installation environment" local wanted_programs=( gpg hwclock lsblk ntpd partprobe python3 "?rhash" sha512sum sgdisk uuidgen wget ) [[ $USED_BTRFS == "true" ]] \ && wanted_programs+=(btrfs) [[ $USED_ZFS == "true" ]] \ && wanted_programs+=(zfs) [[ $USED_RAID == "true" ]] \ && wanted_programs+=(mdadm) [[ $USED_LUKS == "true" ]] \ && wanted_programs+=(cryptsetup) # Check for existence of required programs check_wanted_programs "${wanted_programs[@]}" # Sync time now to prevent issues later sync_time maybe_exec 'after_prepare_environment'} function check_encryption_key() { if [[ -z "${GENTOO_INSTALL_ENCRYPTION_KEY+set}" ]]; then elog "You have enabled encryption, but haven't specified a key in the environment variable GENTOO_INSTALL_ENCRYPTION_KEY." if ask "Do you want to enter an encryption key now?"; then local encryption_key_1 local encryption_key_2 while true; do flush_stdin IFS="" read -s -r -p "Enter encryption key: " encryption_key_1 \ || die "Error in read" echo [[ ${#encryption_key_1} -ge 8 ]] \ || { ewarn "Your encryption key must be at least 8 characters long."; continue; } flush_stdin IFS="" read -s -r -p "Repeat encryption key: " encryption_key_2 \ || die "Error in read" echo [[ "$encryption_key_1" == "$encryption_key_2" ]] \ || { ewarn "Encryption keys mismatch."; continue; } break done export GENTOO_INSTALL_ENCRYPTION_KEY="$encryption_key_1" else die "Please export GENTOO_INSTALL_ENCRYPTION_KEY with the desired key." fi fi [[ ${#GENTOO_INSTALL_ENCRYPTION_KEY} -ge 8 ]] \ || die "Your encryption key must be at least 8 characters long."} function add_summary_entry() { local parent="$1" local id="$2" local name="$3" local hint="$4" local desc="$5" local ptr case "$id" in "${DISK_ID_BIOS-__unused__}") ptr="[1;32m← bios[m" ;; "${DISK_ID_EFI-__unused__}") ptr="[1;32m← efi[m" ;; "${DISK_ID_SWAP-__unused__}") ptr="[1;34m← swap[m" ;; "${DISK_ID_ROOT-__unused__}") ptr="[1;33m← root[m" ;; # \x1f characters compensate for printf byte count and unicode character count mismatch due to '←' *) ptr="[1;32m[m$(echo -e "\x1f\x1f")" ;; esac summary_tree[$parent]+=";$id" summary_name[$id]="$name" summary_hint[$id]="$hint" summary_ptr[$id]="$ptr" summary_desc[$id]="$desc"} function summary_color_args() { for arg in "$@"; do if [[ -v "arguments[$arg]" ]]; then printf '%-28s ' "[1;34m$arg[2m=[m${arguments[$arg]}" fi done} function disk_existing() { local new_id="${arguments[new_id]}" if [[ ${disk_action_summarize_only-false} == "true" ]]; then add_summary_entry __root__ "$new_id" "${arguments[device]}" "(no-format, existing)" "" fi # no-op;} function disk_create_gpt() { local new_id="${arguments[new_id]}" if [[ ${disk_action_summarize_only-false} == "true" ]]; then if [[ -v arguments[id] ]]; then add_summary_entry "${arguments[id]}" "$new_id" "gpt" "" "" else add_summary_entry __root__ "$new_id" "${arguments[device]}" "(gpt)" "" fi return 0 fi local device local device_desc="" if [[ -v arguments[id] ]]; then device="$(resolve_device_by_id "${arguments[id]}")" device_desc="$device ($id)" else device="${arguments[device]}" device_desc="$device" fi local ptuuid="${DISK_ID_TO_UUID[$new_id]}" einfo "Creating new gpt partition table ($new_id) on $device_desc" wipefs --quiet --all --force "$device" \ || die "Could not erase previous file system signatures from '$device'" sgdisk -Z -U "$ptuuid" "$device" >/dev/null \ || die "Could not create new gpt partition table ($new_id) on '$device'" partprobe "$device"} function disk_create_partition() { local new_id="${arguments[new_id]}" local id="${arguments[id]}" local size="${arguments[size]}" local type="${arguments[type]}" if [[ ${disk_action_summarize_only-false} == "true" ]]; then add_summary_entry "$id" "$new_id" "part" "($type)" "$(summary_color_args size)" return 0 fi if [[ $size == "remaining" ]]; then arg_size=0 else arg_size="+$size" fi local device device="$(resolve_device_by_id "$id")" \ || die "Could not resolve device with id=$id" local partuuid="${DISK_ID_TO_UUID[$new_id]}" local extra_args="" case "$type" in 'bios') type='ef02' extra_args='--attributes=0:set:2';; 'efi') type='ef00' ;; 'swap') type='8200' ;; 'raid') type='fd00' ;; 'luks') type='8309' ;; 'linux') type='8300' ;; *) ;; esac einfo "Creating partition ($new_id) with type=$type, size=$size on $device" # shellcheck disable=SC2086 sgdisk -n "0:0:$arg_size" -t "0:$type" -u "0:$partuuid" $extra_args "$device" >/dev/null \ || die "Could not create new gpt partition ($new_id) on '$device' ($id)" partprobe "$device" # On some system, we need to wait a bit for the partition to show up. local new_device new_device="$(resolve_device_by_id "$new_id")" \ || die "Could not resolve new device with id=$new_id" for i in {1..10}; do [[ -e "$new_device" ]] && break [[ "$i" -eq 1 ]] && printf "Waiting for partition (%s) to appear..." "$new_device" printf " %s" "$((10 - i + 1))" sleep 1 [[ "$i" -eq 10 ]] && echo done} function disk_create_raid() { local new_id="${arguments[new_id]}" local level="${arguments[level]}" local name="${arguments[name]}" local ids="${arguments[ids]}" if [[ ${disk_action_summarize_only-false} == "true" ]]; then local id # Splitting is intentional here # shellcheck disable=SC2086 for id in ${ids//';'/ }; do add_summary_entry "$id" "_$new_id" "raid$level" "" "$(summary_color_args name)" done add_summary_entry __root__ "$new_id" "raid$level" "" "$(summary_color_args name)" return 0 fi local devices_desc="" local devices=() local id local dev # Splitting is intentional here # shellcheck disable=SC2086 for id in ${ids//';'/ }; do dev="$(resolve_device_by_id "$id")" \ || die "Could not resolve device with id=$id" devices+=("$dev") devices_desc+="$dev ($id), " done devices_desc="${devices_desc:0:-2}" local mddevice="/dev/md/$name" local uuid="${DISK_ID_TO_UUID[$new_id]}" extra_args=() if [[ ${level} == 1 ]]; then extra_args+=("--metadata=1.0") else extra_args+=("--metadata=1.2") fi einfo "Creating raid$level ($new_id) on $devices_desc" mdadm \ --create "$mddevice" \ --verbose \ --homehost="$HOSTNAME" \ "${extra_args[@]}" \ --raid-devices="${#devices[@]}" \ --uuid="$uuid" \ --level="$level" \ "${devices[@]}" \ || die "Could not create raid$level array '$mddevice' ($new_id) on $devices_desc"} function disk_create_luks() { local new_id="${arguments[new_id]}" local name="${arguments[name]}" if [[ ${disk_action_summarize_only-false} == "true" ]]; then if [[ -v arguments[id] ]]; then add_summary_entry "${arguments[id]}" "$new_id" "luks" "" "" else add_summary_entry __root__ "$new_id" "${arguments[device]}" "(luks)" "" fi return 0 fi local device local device_desc="" if [[ -v arguments[id] ]]; then device="$(resolve_device_by_id "${arguments[id]}")" device_desc="$device ($id)" else device="${arguments[device]}" device_desc="$device" fi local uuid="${DISK_ID_TO_UUID[$new_id]}" einfo "Creating luks ($new_id) on $device_desc" cryptsetup luksFormat \ --type luks2 \ --uuid "$uuid" \ --key-file <(echo -n "$GENTOO_INSTALL_ENCRYPTION_KEY") \ --cipher aes-xts-plain64 \ --hash sha512 \ --pbkdf argon2id \ --iter-time 4000 \ --key-size 512 \ --batch-mode \ "$device" \ || die "Could not create luks on $device_desc" mkdir -p "$LUKS_HEADER_BACKUP_DIR" \ || die "Could not create luks header backup dir '$LUKS_HEADER_BACKUP_DIR'" local header_file="$LUKS_HEADER_BACKUP_DIR/luks-header-$id-${uuid,,}.img" [[ ! -e $header_file ]] \ || rm "$header_file" \ || die "Could not remove old luks header backup file '$header_file'" cryptsetup luksHeaderBackup "$device" \ --header-backup-file "$header_file" \ || die "Could not backup luks header on $device_desc" cryptsetup open --type luks2 \ --key-file <(echo -n "$GENTOO_INSTALL_ENCRYPTION_KEY") \ "$device" "$name" \ || die "Could not open luks encrypted device $device_desc"} function disk_create_dummy() { local new_id="${arguments[new_id]}" local device="${arguments[device]}" if [[ ${disk_action_summarize_only-false} == "true" ]]; then add_summary_entry __root__ "$new_id" "$device" "" "" return 0 fi} function init_btrfs() { local device="$1" local desc="$2" mkdir -p /btrfs \ || die "Could not create /btrfs directory" mount "$device" /btrfs \ || die "Could not mount $desc to /btrfs" btrfs subvolume create /btrfs/root \ || die "Could not create btrfs subvolume /root on $desc" btrfs subvolume set-default /btrfs/root \ || die "Could not set default btrfs subvolume to /root on $desc" umount /btrfs \ || die "Could not unmount btrfs on $desc"} function disk_format() { local id="${arguments[id]}" local type="${arguments[type]}" local label="${arguments[label]}" if [[ ${disk_action_summarize_only-false} == "true" ]]; then add_summary_entry "${arguments[id]}" "__fs__${arguments[id]}" "${arguments[type]}" "(fs)" "$(summary_color_args label)" return 0 fi local device device="$(resolve_device_by_id "$id")" \ || die "Could not resolve device with id=$id" einfo "Formatting $device ($id) with $type" wipefs --quiet --all --force "$device" \ || die "Could not erase previous file system signatures from '$device' ($id)" case "$type" in 'bios'|'efi') if [[ -v "arguments[label]" ]]; then mkfs.fat -F 32 -n "$label" "$device" \ || die "Could not format device '$device' ($id)" else mkfs.fat -F 32 "$device" \ || die "Could not format device '$device' ($id)" fi ;; 'swap') if [[ -v "arguments[label]" ]]; then mkswap -L "$label" "$device" \ || die "Could not format device '$device' ($id)" else mkswap "$device" \ || die "Could not format device '$device' ($id)" fi # Try to swapoff in case the system enabled swap automatically swapoff "$device" &>/dev/null ;; 'ext4') if [[ -v "arguments[label]" ]]; then mkfs.ext4 -q -L "$label" "$device" \ || die "Could not format device '$device' ($id)" else mkfs.ext4 -q "$device" \ || die "Could not format device '$device' ($id)" fi ;; 'btrfs') if [[ -v "arguments[label]" ]]; then mkfs.btrfs -q -L "$label" "$device" \ || die "Could not format device '$device' ($id)" else mkfs.btrfs -q "$device" \ || die "Could not format device '$device' ($id)" fi init_btrfs "$device" "'$device' ($id)" ;; *) die "Unknown filesystem type" ;; esac} # This function will be called when a custom zfs pool type has been chosen.# $1: either 'true' or 'false' determining if the datasets should be encrypted# $2: either 'false' or a value determining the dataset compression algorithm# $3: a string describing all device paths (for error messages)# $@: device pathsfunction format_zfs_standard() { local encrypt="$1" local compress="$2" local device_desc="$3" shift 3 local devices=("$@") local extra_args=() einfo "Creating zfs pool on $devices_desc" local zfs_stdin="" if [[ "$encrypt" == true ]]; then extra_args+=( "-O" "encryption=aes-256-gcm" "-O" "keyformat=passphrase" "-O" "keylocation=prompt" ) zfs_stdin="$GENTOO_INSTALL_ENCRYPTION_KEY" fi # dnodesize=legacy might be needed for GRUB2, but auto is preferred for xattr=sa. zpool create \ -R "$ROOT_MOUNTPOINT" \ -o ashift=12 \ -O acltype=posix \ -O atime=off \ -O xattr=sa \ -O dnodesize=auto \ -O mountpoint=none \ -O canmount=noauto \ -O devices=off \ "${extra_args[@]}" \ rpool \ "${devices[@]}" \ <<< "$zfs_stdin" \ || die "Could not create zfs pool on $devices_desc" if [[ "$compress" != false ]]; then zfs set "compression=$compress" rpool \ || die "Could enable compression on dataset 'rpool'" fi zfs create rpool/ROOT \Lines 1–500 of 999. Load more
# shellcheck source=./scripts/protection.sh source "$GENTOO_INSTALL_REPO_DIR/scripts/protection.sh" || exit 1 ################################################ # Functions function sync_time() { einfo "Syncing time" try ntpd -g -q einfo "Current date: $(LANG=C date)" einfo "Writing time to hardware clock" hwclock --systohc --utc \ || die "Could not save time to hardware clock" } function check_config() { [[ $KEYMAP =~ ^[0-9A-Za-z-]*$ ]] \ || die "KEYMAP contains invalid characters" if [[ "$SYSTEMD" == "true" ]]; then [[ "$STAGE3_BASENAME" == *systemd* ]] \ || die "Using systemd requires a systemd stage3 archive!" else [[ "$STAGE3_BASENAME" != *systemd* ]] \ || die "Using OpenRC requires a non-systemd stage3 archive!" fi # Check hostname per RFC1123 local hostname_regex='^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$' [[ $HOSTNAME =~ $hostname_regex ]] \ || die "'$HOSTNAME' is not a valid hostname" [[ -v "DISK_ID_ROOT" && -n $DISK_ID_ROOT ]] \ || die "You must assign DISK_ID_ROOT" [[ -v "DISK_ID_EFI" && -n $DISK_ID_EFI ]] || [[ -v "DISK_ID_BIOS" && -n $DISK_ID_BIOS ]] \ || die "You must assign DISK_ID_EFI or DISK_ID_BIOS" [[ -v "DISK_ID_BIOS" ]] && [[ ! -v "DISK_ID_TO_UUID[$DISK_ID_BIOS]" ]] \ && die "Missing uuid for DISK_ID_BIOS, have you made sure it is used?" [[ -v "DISK_ID_EFI" ]] && [[ ! -v "DISK_ID_TO_UUID[$DISK_ID_EFI]" ]] \ && die "Missing uuid for DISK_ID_EFI, have you made sure it is used?" [[ -v "DISK_ID_SWAP" ]] && [[ ! -v "DISK_ID_TO_UUID[$DISK_ID_SWAP]" ]] \ && die "Missing uuid for DISK_ID_SWAP, have you made sure it is used?" [[ -v "DISK_ID_ROOT" ]] && [[ ! -v "DISK_ID_TO_UUID[$DISK_ID_ROOT]" ]] \ && die "Missing uuid for DISK_ID_ROOT, have you made sure it is used?" if [[ -v "DISK_ID_EFI" ]]; then IS_EFI=true else IS_EFI=false fi } function preprocess_config() { disk_configuration # Check encryption key if used [[ $USED_ENCRYPTION == "true" ]] \ && check_encryption_key check_config } function prepare_installation_environment() { maybe_exec 'before_prepare_environment' einfo "Preparing installation environment" local wanted_programs=( gpg hwclock lsblk ntpd partprobe python3 "?rhash" sha512sum sgdisk uuidgen wget ) [[ $USED_BTRFS == "true" ]] \ && wanted_programs+=(btrfs) [[ $USED_ZFS == "true" ]] \ && wanted_programs+=(zfs) [[ $USED_RAID == "true" ]] \ && wanted_programs+=(mdadm) [[ $USED_LUKS == "true" ]] \ && wanted_programs+=(cryptsetup) # Check for existence of required programs check_wanted_programs "${wanted_programs[@]}" # Sync time now to prevent issues later sync_time maybe_exec 'after_prepare_environment' } function check_encryption_key() { if [[ -z "${GENTOO_INSTALL_ENCRYPTION_KEY+set}" ]]; then elog "You have enabled encryption, but haven't specified a key in the environment variable GENTOO_INSTALL_ENCRYPTION_KEY." if ask "Do you want to enter an encryption key now?"; then local encryption_key_1 local encryption_key_2 while true; do flush_stdin IFS="" read -s -r -p "Enter encryption key: " encryption_key_1 \ || die "Error in read" echo [[ ${#encryption_key_1} -ge 8 ]] \ || { ewarn "Your encryption key must be at least 8 characters long."; continue; } flush_stdin IFS="" read -s -r -p "Repeat encryption key: " encryption_key_2 \ || die "Error in read" echo [[ "$encryption_key_1" == "$encryption_key_2" ]] \ || { ewarn "Encryption keys mismatch."; continue; } break done export GENTOO_INSTALL_ENCRYPTION_KEY="$encryption_key_1" else die "Please export GENTOO_INSTALL_ENCRYPTION_KEY with the desired key." fi fi [[ ${#GENTOO_INSTALL_ENCRYPTION_KEY} -ge 8 ]] \ || die "Your encryption key must be at least 8 characters long." } function add_summary_entry() { local parent="$1" local id="$2" local name="$3" local hint="$4" local desc="$5" local ptr case "$id" in "${DISK_ID_BIOS-__unused__}") ptr="[1;32m← bios[m" ;; "${DISK_ID_EFI-__unused__}") ptr="[1;32m← efi[m" ;; "${DISK_ID_SWAP-__unused__}") ptr="[1;34m← swap[m" ;; "${DISK_ID_ROOT-__unused__}") ptr="[1;33m← root[m" ;; # \x1f characters compensate for printf byte count and unicode character count mismatch due to '←' *) ptr="[1;32m[m$(echo -e "\x1f\x1f")" ;; esac summary_tree[$parent]+=";$id" summary_name[$id]="$name" summary_hint[$id]="$hint" summary_ptr[$id]="$ptr" summary_desc[$id]="$desc" } function summary_color_args() { for arg in "$@"; do if [[ -v "arguments[$arg]" ]]; then printf '%-28s ' "[1;34m$arg[2m=[m${arguments[$arg]}" fi done } function disk_existing() { local new_id="${arguments[new_id]}" if [[ ${disk_action_summarize_only-false} == "true" ]]; then add_summary_entry __root__ "$new_id" "${arguments[device]}" "(no-format, existing)" "" fi # no-op; } function disk_create_gpt() { local new_id="${arguments[new_id]}" if [[ ${disk_action_summarize_only-false} == "true" ]]; then if [[ -v arguments[id] ]]; then add_summary_entry "${arguments[id]}" "$new_id" "gpt" "" "" else add_summary_entry __root__ "$new_id" "${arguments[device]}" "(gpt)" "" fi return 0 fi local device local device_desc="" if [[ -v arguments[id] ]]; then device="$(resolve_device_by_id "${arguments[id]}")" device_desc="$device ($id)" else device="${arguments[device]}" device_desc="$device" fi local ptuuid="${DISK_ID_TO_UUID[$new_id]}" einfo "Creating new gpt partition table ($new_id) on $device_desc" wipefs --quiet --all --force "$device" \ || die "Could not erase previous file system signatures from '$device'" sgdisk -Z -U "$ptuuid" "$device" >/dev/null \ || die "Could not create new gpt partition table ($new_id) on '$device'" partprobe "$device" } function disk_create_partition() { local new_id="${arguments[new_id]}" local id="${arguments[id]}" local size="${arguments[size]}" local type="${arguments[type]}" if [[ ${disk_action_summarize_only-false} == "true" ]]; then add_summary_entry "$id" "$new_id" "part" "($type)" "$(summary_color_args size)" return 0 fi if [[ $size == "remaining" ]]; then arg_size=0 else arg_size="+$size" fi local device device="$(resolve_device_by_id "$id")" \ || die "Could not resolve device with id=$id" local partuuid="${DISK_ID_TO_UUID[$new_id]}" local extra_args="" case "$type" in 'bios') type='ef02' extra_args='--attributes=0:set:2';; 'efi') type='ef00' ;; 'swap') type='8200' ;; 'raid') type='fd00' ;; 'luks') type='8309' ;; 'linux') type='8300' ;; *) ;; esac einfo "Creating partition ($new_id) with type=$type, size=$size on $device" # shellcheck disable=SC2086 sgdisk -n "0:0:$arg_size" -t "0:$type" -u "0:$partuuid" $extra_args "$device" >/dev/null \ || die "Could not create new gpt partition ($new_id) on '$device' ($id)" partprobe "$device" # On some system, we need to wait a bit for the partition to show up. local new_device new_device="$(resolve_device_by_id "$new_id")" \ || die "Could not resolve new device with id=$new_id" for i in {1..10}; do [[ -e "$new_device" ]] && break [[ "$i" -eq 1 ]] && printf "Waiting for partition (%s) to appear..." "$new_device" printf " %s" "$((10 - i + 1))" sleep 1 [[ "$i" -eq 10 ]] && echo done } function disk_create_raid() { local new_id="${arguments[new_id]}" local level="${arguments[level]}" local name="${arguments[name]}" local ids="${arguments[ids]}" if [[ ${disk_action_summarize_only-false} == "true" ]]; then local id # Splitting is intentional here # shellcheck disable=SC2086 for id in ${ids//';'/ }; do add_summary_entry "$id" "_$new_id" "raid$level" "" "$(summary_color_args name)" done add_summary_entry __root__ "$new_id" "raid$level" "" "$(summary_color_args name)" return 0 fi local devices_desc="" local devices=() local id local dev # Splitting is intentional here # shellcheck disable=SC2086 for id in ${ids//';'/ }; do dev="$(resolve_device_by_id "$id")" \ || die "Could not resolve device with id=$id" devices+=("$dev") devices_desc+="$dev ($id), " done devices_desc="${devices_desc:0:-2}" local mddevice="/dev/md/$name" local uuid="${DISK_ID_TO_UUID[$new_id]}" extra_args=() if [[ ${level} == 1 ]]; then extra_args+=("--metadata=1.0") else extra_args+=("--metadata=1.2") fi einfo "Creating raid$level ($new_id) on $devices_desc" mdadm \ --create "$mddevice" \ --verbose \ --homehost="$HOSTNAME" \ "${extra_args[@]}" \ --raid-devices="${#devices[@]}" \ --uuid="$uuid" \ --level="$level" \ "${devices[@]}" \ || die "Could not create raid$level array '$mddevice' ($new_id) on $devices_desc" } function disk_create_luks() { local new_id="${arguments[new_id]}" local name="${arguments[name]}" if [[ ${disk_action_summarize_only-false} == "true" ]]; then if [[ -v arguments[id] ]]; then add_summary_entry "${arguments[id]}" "$new_id" "luks" "" "" else add_summary_entry __root__ "$new_id" "${arguments[device]}" "(luks)" "" fi return 0 fi local device local device_desc="" if [[ -v arguments[id] ]]; then device="$(resolve_device_by_id "${arguments[id]}")" device_desc="$device ($id)" else device="${arguments[device]}" device_desc="$device" fi local uuid="${DISK_ID_TO_UUID[$new_id]}" einfo "Creating luks ($new_id) on $device_desc" cryptsetup luksFormat \ --type luks2 \ --uuid "$uuid" \ --key-file <(echo -n "$GENTOO_INSTALL_ENCRYPTION_KEY") \ --cipher aes-xts-plain64 \ --hash sha512 \ --pbkdf argon2id \ --iter-time 4000 \ --key-size 512 \ --batch-mode \ "$device" \ || die "Could not create luks on $device_desc" mkdir -p "$LUKS_HEADER_BACKUP_DIR" \ || die "Could not create luks header backup dir '$LUKS_HEADER_BACKUP_DIR'" local header_file="$LUKS_HEADER_BACKUP_DIR/luks-header-$id-${uuid,,}.img" [[ ! -e $header_file ]] \ || rm "$header_file" \ || die "Could not remove old luks header backup file '$header_file'" cryptsetup luksHeaderBackup "$device" \ --header-backup-file "$header_file" \ || die "Could not backup luks header on $device_desc" cryptsetup open --type luks2 \ --key-file <(echo -n "$GENTOO_INSTALL_ENCRYPTION_KEY") \ "$device" "$name" \ || die "Could not open luks encrypted device $device_desc" } function disk_create_dummy() { local new_id="${arguments[new_id]}" local device="${arguments[device]}" if [[ ${disk_action_summarize_only-false} == "true" ]]; then add_summary_entry __root__ "$new_id" "$device" "" "" return 0 fi } function init_btrfs() { local device="$1" local desc="$2" mkdir -p /btrfs \ || die "Could not create /btrfs directory" mount "$device" /btrfs \ || die "Could not mount $desc to /btrfs" btrfs subvolume create /btrfs/root \ || die "Could not create btrfs subvolume /root on $desc" btrfs subvolume set-default /btrfs/root \ || die "Could not set default btrfs subvolume to /root on $desc" umount /btrfs \ || die "Could not unmount btrfs on $desc" } function disk_format() { local id="${arguments[id]}" local type="${arguments[type]}" local label="${arguments[label]}" if [[ ${disk_action_summarize_only-false} == "true" ]]; then add_summary_entry "${arguments[id]}" "__fs__${arguments[id]}" "${arguments[type]}" "(fs)" "$(summary_color_args label)" return 0 fi local device device="$(resolve_device_by_id "$id")" \ || die "Could not resolve device with id=$id" einfo "Formatting $device ($id) with $type" wipefs --quiet --all --force "$device" \ || die "Could not erase previous file system signatures from '$device' ($id)" case "$type" in 'bios'|'efi') if [[ -v "arguments[label]" ]]; then mkfs.fat -F 32 -n "$label" "$device" \ || die "Could not format device '$device' ($id)" else mkfs.fat -F 32 "$device" \ || die "Could not format device '$device' ($id)" fi ;; 'swap') if [[ -v "arguments[label]" ]]; then mkswap -L "$label" "$device" \ || die "Could not format device '$device' ($id)" else mkswap "$device" \ || die "Could not format device '$device' ($id)" fi # Try to swapoff in case the system enabled swap automatically swapoff "$device" &>/dev/null ;; 'ext4') if [[ -v "arguments[label]" ]]; then mkfs.ext4 -q -L "$label" "$device" \ || die "Could not format device '$device' ($id)" else mkfs.ext4 -q "$device" \ || die "Could not format device '$device' ($id)" fi ;; 'btrfs') if [[ -v "arguments[label]" ]]; then mkfs.btrfs -q -L "$label" "$device" \ || die "Could not format device '$device' ($id)" else mkfs.btrfs -q "$device" \ || die "Could not format device '$device' ($id)" fi init_btrfs "$device" "'$device' ($id)" ;; *) die "Unknown filesystem type" ;; esac } # This function will be called when a custom zfs pool type has been chosen. # $1: either 'true' or 'false' determining if the datasets should be encrypted # $2: either 'false' or a value determining the dataset compression algorithm # $3: a string describing all device paths (for error messages) # $@: device paths function format_zfs_standard() { local encrypt="$1" local compress="$2" local device_desc="$3" shift 3 local devices=("$@") local extra_args=() einfo "Creating zfs pool on $devices_desc" local zfs_stdin="" if [[ "$encrypt" == true ]]; then extra_args+=( "-O" "encryption=aes-256-gcm" "-O" "keyformat=passphrase" "-O" "keylocation=prompt" ) zfs_stdin="$GENTOO_INSTALL_ENCRYPTION_KEY" fi # dnodesize=legacy might be needed for GRUB2, but auto is preferred for xattr=sa. zpool create \ -R "$ROOT_MOUNTPOINT" \ -o ashift=12 \ -O acltype=posix \ -O atime=off \ -O xattr=sa \ -O dnodesize=auto \ -O mountpoint=none \ -O canmount=noauto \ -O devices=off \ "${extra_args[@]}" \ rpool \ "${devices[@]}" \ <<< "$zfs_stdin" \ || die "Could not create zfs pool on $devices_desc" if [[ "$compress" != false ]]; then zfs set "compression=$compress" rpool \ || die "Could enable compression on dataset 'rpool'" fi zfs create rpool/ROOT \