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