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