easy-arch/easy-arch.sh
i-c-u-p c7536cef0e
remove underline text formatting from script
if the script is being run in the live arch iso's terminal and not through ssh, text underlines don't appear and the text just becomes blue, so they've been removed to make the appearance on both more alike.
2022-04-29 08:31:29 +00:00

469 lines
16 KiB
Bash
Executable file

#!/usr/bin/env -S bash -e
# Cleaning the TTY.
clear
# Colors/formatting for echo
BOLD='\e[1m'
RESET='\e[0m' # Reset text to default appearance
# High intensity colors:
BRED='\e[91m'
BGREEN='\e[92m'
BYELLOW='\e[93m'
BPURPLE='\e[95m'
# Pretty print (function).
print () {
echo -e "${BOLD}${BYELLOW}[ ${BGREEN}${BYELLOW} ] $1${RESET}"
}
# Alert user of bad input (function).
incEcho () {
echo -e "${BPURPLE}$1${RESET}"
}
# Virtualization check (function).
virt_check () {
hypervisor=$(systemd-detect-virt)
case $hypervisor in
kvm ) print "KVM has been detected."
print "Installing guest tools."
pacstrap /mnt qemu-guest-agent >/dev/null
print "Enabling specific services for the guest tools."
systemctl enable qemu-guest-agent --root=/mnt &>/dev/null
;;
vmware ) print "VMWare Workstation/ESXi has been detected."
print "Installing guest tools."
pacstrap /mnt open-vm-tools >/dev/null
print "Enabling specific services for the guest tools."
systemctl enable vmtoolsd --root=/mnt &>/dev/null
systemctl enable vmware-vmblock-fuse --root=/mnt &>/dev/null
;;
oracle ) print "VirtualBox has been detected."
print "Installing guest tools."
pacstrap /mnt virtualbox-guest-utils >/dev/null
print "Enabling specific services for the guest tools."
systemctl enable vboxservice --root=/mnt &>/dev/null
;;
microsoft ) print "Hyper-V has been detected."
print "Installing guest tools."
pacstrap /mnt hyperv >/dev/null
print "Enabling specific services for the guest tools."
systemctl enable hv_fcopy_daemon --root=/mnt &>/dev/null
systemctl enable hv_kvp_daemon --root=/mnt &>/dev/null
systemctl enable hv_vss_daemon --root=/mnt &>/dev/null
esac
}
# Selecting a kernel to install (function).
kernel_selector () {
print "List of kernels:"
print "1) Stable: Vanilla Linux kernel with a few specific Arch Linux patches applied"
print "2) Hardened: A security-focused Linux kernel"
print "3) LTS: Long-term support (LTS) Linux kernel"
print "4) Zen: A Linux kernel optimized for desktop usage"
read -r -p "Insert the number of the corresponding kernel: " kernel_choice
case $kernel_choice in
1 ) kernel="linux"
return 0;;
2 ) kernel="linux-hardened"
return 0;;
3 ) kernel="linux-lts"
return 0;;
4 ) kernel="linux-zen"
return 0;;
* ) incEcho "You did not enter a valid selection."
return 1
esac
}
# Selecting a way to handle internet connection (function).
network_selector () {
print "Network utilities:"
print "1) IWD: iNet wireless daemon is a wireless daemon for Linux written by Intel (WiFi-only)"
print "2) NetworkManager: Universal network utility to automatically connect to networks (both WiFi and Ethernet)"
print "3) wpa_supplicant: Cross-platform supplicant with support for WEP, WPA and WPA2 (WiFi-only, a DHCP client will be automatically installed as well)"
print "4) dhcpcd: Basic DHCP client (Ethernet only or VMs)"
print "5) I will do this on my own (only advanced users)"
read -r -p "Insert the number of the corresponding networking utility: " network_choice
if ! ((1 <= network_choice <= 5)); then
incEcho "You did not enter a valid selection."
return 1
fi
}
# Installing the chosen networking method to the system (function).
network_installer () {
case $network_choice in
1 ) print "Installing IWD."
pacstrap /mnt iwd >/dev/null
print "Enabling IWD."
systemctl enable iwd --root=/mnt &>/dev/null
;;
2 ) print "Installing NetworkManager."
pacstrap /mnt networkmanager >/dev/null
print "Enabling NetworkManager."
systemctl enable NetworkManager --root=/mnt &>/dev/null
;;
3 ) print "Installing wpa_supplicant and dhcpcd."
pacstrap /mnt wpa_supplicant dhcpcd >/dev/null
print "Enabling wpa_supplicant and dhcpcd."
systemctl enable wpa_supplicant --root=/mnt &>/dev/null
systemctl enable dhcpcd --root=/mnt &>/dev/null
;;
4 ) print "Installing dhcpcd."
pacstrap /mnt dhcpcd >/dev/null
print "Enabling dhcpcd."
systemctl enable dhcpcd --root=/mnt &>/dev/null
esac
}
# User enters a password for the LUKS Container (function).
lukspass_selector () {
while true; do
read -r -s -p "Insert password for the LUKS container (you're not going to see the password): " password
while [ -z "$password" ]; do
echo
incEcho "You need to enter a password for the LUKS Container in order to continue."
read -r -s -p "Insert password for the LUKS container (you're not going to see the password): " password
[ -n "$password" ] && break
done
echo
read -r -s -p "Password (again): " password2
echo
[ "$password" = "$password2" ] && break
incEcho "Passwords don't match, try again."
done
}
# User enters a password for the user account (function).
userpass_selector () {
while true; do
read -r -s -p "Set a user password for $username: " userpass
while [ -z "$userpass" ]; do
echo
incEcho "You need to enter a password for $username."
read -r -s -p "Set a user password for $username: " userpass
[ -n "$userpass" ] && break
done
echo
read -r -s -p "Insert password again: " userpass2
echo
[ "$userpass" = "$userpass2" ] && break
incEcho "Passwords don't match, try again."
done
}
# User enters a password for the root account (function).
rootpass_selector () {
while true; do
read -r -s -p "Set a root password: " rootpass
while [ -z "$rootpass" ]; do
echo
incEcho "You need to enter a root password."
read -r -s -p "Set a root password: " rootpass
[ -n "$rootpass" ] && break
done
echo
read -r -s -p "Password (again): " rootpass2
echo
[ "$rootpass" = "$rootpass2" ] && break
incEcho "Passwords don't match, try again."
done
}
# Microcode detector (function).
microcode_detector () {
CPU=$(grep vendor_id /proc/cpuinfo)
if [[ $CPU == *"AuthenticAMD"* ]]; then
print "An AMD CPU has been detected, the AMD microcode will be installed."
microcode="amd-ucode"
else
print "An Intel CPU has been detected, the Intel microcode will be installed."
microcode="intel-ucode"
fi
}
# User enters a hostname (function).
hostname_selector () {
read -r -p "Please enter the hostname: " hostname
if [ -z "$hostname" ]; then
incEcho "You need to enter a hostname in order to continue."
return 1
fi
return 0
}
# User chooses the locale (function).
locale_selector () {
read -r -p "Please insert the locale you use (format: xx_XX. Enter empty to use en_US, or \"/\" to search locales): " locale
case $locale in
'') print "en_US will be used as default locale."
locale="en_US.UTF-8";;
'/') sed -E '/^# +|^#$/d;s/^#| *$//g;s/ .*/ (Charset:&)/' /etc/locale.gen | less -M
clear
return 1;;
*) if ! grep -q "^#\?$(sed 's/[].*[]/\\&/g' <<< $locale) " /etc/locale.gen; then
incEcho "The specified locale doesn't exist or isn't supported."
return 1
fi
return 0
esac
}
# User chooses the console keyboard layout (function).
keyboard_selector () {
read -r -p "Please insert the keyboard keymap/layout to use in console (enter empty to use us, or \"/\" to search keymaps): " kblayout
case $kblayout in
'') print "The us keymap will be used in console by default."
kblayout="us"
return 0;;
'/') localectl list-keymaps
clear
return 1;;
*) if ! localectl list-keymaps | grep -Fxq $kblayout; then
incEcho "The specified keymap doesn't exist."
return 1
fi
print "Changing console layout to $kblayout."
loadkeys $kblayout
return 0
esac
}
# Selecting the target for the installation.
print "Welcome to easy-arch, a script made in order to simplify the process of installing Arch Linux."
# Setting up keyboard layout.
until keyboard_selector; do : ; done
PS3="Please select the disk NUMBER (e.g. 1) where Arch Linux is going to be installed: "
select ENTRY in $(lsblk -dpnoNAME|grep -P "/dev/sd|nvme|vd");
do
DISK=$ENTRY
print "Arch Linux will be installed to $DISK."
break
done
# Warn user about deletion of old partition scheme.
echo -en "${BOLD}${BRED}This will delete the current partition table on $DISK once installation starts. Do you agree [y/N]?:${RESET} "
read -r disk_response
disk_response=${disk_response,,}
if ! [[ "$disk_response" =~ ^(yes|y)$ ]]; then
print "Quitting."
exit
fi
# Setting up LUKS password.
lukspass_selector
# Setting up the kernel.
until kernel_selector; do : ; done
# User choses the network.
until network_selector; do : ; done
# User choses the locale.
until locale_selector; do : ; done
# User choses the hostname.
until hostname_selector; do : ; done
# User chooses username.
read -r -p "Please enter name for a user account (enter empty to not create one): " username
userpass_selector
rootpass_selector
# Deleting old partition scheme.
print "Wiping $DISK."
wipefs -af "$DISK" &>/dev/null
sgdisk -Zo "$DISK" &>/dev/null
# Creating a new partition scheme.
print "Creating the partitions on $DISK."
parted -s "$DISK" \
mklabel gpt \
mkpart ESP fat32 1MiB 513MiB \
set 1 esp on \
mkpart CRYPTROOT 513MiB 100% \
ESP="/dev/disk/by-partlabel/ESP"
CRYPTROOT="/dev/disk/by-partlabel/CRYPTROOT"
# Informing the Kernel of the changes.
print "Informing the Kernel about the disk changes."
partprobe "$DISK"
# Formatting the ESP as FAT32.
print "Formatting the EFI Partition as FAT32."
mkfs.fat -F 32 $ESP &>/dev/null
# Creating a LUKS Container for the root partition.
print "Creating LUKS Container for the root partition."
echo -n "$password" | cryptsetup luksFormat "$CRYPTROOT" -d -
echo -n "$password" | cryptsetup open "$CRYPTROOT" cryptroot -d -
BTRFS="/dev/mapper/cryptroot"
# Formatting the LUKS Container as BTRFS.
print "Formatting the LUKS container as BTRFS."
mkfs.btrfs $BTRFS &>/dev/null
mount $BTRFS /mnt
# Creating BTRFS subvolumes.
print "Creating BTRFS subvolumes."
subvols=(snapshots var_pkgs var_log home root srv)
for subvol in '' "${subvols[@]}"; do
btrfs su cr /mnt/@"$subvol"
done
# Mounting the newly created subvolumes.
umount /mnt
print "Mounting the newly created subvolumes."
mountopts="ssd,noatime,compress-force=zstd:3,discard=async"
mount -o $mountopts,subvol=@ $BTRFS /mnt
mkdir -p /mnt/{home,root,srv,.snapshots,var/{log,cache/pacman/pkg},boot}
for subvol in "${subvols[@]:2}"; do # ":2" excludes first two subvols (@snapshots and @var_pkgs) from loop
mount -o "$mountopts",subvol=@"$subvol" "$BTRFS" /mnt/"$(sed 's,_,/,g' <<< "$subvol")"
done
chmod 750 /mnt/root
mount -o $mountopts,subvol=@snapshots $BTRFS /mnt/.snapshots
mount -o $mountopts,subvol=@var_pkgs $BTRFS /mnt/var/cache/pacman/pkg
chattr +C /mnt/var/log
mount $ESP /mnt/boot/
# Pacstrap (setting up a base sytem onto the new root).
print "Installing the base system (it may take a while)."
pacstrap /mnt --needed base $kernel $microcode linux-firmware $kernel-headers btrfs-progs grub grub-btrfs rsync efibootmgr snapper reflector base-devel snap-pac zram-generator >/dev/null
# Setting up the hostname.
echo "$hostname" > /mnt/etc/hostname
# Generating /etc/fstab.
print "Generating a new fstab."
genfstab -U /mnt >> /mnt/etc/fstab
# Configure selected locale and console keymap
sed -i "s/^#$locale/$locale/" /mnt/etc/locale.gen
echo "LANG=$locale" > /mnt/etc/locale.conf
echo "KEYMAP=$kblayout" > /mnt/etc/vconsole.conf
# Setting hosts file.
print "Setting hosts file."
cat > /mnt/etc/hosts <<EOF
127.0.0.1 localhost
::1 localhost
127.0.1.1 $hostname.localdomain $hostname
EOF
# Checking the microcode to install.
microcode_detector
# Virtualization check.
virt_check
# Setting up the network.
network_installer
# Configuring /etc/mkinitcpio.conf.
print "Configuring /etc/mkinitcpio.conf."
cat > /mnt/etc/mkinitcpio.conf <<EOF
HOOKS=(base systemd autodetect keyboard sd-vconsole modconf block sd-encrypt filesystems)
COMPRESSION=(zstd)
EOF
# Setting up LUKS2 encryption in grub.
print "Setting up grub config."
UUID=$(blkid -s UUID -o value $CRYPTROOT)
sed -i "\,^GRUB_CMDLINE_LINUX=\"\",s,\",&rd.luks.name=$UUID=cryptroot root=$BTRFS," /mnt/etc/default/grub
# Configuring the system.
arch-chroot /mnt /bin/bash -e <<EOF
# Setting up timezone.
echo "Setting up the timezone."
ln -sf /usr/share/zoneinfo/$(curl -s http://ip-api.com/line?fields=timezone) /etc/localtime &>/dev/null
# Setting up clock.
echo "Setting up the system clock."
hwclock --systohc
# Generating locales.
echo "Generating locales."
locale-gen &>/dev/null
# Generating a new initramfs.
echo "Creating a new initramfs."
mkinitcpio -P &>/dev/null
# Snapper configuration
echo "Configuring Snapper."
umount /.snapshots
rm -r /.snapshots
snapper --no-dbus -c root create-config /
btrfs subvolume delete /.snapshots &>/dev/null
mkdir /.snapshots
mount -a
chmod 750 /.snapshots
# Installing GRUB.
echo "Installing GRUB on /boot."
grub-install --target=x86_64-efi --efi-directory=/boot/ --bootloader-id=GRUB &>/dev/null
# Creating grub config file.
echo "Creating GRUB config file."
grub-mkconfig -o /boot/grub/grub.cfg &>/dev/null
EOF
# Setting root password.
print "Setting root password."
echo "root:$rootpass" | arch-chroot /mnt chpasswd
# Setting user password.
if [ -n "$username" ]; then
print "Adding the user $username to the system with root privilege."
arch-chroot /mnt useradd -m -G wheel -s /bin/bash "$username"
sed -i '/^# %wheel ALL=(ALL) ALL/s/^# //' /mnt/etc/sudoers
print "Setting user password for $username."
echo "$username:$userpass" | arch-chroot /mnt chpasswd
fi
# Boot backup hook.
print "Configuring /boot backup when pacman transactions are made."
mkdir /mnt/etc/pacman.d/hooks
cat > /mnt/etc/pacman.d/hooks/50-bootbackup.hook <<EOF
[Trigger]
Operation = Upgrade
Operation = Install
Operation = Remove
Type = Path
Target = usr/lib/modules/*/vmlinuz
[Action]
Depends = rsync
Description = Backing up /boot...
When = PostTransaction
Exec = /usr/bin/rsync -a --delete /boot /.bootbackup
EOF
# ZRAM configuration.
print "Configuring ZRAM."
cat > /mnt/etc/systemd/zram-generator.conf <<EOF
[zram0]
zram-size = min(ram, 8192)
EOF
# Pacman eye-candy features.
print "Enabling colours, animations, and parallel in pacman."
sed -i 's/^#Color$/Color\nILoveCandy/;s/^#ParallelDownloads.*/ParallelDownloads = 10/' /mnt/etc/pacman.conf
# Enabling various services.
print "Enabling Reflector, automatic snapshots, BTRFS scrubbing and systemd-oomd."
for service in reflector.timer snapper-timeline.timer snapper-cleanup.timer btrfs-scrub@-.timer btrfs-scrub@home.timer btrfs-scrub@var-log.timer btrfs-scrub@\\x2esnapshots.timer grub-btrfs.path systemd-oomd
do
systemctl enable "$service" --root=/mnt &>/dev/null
done
# Finishing up.
print "Done, you may now wish to reboot (further changes can be done by chrooting into /mnt)."
exit