-
Notifications
You must be signed in to change notification settings - Fork 0
/
rsync.sh
executable file
·176 lines (151 loc) · 4.85 KB
/
rsync.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#!/bin/bash
set -eu -o pipefail
safe_source () { [[ ! -z ${1:-} ]] && source $1; _dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"; _sdir=$(dirname "$(readlink -f "$0")"); }; safe_source
# end of bash boilerplate
safe_source $_sdir/lib/all.sh
# do not exit on errors
set +e
# show help
show_help(){
cat <<HELP
$(basename $0) [options] /path/to/source /path/to/destination
Options:
--dry-run : Dry run, don't touch anything actually
-u : Unattended run, don't show yes/no prompt
--ssh[="settings"] : Switch to SSH mode by using "settings"
Example:
rsync.sh --ssh user@myhost:/path/to/src/ /path/to/dest/
rsync.sh --ssh="-p 1234 -i /path/to/id" user@myhost:/path/to/src/ /path/to/dest/
HELP
exit
}
die () {
echo
echo_red "$1"
show_help
exit 255
}
# Parse command line arguments
# ---------------------------
# Initialize parameters
dry_run=false
unattended=false
iredir=false # internal redirect
ssh_mode=false
ssh_settings=
# ---------------------------
args=("$@")
_count=1
while :; do
key="${1:-}"
case $key in
-h|-\?|--help|'')
show_help # Display a usage synopsis.
exit
;;
# --------------------------------------------------------
--dry-run) shift
dry_run=true
;;
-u) shift
unattended=true
;;
--internal-redirect) shift
iredir=true
;;
--ssh*) shift
ssh_mode=true
# use port/id file settings after "=" sign (or null)
ssh_settings=$(echo $key | sed -e 's/^[^=]*//' | cut -d "=" -f 2)
;;
# --------------------------------------------------------
-*) # Handle unrecognized options
echo
echo "Unknown option: $1"
show_help
exit 1
;;
*) # Generate the positional arguments: $_arg1, $_arg2, ...
[[ ! -z ${1:-} ]] && declare _arg$((_count++))="$1" && shift
esac
[[ -z ${1:-} ]] && break
done; set -- "${args[@]}"
# use $_arg1 in place of $1, $_arg2 in place of $2 and so on, "$@" is intact
src=${_arg1:-}
dest=${_arg2:-}
[[ -z $src ]] && die "Source can not be empty"
[[ -z $dest ]] && die "Destination can not be empty"
[[ $iredir = false ]] && echo_green "Using destination directory: $dest"
if [[ $unattended = false ]]; then
if ! prompt_yes_no "Should we really continue?"; then
echo_info "Interrupted by user."
exit 0
fi
fi
# All checks are done, run as root
[[ $(whoami) = "root" ]] || { sudo $0 "$@" -u --internal-redirect; exit 0; }
if [[ $ssh_mode = false ]]; then
for path in $src $dest; do
if [[ $path =~ ^[a-zA-Z0-9_@.%+-]+\:[0-9]{1,4}.* ]]; then
echo_info "It seems that SSH mode is being used with a custom port."
die "Use --ssh=\"-p ...\" switch to declare the SSH port."
fi
done
for path in $src $dest; do
if [[ $path =~ ^[a-zA-Z0-9_@.%+-]+\:.* ]]; then
echo_info "SSH mode seems to be intended"
die "Please add the --ssh switch."
fi
done
fi
# Cleanup code (should be after "run as root")
sure_exit(){
echo
echo_yellow "Interrupted by user."
exit 5
}
cleanup(){
exit_code=$?
if [[ $exit_code -eq 0 ]]; then
echo_green "Have a nice day."
else
echo_red "Something went wrong: Code: $exit_code"
fi
exit $exit_code
}
trap sure_exit SIGINT # Runs on Ctrl+C, before EXIT
trap cleanup EXIT
RSYNC="nice -n19 ionice -c3 rsync"
SSH="ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -o ExitOnForwardFailure=yes -o AddressFamily=inet"
start_timer
# build rsync params
_params=
[[ $dry_run = true ]] && _params="$_params --dry-run"
if [[ $ssh_mode = true ]]; then
ssh_config_path="$(eval echo ~$SUDO_USER)/.ssh/config"
ssh_config_arg=
[[ -f ssh_config_path ]] && ssh_config_arg="-F $ssh_config_path"
ssh_id_path="$(eval echo ~$SUDO_USER)/.ssh/id_rsa"
_params="$_params --rsh=\"$SSH $ssh_settings $ssh_config_arg\" --rsync-path=\"sudo rsync\""
fi
for i in `seq 1 3`; do
eval $RSYNC -aHAXvPh $_params --delete --delete-excluded --numeric-ids \
--filter="\"merge $_sdir/exclude-list.txt\"" "$src" "$dest"
exit
exit_code=$?
if [ $exit_code -eq 11 ]; then
echo_red "NO Space Left on the device (code $exit_code)"
# It's useful to retry on "No Space Left on the device" error on BTRFS because
# user might have deleted some big snapshots recently and btrfs-cleanup might be still
# working on freeing the available space.
# TODO: Retry only if it's BTRFS filesystem.
retry="10m"
echo_yellow "...will retry in $retry"
sleep ${retry}
echo_green "...Retrying..."
continue
fi
break
done
show_timer "sync completed in:"
exit $exit_code