lib/tools.in(maketemp): really remove insecure fall-back if mktemp is missing, since...
[matthijs/upstream/backupninja.git] / handlers / dup.helper.in
1 # -*- mode: sh; sh-basic-offset: 3; indent-tabs-mode: nil; -*-
2
3 HELPERS="$HELPERS dup:incremental_encrypted_remote_filesystem_backup"
4
5 ### Functions
6
7 do_dup_host_includes() {
8    set -o noglob
9    # choose the files to backup
10    REPLY=
11    while [ -z "$REPLY" ]; do
12       formBegin "$dup_title - host system: includes"
13          [ -z "$dup_includes" ] && dup_includes="$dup_default_includes"
14          for i in $dup_includes; do
15             formItem include "$i"
16          done
17          formItem include ""
18          formItem include ""
19          formItem include ""
20          formDisplay
21       [ $? = 0 ] || return 1
22       dup_includes="$REPLY"
23    done
24    set +o noglob
25 }
26
27 do_dup_vserver() {
28    # choose the vservers to backup (into $selected_vservers)
29    choose_one_or_more_vservers "$dup_title"
30    [ $? = 0 ] || return 1
31
32    set -o noglob
33    # choose the files to backup
34    REPLY=
35    while [ -z "$REPLY" ]; do
36       formBegin "$dup_title - vservers: vsincludes (backup these directories from every selected vserver)"
37          [ -z "$dup_vsincludes" ] && dup_vsincludes="$dup_default_includes"
38          for i in $dup_vsincludes; do
39             formItem include "$i"
40          done
41          formItem include ""
42          formItem include ""
43          formItem include ""
44       formDisplay
45       [ $? = 0 ] || return 1
46       dup_vsincludes="$REPLY"
47    done
48    set +o noglob
49 }
50
51 do_dup_excludes() {
52    set -o noglob
53    formBegin "$dup_title: excludes"
54      [ -z "$dup_excludes" ] && dup_excludes="$dup_default_excludes"
55      for i in $dup_excludes; do
56         formItem exclude "$i"
57      done
58      formItem exclude ""
59      formItem exclude ""
60      formItem exclude ""
61    formDisplay
62    [ $? = 0 ] || return 1
63    dup_excludes="$REPLY"
64    set +o noglob
65 }
66
67 do_dup_src() {
68    choose_host_or_vservers_or_both "$dup_title"
69    [ $? = 0 ] || return 1
70    case $host_or_vservers in
71       'host')
72          do_dup_host_includes
73          [ $? = 0 ] || return 1
74          ;;
75       'vservers')
76          do_dup_vserver
77          [ $? = 0 ] || return 1
78          ;;
79       'both')
80          do_dup_host_includes
81          [ $? = 0 ] || return 1
82          do_dup_vserver
83          [ $? = 0 ] || return 1
84          ;;
85       *)
86          return 1
87          ;;
88    esac
89    do_dup_excludes
90    [ $? = 0 ] || return 1
91    
92    _src_done="(DONE)"
93    setDefault dest
94 }
95
96 do_dup_dest() {
97
98    local replyconverted
99    local thereply
100
101    set -o noglob
102    REPLY=
103    while [ -z "$REPLY" -o -z "$dup_destdir" -o -z "$dup_desthost" -o -z "$dup_destuser" ]; do
104       formBegin "$dup_title - destination: first three items are compulsory"
105         formItem "desthost" "$dup_desthost"
106         formItem "destuser" "$dup_destuser"
107         formItem "destdir" "$dup_destdir"
108         formItem "keep" "$dup_keep"
109         formItem "incremental" "$dup_incremental"
110         formItem "bandwidthlimit" "$dup_bandwidth"
111         formItem "sshoptions" "$dup_sshoptions"
112       formDisplay
113       [ $? = 0 ] || return 1
114
115       IFS=$''
116       replyconverted=`echo $REPLY | tr '\n' :`
117       IFS=$':'
118       thereply=($replyconverted)
119       IFS=$' \t\n'
120       
121       dup_desthost=${thereply[0]}
122       dup_destuser=${thereply[1]}
123       dup_destdir=${thereply[2]}
124       dup_keep=${thereply[3]}
125       dup_incremental=${thereply[4]}
126       dup_bandwidth=${thereply[5]}
127       dup_sshoptions=${thereply[6]}
128
129    done
130    set +o noglob
131
132    _dest_done="(DONE)"
133    setDefault gpg
134 }
135
136 do_dup_gpg_encryptkey() {
137    REPLY=
138    while [ -z "$REPLY" -o -z "$dup_gpg_encryptkey" ]; do
139       inputBox "$dup_title - GnuPG" "Enter ID of the public GnuPG key to be used to encrypt the backups:" "$dup_gpg_encryptkey"
140       [ $? = 0 ] || return 1
141       dup_gpg_encryptkey="$REPLY"
142    done
143 }
144
145 do_dup_gpg_sign() {
146    # sign ?
147    booleanBox "$dup_title - GnuPG" "Sign the backups?" "$dup_gpg_sign"
148    if [ $? = 0 ]; then
149       dup_gpg_sign=yes
150    else
151       dup_gpg_sign=no
152    fi
153 }
154
155 do_dup_gpg_signkey() {
156    # one key pair ?
157    booleanBox "$dup_title - GnuPG" "Use the same GnuPG key pair for encryption and signing?" "$dup_gpg_onekeypair"
158    if [ $? = 0 ]; then
159       dup_gpg_onekeypair=yes
160    else
161       dup_gpg_onekeypair=no
162    fi
163
164    if [ "$dup_gpg_onekeypair" == "no" }; then
165       # signkey ?
166       REPLY=
167       while [ -z "$REPLY" -o -z "$dup_gpg_signkey" ]; do
168          inputBox "$dup_title - GnuPG" "Enter the ID of the private GnuPG key to be used to sign the backups:" "$dup_gpg_signkey"
169          [ $? = 0 ] || return 1
170          dup_gpg_signkey="$REPLY"
171       done
172    fi
173 }
174
175 do_dup_gpg_passphrase() {
176    local question="Enter the passphrase needed to unlock the GnuPG key:"
177    REPLY=
178    while [ -z "$REPLY" -o -z "$dup_gpg_password" ]; do
179       passwordBox "$dup_title - GnuPG" "$question"
180       [ $? = 0 ] || return 1
181       dup_gpg_password="$REPLY"
182    done
183 }
184
185 do_dup_gpg() {
186    
187    # symmetric or public key encryption ?
188    booleanBox "$dup_title - GnuPG" "Use public key encryption? Otherwise, symmetric encryption will be used, and data signing will be impossible." "$dup_gpg_asymmetric_encryption"
189    if [ $? = 0 ]; then
190       dup_gpg_asymmetric_encryption=yes
191    else
192       dup_gpg_asymmetric_encryption=no
193    fi
194
195    # when using public/private key pair encryption, ask for the keys to use
196    if [ "$dup_gpg_asymmetric_encryption" == yes ]; then
197       do_dup_gpg_encryptkey ; [ $? = 0 ] || return 1
198       do_dup_gpg_sign ; [ $? = 0 ] || return 1
199       if [ "$dup_gpg_sign" == yes ]; then
200          do_dup_gpg_signkey ; [ $? = 0 ] || return 1
201       fi
202    else
203       dup_gpg_sign=no
204    fi
205
206    # a passphrase is alway needed
207    do_dup_gpg_passphrase
208
209    _gpg_done="(DONE)"
210    setDefault adv
211    # TODO: replace the above line by the following when do_dup_conn is written
212    # setDefault conn
213 }
214
215 # TODO: share rdiff.helper code in some lib, and use it here
216 do_dup_conn() {
217    _con_done="(DONE)"
218    setDefault adv
219 }
220
221 do_dup_misc_options() {
222
223    set -o noglob
224    local replyconverted
225    local thereply
226
227    formBegin "$dup_title - misc. options"
228      formItem "nicelevel" "$dup_nicelevel"
229      formItem "testconnect" "$dup_testconnect"
230      formItem "options" "$dup_options"
231    formDisplay
232    [ $? = 0 ] || return 1
233
234    IFS=$''
235    replyconverted=`echo $REPLY | tr '\n' :`
236    IFS=$':'
237    thereply=($replyconverted)
238    IFS=$' \t\n'
239
240    dup_nicelevel=${thereply[0]}
241    dup_testconnect=${thereply[1]}
242    dup_options=${thereply[2]}
243
244    set +o noglob
245 }
246
247 # (rdiff.helper compatible interface... there could be some sode to share, hmmm.)
248 do_dup_adv() {
249    do_dup_misc_options
250    [ $? = 0 ] || return 1
251    _adv_done="(DONE)"
252    setDefault finish
253 }
254
255 do_dup_finish() {
256    get_next_filename $configdirectory/90.dup
257    cat > $next_filename <<EOF
258 # passed directly to duplicity
259 #options = --verbosity 8
260 options = $dup_options
261
262 # default is 0, but set to 19 if you want to lower the priority.
263 nicelevel = $dup_nicelevel
264
265 # default is yes. set to no to skip the test if the remote host is alive
266 testconnect = $dup_testconnect
267
268 ######################################################
269 ## gpg section
270 ## (how to encrypt and optionally sign the backups)
271 ##
272 ## WARNING: old (pre-0.9.4) example.dup used to give wrong information about
273 ##          the way the following options are used. Please read the following
274 ##          carefully.
275 ##
276 ## If the encryptkey variable is set:
277 ##   - data is encrypted with the GnuPG public key specified by the encryptkey
278 ##     variable
279 ##   - if signing is enabled, data is signed with the GnuPG private
280 ##     key specified by the signkey variable
281 ##   - the password variable is used to unlock the GnuPG key(s) used
282 ##     for encryption and (optionnal) signing
283 ##
284 ## If the encryptkey option is not set:
285 ##   - data signing is not possible
286 ##   - the password variable is used to encrypt the data with symmetric
287 ##     encryption: no GnuPG key pair is needed
288
289 [gpg]
290
291 # when set to yes, encryptkey variable must be set below; if you want to use
292 # two different keys for encryption and signing, you must also set the signkey
293 # variable below.
294 # default is no, for backwards compatibility with backupninja <= 0.5.
295 sign = $dup_gpg_sign
296
297 # ID of the GnuPG public key used for data encryption.
298 # if not set, symmetric encryption is used, and data signing is not possible.
299 encryptkey = $dup_gpg_encryptkey
300
301 # ID of the GnuPG private key used for data signing.
302 # if not set, encryptkey will be used.
303 signkey = $dup_gpg_signkey
304
305 # password
306 # NB: neither quote this, nor should it include any quotes
307 password = $dup_gpg_password
308
309 ######################################################
310 ## source section
311 ## (where the files to be backed up are coming from)
312
313 [source]
314
315 # A few notes about includes and excludes:
316 # 1. include, exclude and vsinclude statements support globbing with '*'
317 # 2. Symlinks are not dereferenced. Moreover, an include line whose path
318 #    contains, at any level, a symlink to a directory, will only have the
319 #    symlink backed-up, not the target directory's content. Yes, you have to
320 #    dereference yourself the symlinks, or to use 'mount --bind' instead.
321 #    Example: let's say /home is a symlink to /mnt/crypt/home ; the following
322 #    line will only backup a "/home" symlink ; neither /home/user nor
323 #    /home/user/Mail will be backed-up :
324 #      include = /home/user/Mail
325 #    A workaround is to 'mount --bind /mnt/crypt/home /home' ; another one is to
326 #    write :
327 #      include = /mnt/crypt/home/user/Mail
328 # 3. All the excludes come after all the includes. The order is not otherwise
329 #    taken into account.
330
331 # files to include in the backup
332 EOF
333
334    if [ "$host_or_vservers" == host -o "$host_or_vservers" == both ]; then
335       set -o noglob
336       for i in $dup_includes; do
337          echo "include = $i" >> $next_filename
338       done
339       set +o noglob
340    fi
341
342    cat >> $next_filename <<EOF
343
344 # If vservers = yes in /etc/backupninja.conf then the following variables can
345 # be used:
346 # vsnames = all | <vserver1> <vserver2> ... (default = all)
347 # vsinclude = <path>
348 # vsinclude = <path>
349 # ...
350 # Any path specified in vsinclude is added to the include list for each vserver
351 # listed in vsnames (or all if vsnames = all, which is the default).
352 #
353 # For example, vsinclude = /home will backup the /home directory in every
354 # vserver listed in vsnames. If you have 'vsnames = foo bar baz', this
355 # vsinclude will add to the include list /vservers/foo/home, /vservers/bar/home
356 # and /vservers/baz/home.
357 # Vservers paths are derived from $VROOTDIR.
358
359 EOF
360
361    if [ "$host_or_vservers" == vservers -o "$host_or_vservers" == both ]; then
362       set -o noglob
363       echo -e "vsnames = $selected_vservers\n" >> $next_filename
364       for i in $dup_vsincludes; do
365          echo "vsinclude = $i" >> $next_filename
366       done
367       set +o noglob
368    fi
369
370    # excludes
371    cat >> $next_filename <<EOF
372
373 # files to exclude from the backup
374 EOF
375     set -o noglob
376     for i in $dup_excludes; do
377         echo "exclude = $i" >> $next_filename
378     done
379     set +o noglob
380
381     cat >> $next_filename <<EOF
382
383 ######################################################
384 ## destination section
385 ## (where the files are copied to)
386
387 [dest]
388
389 # perform an incremental backup? (default = yes)
390 # if incremental = no, perform a full backup in order to start a new backup set
391 incremental = $dup_incremental
392
393 # how many days of data to keep ; default is 60 days.
394 # (you can also use the time format of duplicity)
395 # 'keep = yes' means : do not delete old data, the remote host will take care of this
396 #keep = 60
397 #keep = yes
398 keep = $dup_keep
399
400 # full destination URL, in duplicity format; if set, desturl overrides
401 # sshoptions, destdir, desthost and destuser; it also disables testconnect and
402 # bandwithlimit. For details, see duplicity manpage, section "URL FORMAT".
403 #desturl = file:///usr/local/backup
404 #desturl = rsync://user@other.host//var/backup/bla
405
406 # bandwith limit, in kbit/s ; default is 0, i.e. no limit
407 #bandwidthlimit = 128
408 bandwidthlimit = $dup_bandwidth
409
410 # passed directly to ssh, scp (and sftp in duplicity >=0.4.2)
411 # warning: sftp does not support all scp options, especially -i; as
412 # a workaround, you can use "-o <SSHOPTION>"
413 #sshoptions = -o IdentityFile=/root/.ssh/id_dsa_duplicity
414 sshoptions = $dup_sshoptions
415
416 # put the backups under this directory
417 destdir = $dup_destdir
418
419 # the machine which will receive the backups
420 desthost = $dup_desthost
421
422 # make the files owned by this user
423 # note: you must be able to ssh backupuser@backhost
424 # without specifying a password (if type = remote).
425 destuser = $dup_destuser
426
427 EOF
428
429     chmod 600 $next_filename
430
431 }
432
433 dup_main_menu() {
434
435   while true; do
436      srcitem="choose files to include & exclude $_src_done"
437      destitem="configure backup destination $_dest_done"
438      gpgitem="configure GnuPG encryption/signing $_gpg_done"
439      conitem="set up ssh keys and test remote connection $_con_done"
440      advitem="edit advanced settings $_adv_done"
441      # TODO: add the following to the menu when do_dup_conn is written
442      # conn "$conitem" \
443      menuBox "$dup_title" "choose a step:" \
444         src "$srcitem" \
445         dest "$destitem" \
446         gpg "$gpgitem" \
447         adv "$advitem" \
448         finish "finish and create config file"
449      [ $? = 0 ] || return 1
450      result="$REPLY"
451
452      case "$result" in
453         "src") do_dup_src;;
454         "dest") do_dup_dest;;
455         "gpg") do_dup_gpg;;
456         # TODO: enable the following when do_dup_conn is written
457         # "conn") do_dup_conn;;
458         "adv") do_dup_adv;;
459         "finish")
460            if [[ "$_dest_done$_gpg_done$_src_done" != "(DONE)(DONE)(DONE)" ]]; then
461            # TODO: replace the previous test by the following when do_dup_conn is written
462            # if [[ "$_con_done$_dest_done$_gpg_done$_src_done" != "(DONE)(DONE)(DONE)(DONE)" ]]; then
463               msgBox "$dup_title" "You cannot create the configuration file until the four first steps are completed."
464            else
465               do_dup_finish
466               break
467            fi
468            ;;
469      esac
470
471   done
472 }
473
474 ### Main function
475
476 dup_wizard() {
477    
478    require_packages duplicity
479
480    # Global variables
481    dup_title="Duplicity action wizard"
482    _src_done=
483    _dest_done=
484    _con_done=
485    _gpg_done=
486    _adv_done=
487    dup_includes=
488    dup_excludes=
489    dup_vsincludes=
490    dup_incremental=yes
491    dup_keep=60
492    dup_bandwidth=
493    dup_sshoptions=
494    dup_destdir="/backups/`hostname`"
495    dup_desthost=
496    dup_destuser=
497    dup_gpg_asymmetric_encryption="yes"
498    dup_gpg_encryptkey=""
499    dup_gpg_sign="yes"
500    dup_gpg_onekeypair="yes"
501    dup_gpg_signkey=""
502    dup_gpg_password=""
503    dup_nicelevel=19
504    dup_testconnect=yes
505    dup_options=
506
507    # Global variables whose '*' shall not be expanded
508    set -o noglob
509    dup_default_includes="/var/spool/cron/crontabs /var/backups /etc /root /home /usr/local/*bin /var/lib/dpkg/status*"
510    dup_default_excludes="/home/*/.gnupg /home/*/.gnupg /home/*/.local/share/Trash /home/*/.Trash /home/*/.thumbnails /home/*/.beagle /home/*/.aMule /home/*/gtk-gnutella-downloads"
511    set +o noglob
512
513    dup_main_menu
514 }