- CLI binary: bin/gniza -> bin/gniza4cp - Install path: /usr/local/gniza4cp/ - Config path: /etc/gniza4cp/ - Log path: /var/log/gniza4cp/ - WHM plugin: gniza4cp-whm/ - cPanel plugin: cpanel/gniza4cp/ - AdminBin: Gniza4cp::Restore - Perl modules: Gniza4cpWHM::*, Gniza4cpCPanel::* - DaisyUI theme: gniza4cp - All internal references, branding, paths updated - Git remote updated to gniza4cp repo
147 lines
4.4 KiB
Bash
147 lines
4.4 KiB
Bash
#!/usr/bin/env bash
|
|
# gniza4cp/lib/transfer.sh — rsync --link-dest to remote, .partial atomicity, retries
|
|
|
|
rsync_to_remote() {
|
|
local source_dir="$1"
|
|
local remote_dest="$2"
|
|
local link_dest="${3:-}"
|
|
local attempt=0
|
|
local max_retries="${SSH_RETRIES:-$DEFAULT_SSH_RETRIES}"
|
|
local rsync_ssh; rsync_ssh=$(build_rsync_ssh_cmd)
|
|
|
|
local rsync_opts=(-aHAX --numeric-ids --delete --rsync-path="rsync --fake-super")
|
|
|
|
if [[ -n "$link_dest" ]]; then
|
|
rsync_opts+=(--link-dest="$link_dest")
|
|
fi
|
|
|
|
if [[ "${BWLIMIT:-0}" -gt 0 ]]; then
|
|
rsync_opts+=(--bwlimit="$BWLIMIT")
|
|
fi
|
|
|
|
if [[ -n "${RSYNC_EXTRA_OPTS:-}" ]]; then
|
|
# shellcheck disable=SC2206
|
|
rsync_opts+=($RSYNC_EXTRA_OPTS)
|
|
fi
|
|
|
|
rsync_opts+=(-e "$rsync_ssh")
|
|
|
|
# Ensure source ends with /
|
|
[[ "$source_dir" != */ ]] && source_dir="$source_dir/"
|
|
|
|
while (( attempt < max_retries )); do
|
|
((attempt++)) || true
|
|
log_debug "rsync attempt $attempt/$max_retries: $source_dir -> $remote_dest"
|
|
|
|
log_debug "CMD: rsync ${rsync_opts[*]} $source_dir ${REMOTE_USER}@${REMOTE_HOST}:${remote_dest}"
|
|
local rsync_cmd=(rsync "${rsync_opts[@]}" "$source_dir" "${REMOTE_USER}@${REMOTE_HOST}:${remote_dest}")
|
|
if _is_password_mode; then
|
|
export SSHPASS="$REMOTE_PASSWORD"
|
|
rsync_cmd=(sshpass -e "${rsync_cmd[@]}")
|
|
fi
|
|
local rc=0
|
|
"${rsync_cmd[@]}" || rc=$?
|
|
if (( rc == 0 )); then
|
|
log_debug "rsync succeeded on attempt $attempt"
|
|
return 0
|
|
fi
|
|
|
|
log_warn "rsync failed (exit $rc), attempt $attempt/$max_retries"
|
|
|
|
if (( attempt < max_retries )); then
|
|
local backoff=$(( attempt * 10 ))
|
|
log_info "Retrying in ${backoff}s..."
|
|
sleep "$backoff"
|
|
fi
|
|
done
|
|
|
|
log_error "rsync failed after $max_retries attempts"
|
|
return 1
|
|
}
|
|
|
|
transfer_pkgacct() {
|
|
local user="$1"
|
|
local timestamp="$2"
|
|
local prev_snapshot="${3:-}"
|
|
local temp_dir="${TEMP_DIR:-$DEFAULT_TEMP_DIR}"
|
|
local source="$temp_dir/$user"
|
|
|
|
if _is_rclone_mode; then
|
|
local snap_subpath="accounts/${user}/snapshots/${timestamp}"
|
|
log_info "Transferring pkgacct data for $user (rclone)..."
|
|
rclone_to_remote "$source" "$snap_subpath"
|
|
return
|
|
fi
|
|
|
|
local snap_dir; snap_dir=$(get_snapshot_dir "$user")
|
|
local dest="$snap_dir/${timestamp}.partial/"
|
|
local link_dest=""
|
|
|
|
if [[ -n "$prev_snapshot" ]]; then
|
|
# Detect old format (pkgacct/ subdir) vs new format (content at root)
|
|
if remote_exec "test -d '$snap_dir/$prev_snapshot/pkgacct'" 2>/dev/null; then
|
|
link_dest="$snap_dir/$prev_snapshot/pkgacct"
|
|
else
|
|
link_dest="$snap_dir/$prev_snapshot"
|
|
fi
|
|
fi
|
|
|
|
ensure_remote_dir "$dest" || return 1
|
|
|
|
log_info "Transferring pkgacct data for $user..."
|
|
rsync_to_remote "$source" "$dest" "$link_dest"
|
|
}
|
|
|
|
transfer_homedir() {
|
|
local user="$1"
|
|
local timestamp="$2"
|
|
local prev_snapshot="${3:-}"
|
|
local homedir; homedir=$(get_account_homedir "$user")
|
|
|
|
if [[ ! -d "$homedir" ]]; then
|
|
log_warn "Home directory not found for $user: $homedir"
|
|
return 1
|
|
fi
|
|
|
|
if _is_rclone_mode; then
|
|
local snap_subpath="accounts/${user}/snapshots/${timestamp}/homedir"
|
|
log_info "Transferring homedir for $user ($homedir) (rclone)..."
|
|
rclone_to_remote "$homedir" "$snap_subpath"
|
|
return
|
|
fi
|
|
|
|
local snap_dir; snap_dir=$(get_snapshot_dir "$user")
|
|
local dest="$snap_dir/${timestamp}.partial/homedir/"
|
|
local link_dest=""
|
|
|
|
if [[ -n "$prev_snapshot" ]]; then
|
|
link_dest="$snap_dir/$prev_snapshot/homedir"
|
|
fi
|
|
|
|
ensure_remote_dir "$dest" || return 1
|
|
|
|
log_info "Transferring homedir for $user ($homedir)..."
|
|
rsync_to_remote "$homedir" "$dest" "$link_dest"
|
|
}
|
|
|
|
finalize_snapshot() {
|
|
local user="$1"
|
|
local timestamp="$2"
|
|
|
|
if _is_rclone_mode; then
|
|
log_info "Finalizing snapshot for $user: $timestamp (rclone)"
|
|
rclone_finalize_snapshot "$user" "$timestamp"
|
|
return
|
|
fi
|
|
|
|
local snap_dir; snap_dir=$(get_snapshot_dir "$user")
|
|
|
|
log_info "Finalizing snapshot for $user: $timestamp"
|
|
remote_exec "mv '$snap_dir/${timestamp}.partial' '$snap_dir/$timestamp'" || {
|
|
log_error "Failed to finalize snapshot for $user: $timestamp"
|
|
return 1
|
|
}
|
|
|
|
update_latest_symlink "$user" "$timestamp"
|
|
}
|