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