From 9f0350f99ac2b5ecb212b2c85204e13b285d30e6 Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Thu, 16 Jan 2014 10:06:33 +0000 Subject: [PATCH] check-bkp-status: New program writes reports about backups. --- Makefile.am | 10 + check-bkp-status.8 | 60 ++++++ check-bkp-status.in | 441 ++++++++++++++++++++++++++++++++++++++++++++ debian/rsync-backup.install | 2 + rsync-backup.8 | 1 + 5 files changed, 514 insertions(+) create mode 100644 check-bkp-status.8 create mode 100644 check-bkp-status.in diff --git a/Makefile.am b/Makefile.am index 413d541..90618b8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -99,6 +99,16 @@ update-bkp-index: update-bkp-index.in Makefile chmod +x update-bkp-index.new && \ mv update-bkp-index.new update-bkp-index +sbin_SCRIPTS += check-bkp-status +dist_man_MANS += check-bkp-status.8 +CLEANFILES += check-bkp-status +EXTRA_DIST += check-bkp-status.in +check-bkp-status: check-bkp-status.in Makefile + $(SUBST) >check-bkp-status.new \ + $(srcdir)/check-bkp-status.in $(SUBSTVARS) && \ + chmod +x check-bkp-status.new && \ + mv check-bkp-status.new check-bkp-status + bin_SCRIPTS += fshash dist_man_MANS += fshash.1 CLEANFILES += fshash diff --git a/check-bkp-status.8 b/check-bkp-status.8 new file mode 100644 index 0000000..c76ed9c --- /dev/null +++ b/check-bkp-status.8 @@ -0,0 +1,60 @@ +.ie t .ds o \(bu +.el .ds o o +.de hP +.IP +\h'-\w'\fB\\$1\ \fP'u'\fB\\$1\ \fP\c +.. +.TH check-bkp-status 8 "16 January 2014" rsync-backup +.SH NAME +check-bkp-status \- write backup report +.SH SYNOPSIS +.B check-bkp-status +.RB [ \-v ] +.RB [ \-c +.IR config-file ] +.RB [ \-f +.IR format ] +.SH DESCRIPTION +The +.B check-bkp-status +script writes to its standard output a report about the current backup +status by checking the index database and logfiles written by +.BR rsync-backup (8). +.PP +The following command-line options are recognized. +.TP +.B \-h +Show a brief help message for the program, and exit successfully. +.TP +.B \-V +Show +.BR check-bkp-status 's +version number and some choice pieces of build-time configuration, and +exit successfully. +.TP +.BI "\-c " conf +Read +.I conf +instead of the default configuration file (shown as +.B conf +in the +.B \-V +output). +.TP +.BI "\-f " format +Write output in +.IR format , +which may be +.B txt +for plain text output, suitable for email, or +.B html +for HTML output, suitable for use as a web page. +.TP +.B \-v +Write information for all backups, rather than just those which failed. +By default, if all backups are up-to-date, then no output is produced at +all. +.SH SEE ALSO +.BR rsync-backup (8). +.SH AUTHOR +Mark Wooding, diff --git a/check-bkp-status.in b/check-bkp-status.in new file mode 100644 index 0000000..15afadd --- /dev/null +++ b/check-bkp-status.in @@ -0,0 +1,441 @@ +#! @BASH@ +### +### Check that dumps have been made as expected. +### +### (c) 2013 Mark Wooding +### + +###----- Licensing notice --------------------------------------------------- +### +### This file is part of the `rsync-backup' program. +### +### rsync-backup is free software; you can redistribute it and/or modify +### it under the terms of the GNU General Public License as published by +### the Free Software Foundation; either version 2 of the License, or +### (at your option) any later version. +### +### rsync-backup is distributed in the hope that it will be useful, +### but WITHOUT ANY WARRANTY; without even the implied warranty of +### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +### GNU General Public License for more details. +### +### You should have received a copy of the GNU General Public License +### along with rsync-backup; if not, write to the Free Software Foundation, +### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +set -e + +quis=${0##*/} +. @pkgdatadir@/lib.sh + +###-------------------------------------------------------------------------- +### Stubs for the configuration file. + +defhook () { :; } +addhook () { :; } + +retain () { :; } +snaptype () { :; } +like () { :; } +retry () { :; } +user () { :; } + +###-------------------------------------------------------------------------- +### Output format switch. + +formats=: +defformat () { formats=$formats$1:; } +fmtstate=begin + +fmt () { + state=$1; shift + + while :; do + ostate=$fmtstate + case $fmtstate in $state) break ;; esac + case "$fmtstate,$state" in + begin,end) + fmtstate=end + ;; + begin,*) + ${fmt}_header "$@" + fmtstate=hosttbl_begin + ;; + hosttbl_begin,hosttbl_*) + ${fmt}_hosttbl_begin "$@" + fmtstate=hosttbl_host + ;; + hosttbl_host,hosttbl_fs) + fmtstate=hosttbl_fs + ;; + hosttbl_fs,hosttbl_host) + ${fmt}_hosttbl_sep "$@" + fmtstate=hosttbl_host + ;; + hosttbl_begin,* | hosttbl_end,*) + fmtstate=logdump_begin + ;; + hosttbl_*,*) + ${fmt}_hosttbl_end "$@" + fmtstate=hosttbl_end + ;; + logdump_begin,logdump_*) + fmtstate=logdump_out + ;; + logdump_out,logdump_info | logdump_out,logdump_file) + fmtstate=$state + ;; + logdump_*,logdump_begin) + ${fmt}_logdump_end "$@" + fmtstate=logdump_begin + ;; + logdump_end,*) + fmtstate=footer + ;; + logdump_*,*) + fmtstate=logdump_end + ;; + footer,end) + ${fmt}_footer "$@" + fmtstate=end + ;; + esac + case $fmtstate in + "$ostate") + echo >&2 "$quis: FATAL! NO PROGRESS IN FMT STATE MACHINE" + exit 9 + ;; + esac + done + + ${fmt}_$fmtstate "$@" +} + +###-------------------------------------------------------------------------- +### Plain text output. + +defformat txt + +txt_header () { :; } +txt_hosttbl_begin () { :; } +txt_hosttbl_host () { echo "HOST $1"; } +txt_hosttbl_fs () { printf " %-23s %s\n" "$2" "$4"; } +txt_hosttbl_sep () { echo; } +txt_hosttbl_end () { :; } + +txt_logdump_begin () { + cat < + + + $now rsync-backup report + + + + +

rsync-backup report: $now

+EOF +} + +html_hosttbl_begin () { + cat <Overview +EOF +} + +html_hosttbl_host () { + cat < + $1 +EOF +} + +html_hosttbl_fs () { + case $3 in + winning) link="" knil="" ;; + *) link="" knil="";; + esac + cat < + $2 + $link$4$knil +EOF +} + +html_hosttbl_sep () { + cat < +EOF +} + +html_hosttbl_end () { + cat < +EOF +} + +html_logdump_begin () { + cat <Log tail for $1:$2 +EOF +} + +html_logdump_info () { + cat <$3 +EOF +} + +html_logdump_file () { + cat < +EOF + cat "$3" + cat < +EOF +} + +html_logdump_end () { :; } + +html_footer () { + cat < + Checked at $now $now_time. +
rsync-backup $VERSION; © 2014 Mark Wooding + + + + +EOF +} + +html_end () { :; } + +###-------------------------------------------------------------------------- +### Main checking. + +INDEXDB=@pkglocalstatedir@/index.db + +host () { host=$1; } + +patterns= +showhost= +failures= + +backup () { + for fs in "$@"; do + case $fs in *:*) fs=${fs%%:*} ;; esac + matchp=nil + for p in "${patterns[@]}"; do + case $host:$fs in $p) matchp=t; break ;; esac + done + case $matchp in nil) return ;; esac + when=$(sqlite3 $INDEXDB \ + "SELECT MAX(date) FROM idx WHERE host = '$host' AND fs = '$fs';") + case $when in + "") + class=never + info="NEVER" + show=t + win=nil + ;; + "$now") + class=winning + info="today" + show=$verbose + win=t + ;; + *) + jdn=$(julian "$when") + ago=$(( $now_jdn - $jdn )) + case $ago in 1 | -1) days=day ;; *) days=days ;; esac + case $ago in + -*) class=future; info="${ago#-} $days in the FUTURE" ;; + 1 | 2) class=failed; info="$ago $days ago" ;; + *) class=broken; info="$ago $days ago" ;; + esac + show=t + win=nil + ;; + esac + case $show in + t) + case $showhost in + "$host") ;; + *) + fmt hosttbl_host $host + showhost=$host + ;; + esac + fmt hosttbl_fs $host $fs $class "$info" + case $win in + nil) failures="$failures $host:$fs" ;; + esac + ;; + esac + done +} + +failure_logs () { + for fail in $failures; do + host=${fail%:*} fs=${fail##*:} + any=nil + for i in "$logdir/$host/$fs.$now#"*; do + if [ -f "$i" ]; then log=$i; any=t; fi + done + fmt logdump_begin $host $fs + case $any in + t) fmt logdump_file $host $fs "$log" ;; + nil) fmt logdump_info $host $fs "No log! No backup attempted." ;; + esac + done +} + +###-------------------------------------------------------------------------- +### Read the configuration and we're done. + +usage () { + echo "usage: $quis [-v] [-c CONF] [-f FORMAT] [PATTERNS...]" +} + +version () { + echo "$quis, rsync-backup version $VERSION" +} + +verbose=nil + +while getopts "hVc:f:v" opt; do + case "$opt" in + h) usage; exit 0 ;; + V) version; config; exit 0 ;; + c) conf=$OPTARG ;; + f) + case $formats in + *":$OPTARG:"*) ;; + *) echo >&2 "$0: unknown format \`$OPTARG'"; exit 1 ;; + esac + fmt=$OPTARG + ;; + v) verbose=t ;; + *) exit 1 ;; + esac +done +shift $((OPTIND - 1)) +case $# in + 0) declare -a patterns=("*") ;; + *) declare -a patterns=("$@") ;; +esac + +now=$(date +"%Y-%m-%d") +now_time=$(date +"%H:%M:%S %z") +now_jdn=$(julian $now) +. "$conf" +failure_logs +fmt end + +###----- That's all, folks -------------------------------------------------- diff --git a/debian/rsync-backup.install b/debian/rsync-backup.install index 99ef749..58f4674 100644 --- a/debian/rsync-backup.install +++ b/debian/rsync-backup.install @@ -1,5 +1,7 @@ /usr/sbin/rsync-backup +/usr/sbin/check-bkp-status /usr/sbin/update-bkp-index /usr/share/rsync-backup/lib.sh /usr/share/man/man8/rsync-backup.8 +/usr/share/man/man8/check-bkp-status.8 /usr/share/man/man8/update-bkp-index.8 diff --git a/rsync-backup.8 b/rsync-backup.8 index 04a489a..5ff20bc 100644 --- a/rsync-backup.8 +++ b/rsync-backup.8 @@ -551,6 +551,7 @@ There is also a symbolic link .B last referring to the most recent backup of the filesystem. .SH SEE ALSO +.BR check-bkp-status (8), .BR fshash (1), .BR lvm (8), .BR rfreezefs (8), -- 2.11.0