chiark / gitweb /
Index: debian/changelog
[chiark-utils.git] / backup / snaprsync
1 #!/bin/bash
2 #
3 # usage: snaprsync <setting>... <positionals>
4 #  <setting> is --<name>=<value>
5 #  <positionals> are assigned to unused mandatory values in order
6 # mandatory:
7 #   rhost device mountpoint localarea 
8 # optional:
9         localprevious=
10         snapkind=lvm
11         rsharedir=/usr/share/chiark-backup 
12         retcdir=/etc/chiark-backup
13         rvardir=/var/lib/chiark-backup
14         bwlimit=
15         subdir=.
16         rsyncopts=
17         summer=summer
18
19 set -e
20
21 badusage () { echo >&2 "snaprsync: bad usage: $1"; exit 12; }
22 x () { echo "+ $@"; "$@"; }
23 xspawned () { eval "${1}pid=$!; echo \"+[$!] ($1) &\";"; }
24 xwait () { eval "echo \"+[\$${1}pid] ($1)...\"; wait \$${1}pid;"; }
25
26 while true; do
27         case "$1" in
28         --?*=*)
29                 name=${1#--}; name=${name%%=*}
30                 value=${1#--*=}
31                 case "$name" in
32                 rhost|device|mountpoint|localarea);;
33                 localprevious|snapkind|rsharedir|retcdir|rvardir|bwlimit);;
34                 subdir|rsyncopts|summer);;
35                 *) badusage "unknown setting $name";;
36                 esac
37                 eval "$name=\$value"
38                 ;;
39         --)     shift; break ;;
40         -*)     badusage "unknown option $1" ;;
41         *)      break ;;
42         esac
43         shift
44 done
45
46 for name in rhost device mountpoint localarea; do
47         eval "value=\$$name"
48         if [ "x$value" != x ]; then continue; fi
49         if [ $# = 0 ]; then badusage "no value for setting $name"; fi
50         eval "$name=$1"
51         shift
52 done
53
54 datefmt='%Y-%m-%d %H:%M:%S Z'
55 rsync="rsync ${bwlimit:+--bwlimit} $bwlimit"
56 export RSYNC_RSH='ssh -o compression=no'
57 sshpfx='PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin; export PATH; '
58
59 ssh $rhost "$sshpfx date -u '+$rhost $datefmt start'"
60 ssh $rhost "$sshpfx id"
61 ssh $rhost "$sshpfx ls -d $rsharedir"
62 ssh $rhost "$sshpfx ls -d $rvardir"
63
64 test -d $localarea || x mkdir $localarea
65 ournode=`uname -n`
66 rsumsfile=for-$ournode.sums
67 summer="$summer -ACDbtqf"
68
69 td=/dev/enoent
70 rc=12
71 trap 'rm -rf $td; exit $rc' 0
72 td=`mktemp -td`
73
74 mkfifo -m 600 $td/sentinel
75 exec 4<>$td/sentinel
76
77 x ssh $rhost "$sshpfx $rsharedir/snap-drop"
78 ssh $rhost "
79         $sshpfx
80         set -e
81         cd $rvardir
82         echo '$retcdir/snap/$snapkind drop $rvardir' >snap-drop.new
83         mv snap-drop.new snap-drop
84 "
85 x ssh $rhost "$sshpfx $retcdir/snap/$snapkind snap $rvardir $device $mountpoint"
86 ssh $rhost <$td/sentinel 4<&- "
87   $sshpfx
88   set -e
89   date -u '+$rhost $datefmt main'
90   exec 3<&0 0</dev/null
91   (set +e; read x <&3; kill 0) &
92   cd $rvardir
93   umask 077
94   exec 3>$rsumsfile
95   cd snap-mount
96   $summer . >&3
97   date -u '+$rhost $datefmt sumsdone'
98   cd ..
99 " &
100 xspawned rsum
101 x $rsync -aHSxz --numeric-ids --delete $rsyncopts \
102         ${localprevious:+--link-dest} $localprevious \
103         $rhost:$rvardir/snap-mount/$subdir $localarea/.
104 date -u "+ $datefmt rsyncdone"
105
106 exec 3>$localarea,lsums
107 (cd $localarea && \
108  $summer . >&3) &
109 xspawned lsum
110 exec 3>&-
111
112 xwait rsum
113 exec 4<&-
114 date -u "+ $datefmt sumsdone"
115 x ssh $rhost "$sshpfx $rsharedir/snap-drop"
116
117 if [ "x${localprevious}" != x ] && test -f "$localprevious,rsums"; then
118         cp "$localprevious,rsums" "$localarea,rsums"
119 fi
120 x $rsync -p \
121         $rhost:$rvardir/$rsumsfile \
122         "$localarea,rsums"
123
124 xwait $lsum
125 date -u "+ $datefmt checking"
126
127 set +e
128 diff -u "$localarea,rsums" "$localarea,lsums" >"$localarea,sumsdiff"
129 diffrc=$?
130 set -e
131 test $diffrc = 0 || test $diffrc = 1
132
133 date -u "+ $datefmt checked $diffrc"
134 rc=$diffrc