#!/usr/bin/env bash
set -a
set -E
# SSH public keys
sshkeys=''
## Tput codes
reset=$(tput sgr0)
bold=$(tput bold)
italic=$(tput sitm)
blink=$(tput blink)
black=${reset}$(tput setaf 0)
red=${reset}$(tput setaf 1)
green=${reset}$(tput setaf 2)
yellow=${reset}$(tput setaf 3)
blue=${reset}$(tput setaf 4)
magenta=${reset}$(tput setaf 5)
cyan=${reset}$(tput setaf 6)
white=${reset}$(tput setaf 7)
# Color codes
function say
{
for format in ${@:2}
do
echo -n ${!format}
done
echo -e "${1}"
echo -n ${reset}
}
function say_n
{
for format in ${@:2}
do
echo -n ${!format}
done
echo -e -n "${1}"
echo -n ${reset}
}
# Exit function
trap '[ "$?" -ne 77 ] || exit 77' ERR
function die
{
cat <<- abort
${red}
Error encountered for the following reason:
${yellow}
"${1}"
${red}
Script aborted...
${reset}
abort
exit 77
}
# 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 \e[32miwd-connect\e[33m if using wifi and try again'
fi
function returnUUID
{
for partuuid in \
$(blkid -s UUID -o value ${1}) \
$(lsblk -d -n -o uuid ${1}) \
$(ls -l -a /dev/disk/by-uuid | grep "$(echo ${1} | sed 's\/dev\\')" | awk '{print $9}')
do
if [ ${partuuid} ]
then
echo ${partuuid}
break
else
unset partuuid
fi
done
if [ -z ${partuuid} ]
then
die 'Unable to determine partition UUID'
fi
}
clear
cat <
' kernel_choice
echo
if ! [[ ${kernel_choice} = [1-4] ]]
then
echo
say 'Invalid selection, type an option from 1 to 4' red
fi
done
case ${kernel_choice} in
1)
linux_kernel='linux'
;;
2)
linux_kernel='linux-lts'
;;
3)
linux_kernel='linux-hardened'
;;
4)
linux_kernel='linux-zen'
;;
esac
echo
say " You have chosen ${green}${linux_kernel}${reset} as a kernel" reset
echo
# Unmount if mounted
if findmnt '/mnt' | grep -q -w '/mnt'
then
umount -R /mnt
fi
# Shred installation drive
say "Partitioning /dev/${installation_disk}" yellow bold
wipefs -f -a /dev/${installation_disk}
blkdiscard -f /dev/${installation_disk}
if [ -d /sys/firmware/efi/efivars ]
then
parted --script --align=optimal /dev/${installation_disk} \
mklabel gpt \
mkpart primary fat32 1MiB 100MiB \
mkpart primary ${partition} 100MiB 100% \
set 1 esp on
partprobe /dev/${installation_disk}
export {efivol,bootvol}=/dev/$(lsblk -l -o name | grep "${installation_disk}".*1$)
export {rootpart,rootvol}=/dev/$(lsblk -l -o name | grep "${installation_disk}".*2$)
echo
function bootLoader
{
# Systemd-boot
say "Configuring systemd-boot" yellow bold
bootctl --path=/boot install
echo -e 'title Arch Linux
linux /vmlinuz-'${linux_kernel}'
initrd /initramfs-'${linux_kernel}'.img
options quiet root=UUID='$(returnUUID ${rootpart})' rw' > /boot/loader/entries/arch.conf
echo -e 'default arch
timeout 0
console-mode max
editor no' > /boot/loader/loader.conf
systemdbootservice='systemd-boot-update.service'
}
else
bios='syslinux'
parted --script --align=optimal /dev/${installation_disk} \
mklabel msdos \
mkpart primary ${partition} 1MiB 100% \
set 1 boot on || die 'Disk partitioning failed'
partprobe /dev/${installation_disk}
export {rootpart,rootvol}=/dev/$(lsblk -l -o name | grep "${installation_disk}".*1$)
echo
function bootLoader
{
# Syslinux
say "Configuring syslinux" yellow bold
syslinux-install_update -i -a -m
sed -i 's\LINUX ../vmlinuz-linux.*\LINUX ../vmlinuz-'${linux_kernel}'\g' /boot/syslinux/syslinux.cfg
sed -i 's/APPEND root.*/APPEND root=UUID='"$(returnUUID ${rootpart})"' rw quiet/g' /boot/syslinux/syslinux.cfg
sed -i 's/.*PROMPT.*/PROMPT 0/g' /boot/syslinux/syslinux.cfg
sed -i 's/.*TIMEOUT.*/TIMEOUT 0/g' /boot/syslinux/syslinux.cfg
sed -i 's/.*UI menu.*/#UI menu/g' /boot/syslinux/syslinux.cfg
}
fi
say "Configuring volumes" yellow bold
yes | mkfs.ext4 ${rootvol}
mount ${rootvol} /mnt
if [ -d /sys/firmware/efi/efivars ]
then
mkdir /mnt/boot
yes | mkfs.fat -F 32 ${efivol}
mount ${bootvol} /mnt/boot
findmnt '/mnt/boot' | grep -q -w "${bootvol}" || die 'Boot partition has not been mounted properly'
echo
fi
say "Installing Arch Linux base packages on /dev/${installation_disk}" yellow bold
sed -i \
-e '/Color/c\Color' \
-e '/ParallelDownloads/c\ParallelDownloads = 10' \
-e 's#^\[core\]$\|^\[extra\]$#&\
CacheServer = http://192.168.122.1:9090#' \
/etc/pacman.conf
# Temporarily disable mkinitcpio
ln -s -f /dev/null /etc/pacman.d/hooks/90-mkinitcpio-install.hook
pacstrap -K /mnt ${linux_kernel} qemu-guest-agent base mkinitcpio sudo \
${bios} reflector openssh rsync \
wireguard-tools systemd-resolvconf \
pacman-contrib bash-completion vim
genfstab -U -p /mnt >> /mnt/etc/fstab
grep -q 'UUID' /mnt/etc/fstab || die
# Make custom directories
mkdir -p /mnt/etc/pacman.d/hooks /mnt/usr/bin/local
# pacman.conf hook
install /dev/stdin /mnt/usr/bin/local/hook-pacman.conf </mnt/etc/pacman.d/hooks/pacman.conf.hook </mnt/etc/mkinitcpio.d/linux.preset
rm /mnt/usr/share/mkinitcpio/hook.preset
rsync -a /mnt/usr/lib/modules/*/vmlinuz /mnt/boot/vmlinuz-linux
# mkinitcpio preset hook
cat >/mnt/etc/pacman.d/hooks/linux.preset.hook </etc/mkinitcpio.d/linux.preset
rm /usr/share/mkinitcpio/hook.preset
fi
hook
arch-chroot /mnt mkinitcpio -P
# Networking
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
arch-chroot /mnt /bin/bash <<"SYU"
# Install bootloader
echo
bootLoader
echo
# Locale
sed -i '/#en_US.UTF-8 UTF-8/ s/#//' /etc/locale.gen
locale-gen >/dev/null
echo 'LANG=en_US.UTF-8' >>/etc/locale.conf
say 'Locale configured' yellow bold
# Time zone
ln -s -f /usr/share/zoneinfo/UTC /etc/localtime
hwclock --systohc --utc
say 'Time zone configured' yellow bold
# Hostname
echo ${hostname} >/etc/hostname
cat >>/etc/hosts </dev/null
echo '%wheel ALL=(ALL:ALL) ALL' > /etc/sudoers.d/wheel
else
echo -e '%wheel ALL=(ALL:ALL) NOPASSWD: ALL' > /etc/sudoers.d/wheel
mkdir -p /etc/systemd/system/getty@tty1.service.d
echo '[Service]
ExecStart=
ExecStart=-/usr/bin/agetty --autologin user --noclear %I $TERM' > /etc/systemd/system/getty@tty1.service.d/override.conf
fi
if [ "$rootpass" ]
then
printf '%s\n' "$rootpass" "$rootpass" | passwd &>/dev/null
fi
say "Configured superuser and user" yellow bold
echo
# Sysctl custom settings
echo -e 'net.core.netdev_max_backlog = 16384
net.core.somaxconn = 8192
net.core.rmem_default = 1048576
net.core.rmem_max = 16777216
net.core.wmem_default = 1048576
net.core.wmem_max = 16777216
net.core.optmem_max = 65536
net.ipv4.tcp_rmem = 4096 1048576 2097152
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.udp_rmem_min = 8192
net.ipv4.udp_wmem_min = 8192
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_timestamps = 0
net.core.default_qdisc = cake
net.ipv4.tcp_congestion_control = bbr' > /etc/sysctl.d/99-sysctl.conf
# iptables
install /dev/stdin /usr/bin/local/iptables.hook </etc/pacman.d/hooks/iptables.rules.hook </etc/pacman.d/hooks/paccache.hook <<'paccache'
[Trigger]
Operation = Upgrade
Operation = Install
Operation = Remove
Type = Package
Target = *
[Action]
Description = Cleaning pacman cache...
When = PostTransaction
Exec = /usr/bin/paccache -r
paccache
# locale.gen.pacnew hook
install /dev/stdin /usr/bin/local/hook-localegen </dev/null
fi
hook
# locale.gen.pacnew hook
cat >/etc/pacman.d/hooks/localegen.hook </etc/ssh/sshd_config.d/10-sshd.conf </etc/ssh/ssh_config.d/10-global.conf </etc/polkit-1/rules.d/49-nopasswd_global.rules <<'polkit'
/* Allow members of the wheel group to execute any actions
* without password authentication, similar to "sudo NOPASSWD:"
*/
polkit.addRule(function(action, subject) {
if (subject.isInGroup("wheel")) {
return polkit.Result.YES;
}
});
polkit
# Custom pacman wrapper
install /dev/stdin /usr/local/bin/syu < ~/.ssh/authorized_keys
# bash
# cp /etc/skel/.bash* ~/
cat >> ~/.bashrc <<'BASHRC'
unset HISTFILE
alias ll='ls -l -a -h'
# Grep color
alias grep='grep --color=auto'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
# Adjust terminal upon window resize
shopt -s checkwinsize
# Auto cd into directory
shopt -s autocd
# Ignore duplicate and whitespace history entries
export HISTCONTROL=ignoreboth
#
# ~/.bash_aliases
#
# Reboot and poweroff
alias poweroff='sudo poweroff'
alias reboot='sudo reboot'
# Miscellanous pacman
alias orphans='pacman -Rcns $(pacman -Qtdq)'
alias unlockpacmandb='rm /var/lib/pacman/db.lck && pacman -Syy'
# Rsync
alias rsync='rsync --progress --info=progress2 -v -h'
#
# ~/.bash_functions
#
# Pacman tools
function installer
{
sudo pacman -S "$@"
echo
}
function uninstall
{
sudo pacman -Rcns "$@"
echo
}
function syur
{
/usr/local/bin/syu &&
reboot
}
function syup
{
/usr/local/bin/syu &&
poweroff
}
# Update configs
function update-bash
{
vim ~/.bashrc &&
source ~/.bashrc
}
BASHRC
CHANGEUSER
SYU
# Script for installing desktop environment
install /dev/stdin /mnt/usr/local/bin/desktop <<'DESKTOPINSTALL'
#!/usr/bin/env bash
set -a -E
# Exit function
trap '[ "$?" -ne 77 ] || exit 77' ERR
die()
{
echo -e '\e[1;31m\nError encountered, script aborted...\n\e[0m'
exit 77
}
# 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
sudo timedatectl set-ntp true
else
echo -e '\n\e[31mNo internet connectivity detected'
echo -e 'Connect to a network and try again'
echo -e 'Aborting installer...\e[0m\n'
die
fi
echo -e '\n\e[1;35mSelect a desktop\e[0m'
echo -e '\t1) i3'
echo -e '\t2) none'
until [[ ${desktop} = [12] ]]
do
read -n 1 -p '> ' desktop
[[ ${desktop} = [12] ]] || echo -e '\n\n\e[1;31mInvalid selection, type an option from 1 to 2\e[0m'
done
# Assign DE variables
case ${desktop} in
1)
# Install and configure x
echo -e '\n\n\t\e[1mYou have chosen \e[32mi3\e[0m\e[1m desktop\e[0m'
echo -e '\n\e[1;35mInstalling base packages\e[0m'
sudo pacman -S --noconfirm spice-vdagent xf86-video-qxl xorg xorg-xinit phonon-qt5-gstreamer ttf-dejavu ttf-liberation noto-fonts noto-fonts-cjk noto-fonts-emoji firefox i3-gaps i3status i3lock dmenu lightdm lightdm-gtk-greeter pavucontrol konsole kate dolphin kompare breeze-icons
echo
echo 'exec i3' > ~/.xinitrc
echo -e '\nXDG_CURRENT_DESKTOP=gnome' | sudo tee -a /etc/environment >/dev/null
# i3
mkdir -p ~/.config/i3
curl -s -L https://raw.githubusercontent.com/i3/i3/next/etc/config | sed 's/exec i3-config-wizard/# &/' > ~/.config/i3/config
tee -a ~/.config/i3/config >/dev/null <<'I3CONFIG'
exec xrandr --output $(xrandr -q | grep -w 'connected primary' | awk '{print $1}') --mode 1920x1080
gaps inner 8
gaps outer 4
# for_window [class="^.*"] border pixel 2
exec spice-vdagent
I3CONFIG
# i3 function
echo -e '\n# i3 config
function i3-config
{
vim ~/.config/i3/config
}' >> ~/.bash_functions
cat >> ~/.bashrc <<'BASHRC'
# Autostart i3
if [ -z "$DISPLAY" ] && [ "$XDG_VTNR" = 1 ]
then
exec startx
fi
BASHRC
;;
2) echo
;;
esac
sudo rm -f ${0}
case ${desktop} in
1)
echo -e '\e[1;34mDesktop installed, press any key to load i3\e[5m...\e[0m\n'
read -n 1 -s
sudo systemctl -q enable --now lightdm.service
;;
2)
echo -e '\e[1;34mSetup complete, press any key to continue\e[5m...\e[0m\n'
read -n 1 -s
;;
*)
die
;;
esac
DESKTOPINSTALL
# Reboot only if script succeeded
if /usr/bin/sh -c 'arch-chroot /mnt uname -a' | grep -q Linux
then
umount -R /mnt
echo -e '\e[1;34mInstaller has completed and system drive has been unmounted'
echo -e 'Boot into the new system, connect to a network and install a DE by running \e[35mdesktop\e[34m in the terminal'
echo -e 'Rebooting...\n\e[0m'
reboot
else
die
fi