chiark / gitweb /
git-cache-proxy: housekeeping: check errno value from stat after deletion
[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         rsynccompress=z
18         sshopts=
19         summer=summer
20
21
22 # snaprsync
23 #
24 # This file is part of chiark backup, a system for backing up GNU/Linux and
25 # other UN*X-compatible machines, as used on chiark.greenend.org.uk.
26 #
27 # chiark backup is:
28 #  Copyright (C) 1997-1998,2000-2001,2007
29 #                     Ian Jackson <ian@chiark.greenend.org.uk>
30 #  Copyright (C) 1999 Peter Maydell <pmaydell@chiark.greenend.org.uk>
31 #
32 # This is free software; you can redistribute it and/or modify it under the
33 # terms of the GNU General Public License as published by the Free Software
34 # Foundation; either version 3, or (at your option) any later version.
35 #
36 # This is distributed in the hope that it will be useful, but WITHOUT ANY
37 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
38 # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
39 # details.
40 #
41 # You should have received a copy of the GNU General Public License along
42 # with this program; if not, consult the Free Software Foundation's
43 # website at www.fsf.org, or the GNU Project website at www.gnu.org.
44
45
46 set -e
47
48 badusage () { echo >&2 "snaprsync: bad usage: $1"; exit 12; }
49 nb_echo () { (echo "$@"); } # See Debian #382798
50 x () { nb_echo "+ $@"; "$@"; }
51 xspawned () { eval "${1}pid=$!; nb_echo \"+[$!] ($1) &\";"; }
52 xwait () { eval "nb_echo \"+[\$${1}pid] ($1)...\"; wait \$${1}pid;"; }
53
54 while true; do
55         case "$1" in
56         --?*=*)
57                 name=${1#--}; name=${name%%=*}
58                 value=${1#--*=}
59                 case "$name" in
60                 rhost|device|mountpoint|localarea);;
61                 localprevious|snapkind|rsharedir|retcdir|rvardir|bwlimit);;
62                 subdir|rsyncopts|rsynccompress|sshopts|summer);;
63                 *) badusage "unknown setting $name";;
64                 esac
65                 eval "$name=\$value"
66                 ;;
67         --)     shift; break ;;
68         -*)     badusage "unknown option $1" ;;
69         *)      break ;;
70         esac
71         shift
72 done
73
74 for name in rhost device mountpoint localarea; do
75         eval "value=\$$name"
76         if [ "x$value" != x ]; then continue; fi
77         if [ $# = 0 ]; then badusage "no value for setting $name"; fi
78         eval "$name=$1"
79         shift
80 done
81
82 datefmt='%Y-%m-%d %H:%M:%S Z'
83 rsync="rsync ${bwlimit:+--bwlimit} $bwlimit"
84 export RSYNC_RSH="ssh -o compression=no $sshopts"
85 sshpfx='PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin; export PATH; '
86
87 ssh $sshopts $rhost "$sshpfx date -u '+$rhost $datefmt start'"
88 ssh $sshopts $rhost "$sshpfx id"
89 ssh $sshopts $rhost "$sshpfx ls -d $rsharedir"
90 ssh $sshopts $rhost "$sshpfx ls -d $rvardir"
91
92 test -d $localarea || x mkdir $localarea
93 ournode=`uname -n`
94 rsumsfile=for-$ournode.sums
95 summer="$summer -ACDBtqfx"
96
97 td=/dev/enoent
98 rc=12
99 trap 'rm -rf $td; exit $rc' 0
100 td=`mktemp -td`
101
102 mkfifo -m 600 $td/sentinel
103 exec 4<>$td/sentinel
104
105 x ssh $sshopts $rhost "$sshpfx $rsharedir/snap-drop $rvardir"
106 x ssh $sshopts $rhost "
107         $sshpfx
108         set -e
109         cd $rvardir
110         echo '$retcdir/snap/$snapkind drop $rvardir' >snap-drop.new
111         mv snap-drop.new snap-drop
112 "
113 x ssh $sshopts $rhost "$sshpfx $retcdir/snap/$snapkind snap $rvardir $device $mountpoint"
114 ssh $sshopts $rhost <$td/sentinel 4<&- "
115   $sshpfx
116   set -e
117   date -u '+$rhost $datefmt main'
118   exec 3<&0 0</dev/null
119   (set +e; read x <&3; kill 0) &
120   cd $rvardir
121   umask 077
122   exec 3>$rsumsfile
123   cd snap-mount
124   $summer . >&3
125   date -u '+$rhost $datefmt sumsdone'
126   cd ..
127 " &
128 xspawned rsum
129 x $rsync -aHSx$rsynccompress --numeric-ids --delete $rsyncopts \
130         ${localprevious:+--link-dest} $localprevious \
131         $rhost:$rvardir/snap-mount/$subdir $localarea/.
132 date -u "+ $datefmt rsyncdone"
133
134 exec 3>$localarea,lsums
135 (cd $localarea && \
136  $summer . >&3) &
137 xspawned lsum
138 exec 3>&-
139
140 xwait rsum
141 exec 4<&-
142 date -u "+ $datefmt sumsdone"
143 x ssh $sshopts $rhost "$sshpfx $rsharedir/snap-drop $rvardir"
144
145 if [ "x${localprevious}" != x ] && test -f "$localprevious,rsums"; then
146         cp "$localprevious,rsums" "$localarea,rsums"
147 fi
148 x $rsync -pI \
149         $rhost:$rvardir/$rsumsfile \
150         "$localarea,rsums"
151
152 xwait $lsum
153 date -u "+ $datefmt checking"
154
155 set +e
156 diff -u <(sed -e 's/^mountpoint/dir       /' "$localarea,rsums") \
157   "$localarea,lsums" >"$localarea,sumsdiff"
158 diffrc=$?
159 set -e
160 test $diffrc = 0 || test $diffrc = 1
161
162 date -u "+ $datefmt checked $diffrc"
163 rc=$diffrc