diff options
| -rwxr-xr-x | archsetup | 306 | ||||
| -rw-r--r-- | archsetup.conf.example | 14 |
2 files changed, 171 insertions, 149 deletions
@@ -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) diff --git a/archsetup.conf.example b/archsetup.conf.example index 969079a..4d03fe1 100644 --- a/archsetup.conf.example +++ b/archsetup.conf.example @@ -15,7 +15,7 @@ # Username for the primary user account (default: cjennings) USERNAME=cjennings -# Initial password - should be changed on first login (default: welcome) +# Initial password - CHANGE ON FIRST LOGIN (default: welcome) PASSWORD=welcome ############################# @@ -30,3 +30,15 @@ PASSWORD=welcome # Skip GPU driver auto-detection and installation (default: no) # Set to "yes" if you want to handle GPU drivers manually #NO_GPU_DRIVERS=no + +############################# +# Git Repositories +############################# +# Override these to use your own forks of suckless tools and dotfiles. +# Defaults point to git.cjennings.net - fork these for your own setup. + +#DWM_REPO=https://github.com/yourusername/dwm.git +#DMENU_REPO=https://github.com/yourusername/dmenu.git +#ST_REPO=https://github.com/yourusername/st.git +#SLOCK_REPO=https://github.com/yourusername/slock.git +#DOTEMACS_REPO=https://github.com/yourusername/dotemacs.git |
