#!/bin/bash # Function to check if a package is installed is_installed() { pacman -Qi "$1" &> /dev/null } # Function to check if a package is installed is_group_installed() { pacman -Qg "$1" &> /dev/null } # Function to install packages if not already installed install_packages() { local packages=("$@") local to_install=() for pkg in "${packages[@]}"; do if ! is_installed "$pkg" && ! is_group_installed "$pkg"; then to_install+=("$pkg") fi done if [ ${#to_install[@]} -ne 0 ]; then echo "Installing: ${to_install[*]}" yay -S --noconfirm --answerdiff=None --answeredit=None --answerclean=None "${to_install[@]}" fi } # Function to remove pacman/AUR packages if installed remove_packages() { local packages=("$@") local to_remove=() for pkg in "${packages[@]}"; do if is_installed "$pkg"; then to_remove+=("$pkg") fi done if [ ${#to_remove[@]} -ne 0 ]; then echo "Removing: ${to_remove[*]}" sudo pacman -Rns --noconfirm "${to_remove[@]}" fi } # Function to enable systemd services if not already enabled enable_services() { for service in "$@"; do if ! systemctl is-enabled "$service" &> /dev/null; then echo "Enabling $service..." sudo systemctl enable "$service" else echo "$service is already enabled." fi done } # Output of the last update's pacman -Su, written by updates.d/10-pacman.sh PACMAN_UPDATE_LOG="$HOME/.local/state/miniserver/pacman-update.log" # True if the last update rebuilt the initramfs and mkinitcpio reported a # failure. Rebooting then can leave the machine unbootable. initramfs_build_failed() { [ -f "$PACMAN_UPDATE_LOG" ] || return 1 grep -q "Updating linux initcpios" "$PACMAN_UPDATE_LOG" || return 1 grep -q "==> ERROR" "$PACMAN_UPDATE_LOG" || ! grep -q "Image generation successful" "$PACMAN_UPDATE_LOG" } # Install a script atomically (copy to a temp file, then rename over the target) # so a copy of it that is running right now keeps reading the old file install_script() { local tmp tmp="$(mktemp "$2.XXXXXX")" && cp "$1" "$tmp" && chmod 755 "$tmp" && mv -f "$tmp" "$2" } # Start Cockpit. Safe to re-run: does nothing once set up. The cockpit package # itself comes from packages.conf; its firewall port is in firewall.conf. setup_cockpit() { if ! systemctl is-enabled --quiet cockpit.socket || ! systemctl is-active --quiet cockpit.socket; then echo "Enabling Cockpit..." sudo systemctl enable --now cockpit.socket fi } # Allow the services and ports in firewall.conf through firewalld's default # zone, then make sure firewalld is running. Only adds rules, never removes # them, so rules added by hand or by sibling projects stay. Safe to re-run. setup_firewall() { command -v firewall-offline-cmd &> /dev/null || return 0 source "$HOME/.local/share/MiniServer/firewall.conf" # firewall-cmd only works while firewalld is running; before that, write the # permanent config directly so SSH is allowed before the firewall comes up local fw running=0 changed=0 svc port if systemctl is-active --quiet firewalld; then running=1 fw=(sudo firewall-cmd --permanent) else fw=(sudo firewall-offline-cmd) fi # Keep SSH reachable if sshd listens on a port other than 22 local ports=("${FIREWALL_PORTS[@]}") if command -v sshd &> /dev/null; then for port in $(sudo sshd -T 2> /dev/null | awk '$1 == "port" && $2 != 22 { print $2 }'); do ports+=("$port/tcp") done fi for svc in "${FIREWALL_SERVICES[@]}"; do if ! "${fw[@]}" --query-service="$svc" &> /dev/null; then echo "Firewall: allowing $svc" "${fw[@]}" --add-service="$svc" changed=1 fi done for port in "${ports[@]}"; do if ! "${fw[@]}" --query-port="$port" &> /dev/null; then echo "Firewall: allowing $port" "${fw[@]}" --add-port="$port" changed=1 fi done if (( running )); then if (( changed )); then sudo firewall-cmd --reload fi else echo "Starting firewalld..." sudo systemctl enable --now firewalld # Docker sets up its firewalld zone only when it starts if systemctl is-active --quiet docker; then echo "Docker started before firewalld. Restart it (sudo systemctl restart docker) or reboot so its containers' ports work through the firewall." fi fi }