#!/usr/bin/env bash set -euo pipefail # To run this, do: ## curl -o bootstrap https://bootstrap.dougthompson.co.uk ## chmod +x bootstrap ## export USEFUL_HOST=yourhostnamehere ## ./bootstrap echo "=== useful arch bootstrapper @ {{REF}} ===" log() { echo "[useful] $@" >/dev/stderr } log "pre-flight checks" FAIL=0 if ! curl -fsS ping.archlinux.org >/dev/null; then log "no internet connectivity, aborting." log "(hint: ip link, iwctl)" FAIL=1 fi if ! timedatectl | grep 'synchronized: yes'; then log "clock is out of sync, aborting." log "(hint: timedatectl)" FAIL=1 fi if [ -z "${USEFUL_HOST:-}" ]; then log "please set USEFUL_HOST" FAIL=1 fi if [ -z "${USEFUL_DISK:-}" ]; then USEFUL_DISK=/dev/nvme0n1 fi if [ "$USEFUL_DISK" = /dev/nvme0n1 ]; then USEFUL_ESP=/dev/nvme0n1p1 USEFUL_LUKS=/dev/nvme0n1p2 elif [ "$USEFUL_DISK" = /dev/vda ]; then USEFUL_ESP=/dev/vda1 USEFUL_LUKS=/dev/vda2 elif [ -z "${USEFUL_ESP}:-}" ] || [ -z "${USEFUL_LUKS}" ]; then log "USEFUL_DISK is set, but not sure what to call partition devices." log "please additionally set USEFUL_ESP, USEFUL_LUKS." FAIL=1 fi [ "$FAIL" = 1 ] && exit 1 log "=> OK" # You should've already done this, but doing it again for good measure before password entry: loadkeys uk mkdir -p /tmp/useful PASSWORD='' if [ -f /tmp/useful/password ]; then log "using cached /tmp/useful/password" PASSWORD="$(cat /tmp/useful/password)" else PASSWORD_OK=0 while [ "$PASSWORD_OK" != 1 ]; do PASSWORD_CONFIRM='' read -p "Set system password: " -s PASSWORD echo read -p " Confirm password: " -s PASSWORD_CONFIRM echo if [ "$PASSWORD" == "$PASSWORD_CONFIRM" ]; then PASSWORD_OK=1 else echo "Passwords don't match!" fi done echo -n "$PASSWORD" >/tmp/useful/password fi log "installing on $USEFUL_DISK" echo "=== THIS COMPUTER IS ABOUT TO BE WIPED ===" echo "The partition table (if any) on $USEFUL_DISK is about to be DESTROYED." while true; do read -p "Are you completely sure? [y/n]: " yn case $yn in [Yy]*) break ;; *) log "aborted." exit 1 ;; esac done log "cleaning up any previous install attempt" umount -R /mnt >/dev/null 2>&1 || true lvremove arch -y >/dev/null 2>&1 || true vgremove arch -y >/dev/null 2>&1 || true cryptsetup luksClose crypt >/dev/null 2>&1 || true log "creating partition table" echo -n "label: gpt start=, size=1G, type=uefi, name=arch, bootable start=, size=+, type=empty, name=luks " | sfdisk "$USEFUL_DISK" --wipe always --wipe-partitions always log "creating luks partition" echo -n "$PASSWORD" | cryptsetup -q luksFormat --type luks2 --key-file - "$USEFUL_LUKS" echo -n "$PASSWORD" | cryptsetup -q luksOpen --allow-discards --persistent --key-file - "$USEFUL_LUKS" crypt log "creating lvm on luks" pvcreate /dev/mapper/crypt vgcreate arch /dev/mapper/crypt lvcreate --name swap -L 8G arch lvcreate --name root -l 100%FREE arch log "formatting lvm partitions" mkfs.vfat "$USEFUL_ESP" mkswap /dev/arch/swap mkfs.ext4 -L root /dev/arch/root log "mounting partitions" mount /dev/arch/root /mnt mount --mkdir "$USEFUL_ESP" /mnt/boot log "running pacstrap" # Note some of these will be removed in later bootstrapping. PACKAGES=' base amd-ucode intel-ucode linux linux-firmware linux-headers exfatprogs e2fsprogs dosfstools lvm2 cryptsetup dracut networkmanager neovim plasma-meta fish git mesa epiphany ' pacstrap -K /mnt $PACKAGES log "configuring system" echo "$USEFUL_HOST" > /etc/hostname # Technically not the same file at this point, but doesn't matter. ln -s /usr/share/zoneinfo/Europe/London /mnt/etc/localtime echo 'en_GB.UTF-8 UTF-8' > /mnt/etc/locale.gen echo 'LANG=en_GB.UTF-8' > /mnt/etc/locale.conf echo 'KEYMAP=uk' > /mnt/etc/vconsole.conf UUID_ESP="$(blkid -o value -s UUID $USEFUL_ESP)" UUID_LUKS="$(blkid -o value -s UUID $USEFUL_LUKS)" UUID_LVM_ROOT="$(blkid -o value -s UUID /dev/arch/root)" UUID_LVM_SWAP="$(blkid -o value -s UUID /dev/arch/swap)" # NOTE: continuous TRIM is purposefully enabled for swap only. echo -n " UUID=$UUID_LVM_ROOT / ext4 rw,noatime 0 1 UUID=$UUID_ESP /boot vfat rw,noatime,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,utf8,errors=remount-ro 0 2 UUID=$UUID_LVM_SWAP none swap defaults,discard 0 0 " >> /mnt/etc/fstab echo "crypt UUID=$UUID_LUKS none luks,initramfs" >> /mnt/etc/crypttab echo 'install_items+=" /etc/crypttab "' > /mnt/etc/dracut.conf.d/10-useful.conf # Most of the below config will be overwritten later - it's just "good enough" # to get us booting to a desktop. mkdir -p /mnt/boot/loader/entries echo -n ' timeout 5 default arch.conf ' > /mnt/boot/loader/loader.conf # Taking the firehose approach to the kernel cmdline here. # Note 'quiet splash' is absent for now, would prefer to know if there are issues on first boot. echo -n " title Arch Linux (bootstrapping) linux /vmlinuz-linux initrd /initramfs-linux.img options root=UUID=$UUID_LVM_ROOT rd.auto rd.retry=10 rd.luks.allow-discards rd.dm=0 rd.md=0 ro amdgpu.dcdebugmask=0x10 amdgpu.runpm=0 " > /mnt/boot/loader/entries/arch.conf log "finalising config in chroot" arch-chroot /mnt bash -c " set -euo pipefail log() { echo \"[useful][chroot] \$@\" } log 'adding user' useradd -m -G users,wheel,video,storage doug log 'setting user passwords' printf '%s\n' \"$PASSWORD\" \"$PASSWORD\" | passwd printf '%s\n' \"$PASSWORD\" \"$PASSWORD\" | passwd doug log 'setting hardware clock' hwclock --systohc log 'activating ntp' timedatectl set-ntp true log 'generating locales' locale-gen log 'running dracut' dracut -v -f /boot/initramfs-linux.img log 'installing bootloader' bootctl install " log "done - ready to reboot."