X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=bin%2Fbackup-audit;h=6cfcf1637ac1b16d0d61cb72ed6af4df59b5bb03;hb=272abaf53ad9c7207ece6f29ea606dfbd0a61ddb;hp=2a3b99736fc8214829d3024f7f5c735bd4c6f4f4;hpb=b3f41b5e2846a3eb5d61cecb2dd2c5686c48bded;p=backup-script.git diff --git a/bin/backup-audit b/bin/backup-audit index 2a3b997..6cfcf16 100755 --- a/bin/backup-audit +++ b/bin/backup-audit @@ -1,7 +1,7 @@ #!/bin/bash # # backup-script system for cloning systems using rsync -# Copyright (c)2008-2016 Alexander Barton, alex@barton.de +# Copyright (c)2008-2018 Alexander Barton, alex@barton.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -10,7 +10,7 @@ # Please read the file COPYING, README and AUTHORS for more information. # -NAME=`basename $0` +NAME=$(basename "$0") VERBOSE=0 QUIET=0 @@ -27,6 +27,9 @@ default_files="running-config" default_generations=0 default_target="/var/backups" +# Set shell options. +shopt -s nullglob + # Search configuration file (last one is used as default!) for conf in \ "/usr/local/etc/backup-script.conf" \ @@ -42,9 +45,15 @@ for conf in \ done Usage() { - echo "Usage: $NAME [-q|--quiet] [-v|--verbose] [ [ [...]]]" + echo "Usage: $NAME [-q|--quiet] [-v|--verbose] [ [ [...]]]" echo " $NAME <-d|--dirs> " echo + echo " -d, --dirs Compare two backup directories (not jobs)." + echo " -q, --quiet Quite mode, only list jobs with changes or errors." + echo " -v, --verbose Verbose mode, show all checks that are run." + echo + echo "When no is given, all defined jobs are checked." + echo exit 2 } @@ -55,7 +64,7 @@ BeginDiff() { PipeDiff() { local line IFS= - while read line; do + while read -r line; do echo -e " | $line" done } @@ -64,6 +73,24 @@ EndDiff() { : } +ListDirectory() { + local base_dir="$1" + local dir_name="$2" + + local exclude + + exclude=' \.$' + if [[ "$dir_name" == "/" ]]; then + exclude="$exclude"'| \.stamp$| dev$| etc$| proc$| root$| run$| sys$| tmp$' + exclude="$exclude"'| data$| net$| srv$' + exclude="$exclude"'| [[:alnum:]_-]+\.log(\.[[:alnum:]]+|)$' + fi + + # shellcheck disable=SC2012 + find "$base_dir$dir_name". -maxdepth 1 -printf '%M %10u:%-10g %t %12s %f\n' 2>/dev/null \ + | LC_ALL=C sort -k 9 | grep -Ev "($exclude)" +} + HandleSystem() { local fname="$1" @@ -110,19 +137,21 @@ HandleSystem() { echo "Found latest generation in \"$latest_d\"." declare -i code=-1 + # shellcheck source=/dev/null source "$latest_d/.stamp" - if [[ $code -ne 0 && $code -ne 24 ]]; then - echo "Last backup generation has errors, skipping system!" - echo; return 1 + if [[ $code -ne 0 ]]; then + echo "Warning: Last backup generation had errors, code $code!" fi # Search previous generation without errors local previous_d="" - for d in $(ls -1dt $target/[0-9]*-[0-9]*); do + # shellcheck disable=SC2045 + for d in $(ls -1dt "$target/"[0-9]*-[0-9]* 2>/dev/null); do [[ -d "$d" && -r "$d/.stamp" ]] || return 0 declare -i code=-1 + # shellcheck source=/dev/null source "$d/.stamp" if [[ $code -eq 0 || $code -eq 24 ]]; then @@ -160,19 +189,39 @@ DiffGenerations() { /etc/group \ /etc/gshadow \ \ + /boot/grub/grub.cfg \ + /etc/aliases \ + /etc/bash.bashrc \ + /etc/crontab \ + /etc/debian_version \ + /etc/environment \ /etc/fstab \ /etc/hostname \ /etc/hosts \ + /etc/hosts.allow \ + /etc/hosts.deny \ + /etc/inittab \ + /etc/ld.so.conf \ + /etc/login.defs \ /etc/machine-id \ /etc/modules \ /etc/network/interfaces \ /etc/networks \ + /etc/nsswitch.conf \ + /etc/profile \ + /etc/rc.local \ + /etc/resolv.conf \ + /etc/services \ + /etc/shells \ + /etc/ssh/sshd_config \ + /etc/sshd_config \ + /etc/sudoers \ + /etc/sysctl.conf \ ; do [[ -r "${gen1_d}${file}" ]] || continue [[ $VERBOSE -ne 0 ]] && echo "Checking \"$file\" ..." - diff -U 3 "${gen1_d}${file}" "${gen2_d}${file}" >"$tmp_diff" - if [[ $? -ne 0 ]]; then + if ! diff -U 3 "${gen1_d}${file}" "${gen2_d}${file}" >"$tmp_diff"; then BeginDiff "\"$file\"" tail -n +3 "$tmp_diff" | PipeDiff EndDiff @@ -180,12 +229,43 @@ DiffGenerations() { fi done + for dir in \ + / \ + /etc/cron.d/ \ + /etc/cron.daily/ \ + /etc/cron.hourly/ \ + /etc/cron.monthly/ \ + /etc/cron.weekly/ \ + /etc/init.d/ \ + /etc/sudoers.d/ \ + /etc/systemd/network/ \ + /etc/systemd/system/ \ + /etc/systemd/user/ \ + /var/log/dumps/ \ + ; do + [[ ! -d "${gen1_d}${dir}" ]] && continue + [[ ! -d "${gen2_d}${dir}" ]] && continue + + # Make sure that this is a system root; comparing other + # root folders results in misleading output ... + [[ "$dir" == "/" && ! -d "${gen1_d}${dir}/etc" ]] && continue + + [[ $VERBOSE -ne 0 ]] && echo "Checking \"$dir\" ..." + ListDirectory "${gen1_d}" "${dir}" >"$tmp_1" + ListDirectory "${gen2_d}" "${dir}" >"$tmp_2" + if ! diff -U 0 "$tmp_1" "$tmp_2" >"$tmp_diff"; then + BeginDiff "\"$dir\" directory" + tail -n +3 "$tmp_diff" | egrep -v '^@@ ' | PipeDiff + EndDiff + return_code=1 + fi + done + if [[ -d "${gen1_d}/var/lib/dpkg/info" && -d "${gen2_d}/var/lib/dpkg/info" ]]; then [[ $VERBOSE -ne 0 ]] && echo "Checking list of installed packages ..." chroot "${gen1_d}" dpkg --get-selections >"$tmp_1" || return 2 chroot "${gen2_d}" dpkg --get-selections >"$tmp_2" || return 2 - diff -U 0 "$tmp_1" "$tmp_2" >"$tmp_diff" - if [[ $? -ne 0 ]]; then + if ! diff -U 0 "$tmp_1" "$tmp_2" >"$tmp_diff"; then BeginDiff "list of installed packages" tail -n +3 "$tmp_diff" | grep -v '^@@ ' | PipeDiff EndDiff @@ -196,8 +276,7 @@ DiffGenerations() { # scp Backup type file=$(basename "$files") [[ $VERBOSE -ne 0 ]] && echo "Checking \"$file\" ..." - diff -U 3 "${gen1_d}/${file}" "${gen2_d}/${file}" >"$tmp_diff" - if [[ $? -ne 0 ]]; then + if ! diff -U 3 "${gen1_d}/${file}" "${gen2_d}/${file}" >"$tmp_diff"; then BeginDiff "\"$file\"" tail -n +3 "$tmp_diff" | PipeDiff EndDiff @@ -212,10 +291,10 @@ DiffGenerations() { } MkTempFiles() { - tmp_1=$(mktemp /tmp/$NAME.XXXXXX) || exit 1 - tmp_2=$(mktemp /tmp/$NAME.XXXXXX) || exit 1 - tmp_diff=$(mktemp /tmp/$NAME.XXXXXX) || exit 1 - tmp_out=$(mktemp /tmp/$NAME.XXXXXX) || exit 1 + tmp_1=$(mktemp "/tmp/$NAME.XXXXXX") || exit 1 + tmp_2=$(mktemp "/tmp/$NAME.XXXXXX") || exit 1 + tmp_diff=$(mktemp "/tmp/$NAME.XXXXXX") || exit 1 + tmp_out=$(mktemp "/tmp/$NAME.XXXXXX") || exit 1 } CleanUp() { @@ -228,7 +307,7 @@ while [[ $# -gt 0 ]]; do shift [[ $# -eq 2 ]] || Usage MkTempFiles - DiffGenerations "$default_backup_type" "$1/" "$2/" "$default_files" + DiffGenerations "$default_backup_type" "$1" "$2" "$default_files" return_code=$? CleanUp exit $return_code @@ -263,15 +342,15 @@ MkTempFiles for f in "${sys[@]}"; do [[ -r "$f" && -f "$f" ]] || continue - fname=`basename $f` + fname=$(basename "$f") case "$fname" in "backup-script.conf"|*.sh) continue ;; esac - HandleSystem "$fname" >"$tmp_out" 2>&1 - [[ $QUIET -eq 0 || $? -ne 0 ]] && cat "$tmp_out" + HandleSystem "$fname" >"$tmp_out" 2>&1; result=$? + [[ $QUIET -eq 0 || $result -ne 0 ]] && cat "$tmp_out" done CleanUp