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