mirror of
https://github.com/classy-giraffe/easy-arch.git
synced 2025-11-17 11:30:55 +00:00
the paralleldownloads sed in 2fb11db changes the value without actually uncommenting it, and the change the the "Color" sed in adds ILoveCandy without actually uncommenting Color. also made the color regex match "^#Color$" instead of "#Color" to make it more specific
470 lines
16 KiB
Bash
Executable file
470 lines
16 KiB
Bash
Executable file
#!/usr/bin/env -S bash -e
|
|
|
|
# Cleaning the TTY.
|
|
clear
|
|
|
|
# Colors/formatting for echo
|
|
BOLD='\e[1m'
|
|
UNDERLINE='\e[4m'
|
|
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} ] ${UNDERLINE}$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 -Fxq $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}${UNDERLINE}${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 -R 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 "s,^GRUB_CMDLINE_LINUX=\",&rd.luks.name=$UUID=cryptroot root=$BTRFS\",g" /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
|