rdiff,dup: fix include/exclude paths with spaces (Closes: #398435)
[matthijs/upstream/backupninja.git] / handlers / dup.in
1 # -*- mode: sh; sh-basic-offset: 3; indent-tabs-mode: nil; -*-
2 # vim: set filetype=sh sw=3 sts=3 expandtab autoindent:
3 #
4 # duplicity script for backupninja
5 # requires duplicity
6 #
7
8 getconf options
9 getconf testconnect yes
10 getconf nicelevel 0
11 getconf tmpdir
12
13 setsection gpg
14 getconf password
15 getconf sign no
16 getconf encryptkey
17 getconf signkey
18
19 setsection source
20 getconf include
21 getconf vsnames all
22 getconf vsinclude
23 getconf exclude
24
25 setsection dest
26 getconf incremental yes
27 getconf keep 60
28 getconf desturl
29 getconf sshoptions
30 getconf bandwidthlimit 0
31 getconf desthost
32 getconf destdir
33 getconf destuser
34 destdir=${destdir%/}
35
36 ### SANITY CHECKS ##############################################################
37
38 [ -n "$desturl" -o -n "$destdir" ]  || fatal "The destination directory (destdir) must be set when desturl is not used."
39 [ -n "$include" -o -n "$vsinclude" ]  || fatal "No source includes specified"
40 [ -n "$password" ] || fatal "The password option must be set."
41
42 ### VServers
43 # If vservers are configured, check that the ones listed in $vsnames do exist.
44 local usevserver=no
45 if [ $vservers_are_available = yes ]; then
46    if [ "$vsnames" = all ]; then
47       vsnames="$found_vservers"
48    else
49       if ! vservers_exist "$vsnames" ; then
50             fatal "At least one of the vservers listed in vsnames ($vsnames) does not exist."
51       fi
52    fi
53    if [ -n "$vsinclude" ]; then
54       info "Using vservers '$vsnames'"
55       usevserver=yes
56    fi
57 else
58    [ -z "$vsinclude" ] || warning 'vservers support disabled in backupninja.conf, vsincludes configuration lines will be ignored'
59 fi
60
61 ### See if we can login on $desthost
62 if [ "$testconnect" == "yes" ]; then
63    if [ -n "$desturl" ]; then
64       warning 'testconnect can not be used when desturl is set'
65    else
66       debug "ssh $sshoptions -o PasswordAuthentication=no $desthost -l $destuser 'echo -n 1'"
67       if [ ! $test ]; then
68          result=`ssh $sshoptions -o PasswordAuthentication=no $desthost -l $destuser 'echo -n 1'`
69          if [ "$result" != "1" ]; then
70             fatal "Can't connect to $desthost as $destuser."
71          else
72             debug "Connected to $desthost as $destuser successfully"
73          fi
74       fi
75    fi
76 fi
77
78 ### COMMAND-LINE MANGLING ######################################################
79
80 ### initialize $execstr*
81 execstr_command=
82 execstr_options="$options --no-print-statistics"
83 execstr_source=
84 if [ -n "$desturl" ]; then
85    [ -z "$destuser" ] || warning 'the configured destuser is ignored since desturl is set'
86    [ -z "$desthost" ] || warning 'the configured desthost is ignored since desturl is set'
87    [ -z "$destdir" ] || warning 'the configured destdir is ignored since desturl is set'
88    execstr_serverpart="$desturl"
89 else
90    execstr_serverpart="scp://$destuser@$desthost/$destdir"
91 fi
92
93 ### duplicity version
94 duplicity_version="`duplicity --version | @AWK@ '{print $2}'`"
95 duplicity_major="`echo $duplicity_version | @AWK@ -F '.' '{print $1}'`"
96 duplicity_minor="`echo $duplicity_version | @AWK@ -F '.' '{print $2}'`"
97 duplicity_sub="`echo $duplicity_version | @AWK@ -F '.' '{print $3}'`"
98
99 ### ssh/scp/sftp options
100 # 1. duplicity >= 0.4.2 needs --sftp-command
101 #    (NB: sftp does not support the -l option)
102 # 2. duplicity 0.4.3 to 0.4.9 replace --ssh-command with --ssh-options, which is
103 #    passed to scp and sftp commands by duplicity. We don't use it: since this
104 #    version does not use the ssh command anymore, we keep compatibility with
105 #    our previous config files by passing $sshoptions to --scp-command and
106 #    --sftp-command ourselves
107
108 scpoptions="$sshoptions"
109 if [ "$bandwidthlimit" != 0 ]; then
110    [ -z "$desturl" ] || warning 'The bandwidthlimit option is not used when desturl is set.'
111    scpoptions="$scpoptions -l $bandwidthlimit"
112 fi
113
114 # < 0.4.2 : only uses ssh and scp
115 if [ "$duplicity_major" -le 0 -a "$duplicity_minor" -le 4 -a "$duplicity_sub" -lt 2 ]; then
116    execstr_options="${execstr_options} --scp-command 'scp $scpoptions' --ssh-command 'ssh $sshoptions'"
117 # >= 0.4.2 : also uses sftp, --sftp-command option is now supported
118 else
119    sftpoptions="$sshoptions"
120    # == 0.4.2 : uses ssh, scp and sftp
121    if [ "$duplicity_major" -eq 0 -a "$duplicity_minor" -eq 4 -a "$duplicity_sub" -eq 2 ]; then
122       execstr_options="${execstr_options} --scp-command 'scp $scpoptions' --sftp-command 'sftp $sftpoptions' --ssh-command 'ssh $sshoptions'"
123    # >= 0.4.3 : uses only scp and sftp, --ssh-command option is not supported anymore
124    else
125       execstr_options="${execstr_options} --scp-command 'scp $scpoptions' --sftp-command 'sftp $sftpoptions'"
126    fi
127 fi
128
129 ### Symmetric or asymmetric (public/private key pair) encryption
130 if [ -n "$encryptkey" ]; then
131    execstr_options="${execstr_options} --encrypt-key $encryptkey"
132    debug "Data will be encrypted with the GnuPG key $encryptkey."
133 else
134    debug "Data will be encrypted using symmetric encryption."
135 fi
136
137 ### Data signing (or not)
138 if [ "$sign" == yes ]; then
139    # duplicity is not able to sign data when using symmetric encryption
140    [ -n "$encryptkey" ] || fatal "The encryptkey option must be set when signing."
141    # if needed, initialize signkey to a value that is not empty (checked above)
142    [ -n "$signkey" ] || signkey="$encryptkey"
143    execstr_options="${execstr_options} --sign-key $signkey"
144    debug "Data will be signed will the GnuPG key $signkey."
145 else
146    debug "Data won't be signed."
147 fi
148
149 ### Incremental or full backup mode
150 # If incremental==yes, use the default duplicity behaviour: perform an
151 # incremental backup if old signatures can be found, else switch to
152 # full backup.
153 # If incremental==no, force a full backup anyway.
154 if [ "$incremental" == "no" ]; then
155    # before 0.4.4, full was an option and not a command
156    if [ "$duplicity_major" -le 0 -a "$duplicity_minor" -le 4 -a "$duplicity_sub" -lt 4 ]; then
157       execstr_options="${execstr_options} --full"
158    else
159       execstr_command="full"
160    fi
161 fi
162
163 ### Temporary directory
164 precmd=
165 if [ -n "$tmpdir" ]; then
166    if [ ! -d "$tmpdir" ]; then
167       info "Temporary directory ($tmpdir) does not exist, creating it."
168       mkdir -p "$tmpdir"
169       [ $? -eq 0 ] || fatal "Could not create temporary directory ($tmpdir)."
170       chmod 0700 "$tmpdir"
171    fi
172    info "Using $tmpdir as TMPDIR"
173    precmd="${precmd}TMPDIR=$tmpdir "
174 fi
175
176 ### Cleanup old backup sets (or not)
177 if [ "$keep" != "yes" ]; then
178    if [ "`echo $keep | tr -d 0-9`" == "" ]; then
179       keep="${keep}D"
180    fi
181    # before 0.4.4, remove-older-than was an option and not a command
182    if [ "$duplicity_major" -le 0 -a "$duplicity_minor" -le 4 -a "$duplicity_sub" -lt 4 ]; then
183       execstr_options="${execstr_options} --remove-older-than $keep"
184    fi
185 fi
186
187 ### Source
188
189 set -o noglob
190
191 # excludes
192 SAVEIFS=$IFS
193 IFS=$(echo -en "\n\b")
194 for i in $exclude; do
195    str="${i//__star__/*}"
196    execstr_source="${execstr_source} --exclude '$str'"
197 done
198 IFS=$SAVEIFS
199
200 # includes
201 SAVEIFS=$IFS
202 IFS=$(echo -en "\n\b")
203 for i in $include; do
204    [ "$i" != "/" ] || fatal "Sorry, you cannot use 'include = /'"
205    str="${i//__star__/*}"
206    execstr_source="${execstr_source} --include '$str'"
207 done
208 IFS=$SAVEIFS
209
210 # vsincludes
211 if [ $usevserver = yes ]; then
212    for vserver in $vsnames; do
213       SAVEIFS=$IFS
214       IFS=$(echo -en "\n\b")
215       for vi in $vsinclude; do
216          str="${vi//__star__/*}"
217          str="$VROOTDIR/$vserver$str"
218          execstr_source="${execstr_source} --include '$str'"
219       done
220       IFS=$SAVEIFS
221    done
222 fi
223
224 set +o noglob
225
226 ### EXECUTE ####################################################################
227
228 execstr_source=${execstr_source//\\*/\\\\\\*}
229
230 ### Cleanup commands (duplicity >= 0.4.4)
231
232 # cleanup
233 if [ "$duplicity_major" -ge 0 -a "$duplicity_minor" -ge 4 -a "$duplicity_sub" -ge 4 ]; then
234    debug "$precmd duplicity cleanup --force $execstr_options $execstr_serverpart"
235    if [ ! $test ]; then
236       export PASSPHRASE=$password
237       output=`nice -n $nicelevel \
238          su -c \
239          "$precmd duplicity cleanup --force $execstr_options $execstr_serverpart 2>&1"`
240       exit_code=$?
241       if [ $exit_code -eq 0 ]; then
242          debug $output
243          info "Duplicity cleanup finished successfully."
244       else
245          debug $output
246          warning "Duplicity cleanup failed."
247       fi
248    fi
249 fi
250
251 # remove-older-than
252 if [ "$keep" != "yes" ]; then
253    if [ "$duplicity_major" -ge 0 -a "$duplicity_minor" -ge 4 -a "$duplicity_sub" -ge 4 ]; then
254       debug "$precmd duplicity remove-older-than $keep --force $execstr_options $execstr_serverpart"
255       if [ ! $test ]; then
256          export PASSPHRASE=$password
257          output=`nice -n $nicelevel \
258                    su -c \
259                       "$precmd duplicity remove-older-than $keep --force $execstr_options $execstr_serverpart 2>&1"`
260          exit_code=$?
261          if [ $exit_code -eq 0 ]; then
262             debug $output
263             info "Duplicity remove-older-than finished successfully."
264          else
265             debug $output
266             warning "Duplicity remove-older-than failed."
267          fi
268       fi
269    fi
270 fi
271
272 ### Backup command
273 debug "$precmd duplicity $execstr_command $execstr_options $execstr_source --exclude '**' / $execstr_serverpart"
274 if [ ! $test ]; then
275    outputfile=`maketemp backupout`
276    export PASSPHRASE=$password
277    output=`nice -n $nicelevel \
278              su -c \
279                 "$precmd duplicity $execstr_command $execstr_options $execstr_source --exclude '**' / $execstr_serverpart >$outputfile 2>&1"`
280    exit_code=$?
281    debug $output
282    cat $outputfile | (while read output ; do
283                          info $output
284                       done
285    )
286    if [ $exit_code -eq 0 ]; then
287       info "Duplicity finished successfully."
288    else
289       fatal "Duplicity failed."
290    fi
291    rm $outputfile
292 fi
293
294 return 0