#!/bin/ksh #______________________________________________________________________________________________ # # "rzync" is a simple ksh script using rsync to synchronize a file/directory with a remote one # using the SSH channel. It enables user to define different configurations and prepare SSH keys, # and also supports batch mode and logging option to trace the output. # #______________________________________________________________________________________________ sshpath=`which ssh` sshkeygen=`which ssh-keygen` rsyncpath=`which rsync` rm=/bin/rm mkdir=/bin/mkdir ls=/bin/ls sh=/bin/sh touch=touch hostname=/bin/hostname cut=`which cut` sed=`which sed` chmod=/bin/chmod date="/bin/date +%Y%m%d%H%M" cat=/bin/cat tee=`which tee` #______________________________________________________________________________________________ Rhost=mbalma1-2.lsu.edu # remote host Lhost=`$hostname | $cut -d'.' -f1` # local hostname Ruser=$USER # remote user Luser=$USER # local user Local_path=/tmp/s/ # local path Remote_path=/tmp/d # remote path quick=false # quick mode (no connection check, no locking ) !!! # the option "quick" ignores all controls # lock, unlock, check_connections will return immediately batchon=false # batch mode # if quick==true, also bacth=true logoutput=true # logging ? #______________________________________________________________________________________________ timethreshold=2 progname="rzync" confdir="$HOME/."$progname # configuration directory confile=$progname # configuration file configfile="$confdir/$confile" IdentityFile="$HOME/.ssh/id_$progname" # SSH identityFile ExcludeFile="$confdir/$confile""-exclude-from" # rsync exclude/include files IncludeFile="$confdir/$confile""-include-from" # example: rzync-exclude-from #######.* #######Desktop/* #######Documents/* #######Library #######Movies/* #######Music/* #######Pictures/* #######Public/* #######Send Registration/* #######Sites/* #######inMac/* #######config/* # Timeout=5600 # rsync timeout --timeout logfile=$confdir/log/$progname"_"`$date`".log" # LOG FILE #______________________________________________________________________________________________ dsleep=7 # time to wait if there is a lock dsleepinc=5 # waiting time increment by dsleepinc # list of all provided functions cmds_all="update lock unlock help readconfig configure readargs help check_conn createkeys checktime checkpaths put get setlockfiles printconfig" # allowed_cmds=$cmds_all # options - "rzync" allowed_cmds="configure unlock printconfig help createkeys get put update" Lpath="" # rsync paths Rpath="" configuring=false #______________________________________________________________________________________________ # set lock files setlockfiles(){ #local_lock_file="/tmp"/"$Luser"-locallock_file #remote_lock_file="/tmp"/"$Ruser"-remotelock_file slpath=`echo $Local_path | $sed 's/\/$//' | sed 's/\//_/g'` srpath=`echo $Remote_path | $sed 's/\/$//' | sed 's/\//_/g'` local_lock_file="/tmp"/"$slpath"_LOCK remote_lock_file="/tmp"/"$srpath"_LOCK } #______________________________________________________________________________________________ # perform lock operation lock(){ if $quick ; then return fi echo "lock :" $@ check_conn # check SSH connection setlockfiles dsleeptmp=$dsleep while : do if ! ( $ls $local_lock_file >/dev/null 2>&1 ) then if ! ( $SSH $Rhost -l $Ruser $sh -c \'$ls $remote_lock_file \' \ >/dev/null 2>&1 ) then $touch $local_lock_file if (( $? != 0 )) ; then echo "[$progname] Error : can not create local lock file $local_lock_file) ..." exit 4 fi $SSH $Rhost -l $Ruser $sh -c \' $touch $remote_lock_file \' \ >/dev/null 2>&1 if (( $? != 0 )) ; then echo "[$progname] Error : can not create remote lock file ($Ruser@$Rhost:$remote_lock_file) ..." exit 4 fi break fi fi sleep $dsleeptmp dsleeptmp=$(( $dsleeptmp + $dsleepinc )) done echo "... lock files : ($local_lock_file) and ($Rhost:$remote_lock_file)" } #______________________________________________________________________________________________ # unlock operation unlock(){ if $quick ; then return fi echo "unlock :" $@ check_conn # check connection setlockfiles $rm -f $local_lock_file if (( $? != 0 )) ; then echo "[$progname] Error: can not remove local lock file ($local_lock_file) ..." exit 4 fi $SSH $Rhost -l $Ruser $sh -c \' $rm -f $remote_lock_file \' \ >/dev/null 2>&1 if (( $? != 0 )) ; then echo "[$progname] Error: can not remove remote lock file ($Ruser@$Rhost:$remote_lock_file) ..." exit 4 fi } #______________________________________________________________________________________________ # update operation # does not delete any file # rsync local to remote # rsync remote to local update(){ echo "rsync : update " check_conn checkpaths RSYNC="$rsyncpath -auxvz --timeout=$Timeout" NRSYNC="$rsyncpath -nauxvz --timeout=$Timeout" # --dry-run show what would have been transferred # if exclude/include lists exits, set RSYNC command accordingly if [ -r $ExcludeFile ] ; then RSYNC=$RSYNC" --exclude-from=$ExcludeFile" NRSYNC=$NRSYNC" --exclude-from=$ExcludeFile" fi if [ -r $IncludeFile ] ; then RSYNC=$RSYNC" --exclude-from=$IncludeFile" NRSYNC=$NRSYNC" --exclude-from=$IncludeFile" fi # if batch mode, does not show what will be transfered # else shows what will be transfered if ! $batchon ; then tmp="" ; echo $NRSYNC -e "$SSH" $Lpath $Ruser@$Rhost:$Rpath echo $RSYNC -e "$SSH" $Lpath $Ruser@$Rhost:$Rpath echo "Continue? [y/n]" ; read tmp if [ "x$tmp" != "xy" ]; then exit 0 fi echo $NRSYNC -e "$SSH" $Ruser@$Rhost:$Rpath $Lpath echo $RSYNC -e "$SSH" $Ruser@$Rhost:$Rpath $Lpath echo "Continue? [y/n]" ; read tmp if [ "x$tmp" != "xy" ]; then exit 0 fi fi lock echo ; echo "Running :" echo $RSYNC -e "$SSH" $Lpath $Ruser@$Rhost:$Rpath $RSYNC -e "$SSH" $Lpath $Ruser@$Rhost:$Rpath # >/dev/null 2>&1 if (( $? != 0 )) ; then echo "[$progname] Error: rsync FAILED ..." unlock exit 3 fi echo ; echo "Running :" echo $RSYNC -e "$SSH" $Ruser@$Rhost:$Rpath $Lpath $RSYNC -e "$SSH" $Ruser@$Rhost:$Rpath $Lpath # >/dev/null 2>&1 if (( $? != 0 )) ; then echo "[$progname] Error : rsync FAILED ..." unlock exit 3 fi unlock } #______________________________________________________________________________________________ # rsync from local to remote # with --delete option put(){ echo "rsync : put " check_conn checkpaths RSYNC="$rsyncpath -axvz --delete --timeout=$Timeout" NRSYNC="$rsyncpath -naxvz --delete --timeout=$Timeout" if [ -r $ExcludeFile ] ; then RSYNC=$RSYNC" --exclude-from=$ExcludeFile" NRSYNC=$NRSYNC" --exclude-from=$ExcludeFile" fi if [ -r $IncludeFile ] ; then RSYNC=$RSYNC" --exclude-from=$IncludeFile" NRSYNC=$NRSYNC" --exclude-from=$IncludeFile" fi if ! $batchon ; then tmp="" ; echo $NRSYNC -e "$SSH" $Lpath $Ruser@$Rhost:$Rpath echo $RSYNC -e "$SSH" $Lpath $Ruser@$Rhost:$Rpath echo "Continue? [y/n]" ; read tmp if [ "x$tmp" != "xy" ]; then exit 0 fi fi lock echo ; echo "Running :" echo $RSYNC -e "$SSH" $Lpath $Ruser@$Rhost:$Rpath $RSYNC -e "$SSH" $Lpath $Ruser@$Rhost:$Rpath # >/dev/null 2>&1 if (( $? != 0 )) ; then echo "[$progname] Error: rsync FAILED ..." unlock exit 3 fi unlock } #______________________________________________________________________________________________ # rsync from remote to local # with --delete option get(){ echo "rsync : get " check_conn checkpaths RSYNC="$rsyncpath -axvz --delete --timeout=$Timeout" NRSYNC="$rsyncpath -naxvz --delete --timeout=$Timeout" if [ -r $ExcludeFile ] ; then RSYNC=$RSYNC" --exclude-from=$ExcludeFile" NRSYNC=$NRSYNC" --exclude-from=$ExcludeFile" fi if [ -r $IncludeFile ] ; then RSYNC=$RSYNC" --include-from=$IncludeFile" NRSYNC=$NRSYNC" --include-from=$IncludeFile" fi if ! $batchon ; then tmp="" ; echo echo $NRSYNC -e "$SSH" $Ruser@$Rhost:$Rpath $Lpath $NRSYNC -e "$SSH" $Ruser@$Rhost:$Rpath $Lpath echo $RSYNC -e "$SSH" $Ruser@$Rhost:$Rpath $Lpath echo "Continue? [y/n]" read tmp if [ "x$tmp" != "xy" ]; then exit 0 fi fi lock echo ; echo "Running :" echo $RSYNC -e "$SSH" $Ruser@$Rhost:$Rpath $Lpath $RSYNC -e "$SSH" $Ruser@$Rhost:$Rpath $Lpath # >/dev/null 2>&1 if (( $? != 0 )) ; then echo "[$progname] Error : rsync FAILED ..." unlock exit 3 fi unlock } #______________________________________________________________________________________________ checkpaths(){ Lpath=$Local_path Rpath=$Remote_path if [ "x$Lpath" = "x" ] ; then echo "Error : no source is specified!" exit 4 fi if [ "x$Rpath" = "x" ] ; then echo "Error : no destination is specified!" exit 4 fi if [ -d $Lpath ] ; then Lpath="$Lpath"/ fi $SSH $Ruser@$Rhost $sh -c \' [ -d $Rpath ] \' >/dev/null 2>&1 if (( $? == 0 )) ; then Rpath="$Rpath"/ fi } #______________________________________________________________________________________________ readconfig(){ $mkdir -p $confdir if (( $? != 0 )) ; then echo "[$progname] Error : can not create configuration directory ($confdir)" exit 2 fi if $logoutput ; then $mkdir -p $confdir/log if (( $? != 0 )) ; then echo "[$progname] Error : can not create log directory ($confdir/log)" exit 2 fi fi #echo "using configuration file ($configfile)" [ -r $configfile ] && . $configfile } #______________________________________________________________________________________________ printconfig(){ echo echo "printing configuration ($configfile):" echo " local path :"$Local_path echo " remote path :"$Remote_path echo " remore host :"$Rhost echo " local host :"$Lhost echo " remote user :"$Ruser echo " local user :"$Luser echo " rsync exclude file :"$ExcludeFile echo " rsync include file :"$IncludeFile echo " quick option :"$quick echo " batch mode :"$batchon echo " log output :"$logoutput echo } #______________________________________________________________________________________________ configure(){ configuring=true if $batchon ; then echo "[$progname] Error : command (configure) can not run on batch mode ..." exit 1 fi tmp=""; echo "generating configuration file for $progname ..." echo -n " remote path [ $Remote_path ] :" read tmp [ "x$tmp" != "x" ] && Remote_path=$tmp echo -n " local path [ $Local_path ] :" read tmp [ "x$tmp" != "x" ] && Local_path=$tmp echo -n " remote server [ $Rhost ] :" read tmp [ "x$tmp" != "x" ] && Rhost=$tmp echo -n " remote user [ $Ruser ] :" read tmp [ "x$tmp" != "x" ] && Ruser=$tmp echo -n " file in which exclude patterns are listed \ [ $ExcludeFile ] :" read tmp [ "x$tmp" != "x" ] && ExcludeFile=$tmp echo -n " file in which include-from patterns are listed \ [ $IncludeFile ] :" read tmp [ "x$tmp" != "x" ] && IncludeFile=$tmp echo "writing into ($configfile) ...." ( echo "Local_path="$Local_path echo "Remote_path="$Remote_path echo "Rhost="$Rhost echo "Lhost="$Lhost echo "Ruser="$Ruser echo "Luser="$Luser echo "ExcludeFile="$ExcludeFile echo "IncludeFile="$IncludeFile ) > $configfile touch $ExcludeFile touch $IncludeFile check_conn configuring=false } #______________________________________________________________________________________________ createkeys(){ if $batchon ; then echo "[$progname] Error : command (createkeys) can not run on batch mode ..." exit 1 fi tmp=""; echo "Configure SSH keys for automatic authentication." echo -n "Continue ? [y/n]" read tmp if [ "x$tmp" != "xy" ] ; then return fi $rm -f $IdentityFile "$IdentityFile".pub $sshkeygen -t dsa -N '' -f "$IdentityFile" if (( $? != 0 )) ; then echo "[$progname] Error : can not generate SSH keys ..." exit 2 fi echo "please enter password for $Ruser@$Rhost" ( $cat "$IdentityFile".pub | $sshpath -o IdentityFile=$IdentityFile $Ruser@$Rhost $sh -c \' $mkdir -p .ssh \; $chmod 0700 .ssh \; $touch .ssh/authorized_keys \; $chmod 0600 .ssh/authorized_keys \; $cat >> .ssh/authorized_keys \' ) echo "... checking SSH connection (IdentityFile=$IdentityFile)" $sshpath -o IdentityFile=$IdentityFile $Ruser@$Rhost true >/dev/null 2>&1 if (( $? != 0 )) ; then echo "[$progname] Error : unable to connect to remote host ..." exit 2 fi SSH="$sshpath -o IdentityFile=$IdentityFile" checktime } #______________________________________________________________________________________________ checktime(){ echo "checking time synchronization ..." localdate=`$date` remotedate=`$SSH $Ruser@$Rhost $sh -c \'$date\' ` if (( $? != 0 )) ; then echo "[$progname] Error : can not check time on remote server ($Rhost) ..." exit 2 fi diffstr=$(( $localdate - $remotedate )) diff=`echo $diffstr | $sed 's/-//g'` if (( $diff > $timethreshold )) ; then echo "[$progname] Error : time not synchronized ..." exit 2 fi } #______________________________________________________________________________________________ check_conn(){ if $quick ; then return fi SSH="$sshpath -o BatchMode=yes " echo "checking SSH connection ..." $SSH $Ruser@$Rhost true >/dev/null 2>&1 if (( $? == 0 )) ; then checktime if $configuring ; then echo "SSH=\" $SSH \" " >> $configfile fi return fi SSH="$SSH -o IdentityFile=$IdentityFile " $SSH $Ruser@$Rhost true >/dev/null 2>&1 if (( $? == 0 )) ; then checktime if $configuring ; then echo "SSH=\" $SSH \" " >> $configfile fi return fi echo " FAILED" if ! $batchon ; then createkeys else echo "[$progname] Error : can not connect to remote host ($Rhost) ..." exit 2 fi if $configuring ; then echo "SSH=\" $SSH \" " >> $configfile fi } #______________________________________________________________________________________________ readargs(){ set -A arguments -- "$@" i=1 while (( $i < ${#arguments[@]} )) do if [ ${arguments[i]} = "--quick" ]; then quick=true batchon=true else if [ ${arguments[i]} = "--batchmode" ]; then batchon=true else if [ ${arguments[i]} = "--config" ]; then i=$(( $i + 1 )) configfile="$confdir/$confile-"${arguments[i]} else if [ ${arguments[i]} = "--nologging" ]; then logoutput=false else echo "[$progname] Error : invalid argument for (${arguments[0]}) ... " exit 1 fi fi fi fi i=$(( $i + 1 )) done } #______________________________________________________________________________________________ help(){ echo $progname" :" echo " commands : "$allowed_cmds echo " options : --quick, --batchmode, --config , --nologging" echo echo "ex : $progname --update --nologging --config test1 --batchmode" echo echo "commands : configure: configure rzync. writes the following variables to configuration file. remote server, remote path, remote user, local path, exclude file, include/exclude files unlock: remove lock files. if lock files exist, it will wait till they are removed. printconfig : print configuration information. createkeys: create SSH keys in order to connect without a password update: rsync from local to remote AND rsync from remote to local. without --delete option get: rsync from remote to local . with --delete option. put: rsync from local to remote. with --delete option. options: quick: ignores all controls. lock, unlock, check_connections will return immediately. batchmode: if batch mode, does not show what will be transfered, else first shows what will be transfered nologging: disable logging confile : use the given configuration file instead of the default one " } #______________________________________________________________________________________________ main() { set -A args -- "$@" cmd=${args[0]}; args[0]=" " cmd=`echo $cmd | $sed 's/-//g'` if echo $allowed_cmds | grep $cmd >/dev/null 2>&1 then readargs "$cmd ${args[@]}" readconfig ${args[@]} if $logoutput ; then ( printconfig ${args[@]} $cmd ${args[@]} ) | $tee -a $logfile 2>&1 else ( printconfig ${args[@]} $cmd ${args[@]} ) fi else if [ "x$cmd" != "x" ] ; then echo "[$progname] Error : command \"$cmd\" not found" exit 1 else $cmd help fi fi } #______________________________________________________________________________________________ main $@