diff options
-rw-r--r-- | docs/changelog | 4 | ||||
-rw-r--r-- | handlers/easydialog.sh | 7 | ||||
-rw-r--r-- | handlers/rdiff | 147 | ||||
-rw-r--r-- | handlers/rdiff.helper | 141 | ||||
-rwxr-xr-x | ninjahelper | 4 |
5 files changed, 195 insertions, 108 deletions
diff --git a/docs/changelog b/docs/changelog index 50a12ef..feef624 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,4 +1,4 @@ -version 0.9 -- unreleased +version 0.9 -- October 19 2005 *** IMPORTANT CHANGE, UPGRADE AT ONCE *** fixed insecure temporary file creation ***************************************** @@ -10,6 +10,8 @@ version 0.9 -- unreleased rdiff handler now supports remote source and local dest. (patch from cmccallum@thecsl.org). man pages are greatly improved. + fixed many bugs in rdiff helper. + rdiff handler does not require 'label' version 0.8 -- September 15 2005 added pgsql (PostgreSQL) handler, with vservers support. diff --git a/handlers/easydialog.sh b/handlers/easydialog.sh index 5d70653..18cb7c3 100644 --- a/handlers/easydialog.sh +++ b/handlers/easydialog.sh @@ -237,7 +237,12 @@ formDisplay() { done ) | xargs $DIALOG 2> $temp local status=$? - [ $status = 0 ] && REPLY=`cat $temp` + + if [ $status = 0 ]; then + IFS=$'' + REPLY=`cat $temp` + IFS=$' \t\n' + fi rm -f $temp return $status } diff --git a/handlers/rdiff b/handlers/rdiff index 40ad52d..9de8650 100644 --- a/handlers/rdiff +++ b/handlers/rdiff @@ -3,20 +3,83 @@ # 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 / @@ -24,6 +87,9 @@ destdir=${destdir%/} 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" ] @@ -37,47 +103,44 @@ then 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 @@ -86,8 +149,7 @@ removestr="${removestr}${destdir}/${label}"; 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 @@ -96,31 +158,27 @@ if [ ! $test ]; then 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 @@ -131,13 +189,12 @@ fi 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 diff --git a/handlers/rdiff.helper b/handlers/rdiff.helper index 8be68ac..066d53a 100644 --- a/handlers/rdiff.helper +++ b/handlers/rdiff.helper @@ -1,68 +1,78 @@ 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?" @@ -78,15 +88,18 @@ do_rdiff_con() { 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 @@ -112,9 +125,15 @@ do_rdiff_finish() { 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 @@ -126,6 +145,7 @@ EOF } rdiff_main_menu() { + while true; do srcitem="choose files to include & exclude $_src_done" destitem="configure backup destination $_dest_done" @@ -138,6 +158,7 @@ rdiff_main_menu() { finish "finish and create config file" [ $? = 1 ] && return; result="$REPLY" + case "$result" in "src") do_rdiff_src;; "dest") do_rdiff_dest;; @@ -152,12 +173,12 @@ rdiff_main_menu() { fi ;; esac - + done } rdiff_wizard() { -# require_packages rdiff-backup + require_packages rdiff-backup _src_done= _dest_done= _con_done= @@ -166,6 +187,8 @@ rdiff_wizard() { 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 } diff --git a/ninjahelper b/ninjahelper index 817b47b..13a4ca9 100755 --- a/ninjahelper +++ b/ninjahelper @@ -144,7 +144,7 @@ doaction() { $enable "$enable action" \ name "change the filename" \ run "run this action now" \ - test "do a test run" \ + test "test connections and passwords only" \ kill "remove this action" [ $? = 1 ] && return; result="$REPLY" @@ -237,7 +237,7 @@ for file in `find $conf/etc/backup.d/ -type f | sort -n`; do let "i += 1" done -menuBox "main menu" "select an action to edit" $menulist \ +menuBox "main menu" "Select a backup action for more options, or create a new action:" $menulist \ new "create a new backup action" \ quit "leave ninjahelper" |