Refactored installer into modular library structure with improved error handling and logging.
The changes include: - Split monolithic script into lib/, config/, profiles/, and files/ directories - Added error handling with cleanup on failure - Added installation logging to /var/log/arch-install.log - Added username validation
This commit is contained in:
104
lib/system/base.sh
Normal file
104
lib/system/base.sh
Normal file
@@ -0,0 +1,104 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2026 Logan Fick
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# base.sh - Base system installation functions
|
||||
#
|
||||
# Installs and configures the core Arch Linux system:
|
||||
# - Runs pacstrap with base packages defined in defaults.conf
|
||||
# - Detects CPU vendor and installs appropriate microcode (Intel/AMD)
|
||||
# - Generates /etc/fstab with UUIDs
|
||||
# - Provides chroot helper functions for running commands in new system
|
||||
# - Copies configuration files from installer to target system
|
||||
|
||||
# Run a command in the chroot environment
|
||||
# Arguments:
|
||||
# $@ - command and arguments
|
||||
chroot_run() {
|
||||
arch-chroot "${MOUNT_POINT}" "$@"
|
||||
}
|
||||
|
||||
# Install packages in the chroot environment
|
||||
# Arguments:
|
||||
# $@ - package names
|
||||
chroot_install() {
|
||||
run_visible_cmd chroot_run pacman --noconfirm -S "$@"
|
||||
}
|
||||
|
||||
# Enable a systemd service in the chroot environment
|
||||
# Arguments:
|
||||
# $@ - service names
|
||||
chroot_enable() {
|
||||
run_visible_cmd chroot_run systemctl enable "$@"
|
||||
}
|
||||
|
||||
# Install base Arch Linux packages
|
||||
install_base_packages() {
|
||||
print "Installing Arch Linux base..."
|
||||
|
||||
run_visible_cmd pacstrap -K "${MOUNT_POINT}" "${BASE_PACKAGES[@]}"
|
||||
}
|
||||
|
||||
# Detect CPU vendor
|
||||
# Outputs:
|
||||
# "intel", "amd", or "unknown"
|
||||
detect_cpu_vendor() {
|
||||
local vendor
|
||||
vendor=$(grep -m 1 'vendor_id' /proc/cpuinfo | awk '{print $3}')
|
||||
|
||||
case "$vendor" in
|
||||
"GenuineIntel")
|
||||
echo "intel"
|
||||
;;
|
||||
"AuthenticAMD")
|
||||
echo "amd"
|
||||
;;
|
||||
*)
|
||||
echo "unknown"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Install CPU microcode based on detected vendor
|
||||
install_microcode() {
|
||||
local vendor
|
||||
vendor=$(detect_cpu_vendor)
|
||||
|
||||
print "Installing CPU microcode..."
|
||||
|
||||
case "$vendor" in
|
||||
"intel")
|
||||
chroot_install intel-ucode
|
||||
;;
|
||||
"amd")
|
||||
chroot_install amd-ucode
|
||||
;;
|
||||
*)
|
||||
print_warning "Unknown CPU vendor: ${vendor}. Please install microcode manually after installation, if available."
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Generate /etc/fstab
|
||||
generate_fstab() {
|
||||
print "Generating /etc/fstab..."
|
||||
genfstab -U "${MOUNT_POINT}" >> "${MOUNT_POINT}/etc/fstab"
|
||||
}
|
||||
|
||||
# Copy configuration files from installer to target system
|
||||
copy_config_files() {
|
||||
print "Installing default configuration files..."
|
||||
cp -r "${CONFIG_SRC_DIR}" "${MOUNT_POINT}"
|
||||
}
|
||||
88
lib/system/bootloader.sh
Normal file
88
lib/system/bootloader.sh
Normal file
@@ -0,0 +1,88 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2026 Logan Fick
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# bootloader.sh - systemd-boot configuration
|
||||
#
|
||||
# Installs and configures systemd-boot as the bootloader:
|
||||
# - Runs bootctl install to set up EFI boot manager
|
||||
# - Creates boot entry with LUKS unlock parameters
|
||||
# - Supports both single-disk and RAID1 configurations
|
||||
# - Configures loader.conf timeout setting
|
||||
|
||||
# Install systemd-boot bootloader
|
||||
install_bootloader() {
|
||||
print "Installing bootloader..."
|
||||
run_visible_cmd chroot_run bootctl install
|
||||
}
|
||||
|
||||
# Create boot entry for single-disk installation
|
||||
# Arguments:
|
||||
# $1 - LUKS UUID
|
||||
create_boot_entry_single() {
|
||||
local luks_uuid="$1"
|
||||
|
||||
chroot_run sh -c "cat > /boot/loader/entries/arch.conf" <<EOF
|
||||
title Arch Linux
|
||||
linux /vmlinuz-linux
|
||||
initrd /initramfs-linux.img
|
||||
options rd.luks.name=${luks_uuid}=cryptroot rd.luks.options=discard root=/dev/mapper/cryptroot
|
||||
EOF
|
||||
}
|
||||
|
||||
# Create boot entry for RAID1 installation
|
||||
# Arguments:
|
||||
# $1 - first LUKS UUID
|
||||
# $2 - second LUKS UUID
|
||||
create_boot_entry_raid1() {
|
||||
local luks_uuid_1="$1"
|
||||
local luks_uuid_2="$2"
|
||||
|
||||
chroot_run sh -c "cat > /boot/loader/entries/arch.conf" <<EOF
|
||||
title Arch Linux
|
||||
linux /vmlinuz-linux
|
||||
initrd /initramfs-linux.img
|
||||
options rd.luks.name=${luks_uuid_1}=cryptroot-primary rd.luks.name=${luks_uuid_2}=cryptroot-secondary rd.luks.options=${luks_uuid_1}=discard rd.luks.options=${luks_uuid_2}=discard root=/dev/mapper/cryptroot-primary
|
||||
EOF
|
||||
}
|
||||
|
||||
# Create appropriate boot entry based on storage mode
|
||||
# Arguments:
|
||||
# $1 - storage mode (single, raid1)
|
||||
create_boot_entry() {
|
||||
local storage_mode="$1"
|
||||
|
||||
if [ "$storage_mode" = "raid1" ]; then
|
||||
create_boot_entry_raid1 "$LUKS_UUID" "$LUKS_UUID_2"
|
||||
else
|
||||
create_boot_entry_single "$LUKS_UUID"
|
||||
fi
|
||||
}
|
||||
|
||||
# Configure loader.conf timeout
|
||||
configure_loader() {
|
||||
chroot_run sed -i '/^#timeout 3/s/^#//' /boot/loader/loader.conf
|
||||
}
|
||||
|
||||
# Full bootloader setup
|
||||
# Arguments:
|
||||
# $1 - storage mode
|
||||
setup_bootloader() {
|
||||
local storage_mode="$1"
|
||||
|
||||
install_bootloader
|
||||
create_boot_entry "$storage_mode"
|
||||
configure_loader
|
||||
}
|
||||
43
lib/system/locale.sh
Normal file
43
lib/system/locale.sh
Normal file
@@ -0,0 +1,43 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2026 Logan Fick
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# locale.sh - Locale and timezone configuration
|
||||
#
|
||||
# Configures locale (en_US.UTF-8) and runs systemd-firstboot for timezone,
|
||||
# keymap, and hostname setup.
|
||||
|
||||
# Configure system locale (en_US.UTF-8)
|
||||
configure_locale() {
|
||||
print "Setting up locale..."
|
||||
|
||||
chroot_run sed -i '/^#.*en_US.UTF-8 UTF-8/s/^#//' /etc/locale.gen
|
||||
run_visible_cmd chroot_run locale-gen
|
||||
chroot_run systemd-firstboot --locale=en_US.UTF-8
|
||||
}
|
||||
|
||||
# Run interactive firstboot setup for timezone, keymap, hostname
|
||||
run_firstboot() {
|
||||
print "Entering first time setup..."
|
||||
print "Your keymap is probably 'us' and the time zone is probably 'America/New_York'."
|
||||
|
||||
run_visible_cmd chroot_run systemd-firstboot --prompt
|
||||
}
|
||||
|
||||
# Full locale and timezone setup
|
||||
setup_locale() {
|
||||
configure_locale
|
||||
run_firstboot
|
||||
}
|
||||
95
lib/system/network.sh
Normal file
95
lib/system/network.sh
Normal file
@@ -0,0 +1,95 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2026 Logan Fick
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# network.sh - Network configuration
|
||||
#
|
||||
# Handles network setup for both installation and target system:
|
||||
# - Verifies internet connectivity before installation begins
|
||||
# - Checks system time synchronization via systemd-timesyncd
|
||||
# - Configures pacman mirrorlist to use private mirror
|
||||
# - Enables systemd-resolved, systemd-networkd, and systemd-timesyncd
|
||||
# - Optionally installs iwd for Wi-Fi support
|
||||
|
||||
# Check internet connectivity
|
||||
check_internet() {
|
||||
print "Checking internet connectivity..."
|
||||
|
||||
if curl -s --head "$INTERNET_CHECK_URL" | grep "200" >/dev/null; then
|
||||
print_success "Internet connection is available!"
|
||||
return 0
|
||||
else
|
||||
print_error "Internet connection appears not available (HTTP request to \"$INTERNET_CHECK_URL\" failed). Please check network settings and re-run this script."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Check system time synchronization
|
||||
check_time_sync() {
|
||||
print "Checking system time synchronization state..."
|
||||
|
||||
if timedatectl status | grep -q "System clock synchronized: yes"; then
|
||||
print_success "System time is synchronized!"
|
||||
return 0
|
||||
else
|
||||
print_error "The system time is not synchronized. Please check systemd-timesyncd and re-run this script."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Configure pacman mirrorlist
|
||||
configure_mirrorlist() {
|
||||
print "Setting mirrorlist to use private mirror..."
|
||||
echo "Server = ${MIRROR_URL}" > /etc/pacman.d/mirrorlist
|
||||
}
|
||||
|
||||
# Enable systemd-resolved
|
||||
enable_resolved() {
|
||||
print "Enabling systemd-resolved..."
|
||||
|
||||
chroot_enable systemd-resolved.service
|
||||
ln -sf ../run/systemd/resolve/stub-resolv.conf "${MOUNT_POINT}/etc/resolv.conf"
|
||||
}
|
||||
|
||||
# Enable systemd-networkd
|
||||
enable_networkd() {
|
||||
print "Enabling systemd-networkd..."
|
||||
chroot_enable systemd-networkd.service
|
||||
}
|
||||
|
||||
# Enable systemd-timesyncd
|
||||
enable_timesyncd() {
|
||||
print "Enabling systemd-timesyncd..."
|
||||
chroot_enable systemd-timesyncd.service
|
||||
}
|
||||
|
||||
# Prompt and install iwd for Wi-Fi support
|
||||
prompt_install_wifi() {
|
||||
print "Would you like to install iwd for Wi-Fi support? Enter 'y' exactly for yes, otherwise anything else to skip."
|
||||
read -r install_iwd
|
||||
|
||||
if [ "$install_iwd" = "y" ]; then
|
||||
print "Installing iwd..."
|
||||
chroot_install iwd
|
||||
chroot_enable iwd.service
|
||||
fi
|
||||
}
|
||||
|
||||
# Full network setup
|
||||
setup_network() {
|
||||
enable_resolved
|
||||
enable_networkd
|
||||
enable_timesyncd
|
||||
}
|
||||
131
lib/system/security.sh
Normal file
131
lib/system/security.sh
Normal file
@@ -0,0 +1,131 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2026 Logan Fick
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# security.sh - Security hardening functions
|
||||
#
|
||||
# Applies security hardening to the installed system:
|
||||
# - Configures mkinitcpio with sd-encrypt hook for LUKS
|
||||
# - Enables sudo access for wheel group
|
||||
# - Disables root account login
|
||||
# - Enables nftables firewall, smartd, and fstrim timer
|
||||
# - Configures OpenSSH with restricted settings
|
||||
# - Installs custom CA certificate to system trust store
|
||||
# - Sets up USBGuard to whitelist connected devices
|
||||
|
||||
# Configure mkinitcpio hooks for encrypted root
|
||||
configure_initramfs() {
|
||||
print "Configuring initramfs..."
|
||||
|
||||
local default_line="HOOKS=(base systemd autodetect microcode modconf kms keyboard keymap sd-vconsole block filesystems fsck)"
|
||||
local new_line="HOOKS=(systemd autodetect microcode modconf kms keyboard sd-vconsole block sd-encrypt filesystems fsck)"
|
||||
|
||||
chroot_run sed -i "s|^${default_line}|${new_line}|" /etc/mkinitcpio.conf
|
||||
run_visible_cmd chroot_run mkinitcpio -P
|
||||
}
|
||||
|
||||
# Enable fstrim timer for SSD maintenance
|
||||
enable_fstrim() {
|
||||
print "Enabling fstrim timer..."
|
||||
chroot_enable fstrim.timer
|
||||
}
|
||||
|
||||
# Enable BTRFS scrub timer
|
||||
# Arguments:
|
||||
# $1 - filesystem type
|
||||
enable_btrfs_scrub() {
|
||||
local filesystem="$1"
|
||||
|
||||
if [ "$filesystem" = "btrfs" ] || [ "$filesystem" = "btrfs-dup" ]; then
|
||||
print "Enabling btrfs scrub timer..."
|
||||
chroot_enable btrfs-scrub@-.timer
|
||||
fi
|
||||
}
|
||||
|
||||
# Configure sudo access for wheel group
|
||||
configure_sudo() {
|
||||
print "Enabling sudo access for wheel group..."
|
||||
chroot_run sed -i "s|^# %wheel ALL=(ALL:ALL) ALL|%wheel ALL=(ALL:ALL) ALL|" /etc/sudoers
|
||||
}
|
||||
|
||||
# Disable root account login
|
||||
disable_root() {
|
||||
print "Disabling root account..."
|
||||
chroot_run passwd -l root
|
||||
}
|
||||
|
||||
# Enable nftables firewall
|
||||
enable_firewall() {
|
||||
print "Enabling nftables firewall..."
|
||||
chroot_enable nftables.service
|
||||
}
|
||||
|
||||
# Enable smartd for drive monitoring
|
||||
enable_smartd() {
|
||||
print "Enabling smartd..."
|
||||
chroot_enable smartd.service
|
||||
}
|
||||
|
||||
# Configure SSH server
|
||||
# Arguments:
|
||||
# $1 - username to allow SSH access
|
||||
configure_ssh() {
|
||||
local username="$1"
|
||||
|
||||
print "Setting up and enabling OpenSSH server..."
|
||||
|
||||
chroot_run sed -i "s|PLACEHOLDER|${username}|" /etc/ssh/sshd_config
|
||||
run_visible_cmd chroot_run ssh-keygen -t ed25519 -C "" -N "" -f /etc/ssh/ssh_host_ed25519_key
|
||||
chroot_enable sshd.service
|
||||
}
|
||||
|
||||
# Display SSH host key fingerprint
|
||||
show_ssh_fingerprint() {
|
||||
print "Public SSH key fingerprint of this host:"
|
||||
run_visible_cmd chroot_run ssh-keygen -lvf /etc/ssh/ssh_host_ed25519_key.pub
|
||||
}
|
||||
|
||||
# Install custom CA certificate
|
||||
install_ca_certificate() {
|
||||
print "Adding LogalNet Internal Certification Authority to system CA store..."
|
||||
|
||||
cp "${CA_CERT_PATH}" "${MOUNT_POINT}"
|
||||
chroot_run trust anchor --store /logalnet-internal-ca.crt
|
||||
chroot_run rm /logalnet-internal-ca.crt
|
||||
}
|
||||
|
||||
# Configure USBGuard
|
||||
configure_usbguard() {
|
||||
print "Please add or remove any USB devices, including the installer drive, to form the standard configuration for this system. USBGuard will be configured to only allow the USB devices connected at the time you press enter to be used; everything else will be blocked."
|
||||
print "When ready to proceed, press enter."
|
||||
read -r
|
||||
|
||||
chroot_run sh -c "usbguard generate-policy > /etc/usbguard/rules.conf"
|
||||
chroot_enable usbguard.service
|
||||
}
|
||||
|
||||
# Full security setup
|
||||
# Arguments:
|
||||
# $1 - filesystem type
|
||||
setup_security() {
|
||||
local filesystem="$1"
|
||||
|
||||
configure_sudo
|
||||
disable_root
|
||||
enable_firewall
|
||||
enable_smartd
|
||||
enable_fstrim
|
||||
enable_btrfs_scrub "$filesystem"
|
||||
}
|
||||
66
lib/system/user.sh
Normal file
66
lib/system/user.sh
Normal file
@@ -0,0 +1,66 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2026 Logan Fick
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# user.sh - User account management
|
||||
#
|
||||
# Creates the primary user account with wheel group membership.
|
||||
|
||||
# Prompt for username
|
||||
# Sets:
|
||||
# USERNAME - the entered username
|
||||
prompt_username() {
|
||||
local username
|
||||
|
||||
while true; do
|
||||
print "Please enter the username you'd like to use for your account:"
|
||||
read -r username
|
||||
|
||||
if validate_username "$username"; then
|
||||
USERNAME="$username"
|
||||
return 0
|
||||
fi
|
||||
|
||||
print "Please try again."
|
||||
done
|
||||
}
|
||||
|
||||
# Create a user account
|
||||
# Arguments:
|
||||
# $1 - username
|
||||
create_user() {
|
||||
local username="$1"
|
||||
|
||||
chroot_run useradd -m -G wheel "$username"
|
||||
}
|
||||
|
||||
# Set password for a user
|
||||
# Arguments:
|
||||
# $1 - username
|
||||
set_user_password() {
|
||||
local username="$1"
|
||||
|
||||
print "Please set the password for your new account."
|
||||
chroot_run passwd "$username"
|
||||
}
|
||||
|
||||
# Full user setup
|
||||
# Sets:
|
||||
# USERNAME - the created username
|
||||
setup_user() {
|
||||
prompt_username
|
||||
create_user "$USERNAME"
|
||||
set_user_password "$USERNAME"
|
||||
}
|
||||
Reference in New Issue
Block a user