-
Notifications
You must be signed in to change notification settings - Fork 0
/
btrfs-sync.bak
executable file
·152 lines (129 loc) · 4.38 KB
/
btrfs-sync.bak
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
#!/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
show_help(){
local script=$(basename $0)
local reason=${1:-}
[[ ! -z $reason ]] && cat <<REASON
-------------------------------
ERROR: $reason
-------------------------------
REASON
cat <<HELP
$script [options] /path/to/source /path/to/destination
Options:
--dry-run : Dry run, don't touch anything actually
HELP
exit
}
# for debugging
#set -x
# Parse command line arguments
# ---------------------------
# Initialize parameters
dry_run=false
# ---------------------------
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
;;
# --------------------------------------------------------
-*)
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
s=${_arg1:-}
d=${_arg2:-}
[[ -z $s ]] && show_help "Source can not be empty"
[[ -z $d ]] && show_help "Destination can not be empty"
[[ $(whoami) = "root" ]] || { sudo $0 "$@"; exit 0; }
start_timer
[[ $dry_run = true ]] && dry_run_str="(dry run)"
echo "=====================${dry_run_str:-}=========================="
echo "from $s to $d "
echo
echo "Following snapshot roots will be synced:"
for _snap_root in $(get_snapshot_roots $s); do
echo "* $_snap_root"
done
echo "==============================================="
echo
# Fixme: Following command takes too long
#start=$SECONDS
#for i in 1; do
# echo "pass $i"
# find_sent_subs $s $d > x2
#done
#echo "took: $(( $SECONDS - $start ))"
# source and destination should be on different disks
require_different_disks $s $d
src_mnt=$(mount_point_of $s)
dst_mnt=$(mount_point_of $d)
for _snap_root in $(get_snapshot_roots $s); do
snap_root=${_snap_root#$src_mnt/}
echo_blue "Syncing $snap_root -> $dst_mnt/..."
# create target directory structure
mkdir -p "$dst_mnt/$snap_root"
echo "--- already sent: ---"
already_sent=$(find_sent_subs "$src_mnt/$snap_root" "$dst_mnt/$snap_root")
echo "$already_sent"
last_sent=$(echo $already_sent | rev | cut -d " " -f 1 | rev)
#echo "LAST SENT: $last_sent"
echo "--- incomplete transfers ---"
for incomplete in `list_subvol_below $dst_mnt/$snap_root true`; do
if is_subvolume_incomplete $incomplete; then
echo_yellow "Found incomplete snapshot: $incomplete"
if [[ $dry_run = false ]]; then
btrfs sub del $incomplete
else
echo "(This is dry run, won't delete anything actually)"
fi
fi
done
echo "--- missing: ---"
snapshots=$(list_subvol_below $src_mnt/$snap_root)
for missing in `find_missing_subs "$src_mnt/$snap_root" "$dst_mnt/$snap_root"`; do
if [[ ! -z $last_sent ]]; then
if [ $missing \< $last_sent ]; then
echo_yellow "Skipping older snapshot: $(basename $missing)"
continue
fi
fi
parent=$(find_prev_snap $missing $snapshots)
if [[ -z $parent ]]; then
echo_yellow "No parent found for $missing, sending whole snapshot"
_parent_arg=
else
echo_blue "Sending $(basename $missing) (based on $(basename $parent)) "
_parent_arg="-p $parent"
fi
if [[ $dry_run = true ]]; then
echo "(This is dry run, won't send anything actually.)"
else
btrfs send -q $_parent_arg $missing | pv | btrfs receive $dst_mnt/$snap_root/ > /dev/null
echo_green "...$missing succesfully sent."
echo "$missing has been sent to $dst_mnt/$snap_root" >> "$s/log.txt"
fi
done
echo "end of syncing $snap_root"
done
show_timer "Completed in: "