999 lines · 28.9 KB · Shell
RawDownload
# 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="← bios" ;;		"${DISK_ID_EFI-__unused__}")   ptr="← efi"  ;;		"${DISK_ID_SWAP-__unused__}")  ptr="← swap" ;;		"${DISK_ID_ROOT-__unused__}")  ptr="← root" ;;		# \x1f characters compensate for printf byte count and unicode character count mismatch due to '←'		*)                             ptr="$(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 ' "$arg=${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.