/
500_make_backup.sh
221 lines (199 loc) · 9.04 KB
/
500_make_backup.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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# 500_make_backup.sh
#
function set_tar_features {
# Default tar options
TAR_OPTIONS=
# Test for features in tar
# true if at supports the --warning option (v1.23+)
FEATURE_TAR_WARNINGS=
local tar_version=$(get_version tar --version)
if version_newer "$tar_version" 1.23; then
FEATURE_TAR_WARNINGS="y"
TAR_OPTIONS="$TAR_OPTIONS --warning=no-xdev"
fi
FEATURE_TAR_IS_SET=1
}
Log "Include list:"
while read -r ; do
Log " $REPLY"
done < $TMP_DIR/backup-include.txt
Log "Exclude list:"
while read -r ; do
Log " $REPLY"
done < $TMP_DIR/backup-exclude.txt
local scheme=$(url_scheme $BACKUP_URL)
local path=$(url_path $BACKUP_URL)
local opath=$(backup_path $scheme $path)
if [[ "$opath" ]]; then
mkdir -p $v "${opath}" >&2
fi
# Disable BACKUP_PROG_CRYPT_OPTIONS by replacing the default with 'cat' when encryption is disabled
# (by default encryption is disabled but the default BACKUP_PROG_CRYPT_OPTIONS is not 'cat'):
if is_true "$BACKUP_PROG_CRYPT_ENABLED" ; then
# Backup archive encryption is only supported with 'tar':
test "tar" = "$BACKUP_PROG" || Error "Backup archive encryption is only supported with BACKUP_PROG=tar"
LogPrint "Encrypting backup archive with key defined in variable \$BACKUP_PROG_CRYPT_KEY"
else
Log "Encrypting backup archive is disabled"
BACKUP_PROG_CRYPT_OPTIONS="cat"
BACKUP_PROG_CRYPT_KEY=""
fi
# Check if the backup needs to be splitted or not (on multiple ISOs)
if [[ -n "$ISO_MAX_SIZE" ]]; then
# Computation of the real backup maximum size by excluding bootable files size on the first ISO (EFI, kernel, ramdisk)
# Don't use that on max size less than 200MB which would result in too many backups
if [[ $ISO_MAX_SIZE -gt 200 ]]; then
INITRD_SIZE=$(stat -c '%s' $TMP_DIR/$REAR_INITRD_FILENAME)
KERNEL_SIZE=$(stat -c '%s' $KERNEL_FILE)
# We add 15MB which is the average size of all isolinux binaries
BASE_ISO_SIZE=$(((${INITRD_SIZE}+${KERNEL_SIZE})/1024/1024+15))
# If we are EFI, add 30MB (+ previous 15MB), UEFI files can't exceed this size
is_true $USING_UEFI_BOOTLOADER && BASE_ISO_SIZE=$((${BASE_ISO_SIZE}+30))
ISO_MAX_SIZE=$((${ISO_MAX_SIZE}-${BASE_ISO_SIZE}))
fi
SPLIT_COMMAND="split -d -b ${ISO_MAX_SIZE}m - ${backuparchive}."
else
SPLIT_COMMAND="dd of=$backuparchive"
fi
LogPrint "Creating $BACKUP_PROG archive '$backuparchive'"
ProgressStart "Preparing archive operation"
(
case "$(basename ${BACKUP_PROG})" in
# tar compatible programs here
(tar)
set_tar_features
Log $BACKUP_PROG $TAR_OPTIONS --sparse --block-number --totals --verbose \
--no-wildcards-match-slash --one-file-system \
--ignore-failed-read "${BACKUP_PROG_OPTIONS[@]}" \
$BACKUP_PROG_CREATE_NEWER_OPTIONS \
${BACKUP_PROG_BLOCKS:+-b $BACKUP_PROG_BLOCKS} "${BACKUP_PROG_COMPRESS_OPTIONS[@]}" \
-X $TMP_DIR/backup-exclude.txt -C / -c -f - \
$(cat $TMP_DIR/backup-include.txt) $RUNTIME_LOGFILE \| $BACKUP_PROG_CRYPT_OPTIONS BACKUP_PROG_CRYPT_KEY \| $SPLIT_COMMAND
$BACKUP_PROG $TAR_OPTIONS --sparse --block-number --totals --verbose \
--no-wildcards-match-slash --one-file-system \
--ignore-failed-read "${BACKUP_PROG_OPTIONS[@]}" \
$BACKUP_PROG_CREATE_NEWER_OPTIONS \
${BACKUP_PROG_BLOCKS:+-b $BACKUP_PROG_BLOCKS} "${BACKUP_PROG_COMPRESS_OPTIONS[@]}" \
-X $TMP_DIR/backup-exclude.txt -C / -c -f - \
$(cat $TMP_DIR/backup-include.txt) $RUNTIME_LOGFILE | $BACKUP_PROG_CRYPT_OPTIONS $BACKUP_PROG_CRYPT_KEY | $SPLIT_COMMAND
;;
(rsync)
# make sure that the target is a directory
mkdir -p $v "$backuparchive" >&2
Log $BACKUP_PROG --verbose "${BACKUP_RSYNC_OPTIONS[@]}" --one-file-system --delete \
--exclude-from=$TMP_DIR/backup-exclude.txt --delete-excluded \
$(cat $TMP_DIR/backup-include.txt) "$backuparchive"
$BACKUP_PROG --verbose "${BACKUP_RSYNC_OPTIONS[@]}" --one-file-system --delete \
--exclude-from=$TMP_DIR/backup-exclude.txt --delete-excluded \
$(cat $TMP_DIR/backup-include.txt) "$backuparchive" >&2
;;
(*)
Log "Using unsupported backup program '$BACKUP_PROG'"
Log $BACKUP_PROG "${BACKUP_PROG_COMPRESS_OPTIONS[@]}" \
$BACKUP_PROG_OPTIONS_CREATE_ARCHIVE $TMP_DIR/backup-exclude.txt \
"${BACKUP_PROG_OPTIONS[@]}" $backuparchive \
$(cat $TMP_DIR/backup-include.txt) $RUNTIME_LOGFILE > $backuparchive
$BACKUP_PROG "${BACKUP_PROG_COMPRESS_OPTIONS[@]}" \
$BACKUP_PROG_OPTIONS_CREATE_ARCHIVE $TMP_DIR/backup-exclude.txt \
"${BACKUP_PROG_OPTIONS[@]}" $backuparchive \
$(cat $TMP_DIR/backup-include.txt) $RUNTIME_LOGFILE > $backuparchive
;;
esac 2> "${TMP_DIR}/${BACKUP_PROG_ARCHIVE}.log"
# important trick: the backup prog is the last in each case entry and the case .. esac is the last command
# in the (..) subshell. As a result the return code of the subshell is the return code of the backup prog!
) &
BackupPID=$!
starttime=$SECONDS
sleep 1 # Give the backup software a good chance to start working
# return disk usage in bytes
function get_disk_used() {
let "$(stat -f -c 'used=(%b-%f)*%S' $1)"
echo $used
}
# While the backup runs in a sub-process, display some progress information to the user.
# ProgressInfo texts have a space at the end to get the 'OK' from ProgressStop shown separated.
test "$PROGRESS_WAIT_SECONDS" || PROGRESS_WAIT_SECONDS=1
case "$( basename $BACKUP_PROG )" in
(tar)
while sleep $PROGRESS_WAIT_SECONDS ; kill -0 $BackupPID 2>/dev/null; do
#blocks="$(stat -c %b ${backuparchive})"
#size="$((blocks*512))"
size="$(stat -c %s ${backuparchive}* | awk '{s+=$1} END {print s}')"
ProgressInfo "Archived $((size/1024/1024)) MiB [avg $((size/1024/(SECONDS-starttime))) KiB/sec] "
done
;;
(rsync)
# since we do not want to do a $(du -s) run every second we count disk usage instead
# this obviously leads to wrong results in case something else is writing to the same
# disk at the same time as is very likely with a networked file system. For local disks
# this should be good enough and in any case this is only some eye candy.
# TODO: Find a fast way to count the actual transfer data, preferrable getting the info from rsync.
let old_disk_used="$(get_disk_used "$backuparchive")"
while sleep $PROGRESS_WAIT_SECONDS ; kill -0 $BackupPID 2>/dev/null; do
let disk_used="$(get_disk_used "$backuparchive")" size=disk_used-old_disk_used
ProgressInfo "Archived $((size/1024/1024)) MiB [avg $((size/1024/(SECONDS-starttime))) KiB/sec] "
done
;;
(*)
while sleep $PROGRESS_WAIT_SECONDS ; kill -0 $BackupPID 2>/dev/null; do
size="$(stat -c "%s" "$backuparchive")" || {
kill -9 $BackupPID
ProgressError
Error "$(basename $BACKUP_PROG) failed to create the archive file"
}
ProgressInfo "Archived $((size/1024/1024)) MiB [avg $((size/1024/(SECONDS-starttime))) KiB/sec] "
done
;;
esac
ProgressStop
transfertime="$((SECONDS-starttime))"
# harvest return code from background job. The kill -0 $BackupPID loop above should
# have made sure that this wait won't do any real "waiting" :-)
wait $BackupPID
backup_prog_rc=$?
if [[ $BACKUP_INTEGRITY_CHECK =~ ^[yY1] && "$(basename ${BACKUP_PROG})" = "tar" ]] ; then
(cd $(dirname $backuparchive) && md5sum $(basename $backuparchive) > ${backuparchive}.md5 || md5sum $(basename $backuparchive).?? > ${backuparchive}.md5)
fi
sleep 1
# everyone should see this warning, even if not verbose
case "$(basename $BACKUP_PROG)" in
(tar)
if (( $backup_prog_rc == 1 )); then
LogPrint "WARNING: $(basename $BACKUP_PROG) ended with return code $backup_prog_rc and below output:
---snip---
$(grep '^tar: ' $RUNTIME_LOGFILE | sed -e 's/^/ /' | tail -n3)
----------
This means that files have been modified during the archiving
process. As a result the backup may not be completely consistent
or may not be a perfect copy of the system. Relax-and-Recover
will continue, however it is highly advisable to verify the
backup in order to be sure to safely recover this system.
"
elif (( $backup_prog_rc > 1 )); then
Error "$(basename $BACKUP_PROG) failed with return code $backup_prog_rc and below output:
---snip---
$(grep '^tar: ' $RUNTIME_LOGFILE | sed -e 's/^/ /' | tail -n3)
----------
This means that the archiving process ended prematurely, or did
not even start. As a result it is unlikely you can recover this
system properly. Relax-and-Recover is therefore aborting execution.
"
fi;;
(*)
if (( $backup_prog_rc > 0 )) ; then
Error "$(basename $BACKUP_PROG) failed with return code $backup_prog_rc
This means that the archiving process ended prematurely, or did
not even start. As a result it is unlikely you can recover this
system properly. Relax-and-Recover is therefore aborting execution.
"
fi
;;
esac
tar_message="$(tac $RUNTIME_LOGFILE | grep -m1 '^Total bytes written: ')"
if [ $backup_prog_rc -eq 0 -a "$tar_message" ] ; then
LogPrint "$tar_message in $transfertime seconds."
elif [ "$size" ]; then
LogPrint "Archived $((size/1024/1024)) MiB in $((transfertime)) seconds [avg $((size/1024/transfertime)) KiB/sec]"
fi
### Copy progress log to backup media
cp $v "${TMP_DIR}/${BACKUP_PROG_ARCHIVE}.log" "${opath}/${BACKUP_PROG_ARCHIVE}.log" >&2