3 # backup-script system for cloning systems using rsync
4 # Copyright (c)2008-2016 Alexander Barton, alex@barton.de
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 # Please read the file COPYING, README and AUTHORS for more information.
20 # Default settings, can be overwritten in backup-script.conf:
21 [ -d "/usr/local/etc/backup-script.d" ] \
22 && conf_d="/usr/local/etc/backup-script.d" \
23 || conf_d="/etc/backup-script.d"
25 default_backup_type="rsync"
26 default_files="running-config"
28 default_target="/var/backups"
30 # Search configuration file (last one is used as default!)
32 "/usr/local/etc/backup-script.conf" \
33 "/etc/backup-script.conf" \
34 "${conf_d}/backup-script.conf" \
35 "/usr/local/etc/backup-script.conf" \
37 if [ -r "$conf" ]; then
38 # shellcheck source=/dev/null
45 echo "Usage: $NAME [-q|--quiet] [-v|--verbose] [<system> [<system> [...]]]"
46 echo " $NAME <-d|--dirs> <dir1> <dir2>"
52 echo "Differences in $*:"
71 local backup_type="$default_backup_type"
72 local files="$default_files"
73 local generations="$default_generations"
76 local target="$default_target"
78 # Read in system configuration file
79 # shellcheck source=/dev/null
82 target="$target/$(basename "$f")"
84 [[ -d "$target" ]] || return 0
87 [[ "$system" == "$fname" ]] \
88 && systxt="\"$system\"" \
89 || systxt="\"$fname\" [\"$system\"]"
90 [[ "$local" -eq 0 ]] \
91 && echo "Checking $systxt ..." \
92 || echo "Checking $systxt (local system) ..."
94 # Check if job is disabled
95 if [[ "$backup_type" == "disabled" ]]; then
96 echo "Job is DISABLED and will be skipped."
100 if [ $generations -lt 1 ]; then
101 echo "No generations configured, nothing to compare, skipping system!"
105 local latest_d="$target/latest"
106 if [[ ! -d "$latest_d" || ! -r "$latest_d/.stamp" ]]; then
107 echo "Failed to access latest backup generation in \"$latest_d\", skipping system!"
110 echo "Found latest generation in \"$latest_d\"."
113 source "$latest_d/.stamp"
115 if [[ $code -ne 0 && $code -ne 24 ]]; then
116 echo "Last backup generation has errors, skipping system!"
120 # Search previous generation without errors
122 for d in $(ls -1dt $target/[0-9]*-[0-9]*); do
123 [[ -d "$d" && -r "$d/.stamp" ]] || return 0
128 if [[ $code -eq 0 || $code -eq 24 ]]; then
133 if [[ -z "$previous_d" || ! -d "$previous_d" || ! -r "$previous_d/.stamp" ]]; then
134 echo "Failed to find previous successfull backup generation, skipping system!"
137 echo "Comparing with generation in $previous_d ..."
139 DiffGenerations "$backup_type" "$previous_d" "$latest_d" "$files"
147 local backup_type="$1"
154 if [[ "$backup_type" == "rsync" ]]; then
168 /etc/network/interfaces \
171 [[ -r "${gen1_d}${file}" ]] || continue
173 [[ $VERBOSE -ne 0 ]] && echo "Checking \"$file\" ..."
174 diff -U 3 "${gen1_d}${file}" "${gen2_d}${file}" >"$tmp_diff"
175 if [[ $? -ne 0 ]]; then
176 BeginDiff "\"$file\""
177 tail -n +3 "$tmp_diff" | PipeDiff
183 if [[ -d "${gen1_d}/var/lib/dpkg/info" && -d "${gen2_d}/var/lib/dpkg/info" ]]; then
184 [[ $VERBOSE -ne 0 ]] && echo "Checking list of installed packages ..."
185 chroot "${gen1_d}" dpkg --get-selections >"$tmp_1" || return 2
186 chroot "${gen2_d}" dpkg --get-selections >"$tmp_2" || return 2
187 diff -U 0 "$tmp_1" "$tmp_2" >"$tmp_diff"
188 if [[ $? -ne 0 ]]; then
189 BeginDiff "list of installed packages"
190 tail -n +3 "$tmp_diff" | grep -v '^@@ ' | PipeDiff
195 elif [[ "$backup_type" == "scp" ]]; then
197 file=$(basename "$files")
198 [[ $VERBOSE -ne 0 ]] && echo "Checking \"$file\" ..."
199 diff -U 3 "${gen1_d}/${file}" "${gen2_d}/${file}" >"$tmp_diff"
200 if [[ $? -ne 0 ]]; then
201 BeginDiff "\"$file\""
202 tail -n +3 "$tmp_diff" | PipeDiff
207 echo "Backup type \"$backup_type\" undefined, \"$system\" skipped!"
215 tmp_1=$(mktemp /tmp/$NAME.XXXXXX) || exit 1
216 tmp_2=$(mktemp /tmp/$NAME.XXXXXX) || exit 1
217 tmp_diff=$(mktemp /tmp/$NAME.XXXXXX) || exit 1
218 tmp_out=$(mktemp /tmp/$NAME.XXXXXX) || exit 1
222 rm -f "$tmp_1" "$tmp_2" "$tmp_diff" "$tmp_out"
225 while [[ $# -gt 0 ]]; do
229 [[ $# -eq 2 ]] || Usage
231 DiffGenerations "$default_backup_type" "$1/" "$2/" "$default_files"
250 if [[ $# -ge 1 ]]; then
252 if [ ! -r "${conf_d}/$s" ]; then
253 echo "$NAME: Can' read \"${conf_d}/$s\"!"
256 sys+=("${conf_d}/$s")
263 for f in "${sys[@]}"; do
264 [[ -r "$f" && -f "$f" ]] || continue
268 "backup-script.conf"|*.sh)
273 HandleSystem "$fname" >"$tmp_out" 2>&1
274 [[ $QUIET -eq 0 || $? -ne 0 ]] && cat "$tmp_out"