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