mirror of
https://codeberg.org/privacy1st/arch
synced 2024-12-23 01:16:04 +01:00
398 lines
12 KiB
Bash
Executable File
398 lines
12 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# load config
|
|
source /etc/de-p1st-installer/installer.cfg || { exit 1; }
|
|
|
|
# load functions
|
|
source /usr/lib/de-p1st-installer/util.sh || { exit 1; }
|
|
source /usr/lib/de-p1st-installer/user-input.sh || { exit 1; }
|
|
source /usr/lib/de-p1st-installer/block-device.sh || { exit 1; }
|
|
|
|
|
|
function check_network() {
|
|
echo "Sending ping to wikipedia.de ..."
|
|
ping -c 1 wikipedia.de >/dev/null || {
|
|
echo "Pleas set up network access."
|
|
return 1
|
|
}
|
|
}
|
|
|
|
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 || return $?
|
|
}
|
|
|
|
function get_user_input() {
|
|
# @post
|
|
# BIOS_TYPE (uefi or bios)
|
|
# FS (BTRFS, EXT4, F2FS)
|
|
# HOSTNAME
|
|
# USERNAME, USER_PWD
|
|
# LUKS_PWD
|
|
|
|
get_block_devices_with_size || return $?
|
|
get_single_choice TARGET_BLOCK_DEVICE "Select target device for installation" BLOCK_DEVICE_SIZES || return $?
|
|
|
|
if [ "${BIOS_TYPE}" = "autodetect" ]; then
|
|
# Detect BIOS type: https://askubuntu.com/a/162573
|
|
|
|
# Check exit code; if 0 EFI, else BIOS.
|
|
# "-q": tell grep to output nothing
|
|
if dmesg | grep -q "EFI v"; then
|
|
echo "Detected EFI boot."
|
|
BIOS_TYPE="uefi"
|
|
else
|
|
echo "Detected BIOS boot"
|
|
BIOS_TYPE="bios"
|
|
fi
|
|
|
|
else
|
|
# Let user select BIOS type
|
|
|
|
TMP1=('uefi' 'Newer mainboards' 'bios' 'Legacy BIOS on older mainboards')
|
|
get_single_choice BIOS_TYPE "Select your bios type" TMP1 || return $?
|
|
fi
|
|
|
|
TMP1=('BTRFS' 'Allows snapshots and dynamic extension of the FS' 'EXT4' 'Default FS of many distributions' 'F2FS' 'Flash-Friendly-FS for SSD or NVMe')
|
|
get_single_choice FS "Select filesystem to use" TMP1 || return $?
|
|
|
|
get_text_input HOSTNAME "Enter hostname:" || return $?
|
|
get_text_input USERNAME "Enter username:" || return $?
|
|
|
|
if [ -z "${USER_PWD}" ]; then
|
|
get_text_input USER_PWD "Enter a user password:" || return $?
|
|
get_text_input USER_PWD2 "Please enter the password again:" || return $?
|
|
[[ "${USER_PWD}" == "${USER_PWD2}" ]] || {
|
|
echo "Passwords did not match";
|
|
exit 1;
|
|
}
|
|
fi
|
|
if [ -z "${LUKS_PWD}" ]; then
|
|
get_text_input LUKS_PWD "Enter a disk encryption password:" || return $?
|
|
get_text_input LUKS_PWD2 "Please enter the password again:" || return $?
|
|
[[ "${LUKS_PWD}" == "${LUKS_PWD2}" ]] || {
|
|
echo "Passwords did not match";
|
|
exit 1;
|
|
}
|
|
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)
|
|
# https://wiki.archlinux.org/index.php/Ext4#Enabling_metadata_checksums
|
|
# If the CPU supports SSE 4.2, make sure the crc32c_intel kernel module is loaded
|
|
FS_DEFAULT_MOUNT_OPTIONS+=('metadata_csum')
|
|
;;
|
|
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 choose_mount_options() {
|
|
# @pre
|
|
# FS
|
|
# @post
|
|
# FS_CHOSEN_MOUNT_OPTIONS (array)
|
|
|
|
case "${FS}" in
|
|
BTRFS)
|
|
# noatime, nodiratime:
|
|
# - The atime options do impact drive performance;
|
|
# - noatime implies nodiratime, one does not need to specify both;
|
|
# - The noatime option 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.
|
|
TMP1=('noatime' "Don't write file/folder access times" 'on' 'ssd' 'Enable if using SSD/NVMe' 'off')
|
|
;;
|
|
EXT4)
|
|
TMP1=('noatime'" Don't write file/folder access times" 'on')
|
|
;;
|
|
F2FS)
|
|
TMP1=('noatime' "Don't write file/folder access times" 'on')
|
|
;;
|
|
*)
|
|
echo "Filesystem $FS not yet supported!"
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
get_multi_choice FS_CHOSEN_MOUNT_OPTIONS "Select mount options" TMP1 || return $?
|
|
}
|
|
|
|
function run_pacstrap() {
|
|
# @pre
|
|
# BIOS_TYPE
|
|
|
|
echo "Running pacstrap ..."
|
|
PKGS=("${ADDITIONAL_PKGS[@]}")
|
|
|
|
case "${BIOS_TYPE}" in
|
|
uefi)
|
|
PKGS+=('de-p1st-base')
|
|
;;
|
|
bios)
|
|
echo "Not yet implemented"
|
|
return 1
|
|
;;
|
|
*)
|
|
echo "Not yet implemented!"
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
# If CPU_VENDOR is not empty, then
|
|
if [ -n "${CPU_VENDOR}" ]; then
|
|
case "${CPU_VENDOR}" in
|
|
amd)
|
|
PKGS+=('de-p1st-ucode-amd')
|
|
;;
|
|
intel)
|
|
PKGS+=('de-p1st-ucode-intel')
|
|
;;
|
|
none)
|
|
PKGS+=('de-p1st-ucode-placeholder')
|
|
;;
|
|
*)
|
|
echo "Invalid option '${CPU_VENDOR}'!"
|
|
return 1
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
local args=()
|
|
if [ "${PACSTRAP_INTERACTIVE}" = "1" ]; then
|
|
args+=('-i') # run interactively
|
|
fi
|
|
args+=('/mnt')
|
|
|
|
sudo pacstrap "${args[@]}" "${PKGS[@]}" || return $?
|
|
}
|
|
|
|
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]\+//') || return $?
|
|
# Check if fstab does still contain subvolid mount option
|
|
if printf "%s" "${fstab}" | grep -q 'subvolid='; then
|
|
echo "This should not happen!"
|
|
return 1
|
|
fi
|
|
;;
|
|
EXT4)
|
|
true
|
|
;;
|
|
F2FS)
|
|
true
|
|
;;
|
|
*)
|
|
echo "Filesystem $FS not yet supported!"
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
printf "%s" "${fstab}" | sudo tee /mnt/etc/fstab >/dev/null || return $?
|
|
}
|
|
|
|
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, e.g. 1)
|
|
|
|
echo "Set hostname ..."
|
|
echo "${HOSTNAME}" | sudo tee /mnt/etc/hostname >/dev/null || return $?
|
|
|
|
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 || return $?
|
|
|
|
if [ "${IPV6_CAPABLE}" = "1" ]; 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 || return $?
|
|
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}" || return $?
|
|
sudo arch-chroot /mnt chsh -s /usr/bin/zsh || return $?
|
|
|
|
# If ROOT_PWD is not given, the use USER_PWD for root user
|
|
ROOT_PWD="${ROOT_PWD:="${USER_PWD}"}"
|
|
|
|
printf "%s:%s" "${USERNAME}" "${USER_PWD}" | sudo chpasswd --root /mnt || return $?
|
|
printf "%s:%s" "root" "${ROOT_PWD}" | sudo chpasswd --root /mnt || return $?
|
|
}
|
|
|
|
function bootloader() {
|
|
# @pre
|
|
# TARGET_BLOCK_DEVICE
|
|
# LUKS_PART_UUID
|
|
|
|
echo "Installing grub ..."
|
|
case "${BIOS_TYPE}" 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 || return $?
|
|
;;
|
|
bios)
|
|
sudo arch-chroot /mnt grub-install --target=i386-pc "${TARGET_BLOCK_DEVICE}" || return $?
|
|
;;
|
|
*)
|
|
echo "Not yet implemented!"
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
echo "Generating /boot/grub/grub.cfg ..."
|
|
{
|
|
# /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}" || return $?
|
|
sudo echo '#!/bin/sh
|
|
sed "s|^GRUB_CMDLINE_LINUX=.*\$|GRUB_CMDLINE_LINUX=\"cryptdevice=/dev/disk/by-uuid/'"${LUKS_PART_UUID}"':crypt\"|"' \
|
|
| sudo tee "${holoScriptDir}"/grub.holoscript || return $?
|
|
sudo chmod 0544 "${holoScriptDir}"/grub.holoscript || return $?
|
|
}
|
|
# Then we apply the holoscript
|
|
sudo arch-chroot /mnt holo apply -f file:/etc/default/grub || return $?
|
|
# And finally run grub-mkconfig
|
|
sudo arch-chroot /mnt grub-mkconfig -o /boot/grub/grub.cfg || return $?
|
|
}
|
|
}
|
|
|
|
function main() {
|
|
# @pre
|
|
# bash libraries imported
|
|
# @post
|
|
# installation finished
|
|
|
|
check_network || return $?
|
|
# out: BIOS_TYPE, FS, HOSTNAME, USERNAME, USER_PWD, LUKS_PWD
|
|
get_user_input || return $?
|
|
# in: CPU_VENDOR (optional)
|
|
# out: CPU_VENDOR
|
|
get_cpu_vendor || return $?
|
|
|
|
# in: FS
|
|
# out: FS_DEFAULT_MOUNT_OPTIONS
|
|
get_default_mount_options || return $?
|
|
# in: FS
|
|
# out: FS_CHOSEN_MOUNT_OPTIONS
|
|
choose_mount_options || return $?
|
|
|
|
# in: TARGET_BLOCK_DEVICE, BIOS_TYPE
|
|
# out: BOOT_PART, LUKS_PART
|
|
partition || return $?
|
|
# in: BIOS_TYPE, BOOT_PART, LUKS_PART, LUKS_PWD, FS
|
|
# out: LUKS_PART_UUID, DATA_PART
|
|
format || return $?
|
|
|
|
# Combine default and chosen mount options
|
|
TMP1=("${FS_DEFAULT_MOUNT_OPTIONS[@]}" "${FS_CHOSEN_MOUNT_OPTIONS[@]}") || return $?
|
|
# Join array elements by ","
|
|
join_by "," TMP1 FS_MOUNT_OPTIONS || return $?
|
|
|
|
echo "Mounting data partition with options: ${FS_MOUNT_OPTIONS}"
|
|
sudo mount -o "${FS_MOUNT_OPTIONS}" "$DATA_PART" /mnt || return $?
|
|
|
|
echo "Mounting boot partition ..."
|
|
mkdir /mnt/boot || return $?
|
|
sudo mount "$BOOT_PART" /mnt/boot || return $?
|
|
|
|
# in: BIOS_TYPE
|
|
run_pacstrap || return $?
|
|
# in: FS
|
|
run_genfstab || return $?
|
|
|
|
# in: HOSTNAME, FQDN (optional), STATIC_IP (optional), IPV6_CAPABLE (optional)
|
|
config_hostname_and_hosts || return $?
|
|
# in: USERNAME, USER_PWD, ROOT_PWD (optional)
|
|
user_and_pwd || return $?
|
|
|
|
sudo arch-chroot /mnt mkinitcpio -P || return $?
|
|
# in: TARGET_BLOCK_DEVICE, LUKS_PART_UUID
|
|
bootloader || return $?
|
|
|
|
if [ "${LEAVE_MOUNTED}" -eq "1" ]; then
|
|
echo "Leaving partitions below /mnt mounted and ${DATA_PART} opened."
|
|
else
|
|
sudo umount -R /mnt || return $?
|
|
sudo cryptsetup luksClose "$(basename "${DATA_PART}")" || return $?
|
|
fi
|
|
echo "Finished installation without errors!"
|
|
}
|
|
|
|
main "$@"
|