# requires rdiff-backup
#
+### FUNCTIONS ###
+
+function test_connection() {
+ # given a user and host,
+ # tests the connection.
+ # if user or host is missing, returns 0
+ # (ie, assume it's a local connection).
+ if [ $# -lt 2 ]; then
+ debug "(local is assumed to be a good connection)"
+ return 0
+ fi
+ local user=$1
+ local host=$2
+ debug "ssh -o PasswordAuthentication=no $host -l $user 'echo -n 1'"
+ local ret=`ssh -o PasswordAuthentication=no $host -l $user 'echo -n host is alive'`
+ if echo $ret | grep "host is alive"; then
+ debug "Connected to $host as $user successfully"
+ else
+ fatal "Can't connect to $host as $user."
+ fi
+}
+
+function get_version() {
+ # given no arguments, returns the local version.
+ # given a user and host, returns the remote version.
+ # if user or host is missing, returns the local version.
+ if [ "$#" -lt 2 ]; then
+ debug "$RDIFFBACKUP -V"
+ echo `$RDIFFBACKUP -V`
+ else
+ local user=$1
+ local host=$2
+ debug "ssh $host -l $user '$RDIFFBACKUP -V'"
+ echo `ssh $host -l $user "$RDIFFBACKUP -V | grep rdiff-backup"`
+ fi
+}
+
+function check_consistency() {
+ local section=$1
+ local type=$2
+ local user=$3
+ local host=$4
+ if [ "$type" == "local" ]; then
+ if [ "$user" != "" ]; then
+ warning "User should not be specified for local $section."
+ fi
+ if [ "$host" != "" ]; then
+ warning "Host should not be specified for local $section."
+ fi
+ fi
+ if [ "$type" == "remote" ]; then
+ if [ "$user" == "" ]; then
+ fatal "User must be specified for remote $section."
+ fi
+ if [ "host" == "" ]; then
+ fatal "Host must be specifed for remote $section."
+ fi
+ fi
+}
+
+### GET CONFIG ###
+
getconf options
getconf testconnect yes
getconf nicelevel 0
setsection source
getconf type; sourcetype=$type
+getconf user; sourceuser=$user
+getconf host; sourcehost=$host
+check_consistency "source" "$type" "$user" "$host"
getconf label
getconf keep 60
getconf include
getconf vsinclude
getconf exclude
-### DESTINATION ###
-
setsection dest
getconf directory; destdir=$directory
# strip trailing /
getconf type; desttype=$type
getconf user; destuser=$user
getconf host; desthost=$host
+check_consistency "destination" "$type" "$user" "$host"
+
+### CHECK CONFIG ###
# See if vservers are configured
if [ "$vservers" = "yes" ]
fi
fi
-[ "$destdir" != "" ] || fatal "Destination directory not set"
-
-if [ "$desttype" == "remote" ]; then
- # see if we can login
- if [ "$testconnect" == "yes" ]; then
- hostalive=0
- debug "ssh -o PreferredAuthentications=publickey $desthost -l $destuser 'echo -n 1'"
- ret=`ssh -o PreferredAuthentications=publickey $desthost -l $destuser 'echo -n host is alive'`
- if echo $ret | grep "host is alive"; then
- debug "Connected to $desthost as $destuser successfully"
- else
- fatal "Can't connect to $desthost as $destuser."
- fi
- fi
- # see that rdiff-backup has the same version as here
- debug "ssh -o PreferredAuthentications=publickey $desthost -l $destuser '$RDIFFBACKUP -V'\""
- remoteversion=`ssh -o PreferredAuthentications=publickey $desthost -l $destuser "$RDIFFBACKUP -V | grep rdiff-backup"`
- localversion=`$RDIFFBACKUP -V`
- if [ "$remoteversion" != "$localversion" ]; then
- fatal "rdiff-backup does not have the same version on this computer and the backup server."
- fi
- execstr_serverpart="$destuser@$desthost::$destdir/$label"
-else
- execstr_serverpart="$destdir/$label"
+# check the connection at the source and destination
+if [ "$testconnect" == "yes" -o $test ]; then
+ test_connection $sourceuser $sourcehost
+ test_connection $destuser $desthost
fi
-### SOURCE ###
+# see that rdiff-backup has the same version at the source and destination
+sourceversion=`get_version $sourceuser $sourcehost`
+destversion=`get_version $destuser $desthost`
+if [ "$sourceversion" != "$destversion" ]; then
+ fatal "rdiff-backup does not have the same version at the source and at the destination."
+fi
-[ "$sourcetype" == "local" ] || fatal "Only local source type supported"
+# source specific checks
[ "$include" != "" -o "$vsinclude" != "" ] || fatal "No source includes specified"
#TODO should I test for vsinclude if usevservers=1?
+case $sourcetype in
+ remote ) execstr_sourcepart="$sourceuser@$sourcehost::/" ;;
+ local ) execstr_sourcepart="/" ;;
+ * ) fatal "sourcetype '$sourcetype' is neither local nor remote" ;;
+esac
-execstr_clientpart="/"
+# destination specific checks
+[ "$destdir" != "" ] || fatal "Destination directory not set"
+case $desttype in
+ remote ) execstr_destpart="$destuser@$desthost::$destdir/$label" ;;
+ local ) execstr_destpart="$destdir/$label" ;;
+ * ) fatal "desttype '$desttype' is neither local nor remote" ;;
+esac
-## REMOVE OLD BACKUPS
+### REMOVE OLD BACKUPS ###
if [ "`echo $keep | tr -d 0-9`" == "" ]; then
+ # add D if no other date unit is specified
keep="${keep}D"
fi
-removestr="rdiff-backup --force --remove-older-than $keep "
+removestr="$RDIFFBACKUP --force --remove-older-than $keep "
if [ "$desttype" == "remote" ]; then
removestr="${removestr}${destuser}@${desthost}::"
fi
debug "$removestr"
if [ ! $test ]; then
output=`$removestr 2>&1`
- code=$?
- if [ "$code" == "0" ]; then
+ if [ $? = 0 ]; then
debug $output
info "Removing backups older than $keep days succeeded."
else
fi
fi
-## EXECUTE ##
+### EXECUTE ###
execstr="$RDIFFBACKUP $options --print-statistics "
# TODO: order the includes and excludes
-
# excludes
for i in $exclude; do
str="${i//__star__/*}"
execstr="${execstr}--exclude '$str' "
done
-
# includes
for i in $include; do
+ [ "$i" != "/" ] || fatal "Sorry, you cannot use 'include = /'"
str="${i//__star__/*}"
execstr="${execstr}--include '$str' "
done
# vsinclude
-if [ $usevserver ]
-then
- for vserver in `ls $VROOTDIR | grep -E -v "lost+found|ARCHIVES"`
- do
- for vi in $vsinclude
- do
+if [ $usevserver ]; then
+ for vserver in `ls $VROOTDIR|grep -v lost+found`; do
+ for vi in $vsinclude; do
str="${vi//__star__/*}"
execstr="${execstr}--include '$VROOTDIR/$vserver$str' "
done
execstr="${execstr}--exclude '/*' "
# include client-part and server-part
-execstr="${execstr}$execstr_clientpart $execstr_serverpart"
+execstr="${execstr}$execstr_sourcepart $execstr_destpart"
debug "$execstr"
if [ ! $test ]; then
output=`nice -n $nicelevel su -c "$execstr" 2>&1`
- code=$?
- if [ "$code" == "0" ]; then
+ if [ $? = 0 ]; then
debug $output
info "Successfully finished backing up source $label"
else
HELPERS="$HELPERS rdiff:incremental_remote_filesystem_backup"
+declare -a rdiff_includes
+declare -a rdiff_excludes
+
do_rdiff_dest() {
- formBegin "rdiff action wizard"
- formItem "keep" "$rdiff_keep"
- formItem "dest_directory" "$rdiff_directory"
- formItem "dest_host" "$rdiff_host"
- formItem "dest_user" "$rdiff_user"
- formDisplay
- [ $? = 1 ] && return;
-
- set -- $REPLY
- rdiff_keep=$1
- rdiff_directory=$2
- rdiff_host=$3
- rdiff_user=$4
+ set -o noglob
+ formBegin "rdiff action wizard"
+ formItem "keep" "$rdiff_keep"
+ formItem "dest_directory" "$rdiff_directory"
+ formItem "dest_host" "$rdiff_host"
+ formItem "dest_user" "$rdiff_user"
+ formDisplay
+ [ $? = 1 ] && return;
+
+ IFS=$''
+ replyconverted=`echo $REPLY | tr '\n' :`
+ IFS=$':'
+ thereply=($replyconverted)
+ IFS=$' \t\n'
+
+ rdiff_keep=${thereply[0]}
+ rdiff_directory=${thereply[1]}
+ rdiff_host=${thereply[2]}
+ rdiff_user=${thereply[3]}
_dest_done="(DONE)"
setDefault conn
+ set +o noglob
}
do_rdiff_src() {
- formBegin "rdiff action wizard: includes"
- formItem include /var/spool/cron/crontabs
- formItem include /var/backups
- formItem include /etc
- formItem include /root
- formItem include /home
- formItem include '/usr/local/*bin'
- formItem include '/var/lib/dpkg/status*'
- formItem include
- formItem include
- formItem include
- formDisplay
- [ $? = 1 ] && return;
-
- rdiff_includes=
- set -o noglob
- for i in $REPLY; do
- [ "$i" != "" ] && rdiff_includes="$rdiff_includes\ninclude = $i"
- done
- set +o noglob
-
- formBegin "rdiff action wizard: excludes"
- formItem exclude '/home/*/.gnupg'
- formItem exclude
- formItem exclude
- formDisplay
- [ $? = 1 ] && return;
-
- rdiff_excludes=
- set -o noglob
- for i in $REPLY; do
- [ "$i" != "" ] && rdiff_excludes="$rdiff_excludes\nexclude = $i"
- done
- set +o noglob
+ #echo ${rdiff_includes[@]}
+ set -o noglob
+ formBegin "rdiff action wizard: includes"
+ for ((i=0; i < ${#rdiff_includes[@]} ; i++)); do
+ formItem include ${rdiff_includes[$i]}
+ done
+ formItem include
+ formItem include
+ formItem include
+ formDisplay
+ [ $? = 1 ] && return;
+
+ unset rdiff_includes
+ rdiff_includes=($REPLY)
+
+ formBegin "rdiff action wizard: excludes"
+ for ((i=0; i < ${#rdiff_excludes[@]} ; i++)); do
+ formItem exclude ${rdiff_excludes[$i]}
+ done
+ formItem exclude
+ formItem exclude
+ formDisplay
+ [ $? = 1 ] && return;
+
+ unset rdiff_excludes
+ rdiff_excludes=($REPLY)
- _src_done="(DONE)"
- setDefault dest
+ _src_done="(DONE)"
+ setDefault dest
+ set +o noglob
}
do_rdiff_con() {
+ IFS=$' \t\n'
if [ "$_dest_done" = "" ]; then
- msgBox "rdiff action wizard: error" "You must first configure the destination"
+ msgBox "rdiff action wizard: error" "You must first configure the destination."
+ return
+ elif [ "$rdiff_user" = "" ]; then
+ msgBox "rdiff action wizard: error" "You must first configure the destination user."
+ return
+ elif [ "$rdiff_host" = "" ]; then
+ msgBox "rdiff action wizard: error" "You must first configure the destination host."
return
else
booleanBox "rdiff action wizard" "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. Are you sure you want to continue?"
ssh -o PreferredAuthentications=publickey $rdiff_host -l $rdiff_user "exit" 2> /dev/null
if [ $? -ne 0 ]; then
- echo "Copying root's public ssh key to authorized_keys of $rdiff_user@$rdiff_host. Specify the password for user $rdiff_user@$rdiff_host."
+ 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."
ssh-copy-id -i /root/.ssh/id_[rd]sa.pub $rdiff_user@$rdiff_host
if [ $? -ne 0 ]; then
- echo "Couldn't copy root's public ssh key to authorized_keys of $rdiff_user@$rdiff_host. This time, testing whether directory is writable."
+ echo "FAILED: Couldn't copy root's public ssh key to authorized_keys of $rdiff_user@$rdiff_host."
ssh $rdiff_user@$rdiff_host 'test -w .ssh || test -w .'
- case $? in
+ result=$?
+ echo "Hit return to continue."
+ read
+ case $result in
0 ) msgBox "rdiff action wizard: error" "Directories are writable: Probably just a typo the first time." ;;
1 ) msgBox "rdiff action wizard: error" "Connected successfully to $rdiff_user@$rdiff_host, but unable to write. Check ownership and modes of ~$rdiff_user on $rdiff_host." ;;
- 255 ) msgBox "rdiff action wizard: error" "Failed to connect to $rdiff_user@$rdiff_host. Check hostname, username, and password." ;;
+ 255 ) msgBox "rdiff action wizard: error" "Failed to connect to $rdiff_user@$rdiff_host. Check hostname, username, and password. Also, make sure sshd is running on the destination host." ;;
* ) msgBox "rdiff action wizard: error" "Unexpected error." ;;
esac
return
type = local
keep = $rdiff_keep
EOF
- echo -n -e "$rdiff_includes" >> $next_filename
- echo -e "$rdiff_excludes" >> $next_filename
- cat >> $next_filename <<EOF
+ set -o noglob
+ for ((i=0; i < ${#rdiff_includes[@]} ; i++)); do
+ echo include = ${rdiff_includes[$i]}
+ done
+ for ((i=0; i < ${#rdiff_includes[@]} ; i++)); do
+ echo exclude = ${rdiff_excludes[$i]}
+ done
+ set +o noglob
+ cat >> $next_filename <<EOF
[dest]
type = remote
}
rdiff_main_menu() {
+
while true; do
srcitem="choose files to include & exclude $_src_done"
destitem="configure backup destination $_dest_done"
finish "finish and create config file"
[ $? = 1 ] && return;
result="$REPLY"
+
case "$result" in
"src") do_rdiff_src;;
"dest") do_rdiff_dest;;
fi
;;
esac
-
+
done
}
rdiff_wizard() {
-# require_packages rdiff-backup
+ require_packages rdiff-backup
_src_done=
_dest_done=
_con_done=
rdiff_directory=/backup/`hostname`
rdiff_user=
rdiff_host=
+ rdiff_includes=(/var/spool/cron/crontabs /var/backups /etc /root /home /usr/local/*bin /var/lib/dpkg/status*)
+ rdiff_excludes=(/home/*/.gnupg)
rdiff_main_menu
}