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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
|
#!/bin/bash
# Informational output w/ happy colors
debug () {
[[ $DEBUG ]] && echo -e '\033[1;33mDEBUG ::\033[1;m ' $*
}
info () {
echo -e '\033[1;34m::\033[1;m ' $*
}
die () {
echo -e '\033[1;31mFATAL ::\033[1;m ' $* >&2
exit 1
}
mount_squash () {
# Arguments: none
# Returns: return code of mount command
mount -t loop,ro "$SEED" "${BKUP_ROOT}/ro"
return $?
}
mount_union_with_bins () {
# Arguments: numbers of bins to be mounted (variable number)
# Returns: 0 on successful mount, non-zero on failure
# Mount first as rw, shift, and mount the rest ro
branches="br=${BINS_DIR}/$1=rw:"; shift
for bin in $*; do
branches="${branches}/bins/$bin=ro:"
done
branches="${branches}${BKUP_ROOT}/ro=ro"
debug "mount -t aufs none "${BKUP_ROOT}/rw" -o udba=reval,$branches"
mount -t aufs none "${BKUP_ROOT}/rw" -o udba=reval,$branches
return $?
}
get_next_available_bin () {
# Arguments: none
# Returns: Numeric value of the next unused bin
return $[ $(cut -d: -f1 "$BINVENTORY" | sort -n | tail -1) + 1 ]
}
sweep_bins () {
# Arguments: none
# Returns: none
count=1
# Make sure bins are numbered in order, clean up if not. In other words,
# if we have 10 bins, make sure they're ordered 1 through 10.
for bin in "${BINS_DIR}/*"; do
if [[ ! -d "${BINS_DIR}/$count" ]]; then
high_bin=$(ls "${BINS_DIR}" | sort -n | tail -1)
mv "${BINS_DIR}/$high_bin" "${BINS_DIR}/$count"
sed -i "/^$high_bin:/s/^$high_bin:/$count:/" "$BINVENTORY"
fi
count=$[ $count + 1 ]
done
}
call_rsync () {
# Arguments: none
# Returns: return code from rsync
# Parse includes and excludes from heredocs in config
INCLUDES=($(sed -n '/^<<INCLUDES$/,/^INCLUDES$/p' $CONFIG | grep -vE "^<*INCLUDES$"))
EXCLUDES=($(sed -n '/^<<EXCLUDES$/,/^EXCLUDES$/p' $CONFIG | \
grep -vE "^<*EXCLUDES$" | \
sed -n 's/\(.*\)/--exclude "\1"/p'))
# rsync source to $BKUP_ROOT/rw
debug "Rsync executing with:"
debug ": Options: ${RSYNC_OPTS[@]}"
debug ": Includes: ${INCLUDES[@]}"
debug ": Excludes: ${EXCLUDES[@]}"
rsync ${RSYNC_OPTS[@]} ${INCLUDES[@]} ${EXCLUDES[@]} "${BKUP_ROOT}/rw"
return $?
}
create_new_bin () {
# Arguments: 1, the number of the bin to create
# Returns: 0 on success, non-zero on error
# Create new directory, fail if it exists (something's wrong)
mkdir "${BINS_DIR}/$1"
if [[ $? -ne 0 ]]; then
return $?
fi
# Update binventory with new bin name and timestamp
echo "${1}:$(stat -c %u ${BINS_DIR}/$1)" >> "$BINVENTORY"
return $?
}
# Unmounting functions
unmount_union () {
# Args: none
# Returns: return code from umount
umount "${BKUP_ROOT}/rw"
return $?
}
unmount_seed () {
# Args: none
# Returns: return code from umount
umount "${BKUP_ROOT}/ro"
return $?
}
unmount_all () {
# Args: none
# Returns: none
# Union MUST be unmounted first
unmount_union
unmoun_seed
}
check_for_resquash () {
# Args: none
# Returns: number of bins needing to be merged
local number_of_bins=$(wc -l "$BINVENTORY")
if [[ $number_of_bins -gt $MAX_BINS ]]; then
return $[ $number_of_bins - $MIN_BINS ]
else
return 0
fi
}
create_new_squash () {
# Args: number of bins to be squashed (as determined by check_for_resquash), -1 on initial creation
# Returns: 0 on success, non-zero on failure
# If making first seed, create it empty and return
if [[ $1 -eq -1 ]]; then
mksquashfs "${BKUP_ROOT}/rw" "$SEED" -b 65536
return $?
fi
# Determine oldest $1 bins and mount them with the current squash
local old_bins=($(sort -n -r -t: -k2 "$BINVENTORY" | tail -$1 | cut -d: -f1))
mount_union_with_bins ${old_bins[@]}
# Create new squash with temp name
mksquashfs "${BKUP_ROOT}/rw" "$SEED.replace" -b 65536
# If the squash wasn't made correctly, we don't want to continue
if [[ $? -ne 0 ]]; then
return 1
fi
unmount_all
# Replace old squash
mv "${SEED}.replace" "$SEED"
# Delete old bins, and remove entry from binventory
for bin in $old_bins; do
rm -rf "${BKUP_ROOT}/bins/$bin"
sed -i "/^$bin:/d" "$BINVENTORY"
done
}
create_new_incremental () {
# Args: none
# Returns: 0 on success, non-zero on error
# Make a new bin for this incremenetal
get_next_available_bin
create_new_bin $?
# Determine the mount order via binventory
bin_order=($(sort -n -r -t:2 -k2 "$BINVENTORY" | cut -d: -f1))
mount_union_with_bins ${BIN_ORDER[@]}
# Die with error on mount, else start rsync
if [[ $? -ne 0 ]]; then
return 1;
fi
call_rsync
return $?
}
|