#!/usr/bin/env bash # shellcheck disable=SC2207,SC2120 SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" # Set up a config file CONFIG_FILE="$SCRIPT_DIR"/setup.conf [[ -f "$CONFIG_FILE" ]] && rm -f "$CONFIG_FILE" >/dev/null 2>&1 set_option() { if grep -Eq "^${1}.*" "$CONFIG_FILE"; then sed -i -e "/^${1}.*/d" "$CONFIG_FILE" fi echo "${1}=${2}" >>"$CONFIG_FILE" } # Adding global functions and variables to use in this script check_root() { if [[ "$(id -u)" != "0" ]]; then echo -ne "ERROR! This script must be running under the 'root' user!\n" exit 0 fi } check_docker() { if awk -F/ '$2 == "docker"' /proc/self/cgroup | read -r; then echo -ne "ERROR! Docker container not supported (at the moment)\n" exit 0 elif [[ -f /.dockerenv ]]; then echo -ne "ERROR! Docker container not supported (at the moment)\n" exit 0 fi } check_arch() { if [[ ! -e /etc/arch-release ]]; then echo -ne "ERROR! This script must be run in Arch Linux!\n" exit 0 fi } check_pacman() { if [[ -f /var/lib/pacman/db.lck ]]; then echo "ERROR! Pacman is blocked." echo -ne "If not running remove /var/lib/pacman/db.lck.\n" exit 0 fi } connection_test() { ping -q -w 1 -c 1 "$(ip r | grep default | awk 'NR==1 {print $3}')" &>/dev/null && return 1 || return 0 } do_curl() { _ISO=$(curl --fail https://ifconfig.co/country-iso) set_option "ISO" "$_ISO" } set_ntp() { timedatectl set-ntp true } efi_check() { if [[ -d "/sys/firmware/efi/" ]]; then if (mount | grep /sys/firmware/efi/efivars); then (mount -t efivarfs efivarfs /sys/firmware/efi/efivars) >/dev/null 2>&1 fi set_option "UEFI" 1 else set_option "UEFI" 0 fi } set_btrfs() { echo "Please enter your btrfs subvolumes separated by space" echo "usualy they start with @." echo "[like @home, default are @home, @var, @tmp, @.snapshots]" echo " " read -r -p "press enter to use default: " -a ARR if [[ -z "${ARR[*]}" ]]; then set_option "SUBVOLUMES" "(@ @home @var @tmp @.snapshots)" else NAMES=(@) for i in "${ARR[@]}"; do if [[ $i =~ [@] ]]; then NAMES+=("$i") else NAMES+=(@"${i}") fi done IFS=" " read -r -a SUBS <<<"$(tr ' ' '\n' <<<"${NAMES[@]}" | awk '!x[$0]++' | tr '\n' ' ')" set_option "SUBVOLUMES" "${SUBS[*]}" fi } set_lvm() { read -r -p "Name your lvm volume group [like MyVolGroup, default is MyVolGroup]: " _VG if [[ -z "$_VG" ]]; then _VG="MyVolGroup" fi read -r -p "Enter number of partitions [like 2, default is 1]: " _PART_NUM echo "Please make sure 1st partition is considered as root partition" echo "And will be mounted at /mnt/ and other partitions will be mounted" echo "at /mnt/partition_name by making a directory /mnt/partition_name" i=1 _LVM_NAMES=() LVM_SIZES=() if [[ -z "$_PART_NUM" ]]; then _PART_NUM=1 _LVM_NAMES+=("root") # LVM_SIZES+=("100%FREE") i=2 fi while [[ $i -le "$_PART_NUM" ]]; do if [[ "$_PART_NUM" -eq "1" ]]; then read -r -p "Enter last partition name [like home]: " _LVM_NAME _LVM_NAMES+=("$_LVM_NAME") fi read -r -p "Enter $i partition name [like root]: " _LVM_NAME _LVM_NAMES+=("$_LVM_NAME") read -r -p "Enter $i partition size [like 25G, 200M]: " _LVM_SIZE LVM_SIZES+=("$_LVM_SIZE") i=$((i + 1)) done IFS=" " read -r -a LVM_NAMES <<<"$(tr ' ' '\n' <<<"${_LVM_NAMES[@]}" | awk '!x[$0]++' | tr '\n' ' ')" set_option "LVM_VG" "$_VG" set_option "LVM_PART_NUM" "$_PART_NUM" set_option "LVM_NAMES" "(${LVM_NAMES[*]})" set_option "LVM_SIZES" "(${LVM_SIZES[*]})" } elements_present() { for e in "${@:2}"; do [[ "$e" == "$1" ]] && break; done } invalid_option() { echo -ne "ERROR! Your selected option is invalid, retry \n" } set_password() { read -rs -p "Please enter password: " PASSWORD1 echo -ne "\n" read -rs -p "Please re-enter password: " PASSWORD2 echo -ne "\n" if [[ "$PASSWORD1" == "$PASSWORD2" ]]; then set_option "$1" "$PASSWORD1" else echo -ne "ERROR! Passwords do not match \n" set_password fi } title() { echo -ne "\n" echo -ne "------------------------------------------------------------------------\n" echo -ne "\t\t\"$1\"\n" echo -ne "------------------------------------------------------------------------\n" } # Write shared functions to to setup.conf write_to_config() { cat <"$CONFIG_FILE" #!/usr/bin/env bash title () { echo -ne "\n" echo -ne "------------------------------------------------------------------------\n" echo -ne "\t\t\$1\n" echo -ne "------------------------------------------------------------------------\n" } set_option() { if grep -Eq "^\${1}.*" "\$CONFIG_FILE"; then sed -i -e "/^\${1}.*/d" "\$CONFIG_FILE" fi echo "\${1}=\${2}" >>"\$CONFIG_FILE" } install_pkg () { pacman -S --noconfirm --needed "\$@" } refresh_pacman() { pacman -Sy --noconfirm } something_failed() { echo "ERROR! Something is not right. Exiting.\n" exit 0 } logo () { echo -ne " ------------------------------------------------------------------------ █████╗ ██████╗ ██████╗██╗ ██╗████████╗██╗████████╗██╗ ██╗███████╗ ██╔══██╗██╔══██╗██╔════╝██║ ██║╚══██╔══╝██║╚══██╔══╝██║ ██║██╔════╝ ███████║██████╔╝██║ ███████║ ██║ ██║ ██║ ██║ ██║███████╗ ██╔══██║██╔══██╗██║ ██╔══██║ ██║ ██║ ██║ ██║ ██║╚════██║ ██║ ██║██║ ██║╚██████╗██║ ██║ ██║ ██║ ██║ ╚██████╔╝███████║ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝ " } BOOT=EFIBOOT ROOT=ROOT MOUNTPOINT=/mnt EOF } PROMPT="Please enter your option: " logo() { echo -ne " ------------------------------------------------------------------------ █████╗ ██████╗ ██████╗██╗ ██╗████████╗██╗████████╗██╗ ██╗███████╗ ██╔══██╗██╔══██╗██╔════╝██║ ██║╚══██╔══╝██║╚══██╔══╝██║ ██║██╔════╝ ███████║██████╔╝██║ ███████║ ██║ ██║ ██║ ██║ ██║███████╗ ██╔══██║██╔══██╗██║ ██╔══██║ ██║ ██║ ██║ ██║ ██║╚════██║ ██║ ██║██║ ██║╚██████╗██║ ██║ ██║ ██║ ██║ ╚██████╔╝███████║ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝ " } background_check() { check_root check_docker check_arch check_pacman write_to_config efi_check if connection_test; then echo -ne "ERROR! There seems to be no internet connection.\n" exit 0 fi set_ntp do_curl } set_filesystem() { title "Setup File System" FILESYS=("btrfs" "ext2" "ext3" "ext4" "f2fs" "jfs" "nilfs2" "ntfs" "vfat" "xfs") PS3="$PROMPT" select OPT in "${FILESYS[@]}"; do if elements_present "$OPT" "${FILESYS[@]}"; then set_option "FS" "$OPT" break else invalid_option set_filesystem break fi done } set_partion_layout() { title "Setup Partioning Layout" LAYOUTS=("LVM" "LVM+LUKS" "Maintain Current") PS3="$PROMPT" select OPT in "${LAYOUTS[@]}"; do if elements_present "$OPT" "${LAYOUTS[@]}"; then case "$REPLY" in # 1) # set_option "LAYOUT" 1 # break # ;; 1) set_option "LVM" 1 set_lvm break ;; 2) set_lvm set_option "LUKS" 1 set_option "LUKS_PATH" "/dev/mapper/luks" set_password "LUKS_PASSWORD" break ;; 3) echo -ne "Maintaining current settings" CHOICE=($(lsblk | grep 'part' | awk '{print "/dev/" substr($1,3)}')) if [[ -d "/sys/firmware/efi/" ]]; then echo "Select your boot partition" PS3="$PROMPT" select OPT in "${CHOICE[@]}"; do if elements_present "$OPT" "${CHOICE[@]}"; then set_option "LAYOUT" 0 set_option "BOOT_PARTITION" "$OPT" break fi done fi echo "Select your root partition" PS3="$PROMPT" select OPT in "${CHOICE[@]}"; do if elements_present "$OPT" "${CHOICE[@]}"; then set_option "ROOT_PARTITION" "$OPT" break fi done set_filesystem break ;; *) invalid_option set_partion_layout break ;; esac else invalid_option set_partion_layout fi done } # Added this from arch wiki https://wiki.archlinux.org/title/System_time set_timezone() { title "Setup Time Zone" _TIMEZONE="$(curl --fail https://ipapi.co/timezone)" _ZONE=($(timedatectl list-timezones | sed 's/\/.*$//' | uniq)) echo -ne "System detected your timezone to be '$_TIMEZONE'" echo " " read -r -p "Is this correct? [like yes/no]: " ANSWER case "$ANSWER" in y | Y | yes | Yes | YES) set_option TIMEZONE "$_TIMEZONE" ;; n | N | no | NO | No) title "Manually setting timezone" PS3="$PROMPT" echo -ne "Please select your zone: \n" select ZONE in "${_ZONE[@]}"; do if elements_present "$ZONE" "${_ZONE[@]}"; then _SUBZONE=($(timedatectl list-timezones | grep "${ZONE}" | sed 's/^.*\///')) PS3="$PROMPT" echo -ne "Please select your subzone: \n" select SUBZONE in "${_SUBZONE[@]}"; do if elements_present "$SUBZONE" "${_SUBZONE[@]}"; then set_option "TIMEZONE" "${ZONE}/${SUBZONE}" break else invalid_option break fi done break else invalid_option set_timezone break fi done ;; *) invalid_option set_timezone ;; esac } set_keymap() { title "Setup Keymap" KEYMAPS=("by" "ca" "cf" "cz" "de" "dk" "es" "et" "fa" "fi" "fr" "gr" "hu" "il" "it" "lt" "lv" "mk" "nl" "no" "pl" "ro" "ru" "sg" "ua" "uk" "us") PS3="$PROMPT" select OPT in "${KEYMAPS[@]}"; do if elements_present "$OPT" "${KEYMAPS[@]}"; then set_option "KEYMAP" "$OPT" break else invalid_option set_keymap break fi done } ssd_drive() { title "SSD Drive Confirmation" read -r -p "Is this system using an SSD? [like yes/no]: " _SSD case "$_SSD" in y | Y | yes | Yes | YES) set_option "SSD" 1 set_option "MOUNTOPTION" "noatime,compress=zstd,ssd,commit=120" ;; n | N | no | NO | No) set_option "SSD" 0 set_option "MOUNTOPTION" "noatime,compress=zstd,commit=120" ;; *) invalid_option ssd_drive ;; esac } disk_selection() { title "Disk Selection" DISKLIST="$(lsblk -n --output TYPE,KNAME,SIZE | awk '$1=="disk"{print "/dev/"$2" - "$3}')" # show disks with /dev/ prefix and size PS3="$PROMPT" select _DISK in "${DISKLIST[@]}"; do if elements_present "$_DISK" "${DISKLIST[@]}"; then DISK=$(echo "$_DISK" | awk '{print $1}') set_option "DISK" "$DISK" break else invalid_option disk_selection break fi done } user_info() { title "Add Your Information" while true; do read -r -p "Please enter your username [default is archtitus]: " USERNAME if [[ -z "$USERNAME" ]]; then set_option "USERNAME" "archtitus" break elif [[ "${USERNAME,,}" =~ ^[a-z_]([a-z0-9_-]{0,31}|[a-z0-9_-]{0,30}\$)$ ]]; then set_option "USERNAME" "${USERNAME,,}" # convert to lower case as in issue #109 break else invalid_option continue fi done set_password "PASSWORD" while true; do read -r -p "Please enter your hostname [default is archlinux]: " HOSTNAME if [[ -z "$HOSTNAME" ]]; then set_option "HOSTNAME" "archlinux" break elif [[ "${HOSTNAME,,}" =~ ^[a-z][a-z0-9_.-]{0,62}[a-z0-9]$ ]]; then set_option "HOSTNAME" "${HOSTNAME,,}" break else invalid_option continue fi done } set_locale() { title "Setup Locale" LOCALES=($(grep UTF-8 /etc/locale.gen | sed 's/\..*$//' | sed '/@/d' | awk '{print $1}' | uniq | sed 's/#//g')) PS3="$PROMPT" select LOCALE in "${LOCALES[@]}"; do if elements_present "$LOCALE" "${LOCALES[@]}"; then set_option "LOCALE" "\"${LOCALE}.UTF-8 UTF-8\"" break else invalid_option set_locale break fi done } set_desktop() { title "Select either desktop Environment or Window Manager" SELECTION=("Default (KDE)" "Gnome" "XFCE" "Mate" "LXQT" "Minimal" "Awesome" "OpenBox" "i3" "i3-Gaps" "Deepin" "Budgie") PS3="$PROMPT" select OPT in "${SELECTION[@]}"; do if elements_present "$OPT" "${SELECTION[@]}"; then if [[ "$OPT" == "Default (KDE)" ]]; then set_option "DESKTOP" "default" break else set_option "DESKTOP" "${OPT,,}" break fi else invalid_option set_desktop break fi done } set_aur_helper() { title "Select your preferred AUR helper" SELECTION=("yay" "trizen" "aurman" "aura" "pikaur" "none") PS3="$PROMPT" select OPT in "${SELECTION[@]}"; do if elements_present "$OPT" "${SELECTION[@]}"; then set_option "AURHELPER" "$OPT" break else invalid_option set_aur_helper break fi done } set_bootloader() { title "Select your bootloader" SELECTION=("Default (GRUB)" "Systemd" "UEFI" "None") echo "Systemd and UEFI are only available on a UEFI system" echo "None will skip a bootloader and you will not be able to boot" PS3="$PROMPT" select OPT in "${SELECTION[@]}"; do if elements_present "$OPT" "${SELECTION[@]}"; then if [[ "$OPT" == "Default (GRUB)" ]]; then set_option "BOOTLOADER" "grub" break else set_option "BOOTLOADER" "${OPT,,}" break fi else invalid_option set_bootloader break fi done } make_choice() { title "Your system choice" CHOICE=("Default Install" "Custom Install") PS3="$PROMPT" echo "Default installation comprises of the settings and the packages used" echo "by Chris Titus himself. More specifically, it uses btrfs as file systems," echo "KDE Plasma as desktop environment and sddm as window manager and package" echo "list is in 'pkg-files/pacman-pkgs.txt'." echo "While custom install allows you to choose your choices i.e. LVM, LUKS," echo "DE, WM, file systems and etc." echo " " select OPT in "${CHOICE[@]}"; do if elements_present "$OPT" "${CHOICE[@]}"; then case "$REPLY" in 1) clear logo user_info disk_selection clear set_locale clear set_timezone set_keymap ssd_drive set_btrfs set_option "LAYOUT" 1 set_option "BOOTLOADER" "grub" set_option "FS" "btrfs" set_option "AURHELPER" "yay" set_option "DESKTOP" "default" break ;; 2) clear logo user_info disk_selection clear set_locale clear set_timezone set_keymap ssd_drive # Advance options set_aur_helper set_partion_layout set_bootloader set_filesystem set_desktop break ;; *) invalid_option make_choice break ;; esac else invalid_option make_choice break fi done } background_check # write_to_config clear logo make_choice # user_info # set_partion_layout