system-setup/alis-commons.sh

455 lines
13 KiB
Bash

#!/usr/bin/env bash
set -eu
# Arch Linux Install Script (alis) installs unattended, automated
# and customized Arch Linux system.
# Copyright (C) 2022 picodotdev
# Common functions and definitions.
# common static variables
ALIS_CONF_FILE="alis.conf"
ALIS_LOG_FILE="alis.log"
ALIS_ASCIINEMA_FILE="alis.asciinema"
RECOVERY_CONF_FILE="alis-recovery.conf"
RECOVERY_LOG_FILE="alis-recovery.log"
RECOVERY_ASCIINEMA_FILE="alis-recovery.asciinema"
PACKAGES_CONF_FILE="alis-packages.conf"
PACKAGES_LOG_FILE="alis-packages.log"
COMMONS_CONF_FILE="alis-commons.conf"
PROVISION_DIRECTORY="files/"
RED='\033[0;91m'
GREEN='\033[0;92m'
BLUE='\033[0;96m'
WHITE='\033[0;97m'
NC='\033[0m'
function sanitize_variable() {
local VARIABLE="$1"
local VARIABLE=$(echo "$VARIABLE" | sed "s/![^ ]*//g") # remove disabled
local VARIABLE=$(echo "$VARIABLE" | sed -r "s/ {2,}/ /g") # remove unnecessary white spaces
local VARIABLE=$(echo "$VARIABLE" | sed 's/^[[:space:]]*//') # trim leading
local VARIABLE=$(echo "$VARIABLE" | sed 's/[[:space:]]*$//') # trim trailing
echo "$VARIABLE"
}
function trim_variable() {
local VARIABLE="$1"
local VARIABLE=$(echo "$VARIABLE" | sed 's/^[[:space:]]*//') # trim leading
local VARIABLE=$(echo "$VARIABLE" | sed 's/[[:space:]]*$//') # trim trailing
echo "$VARIABLE"
}
function check_variables_value() {
local NAME="$1"
local VALUE="$2"
if [ -z "$VALUE" ]; then
echo "$NAME environment variable must have a value."
exit 1
fi
}
function check_variables_boolean() {
local NAME="$1"
local VALUE="$2"
check_variables_list "$NAME" "$VALUE" "true false" "true" "true"
}
function check_variables_list() {
local NAME="$1"
local VALUE="$2"
local VALUES="$3"
local REQUIRED="$4"
local SINGLE="$5"
if [ "$REQUIRED" == "" -o "$REQUIRED" == "true" ]; then
check_variables_value "$NAME" "$VALUE"
fi
if [[ ("$SINGLE" == "" || "$SINGLE" == "true") && "$VALUE" != "" && "$VALUE" =~ " " ]]; then
echo "$NAME environment variable value [$VALUE] must be a single value of [$VALUES]."
exit 1
fi
if [ "$VALUE" != "" -a -z "$(echo "$VALUES" | grep -F -w "$VALUE")" ]; then
echo "$NAME environment variable value [$VALUE] must be in [$VALUES]."
exit 1
fi
}
function check_variables_equals() {
local NAME1="$1"
local NAME2="$2"
local VALUE1="$3"
local VALUE2="$4"
if [ "$VALUE1" != "$VALUE2" ]; then
echo "$NAME1 and $NAME2 must be equal [$VALUE1, $VALUE2]."
exit 1
fi
}
function check_variables_size() {
local NAME="$1"
local SIZE_EXPECT="$2"
local SIZE="$3"
if [ "$SIZE_EXPECT" != "$SIZE" ]; then
echo "$NAME array size [$SIZE] must be [$SIZE_EXPECT]."
exit 1
fi
}
function configure_network() {
if [ -n "$WIFI_INTERFACE" ]; then
iwctl --passphrase "$WIFI_KEY" station $WIFI_INTERFACE connect "$WIFI_ESSID"
sleep 10
fi
# only one ping -c 1, ping gets stuck if -c 5
ping -c 1 -i 2 -W 5 -w 30 $PING_HOSTNAME
if [ $? -ne 0 ]; then
echo "Network ping check failed. Cannot continue."
exit 1
fi
}
function facts_commons() {
if [ -d /sys/firmware/efi ]; then
BIOS_TYPE="uefi"
else
BIOS_TYPE="bios"
fi
if [ -f "$ALIS_ASCIINEMA_FILE" -o -f "$RECOVERY_ASCIINEMA_FILE" ]; then
ASCIINEMA="true"
else
ASCIINEMA="false"
fi
if [ -n "$(lscpu | grep GenuineIntel)" ]; then
CPU_VENDOR="intel"
elif [ -n "$(lscpu | grep AuthenticAMD)" ]; then
CPU_VENDOR="amd"
fi
if [ -n "$(lspci -nn | grep "\[03" | grep -i intel)" ]; then
GPU_VENDOR="intel"
elif [ -n "$(lspci -nn | grep "\[03" | grep -i amd)" ]; then
GPU_VENDOR="amd"
elif [ -n "$(lspci -nn | grep "\[03" | grep -i nvidia)" ]; then
GPU_VENDOR="nvidia"
elif [ -n "$(lspci -nn | grep "\[03" | grep -i vmware)" ]; then
GPU_VENDOR="vmware"
fi
if [ -n "$(systemd-detect-virt | grep -i oracle)" ]; then
VIRTUALBOX="true"
fi
if [ -n "$(systemd-detect-virt | grep -i vmware)" ]; then
VMWARE="true"
fi
USER_NAME_INSTALL="$(whoami)"
if [ "$USER_NAME_INSTALL" == "root" ]; then
SYSTEM_INSTALLATION="true"
else
SYSTEM_INSTALLATION="false"
fi
}
function init_log_trace() {
local ENABLE="$1"
if [ "$ENABLE" == "true" ]; then
set -o xtrace
fi
}
function init_log_file() {
local ENABLE="$1"
local FILE="$2"
if [ "$ENABLE" == "true" ]; then
exec &> >(tee -a $FILE)
fi
}
function pacman_uninstall() {
local ERROR="true"
set +e
IFS=' ' local PACKAGES=($1)
local PACKAGES_UNINSTALL=()
for PACKAGE in "${PACKAGES[@]}"
do
execute_sudo "pacman -Qi $PACKAGE > /dev/null 2>&1"
local PACKAGE_INSTALLED=$?
if [ $PACKAGE_INSTALLED == 0 ]; then
local PACKAGES_UNINSTALL+=("$PACKAGE")
fi
done
if [ -z "${PACKAGES_UNINSTALL[@]}" ]; then
return
fi
local COMMAND="pacman -Rdd --noconfirm ${PACKAGES_UNINSTALL[@]}"
execute_sudo "$COMMAND"
if [ $? == 0 ]; then
local ERROR="false"
fi
set -e
if [ "$ERROR" == "true" ]; then
exit 1
fi
}
function pacman_install() {
local ERROR="true"
set +e
IFS=' ' local PACKAGES=($1)
for VARIABLE in {1..5}
do
local COMMAND="pacman -Syu --noconfirm --needed ${PACKAGES[@]}"
execute_sudo "$COMMAND"
if [ $? == 0 ]; then
local ERROR="false"
break
else
sleep 10
fi
done
set -e
if [ "$ERROR" == "true" ]; then
exit 1
fi
}
function aur_install() {
local ERROR="true"
set +e
which "$AUR_COMMAND"
if [ "$AUR_COMMAND" != "0" ]; then
aur_command_install "$USER_NAME" "$AUR_PACKAGE"
fi
IFS=' ' local PACKAGES=($1)
for VARIABLE in {1..5}
do
local COMMAND="$AUR_COMMAND -Syu --noconfirm --needed ${PACKAGES[@]}"
execute_aur "$COMMAND"
if [ $? == 0 ]; then
local ERROR="false"
break
else
sleep 10
fi
done
set -e
if [ "$ERROR" == "true" ]; then
return
fi
}
function aur_command_install() {
pacman_install "git"
local USER_NAME="$1"
local COMMAND="$2"
execute_aur "rm -rf /home/$USER_NAME/.alis && mkdir -p /home/$USER_NAME/.alis/aur && cd /home/$USER_NAME/.alis/aur && git clone https://aur.archlinux.org/$COMMAND.git && (cd $COMMAND && makepkg -si --noconfirm) && rm -rf /home/$USER_NAME/.alis"
}
function systemd_units() {
IFS=' ' local UNITS=($SYSTEMD_UNITS)
for U in ${UNITS[@]}; do
local ACTION=""
local UNIT=${U}
if [[ $UNIT == -* ]]; then
local ACTION="disable"
local UNIT=$(echo $UNIT | sed "s/^-//g")
elif [[ $UNIT == +* ]]; then
local ACTION="enable"
local UNIT=$(echo $UNIT | sed "s/^+//g")
elif [[ $UNIT =~ ^[a-zA-Z0-9]+ ]]; then
local ACTION="enable"
local UNIT=$UNIT
fi
if [ -n "$ACTION" ]; then
execute_sudo "systemctl $ACTION $UNIT"
fi
done
}
function execute_flatpak() {
local COMMAND="$1"
if [ "$SYSTEM_INSTALLATION" == "true" ]; then
arch-chroot /mnt bash -c "$COMMAND"
else
bash -c "$COMMAND"
fi
}
function execute_aur() {
local COMMAND="$1"
if [ "$SYSTEM_INSTALLATION" == "true" ]; then
arch-chroot /mnt sed -i 's/^%wheel ALL=(ALL:ALL) ALL$/%wheel ALL=(ALL:ALL) NOPASSWD: ALL/' /etc/sudoers
arch-chroot /mnt bash -c "echo -e \"$USER_PASSWORD\n$USER_PASSWORD\n$USER_PASSWORD\n$USER_PASSWORD\n\" | su $USER_NAME -s /usr/bin/bash -c \"$COMMAND\""
arch-chroot /mnt sed -i 's/^%wheel ALL=(ALL:ALL) NOPASSWD: ALL$/%wheel ALL=(ALL:ALL) ALL/' /etc/sudoers
else
bash -c "$COMMAND"
fi
}
function execute_sudo() {
local COMMAND="$1"
if [ "$SYSTEM_INSTALLATION" == "true" ]; then
arch-chroot /mnt bash -c "$COMMAND"
else
sudo bash -c "$COMMAND"
fi
}
function execute_user() {
local USER_NAME="$1"
local COMMAND="$2"
if [ "$SYSTEM_INSTALLATION" == "true" ]; then
arch-chroot /mnt bash -c "su $USER_NAME -s /usr/bin/bash -c \"$COMMAND\""
else
bash -c "$COMMAND"
fi
}
function do_reboot() {
umount -R /mnt/boot
umount -R /mnt
reboot
}
function print_step() {
STEP="$1"
echo ""
echo -e "${BLUE}# ${STEP} step${NC}"
echo ""
}
function execute_step() {
local STEP="$1"
eval "$STEP"
}
function partition_setup() {
# setup
if [ "$PARTITION_MODE" == "auto" ]; then
PARTITION_PARTED_FILE_SYSTEM_TYPE="$FILE_SYSTEM_TYPE"
if [ "$PARTITION_PARTED_FILE_SYSTEM_TYPE" == "f2fs" ]; then
PARTITION_PARTED_FILE_SYSTEM_TYPE=""
fi
PARTITION_PARTED_UEFI="mklabel gpt mkpart ESP fat32 1MiB 2048MiB mkpart root $PARTITION_PARTED_FILE_SYSTEM_TYPE 2048MiB 100% set 1 esp on"
PARTITION_PARTED_BIOS="mklabel msdos mkpart primary ext4 4MiB 2048MiB mkpart primary $PARTITION_PARTED_FILE_SYSTEM_TYPE 2048MiB 100% set 1 boot on"
elif [ "$PARTITION_MODE" == "custom" ]; then
PARTITION_PARTED_UEFI="$PARTITION_CUSTOM_PARTED_UEFI"
PARTITION_PARTED_BIOS="$PARTITION_CUSTOM_PARTED_BIOS"
fi
if [ "$DEVICE_SDA" == "true" ]; then
PARTITION_BOOT="$(partition_device "${DEVICE}" "${PARTITION_BOOT_NUMBER}")"
PARTITION_ROOT="$(partition_device "${DEVICE}" "${PARTITION_ROOT_NUMBER}")"
DEVICE_ROOT="$(partition_device "${DEVICE}" "${PARTITION_ROOT_NUMBER}")"
fi
if [ "$DEVICE_NVME" == "true" ]; then
PARTITION_BOOT="$(partition_device "${DEVICE}" "${PARTITION_BOOT_NUMBER}")"
PARTITION_ROOT="$(partition_device "${DEVICE}" "${PARTITION_ROOT_NUMBER}")"
DEVICE_ROOT="$(partition_device "${DEVICE}" "${PARTITION_ROOT_NUMBER}")"
fi
if [ "$DEVICE_VDA" == "true" ]; then
PARTITION_BOOT="$(partition_device "${DEVICE}" "${PARTITION_BOOT_NUMBER}")"
PARTITION_ROOT="$(partition_device "${DEVICE}" "${PARTITION_ROOT_NUMBER}")"
DEVICE_ROOT="$(partition_device "${DEVICE}" "${PARTITION_ROOT_NUMBER}")"
fi
if [ "$DEVICE_MMC" == "true" ]; then
PARTITION_BOOT="$(partition_device "${DEVICE}" "${PARTITION_BOOT_NUMBER}")"
PARTITION_ROOT="$(partition_device "${DEVICE}" "${PARTITION_ROOT_NUMBER}")"
DEVICE_ROOT="$(partition_device "${DEVICE}" "${PARTITION_ROOT_NUMBER}")"
fi
}
function partition_device() {
local DEVICE="$1"
local NUMBER="$2"
local PARTITION_DEVICE=""
if [ "$DEVICE_SDA" == "true" ]; then
PARTITION_DEVICE="${DEVICE}${NUMBER}"
fi
if [ "$DEVICE_NVME" == "true" ]; then
PARTITION_DEVICE="${DEVICE}p${NUMBER}"
fi
if [ "$DEVICE_VDA" == "true" ]; then
PARTITION_DEVICE="${DEVICE}${NUMBER}"
fi
if [ "$DEVICE_MMC" == "true" ]; then
PARTITION_DEVICE="${DEVICE}p${NUMBER}"
fi
echo "$PARTITION_DEVICE"
}
function partition_options() {
PARTITION_OPTIONS_BOOT="defaults"
PARTITION_OPTIONS="defaults"
if [ "$DEVICE_TRIM" == "true" ]; then
PARTITION_OPTIONS_BOOT="$PARTITION_OPTIONS_BOOT,noatime"
PARTITION_OPTIONS="$PARTITION_OPTIONS,noatime"
if [ "$FILE_SYSTEM_TYPE" == "f2fs" ]; then
PARTITION_OPTIONS="$PARTITION_OPTIONS,nodiscard"
fi
fi
}
function partition_mount() {
if [ "$FILE_SYSTEM_TYPE" == "btrfs" ]; then
# mount subvolumes
mount -o "subvol=${BTRFS_SUBVOLUME_ROOT[1]},$PARTITION_OPTIONS,compress=zstd" "$DEVICE_ROOT" /mnt
mkdir -p /mnt/boot
mount -o "$PARTITION_OPTIONS_BOOT" "$PARTITION_BOOT" /mnt/boot
for I in "${BTRFS_SUBVOLUMES_MOUNTPOINTS[@]}"; do
IFS=',' SUBVOLUME=($I)
if [ ${SUBVOLUME[0]} == "root" ]; then
continue
fi
if [ ${SUBVOLUME[0]} == "swap" -a -z "$SWAP_SIZE" ]; then
continue
fi
if [ ${SUBVOLUME[0]} == "swap" ]; then
mkdir -p -m 0755 "/mnt${SUBVOLUME[2]}"
else
mkdir -p "/mnt${SUBVOLUME[2]}"
fi
mount -o "subvol=${SUBVOLUME[1]},$PARTITION_OPTIONS,compress=zstd" "$DEVICE_ROOT" "/mnt${SUBVOLUME[2]}"
done
else
# root
mount -o "$PARTITION_OPTIONS" "$DEVICE_ROOT" /mnt
# boot
mkdir -p /mnt/boot
mount -o "$PARTITION_OPTIONS_BOOT" "$PARTITION_BOOT" /mnt/boot
# mount points
for I in "${PARTITION_MOUNT_POINTS[@]}"; do
if [[ "$I" =~ ^!.* ]]; then
continue
fi
IFS='=' PARTITION_MOUNT_POINT=($I)
if [ "${PARTITION_MOUNT_POINT[1]}" == "/boot" -o "${PARTITION_MOUNT_POINT[1]}" == "/" ]; then
continue
fi
local PARTITION_DEVICE="$(partition_device "${DEVICE}" "${PARTITION_MOUNT_POINT[0]}")"
mkdir -p "/mnt${PARTITION_MOUNT_POINT[1]}"
mount -o "$PARTITION_OPTIONS" "${PARTITION_DEVICE}" "/mnt${PARTITION_MOUNT_POINT[1]}"
done
fi
}