summaryrefslogtreecommitdiff
path: root/archsetup
diff options
context:
space:
mode:
Diffstat (limited to 'archsetup')
-rwxr-xr-xarchsetup306
1 files changed, 158 insertions, 148 deletions
diff --git a/archsetup b/archsetup
index f4958f3..aa96be7 100755
--- a/archsetup
+++ b/archsetup
@@ -107,24 +107,34 @@ load_config() {
[[ "$AUTOLOGIN" == "yes" ]] && enable_autologin=true
[[ "$AUTOLOGIN" == "no" ]] && enable_autologin=false
[[ "$NO_GPU_DRIVERS" == "yes" ]] && skip_gpu_drivers=true
+
+ # Repository overrides
+ [[ -n "$DWM_REPO" ]] && dwm_repo="$DWM_REPO"
+ [[ -n "$DMENU_REPO" ]] && dmenu_repo="$DMENU_REPO"
+ [[ -n "$ST_REPO" ]] && st_repo="$ST_REPO"
+ [[ -n "$SLOCK_REPO" ]] && slock_repo="$SLOCK_REPO"
+ [[ -n "$DOTEMACS_REPO" ]] && dotemacs_repo="$DOTEMACS_REPO"
}
# Load config if specified
[[ -n "$config_file" ]] && load_config "$config_file"
-### Constants (defaults, may be overridden by config file)
+### Configuration Defaults
+# These can be overridden via --config-file
username="${username:-cjennings}"
-password="${password:-welcome}" # will be changed on first login. :)
+password="${password:-welcome}" # CHANGE ON FIRST LOGIN
archsetup_dir="$(dirname "$(readlink -f "$0")")"
dotfiles_dir="$archsetup_dir/dotfiles"
-dwm_repo="https://git.cjennings.net/dwm.git"
-dmenu_repo="https://git.cjennings.net/dmenu.git"
-st_repo="https://git.cjennings.net/st.git"
-slock_repo="https://git.cjennings.net/slock.git"
-dotemacs_repo="https://git.cjennings.net/dotemacs.git"
+# Git repositories for suckless tools and dotfiles
+# Override these in config file to use your own forks
+dwm_repo="${dwm_repo:-https://git.cjennings.net/dwm.git}"
+dmenu_repo="${dmenu_repo:-https://git.cjennings.net/dmenu.git}"
+st_repo="${st_repo:-https://git.cjennings.net/st.git}"
+slock_repo="${slock_repo:-https://git.cjennings.net/slock.git}"
+dotemacs_repo="${dotemacs_repo:-https://git.cjennings.net/dotemacs.git}"
logfile="/var/log/archsetup-$(date +'%Y-%m-%d-%H-%M-%S').log"
source_dir="/home/$username/.local/src" # aur/git source goes here
@@ -261,113 +271,111 @@ preflight_checks() {
### Intro
intro() {
- printf "\n\nArchSetup launched @ %s\n" "$(date +'%D %T')"| tee -a "$logfile"
errors_encountered=0
# begin with a clean logfile
[ -f "$logfile" ] && rm -f "$logfile"
touch "$logfile"
+ printf "\n\nArchSetup launched @ %s\n" "$(date +'%D %T')" | tee -a "$logfile"
+
# count the arch packages before install
pacman -Q > "$packages_before" || \
- error "crash" "generating pre-install package list" "$?"
+ error_fatal "generating pre-install package list" "$?"
}
-### General Functions
-# Error
-error () {
- # $1 = type ERROR, noted but the script will continue to run.
- # anything else will produce CRASH, which halts the script
- # $2 = what was happening (e.g., "adding $username to group $groupname")
- # $3 = the error code (i.e., "$?")
+### Error Handling
+# Non-fatal error - log and continue
+# Usage: error_warn "what failed" "$?"
+error_warn() {
errors_encountered=$((errors_encountered+1))
- case "$1" in
- "error")
- msg="$2 (error code: $3)"
- error_messages+=("$msg")
- printf "ERROR: %s @ %s\n" "$msg" "$(date +'%T')" | tee -a "$logfile"
- return 1;
- ;;
- *)
- printf "CRASH: %s failed with error: %s @ %s. Script halted.\n" \
- "$2" "$3" "$(date +'%T')" | tee -a "$logfile"
- exit 1;
- ;;
- esac
+ local msg="$1 (error code: $2)"
+ error_messages+=("$msg")
+ printf "ERROR: %s @ %s\n" "$msg" "$(date +'%T')" | tee -a "$logfile"
+ return 1
+}
+
+# Fatal error - log and exit
+# Usage: error_fatal "what failed" "$?"
+error_fatal() {
+ printf "CRASH: %s (error: %s) @ %s. Halting.\n" \
+ "$1" "$2" "$(date +'%T')" | tee -a "$logfile"
+ exit 1
}
-# Display
-display () {
- # $1 = type (TITLE, ACTION)
- # $2 = description (answers: "what are you trying to do?")
+### Output & Logging
+display() {
case "$1" in
"title")
printf "\n##### %s\n" "$2" | tee -a "$logfile"
- return 0;
;;
"subtitle")
- printf "\n%s\n" "$2" | tee -a "$logfile"
- return 0;
+ printf "\n%s\n" "$2" | tee -a "$logfile"
;;
"task")
printf "...%s @ %s\n" "$2" "$(date +'%T')" | tee -a "$logfile"
- return 0;
;;
*)
- printf "CRASH: display () called with incorrect arguments.\n"
+ printf "CRASH: display() called with incorrect arguments.\n"
printf "...called %s type, %s action @ %s\n" \
- "$1" "$2" "$(date +'%T')" | tee -a "$logfile"
- exit 1;
+ "$1" "$2" "$(date +'%T')" | tee -a "$logfile"
+ exit 1
;;
esac
+}
+
+### Installation Helpers
+MAX_INSTALL_RETRIES=3
+retry_install() {
+ local pkg="$1"
+ local source="$2"
+ local cmd="$3"
+ local attempt=1
+
+ display "task" "installing $pkg via $source"
+ while [ $attempt -le $MAX_INSTALL_RETRIES ]; do
+ if eval "$cmd" >> "$logfile" 2>&1; then
+ return 0
+ fi
+ attempt=$((attempt + 1))
+ if [ $attempt -le $MAX_INSTALL_RETRIES ]; then
+ display "task" "retrying $pkg (attempt $attempt/$MAX_INSTALL_RETRIES)"
+ fi
+ done
+ error_warn "$pkg ($source)" "$?"
}
# Pacman Install
pacman_install() {
- action="installing $1 via pacman" && display "task" "$action"
- if ! (pacman --noconfirm --needed -S "$1" >> "$logfile" 2>&1); then
- action="retrying $1" && display "task" "$action"
- if ! (pacman --noconfirm --needed -S "$1" >> "$logfile" 2>&1); then
- action="retrying $1 once more" && display "task" "$action"
- (pacman --noconfirm --needed -S "$1" >> "$logfile" 2>&1) ||
- error "error" "$1 (pacman)" "$?"
- fi
- fi
+ retry_install "$1" "pacman" "pacman --noconfirm --needed -S $1"
+}
+
+# AUR Install
+aur_install() {
+ retry_install "$1" "AUR" "sudo -u $username yay -S --noconfirm $1"
}
# Git Install
git_install() {
+ local prog_name
prog_name="$(basename "$1" .git)"
- build_dir="$source_dir/$prog_name"
- action="building & installing $prog_name from source"
- display "task" "$action"
+ local build_dir="$source_dir/$prog_name"
+
+ display "task" "building & installing $prog_name from source"
if ! (sudo -u "$username" git clone --depth 1 "$1" "$build_dir" >> "$logfile" 2>&1); then
- error "error" "cloning source code for $prog_name - directory may exist, removing and retrying" "$?"
- (rm -rf "$build_dir" >> "$logfile" 2>&1) || \
- error "error" "removing existing directory for $prog_name" "$?"
- (sudo -u "$username" git clone --depth 1 "$1" "$build_dir" >> "$logfile" 2>&1) || \
- error "crash" "re-cloning source code for $prog_name after cleanup" "$?"
+ error_warn "cloning $prog_name - directory may exist, removing and retrying" "$?"
+ rm -rf "$build_dir" >> "$logfile" 2>&1 || \
+ error_warn "removing existing directory for $prog_name" "$?"
+ sudo -u "$username" git clone --depth 1 "$1" "$build_dir" >> "$logfile" 2>&1 || \
+ error_fatal "re-cloning $prog_name after cleanup" "$?"
fi
(cd "$build_dir" && make install >> "$logfile" 2>&1) || \
- error "error" "building $prog_name from source code" "$?"
-}
-
-# AUR Install
-aur_install() {
- action="installing $1 via the AUR" && display "task" "$action"
- if ! (sudo -u "$username" yay -S --noconfirm "$1" >> "$logfile" 2>&1); then
- action="retrying $1" && display "task" "$action"
- if ! (sudo -u "$username" yay -S --noconfirm "$1" >> "$logfile" 2>&1); then
- action="retrying $1 once more" && display "task" "$action"
- (sudo -u "$username" yay -S --noconfirm "$1" >> "$logfile" 2>&1) ||
- error "error" "$1 (AUR)" "$?"
- fi
- fi
+ error_warn "building $prog_name from source" "$?"
}
# PIP Install (using pipx for isolated environments)
@@ -375,10 +383,11 @@ pip_install() {
[ -x "$(command -v "pipx")" ] || pacman_install python-pipx
action="installing $1 via pipx" && display "task" "$action"
(sudo -u "$username" pipx install "$1" >> "$logfile" 2>&1) || \
- error "error" "$action" "$?"
+ error_warn "$action" "$?"
}
-# Filesystem Detection
+### System Detection
+
is_zfs_root() {
# Returns 0 (true) if root filesystem is ZFS, 1 (false) otherwise
[ "$(findmnt -n -o FSTYPE /)" = "zfs" ]
@@ -421,7 +430,8 @@ has_nvme_drives() {
ls /dev/nvme* &>/dev/null
}
-# Automatic Login Configuration
+### System Configuration
+
configure_autologin() {
local do_autologin=false
@@ -568,16 +578,16 @@ prerequisites() {
display "subtitle" "Bootstrapping"
action="ensuring current Arch Linux keyring" && display "task" "$action"
- (pacman -Syy) >> "$logfile" 2>&1 || error "crash" "$action" "$?"
+ (pacman -Syy) >> "$logfile" 2>&1 || error_fatal "$action" "$?"
(pacman -S --noconfirm archlinux-keyring) >> "$logfile" 2>&1 || \
- error "crash" "$action" "$?"
+ error_fatal "$action" "$?"
display "task" "verifying Arch Linux keys"
(pacman-key --populate archlinux >> "$logfile" 2>&1) || \
- error "crash" "verifying Arch Linux keys" "$?"
+ error_fatal "verifying Arch Linux keys" "$?"
action="refreshing the package cache" && display "task" "$action"
- (pacman -Syu --noconfirm >> "$logfile" 2>&1) || error "crash" "$action" "$?"
+ (pacman -Syu --noconfirm >> "$logfile" 2>&1) || error_fatal "$action" "$?"
display "subtitle" "Required Software"
@@ -592,19 +602,19 @@ prerequisites() {
# configure locale (must happen before package installs that depend on locale)
action="configuring locale" && display "task" "$action"
sed -i 's/^#en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen
- (locale-gen >> "$logfile" 2>&1) || error "error" "$action" "$?"
+ (locale-gen >> "$logfile" 2>&1) || error_warn "$action" "$?"
echo "LANG=en_US.UTF-8" > /etc/locale.conf
export LANG=en_US.UTF-8
# sync the time on this machine (one-shot chrony sync)
action="synchronizing system time" && display "task" "$action"
- (chronyd -q 'server 0.us.pool.ntp.org iburst' >> "$logfile" 2>&1) || error "error" "$action" "$?"
+ (chronyd -q 'server 0.us.pool.ntp.org iburst' >> "$logfile" 2>&1) || error_warn "$action" "$?"
# enable chrony for ongoing time sync and create config to suppress warning
action="enabling chrony time sync service" && display "task" "$action"
mkdir -p /etc/sysconfig
echo 'OPTIONS=""' > /etc/sysconfig/chronyd
- systemctl enable chronyd.service >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ systemctl enable chronyd.service >> "$logfile" 2>&1 || error_warn "$action" "$?"
action="configuring compiler to use all processor cores" && display "task" "$action"
sed -i "s/-j2/-j$(nproc)/;s/^#MAKEFLAGS/MAKEFLAGS/" /etc/makepkg.conf >> "$logfile" 2>&1
@@ -647,29 +657,29 @@ EOF
action="enabling the reflector timer" && display "task" "$action"
(systemctl enable reflector.timer >> "$logfile" 2>&1) || \
- error "error" "$action" "$?"
+ error_warn "$action" "$?"
action="replacing sudoers file if new package version exists" && display "task" "$action"
[ -f /etc/sudoers.pacnew ] && cp /etc/sudoers.pacnew /etc/sudoers >> "$logfile" 2>&1
action="creating a directory to build/install software from git/AUR."
- (mkdir -p "$source_dir") || error "crash" "creating the directory $source_dir"
+ (mkdir -p "$source_dir") || error_fatal "creating the directory $source_dir"
}
### Create User
-create_user () {
+create_user() {
display "title" "User Creation"
display "task" "checking if user exists"
# halt if $username exists
( id -u "$username" >/dev/null 2>&1; ) && \
- error "crash" "user '$username' already exists!"
+ error_fatal "user '$username' already exists!"
# create $username with home, group, shell, password
action="creating user and home directory" && display "task" "$action"
(useradd -m -G wheel -s /bin/zsh "$username" >> "$logfile" 2>&1) || \
- error "crash" "adding user '$username" "$?"
+ error_fatal "adding user '$username" "$?"
display "task" "assigning the password"
echo "$username:$password" | chpasswd # any text is allowable! be careful!
@@ -677,7 +687,7 @@ create_user () {
display "task" "adding to appropriate groups"
(usermod -aG \
sys,adm,network,scanner,power,uucp,audio,lp,rfkill,video,storage,optical,users \
- "$username" >> "$logfile" 2>&1) || error "crash" "adding $username to groups" "$?"
+ "$username" >> "$logfile" 2>&1) || error_fatal "adding $username to groups" "$?"
display "task" "configuring shell"
# zsh cache required: $username will install via yay; zsh will run those commands
@@ -686,23 +696,23 @@ create_user () {
# give $username sudo nopasswd rights (required for aur installs)
display "task" "granting permissions"
(echo "%$username ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers) \
- || error "error" "$action" "$?"
+ || error_warn "$action" "$?"
# mount as ramdisk to speed aur/git build/installs
(mount -t tmpfs -o size=4G archsetup "$source_dir" >> "$logfile" 2>&1) || \
- error "crash" "mounting the RAM disk for archsetup" "$?"
+ error_fatal "mounting the RAM disk for archsetup" "$?"
(chown -R "$username":wheel "$source_dir" >> "$logfile" 2>&1) || \
- error "crash" "changing ownership of $source_dir" "$?"
+ error_fatal "changing ownership of $source_dir" "$?"
# Bootstrap DNS for git clones and AUR installs (full config in essential_services)
if [ ! -L /etc/resolv.conf ] || [ "$(readlink /etc/resolv.conf)" != "/run/systemd/resolve/stub-resolv.conf" ]; then
display "task" "bootstrapping DNS resolution"
# Must start systemd-resolved first - stub-resolv.conf only exists when it's running
systemctl start systemd-resolved >> "$logfile" 2>&1 || \
- error "error" "starting systemd-resolved for DNS bootstrap" "$?"
+ error_warn "starting systemd-resolved for DNS bootstrap" "$?"
ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf >> "$logfile" 2>&1 || \
- error "error" "bootstrapping DNS resolution" "$?"
+ error_warn "bootstrapping DNS resolution" "$?"
fi
}
@@ -718,25 +728,25 @@ user_customizations() {
(mkdir -p "$(dirname "$user_archsetup_dir")" && \
git clone --depth 1 https://git.cjennings.net/archsetup.git "$user_archsetup_dir" && \
chown -R "$username": "/home/$username/code") \
- >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ >> "$logfile" 2>&1 || error_warn "$action" "$?"
# Update dotfiles_dir to point to user-accessible location
dotfiles_dir="$user_archsetup_dir/dotfiles"
action="linking dotfiles into place" && display "task" "$action"
(cd "$dotfiles_dir" && stow --target="/home/$username" --no-folding --adopt system \
- >> "$logfile" 2>&1 ) || error "error" "$action" "$?"
+ >> "$logfile" 2>&1 ) || error_warn "$action" "$?"
# install desktop-file-utils before updating database (provides update-desktop-database)
pacman_install desktop-file-utils
action="updating desktop database" && display "task" "$action"
(sudo -u "$username" update-desktop-database "/home/$username/.local/share/applications" \
- >> "$logfile" 2>&1 ) || error "error" "$action" "$?"
+ >> "$logfile" 2>&1 ) || error_warn "$action" "$?"
action="restoring dotfile versions" && display "task" "$action"
(cd "$dotfiles_dir" && git config --global --add safe.directory "$user_archsetup_dir" && \
- git restore . >> "$logfile" 2>&1 ) || error "error" "$action" "$?"
+ git restore . >> "$logfile" 2>&1 ) || error_warn "$action" "$?"
action="creating common directories" && display "task" "$action"
# Create default directories and grant permissions
@@ -763,7 +773,7 @@ user_customizations() {
}
### AUR Installer
-aur_installer () {
+aur_installer() {
display "title" "AUR Installer"
yay_repo="https://aur.archlinux.org/yay.git"
@@ -771,16 +781,16 @@ aur_installer () {
display "task" "fetching source code for yay"
if ! (sudo -u "$username" git clone --depth 1 "$yay_repo" "$build_dir" >> "$logfile" 2>&1); then
- error "error" "cloning source code for yay - directory may exist, removing and retrying" "$?"
+ error_warn "cloning source code for yay - directory may exist, removing and retrying" "$?"
(rm -rf "$build_dir" >> "$logfile" 2>&1) || \
- error "crash" "removing existing directory for yay" "$?"
+ error_fatal "removing existing directory for yay" "$?"
(sudo -u "$username" git clone --depth 1 "$yay_repo" "$build_dir" >> "$logfile" 2>&1) || \
- error "crash" "re-cloning source code for yay after cleanup" "$?"
+ error_fatal "re-cloning source code for yay after cleanup" "$?"
fi
action="packaging and installing yay"; display "task" "$action"
(cd "$build_dir" && sudo -u "$username" makepkg --noconfirm -si >> "$logfile" 2>&1) || \
- error "crash" "$action" "$?"
+ error_fatal "$action" "$?"
}
### Essential Services
@@ -792,16 +802,16 @@ essential_services() {
display "subtitle" "Randomness"
pacman_install rng-tools
action="enabling rngd service" && display "task" "$action"
- systemctl enable rngd >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ systemctl enable rngd >> "$logfile" 2>&1 || error_warn "$action" "$?"
action="starting rngd service" && display "task" "$action"
- systemctl start rngd >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ systemctl start rngd >> "$logfile" 2>&1 || error_warn "$action" "$?"
# Networking
display "subtitle" "Networking"
pacman_install networkmanager
action="enabling NetworkManager" && display "task" "$action"
- systemctl enable NetworkManager.service >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ systemctl enable NetworkManager.service >> "$logfile" 2>&1 || error_warn "$action" "$?"
action="configuring MAC address randomization" && display "task" "$action"
mkdir -p /etc/NetworkManager/conf.d
@@ -844,27 +854,27 @@ EOF
# (127.0.0.53) may be the cause. Fix: configure Docker to use direct DNS, or
# disable systemd-resolved and use /etc/resolv.conf directly. (2026-01-18)
action="enabling systemd-resolved" && display "task" "$action"
- systemctl enable systemd-resolved >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ systemctl enable systemd-resolved >> "$logfile" 2>&1 || error_warn "$action" "$?"
# Create resolv.conf symlink to systemd-resolved
action="linking resolv.conf to systemd-resolved" && display "task" "$action"
- ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf >> "$logfile" 2>&1 || error_warn "$action" "$?"
# Power
display "subtitle" "Power"
pacman_install upower
action="enabling upower service" && display "task" "$action"
- systemctl enable upower >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ systemctl enable upower >> "$logfile" 2>&1 || error_warn "$action" "$?"
# Secure Shell
display "subtitle" "Secure Shell"
pacman_install openssh
action="enabling the openssh service to run at boot" && display "task" "$action"
- systemctl enable sshd >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ systemctl enable sshd >> "$logfile" 2>&1 || error_warn "$action" "$?"
action="starting the openssh service" && display "task" "$action"
- systemctl start sshd >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ systemctl start sshd >> "$logfile" 2>&1 || error_warn "$action" "$?"
# SSH Brute Force Protection
@@ -890,15 +900,15 @@ bantime = 1h
EOF
action="enabling fail2ban service" && display "task" "$action"
- systemctl enable fail2ban >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ systemctl enable fail2ban >> "$logfile" 2>&1 || error_warn "$action" "$?"
action="starting fail2ban service" && display "task" "$action"
- systemctl start fail2ban >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ systemctl start fail2ban >> "$logfile" 2>&1 || error_warn "$action" "$?"
display "subtitle" "Firewall"
pacman_install ufw
action="configuring ufw to deny by default" && display "task" "$action"
- ufw default deny incoming >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ ufw default deny incoming >> "$logfile" 2>&1 || error_warn "$action" "$?"
# Firewall rules - only open ports for services we actually run
for protocol in \
@@ -918,23 +928,23 @@ EOF
# 5353/tcp,udp: mDNS/Avahi local network discovery
# transmission: BitTorrent client
action="adding ufw rule to allow $protocol" && display "task" "$action"
- (ufw allow "$protocol" >> "$logfile" 2>&1) || error "error" "$action" "$?"
+ (ufw allow "$protocol" >> "$logfile" 2>&1) || error_warn "$action" "$?"
done
action="rate-limiting SSH to protect from brute force attacks" && display "task" "$action"
- (ufw limit 22/tcp >> "$logfile" 2>&1) || error "error" "$action" "$?"
+ (ufw limit 22/tcp >> "$logfile" 2>&1) || error_warn "$action" "$?"
action="enabling firewall" && display "task" "$action"
- ufw --force enable >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ ufw --force enable >> "$logfile" 2>&1 || error_warn "$action" "$?"
action="enabling firewall service to launch on boot" && display "task" "$action"
- systemctl enable ufw.service >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ systemctl enable ufw.service >> "$logfile" 2>&1 || error_warn "$action" "$?"
# Verify firewall is actually active
action="verifying firewall is active" && display "task" "$action"
if ! ufw status | grep -q "Status: active"; then
error_messages=("FIREWALL NOT ACTIVE - run: sudo ufw enable" "${error_messages[@]}")
- error "error" "$action" "1"
+ error_warn "$action" "1"
fi
# Service Discovery
@@ -948,12 +958,12 @@ EOF
else
pacman_install avahi # service discovery on a local network using mdns
action="enabling avahi for mDNS discovery" && display "task" "$action"
- systemctl enable avahi-daemon.service >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ systemctl enable avahi-daemon.service >> "$logfile" 2>&1 || error_warn "$action" "$?"
fi
pacman_install geoclue # geolocation service for location-aware apps
action="enabling geoclue geolocation service" && display "task" "$action"
- systemctl enable geoclue.service >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ systemctl enable geoclue.service >> "$logfile" 2>&1 || error_warn "$action" "$?"
# Fix dbus-broker race condition with sysusers (geoclue user must exist before dbus parses service files)
action="configuring dbus-broker to wait for sysusers" && display "task" "$action"
@@ -968,17 +978,17 @@ EOF
display "subtitle" "Job Scheduling"
pacman_install cronie
action="enabling cronie to launch at boot" && display "task" "$action"
- systemctl enable cronie >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ systemctl enable cronie >> "$logfile" 2>&1 || error_warn "$action" "$?"
pacman_install at
action="enabling the batch delayed command scheduler" && display "task" "$action"
- systemctl enable atd >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ systemctl enable atd >> "$logfile" 2>&1 || error_warn "$action" "$?"
# Package Repository Cache Maintenance
display "subtitle" "Package Repository Cache Maintenance"
pacman_install pacman-contrib
action="enabling the package cache cleanup timer" && display "task" "$action"
- systemctl enable --now paccache.timer >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ systemctl enable --now paccache.timer >> "$logfile" 2>&1 || error_warn "$action" "$?"
action="configuring paccache to keep 3 versions" && display "task" "$action"
sed -i 's/^PACCACHE_ARGS=.*/PACCACHE_ARGS=-k3/' /etc/conf.d/pacman-contrib
@@ -1164,12 +1174,12 @@ WantedBy=timers.target
EOF
action="enabling sanoid timer" && display "task" "$action"
- systemctl enable sanoid.timer >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ systemctl enable sanoid.timer >> "$logfile" 2>&1 || error_warn "$action" "$?"
action="enabling weekly ZFS scrub" && display "task" "$action"
# Get pool name dynamically (usually zroot)
zfs_pool=$(zpool list -H -o name | head -1)
- systemctl enable "zfs-scrub-weekly@${zfs_pool}.timer" >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ systemctl enable "zfs-scrub-weekly@${zfs_pool}.timer" >> "$logfile" 2>&1 || error_warn "$action" "$?"
# Note: zfs-replicate.timer is NOT enabled automatically
# User must set up SSH key auth to TrueNAS first, then run:
@@ -1182,19 +1192,19 @@ EOF
aur_install timeshift-autosnap
pacman_install grub-btrfs
action="enabling snapshot boot menu updates" && display "task" "$action"
- systemctl enable grub-btrfsd >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ systemctl enable grub-btrfsd >> "$logfile" 2>&1 || error_warn "$action" "$?"
action="starting snapshot boot menu updates" && display "task" "$action"
# starting and stopping service to generate the grub-btrfs config
- systemctl start grub-btrfsd >> "$logfile" 2>&1 || error "error" "$action" "$?"
- systemctl stop grub-btrfsd >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ systemctl start grub-btrfsd >> "$logfile" 2>&1 || error_warn "$action" "$?"
+ systemctl stop grub-btrfsd >> "$logfile" 2>&1 || error_warn "$action" "$?"
# edit grub-btrfs config for timeshift auto snapshot support
sed -i \
's|ExecStart=/usr/bin/grub-btrfsd --syslog /.snapshots|ExecStart=/usr/bin/grub-btrfsd --syslog --timeshift-auto|' \
/etc/systemd/system/grub-btrfsd.service
action="regenerating boot menu" && display "task" "$action"
- grub-mkconfig -o /boot/grub/grub.cfg >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ grub-mkconfig -o /boot/grub/grub.cfg >> "$logfile" 2>&1 || error_warn "$action" "$?"
else
# ext4 or other filesystem - no automatic snapshots
display "task" "ext4/other filesystem detected - skipping snapshot tools"
@@ -1224,7 +1234,7 @@ xorg() {
EndSection
EOF
action="configuring xorg server" && display "task" "$action"
- chmod 644 /etc/X11/xorg.conf.d/00-no-vt-or-zap.conf >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ chmod 644 /etc/X11/xorg.conf.d/00-no-vt-or-zap.conf >> "$logfile" 2>&1 || error_warn "$action" "$?"
# Install GPU-specific drivers
install_gpu_drivers
@@ -1368,7 +1378,7 @@ desktop_environment() {
pacman_install "$software"
done
action="enabling bluetooth to launch at boot" && display "task" "$action"
- systemctl enable bluetooth.service >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ systemctl enable bluetooth.service >> "$logfile" 2>&1 || error_warn "$action" "$?"
# Command Line Utilities
@@ -1455,11 +1465,11 @@ desktop_environment() {
pacman_install system-config-printer # graphical printer config tool
action="enabling printing service to launch at boot" && display "task" "$action"
- (systemctl enable cups.service >> "$logfile" 2>&1) || error "error" "$action" "$?"
+ (systemctl enable cups.service >> "$logfile" 2>&1) || error_warn "$action" "$?"
}
### Developer Workstation
-developer_workstation () {
+developer_workstation() {
action="Developer Workstation" && display "title" "$action"
@@ -1499,7 +1509,7 @@ developer_workstation () {
# AI coding assistant (native install to ~/.local/bin)
action="installing claude-code via native installer" && display "task" "$action"
(sudo -u "$username" bash -c 'curl -fsSL https://claude.ai/install.sh | sh' >> "$logfile" 2>&1) || \
- error "error" "$action" "$?"
+ error_warn "$action" "$?"
# HTML
pacman_install tidy # HTML formatter
@@ -1548,10 +1558,10 @@ developer_workstation () {
emacs_dir="/home/$username/.emacs.d"
if [ -d "$emacs_dir" ]; then
(cd "$emacs_dir" && sudo -u "$username" git pull --recurse-submodules >> "$logfile" 2>&1) || \
- error "error" "$action" "$?"
+ error_warn "$action" "$?"
else
(sudo -u "$username" git clone --recurse-submodules "$dotemacs_repo" "$emacs_dir" >> \
- "$logfile" 2>&1) || error "error" "$action" "$?"
+ "$logfile" 2>&1) || error_warn "$action" "$?"
fi
action="Android Utilities" && display "subtitle" "$action"
@@ -1563,7 +1573,7 @@ developer_workstation () {
pacman_install tailscale # mesh VPN - run 'tailscale up' to authenticate
action="enabling tailscale service" && display "task" "$action"
- systemctl enable tailscaled >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ systemctl enable tailscaled >> "$logfile" 2>&1 || error_warn "$action" "$?"
action="DevOps Utilities" && display "subtitle" "$action"
@@ -1582,7 +1592,7 @@ developer_workstation () {
pacman_install docker
pacman_install docker-compose
action="adding user to docker group" && display "task" "$action"
- (gpasswd -a "$username" docker >> "$logfile" 2>&1) || error "error" "$action" "$?"
+ (gpasswd -a "$username" docker >> "$logfile" 2>&1) || error_warn "$action" "$?"
if is_zfs_root; then
action="configuring docker to use ZFS storage driver" && display "task" "$action"
mkdir -p /etc/docker
@@ -1593,7 +1603,7 @@ developer_workstation () {
EOF
fi
action="enabling docker service to launch on boot" && display "task" "$action"
- systemctl enable docker.service >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ systemctl enable docker.service >> "$logfile" 2>&1 || error_warn "$action" "$?"
}
### Supplemental Software
@@ -1691,7 +1701,7 @@ supplemental_software() {
# working around an temp integ issue with python-lyricsgenius expiration date
action="prep to workaround tidal-dl issue" && display "task" "$action"
- yay -S --noconfirm --mflags --skipinteg python-lyricsgenius >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ yay -S --noconfirm --mflags --skipinteg python-lyricsgenius >> "$logfile" 2>&1 || error_warn "$action" "$?"
aur_install tidal-dl # tidal-dl:tidal as yt-dlp:youtube
}
@@ -1711,11 +1721,11 @@ boot_ux() {
fi
action="removing distro and date/time from initial screen" && display "task" "$action"
- (cat /dev/null >/etc/issue) || error "error" "$action" "$?"
+ (cat /dev/null >/etc/issue) || error_warn "$action" "$?"
action="preventing kernel messages on the console" && display "task" "$action"
(echo "kernel.printk = 3 3 3 3" >/etc/sysctl.d/20-quiet-printk.conf) || \
- error "error" "$action" "$?"
+ error_warn "$action" "$?"
action="configuring console font" && display "task" "$action"
if grep -q "^FONT=" /etc/vconsole.conf 2>/dev/null; then
@@ -1728,8 +1738,8 @@ boot_ux() {
# ZFS initramfs hook is busybox-based and incompatible with systemd hook
if ! is_zfs_root; then
action="delegating fsck messages from udev to systemd" && display "task" "$action"
- sed -i '/^HOOKS=/ s/\budev\b/systemd/' /etc/mkinitcpio.conf || error "error" "$action" "$?"
- mkinitcpio -P >> "$logfile" 2>&1 || error "error" "running mkinitcpio -P to silence fsck messages" "$?"
+ sed -i '/^HOOKS=/ s/\budev\b/systemd/' /etc/mkinitcpio.conf || error_warn "$action" "$?"
+ mkinitcpio -P >> "$logfile" 2>&1 || error_warn "running mkinitcpio -P to silence fsck messages" "$?"
fi
action="configuring quiet fsck output" && display "task" "$action"
@@ -1751,7 +1761,7 @@ EOF
configure_autologin
action="silencing the unneeded and chatty watchdog module" && display "task" "$action"
- echo "blacklist iTCO_wdt" >/etc/modprobe.d/nowatchdog.conf || error "error" "$action" "$?"
+ echo "blacklist iTCO_wdt" >/etc/modprobe.d/nowatchdog.conf || error_warn "$action" "$?"
action="configuring journald retention" && display "task" "$action"
mkdir -p /etc/systemd/journald.conf.d
@@ -1773,7 +1783,7 @@ EOF
sed -i 's/.*GRUB_GFXMODE=auto/GRUB_GFXMODE=1024x768/' /etc/default/grub
sed -i "s/.*GRUB_RECORDFAIL_TIMEOUT=.*/GRUB_RECORDFAIL_TIMEOUT=2/g" /etc/default/grub
sed -i "s/.*GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT=\"rw loglevel=2 rd.systemd.show_status=auto rd.udev.log_level=2 nvme.noacpi=1 mem_sleep_default=deep nowatchdog random.trust_cpu=off quiet splash\"/g" /etc/default/grub
- grub-mkconfig -o /boot/grub/grub.cfg >> "$logfile" 2>&1 || error "error" "generating grub config" "$?"
+ grub-mkconfig -o /boot/grub/grub.cfg >> "$logfile" 2>&1 || error_warn "generating grub config" "$?"
fi
}
@@ -1784,13 +1794,13 @@ outro() {
action="Cleanup" && display "title" "$action"
action="forcing user password change on first login" && display "task" "$action"
- chage -d 0 "$username" >> "$logfile" 2>&1 || error "error" "$action" "$?"
+ chage -d 0 "$username" >> "$logfile" 2>&1 || error_warn "$action" "$?"
display "subtitle" "Statistics"
action="identifying newly installed packages" && display "task" "$action"
- pacman -Q > "$packages_after" || error "error" "$action" "$?"
+ pacman -Q > "$packages_after" || error_warn "$action" "$?"
(comm -13 --nocheck-order "$packages_before" "$packages_after" > "$archsetup_packages") || \
- error "error" "$action" "$?"
+ error_warn "$action" "$?"
action="comparing timestamps" && display "task" "$action"
ENDTIME=$(date +%s)