@@ -222,7 +222,7 @@ END_EXCLUDES
222
222
223
223
# =================================================================
224
224
# SCRIPT INITIALIZATION & SETUP
225
- # v0.9 - 2025.08.09
225
+ # v0.10 - 2025.08.09
226
226
# =================================================================
227
227
set -Euo pipefail
228
228
umask 077
@@ -330,8 +330,12 @@ send_notification() {
330
330
331
331
run_integrity_check () {
332
332
local rsync_check_opts=(-ainc -c --delete --exclude-from=" $EXCLUDE_FILE_TMP " --out-format=" %n" -e " ssh ${SSH_OPTS_STR:- } " )
333
- # shellcheck disable=SC2086
334
- LC_ALL=C rsync " ${rsync_check_opts[@]} " $BACKUP_DIRS " $REMOTE_TARGET " 2>> " ${LOG_FILE:-/ dev/ null} "
333
+
334
+ for dir in $BACKUP_DIRS ; do
335
+ local remote_subdir=" ${REMOTE_TARGET} /$( basename " $dir " ) /"
336
+ # shellcheck disable=SC2086
337
+ LC_ALL=C rsync " ${rsync_check_opts[@]} " " $dir " " $remote_subdir " 2>> " ${LOG_FILE:-/ dev/ null} "
338
+ done
335
339
}
336
340
337
341
parse_stat () {
@@ -415,15 +419,24 @@ if [[ "${1:-}" ]]; then
415
419
--dry-run)
416
420
trap - ERR
417
421
echo " --- DRY RUN MODE ACTIVATED ---"
418
- # shellcheck disable=SC2086
419
- if ! rsync " ${RSYNC_BASE_OPTS[@]} " --dry-run --info=progress2 $BACKUP_DIRS " $REMOTE_TARGET " ; then
420
- echo " "
421
- echo " ❌ Dry run FAILED. See the rsync error message above for details."
422
- exit 1
422
+ DRY_RUN_FAILED=false
423
+ for dir in $BACKUP_DIRS ; do
424
+ remote_subdir=" ${REMOTE_TARGET} /$( basename " $dir " ) /"
425
+ echo " --- Checking dry run for: $dir -> $remote_subdir "
426
+ # shellcheck disable=SC2086
427
+ if ! rsync " ${RSYNC_BASE_OPTS[@]} " --dry-run --info=progress2 " $dir " " $remote_subdir " ; then
428
+ DRY_RUN_FAILED=true
429
+ fi
430
+ done
431
+
432
+ if [[ " $DRY_RUN_FAILED " == " true" ]]; then
433
+ echo " "
434
+ echo " ❌ Dry run FAILED for one or more directories. See the rsync error messages above for details."
435
+ exit 1
423
436
fi
424
437
echo " --- DRY RUN COMPLETED ---" ; exit 0 ;;
438
+
425
439
--checksum | --summary)
426
- # Both modes use the same check, just with different reporting
427
440
echo " --- INTEGRITY CHECK MODE ACTIVATED ---"
428
441
echo " Calculating differences..."
429
442
FILE_DISCREPANCIES=$( run_integrity_check)
462
475
echo " ============================================================" >> " $LOG_FILE "
463
476
log_message " Starting rsync backup..."
464
477
478
+ # --- Execute Backup for Each Directory ---
465
479
START_TIME= $( date +%s)
480
+ success_dirs= ()
481
+ failed_dirs= ()
482
+ overall_exit_code= 0
483
+ full_rsync_output= " "
484
+
485
+ for dir in $BACKUP_DIRS ; do
486
+ log_message " Backing up directory: $dir "
487
+
488
+ remote_subdir=" ${REMOTE_TARGET} /$( basename " $dir " ) /"
489
+
490
+ RSYNC_LOG_TMP=$( mktemp)
491
+ RSYNC_EXIT_CODE=0
492
+ RSYNC_OPTS=(" ${RSYNC_BASE_OPTS[@]} " )
493
+
494
+ if [[ " $VERBOSE_MODE " == " true" ]]; then
495
+ RSYNC_OPTS+=(--info=stats2,progress2)
496
+ # shellcheck disable=SC2086
497
+ nice -n 19 ionice -c 3 rsync " ${RSYNC_OPTS[@]} " " $dir " " $remote_subdir " 2>&1 | tee " $RSYNC_LOG_TMP "
498
+ RSYNC_EXIT_CODE=${PIPESTATUS[0]}
499
+ else
500
+ RSYNC_OPTS+=(--info=stats2)
501
+ # shellcheck disable=SC2086
502
+ nice -n 19 ionice -c 3 rsync " ${RSYNC_OPTS[@]} " " $dir " " $remote_subdir " > " $RSYNC_LOG_TMP " 2>&1 || RSYNC_EXIT_CODE=$?
503
+ fi
466
504
467
- RSYNC_LOG_TMP= $( mktemp )
468
- RSYNC_EXIT_CODE = 0
469
- RSYNC_OPTS = ( " ${RSYNC_BASE_OPTS[@]} " )
505
+ cat " $ RSYNC_LOG_TMP" >> " $LOG_FILE "
506
+ full_rsync_output+= $' \n ' " $( < " $RSYNC_LOG_TMP " ) "
507
+ rm -f " $RSYNC_LOG_TMP "
470
508
471
- if [[ " $VERBOSE_MODE " == " true" ]]; then
472
- RSYNC_OPTS+=(--info=stats2,progress2)
473
- # shellcheck disable=SC2086
474
- nice -n 19 ionice -c 3 rsync " ${RSYNC_OPTS[@]} " $BACKUP_DIRS " $REMOTE_TARGET " 2>&1 | tee " $RSYNC_LOG_TMP "
475
- RSYNC_EXIT_CODE=${PIPESTATUS[0]}
476
- else
477
- RSYNC_OPTS+=(--info=stats2)
478
- # shellcheck disable=SC2086
479
- nice -n 19 ionice -c 3 rsync " ${RSYNC_OPTS[@]} " $BACKUP_DIRS " $REMOTE_TARGET " > " $RSYNC_LOG_TMP " 2>&1 || RSYNC_EXIT_CODE=$?
480
- fi
509
+ if [[ $RSYNC_EXIT_CODE -eq 0 || $RSYNC_EXIT_CODE -eq 24 ]]; then
510
+ success_dirs+=(" $( basename " $dir " ) " )
511
+ if [[ $RSYNC_EXIT_CODE -eq 24 ]]; then
512
+ log_message " WARNING for $dir : rsync completed with code 24 (some source files vanished)."
513
+ overall_exit_code=24 # Mark the overall run as a warning
514
+ fi
515
+ else
516
+ failed_dirs+=(" $( basename " $dir " ) " )
517
+ log_message " FAILED for $dir : rsync exited with code: $RSYNC_EXIT_CODE ."
518
+ overall_exit_code=1 # Mark the overall run as a failure
519
+ fi
520
+ done
481
521
482
522
END_TIME= $( date +%s)
483
523
DURATION= $(( END_TIME - START_TIME))
484
-
485
- cat " $RSYNC_LOG_TMP " >> " $LOG_FILE "
486
- RSYNC_OUTPUT= $( < " $RSYNC_LOG_TMP " )
487
-
488
524
trap - ERR
489
525
490
- case $RSYNC_EXIT_CODE in
491
- 0)
492
- BACKUP_STATS=$( format_backup_stats " $RSYNC_OUTPUT " )
493
- SUCCESS_MSG=$( printf " %s\n\nDuration: %dm %ds" " $BACKUP_STATS " $(( DURATION / 60 )) $(( DURATION % 60 )) )
494
- log_message " SUCCESS: rsync completed."
495
- send_notification " ✅ Backup SUCCESS: ${HOSTNAME} " " white_check_mark" " ${NTFY_PRIORITY_SUCCESS} " " success" " $SUCCESS_MSG " ;;
496
- 24)
497
- BACKUP_STATS=$( format_backup_stats " $RSYNC_OUTPUT " )
498
- WARN_MSG=$( printf " rsync completed with a warning (code 24).\nSome source files vanished during transfer.\n\n%s\n\nDuration: %dm %ds" " $BACKUP_STATS " $(( DURATION / 60 )) $(( DURATION % 60 )) )
499
- log_message " WARNING: rsync completed with code 24 (some source files vanished)."
500
- send_notification " ⚠️ Backup Warning: ${HOSTNAME} " " warning" " ${NTFY_PRIORITY_WARNING} " " warning" " $WARN_MSG " ;;
501
- * )
502
- FAIL_MSG=$( printf " rsync failed on ${HOSTNAME} with exit code ${RSYNC_EXIT_CODE} . Check log for details.\n\nDuration: %dm %ds" $(( DURATION / 60 )) $(( DURATION % 60 )) )
503
- log_message " FAILED: rsync exited with code: $RSYNC_EXIT_CODE ."
504
- send_notification " ❌ Backup FAILED: ${HOSTNAME} " " x" " ${NTFY_PRIORITY_FAILURE} " " failure" " $FAIL_MSG " ;;
505
- esac
526
+ # --- Final Notification Logic ---
527
+ BACKUP_STATS= $( format_backup_stats " $full_rsync_output " )
528
+ FINAL_MESSAGE= $( printf " %s\n\nDuration: %dm %ds" " $BACKUP_STATS " $(( DURATION / 60 )) $(( DURATION % 60 )) )
529
+
530
+ if [[ ${# failed_dirs[@]} -eq 0 ]]; then
531
+ log_message " SUCCESS: All backups completed."
532
+ if [[ $overall_exit_code -eq 24 ]]; then
533
+ send_notification " ⚠️ Backup Warning: ${HOSTNAME} " " warning" " ${NTFY_PRIORITY_WARNING} " " warning" " $FINAL_MESSAGE "
534
+ else
535
+ send_notification " ✅ Backup SUCCESS: ${HOSTNAME} " " white_check_mark" " ${NTFY_PRIORITY_SUCCESS} " " success" " $FINAL_MESSAGE "
536
+ fi
537
+ else
538
+ printf -v FAIL_MSG " One or more backups failed.\n\nSuccessful: %s\nFailed: %s\n\n%s" \
539
+ " ${success_dirs[*]:- None} " " ${failed_dirs[*]} " " $FINAL_MESSAGE "
540
+ log_message " FAILURE: One or more backups failed."
541
+ send_notification " ❌ Backup FAILED: ${HOSTNAME} " " x" " ${NTFY_PRIORITY_FAILURE} " " failure" " $FAIL_MSG "
542
+ fi
506
543
507
544
echo " ======================= Run Finished =======================" >> " $LOG_FILE "
508
545
echo " " >> " $LOG_FILE "
0 commit comments