add a few more 'formItem include' lines to the rdiff and dup handlers
[matthijs/upstream/backupninja.git] / handlers / rdiff.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 rdiff:incremental_remote_filesystem_backup"
5
6 declare -a rdiff_includes
7 declare -a rdiff_excludes
8 declare -a rdiff_vsincludes
9 declare -a rdiff_vsexcludes
10
11 # FUNCTIONS
12
13 do_rdiff_host_includes() {
14    set -o noglob
15    # choose the files to backup
16    REPLY=
17    while [ -z "$REPLY" ]; do
18       formBegin "$rdiff_title - host system: includes"
19          for ((i=0; i < ${#rdiff_includes[@]} ; i++)); do
20             formItem include ${rdiff_includes[$i]}
21          done
22          formItem include
23          formItem include
24          formItem include
25          formItem include
26          formItem include
27          formItem include
28          formItem include
29          formItem include
30       formDisplay
31       [ $? = 0 ] || return
32       unset rdiff_includes
33       rdiff_includes=($REPLY)
34    done
35    set +o noglob
36 }
37
38 do_rdiff_vserver() {
39    # choose the vservers to backup (into $selected_vservers)
40    choose_one_or_more_vservers "$rdiff_title"
41    [ $? = 0 ] || return 1
42
43    set -o noglob
44    # choose the files to backup
45    REPLY=
46
47    while [ -z "$REPLY" ]; do
48       formBegin "$rdiff_title - vsincludes (backup these directories from every vserver)"
49          [ -z "$rdiff_vsincludes" ] && rdiff_vsincludes="$rdiff_default_includes"
50
51          for i in $rdiff_vsincludes; do
52             formItem include "$i"
53          done
54          formItem include ""
55          formItem include ""
56          formItem include ""
57          formItem include ""
58          formItem include ""
59          formItem include ""
60          formItem include ""
61          formItem include ""
62       formDisplay
63       [ $? = 0 ] || return 1
64       rdiff_vsincludes=($REPLY)
65    done
66
67    set +o noglob
68 }
69
70 do_rdiff_excludes() {
71    set -o noglob
72    formBegin "$rdiff_title: excludes"
73      for ((i=0; i < ${#rdiff_excludes[@]} ; i++))
74      do
75        formItem exclude ${rdiff_excludes[$i]}
76      done
77      formItem exclude
78      formItem exclude
79      formItem exclude
80      formItem exclude
81      formItem exclude
82      formItem exclude
83      formItem exclude
84      formItem exclude
85    formDisplay
86    [ $? = 0 ] || return
87    unset rdiff_excludes
88    rdiff_excludes=($REPLY)
89    set +o noglob
90 }
91
92 do_rdiff_src() {
93    choose_host_or_vservers_or_both "$rdiff_title"
94    [ $? = 0 ] || return 1
95    case $host_or_vservers in
96       'host')
97          do_rdiff_host_includes
98          [ $? = 0 ] || return 1
99          ;;
100       'vservers')
101          do_rdiff_vserver
102          [ $? = 0 ] || return 1
103          ;;
104       'both')
105          do_rdiff_host_includes
106          [ $? = 0 ] || return 1
107          do_rdiff_vserver
108          [ $? = 0 ] || return 1
109          ;;
110       *)
111          return 1
112          ;;
113    esac
114    do_rdiff_excludes
115    [ $? = 0 ] || return 1
116    _src_done="(DONE)"
117    setDefault dest
118 }
119
120 do_rdiff_dest() {
121    declare -a tmp_array
122
123    set -o noglob
124    REPLY=
125    while [ -z "$REPLY" -o -z "$rdiff_directory" -o -z "$rdiff_host" -o -z "$rdiff_user" ]
126    do
127      formBegin "$rdiff_title - destination: last three items are required"
128         formItem "keep" "$rdiff_keep"
129         formItem "dest_directory" "$rdiff_directory"
130         formItem "dest_host" "$rdiff_host"
131         formItem "dest_user" "$rdiff_user"
132         formItem "dest_type" "$rdiff_type"
133         formDisplay
134      [ $? = 0 ] || return
135      tmp_array=($REPLY)
136      rdiff_keep=${tmp_array[0]}
137      rdiff_directory=${tmp_array[1]}
138      rdiff_host=${tmp_array[2]}
139      rdiff_user=${tmp_array[3]}
140      rdiff_type=${tmp_array[4]}
141   done
142   set +o noglob
143
144   _dest_done="(DONE)"
145   setDefault conn
146 }
147
148 do_rdiff_ssh_con() {
149    local remote_status="ok"
150
151    IFS=$' \t\n'
152    if [ "$_dest_done" = "" ]; then
153       msgBox "$rdiff_title: error" "You must first configure the destination."
154       return
155    elif [ "$rdiff_type" = "" ]; then
156       msgBox "$rdiff_title: error" "You must first configure the destination backup type."
157       return
158    elif [ "$rdiff_user" = "" ]; then
159       msgBox "$rdiff_title: error" "You must first configure the destination user."
160       return
161    elif [ "$rdiff_host" = "" ]; then
162       msgBox "$rdiff_title: error" "You must first configure the destination host."
163       return
164    else
165       booleanBox "$rdiff_title" "This step will create a ssh key for the local root user with no passphrase (if one does not already exist), and attempt to copy root's public ssh key to authorized_keys file of $rdiff_user@$rdiff_host. This will allow the local root to make unattended backups to $rdiff_user@$rdiff_host.\n\n\nAre you sure you want to continue?"
166       [ $? = 0 ] || return
167    fi
168
169    if [ ! -f /root/.ssh/id_dsa.pub -a ! -f /root/.ssh/id_rsa.pub ]; then
170       echo "Creating local root's ssh key"
171       ssh-keygen -t dsa -f /root/.ssh/id_dsa -N ""
172       echo "Done. hit return to continue"
173       read
174    fi
175
176    ssh -o PreferredAuthentications=publickey $rdiff_host -l $rdiff_user "exit" 2> /dev/null
177    if [ $? -ne 0 ]; then
178       echo "Copying root's public ssh key to authorized_keys of $rdiff_user@$rdiff_host. When prompted, specify the password for user $rdiff_user@$rdiff_host."
179       ssh-copy-id -i /root/.ssh/id_[rd]sa.pub $rdiff_user@$rdiff_host
180       if [ $? -ne 0 ]; then
181          echo "FAILED: Couldn't copy root's public ssh key to authorized_keys of $rdiff_user@$rdiff_host."
182          ssh $rdiff_user@$rdiff_host 'test -w .ssh || test -w .'
183          result=$?
184          echo "Hit return to continue."
185          read
186          case $result in
187             0 )   msgBox "$rdiff_title: error" "Directories are writable: Probably just a typo the first time." ;;
188             1 )   msgBox "$rdiff_title: error" "Connected successfully to $rdiff_user@$rdiff_host, but unable to write. Check ownership and modes of ~$rdiff_user on $rdiff_host." ;;
189             255 ) msgBox "$rdiff_title: error" "Failed to connect to $rdiff_user@$rdiff_host. Check hostname, username, and password. Also, make sure sshd is running on the destination host." ;;
190             * )   msgBox "$rdiff_title: error" "Unexpected error." ;;
191          esac
192          return
193       else
194          echo "Done. hit return to continue"
195          read
196       fi
197    else
198       echo "root@localhost is already in authorized_keys of $rdiff_user@$rdiff_host."
199       echo "Hit return to continue."
200       read
201    fi
202
203    # test to see if the remote rdiff backup directory exists and is writable
204    echo "Testing to see if remote rdiff backup directory exists and is writable"
205    ssh $rdiff_user@$rdiff_host "test -d ${rdiff_directory}"
206    if [ $? = 0 ]; then
207       ssh $rdiff_user@$rdiff_host "test -w $rdiff_directory"
208       if [ $? != 0 ]; then
209          msgBox "destination directory is not writable!" "The remote destination directory is not writable by the user you specified. Please fix the permissions on the directory and then try again."
210          remote_status=failed
211       fi
212    else
213       booleanBox "Remote directory does not exist" "The destination backup directory does not exist, do you want me to create it for you?"
214       if [ $? = 0 ]; then
215     ssh $rdiff_user@$rdiff_host "mkdir -p ${rdiff_directory}"
216          result=$?
217          case $result in
218             0) msgBox "$rdiff_title: success" "Creation of the remote destination directory was a success!";;
219             1) msgBox "$rdiff_title: error" "Connected successfully to $rdiff_user@$rdiff_host, but was unable to create the destination directory, check the directory permissions."
220                remote_status=failed;;
221             255) msgBox "$rdiff_title: error" "Failed to connect to $rdiff_user@$rdiff_host. Check hostname, username, and password. Also, make sure sshd is running on the destination host."
222                remote_status=failed;;
223             *) msgBox "$rdiff_title: error" "Unexpected error."
224                remote_status=failed;;
225          esac
226       fi
227    fi
228
229    if [ "$remote_status" = "ok" ]; then
230       do_rdiff_con
231    fi
232 }
233
234 do_rdiff_con() {
235    echo "Checking for local install of rdiff-backup"
236    require_packages rdiff-backup
237
238    echo "Testing to make sure destination has rdiff-backup installed and is compatible."
239    remote_result=`/usr/bin/rdiff-backup --test-server $rdiff_user@$rdiff_host::/ 2>&1 >&-`
240    if [ $? -ne 0 ]; then
241       echo $remote_result | grep -q "command not found"
242       if [ $? -eq 0 ]; then
243          if [ "$rdiff_user" = "root" ]; then
244             booleanBox "install rdiff-backup?" "It seems like the remote machine does not have rdiff-backup installed, I can attempt to install rdiff-backup on the remote machine.\n\n\nDo you want me to attempt this now?"
245             if [ $? = 0 ]; then
246                ssh $rdiff_user@$rdiff_host 'apt-get install rdiff-backup'
247                result=$?
248                echo "Hit return to continue."
249                read
250                case $result in
251                   0) msgBox "$rdiff_title: success" "Installation of rdiff-backup was a success!"
252                      do_rdiff_con;;
253                   1) msgBox "$rdiff_title: error" "Connected successfully to $rdiff_user@$rdiff_host, but was unable to install the package for some reason.";;
254                   255) msgBox "$rdiff_title: error" "Failed to connect to $rdiff_user@$rdiff_host. Check hostname, username, and password. Also, make sure sshd is running on the destination host.";;
255                   *) msgBox "$rdiff_title: error" "Unexpected error.";;
256                esac
257                return
258             fi
259          else
260             booleanBox "install rdiff-backup" "Please install rdiff-backup on the remote machine, this cannot be done automatically, as the remote user in your configuration is not root. \n\nIf you have installed rdiff-backup on the remote machine and you are getting this error, then there is a version incompatibility between that version and the local version.\n\nPlease resolve this problem and then try connecting again.\n\n\n\nTry connecting again?"
261             if [ $? = 0 ]; then
262                do_rdiff_con
263             else
264                return
265             fi
266          fi
267       else
268          msgBox "incompatible versions of rdiff-backup" "It looks like rdiff-backup is installed on the remote machine, but it may be an incompatible version with the one installed locally, or something else is amiss.\n\nPlease resolve this problem and then try connecting again.\n\n\nTry connecting again?"
269          if [ $? = 0 ]; then
270             do_rdiff_con
271          else
272             return
273          fi
274       fi
275    else
276     echo "SUCCESS: Everything looks good!"
277    echo "Hit return to continue."
278    read
279    fi
280
281    _con_done="(DONE)"
282    setDefault finish
283 }
284
285 do_rdiff_finish() {
286    get_next_filename $configdirectory/90.rdiff
287    cat > $next_filename <<EOF
288 # options = --force
289 # when = everyday at 02
290
291 [source]
292 type = local
293 keep = $rdiff_keep
294
295 # A few notes about includes and excludes:
296 # 1. include, exclude and vsinclude statements support globbing with '*'
297 # 2. Symlinks are not dereferenced. Moreover, an include line whose path
298 #    contains, at any level, a symlink to a directory, will only have the
299 #    symlink backed-up, not the target directory's content. Yes, you have to
300 #    dereference yourself the symlinks, or to use 'mount --bind' instead.
301 #    Example: let's say /home is a symlink to /mnt/crypt/home ; the following
302 #    line will only backup a "/home" symlink ; neither /home/user nor
303 #    /home/user/Mail will be backed-up :
304 #      include = /home/user/Mail
305 #    A workaround is to 'mount --bind /mnt/crypt/home /home' ; another one is to
306 #    write :
307 #      include = /mnt/crypt/home/user/Mail
308 # 3. All the excludes come after all the includes. The order is not otherwise
309 #    taken into account.
310
311 # files to include in the backup
312 EOF
313    ## includes ##
314    if [ "$host_or_vservers" == host -o "$host_or_vservers" == both ]; then
315       set -o noglob
316       for ((i=0; i < ${#rdiff_includes[@]} ; i++)); do
317          echo "include = ${rdiff_includes[$i]}" >> $next_filename
318       done
319       set +o noglob
320    fi
321
322    if [ "$host_or_vservers" == vservers -o "$host_or_vservers" == both ]; then
323       cat >> $next_filename <<EOF
324 #
325 # If vservers = yes in /etc/backupninja.conf then the following variables can
326 # be used:
327 # vsnames = all | <vserver1> <vserver2> ... (default = all)
328 # vsinclude = <path>
329 # vsinclude = <path>
330 # ...
331 # Any path specified in vsinclude is added to the include list for each vserver
332 # listed in vsnames (or all if vsnames = all, which is the default).
333 #
334 # For example, vsinclude = /home will backup the /home directory in every
335 # vserver listed in vsnames. If you have 'vsnames = foo bar baz', this
336 # vsinclude will add to the include list /vservers/foo/home, /vservers/bar/home
337 # and /vservers/baz/home.
338 # Vservers paths are derived from $VROOTDIR.
339
340 EOF
341       set -o noglob
342       echo -e "vsnames = $selected_vservers\n" >> $next_filename
343       for i in $rdiff_vsincludes; do
344          echo "vsinclude = $i" >> $next_filename
345       done
346       set +o noglob
347    fi
348
349    ## excludes ##
350    set -o noglob
351    for ((i=0; i < ${#rdiff_excludes[@]} ; i++)); do
352      echo exclude = ${rdiff_excludes[$i]} >> $next_filename
353    done
354    set +o noglob
355    cat >> $next_filename <<EOF
356
357 ######################################################
358 ## destination section
359 ## (where the files are copied to)
360
361 [dest]
362 type = remote
363 directory = $rdiff_directory
364 host = $rdiff_host
365 user = $rdiff_user
366 EOF
367
368    chmod 600 $next_filename
369 }
370
371 rdiff_main_menu() {
372    while true; do
373       srcitem="choose files to include & exclude $_src_done"
374       destitem="configure backup destination $_dest_done"
375       conitem="set up ssh keys and test remote connection $_con_done"
376       advitem="edit advanced settings $_adv_done"
377       menuBox "$rdiff_title" "choose a step:" \
378          src "$srcitem" \
379          dest "$destitem" \
380          conn "$conitem" \
381          finish "finish and create config file"
382       [ $? = 0 ] || return
383       result="$REPLY"
384       case "$result" in
385          "src") do_rdiff_src;;
386          "dest") do_rdiff_dest;;
387          "conn") do_rdiff_ssh_con;;
388          "adv") do_rdiff_adv;;
389          "finish")
390             if [[ "$_con_done$_dest_done$_src_done" != "(DONE)(DONE)(DONE)" ]]; then
391                msgBox "$rdiff_title" "You cannot create the configuration file until the other steps are completed."
392             else
393                do_rdiff_finish
394                return
395             fi
396             ;;
397       esac
398    done
399 }
400
401 rdiff_wizard() {
402
403    # Global variables
404    rdiff_title="rdiff-backup action wizard"
405    _src_done=
406    _dest_done=
407    _con_done=
408    _adv_done=
409    rdiff_keep=60D
410    rdiff_directory=/backup/`hostname`
411    rdiff_type=remote
412    rdiff_user=
413    rdiff_host=
414
415    # Global variables whose '*' shall not be expanded
416    set -o noglob
417    rdiff_includes=(/var/spool/cron/crontabs /var/backups /etc /root /home /usr/local/*bin /var/lib/dpkg/status*)
418    rdiff_excludes=(/home/*/.gnupg /home/*/.local/share/Trash /home/*/.Trash /home/*/.thumbnails /home/*/.beagle /home/*/.aMule /home/*/gtk-gnutella-downloads)
419    rdiff_vsincludes=
420    set +o noglob
421
422    rdiff_main_menu
423 }
424