archlinux/arch.sh
2025-11-22 23:15:27 +00:00

1755 lines
43 KiB
Bash
Executable file

#!/usr/bin/env bash
revision=1.0l
set -a
set -E
# ZFS key
# zfsgpgkey=DDF7DB817396A49B2A2723F7403BD972F75D9D76 # archzfs
zfsgpgkey=D0F2AE55C1BF11A026D155813A658A95B8CFCC51 # myvezfs
# Exit function
trap '[ "${?}" -ne 77 ] || exit 77' ERR
function die
{
local reset="$(tput sgr0)"
local red="${reset}$(tput setaf 1)"
local yellow="${reset}$(tput setaf 3)"
cat <<- abort
${red}
Error encountered for the following reason:
${yellow}
${@}
${red}
Script aborted...
${reset}
abort
exit 77
}
# EFI system check
if [ ! -d /sys/firmware/efi/efivars ]
then
die 'This script only works with UEFI systems'
fi
# Prompt function
function reformat
{
case "${1}" in
# Formatting
bold) format+=($(tput bold))
;;
italic) format+=($(tput sitm))
;;
uline) format+=($(tput smul))
;;
blink) format+=($(tput blink))
;;
dim) format+=($(tput dim))
;;
# Colours
black) format+=($(tput setaf 0))
;;
red) format+=($(tput setaf 1))
;;
green) format+=($(tput setaf 2))
;;
yellow) format+=($(tput setaf 3))
;;
blue) format+=($(tput setaf 4))
;;
magenta) format+=($(tput setaf 5))
;;
cyan) format+=($(tput setaf 6))
;;
white) format+=($(tput setaf 7))
;;
# Read-specific
array) array="-a"
;;
secret) secret="-s"
;;
press) press="-n 1"
;;
# Everything else goes into line
*) line="${@}"
;;
esac
}
# Syntax: ask for var [in format] "statement"
function ask
{
local format variable line secret press array
case "${1}" in
for)
case "${2}" in
in)
die "Syntax error detected (missing variable before $(tput sitm)$(tput smso)in$(tput rmso)$(tput ritm))
Usage: ask for \${variable} in \${format[@]} \"\${line}\""
;;
*)
variable="${2}"
shift 2
;;
esac
;;
*) die "Syntax error detected (misuse of $(tput sitm)$(tput smso)for$(tput rmso)$(tput ritm))
Usage: ask for \${variable} in \${format[@]} \"\${line}\""
;;
esac
case "${1}" in
in)
shift
for arg in "${@}"
do
reformat ${arg}
done
;;
*) line="${@}"
;;
esac
read ${press} -r -p "$(printf "%s" "${format[@]}" "${line}: " "$(tput sgr0)")" ${secret} ${array} ${variable}
echo
export ${variable}
}
# Syntax: say [as template] [in format] "statement"
function say
{
local format line heading
case "${1}" in
as)
# Templates
case ${2} in
title)
format+=($(tput setaf 6)) # cyan
;;
heading)
format+=($(tput setaf 3) $(tput bold)) # bold yellow
heading=":: "
;;
success)
format+=($(tput setaf 2)) # green
;;
warning)
format+=($(tput setaf 1)) # red
;;
*)
die "Syntax error detected (misuse of $(tput sitm)$(tput smso)as$(tput rmso)$(tput ritm))
Usage: say as \${template} in \${format[@]} \"\${line}\""
;;
esac
shift 2
;;
esac
case "${1}" in
in)
shift
for arg in "${@}"
do
reformat ${arg}
done
;;
*) line="${@}"
;;
esac
printf "%s" "${format[@]}" "${heading}" "${line}" "$(tput sgr0)"
echo
}
function presskeytoresume
{
read -n 1 -s -p "Press any key when ready..."
echo
}
# Internet connection check
if nc -z -w 1 archlinux.org 443 >/dev/null 2>&1 || nc -z -w 1 google.com 443 >/dev/null 2>&1
then
timedatectl set-ntp true
else
die "No internet connectivity detected, plug in an ethernet cable or run ${reset}${green}iwd-connect${yellow} if using wifi and try again"
fi
##
## functions start
##
# Default systemd services
systemd_services+=(systemd-networkd.service systemd-resolved.service sshd.service iptables.service)
# Repeat a command until it exits with 0
function repeat
{
until ${@}
do
sleep 3
done
}
# Pacstrap new root and generate fs tables
function pacstrapGenfstab
{
local archpkgs="sudo openssh efibootmgr pacman-contrib \
vim rsync pv git less openbsd-netcat \
man-db bash-completion reflector \
wireguard-tools systemd-resolvconf \
${linux_firmware[@]} \
${btrfs[@]} ${zfs[@]} \
${ucode} \
${grub[@]} \
${iwd} \
${yubikey[@]} \
${nvidia[@]} \
${bluetooth[@]}"
# Delete unneccessary EFI files
rm -f /sys/firmware/efi/efivars/dump-*
for entry in $(efibootmgr | grep "Arch" | grep -o 'Boot....' | sed 's/Boot//')
do
efibootmgr --quiet -Bb ${entry}
done
# Ensure pacman.conf settings are properly set
sed -e '/Color/c Color' \
-e '/ParallelDownloads/c ParallelDownloads = 10' \
-i /etc/pacman.conf
# Add CacheServer
if [ ${cacheserver} ]
then
sed -e "/^\[core\]$\|^\[extra\]$/a CacheServer = ${cacheserver}" \
-i /etc/pacman.conf
fi
# Temporarily disable mkinitcpio install
ln -s -f /dev/null /etc/pacman.d/hooks/90-mkinitcpio-install.hook
echo
say as heading "Installing Arch Linux base packages"
case ${filesystem} in
zfs)
# Add zfs repo
grep -q '\[myvezfs\]' /etc/pacman.conf || sed -i '/\[core\]/i [myvezfs]\
Server = https://mirror.myvelabs.com/repo/$repo\
Server = https://repo.myvelabs.com/$repo\n' /etc/pacman.conf
# Add CacheServer
if [ ${cacheserver} ]
then
sed -e "/^\[myvezfs\]$/a CacheServer = ${cacheserver}" \
-i /etc/pacman.conf
fi
local zfslinux=$(pacman -Syi zfs-${linux_kernel} | grep "Depends On" | sed "s|.*${linux_kernel}=||" | awk '{print $1}')
# Install zfs-compatible linux kernel
if [ ${zfslinux} = $(pacman -Si myvezfs/${linux_kernel} | grep "Version" | awk '{print $3}') ]
then
repeat pacstrap -K /mnt --ask 4 \
base mkinitcpio iptables-nft ${linux_kernel} ${archpkgs}
else
repeat pacstrap -K /mnt base mkinitcpio iptables-nft
if [ ${cacheserver} ]
then
pacstrap -K -U /mnt ${cacheserver}/${linux_kernel}-${zfslinux}-x86_64.pkg.tar.zst ||\
repeat pacstrap -K -U /mnt https://archive.archlinux.org/packages/l/${linux_kernel}/${linux_kernel}-${zfslinux}-x86_64.pkg.tar.zst
else
repeat pacstrap -K -U /mnt https://archive.archlinux.org/packages/l/${linux_kernel}/${linux_kernel}-${zfslinux}-x86_64.pkg.tar.zst
fi
repeat pacstrap -K /mnt --ask 4 ${archpkgs}
fi
# Add archzfs repo
sed -e '/\[core\]/i [myvezfs]\
Server = https://mirror.myvelabs.com/repo/$repo\
Server = https://repo.myvelabs.com/$repo\n' \
-i /mnt/etc/pacman.conf
# Add archzfs repo keys
arch-chroot /mnt pacman-key -r ${zfsgpgkey}
arch-chroot /mnt pacman-key --lsign-key ${zfsgpgkey}
# ZFS properties
zpool set bootfs=zroot/ROOT zroot
zpool set cachefile=/etc/zfs/zpool.cache zroot
rsync -a /etc/zfs/zpool.cache /mnt/etc/zfs/
# Create zfs directory
mkdir -p /mnt/zfs/bin/
# Configure zfs for mkinitcpio
echo 'BINARIES+=(/usr/bin/zfs)' >/mnt/etc/mkinitcpio.conf.d/zz-binaries.conf
sed -e '/^HOOKS/ s/filesystems/zfs &/' \
-e '/^HOOKS/ s/ fsck//' \
/mnt/etc/mkinitcpio.conf >/mnt/etc/mkinitcpio.conf.d/zz-hooks.conf
# Generate fstab
case ${arch} in
1|2)
genfstab -U -p /mnt/boot | sed "s|vfat.*rw|vfat rw,x-systemd.idle-timeout=1min,x-systemd.automount,noauto,nofail|" >>/mnt/etc/fstab
sed -i '/UUID.*vfat/ s|/|/boot|' /mnt/etc/fstab
;;
*) genfstab -U -p /mnt | grep -v zroot >>/mnt/etc/fstab
;;
esac
# Add systemd services
systemd_services+=(zfs.target zfs-import-cache.service zfs-mount.service zfs-import.target zfs-trim@zroot.timer zfs-scrub@zroot.timer)
;;
btrfs|ext4)
repeat pacstrap -K /mnt --ask 4 \
base mkinitcpio iptables-nft ${linux_kernel} ${archpkgs}
# Generate fstab
genfstab -U -p /mnt >>/mnt/etc/fstab
case ${filesystem} in
btrfs) echo 'BINARIES+=(/usr/bin/btrfs)' >/mnt/etc/mkinitcpio.conf.d/zz-binaries.conf
;;
esac
;;
esac
# Ensure pacman.conf settings are properly set
sed -e '/Color/c Color' \
-e '/ParallelDownloads/c ParallelDownloads = 10' \
-i /mnt/etc/pacman.conf
# Custom mkinitcpio.conf
echo 'MODULES_DECOMPRESS="yes"' >/mnt/etc/mkinitcpio.conf.d/zz-modules_decompress.conf
# Add CacheServer
if [ ${cacheserver} ]
then
grep -q "^CacheServer" /etc/pacman.conf ||\
sed -e "/^\[core\]$\|^\[extra\]$\|^\[myvezfs\]$/a CacheServer = ${cacheserver}" \
-i /mnt/etc/pacman.conf
fi
# Make custom directories
mkdir -p /mnt/etc/pacman.d/hooks/ /mnt/opt/local/{bin,hooks}/
# Manually configure mkinitcpio
ln -s -f /dev/null /mnt/etc/pacman.d/hooks/90-mkinitcpio-install.hook
# Add hooks
hooks
}
# Update mkinitcpio with encrypt hooks
function encryptHook
{
case ${filesystem} in
zfs)
sed "s/block/& ${1}/" -i /mnt/etc/mkinitcpio.conf.d/zz-hooks.conf
# Pacman hook
install /dev/stdin /mnt/opt/local/hooks/mkinitcpio.conf <<- hook
#!/usr/bin/env bash
grep '^HOOKS' /etc/mkinitcpio.conf | sed -e "s/filesystems/zfs &/" -e "s/ fsck//" -e "s/block/& ${1}/" >/etc/mkinitcpio.conf.d/zz-hooks.conf
sed -e "s|%PKGBASE%|${linux_kernel}|g" \\
-e "s/^fallback/#&/g" \\
-e "s/ 'fallback'//" \\
/usr/share/mkinitcpio/hook.preset >/etc/mkinitcpio.d/${linux_kernel}.preset
hook
;;
*)
grep '^HOOKS' /mnt/etc/mkinitcpio.conf | sed "s/block/& ${1}/" >/mnt/etc/mkinitcpio.conf.d/zz-hooks.conf
# Pacman hook
install /dev/stdin /mnt/opt/local/hooks/mkinitcpio.conf <<- hook
#!/usr/bin/env bash
grep '^HOOKS' /etc/mkinitcpio.conf | sed "s/block/& ${1}/" >/etc/mkinitcpio.conf.d/zz-hooks.conf
sed -e "s|%PKGBASE%|${linux_kernel}|g" \\
-e "s/^fallback/#&/g" \\
-e "s/ 'fallback'//" \\
/usr/share/mkinitcpio/hook.preset >/etc/mkinitcpio.d/${linux_kernel}.preset
hook
;;
esac
cat >/mnt/etc/pacman.d/hooks/85-mkinitcpio.hook <<- mkinitcpio
[Trigger]
Operation = Install
Operation = Upgrade
Type = Package
Target = mkinitcpio
[Action]
Description = Fixing mkinitcpio.conf
When = PostTransaction
Exec = /opt/local/hooks/mkinitcpio.conf
mkinitcpio
}
# Compile yubikey if arch package fails
function compileYubikey
{
cd yubikey-full-disk-encryption
make install || die 'Yubikey full disk encryption (github) package installation failed'
}
# Install yubikey inside new root
function chrootYubikey
{
if [ -d ~/yubikey-full-disk-encryption ]
then
rsync -a ~/yubikey-full-disk-encryption /mnt/
arch-chroot /mnt /usr/bin/bash <<- YUBIKEY
compileYubikey
rm -r /yubikey-full-disk-encryption
YUBIKEY
fi
rsync -a /etc/ykfde.conf /mnt/etc/
chmod 600 /mnt/etc/ykfde.conf
encryptHook ykfde
echo
say in blue 'Copied yubikey configuration files'
}
# Yubikey root encryption
function encryptRootYubikey
{
yubikey=(yubikey-personalization)
for package in yubikey-personalization yubikey-full-disk-encryption
do
if ! pacman -Q | grep -q -w ${package}
then
missing_yubikey_requirements+=(${package})
fi
done
if [ ${missing_yubikey_requirements} ]
then
yes | pacman -Sy ${missing_yubikey_requirements[@]}
echo
fi
function ykfdeFormat
{
# Custom challenge slot
# sed -i '/YKFDE_CHALLENGE_SLOT/c YKFDE_CHALLENGE_SLOT="1"' /etc/ykfde.conf
case ${decryptroot} in
[yY]) sed '/YKFDE_CHALLENGE=/c YKFDE_CHALLENGE="'"$(printf '%q' "${lukspass}")"'"' -i /etc/ykfde.conf ;;
[nN]) sed '/YKFDE_CHALLENGE_PASSWORD_NEEDED/c YKFDE_CHALLENGE_PASSWORD_NEEDED="1"' -i /etc/ykfde.conf ;;
esac
say as heading "Encrypting ${rootpart} with yubikey HMAC encryption"
until printf '%s\n' "${lukspass}" "${lukspass}" | ykfde-format ${encryptopts} ${luks_header} ${rootpart}
do
sleep 3
done
printf '%s\n' "${lukspass}" |\
ykfde-open \
-d ${rootpart} \
-n cryptroot \
-- ${luks_header}
}
while true
do
# Try with yubikey-full-disk-encryption pacman package
ykfdeFormat
if dmsetup ls | grep -q 'cryptroot'
then
yubikey+=(yubikey-full-disk-encryption)
echo
break
fi
for package in git make
do
if ! pacman -Q | grep -q -w ${package}
then
make_yubikey_requirements+=(${package})
fi
done
echo
say in blue 'Setting up yubikey'
if [ ${make_yubikey_requirements} ]
then
yes | pacman -Sy ${make_yubikey_requirements[@]}
echo
fi
# Try yubikey full disk encryption again using latest git
cd ~/
git clone https://github.com/agherzan/yubikey-full-disk-encryption.git
compileYubikey
ykfdeFormat
if dmsetup ls | grep -q 'cryptroot'
then
echo
break
fi
die 'Unable to encrypt root partition'
done
}
# Root encryption
function encryptRootLuks
{
say as heading "Encrypting ${rootpart}"
until printf '%s' "${lukspass}" | cryptsetup luksFormat -v ${encryptopts} ${luks_header} ${rootpart}
do
sleep 3
done
printf '%s' "${lukspass}" | cryptsetup open -v ${rootpart} cryptroot ${luks_header}
if dmsetup ls | grep -q 'cryptroot'
then
echo
else
die 'Unable to encrypt root partition'
fi
}
# External boot encryption
function encryptBootLuks
{
say as heading "Encrypting ${bootpart}"
until printf '%s' "${grubpass}" | cryptsetup luksFormat -v --type luks1 ${bootpart}
do
sleep 3
done
printf '%s' "${grubpass}" | cryptsetup open -v ${bootpart} cryptboot
yes | mkfs.ext2 -q /dev/mapper/cryptboot
if dmsetup ls | grep -q cryptboot
then
echo
else
die 'Unable to encrypt boot partition'
fi
}
# Default cryptsetup options
encryptopts="--cipher aes-xts-plain64 \
--key-size 256 \
--iter-time 2000 \
--hash sha512"
# Generate keyfile for external boot
function generateKeyfile
{
echo
say as heading 'Generating keyfile'
dd bs=1 count=256 if=/dev/random of=/mnt/crypto_keyfile.bin status=progress
chmod 000 /mnt/crypto_keyfile.bin
printf '%s' "${grubpass}" | cryptsetup luksAddKey ${bootpart} /mnt/crypto_keyfile.bin
if [[ ${decryptroot} = [yY] ]]
then
case ${arch} in
3) printf '%s' "${lukspass}" | cryptsetup luksAddKey ${rootpart} /mnt/crypto_keyfile.bin ;;
6) printf '%s' "${lukspass}" | cryptsetup luksAddKey /mnt/boot/header.img /mnt/crypto_keyfile.bin ;;
esac
fi
}
# Format partitions
function configureVolumes
{
say as heading 'Configuring volumes'
# Root
case ${filesystem} in
ext4)
yes | mkfs.ext4 ${rootvol}
mount -o noatime ${rootvol} /mnt
;;
btrfs)
mkfs.btrfs -f ${rootvol}
btrfsopts="compress=zstd:2,noatime,space_cache=v2"
# Create btrfs subvolumes
mount ${rootvol} /mnt
for subvol in @{,home,var{,/pkg,/log,/tmp,/qemu},opt} # ,snapshots{,/root,/home}
do
btrfs subvolume create /mnt/${subvol}
done
chattr +C /mnt/@var/qemu
chmod 1777 /mnt/@var/tmp
umount /mnt
# Mount @root subvolume
mount --mkdir -o ${btrfsopts},subvol=@ ${rootvol} /mnt
# Mount home and home snapshots subvolumes
mount --mkdir -o ${btrfsopts},subvol=@home ${rootvol} /mnt/home
# mount --mkdir -o ${btrfsopts},subvol=@snapshots/home ${rootvol} /mnt/home/.snapshots
# mount --mkdir -o ${btrfsopts},subvol=@snapshots/root ${rootvol} /mnt/.snapshots
# Mount remaining subvolumes
mount --mkdir -o ${btrfsopts},subvol=@var/pkg ${rootvol} /mnt/var/cache/pacman/pkg
mount --mkdir -o ${btrfsopts},subvol=@var/log ${rootvol} /mnt/var/log
mount --mkdir -o ${btrfsopts},subvol=@var/tmp ${rootvol} /mnt/var/tmp
mount --mkdir -o ${btrfsopts},subvol=@var/qemu ${rootvol} /mnt/var/lib/libvirt/images
mount --mkdir -o ${btrfsopts},subvol=@opt ${rootvol} /mnt/opt
mount --mkdir -o ${btrfsopts},subvol=/ ${rootvol} /mnt/btrfs
echo
;;
zfs)
until printf '%s' "${lukspass}" |\
zpool create -f zroot \
-o ashift=12 \
-o autotrim=on \
-R /mnt \
-O acltype=posixacl \
-O canmount=off \
-O compression=zstd \
-O dnodesize=auto \
-O normalization=formD \
-O atime=off \
-O xattr=sa \
-O mountpoint=none \
${zpoolencryption} ${rootvol}
do
sleep 3
done
# Mount datasets
zfs create -o mountpoint=/ -o canmount=noauto zroot/ROOT
zfs create -o mountpoint=/.boot zroot/BOOT
zfs create -o mountpoint=/home zroot/HOME
zfs create -o mountpoint=/var/log zroot/LOG
zfs create -o mountpoint=/var/tmp zroot/TMP
zfs create -o mountpoint=/var/cache/pacman/pkg zroot/PKG
zfs create -o mountpoint=/var/lib/libvirt/images zroot/QEMU
# Verify zpool
zpool export zroot
zpool import -R /mnt zroot -N -d ${rootvol}
# Native encryption
case ${arch} in
2) printf '%s' "${lukspass}" | zfs load-key zroot ;;
esac
zfs mount zroot/ROOT
zfs mount -a
;;
esac
# Boot volume
if [[ ${arch} = [3567] ]]
then
yes | mkfs.fat -F 32 ${efivol}
else
yes | mkfs.fat -F 32 ${bootvol}
fi
mount --mkdir ${bootvol} /mnt/boot
# EFI volume
if [[ ${arch} = [3567] ]]
then
mount --mkdir ${efivol} /mnt/boot/efi
grub+=(grub)
fi
}
# Configure grub
function configureGrub
{
sed '/GRUB_TIMEOUT=/c GRUB_TIMEOUT=3' -i /etc/default/grub
sed '/GRUB_ENABLE_CRYPTODISK/c GRUB_ENABLE_CRYPTODISK=y' -i /etc/default/grub
echo 'cryptboot '${bootpart}' /crypto_keyfile.bin luks' >>/etc/crypttab
}
# Ask for system settings
function initialSetup
{
echo
# Username
say in blue 'Create a new user'
until [ ${username} ]
do
ask for username 'Username'
if [ -z ${username} ]
then
say as warning 'Username cannot be empty, try again'
fi
done
# Hostname
say in blue 'Create a name for your computer'
until [ ${hostname} ]
do
ask for hostname 'Hostname'
if [ -z ${hostname} ]
then
say as warning 'Hostname cannot be empty, try again'
fi
done
# User password
say in blue "Set a password for ${username}"
until [ "${userpass}" = "${userpass2}" -a "${userpass}" ]
do
ask for userpass in secret 'User password'
ask for userpass2 in secret 'Verify user password'
echo
if [ -z "${userpass}" ]
then
say as warning 'Password field cannot be empty, try again'
elif [ "${userpass}" != "${userpass2}" ]
then
say as warning 'Passwords did not match, try again'
fi
done
say as success "${username}@${hostname}'s password has been saved"
echo
# Encryption key
if [[ ${arch} = [2-7] ]]
then
say in blue 'Create an encryption passphrase for the system drive'
until [ "${lukspass}" = "${lukspass2}" -a "${lukspass}" -a "${#lukspass}" -ge 8 ]
do
ask for lukspass in secret 'Encryption password'
ask for lukspass2 in secret 'Verify encryption password'
echo
if [ -z "${lukspass}" ]
then
say as warning 'Passphrase field cannot be empty, try again'
elif [ "${lukspass}" != "${lukspass2}" ]
then
say as warning 'Passphrases did not match, try again'
elif [ "${#lukspass}" -lt 8 ]
then
say as warning 'Passphrase needs to be at least 8 characters'
fi
done
say as success 'Encryption passphrase has been saved'
echo
fi
# GRUB password
if [[ ${arch} = [3567] ]]
then
say in blue 'Create an encryption passphrase for the bootloader'
until [ "${grubpass}" = "${grubpass2}" -a "${grubpass}" -a "${#grubpass}" -ge 6 ]
do
ask for grubpass in secret 'Bootloader password'
ask for grubpass2 in secret 'Verify bootloader password'
echo
if [ -z "${grubpass}" ]
then
say as warning 'Password field cannot be empty, try again'
elif [ "${grubpass}" != "${grubpass2}" ]
then
say as warning 'Passwords did not match, try again'
elif [ "${#grubpass}" -lt 6 ]
then
say as warning 'Passphrase needs to be at least 6 characters'
fi
done
say as success 'Bootloader password has been saved'
echo
fi
# Assign system drive
say in blue 'Identify the system drive from the list of available devices below'
lsblk -d -o name,model,size,mountpoint | grep -v 'archiso'
say in uline white dim '## SSD and HDD device format begins with "sd" or "hd" (sda, sdb, sd[*])'
say in uline white dim '## NVME and PCI device format is "nvme[*]n1" (nvme0n1, nvme1n1, nvme[*]n1)'
while true
do
ask for drive 'Installation device'
if [ ${drive} ] && lsblk -o name | grep -q -w ${drive}
then
break
else
lsblk -d -o name,model,size,mountpoint | grep -v 'archiso'
if [ -z ${drive} ]
then
say as warning 'Field cannot be empty, try again'
else
say as warning 'Invalid selection or drive not available, try again'
fi
fi
done
say as success "Installation drive set as $(tput smso)/dev/${drive}$(tput rmso)"
# Assign detached boot drive (if applicable)
if [[ ${arch} = [67] ]]
then
echo
say in blue 'Identify the removable boot drive from the list of available devices below'
lsblk -d -o name,model,size,mountpoint | grep -v "archiso\|$drive"
say in uline white dim '## Removable drives usually begin with "sd" (sda, sdb, sd[*])'
while true
do
ask for external_drive 'Removable boot device'
if [ ${external_drive} ] && lsblk -o name | grep -v ${drive} | grep -q -w ${external_drive}
then
break
else
lsblk -d -o name,model,size,mountpoint | grep -v "archiso\|$drive"
if [ -z ${external_drive} ]
then
say as warning 'Field cannot be empty, try again'
elif [ ${external_drive} = ${drive} ]
then
say as warning 'Boot drive cannot be the same as the system drive, try again'
else
say as warning 'Invalid selection or drive not available, try again'
fi
fi
done
say as success "Detached boot drive set as $(tput smso)/dev/${external_drive}$(tput rmso)"
fi
}
# Virtual machine defaults
function virtualMachineSetup
{
if ls -l /dev/disk/* | grep -q VBOX
then
hostname=vbox
drive=sda
external_drive=sdb
else
hostname=qemu
if ls -l /dev/disk/* | grep -q virtio
then
drive=vda
elif ls -l /dev/disk/* | grep -q QEMU
then
drive=sda
fi
fi
username=user
userpass=123
lukspass=12345678
grubpass=123456
echo
say in uline white dim 'Troubleshooting defaults loaded'
}
function hooks
{
# Common pacman.conf
install /dev/stdin /mnt/opt/local/hooks/pacman.conf <<- 'hook'
#!/usr/bin/env bash
if [ -f /etc/pacman.conf.pacnew ]
then
sed -e '/ParallelDownloads/c ParallelDownloads = 10' \
-e '/Color/c Color' /etc/pacman.conf.pacnew >/etc/pacman.conf
rm /etc/pacman.conf.pacnew
fi
hook
case ${filesystem} in
zfs)
# pacman.conf
sed -e "/Color\/c Color/a\\
-e '/^\\\[core\\\]$/i [myvezfs]\\\\\\
Server = https://mirror.myvelabs.com/repo/\$repo\\\\\\
Server = https://repo.myvelabs.com/\$repo\\\n' \\\\" \
-i /mnt/opt/local/hooks/pacman.conf
cat >/mnt/etc/pacman.d/hooks/100-pacman.conf.hook <<- pacman
[Trigger]
Operation = Install
Operation = Upgrade
Type = Package
Target = pacman
[Action]
Description = Fixing pacman.conf
When = PostTransaction
Exec = /opt/local/hooks/pacman.conf
pacman
# mkinitcpio.conf
install /dev/stdin /mnt/opt/local/hooks/mkinitcpio.conf <<- 'hook'
#!/usr/bin/env bash
grep '^HOOKS' /etc/mkinitcpio.conf | sed 's/filesystems fsck/zfs filesystems/' >/etc/mkinitcpio.conf.d/zz-hooks.conf
sed -e "s|%PKGBASE%|${linux_kernel}|g" \\
-e "s/^fallback/#&/g" \\
-e "s/ 'fallback'//" \\
/usr/share/mkinitcpio/hook.preset >/etc/mkinitcpio.d/${linux_kernel}.preset
hook
cat >/mnt/etc/pacman.d/hooks/85-mkinitcpio.conf.hook <<- mkinitcpio
[Trigger]
Operation = Install
Operation = Upgrade
Type = Package
Target = mkinitcpio
[Action]
Description = Fixing mkinitcpio.conf
When = PostTransaction
Exec = /opt/local/hooks/mkinitcpio.conf
mkinitcpio
;;
*)
# pacman.conf hook
cat >/mnt/etc/pacman.d/hooks/100-pacman.conf.hook <<- pacman
[Trigger]
Operation = Install
Operation = Upgrade
Type = Package
Target = pacman
[Action]
Description = Fixing pacman.conf
When = PostTransaction
Exec = /opt/local/hooks/pacman.conf
pacman
;;
esac
}
##
## functions end
##
##
## Static variables
##
# Determine network controller
if lspci | grep -q 'Network controller'
then
if ! lspci | grep -q 'Ethernet controller'
then
iwd=iwd
systemd_services+=(iwd.service)
fi
fi
# Determine ucode
if lscpu | grep 'Model name:' | grep -q AMD
then
ucode=amd-ucode
elif lscpu | grep 'Model name:' | grep -q Intel
then
ucode=intel-ucode
else
die 'Unable to determine CPU type'
fi
# Detect bluetooth
if lsmod | grep -q bluetooth || [ -d /sys/class/bluetooth ]
then
bluetooth=(bluez bluez-utils)
fi
# Read flags
rm -f sshkeys
while [ ${1} ]
do
case ${1} in
-s | --ssh-key )
if [ "${2}" ]
then
echo "${2}" >>sshkeys
if ! ssh-keygen -l -f sshkeys >/dev/null
then
die 'Invalid SSH public key detected'
fi
shift
fi
;;
-o | --option )
if [ "${2}" ]
then
arch=${2}
shift
fi
;;
-c | --cache )
if [ "${2}" ]
then
cacheserver=${2}
shift
fi
;;
-k | --kernel )
case "${2}" in
linux) linux_kernel=linux
shift
;;
linux-lts) linux_kernel=linux-lts
shift
;;
linux-hardened) linux_kernel=linux-hardened
shift
;;
linux-zen) linux_kernel=linux-zen
shift
;;
*) die "Invalid option for flag \"${1}\""
;;
esac
;;
-f | --filesystem )
case "${2}" in
ext4)
filesystem_choice=1
shift
;;
btrfs)
filesystem_choice=2
shift
;;
zfs)
filesystem_choice=3
shift
;;
*) die "Invalid option for flag \"${1}\""
;;
esac
;;
-y | --noconfirm )
noconfirm=yes
load_defaults=y
shred_installation_disk=n
shred_boot=n
begin_install=Y
;;
-? | -h | --help )
cat <<- help
Parameters:
-s, --ssh-key Add SSH public key (enclosed in quotes)
-o, --option Arch installation setup
-c, --cache Pacman cache server
-k, --kernel Linux kernel
-f, --filesystem Filesystem choice
-y, --noconfirm Skip choices
-?, -h, --help This help screen
help
exit 0
;;
* ) die "Unknown flag: ${1}"
;;
esac
shift
done
clear
say in uline white dim "## rev ${revision}"
echo
say in bold blue "$(tput smso)Arch Linux Installer"
echo
say in yellow "Select a system configuration from the options below"
cat <<- menu
1) Basic
2) Full Disk Encryption with EFISTUB
3) Full Disk Encryption with Secured GRUB
4) Yubikey Full Disk Encryption with EFISTUB
5) Yubikey Full Disk Encryption with Secured GRUB
menu
if ls -l /dev/disk/* | grep -q 'virtio\|QEMU'
then
echo
until [[ ${arch} = [1-5] ]]
do
ask for arch in press ':'
echo
[[ ${arch} = [1-5] ]] || say as warning 'Invalid selection, type an option from 1 to 5'
done
else
cat <<- menu
6) Full Disk Encryption with Detached LUKS Header and Secured GRUB
7) Yubikey Encrypted Detached LUKS Header with Secured GRUB
menu
echo
until [[ ${arch} = [1-7] ]]
do
ask for arch in press ':'
echo
[[ ${arch} = [1-7] ]] || say as warning 'Invalid selection, type an option from 1 to 7'
done
fi
# Prevent continuing unless yubikey is detected, only applies to yubikey setups
if [[ ${arch} = [457] ]] && ! dmesg | grep -q -i YubiKey
then
say as warning 'Yubikey not detected'
say as warning 'Insert one to continue...'
until dmesg | grep -q -i YubiKey
do
sleep 1
done
fi
clear
say in uline white dim "## rev ${revision}"
echo -e -n "\n$(tput setab 7)$(tput setaf 4)$(tput bold)\t"
case ${arch} in
1) echo 'Basic Installation' ;;
2) echo 'Full Disk Encryption with EFISTUB' ;;
3) echo 'Full Disk Encryption with Secured GRUB' ;;
4) echo 'Yubikey Full Disk Encryption with EFISTUB' ;;
5) echo 'Yubikey Full Disk Encryption with Secured GRUB' ;;
6) echo 'Full Disk Encryption with Detached LUKS Header and Secured GRUB' ;;
7) echo 'Yubikey Encrypted Detached LUKS Header with Secured GRUB' ;;
esac
echo "$(tput sgr0)"
presskeytoresume
# Initial setup
if ls -l /dev/disk/* | grep -q 'VBOX\|virtio\|QEMU'
then
cacheserver=http://192.168.122.1:9090
case ${noconfirm} in
yes)
virtualMachineSetup
;;
*)
echo
while true
do
ask for load_defaults in press yellow 'Would you like to load virtual machine troubleshooting defaults? (y/n)'
case ${load_defaults} in
[yY])
virtualMachineSetup
break
;;
[nN])
initialSetup
break
;;
*)
echo
say as warning 'Not a valid answer, type "y" or "n"'
;;
esac
done
;;
esac
else
initialSetup
fi
# Linux firmware
if ls -l /dev/disk/* | grep -q VBOX
then
linux_firmware=(virtualbox-guest-utils)
systemd_services+=(vboxservice.service)
elif ls -l /dev/disk/* | grep -q 'virtio\|QEMU'
then
linux_firmware=(qemu-guest-agent spice-vdagent)
systemd_services+=(qemu-guest-agent.service)
else
# Detect needed firmwares
linux_firmware=(linux-firmware)
for firmware in $(pacman -Ssq linux-firmware- | sed 's/linux-firmware-//')
do
if lspci | grep -q -i ${firmware}
then
linux_firmware+=(linux-firmware-${firmware})
fi
done
fi
# Choose linux kernel
echo
say in blue "Select a linux kernel:"
cat <<- menu
1) linux
2) linux-lts
3) linux-hardened
4) linux-zen
menu
until [ ${linux_kernel} ]
do
ask for linux_kernel_choice in press ':'
case ${linux_kernel_choice} in
1) linux_kernel=linux ;;
2) linux_kernel=linux-lts ;;
3) linux_kernel=linux-hardened ;;
4) linux_kernel=linux-zen ;;
*) echo
say as warning 'Invalid selection, type an option from 1 to 4'
;;
esac
done
echo
say as success "You have chosen $(tput smso)${linux_kernel}$(tput rmso) for a kernel"
# GPU firmware
if lspci | grep VGA | grep -q QXL
then
linux_firmware+=(xf86-video-qxl)
fi
if lspci | grep VGA | grep -q NVIDIA
then
case ${linux_kernel} in
linux) nvidia=(nvidia-open nvidia-settings) ;;
linux-lts) nvidia=(nvidia-lts nvidia-settings) ;;
*) nvidia=(nvidia-dkms nvidia-settings) ;;
esac
fi
# Choose filesystem
echo
say in blue "Select a filesystem:"
cat <<- menu
1) ext4
2) btrfs
menu
if modprobe zfs >/dev/null 2>&1
then
cat <<- MENU
3) zfs
MENU
fi
until [[ ${filesystem_choice} = [1-3] ]]
do
ask for filesystem_choice in press ':'
if ! [[ ${filesystem_choice} = [1-3] ]]
then
echo
say as warning 'Invalid selection, type an option from 1 to 3'
fi
done
case ${filesystem_choice} in
1)
filesystem=ext4
rootflags='quiet rw'
;;
2)
filesystem=btrfs
rootflags='rootflags=subvol=@ quiet rw'
btrfs=(btrfs-progs timeshift cronie)
systemd_services+=(cronie.service)
;;
3)
filesystem=zfs
rootflags='zfs=bootfs quiet rw'
zfs=(zfs-${linux_kernel} zfs-utils)
;;
esac
echo
say as success "You have chosen $(tput smso)${filesystem}$(tput rmso) for a filesystem"
# Option to automatically decrypt / using a keyfile, only applies to encrypted GRUB/yubikey 1FA setups
if [[ ${arch} = [3-7] ]]
then
echo
if [[ ${arch} = [457] ]]
then
say in uline white dim '## Root will be decrypted as long as yubikey is inserted when prompted'
fi
until [[ ${decryptroot} = [yYnN] ]]
do
ask for decryptroot in press yellow "Would you like to automatically decrypt the root partition upon boot? (y/n)"
if ! [[ ${decryptroot} = [yYnN] ]]
then
echo
say as warning 'Not a valid answer, type "y" or "n"'
fi
done
fi
# Skip confirmations if flag is on
if [ -z ${noconfirm} ]
then
echo
# Device shredding
until [[ ${shred_installation_disk} = [yYnN] ]]
do
ask for shred_installation_disk in press yellow "Would you like to shred your installation drive? (y/n)"
if ! [[ ${shred_installation_disk} = [yYnN] ]]
then
echo
say as warning 'Not a valid answer, type "y" or "n"'
fi
done
if [[ ${arch} = [67] ]]
then
echo
until [[ ${shred_boot} = [yYnN] ]]
do
if [[ ${shred_installation_disk} = [yY] ]]
then
ask for shred_boot in press yellow "Would you also like to shred your removable drive? (y/n)"
else
ask for shred_boot in press yellow "Would you like to shred your removable drive? (y/n)"
fi
if ! [[ ${shred_boot} = [yYnN] ]]
then
echo
say as warning 'Not a valid answer, type "y" or "n"'
fi
done
fi
echo
if [[ ${shred_installation_disk} = [nN] && ${shred_boot} = [nN] ]] || [[ ${arch} != [67] && ${shred_installation_disk} = [nN] ]]
then
say in yellow 'Disk shredding skipped'
echo
elif [[ ${shred_installation_disk} = [yY] || ${shred_boot} = [yY] ]]
then
say in blue "Select an overwrite source:"
cat <<- menu
1) zero
2) urandom
menu
until [[ ${disk_destroyer} = [12] ]]
do
ask for disk_destroyer in press ':'
if ! [[ ${disk_destroyer} = [12] ]]
then
echo
say as warning 'Invalid selection, type an option from 1 to 2'
fi
done
echo
case ${disk_destroyer} in
1) dd=zero ;;
2) dd=urandom ;;
esac
fi
say as heading "Shredding drives"
cat <<- warning
$(tput setab 1)#############################################################$(tput sgr0)
$(tput setab 1)#############################################################$(tput sgr0)
$(tput setab 1) $(tput sgr0)
$(tput setab 1) $(tput blink)!!!WARNING!!! $(tput sgr0)
$(tput setab 1) !!!ALL DATA WILL BE WIPED FROM THE DRIVE!!! $(tput sgr0)
$(tput setab 1) $(tput sgr0)
$(tput setab 1)#############################################################$(tput sgr0)
$(tput setab 1)#############################################################$(tput sgr0)
## This will overwrite the drive by one pass
## Confirm by typing "Y" to proceed
## Anything other than capital Y will abort the installation
warning
ask for begin_install in press ':'
if ! [[ ${begin_install} = Y ]]
then
echo
say as warning 'Aborting installation'
say as warning 'Installer script stopped'
echo
exit 1
fi
fi # Skip disk shredding
# Unmount if mounted
for mounted in /mnt/boot /mnt
do
if mount | grep -q -w ${mounted}
then
umount -R ${mounted} || die 'A drive or partition is already mounted on /mnt, unable to proceed'
fi
done
# Export existing zpools
zpool export -a >/dev/null 2>&1
# Close opened luks containers
for mounted in cryptroot cryptboot
do
if dmsetup ls | grep -q -w ${mounted}
then
cryptsetup close "/dev/mapper/${mounted}" || die 'LUKS container already exists, unable to proceed'
fi
done
# Grab disk-id of ${drive}
installation_disk=$(ls -l /dev/disk/by-id/* | grep "${drive}$" | grep 'wwn\|nvme-uuid\|nvme-nvme\|nvme-eui\|QEMU\|virtio\|VBOX' | awk '{print $9}' | head -1)
external_boot=$(ls -l /dev/disk/by-id/* | grep "${external_drive}$" | grep 'wwn\|nvme-uuid\|nvme-nvme\|nvme-eui\|QEMU\|virtio\|VBOX\|usb' | awk '{print $9}' | head -1)
# Exit if disk IDs are null
if [ -z ${installation_disk} ]
then
die 'Ensure installation disk has a valid ID'
fi
if [ ${external_drive} ] && [ -z ${external_boot} ]
then
die 'Ensure external boot disk has a valid ID'
fi
echo
# Shred installation drive
blkdiscard --quiet --force --secure ${installation_disk} >/dev/null 2>&1
wipefs --quiet --force --all ${installation_disk}
if [[ ${shred_installation_disk} = [yY] ]]
then
say as heading "Shredding ${installation_disk}"
dd if=/dev/${dd} of=${installation_disk} bs=4M status=progress
echo 3 >/proc/sys/vm/drop_caches
echo
fi
# Shred external boot drive
if [[ ${arch} = [67] ]]
then
wipefs --quiet --force --all ${external_boot}
fi
if [[ ${shred_boot} = [yY] ]]
then
say as heading "Shredding ${external_boot}"
dd if=/dev/${dd} of=${external_boot} bs=4M status=progress
echo 3 >/proc/sys/vm/drop_caches
say as success 'Device shredded'
echo
fi
case ${arch} in
1) # Basic setup
parted --script --align=optimal ${installation_disk} \
mklabel gpt \
mkpart boot 1MiB 300MiB \
mkpart root 300MiB 100% \
set 1 esp on
partprobe ${installation_disk}
export {efivol,bootvol}=${installation_disk}-part1
export {rootpart,rootvol}=${installation_disk}-part2
configureVolumes
pacstrapGenfstab
echo
say as heading 'Configuring efistub'
efibootmgr --disk ${installation_disk} --part 1 --create --label "Arch Linux (${hostname})" --loader "/vmlinuz-${linux_kernel}" --unicode "initrd=\initramfs-${linux_kernel}.img root=${rootpart} ${rootflags}"
;;
2|4) # FDE with EFISTUB
parted --script --align=optimal ${installation_disk} \
mklabel gpt \
mkpart boot 1MiB 300MiB \
mkpart root 300MiB 100% \
set 1 esp on
partprobe ${installation_disk}
export {efivol,bootvol}=${installation_disk}-part1
rootpart=${installation_disk}-part2
rootvol=/dev/mapper/cryptroot
case ${arch} in
2)
case ${filesystem} in
zfs)
zpoolencryption="-O encryption=aes-256-gcm \
-O keyformat=passphrase \
-O keylocation=prompt"
rootvol=${installation_disk}-part2
;;
*) encryptRootLuks ;;
esac
;;
4) encryptRootYubikey ;;
esac
configureVolumes
pacstrapGenfstab
case ${arch} in
2)
echo
say as heading 'Configuring efistub'
case ${filesystem} in
zfs) efibootmgr --disk ${installation_disk} --part 1 --create --label "Arch Linux (${hostname})" --loader "/vmlinuz-${linux_kernel}" --unicode "initrd=\initramfs-${linux_kernel}.img ${rootflags}"
;;
btrfs|ext4)
encryptHook encrypt
efibootmgr --disk ${installation_disk} --part 1 --create --label "Arch Linux (${hostname})" --loader "/vmlinuz-${linux_kernel}" --unicode "initrd=\initramfs-${linux_kernel}.img cryptdevice=${rootpart}:cryptroot root=/dev/mapper/cryptroot ${rootflags}"
;;
esac
;;
4)
chrootYubikey
echo
say as heading 'Configuring efistub'
efibootmgr --disk ${installation_disk} --part 1 --create --label "Arch Linux (${hostname})" --loader "/vmlinuz-${linux_kernel}" --unicode "initrd=\initramfs-${linux_kernel}.img cryptdevice=${rootpart}:cryptroot root=/dev/mapper/cryptroot ${rootflags}"
;;
esac
;;
3|5) # FDE with Secured GRUB
parted --script --align=optimal ${installation_disk} \
mklabel gpt \
mkpart efi 1MiB 40MiB \
mkpart boot 40MiB 300MiB \
mkpart root 300MiB 100% \
set 1 esp on
partprobe ${installation_disk}
efivol=${installation_disk}-part1
bootpart=${installation_disk}-part2
rootpart=${installation_disk}-part3
rootvol=/dev/mapper/cryptroot
bootvol=/dev/mapper/cryptboot
case ${arch} in
3) encryptRootLuks ;;
5) encryptRootYubikey ;;
esac
encryptBootLuks
configureVolumes
generateKeyfile
pacstrapGenfstab
case ${arch} in
3)
encryptHook encrypt
if [[ ${decryptroot} = [yY] ]]
then
echo "FILES=(/crypto_keyfile.bin)" >/mnt/etc/mkinitcpio.conf.d/zz-files.conf
fi
;;
5)
chrootYubikey
echo "MODULES=(loop)" >/mnt/etc/mkinitcpio.conf.d/zz-modules.conf
;;
esac
sed "/^GRUB_CMDLINE_LINUX_DEFAULT/c GRUB_CMDLINE_LINUX_DEFAULT=\"cryptdevice=${rootpart}:cryptroot root=/dev/mapper/cryptroot ${rootflags}\"" \
-i /mnt/etc/default/grub
grep -q "${rootpart}" /mnt/etc/default/grub || die 'Grub cfg generation failed'
arch-chroot /mnt /usr/bin/bash <<- grub
configureGrub
grub
;;
6|7) # FDE with detached luks header
parted --script --align=optimal ${external_boot} \
mklabel gpt \
mkpart efi 1MiB 40MiB \
mkpart boot 40MiB 300MiB \
mkpart none 300MiB 100% \
set 1 esp on
partprobe ${external_boot}
rootpart=${installation_disk}
efivol=${external_boot}-part1
bootpart=${external_boot}-part2
rootvol=/dev/mapper/cryptroot
bootvol=/dev/mapper/cryptboot
luks_header=--header=header.img
case ${arch} in
6) encryptRootLuks ;;
7) encryptRootYubikey ;;
esac
encryptBootLuks
configureVolumes
mv header.img /mnt/boot
generateKeyfile
pacstrapGenfstab
# Mkinitcpio files
cpiofiles=(/boot/header.img)
case ${arch} in
6)
sed -e '/for cryptopt in/i\\n local headerFlag=false' \
-e '/case ${cryptopt} in/a\
header)\
cryptargs="${cryptargs} --header /boot/header.img"\
headerFlag=true\
;;' \
-e 's/cryptsetup isLuks/$headerFlag || &/' \
-i /mnt/usr/lib/initcpio/hooks/encrypt
encryptHook encrypt
# encrypt hook
install /dev/stdin /mnt/opt/local/hooks/encrypt-initcpio <<- 'hook'
#!/usr/bin/env bash
if [ -f /usr/lib/initcpio/hooks/encrypt.pacnew ]
then
sed -e '/for cryptopt in/i\\n local headerFlag=false' \
-e '/case ${cryptopt} in/a\
header)\
cryptargs="${cryptargs} --header /boot/header.img"\
headerFlag=true\
;;' \
-e 's/cryptsetup isLuks/$headerFlag || &/' \
-i /usr/lib/initcpio/hooks/encrypt.pacnew
mv /usr/lib/initcpio/hooks/encrypt.pacnew /usr/lib/initcpio/hooks/encrypt
fi
hook
cat >/mnt/etc/pacman.d/hooks/85-encrypt.hook <<- encrypt
[Trigger]
Operation = Install
Operation = Upgrade
Type = Package
Target = cryptsetup
[Action]
Description = Fixing encrypt hook for detached headers
When = PostTransaction
Exec = /opt/local/hooks/encrypt-initcpio
encrypt
if [[ ${decryptroot} = [yY] ]]
then
cpiofiles+=(/crypto_keyfile.bin)
fi
;;
7)
chrootYubikey
sed '/YKFDE_LUKS_OPTIONS/c YKFDE_LUKS_OPTIONS="--header=/boot/header.img"' -i /mnt/etc/ykfde.conf
;;
esac
# mkinitcpio.conf
echo "FILES=(${cpiofiles[@]})" >/mnt/etc/mkinitcpio.conf.d/zz-files.conf
echo "MODULES=(ext2 loop)" >/mnt/etc/mkinitcpio.conf.d/zz-modules.conf
sed "/^GRUB_CMDLINE_LINUX_DEFAULT/c GRUB_CMDLINE_LINUX_DEFAULT=\"cryptdevice=${rootpart}:cryptroot:header root=/dev/mapper/cryptroot ${rootflags}\"" \
-i /mnt/etc/default/grub
grep -q "${rootpart}" /mnt/etc/default/grub || die 'Grub cfg generation failed'
arch-chroot /mnt /usr/bin/bash <<- grub
configureGrub
grub
;;
esac
unset lukspass grubpass
# Re-activate mkinitcpio
rm -f /mnt/etc/pacman.d/hooks/90-mkinitcpio-install.hook
sed -e "s|%PKGBASE%|${linux_kernel}|g" \
-e "s/^fallback/#&/g" \
-e "s/ 'fallback'//" \
/mnt/usr/share/mkinitcpio/hook.preset >/mnt/etc/mkinitcpio.d/${linux_kernel}.preset
rsync -a /mnt/usr/lib/modules/*/vmlinuz /mnt/boot/vmlinuz-${linux_kernel}
# Copy some networking files
ln -s -f /run/systemd/resolve/stub-resolv.conf /mnt/etc/resolv.conf
rsync -a /etc/systemd/network/20-ethernet.network /mnt/etc/systemd/network/
if [ ${iwd} ]
then
rsync -a /usr/local/bin/iwd-connect /mnt/opt/local/bin/
chmod +x /mnt/opt/local/bin/iwd-connect
mkdir -p /mnt/var/lib/iwd /mnt/etc/iwd
rsync -a /var/lib/iwd/*.psk /mnt/var/lib/iwd/
# sed -i '/^Passphrase=/d' /mnt/var/lib/iwd/*.psk
cat >/mnt/etc/iwd/main.conf <<- iwd
[General]
EnableNetworkConfiguration=true
iwd
fi
# chroot setup
arch-chroot /mnt /usr/bin/bash <<- chroot || die "chroot setup failed"
curl --fail --silent https://git.myvelabs.com/lab/archlinux/raw/branch/master/functions/chroot -o /tmp/chroot
/usr/bin/bash /tmp/chroot
chroot
# System services
arch-chroot /mnt systemctl enable ${systemd_services[@]} || die "Unable to start systemd services"
# SSH Authentication
if [ -f sshkeys ]
then
cat sshkeys >/mnt/home/${username}/.ssh/authorized_keys
fi
# DE installer
install /dev/stdin /mnt/opt/local/bin/desktop <<- desktop
#!/usr/bin/env bash
set -e
if curl --fail --silent https://git.myvelabs.com/lab/archlinux/raw/branch/master/functions/desktop -o /tmp/desktop
then
/usr/bin/bash /tmp/desktop \${@}
sudo rm -f \${0}
else
exit 1
fi
desktop
# BTRFS fresh snapshot
case ${filesystem} in
btrfs)
arch-chroot /mnt /usr/bin/bash <<- "timeshift"
# Take fresh snapshots
timeshift --btrfs >/dev/null
timeshift --create --comments "Fresh install" >/dev/null
sed \
-e '/stop_cron_emails/ s/false/true/' \
-e '/schedule_monthly/ s/false/true/' \
-e '/schedule_weekly/ s/false/true/' \
-e '/schedule_daily/ s/false/true/' \
-e '/schedule_hourly/ s/false/true/' \
-e '/schedule_boot/ s/true/false/' \
-e '/count_monthly/ s/: ".*",/: "3",/' \
-e '/count_weekly/ s/: ".*",/: "4",/' \
-e '/count_daily/ s/: ".*",/: "5",/' \
-e '/count_hourly/ s/: ".*",/: "6",/' \
-i /etc/timeshift/timeshift.json
echo -e '\e[1;33mSnapshots taken\e[0m\n'
timeshift
;;
esac
# Reboot only if script succeeded
if arch-chroot /mnt uname -a | grep -q Linux
then
for mounted in /mnt/boot /mnt
do
umount -R ${mounted}
done
case ${filesystem} in
zfs)
zfs snapshot zroot/ROOT@fresh-installation
zpool export -a
;;
esac
say as success in bold "Installer has completed and system drive has been unmounted"
say as success in bold "Boot into the new system, connect to a network and install a DE by running $(tput smso)desktop$(tput rmso) in the terminal"
say as success in bold "Rebooting..."
echo
reboot
else
die 'Something does not feel right'
fi