#!/bin/bash set -e # ---------------------------------------------------------------------------------------------- # --------------------------------- Rsync Core Script ------------------------------------------ # ---------------------------------------------------------------------------------------------- # ---------------- User Variables, Please adjust in Master.conf as needed ---------------------- # ---------------------------------------------------------------------------------------------- # # User variables can be adjusted in Master.conf # # Scripts now just contain runtime logic # # This new setup allows for profiles and arguments to use the core script # # Use arguments in unRAID User Plugin for directory # Example = /mnt/user/appdata/unraid_scripts/Rsync/rsync.sh --dry-run # ---------------------------------------------------------------------------------------------- # -------------- End Of User Variables, Please adjust in Master.conf as needed ----------------- # ---------------------------------------------------------------------------------------------- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck source=common.sh source "$SCRIPT_DIR/common.sh" ############################################# # ARG PARSING (UNRAID SAFE) ############################################# SOURCE="" DEST="" ARGS=() for arg in "$@"; do if [[ "$arg" == -* ]]; then ARGS+=("$arg") elif [[ -z "$SOURCE" ]]; then SOURCE="$arg" elif [[ -z "$DEST" ]]; then DEST="$arg" else warn "Unknown argument: $arg" fi done ############################################# # LOAD CONFIG ############################################# PROFILE_NAME=${PROFILE_NAME:-"default"} MAX_RSYNC_PROCS=${PROFILE_MAX_PROCS:-2} MAX_RSYNC_PROCS=${PROFILE_MAX_PROCS[$PROFILE_NAME]:-$MAX_RSYNC_PROCS} ############################################# # HEADER ############################################# info "Host: $(hostname) → ${REMOTE_HOST:-unknown}" info "Sync Starting" info "Source: $SOURCE" info "Remote: ${REMOTE_HOST:-$DEST}" info "Profile: $PROFILE_NAME" ############################################# # REMOTE RESOLVE ############################################# info "Resolving remote IP..." REMOTE_IP=$(resolve_remote_ip "$REMOTE_HOST") info "Remote IP: $REMOTE_IP" REMOTE_TARGET="${REMOTE_IP}:${DEST}" ############################################# # CHECK REMOTE ############################################# info "Checking remote..." if ! ping -c 1 -W 1 "$REMOTE_IP" >/dev/null 2>&1; then error "Remote unreachable" exit 1 fi ok "Remote reachable" ############################################# # CONTAINER STOP (SAFE BARRIER) ############################################# info "Stopping containers..." stop_containers || true # ensure docker settle (prevents race condition) sleep 3 wait_for_containers_to_stop || true ############################################# # RSYNC SLOT LIMITER (FIXED) ############################################# wait_for_rsync() { : "${RETRY_COUNT:=5}" : "${MAX_RSYNC_PROCS:=2}" : "${SLEEP:=2}" for _ in $(seq 1 "$RETRY_COUNT"); do # ONLY COUNT TOP-LEVEL RSYNC COMMANDS COUNT=$(pgrep -x rsync | wc -l || true) if [[ "$COUNT" -ge "$MAX_RSYNC_PROCS" ]]; then warn "Waiting rsync slot ($COUNT/$MAX_RSYNC_PROCS)" sleep "$SLEEP" else return 0 fi done error "Too many rsync processes" exit 1 } wait_for_rsync ############################################# # RSYNC OPTIONS ############################################# info "Building rsync opts..." RSYNC_OPTS=(-aHAX --numeric-ids --delete) if [[ "${DRY_RUN:-false}" == "true" ]]; then RSYNC_OPTS+=("--dry-run") fi ############################################# # EXECUTE RSYNC ############################################# info "Running rsync..." rsync "${RSYNC_OPTS[@]}" \ -e "ssh -o StrictHostKeyChecking=no" \ "$SOURCE" \ "root@$REMOTE_TARGET"