@@ -222,11 +222,13 @@ END_EXCLUDES
222222
223223# =================================================================
224224# SCRIPT INITIALIZATION & SETUP
225- # v0.12 - 2025.08.10
225+ # v0.13 - 2025.08.10
226226# =================================================================
227227set -Euo pipefail
228228umask 077
229229
230+ HOSTNAME=$( hostname -s)
231+
230232# Check if the script is being run as root
231233if (( EUID != 0 )) ; then
232234 echo " ❌ This script must be run as root or with sudo." >&2
@@ -251,7 +253,7 @@ if [ -f "$CONFIG_FILE" ]; then
251253 fi
252254
253255 if $in_exclude_block ; then
254- [[ ! " $line " =~ ^\s * # |^\s*$ ]] && echo "$line" >> "$EXCLUDE_FILE_TMP"
256+ [[ ! " $line " =~ ^([[:space:]] * # |[[:space:]]*$) ]] && echo "$line" >> "$EXCLUDE_FILE_TMP"
255257 continue
256258 fi
257259
@@ -383,34 +385,54 @@ cleanup() {
383385# PRE-FLIGHT CHECKS & SETUP
384386# =================================================================
385387
388+ run_preflight_checks () {
389+ # This function runs all checks. If 'true' is passed as an argument,
390+ # it runs in a verbose test mode instead of sending notifications.
391+ local test_mode=${1:- false}
392+ local check_failed=false
393+
394+ # 1. Check for required commands
395+ if [[ " $test_mode " == " true" ]]; then echo " --- Checking required commands..." ; fi
396+ for cmd in " ${REQUIRED_CMDS[@]} " ; do
397+ if ! command -v " $cmd " & > /dev/null; then
398+ echo " ❌ FATAL: Required command '$cmd ' not found. Please install it." >&2
399+ check_failed=true
400+ fi
401+ done
402+ if [[ " $check_failed " == " true" ]]; then exit 10; fi
403+ if [[ " $test_mode " == " true" ]]; then echo " ✅ All required commands are present." ; fi
404+
405+ # 2. Check SSH connectivity
406+ if [[ " $test_mode " == " true" ]]; then echo " --- Checking SSH connectivity..." ; fi
407+ if ! ssh ${SSH_OPTS_STR:- } -o BatchMode=yes -o ConnectTimeout=10 " $HETZNER_BOX " ' exit' 2> /dev/null; then
408+ local err_msg=" Unable to SSH into $HETZNER_BOX . Check keys and connectivity."
409+ if [[ " $test_mode " == " true" ]]; then echo " ❌ $err_msg " ; else send_notification " ❌ SSH FAILED: ${HOSTNAME} " " x" " ${NTFY_PRIORITY_FAILURE} " " failure" " $err_msg " ; fi
410+ exit 6
411+ fi
412+ if [[ " $test_mode " == " true" ]]; then echo " ✅ SSH connectivity OK." ; fi
413+
414+ # 3. Check backup directories
415+ if [[ " $test_mode " == " true" ]]; then echo " --- Checking backup directories..." ; fi
416+ for dir in $BACKUP_DIRS ; do
417+ if [[ ! -d " $dir " ]] || [[ " $dir " != * / ]]; then
418+ local err_msg=" A directory in BACKUP_DIRS ('$dir ') must exist and end with a trailing slash ('/')."
419+ if [[ " $test_mode " == " true" ]]; then echo " ❌ FATAL: $err_msg " ; else send_notification " ❌ Backup FAILED: ${HOSTNAME} " " x" " ${NTFY_PRIORITY_FAILURE} " " failure" " FATAL: $err_msg " ; fi
420+ exit 2
421+ fi
422+ done
423+ if [[ " $test_mode " == " true" ]]; then echo " ✅ All backup directories are valid." ; fi
424+ }
425+
386426trap cleanup EXIT
387427trap ' send_notification "❌ Backup Crashed: ${HOSTNAME}" "x" "${NTFY_PRIORITY_FAILURE}" "failure" "Backup script terminated unexpectedly. Check log: ${LOG_FILE:-/dev/null}"' ERR
388428
389429REQUIRED_CMDS=(rsync curl flock hostname date stat mv touch awk numfmt grep printf nice ionice sed mktemp basename)
390- for cmd in " ${REQUIRED_CMDS[@]} " ; do
391- if ! command -v " $cmd " & > /dev/null; then
392- echo " FATAL: Required command '$cmd ' not found. Please install it." >&2 ; trap - ERR; exit 10
393- fi
394- done
395-
396- if ! ssh ${SSH_OPTS_STR:- } -o BatchMode=yes -o ConnectTimeout=10 " $HETZNER_BOX " ' exit' 2> /dev/null; then
397- send_notification " ❌ SSH FAILED: ${HOSTNAME} " " x" " ${NTFY_PRIORITY_FAILURE} " " failure" " Unable to SSH into $HETZNER_BOX . Check keys and connectivity."
398- trap - ERR; exit 6
399- fi
400-
401- for dir in $BACKUP_DIRS ; do
402- if [[ ! -d " $dir " ]] || [[ " $dir " != * / ]]; then
403- send_notification " ❌ Backup FAILED: ${HOSTNAME} " " x" " ${NTFY_PRIORITY_FAILURE} " " failure" " FATAL: A directory in BACKUP_DIRS ('$dir ') must exist and end with a trailing slash ('/')."
404- trap - ERR; exit 2
405- fi
406- done
407430
408431
409432# =================================================================
410433# SCRIPT EXECUTION
411434# =================================================================
412435
413- HOSTNAME= $( hostname -s)
414436VERBOSE_MODE=false
415437if [[ " ${1:- } " == " --verbose" ]]; then
416438 VERBOSE_MODE=true; shift
@@ -468,6 +490,14 @@ if [[ "${1:-}" ]]; then
468490 fi
469491 fi
470492 exit 0 ;;
493+ --test)
494+ echo " --- TEST MODE ACTIVATED ---"
495+ # Call the pre-flight checks in test mode
496+ run_preflight_checks true
497+ echo " ---------------------------"
498+ echo " ✅ All configuration checks passed."
499+ exit 0
500+ ;;
471501 esac
472502fi
473503
0 commit comments