#!/usr/bin/env bash # This script will ask users about their prefrences # like disk, file system, timezone, keyboard layout, # user name, password, etc. # 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 # Check if file exists and remove it if it does [[ -f "$CONFIG_FILE" ]] && rm -f "$CONFIG_FILE" >/dev/null 2>&1 # Set options in setup.conf set_option() { # Check if option exists if grep -Eq "^${1}.*" "$CONFIG_FILE"; then # delete option if exists sed -i -e "/^${1}.*/d" "$CONFIG_FILE" fi # Else add option echo "${1}=${2}" >>"$CONFIG_FILE" } # Adding global functions and variables to use in this script # Check for root user check_root() { if [[ "$(id -u)" != "0" ]]; then echo -ne "ERROR! This script has to be run under the 'root' user!" exit 1 fi } # Check if distro is arch check_arch() { if [[ ! -e /etc/arch-release ]]; then echo -ne "ERROR! This script has to be run under Arch Linux!" exit 1 fi } check_pacman() { if [[ -f /var/lib/pacman/db.lck ]]; then echo "ERROR! Pacman is blocked." echo "If not running remove /var/lib/pacman/db.lck." exit 1 fi } # Check for internet connection connection_test() { ping -q -w 1 -c 1 "$(ip r | grep default | awk 'NR==1 {print $3}')" &>/dev/null && return 1 || return 0 } # Check coutry for mirrorlist do_curl() { _ISO=$(curl --fail https://ifconfig.co/country-iso) set_option "ISO" "$_ISO" } # Install fonts install_font() { pacman -S --noconfirm --needed terminus-font } # timedatectl set-ntp true set_ntp() { timedatectl set-ntp true } # Check for UEFI 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 # UEFI detected set_option "UEFI" 1 else # No UEFI detected set_option "UEFI" 0 fi } # if btrfs is selected set_btrfs() { # Used -a to get more than one argument 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 # An array is a list of values. NAMES=(@) for i in "${ARR[@]}"; do # Check for user input for @ if [[ $i =~ [@] ]]; then # push values to array NAMES+=("$i") else NAMES+=(@"${i}") fi done # Check for duplicates IFS=" " read -r -a SUBS <<<"$(tr ' ' '\n' <<<"${NAMES[@]}" | awk '!x[$0]++' | tr '\n' ' ')" # Set to config file set_option "SUBVOLUMES" "${SUBS[*]}" fi } # If lvm is selected 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") # Stop loop if only 1 partition i=2 fi while [[ $i -le "$_PART_NUM" ]]; do 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[*]})" } # Check if an element exists elements_present() { for e in "${@:2}"; do [[ "$e" == "$1" ]] && break; done } # Invalid option message invalid_option() { echo -ne "Please select a valid option: \n" } # Password helper function set_password() { # Read password without echoing (-s) 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 "Passwords do not match \n" set_password fi } # Make a title 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() { # Check if option exists if grep -Eq "^${1}.*" "$CONFIG_FILE"; then # delete option if exists sed -i -e "/^${1}.*/d" "$CONFIG_FILE" fi # Else add option echo "${1}=${2}" >>"$CONFIG_FILE" } install_pkg () { pacman -S --noconfirm --needed "\$@" } refresh_pacman() { pacman -Syy } # Setup for logging LOG="${SCRIPT_DIR}/main.log" [[ -f \$LOG ]] && rm -f "\$LOG" logo () { echo -ne " ------------------------------------------------------------------------ █████╗ ██████╗ ██████╗██╗ ██╗████████╗██╗████████╗██╗ ██╗███████╗ ██╔══██╗██╔══██╗██╔════╝██║ ██║╚══██╔══╝██║╚══██╔══╝██║ ██║██╔════╝ ███████║██████╔╝██║ ███████║ ██║ ██║ ██║ ██║ ██║███████╗ ██╔══██║██╔══██╗██║ ██╔══██║ ██║ ██║ ██║ ██║ ██║╚════██║ ██║ ██║██║ ██║╚██████╗██║ ██║ ██║ ██║ ██║ ╚██████╔╝███████║ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝ " } # TODO ask user for mount points i.e. boot may be home etc BOOT=EFIBOOT ROOT=ROOT MOUNTPOINT=/mnt EOF } # Ask user for option PROMPT="Please enter your option: " # This will be shown on every set as user is progressing logo() { echo -ne " ------------------------------------------------------------------------ █████╗ ██████╗ ██████╗██╗ ██╗████████╗██╗████████╗██╗ ██╗███████╗ ██╔══██╗██╔══██╗██╔════╝██║ ██║╚══██╔══╝██║╚══██╔══╝██║ ██║██╔════╝ ███████║██████╔╝██║ ███████║ ██║ ██║ ██║ ██║ ██║███████╗ ██╔══██║██╔══██╗██║ ██╔══██║ ██║ ██║ ██║ ██║ ██║╚════██║ ██║ ██║██║ ██║╚██████╗██║ ██║ ██║ ██║ ██║ ╚██████╔╝███████║ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝ " } # Backround checks background_check() { write_to_config if connection_test; then echo -ne "ERROR! There seems to be no internet connection.\n" exit 1 fi set_option "SCRIPT_DIR" "$SCRIPT_DIR" check_arch check_pacman efi_check # check_root set_ntp do_curl install_font setfont ter-v22b } # This function will handle file systems. set_filesystem() { title "Setup File System" FILESYS=("btrfs" "ext2" "ext3" "ext4" "f2fs" "jfs" "nilfs2" "ntfs" "reiserfs" "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 partioning layouts set_partion_layout() { title "Setup Partioning Layout" LAYOUTS=("Default" "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 ;; 2) set_option "LVM" 1 # just weired bug with set_option set_lvm break ;; 3) set_lvm set_option "LUKS" 1 set_option "LUKS_PATH" "/dev/mapper/luks" set_password "LUKS_PASSWORD" break ;; 4) 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 } # These are default key maps as presented in official arch repo archinstall 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 } # Confirm if ssd is present 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 } # Selection for disk type disk_selection() { # show disks present on system 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 # remove size from string 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" read -r -p "Please enter your username [default is archtitus]: " USERNAME if [[ -z "$USERNAME" ]]; then USERNAME="archtitus" fi set_option "USERNAME" "${USERNAME,,}" # convert to lower case as in issue #109 set_password "PASSWORD" read -r -p "Please enter your hostname [default is ArchLinux]: " HOSTNAME if [[ -z "$HOSTNAME" ]]; then HOSTNAME="ArchLinux" fi set_option "HOSTNAME" "$HOSTNAME" } # Set locale 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 } # Desktop selection set_desktop() { title "Select either desktop Environment or Window Manager" SELECTION=("KDE" "Gnome" "XFCE" "Mate" "LXQT" "Minimal" "Awesome" "OpenBox" "i3" "i3-Gaps") PS3="$PROMPT" select OPT in "${SELECTION[@]}"; do if elements_present "$OPT" "${SELECTION[@]}"; then case "$REPLY" in 1) # More packages can be added here set_option "DE" "plasma" set_option "DM" "sddm" break ;; 2) set_option "DE" "gnome" set_option "DM" "gdm" break ;; 3) set_option "DE" "xfce4" set_option "DM" "lightdm" break ;; 4) set_option "DE" "mate" set_option "DM" "lightdm" break ;; 5) set_option "DE" "lxqt" set_option "DM" "lightdm" break ;; 6) set_option "DE" 0 set_option "DM" 0 break ;; 7) set_option "DE" 0 set_option "WM" "awesome" break ;; 8) # openbox set_option "DE" 0 set_option "WM" "openbox" break ;; 9) # i3 set_option "DE" 0 set_option "WM" "i3" break ;; 10) # i3-gaps set_option "DE" 0 set_option "WM" "i3-gaps" break ;; *) echo "Wrong option. Try again" break ;; esac else invalid_option set_desktop break fi done } # Make choice for installation 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 # title "Please select presetup \n\t\t\tsettings for your system" user_info disk_selection clear set_locale clear set_timezone set_keymap ssd_drive set_btrfs set_option "FS" "btrfs" set_option "DE" "plasma" set_option "DM" "sddm" set_option "LAYOUT" 1 break ;; 2) clear logo user_info disk_selection clear set_locale clear set_timezone set_keymap ssd_drive # Advance options set_partion_layout 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 # set_partion_layout