rebostness improvements, partition naming fix, and added autologin

This commit is contained in:
2026-08-28 13:31:03 +02:00
parent 5c2327392d
commit 92e46e1861
+144 -89
View File
@@ -1,35 +1,50 @@
#!/bin/sh #!/bin/bash
set -euo pipefail
# User inputs # User inputs
HOSTNAME="" HOSTNAME=""
ROOT_PASSWORD="" ROOT_PASSWORD=""
USERNAME="" USERNAME=""
USER_PASSWORD="" USER_PASSWORD=""
WANT_AUTOLOGIN=""
# Cleanup on failure
cleanup() {
local exit_code=$?
if [ $exit_code -ne 0 ]; then
echo "An error occurred during installation. Unmounting..."
umount -A -R /mnt 2>/dev/null || true
fi
}
trap cleanup EXIT
install_deps() { install_deps() {
echo "You will need commands like mkfs.ext4, sgisk and pacstrap." echo "You will need commands like mkfs.ext4, sgdisk and pacstrap."
printf "Try to install them with pacman (if you are on arch linux)? [Y/n] " printf "Try to install them with pacman (if you are on arch linux)? [Y/n] "
read CONFIRMATION read -r CONFIRMATION
case "$CONFIRMATION" in case "$CONFIRMATION" in
"n" | "N") [nN]*)
echo "Operation canceled." echo "Operation canceled."
return return
;; ;;
"" | "y" | "Y") "" | [yY]*)
echo "Installing dependencies" echo "Installing dependencies"
sudo pacman -S --needed --noconfirm dosfstools gptfdisk arch-install-scripts sudo pacman -S --needed --noconfirm dosfstools gptfdisk arch-install-scripts
echo "" echo ""
;; ;;
*) *)
echo "Invalid input. Defaulting to 'No'." echo "Invalid input. Defaulting to 'No'."
exit 0 exit 1
;; ;;
esac esac
} }
send_status_message() { send_status_message() {
local term_width
term_width=$(tput cols 2>/dev/null || echo 80) term_width=$(tput cols 2>/dev/null || echo 80)
msg="$1" local msg="$1"
local edge
edge=$(printf '%*s' "$term_width" '' | tr ' ' '=') edge=$(printf '%*s' "$term_width" '' | tr ' ' '=')
printf "\n%s\n" "$edge" printf "\n%s\n" "$edge"
printf "%*s\n" $(((${#msg} + term_width) / 2)) "$msg" printf "%*s\n" $(((${#msg} + term_width) / 2)) "$msg"
@@ -39,60 +54,68 @@ send_status_message() {
get_config_inputs() { get_config_inputs() {
send_status_message "CONFIGURATION: Getting user inputs" send_status_message "CONFIGURATION: Getting user inputs"
while [ -z "$WANT_AUTOLOGIN" ]; do
printf "Do you want to enable autologin? (TTY only) [y/n]: "
read -r WANT_AUTOLOGIN
case "$WANT_AUTOLOGIN" in
[yY]*) WANT_AUTOLOGIN="y" ;;
[nN]*) WANT_AUTOLOGIN="n" ;;
*) WANT_AUTOLOGIN="" ;;
esac
done
echo ""
while [ -z "$HOSTNAME" ]; do while [ -z "$HOSTNAME" ]; do
printf "Enter hostname: " printf "Enter hostname: "
read HOSTNAME read -r HOSTNAME
# Validate hostname
if [ -z "$HOSTNAME" ]; then if [[ ! "$HOSTNAME" =~ ^[a-zA-Z0-9.-]+$ ]]; then
echo "Hostname cannot be empty." echo "Invalid hostname. Use alphanumeric, dots, and hyphens only."
HOSTNAME=""
continue continue
fi fi
break
done done
echo "" echo ""
while [ -z "$ROOT_PASSWORD" ]; do while [ -z "$ROOT_PASSWORD" ]; do
printf "Enter root password: " printf "Enter root password: "
read -s ROOT_PASSWORD read -rs ROOT_PASSWORD
printf "\nConfirm root password: " printf "\nConfirm root password: "
read -s CONFIRM_ROOT_PASSWORD read -rs CONFIRM_ROOT_PASSWORD
echo ""
if [ "$ROOT_PASSWORD" != "$CONFIRM_ROOT_PASSWORD" ]; then if [ "$ROOT_PASSWORD" != "$CONFIRM_ROOT_PASSWORD" ] || [ -z "$ROOT_PASSWORD" ]; then
echo "Root passwords do not match." echo "Root passwords do not match or are empty."
ROOT_PASSWORD="" ROOT_PASSWORD=""
CONFIRM_ROOT_PASSWORD=""
continue continue
fi fi
break
done done
echo "" echo ""
echo ""
while [ -z "$USERNAME" ]; do while [ -z "$USERNAME" ]; do
printf "Enter username: " printf "Enter username: "
read USERNAME read -r USERNAME
# Validate username
if [ -z "$USERNAME" ]; then if [[ ! "$USERNAME" =~ ^[a-z_][a-z0-9_-]*$ ]]; then
echo "Username cannot be empty." echo "Invalid username. Must start with lowercase/underscore and contain no spaces."
USERNAME=""
continue continue
fi fi
break
done done
echo "" echo ""
while [ -z "$USER_PASSWORD" ]; do while [ -z "$USER_PASSWORD" ]; do
printf "Enter user password: " printf "Enter user password: "
read -s USER_PASSWORD read -rs USER_PASSWORD
printf "\nConfirm user password: " printf "\nConfirm user password: "
read -s CONFIRM_USER_PASSWORD read -rs CONFIRM_USER_PASSWORD
echo ""
if [ "$USER_PASSWORD" != "$CONFIRM_USER_PASSWORD" ]; then if [ "$USER_PASSWORD" != "$CONFIRM_USER_PASSWORD" ] || [ -z "$USER_PASSWORD" ]; then
echo "User passwords do not match." echo "User passwords do not match or are empty."
USER_PASSWORD="" USER_PASSWORD=""
CONFIRM_USER_PASSWORD=""
continue continue
fi fi
break
done done
} }
@@ -101,40 +124,45 @@ DISK=""
get_drive() { get_drive() {
send_status_message "DRIVE SETUP: Selecting and confirming target drive" send_status_message "DRIVE SETUP: Selecting and confirming target drive"
lsblk printf '%-8s %-8s %-30s %s\n' NAME SIZE MODEL
printf "\nEnter the drive name (e.g., sda, sdb, vda, nvme0n1): " lsblk # -do NAME,SIZE,MODEL
read DISK printf "\nEnter the drive name (e.g., sda, nvme0n1): "
read -r DISK
if [ -z "${DISK}" ]; then if [ -z "${DISK}" ]; then
echo "No drive name entered. Exiting." echo "No drive name entered. Exiting."
exit 1 exit 1
fi fi
DISK="/dev/${DISK}" DISK="/dev/${DISK}"
if [ ! -b "$DISK" ]; then
echo "Error: ${DISK} is not a valid block device."
exit 1
fi
PART_PREFIX="$DISK" PART_PREFIX="$DISK"
case "$DISK" in if [[ "$DISK" =~ [0-9]$ ]]; then
*nvme*n*) PART_PREFIX="${DISK}p" ;; # nvme devices need a 'p' before partition number PART_PREFIX="${DISK}p"
*) PART_PREFIX="${DISK}" ;; fi
esac
printf "WARNING: All data on %s will be erased. Are you sure? [Y/n] " "${DISK}" printf "WARNING: All data on %s will be erased. Are you sure? [Y/n] " "${DISK}"
read CONFIRMATION read -r CONFIRMATION
case "$CONFIRMATION" in case "$CONFIRMATION" in
"n" | "N") [nN]*)
echo "Operation canceled." echo "Operation canceled."
exit 0 exit 0
;; ;;
"" | "y" | "Y") "" | [yY]*)
echo "Proceeding with the operation on ${DISK}." echo "Proceeding with the operation on ${DISK}."
printf "Wiping drive in " printf "Wiping drive in "
for i in 3 2 1; do for i in 3 2 1; do
printf '%d...' $i printf '%d...' "$i"
sleep 1 sleep 1
done done
echo "" echo ""
;; ;;
*) *)
echo "Invalid input. Defaulting to 'No'." echo "Invalid input. Defaulting to 'No'."
exit 0 exit 1
;; ;;
esac esac
@@ -144,74 +172,93 @@ get_drive() {
setup_partitions() { setup_partitions() {
send_status_message "PARTITIONING: Creating partitions and filesystems" send_status_message "PARTITIONING: Creating partitions and filesystems"
if [ ! -d "/sys/firmware/efi" ]; then # Checking for BIOS system if [ ! -d "/sys/firmware/efi" ]; then
echo "BIOS systems are not supported." echo "BIOS systems are not supported."
exit 1
fi fi
umount -A -R /mnt # make sure everything is unmounted before we start echo "Ensuring $DISK is not in use..."
sgdisk -Z ${DISK} # zap all on disk grep "${DISK}" /proc/swaps | cut -d' ' -f1 | xargs -r swapoff || true
sgdisk -a 2048 -o ${DISK} # new GPT disk 2048 alignment grep "${DISK}" /proc/mounts | cut -d' ' -f2 | xargs -r umount -l || true
wipefs -a "${DISK}" || true
sgdisk -Z "${DISK}" || true
sgdisk -a 2048 -o "${DISK}" # new GPT disk 2048 alignment
# Create partitions # Create partitions
sgdisk -n 1::+1G --typecode=1:ef00 --change-name=1:"BOOT" ${DISK} # partition 1 (UEFI boot partition) sgdisk -n 1::+1G --typecode=1:ef00 --change-name=1:"BOOT" "${DISK}"
sgdisk -n 2::+4G --typecode=2:8200 --change-name=2:"SWAP" ${DISK} # partition 2 (Swap partition) sgdisk -n 2::-0 --typecode=2:8300 --change-name=2:"ROOT" "${DISK}"
sgdisk -n 3::-0 --typecode=3:8300 --change-name=3:"ROOT" ${DISK} # partition 3 (Root), default start, remaining # sgdisk -n 3::+4G --typecode=3:8200 --change-name=3:"SWAP" "${DISK}"
partprobe ${DISK} # reread partition table to ensure it is correct
partprobe "${DISK}"
sleep 2
# Create filesystems # Create filesystems
mkfs.fat -F32 -n "BOOT" ${PART_PREFIX}1 mkfs.fat -F32 -n "BOOT" "${PART_PREFIX}1"
mkswap -f ${PART_PREFIX}2 mkfs.ext4 -F -L "ROOT" "${PART_PREFIX}2"
mkfs.ext4 -F -L "ROOT" ${PART_PREFIX}3 # mkswap -f -L "SWAP" "${PART_PREFIX}3"
# Mount # Mount
mount ${PART_PREFIX}3 /mnt mount -t ext4 "${PART_PREFIX}2" /mnt
if [ $? -ne 0 ]; then mount --mkdir -t vfat "${PART_PREFIX}1" /mnt/boot
echo "Failed to mount the ROOT partition." # swapon "${PART_PREFIX}3"
exit 2 # Exit if mounting ROOT partition fails
fi
mount --mkdir ${PART_PREFIX}1 /mnt/boot
if [ $? -ne 0 ]; then
echo "Failed to mount the BOOT partition."
exit 2 # Exit if mounting BOOT partition fails
fi
swapon ${PART_PREFIX}2
} }
# Setup systemdboot as the bootloader # Setup systemdboot as the bootloader
setup_bootloader() { setup_bootloader() {
send_status_message "BOOTLOADER: Installing and configuring systemd-boot" send_status_message "BOOTLOADER: Installing and configuring systemd-boot"
# Run bootctl inside chroot
arch-chroot /mnt bootctl install arch-chroot /mnt bootctl install
if [ $? -ne 0 ]; then
echo "Error: Failed to install systemd-boot."
exit 3
fi
BOOTLOADER_ENTRY="/mnt/boot/loader/entries/arch.conf" BOOTLOADER_ENTRY="/mnt/boot/loader/entries/arch.conf"
ARCH_ENTRY_TEMPLATE="/mnt/usr/share/systemd/bootctl/arch.conf"
# Get PARTUUID for the root partition PARTUUID=$(blkid -s PARTUUID -o value "${PART_PREFIX}2")
PARTUUID=$(blkid | grep "${PART_PREFIX}3" | awk -F= '{print $NF}' | tr -d '\"')
if [ -z "$PARTUUID" ]; then if [ -z "$PARTUUID" ]; then
echo "Error: Unable to find PARTUUID for ${DISK}3." echo "Error: Unable to find PARTUUID for ${PART_PREFIX}2."
exit 3 exit 3
fi fi
# Create a new entry based on the template and PARTUUID
echo "Creating bootloader entry with PARTUUID=$PARTUUID" echo "Creating bootloader entry with PARTUUID=$PARTUUID"
sed "s/^options.*/options root=PARTUUID=$PARTUUID rw splash/" "$ARCH_ENTRY_TEMPLATE" >"$BOOTLOADER_ENTRY" cat <<EOF > "$BOOTLOADER_ENTRY"
title Arch Linux
linux /vmlinuz-linux
initrd /initramfs-linux.img
options root=PARTUUID=$PARTUUID rw splash
EOF
if [ $? -eq 0 ]; then echo "default arch.conf" > /mnt/boot/loader/loader.conf
echo "Successfully created bootloader entry: $BOOTLOADER_ENTRY" }
else
echo "Error: Failed to create the bootloader entry." setup_autologin() {
exit 3 if [ "$WANT_AUTOLOGIN" != "y" ]; then
return
fi fi
send_status_message "CONFIG: Configuring autologin for $USERNAME"
cat > "/mnt/etc/systemd/system/autologin@.service" <<EOF
[Unit]
Description=Autologin on %I
After=systemd-user-sessions.service
Conflicts=getty@%i.service
[Service]
ExecStart=-/sbin/agetty --autologin $USERNAME --noclear %I \$TERM
Type=idle
Restart=always
TTYPath=/dev/%I
TTYReset=yes
TTYVHangup=yes
TTYVTDisallocate=yes
[Install]
WantedBy=multi-user.target
EOF
arch-chroot /mnt systemctl disable lemurs
arch-chroot /mnt systemctl enable autologin@tty1.service
} }
# >------ Main execution flow ------< # >------ Main execution flow ------<
@@ -247,25 +294,33 @@ send_status_message "SYSTEM CONFIG: Setting timezone, locales, and hostname"
ln -sf /usr/share/zoneinfo/Europe/Paris /mnt/etc/localtime ln -sf /usr/share/zoneinfo/Europe/Paris /mnt/etc/localtime
echo 'en_US.UTF-8 UTF-8' >> /mnt/etc/locale.gen echo 'en_US.UTF-8 UTF-8' >> /mnt/etc/locale.gen
arch-chroot /mnt locale-gen arch-chroot /mnt locale-gen
echo LANG=en_US.UTF-8 >/mnt/etc/locale.conf echo "LANG=en_US.UTF-8" > /mnt/etc/locale.conf
echo $HOSTNAME >/mnt/etc/hostname echo "$HOSTNAME" > /mnt/etc/hostname
send_status_message "USER SETUP: Creating user and setting passwords" send_status_message "USER SETUP: Creating user and setting passwords"
# Set root password # Set root password
arch-chroot /mnt bash -c "echo 'root:$ROOT_PASSWORD' | chpasswd" arch-chroot /mnt chpasswd <<EOF
root:$ROOT_PASSWORD
EOF
# Create user and set password # Create user and set password
arch-chroot /mnt useradd -m $USERNAME arch-chroot /mnt useradd -m "$USERNAME"
arch-chroot /mnt bash -c "echo '$USERNAME:$USER_PASSWORD' | chpasswd" arch-chroot /mnt chpasswd <<EOF
$USERNAME:$USER_PASSWORD
EOF
# Setup wheel group # Setup wheel group
arch-chroot /mnt usermod -aG wheel $USERNAME arch-chroot /mnt usermod -aG wheel "$USERNAME"
arch-chroot /mnt bash -c "echo '%wheel ALL=(ALL) ALL' | EDITOR='tee -a' visudo" echo "%wheel ALL=(ALL:ALL) ALL" > /mnt/etc/sudoers.d/10-wheel
chmod 440 /mnt/etc/sudoers.d/10-wheel
send_status_message "SERVICES: Enabling NetworkManager and lemurs" send_status_message "SERVICES: Enabling NetworkManager and lemurs"
# Setup services and display manager # Setup services and display manager
arch-chroot /mnt systemctl enable NetworkManager lemurs arch-chroot /mnt systemctl enable NetworkManager lemurs
# Configure autologin for lemurs if requested
setup_autologin
setup_bootloader setup_bootloader
send_status_message "CLEANUP: Unmounting all filesystems" send_status_message "CLEANUP: Unmounting all filesystems"