mirror of
https://codeberg.org/privacy1st/arch-installer
synced 2024-12-22 02:16:04 +01:00
650 lines
19 KiB
Bash
Executable File
650 lines
19 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Exit on error.
|
|
set -e
|
|
# Exit on undefined variable reference.
|
|
set -u
|
|
|
|
script_dir="$(dirname "${BASH_SOURCE[0]}")"
|
|
|
|
function script_is_installed(){
|
|
# Check if this script is run installed or locally (development setup).
|
|
[ "${script_dir}" = '/usr/bin' ]
|
|
}
|
|
|
|
if script_is_installed; then
|
|
lib_dir='/usr/lib/de-p1st-installer'
|
|
else
|
|
lib_dir='./lib'
|
|
# Print commands before they get executed.
|
|
set -v
|
|
fi
|
|
|
|
# Source library files.
|
|
# shellcheck source=lib/validate-args.sh
|
|
source "${lib_dir}"/validate-args.sh
|
|
# shellcheck source=lib/util.sh
|
|
source "${lib_dir}"/util.sh
|
|
# shellcheck source=lib/user-input.sh
|
|
source "${lib_dir}"/user-input.sh
|
|
# shellcheck source=lib/block-device.sh
|
|
source "${lib_dir}"/block-device.sh
|
|
|
|
# Get path of configuration file.
|
|
if [ $# -eq 0 ]; then
|
|
# No arguments given.
|
|
if script_is_installed; then
|
|
cfg_file=/etc/de-p1st-installer/installer.cfg
|
|
else
|
|
cfg_file="${script_dir}"/installer.cfg
|
|
fi
|
|
else
|
|
# >= 1 arguments given.
|
|
# First argument is the configuration file!
|
|
cfg_file="${1}"
|
|
fi
|
|
|
|
# Source the configuration file.
|
|
# shellcheck source=installer.cfg
|
|
source "${cfg_file}"
|
|
|
|
function main() {
|
|
# @pre
|
|
# bash libraries imported
|
|
# @post
|
|
# installation finished
|
|
|
|
scrollback
|
|
check_network
|
|
system_time
|
|
repository
|
|
|
|
# in: BOOT_PART_SIZE, BOOT_FIRMWARE, INITRAMFS, FS, HOSTNAME, USERNAME, USER_PWD, FDE, LUKS_PWD; (all variables are optional)
|
|
# out: BOOT_PART_SIZE, BOOT_FIRMWARE, INITRAMFS, FS, HOSTNAME, USERNAME, USER_PWD, FDE, LUKS_PWD (if FDE='true')
|
|
get_user_input
|
|
# in: CPU_VENDOR (optional)
|
|
# out: CPU_VENDOR
|
|
get_cpu_vendor CPU_VENDOR
|
|
|
|
# in: FS
|
|
# out: FS_DEFAULT_MOUNT_OPTIONS
|
|
get_default_mount_options
|
|
# in: FS
|
|
# out: FS_ADDITIONAL_MOUNT_OPTIONS
|
|
get_additional_mount_options
|
|
|
|
# out: BOOT_PART, LUKS_PART
|
|
partition \
|
|
"${TARGET_BLOCK_DEVICE}" "${BOOT_FIRMWARE}" "${BOOT_PART_SIZE}" \
|
|
BOOT_PART LUKS_PART
|
|
# out: LUKS_PART_UUID (if FDE='true'), DATA_PART
|
|
format \
|
|
"${BOOT_PART}" "${LUKS_PART}" "${LUKS_PWD}" "${FDE}" "${FS}" \
|
|
LUKS_PART_UUID DATA_PART
|
|
|
|
# Join default and additional mount options by ','
|
|
# shellcheck disable=SC2034
|
|
FS_MOUNT_OPTIONS_ARRAY=("${FS_DEFAULT_MOUNT_OPTIONS[@]}" "${FS_ADDITIONAL_MOUNT_OPTIONS[@]}")
|
|
join_by ',' FS_MOUNT_OPTIONS_ARRAY FS_MOUNT_OPTIONS
|
|
|
|
mount_partitions
|
|
|
|
# in: BOOT_FIRMWARE, INITRAMFS, PACSTRAP_INTERACTIVE (optional)
|
|
run_pacstrap
|
|
# in: FS
|
|
run_genfstab
|
|
|
|
# in: HOSTNAME, FQDN (optional), STATIC_IP (optional), IPV6_CAPABLE (optional)
|
|
config_hostname_and_hosts
|
|
# in: USERNAME, USER_PWD, ROOT_PWD (optional)
|
|
user_and_pwd
|
|
|
|
# in: INITRAMFS
|
|
initramfs
|
|
# in: TARGET_BLOCK_DEVICE, FDE, LUKS_PART_UUID
|
|
bootloader
|
|
|
|
unmount_partitions
|
|
|
|
echo 'Finished installation without errors!'
|
|
}
|
|
|
|
function scrollback(){
|
|
if ! grep --quiet '^defscrollback' /etc/screenrc; then
|
|
printf '\n%s\n' "defscrollback 100000" | sudo tee -a /etc/screenrc
|
|
printf '%s\n' 'Extended screen scrollback history. Pleas create a new screen session and run the installer again.'
|
|
return 1
|
|
fi
|
|
|
|
if [ -z "${STY:-}" ]; then
|
|
printf '%s\n' 'Pleas run the installer from a screen session.'
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
function check_network() {
|
|
echo 'Sending ping to wikipedia.de ...'
|
|
ping -c 1 wikipedia.de >/dev/null || {
|
|
echo 'Pleas set up network access and then run the installer again.'
|
|
return 1
|
|
}
|
|
}
|
|
|
|
function system_time() {
|
|
# Use timedatectl(1) to ensure the system clock is accurate
|
|
timedatectl set-ntp true
|
|
}
|
|
|
|
function repository(){
|
|
# Check if the [de-p1st] repository is available.
|
|
# If not, add it to pacman.conf
|
|
|
|
if ! grep --quiet 'de-p1st' /etc/pacman.conf; then
|
|
printf '%s\n' 'Enabling [de-p1st] package repository:'
|
|
|
|
printf '\n%s\n' "[de-p1st]
|
|
SigLevel = Optional TrustAll
|
|
Server = https://arch.p1st.de" | sudo tee -a /etc/pacman.conf
|
|
fi
|
|
}
|
|
|
|
function increase_cow_space() {
|
|
# May be useful when running 'pacman -Syu' on the live medium.
|
|
# Usually not necessary!
|
|
|
|
# Make sure that we are on a live medium:
|
|
findmnt /run/archiso/cowspace >/dev/null || {
|
|
echo 'Not on live medium, did not increase cowspace!'
|
|
return 1
|
|
}
|
|
|
|
echo 'Increasing cowspace partition of live medium ...'
|
|
sudo mount -o remount,size=2G /run/archiso/cowspace
|
|
}
|
|
|
|
function get_user_input() {
|
|
# @post
|
|
# BOOT_PART_SIZE
|
|
# BOOT_FIRMWARE: 'uefi' | 'bios'
|
|
# INITRAMFS: 'mkinitcpio' | 'dracut'
|
|
# FS: 'BTRFS' | 'EXT4' | 'F2FS'
|
|
# FS_BTRFS_SUBVOL_LAYOUT: 'root_only' | '@root@home'
|
|
# HOSTNAME
|
|
# USERNAME, USER_PWD
|
|
# FDE: 'true' | 'false'
|
|
# LUKS_PWD: only set if FDE='true'
|
|
|
|
# out: BLOCK_DEVICE_SIZES
|
|
get_block_devices_with_size BLOCK_DEVICE_SIZES
|
|
single_choice_if_empty TARGET_BLOCK_DEVICE 'Select target device for installation' BLOCK_DEVICE_SIZES
|
|
|
|
ask_user_if_empty BOOT_PART_SIZE 'Enter boot partition size in MiB, at least 260:'
|
|
|
|
if [ "${BOOT_FIRMWARE}" = 'autodetect' ]; then
|
|
# Detect boot firmware type: https://askubuntu.com/a/162573
|
|
|
|
# Check exit code; if 0 EFI, else BIOS.
|
|
if dmesg | grep --quiet --fixed-strings 'EFI v'; then
|
|
echo 'Detected EFI boot.'
|
|
BOOT_FIRMWARE='uefi'
|
|
else
|
|
echo 'Detected BIOS boot'
|
|
BOOT_FIRMWARE='bios'
|
|
fi
|
|
|
|
else # If $BOOT_FIRMWARE is empty: Let user select BIOS type
|
|
# shellcheck disable=SC2034
|
|
BOOT_FIRMWARE_QUESTION=('uefi' 'Newer mainboards' \
|
|
'bios' 'Legacy BIOS on older mainboards')
|
|
single_choice_if_empty BOOT_FIRMWARE 'Select your bios type' BOOT_FIRMWARE_QUESTION
|
|
fi
|
|
|
|
# shellcheck disable=SC2034
|
|
INITRAMFS_QUESTION=('mkinitcpio' 'Default for Arch Linux' \
|
|
'dracut' 'Testing')
|
|
single_choice_if_empty INITRAMFS 'Select filesystem to use' INITRAMFS_QUESTION
|
|
|
|
# shellcheck disable=SC2034
|
|
FS_QUESTION=('BTRFS' 'Allows snapshots and dynamic extension of the FS' \
|
|
'EXT4' 'Default FS of many distributions' \
|
|
'F2FS' 'Flash-Friendly-FS for SSD or NVMe')
|
|
single_choice_if_empty FS 'Select filesystem to use' FS_QUESTION
|
|
|
|
if [ "${FS}" = 'BTRFS' ]; then
|
|
# shellcheck disable=SC2034
|
|
FS_QUESTION2=('root_only' 'Just one subvolume for "/".' \
|
|
'@root@home' 'Two subvolumes @ and @home. This configuration allows usage of "Timeshift".')
|
|
single_choice_if_empty FS_BTRFS_SUBVOL_LAYOUT 'Select your preferred subvolume layout' FS_QUESTION2
|
|
fi
|
|
|
|
ask_user_if_empty HOSTNAME 'Enter hostname:'
|
|
ask_user_if_empty USERNAME 'Enter username:'
|
|
|
|
# If USER_PWD is empty
|
|
if [ -z "${USER_PWD}" ]; then
|
|
ask_user_if_empty USER_PWD 'Enter a user password:'
|
|
ask_user_if_empty USER_PWD2 'Please enter the password again:'
|
|
# shellcheck disable=SC2153
|
|
if [ "${USER_PWD}" != "${USER_PWD2}" ]; then
|
|
echo 'Passwords did not match'
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# shellcheck disable=SC2034
|
|
FDE_QUESTION=('true' 'Yes' 'false' 'No')
|
|
single_choice_if_empty FDE 'Shall Full-Disk-Encryption be enabled?' FDE_QUESTION
|
|
|
|
# If FDE enabled but LUKS_PWD is empty
|
|
if [ "${FDE}" = 'true' ] && [ -z "${LUKS_PWD}" ]; then
|
|
ask_user_if_empty LUKS_PWD 'Enter a disk encryption password:'
|
|
ask_user_if_empty LUKS_PWD2 'Please enter the password again:'
|
|
# shellcheck disable=SC2153
|
|
if [ "${LUKS_PWD}" != "${LUKS_PWD2}" ]; then
|
|
echo 'Passwords did not match'
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# ADDITIONAL_PKGS is an array, but all elements should be non-empty.
|
|
# Thus, it is ok if we do only check the first element.
|
|
if [ -z "${ADDITIONAL_PKGS:-}" ]; then
|
|
ask_user_if_empty ADDITIONAL_PKGS 'Additional packages to install (separated by space):'
|
|
space_separated_to_array ADDITIONAL_PKGS ADDITIONAL_PKGS || return $?
|
|
fi
|
|
}
|
|
|
|
function get_default_mount_options() {
|
|
# @pre
|
|
# FS
|
|
# @post
|
|
# FS_DEFAULT_MOUNT_OPTIONS (array)
|
|
|
|
FS_DEFAULT_MOUNT_OPTIONS=()
|
|
|
|
case "${FS}" in
|
|
BTRFS)
|
|
# "compress=lzo": archwiki -> Btrfs#Compression
|
|
# "compress=zstd:1":
|
|
# -> https://btrfs.wiki.kernel.org/index.php/Compression#What_are_the_differences_between_compression_methods.3F
|
|
# -> https://fedoraproject.org/wiki/Changes/BtrfsTransparentCompression#Q:_Why_use_zstd:1_specifically.3F
|
|
#
|
|
# "Enable compression (better performance, longer flash lifespan)"
|
|
FS_DEFAULT_MOUNT_OPTIONS+=('compress=zstd:1')
|
|
;;
|
|
EXT4)
|
|
FS_DEFAULT_MOUNT_OPTIONS+=()
|
|
;;
|
|
F2FS)
|
|
# When mounting the filesystem, specify compress_algorithm=(lzo|lz4|zstd|lzo-rle).
|
|
# Using compress_extension=txt will cause all txt files to be compressed by default.
|
|
FS_DEFAULT_MOUNT_OPTIONS+=('compress_algorithm=lz4')
|
|
;;
|
|
*)
|
|
echo 'Filesystem '"${FS}"' not yet supported!'
|
|
return 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
function get_additional_mount_options() {
|
|
# @pre
|
|
# FS
|
|
# @post
|
|
# FS_ADDITIONAL_MOUNT_OPTIONS (array)
|
|
|
|
case "${FS}" in
|
|
BTRFS)
|
|
# noatime, nodiratime:
|
|
# - `atime` impacts drive performance
|
|
# - `noatime` implies `nodiratime`, one does not need to specify both
|
|
# - `noatime` fully disables writing file access times to the drive every time you read a file.
|
|
# This works well for almost all applications, except for those that need to know if a file has been
|
|
# read since the last time it was modified.
|
|
FS_ADDITIONAL_MOUNT_OPTIONS_QUESTION=('noatime' 'Don'\''t write file/folder access times' 'on' 'ssd' 'Enable if using SSD/NVMe' 'off')
|
|
;;
|
|
EXT4)
|
|
FS_ADDITIONAL_MOUNT_OPTIONS_QUESTION=('noatime' 'Don'\''t write file/folder access times' 'on')
|
|
;;
|
|
F2FS)
|
|
# shellcheck disable=SC2034
|
|
FS_ADDITIONAL_MOUNT_OPTIONS_QUESTION=('noatime' 'Don'\''t write file/folder access times' 'on')
|
|
;;
|
|
*)
|
|
echo 'Filesystem '"${FS}"' not yet supported!'
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
multi_choice_if_empty FS_ADDITIONAL_MOUNT_OPTIONS 'Select mount options' FS_ADDITIONAL_MOUNT_OPTIONS_QUESTION
|
|
}
|
|
|
|
function mount_partitions() {
|
|
# @pre
|
|
# FS, FS_BTRFS_SUBVOL_LAYOUT, FS_MOUNT_OPTIONS, DATA_PART, BOOT_PART
|
|
|
|
if [ "${FS}" = 'BTRFS' ]; then
|
|
case "${FS_BTRFS_SUBVOL_LAYOUT}" in
|
|
'root_only')
|
|
# Nothing special; same steps as for a regular FS
|
|
echo 'Mounting data partition with options: '"${FS_MOUNT_OPTIONS}"
|
|
sudo mount -o "${FS_MOUNT_OPTIONS}" "${DATA_PART}" /mnt
|
|
;;
|
|
'@root@home')
|
|
# Timeshift BTRFS subvol layout:
|
|
# https://github.com/teejee2008/timeshift#supported-system-configurations
|
|
|
|
# Mount top level subvolume
|
|
sudo mount -o subvolid=5 "${DATA_PART}" /mnt
|
|
# Create subvolumes @ and @home
|
|
sudo btrfs subvolume create /mnt/@
|
|
sudo btrfs subvolume create /mnt/@home
|
|
# List the created subvolumes
|
|
sudo btrfs subvolume list /mnt
|
|
# Umount the top level subvolume
|
|
sudo umount -R /mnt
|
|
|
|
echo 'Mounting @ and @home subvolumes with options: '"${FS_MOUNT_OPTIONS}"
|
|
sudo mount -o 'subvol=@,'"${FS_MOUNT_OPTIONS}" "${DATA_PART}" /mnt
|
|
sudo mkdir /mnt/home
|
|
sudo mount -o 'subvol=@home,'"${FS_MOUNT_OPTIONS}" "${DATA_PART}" /mnt/home
|
|
;;
|
|
*)
|
|
echo 'BTRFS subvolume layout '"${FS_BTRFS_SUBVOL_LAYOUT}"' not supported!'
|
|
return 1
|
|
;;
|
|
esac
|
|
else
|
|
echo 'Mounting data partition with options: '"${FS_MOUNT_OPTIONS}"
|
|
sudo mount -o "${FS_MOUNT_OPTIONS}" "${DATA_PART}" /mnt
|
|
fi
|
|
|
|
echo 'Mounting boot partition ...'
|
|
sudo mkdir /mnt/boot
|
|
sudo mount "${BOOT_PART}" /mnt/boot
|
|
|
|
# Print information about partitions.
|
|
lsblk --tree=PATH -o PATH,TYPE,UUID
|
|
}
|
|
|
|
function run_pacstrap() {
|
|
# @pre
|
|
# BOOT_FIRMWARE
|
|
# PACSTRAP_INTERACTIVE: optional, 'true'
|
|
|
|
echo 'Running pacstrap ...'
|
|
PKGS=("${ADDITIONAL_PKGS[@]}")
|
|
|
|
case "${BOOT_FIRMWARE}" in
|
|
uefi)
|
|
PKGS+=('de-p1st-base')
|
|
;;
|
|
bios)
|
|
echo 'Not yet implemented'
|
|
return 1
|
|
;;
|
|
*)
|
|
echo 'Not yet implemented!'
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
case "${INITRAMFS}" in
|
|
mkinitcpio)
|
|
PKGS+=('de-p1st-mkinitcpio')
|
|
;;
|
|
dracut)
|
|
PKGS+=('dracut')
|
|
# PKGS+=('binutils') # for --uefi (Unified Kernel Image) option
|
|
PKGS+=('elfutils') # reduced initramfs size
|
|
PKGS+=('multipath-tools') # dracut module support
|
|
;;
|
|
*)
|
|
echo 'Invalid option: '"${INITRAMFS}"
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
case "${CPU_VENDOR}" in
|
|
amd)
|
|
PKGS+=('de-p1st-ucode-amd')
|
|
;;
|
|
intel)
|
|
PKGS+=('de-p1st-ucode-intel')
|
|
;;
|
|
none)
|
|
PKGS+=('de-p1st-ucode-none')
|
|
;;
|
|
*)
|
|
echo 'Invalid option: '"${CPU_VENDOR}"
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
local args=()
|
|
if [ "${PACSTRAP_INTERACTIVE}" = 'true' ]; then
|
|
args+=('-i') # Run interactively
|
|
fi
|
|
|
|
sudo pacstrap -K "${args[@]}" /mnt "${PKGS[@]}"
|
|
}
|
|
|
|
function run_genfstab() {
|
|
# @pre
|
|
# FS
|
|
|
|
echo 'Generating fstab ...'
|
|
local fstab
|
|
fstab="$(genfstab -U /mnt)"
|
|
|
|
case "${FS}" in
|
|
BTRFS)
|
|
# Remove "subvolid=..." mount option but leave "subvol=..." mount option
|
|
fstab=$(printf '%s' "${fstab}" | sed 's/,subvolid=[^,\s]\+//')
|
|
# Check if fstab does still contain subvolid mount option
|
|
if printf '%s' "${fstab}" | grep --quiet 'subvolid='; then
|
|
echo 'This should not happen!'
|
|
return 1
|
|
fi
|
|
;;
|
|
EXT4)
|
|
true
|
|
;;
|
|
F2FS)
|
|
true
|
|
;;
|
|
*)
|
|
printf '%s\n' "Filesystem ${FS} not yet supported!"
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
echo 'Generating fstab'
|
|
printf '%s' "${fstab}" | sudo tee /mnt/etc/fstab
|
|
}
|
|
|
|
function config_hostname_and_hosts() {
|
|
# @pre
|
|
# HOSTNAME
|
|
# FQDN: optional, e.g. sub.domain.de
|
|
# STATIC_IP: optional, e.g. 93.133.433.133
|
|
# IPV6_CAPABLE: optional, 'true'
|
|
|
|
echo 'Set hostname ...'
|
|
echo "${HOSTNAME}" | sudo tee /mnt/etc/hostname >/dev/null
|
|
|
|
echo 'Create hosts file ...'
|
|
# If the system has a permanent IP address, it should be used instead of 127.0.1.1.
|
|
# * https://wiki.archlinux.org/index.php/Installation_guide#Network_configuration
|
|
|
|
# Desirable entries IPv4/IPv6:
|
|
# * https://man.archlinux.org/man/hosts.5#EXAMPLES
|
|
|
|
# If FQDN not given, use $HOSTNAME.localdomain instead
|
|
FQDN="${FQDN:="${HOSTNAME}.localdomain"}"
|
|
# If STATIC_IP not given, use 127.0.1.1 instead
|
|
STATIC_IP="${STATIC_IP:=127.0.1.1}"
|
|
|
|
echo '# The following lines are desirable for IPv4 capable hosts
|
|
127.0.0.1 localhost
|
|
# 127.0.1.1 is often used for the FQDN of the machine
|
|
'"${STATIC_IP} ${FQDN} ${HOSTNAME}" | sudo tee /mnt/etc/hosts >/dev/null
|
|
|
|
if [ "${IPV6_CAPABLE}" = 'true' ]; then
|
|
echo '
|
|
# The following lines are desirable for IPv6 capable hosts
|
|
::1 localhost ip6-localhost ip6-loopback
|
|
ff02::1 ip6-allnodes
|
|
ff02::2 ip6-allrouters' | sudo tee -a /mnt/etc/hosts >/dev/null
|
|
fi
|
|
}
|
|
|
|
function user_and_pwd() {
|
|
# @pre
|
|
# USERNAME
|
|
# USER_PWD
|
|
# ROOT_PWD (optional)
|
|
|
|
echo 'Adding user and changing shell to /bin/zsh ...'
|
|
# -m: Create home
|
|
# -U: Create a group with the same name as the user, and add the user to this group.
|
|
sudo arch-chroot /mnt useradd -m -s /usr/bin/zsh -g wheel "${USERNAME}"
|
|
sudo arch-chroot /mnt chsh -s /usr/bin/zsh
|
|
|
|
if [ -z "${ROOT_PWD:-}" ]; then
|
|
printf '%s\n' 'No root password given, using the user password for root'
|
|
ROOT_PWD="${USER_PWD}"
|
|
fi
|
|
|
|
printf '%s:%s' "${USERNAME}" "${USER_PWD}" | sudo chpasswd --root /mnt
|
|
printf '%s:%s' "root" "${ROOT_PWD}" | sudo chpasswd --root /mnt
|
|
}
|
|
|
|
function initramfs(){
|
|
# @pre
|
|
# INITRAMFS
|
|
|
|
case "${INITRAMFS}" in
|
|
mkinitcpio)
|
|
sudo arch-chroot /mnt mkinitcpio -P
|
|
;;
|
|
dracut)
|
|
# configuration
|
|
# https://man.archlinux.org/man/dracut.conf.5
|
|
# https://man.archlinux.org/man/dracut.cmdline.7
|
|
|
|
install -m0644 /dev/stdin /mnt/etc/dracut.conf.d/de-p1st.conf << 'EOF'
|
|
# --fstab
|
|
use_fstab=yes
|
|
# --show-modules
|
|
show_modules=yes
|
|
|
|
# https://wiki.archlinux.org/title/Dracut#LVM_/_software_RAID_/_LUKS
|
|
kernel_cmdline="rd.auto rd.luks=1"
|
|
EOF
|
|
|
|
# TODO:
|
|
# Use a hook to do this
|
|
# on the running system after each
|
|
# kernel upgrade.
|
|
#
|
|
# => use kernel-install-for-dracut
|
|
# https://forum.endeavouros.com/t/call-for-testing-kernel-install-for-dracut/30910
|
|
|
|
# https://wiki.archlinux.org/title/Dracut#Generate_a_new_initramfs_on_kernel_upgrade
|
|
# - detect kernel version
|
|
# - install vmlinuz
|
|
# - run dracut
|
|
|
|
for module in /mnt/lib/modules/*; do
|
|
kernel="$(basename "${module}")"
|
|
pkgbase="$(cat "${module}/pkgbase")"
|
|
|
|
install -Dm644 "${module}/vmlinuz" "/mnt/boot/vmlinuz-${pkgbase}"
|
|
|
|
echo 'Kernel command line:'
|
|
arch-chroot /mnt dracut \
|
|
--kver "${kernel}" \
|
|
--print-cmdline \
|
|
"/boot/initramfs-${pkgbase}.img"
|
|
|
|
echo 'Creating initramfs:'
|
|
arch-chroot /mnt dracut \
|
|
--kver "${kernel}" \
|
|
"/boot/initramfs-${pkgbase}.img"
|
|
done
|
|
;;
|
|
*)
|
|
echo 'Invalid option: '"${INITRAMFS}"
|
|
return 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
function bootloader() {
|
|
# @pre
|
|
# TARGET_BLOCK_DEVICE
|
|
# FDE: 'true' | 'false'
|
|
# LUKS_PART_UUID: required if FDE='true'
|
|
|
|
echo 'Installing grub:'
|
|
case "${BOOT_FIRMWARE}" in
|
|
uefi)
|
|
# Portable fallback efi name for grub:
|
|
# * https://www.rodsbooks.com/efi-bootloaders/installation.html#alternative-naming
|
|
# * arch-chroot /mnt cp /boot/EFI/GRUB/grubx64.efi /boot/EFI/BOOT/bootx64.efi
|
|
sudo arch-chroot /mnt grub-install --target=x86_64-efi --bootloader-id=GRUB --efi-directory=/boot --removable
|
|
;;
|
|
bios)
|
|
sudo arch-chroot /mnt grub-install --target=i386-pc "${TARGET_BLOCK_DEVICE}"
|
|
;;
|
|
*)
|
|
echo 'Not yet implemented!'
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
# grub.cfg adjustments
|
|
if [ "${INITRAMFS}" = 'mkinitcpio' ] && [ "${FDE}" = "true" ]; then
|
|
# /etc/default/grub is managed by Holo. Therefore we should not manually modify it.
|
|
# Instead, we create a holosript which writes $LUKS_PART_UUID into GRUB_CMDLINE_LINUX of /etc/default/grub
|
|
{
|
|
# Use filename .../20- for the holoscript so that it gets executed after the one from de-p1st-grub
|
|
local holoScriptDir=/mnt/usr/share/holo/files/20-de-p1st-installer/etc/default/
|
|
# The holoscript shall contain one 'sed "..."' command
|
|
sudo mkdir -p "${holoScriptDir}"
|
|
sudo echo "#!/bin/sh
|
|
py-regex-replace -p '^GRUB_CMDLINE_LINUX=\"\"\$' -r 'GRUB_CMDLINE_LINUX=\"cryptdevice=/dev/disk/by-uuid/${LUKS_PART_UUID}:crypt\"'
|
|
" | sudo tee "${holoScriptDir}"/grub.holoscript
|
|
sudo chmod 0544 "${holoScriptDir}"/grub.holoscript
|
|
}
|
|
# Then we apply the holoscript
|
|
sudo arch-chroot /mnt holo apply --force file:/etc/default/grub
|
|
|
|
# Print start of grub file containing GRUB_CMDLINE_LINUX
|
|
head /mnt/etc/default/grub
|
|
fi
|
|
|
|
echo 'Generating /boot/grub/grub.cfg:'
|
|
sudo arch-chroot /mnt grub-mkconfig -o /boot/grub/grub.cfg
|
|
|
|
if [ "${INITRAMFS}" = 'mkinitcpio' ] && [ "${FDE}" = "true" ]; then
|
|
printf '%s\n' 'Occurrence of "cryptdevice" in /boot/grub/grub.cfg:'
|
|
grep 'cryptdevice' /mnt/boot/grub/grub.cfg
|
|
fi
|
|
}
|
|
|
|
function unmount_partitions(){
|
|
if [ "${LEAVE_MOUNTED}" = 'true' ]; then
|
|
echo 'Leaving partitions below /mnt mounted and '"${DATA_PART}"' opened.'
|
|
else
|
|
echo 'unmount /mnt'
|
|
sudo umount -R /mnt
|
|
if [ "${FDE}" = 'true' ]; then
|
|
echo "luksClose ${DATA_PART}"
|
|
sudo cryptsetup luksClose "$(basename "${DATA_PART}")"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
main "$@"
|