From 6dd20fb29171fb48dcac012b0a1e2c73c7278ddc Mon Sep 17 00:00:00 2001 From: Tobias Strobel Date: Sun, 25 Sep 2022 17:31:16 +0200 Subject: [PATCH] New install.sh --- install.sh | 334 ++++++++++++++++++----------------------------------- 1 file changed, 115 insertions(+), 219 deletions(-) diff --git a/install.sh b/install.sh index f084bb5..5cd9e46 100644 --- a/install.sh +++ b/install.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Arch Linux installation +# Bootstrap a new Arch system from an installation ISO. # # Bootable USB: # - [Download](https://archlinux.org/download/) ISO and GPG files @@ -13,284 +13,180 @@ # - Temporarily disable Secure Boot. # - Make sure a strong UEFI administrator password is set. # - Delete preloaded OEM keys for Secure Boot, allow custom ones. -# - Set SATA operation to AHCI mode. # # Run installation: # -# - Connect to wifi via: `# iwctl station wlan0 connect WIFI-NETWORK` +# - Connect to wifi via: `# iwctl station wlan0 connect $SSID` # - Run: `# bash <(curl -sL https://link.rafe.li/dot)` # -# WARNING: this script will destroy data on the selected disk. -# -set -uo pipefail +set -xeuo pipefail trap 's=$?; echo "$0: Error on line "$LINENO": $BASH_COMMAND"; exit $s' ERR -exec 1> >(tee "stdout.log") -exec 2> >(tee "stderr.log" >&2) +exec 1> >(tee "/root/stdout.log") +exec 2> >(tee "/root/stderr.log" >&2) -export SNAP_PAC_SKIP=y +args=() +target_device="" +new_hostname="" -umount -R /mnt 2> /dev/null || true -swapoff --all -cryptsetup close swap 2> /dev/null || true -cryptsetup luksClose system 2> /dev/null || true +while [[ $# -gt 0 ]] +do + arg="$1" -# Dialog -BACKTITLE="Arch Linux installation" + case "$arg" in + "--device") + target_device="$2" + shift + shift + ;; + "--hostname") + new_hostname="$2" + shift + shift + ;; + *) + args+=("$arg") + shift; + esac +done -get_input() { - title="$1" - description="$2" +if [[ -z "$target_device" ]]; then + echo "Missing --device argument" >&2 + exit 2; +fi - input=$(dialog --clear --stdout --backtitle "$BACKTITLE" --title "$title" --inputbox "$description" 0 0) - echo "$input" -} +if [[ -z "$new_hostname" ]]; then + echo "Missing --hostname argument" >&2 + exit 2; +fi -get_password() { - title="$1" - description="$2" - while : ; do - init_pass=$(dialog --clear --stdout --backtitle "$BACKTITLE" --title "$title" --passwordbox "$description" 0 0) - : "${init_pass:?dialog --clear --stdout --backtitle "$BACKTITLE" --title "$title" --msgbox "Password cannot be empty.\nTry again." 0 0}" +if [[ "${#args[@]}" -ne 0 ]]; then + echo "Unexpected extra arguments: ${args[*]}" >&2 + exit 2 +fi - test_pass=$(dialog --clear --stdout --backtitle "$BACKTITLE" --title "$title" --passwordbox "$description again" 0 0) - if [[ "$init_pass" != "$test_pass" ]]; then - dialog --clear --stdout --backtitle "$BACKTITLE" --title "$title" --msgbox "Passwords did not match.\nTry again." 0 0 - else - break - fi - done - echo "$init_pass" -} - -get_choice() { - title="$1" - description="$2" - shift 2 - options=("$@") - dialog --clear --stdout --backtitle "$BACKTITLE" --title "$title" --menu "$description" 0 0 0 "${options[@]}" -} - - -echo -e "\n### Checking UEFI boot mode" if [ ! -f /sys/firmware/efi/fw_platform_size ]; then echo >&2 "You must boot in UEFI mode to continue" exit 2 fi -echo -e "\n### Ensure the system clock is accurate" +if [[ "$UID" -ne 0 ]]; then + echo "This script needs to be run as root!" >&2 + exit 3 +fi + +read -rp "THIS SCRIPT WILL OVERWRITE ALL CONTENTS OF ${target_device}. Type uppercase yes to continue: " confirmed + +if [[ "$confirmed" != "YES" ]]; then + echo "aborted" >&2 + exit 128 +fi + timedatectl set-ntp true hwclock --systohc --utc - -echo -e "\n### Setting keyboard layout to de-latin1" loadkeys de-latin1 -echo -e "\n### Installing additional tools" -pacman -Sy --noconfirm --needed git reflector terminus-font dialog wget - -echo -e "\n### HiDPI screens" -noyes=("Yes" "The font is too small" "No" "The font size is just fine") -hidpi=$(get_choice "Font size" "Is your screen HiDPI?" "${noyes[@]}") || exit 1 -clear -[[ "$hidpi" == "Yes" ]] && font="ter-132n" || font="ter-716n" -setfont "$font" - -hostname=$(get_input "Hostname" "Enter hostname") || exit 1 -clear -: "${hostname:?"hostname cannot be empty"}" - -user=$(get_input "User" "Enter username") || exit 1 -clear -: "${user:?"user cannot be empty"}" - -password=$(get_password "User" "Enter password") || exit 1 -clear -: "${password:?"password cannot be empty"}" - -devicelist=$(lsblk -dplnx size -o name,size | grep -Ev "boot|rpmb|loop" | tac | tr '\n' ' ') -read -r -a devicelist <<< "$devicelist" - -device=$(get_choice "Installation" "Select installation disk" "${devicelist[@]}") || exit 1 - -clear - -echo -e "\n### Setting up fastest mirrors" -reflector --country 'Germany,France' --protocol https --sort rate --latest 5 --save /etc/pacman.d/mirrorlist - -echo -e "\n### Setting up partitions" -sgdisk --zap-all "${device}" +# Partition +sgdisk --zap-all "${target_device}" sgdisk --clear \ - --new=1:0:+550MiB --typecode=1:ef00 --change-name=1:EFI \ - --new=2:0:+8GiB --typecode=2:8200 --change-name=2:cryptswap \ - --new=3:0:0 --typecode=3:8300 --change-name=3:cryptsystem \ - "${device}" + --new 1:0:+550MiB --typecode 1:ef00 --change-name 1:EFI \ + --new 2:0:+8GiB --typecode 2:8200 --change-name 2:swap \ + --new 3 --typecode 3:8304 --change-name 3:system \ + "${target_device}" + +# Reload partition table sleep 5 +partprobe -s "${target_device}" +sleep 3 -echo -e "\n### Formatting partitions" -# Boot partition +# Encrypt root +echo -n "password" | cryptsetup luksFormat --type luks2 --pbkdf argon2id "/dev/disk/by-partlabel/system" +echo -n "password" | cryptsetup luksOpen --allow-discards --persistent "/dev/disk/by-partlabel/system" system + +# Create file systems mkfs.fat -F 32 -n "EFI" /dev/disk/by-partlabel/EFI - -# Swap partition -cryptsetup open --type plain --key-file /dev/urandom /dev/disk/by-partlabel/cryptswap swap -mkswap -L swap /dev/mapper/swap -swapon -L swap - -# System partition -echo -n "${password}" | cryptsetup luksFormat --type luks2 --pbkdf argon2id "/dev/disk/by-partlabel/cryptsystem" -echo -n "${password}" | cryptsetup luksOpen --allow-discards --persistent "/dev/disk/by-partlabel/cryptsystem" system mkfs.btrfs --force --label system /dev/mapper/system -echo -e "\n### Setting up BTRFS subvolumes" +# Mount system subvolume and create additional subvolumes o=defaults,x-mount.mkdir o_btrfs=$o,compress=zstd,ssd,noatime mount -t btrfs LABEL=system /mnt -btrfs subvolume create /mnt/root -btrfs subvolume create /mnt/home -btrfs subvolume create /mnt/snapshots -btrfs subvolume create /mnt/pkgs -btrfs subvolume create /mnt/aurbuild -btrfs subvolume create /mnt/archbuild -btrfs subvolume create /mnt/docker -btrfs subvolume create /mnt/logs -btrfs subvolume create /mnt/tmp +btrfs subvolume create /mnt/@ # / +btrfs subvolume create /mnt/@home # /home +btrfs subvolume create /mnt/@snapshots # /.snapshots +btrfs subvolume create /mnt/@pkg # /var/cache/pacman/pkg +btrfs subvolume create /mnt/@aurbuild # /var/lib/aurbuild +btrfs subvolume create /mnt/@archbuild # /var/lib/archbuild +btrfs subvolume create /mnt/@log # /var/log +btrfs subvolume create /mnt/@tmp # /var/tmp + umount -R /mnt +mount -t btrfs -o subvol=@,$o_btrfs LABEL=system /mnt +mount -t btrfs -o subvol=@home,$o_btrfs,nodatacow LABEL=system /mnt/home +mount -t btrfs -o subvol=@snapshots,$o_btrfs LABEL=system /mnt/.snapshots +mount -t btrfs -o subvol=@pkg,$o_btrfs LABEL=system /mnt/var/cache/pacman/pkg +mount -t btrfs -o subvol=@aurbuild,$o_btrfs LABEL=system /mnt/var/lib/aurbuild +mount -t btrfs -o subvol=@archbuild,$o_btrfs LABEL=system /mnt/var/lib/archbuild +mount -t btrfs -o subvol=@log,$o_btrfs LABEL=system /mnt/var/log +mount -t btrfs -o subvol=@tmp,$o_btrfs LABEL=system /mnt/var/tmp -mount -t btrfs -o subvol=root,$o_btrfs LABEL=system /mnt -mount -t btrfs -o subvol=home,$o_btrfs LABEL=system /mnt/home -mount -t btrfs -o subvol=snapshots,$o_btrfs LABEL=system /mnt/.snapshots -mount -t btrfs -o subvol=pkgs,$o_btrfs LABEL=system /mnt/var/cache/pacman -mount -t btrfs -o subvol=aurbuild,$o_btrfs LABEL=system /mnt/var/lib/aurbuild -mount -t btrfs -o subvol=archbuild,$o_btrfs LABEL=system /mnt/var/lib/archbuild -mount -t btrfs -o subvol=docker,$o_btrfs LABEL=system /mnt/var/lib/docker -mount -t btrfs -o subvol=logs,$o_btrfs LABEL=system /mnt/var/log -mount -t btrfs -o subvol=tmp,$o_btrfs LABEL=system /mnt/var/tmp - +# Mount additional partitions mount -o $o LABEL=EFI /mnt/efi -echo -e "\n### Configuring custom repo" -mkdir "/mnt/var/cache/pacman/${user}-local" +# Disable CoW for /home due to large loopback files by systemd-homed +chattr +C /mnt/home -# if [[ "${user}" == "maximbaz" && "${hostname}" == "home-"* ]]; then -# wget -m -nH -np -q --show-progress --progress=bar:force --reject='index.html*' --cut-dirs=2 -P "/mnt/var/cache/pacman/${user}-local" 'https://pkgbuild.com/~maximbaz/repo/' -# rename -- 'maximbaz.' "${user}-local." "/mnt/var/cache/pacman/${user}-local"/* -# else - repo-add "/mnt/var/cache/pacman/${user}-local/${user}-local.db.tar" -# fi - -if ! grep "${user}" /etc/pacman.conf > /dev/null; then +if ! grep "# Installer cache" /etc/pacman.conf > /dev/null; then cat >> /etc/pacman.conf << EOF - -[${user}-local] -Server = file:///mnt/var/cache/pacman/${user}-local - -[maximbaz] -Server = https://pkgbuild.com/~maximbaz/repo/x86_64/ - +# Installer cache [options] CacheDir = /mnt/var/cache/pacman/pkg -CacheDir = /mnt/var/cache/pacman/${user}-local EOF fi -echo -e "\n### Installing packages" -kernel_packages=( - "linux" - "linux-headers" - "linux-lts" - "linux-firmware" - "intel-ucode" -) -fs_packages=( - "btrfs-progs" - "dosfstools" - "e2fsprogs" -) -network_packages=( - "iwd" - "networkmanager" -) -basic_packages=( - "man-db" - "man-pages" - "pacman-contrib" - "neovim" - "bash-completion" - "git" - "rsync" - "openssh" - "htop" - "fzf" - "sudo" -) - #"pipewire" - #"pipewire-pulse" - #"pipewire-jack" - #"wireplumber" - #"firefox" - #"firefox-i18n-de" - #"firefox-ublock-origin" - #"firefox-dark-reader" - #"aurutils" # from maximbaz repo - #"devtools" # tools for aurutils - #"docbook-xls" # depenency of plymouth-git - #"efitools" # provides KeyTool - #"libfido2" # for systemd-cryptenroll - #"bluez" - #"bluez-utils" - #"usbutils" # for lsusb -#) -all_packages=( - ${kernel_packages[@]} - ${fs_packages[@]} - ${network_packages[@]} - ${basic_packages[@]} -) +# Bootstrap new chroot +reflector --country 'Germany' --protocol https --sort age --latest 5 --save /etc/pacman.d/mirrorlist +pacstrap /mnt base linux linux-firmware intel-ucode btrfs-progs dracut neovim iwd networkmanager -pacstrap /mnt base base-devel arch-secure-boot chezmoi ${all_packages[@]} - -echo -e "\n### Generating base config files" genfstab -L -p /mnt >> /mnt/etc/fstab -sed -i "s+LABEL=swap+/dev/mapper/swap+" /mnt/etc/fstab -echo "cryptswap /dev/disk/by-partlabel/cryptswap /dev/urandom swap,cipher=aes-xts-plain64,size=256" >> /mnt/etc/crypttab +# Configure timezone, locale, keymap, network sed -i 's/^#en_US\.UTF-8/en_US\.UTF-8/' /mnt/etc/locale.gen sed -i 's/^#de_DE\.UTF-8/de_DE\.UTF-8/' /mnt/etc/locale.gen arch-chroot /mnt locale-gen - arch-chroot /mnt systemd-firstboot \ --locale="en_US.UTF-8" \ --keymap="de-latin1" \ --timezone="Europe/Berlin" \ - --hostname="${hostname}" \ + --hostname="${new_hostname}" \ --setup-machine-id -echo "FONT=$font" > /mnt/etc/vconsole.conf echo -e "127.0.0.1\tlocalhost" >> /mnt/etc/hosts -echo -e "127.0.1.1\t$hostname" >> /mnt/etc/hosts +echo -e "127.0.1.1\t$new_hostname" >> /mnt/etc/hosts echo -e "\n::1\tlocalhost" >> /mnt/etc/hosts -arch-chroot /mnt timedatectl set-ntp 1 -echo -e "\n### Creating user" -arch-chroot /mnt useradd -m "$user" -for group in wheel network video audio input storage power; do - arch-chroot /mnt groupadd -rf "$group" - arch-chroot /mnt gpasswd -a "$user" "$group" -done -echo "$user:$password" | arch-chroot /mnt chpasswd +# Use systemd-resolved as dns backend for NetworkManager (auto-detected) +ln -sf /run/systemd/resolve/stub-resolv.conf /mnt/etc/resolv.conf -echo -e "\n### Disabling root login" -arch-chroot /mnt passwd -dl root - -echo -e "\n### Setting permissions on the custom repo" -arch-chroot /mnt chown -R "$user:$user" "/var/cache/pacman/${user}-local/" - -#echo -e "\n### Cloning dotfiles and running initial setup" -#arch-chroot /mnt sudo -u $user sh -c 'chezmoi init --apply https://code.strobeto.de/strobeltobias/dotfiles.git && chezmoi state delete-bucket --bucket=scriptState' - -cat > /mnt/etc/NetworkManager/conf.d/wifi_backend.conf < /mnt/etc/NetworkManager/conf.d/wifi-backend.conf <