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