check-bkp-status.in: Include day-of-week name in the title.
[rsync-backup] / check-bkp-status.in
CommitLineData
9f0350f9
MW
1#! @BASH@
2###
3### Check that dumps have been made as expected.
4###
5### (c) 2013 Mark Wooding
6###
7
8###----- Licensing notice ---------------------------------------------------
9###
10### This file is part of the `rsync-backup' program.
11###
12### rsync-backup is free software; you can redistribute it and/or modify
13### it under the terms of the GNU General Public License as published by
14### the Free Software Foundation; either version 2 of the License, or
15### (at your option) any later version.
16###
17### rsync-backup is distributed in the hope that it will be useful,
18### but WITHOUT ANY WARRANTY; without even the implied warranty of
19### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20### GNU General Public License for more details.
21###
22### You should have received a copy of the GNU General Public License
23### along with rsync-backup; if not, write to the Free Software Foundation,
24### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26set -e
27
28quis=${0##*/}
29. @pkgdatadir@/lib.sh
30
31###--------------------------------------------------------------------------
32### Stubs for the configuration file.
33
34defhook () { :; }
35addhook () { :; }
36
37retain () { :; }
38snaptype () { :; }
39like () { :; }
40retry () { :; }
41user () { :; }
42
43###--------------------------------------------------------------------------
44### Output format switch.
45
46formats=:
47defformat () { formats=$formats$1:; }
48fmtstate=begin
49
50fmt () {
51 state=$1; shift
52
53 while :; do
54 ostate=$fmtstate
55 case $fmtstate in $state) break ;; esac
56 case "$fmtstate,$state" in
57 begin,end)
58 fmtstate=end
59 ;;
60 begin,*)
61 ${fmt}_header "$@"
62 fmtstate=hosttbl_begin
63 ;;
64 hosttbl_begin,hosttbl_*)
65 ${fmt}_hosttbl_begin "$@"
66 fmtstate=hosttbl_host
67 ;;
68 hosttbl_host,hosttbl_fs)
69 fmtstate=hosttbl_fs
70 ;;
71 hosttbl_fs,hosttbl_host)
72 ${fmt}_hosttbl_sep "$@"
73 fmtstate=hosttbl_host
74 ;;
75 hosttbl_begin,* | hosttbl_end,*)
76 fmtstate=logdump_begin
77 ;;
78 hosttbl_*,*)
79 ${fmt}_hosttbl_end "$@"
80 fmtstate=hosttbl_end
81 ;;
82 logdump_begin,logdump_*)
83 fmtstate=logdump_out
84 ;;
85 logdump_out,logdump_info | logdump_out,logdump_file)
86 fmtstate=$state
87 ;;
88 logdump_*,logdump_begin)
89 ${fmt}_logdump_end "$@"
90 fmtstate=logdump_begin
91 ;;
92 logdump_end,*)
93 fmtstate=footer
94 ;;
95 logdump_*,*)
96 fmtstate=logdump_end
97 ;;
98 footer,end)
99 ${fmt}_footer "$@"
100 fmtstate=end
101 ;;
102 esac
103 case $fmtstate in
104 "$ostate")
105 echo >&2 "$quis: FATAL! NO PROGRESS IN FMT STATE MACHINE"
106 exit 9
107 ;;
108 esac
109 done
110
111 ${fmt}_$fmtstate "$@"
112}
113
114###--------------------------------------------------------------------------
115### Plain text output.
116
117defformat txt
118
119txt_header () { :; }
120txt_hosttbl_begin () { :; }
121txt_hosttbl_host () { echo "HOST $1"; }
122txt_hosttbl_fs () { printf " %-23s %s\n" "$2" "$4"; }
123txt_hosttbl_sep () { echo; }
124txt_hosttbl_end () { :; }
125
126txt_logdump_begin () {
127 cat <<EOF
128
129-----------------------------------------------------------------------------
130Log tail for $1:$2
131
132EOF
133}
134
135txt_logdump_info () { echo "!!! $3"; }
136txt_logdump_file () { cat "$3"; }
137txt_logdump_end () { :; }
138
139txt_footer () { :; }
140txt_end () { :; }
141
142fmt=txt
143
144###--------------------------------------------------------------------------
145### HTML output.
146
147defformat html
148
149html_header () {
150 cat <<EOF
151<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
152 "http://www.w3c.org/TR/html4/strict.dtd">
153<html>
154<head>
155 <title>$now rsync-backup report</title>
156 <style type='text/css'><!--
157 body {
158 background: white;
159 color: black;
160 margin: 1ex 2em;
161 }
162
163 h1, h2 { font-family: sans-serif; font-weight: bold; }
164
165 h1 {
166 padding-bottom: 1ex;
167 border-bottom: solid medium black;
168 margin-bottom: 3ex;
169 font-size: 200%;
170 }
171
172 h2 {
173 border-top: solid thin black;
174 padding-top: 1ex;
175 margin-top: 3ex;
176 font-size: x-large;
177 }
178
179 h1 + h2 {
180 border-top: none;
181 padding-top: 0;
182 }
183
184 div.footer {
185 border-top: solid medium black;
186 margin-top: 3ex;
187 padding-top: 1ex;
188 font-size: small;
189 clear: both;
190 text-align: right;
191 font-style: italic;
192 }
193
194 table.hosttbl {
195 border-collapse: collapse;
196 display: inline-table;
197 margin: 1ex 1em;
198 }
199 table.hosttbl tr.fs td {
200 border: solid thin black;
201 }
202 table.hosttbl td { padding: 0.5ex 0.5em; }
203 table.hosttbl tr.host td {
204 padding-top: 2ex;
205 text-align: center;
206 font-weight: bold;
207 font-family: monospace;
208 }
209 table.hosttbl td.fs {
210 font-family: monospace;
211 }
212
213 table.hosttbl td.winning { background: #2f4; }
214 table.hosttbl td.failed { background: #f80; }
215 table.hosttbl td.broken { background: #f11; }
216 table.hosttbl td.never { background: #66f; }
217
218 pre {
219 clear: both;
220 margin: 3ex 2em;
221 padding: 1ex;
222 background: #eee;
223 border: solid thin black;
224 overflow-y: auto;
225 }
226
227 div.logdump-info {
228 margin: 3ex 2em;
229 padding: 1ex;
230 background: #f11;
231 border: solid thin black;
232 }
233 --></style>
234</head>
235<body>
236
4064bd38 237<h1><tt>rsync-backup</tt> report: $now_dow $now</tt></h1>
9f0350f9
MW
238EOF
239}
240
241html_hosttbl_begin () {
242 cat <<EOF
243
244<h2>Overview</h2>
245EOF
246}
247
248html_hosttbl_host () {
249 cat <<EOF
250<table class=hosttbl>
251 <tr class=host><td colspan=2>$1</tc>
252EOF
253}
254
255html_hosttbl_fs () {
256 case $3 in
257 winning) link="" knil="" ;;
258 *) link="<a href='#log-$host:$fs'>" knil="</a>";;
259 esac
260 cat <<EOF
261 <tr class=fs>
262 <td class=fs>$2</td>
263 <td class=$3>$link$4$knil</td>
264EOF
265}
266
267html_hosttbl_sep () {
268 cat <<EOF
269</table>
270EOF
271}
272
273html_hosttbl_end () {
274 cat <<EOF
275</table>
276EOF
277}
278
279html_logdump_begin () {
280 cat <<EOF
281
282<h2><a name='log-$1:$2'>Log tail for <tt>$1:$2</tt></a></h2>
283EOF
284}
285
286html_logdump_info () {
287 cat <<EOF
288<div class=logdump-info>$3</div>
289EOF
290}
291
292html_logdump_file () {
293 cat <<EOF
294<pre class=logdump>
295EOF
296 cat "$3"
297 cat <<EOF
298</pre>
299EOF
300}
301
302html_logdump_end () { :; }
303
304html_footer () {
305 cat <<EOF
306
307<div class=footer>
308 Checked at $now $now_time.
309 <br><tt>rsync-backup</tt> $VERSION; &copy; 2014 Mark Wooding
310</div>
311
312</body>
313</html>
314EOF
315}
316
317html_end () { :; }
318
319###--------------------------------------------------------------------------
320### Main checking.
321
322INDEXDB=@pkglocalstatedir@/index.db
323
324host () { host=$1; }
325
326patterns=
327showhost=
328failures=
329
330backup () {
331 for fs in "$@"; do
332 case $fs in *:*) fs=${fs%%:*} ;; esac
333 matchp=nil
334 for p in "${patterns[@]}"; do
335 case $host:$fs in $p) matchp=t; break ;; esac
336 done
337 case $matchp in nil) return ;; esac
338 when=$(sqlite3 $INDEXDB \
339 "SELECT MAX(date) FROM idx WHERE host = '$host' AND fs = '$fs';")
340 case $when in
341 "")
342 class=never
343 info="NEVER"
344 show=t
345 win=nil
346 ;;
347 "$now")
348 class=winning
349 info="today"
350 show=$verbose
351 win=t
352 ;;
353 *)
354 jdn=$(julian "$when")
355 ago=$(( $now_jdn - $jdn ))
356 case $ago in 1 | -1) days=day ;; *) days=days ;; esac
357 case $ago in
358 -*) class=future; info="${ago#-} $days in the FUTURE" ;;
359 1 | 2) class=failed; info="$ago $days ago" ;;
360 *) class=broken; info="$ago $days ago" ;;
361 esac
362 show=t
363 win=nil
364 ;;
365 esac
366 case $show in
367 t)
368 case $showhost in
369 "$host") ;;
370 *)
371 fmt hosttbl_host $host
372 showhost=$host
373 ;;
374 esac
375 fmt hosttbl_fs $host $fs $class "$info"
376 case $win in
377 nil) failures="$failures $host:$fs" ;;
378 esac
379 ;;
380 esac
381 done
382}
383
384failure_logs () {
385 for fail in $failures; do
386 host=${fail%:*} fs=${fail##*:}
387 any=nil
388 for i in "$logdir/$host/$fs.$now#"*; do
389 if [ -f "$i" ]; then log=$i; any=t; fi
390 done
391 fmt logdump_begin $host $fs
392 case $any in
393 t) fmt logdump_file $host $fs "$log" ;;
394 nil) fmt logdump_info $host $fs "No log! No backup attempted." ;;
395 esac
396 done
397}
398
399###--------------------------------------------------------------------------
400### Read the configuration and we're done.
401
402usage () {
403 echo "usage: $quis [-v] [-c CONF] [-f FORMAT] [PATTERNS...]"
404}
405
406version () {
407 echo "$quis, rsync-backup version $VERSION"
408}
409
410verbose=nil
411
412while getopts "hVc:f:v" opt; do
413 case "$opt" in
414 h) usage; exit 0 ;;
415 V) version; config; exit 0 ;;
416 c) conf=$OPTARG ;;
417 f)
418 case $formats in
419 *":$OPTARG:"*) ;;
420 *) echo >&2 "$0: unknown format \`$OPTARG'"; exit 1 ;;
421 esac
422 fmt=$OPTARG
423 ;;
424 v) verbose=t ;;
425 *) exit 1 ;;
426 esac
427done
428shift $((OPTIND - 1))
429case $# in
430 0) declare -a patterns=("*") ;;
431 *) declare -a patterns=("$@") ;;
432esac
433
434now=$(date +"%Y-%m-%d")
435now_time=$(date +"%H:%M:%S %z")
4064bd38 436now_dow=$(date +"%A")
9f0350f9
MW
437now_jdn=$(julian $now)
438. "$conf"
439failure_logs
440fmt end
441
442###----- That's all, folks --------------------------------------------------