#!/bin/bash # ************************************* # # # # sshbackup # # # # ************************************* # # **** config section **** version="0.3.1" author="david@socialnerds.org" configfile="$HOME/.sshbackup" #rsync options. rsyncoptions="-qpogEthrzl --numeric-ids --no-motd" #dotglob option removes bug while rsyncing folder with no visible files in it. remotecmd="shopt -s dotglob; /usr/bin/sudo /usr/bin/rsync" localcmd="/usr/bin/rsync" sshkeyfile="$HOME/.ssh/id_rsa" versions=999 config=0 sshkey=0 list=0 options=$* # **** function definitions **** bashtrap() { echo echo "CTRL+C detected." echo "commiting suicide." exit 1 } usage() { echo echo "usage: sshbackup source destination [versions]" echo "source/destination example: [[user@]server:]/path/to/files" echo echo "OPTIONS:" echo " -h, --help show this message" echo " -v, --version version information" echo echo " -l, --list list of sources and destinations" echo " -c, --config alternate config file [~/.sshbackup]" echo " -s, --sshkey alternate sshkey [~/.ssh/id_rsa]" echo } version() { echo echo -e "vesion: \033[1;37m$version\033[0m" echo "author: $author" echo } preflight() { #amiroot? # Thhis is a safter way of testing this # See: http://askubuntu.com/questions/30148/how-can-i-determine-whether-a-shellscript-runs-as-root-or-not/ if ! [ $(id -u) = 0 ]; then echo "aborting mission, you must be root." return 1 fi #source and destination path? if [ -z $sourcepath ]; then echo "aborting mission. no source path given." return 1 elif [ -z $destpath ]; then echo "aborting mission. no destination path given." return 1 fi #if remote source or destination check for sshkey if [[ $sourcepath =~ .*@.* ]] || [[ $destpath =~ .*@.* ]]; then if [ -r $sshkeyfile ]; then #echo "sshkeyfile found. continuing." : else echo "aborting mission. no sshkey found." return 1 fi fi return 0 } sshbackup() { #creating local rsync options var local cmdopt="$rsyncoptions" #move existing versions local num=$versions while [ -d "$destpath/0" ]; do if [ -d "$destpath/$num" ]; then mv $destpath/$num $destpath/$((num+1)) fi let num-- done #create destpath if not existing mkdir -p $destpath/0 #add link-destination option if existing if [ -d $destpath/1 ]; then cmdopt="$cmdopt --link-dest=$destpath/1" fi #run rsync $localcmd $cmdopt -e "ssh -q -i $sshkeyfile" --rsync-path="$remotecmd" $sourcepath $destpath/0 if [ $? -ne "0" ]; then return 1 fi #removing obsolet version(s) local i=1 while [ -d $destpath/$((versions+i)) ]; do rm -rf $destpath/$((versions+i)) let i++ done return 0 } # **** start of script **** #initialize bashtrap trap bashtrap INT # **** option handler **** if [ -z $1 ]; then usage exit 0 fi for option in $options; do case "$option" in -h|--help) usage exit 0 ;; -v|--version) version exit 0 ;; -c|--config) config=1 ;; -l|--list) list=1 ;; -s|--sshkey) sshkey=1 ;; *) if [ $config -eq 1 ]; then if [ -r "$option" ]; then configfile=$option config=0 else echo "aborting mission. cannot read configfile. [$option]" exit 1 fi elif [ $sshkey -eq 1 ]; then if [ -r $option ]; then sshkeyfile=$option sshkey=0 else echo "aborting mission. cannot read sshkeyfile. [$option]" exit 1 fi elif [ $list -eq 1 ]; then if [ -r $option ]; then listfile=$option list=0 else echo "aborting mission. cannot read listfile. [$option]" exit 1 fi else if [[ $option =~ ^-.* ]]; then echo "aborting mission. unknown option given. [$option]" usage exit 1 #TODO: what if source or destination is a number? elif [ -z "${option//[0-9]/}" ]; then versions="$option" else if [ -z "$sourcepath" ]; then if [[ $option =~ .*@.* ]]; then sourcepath="${option%/}/*" elif [[ $option =~ ^/.* ]]; then sourcepath="${option%/}/*" else sourcepath="$(pwd)/${option%/}/*" fi else if [ -z "$destpath" ]; then if [[ $option =~ ^/.* ]]; then destpath="${option%/}" else destpath="$(pwd)/${option%/}" fi fi fi fi fi ;; esac done if [ -r "$configfile" ]; then source "$configfile" fi #read list if listfile is given if [ -r "$listfile" ]; then while read line; do # find first letter fletter=${line:0:1} if [ -z $fletter ]; then #skip line it's empty : elif [ $fletter = "#" ]; then #skip line it's a comment : else sourcepath="" destpath="" for option in $line; do if [ -z "${option//[0-9]/}" ]; then versions="$option" else if [ -z "$sourcepath" ]; then if [[ $option =~ .*@.* ]]; then sourcepath="${option%/}/*" elif [[ $option =~ ^/.* ]]; then sourcepath="${option%/}/*" else sourcepath="$(pwd)/${option%/}/*" fi else if [ -z "$destpath" ]; then if [[ $option =~ ^/.* ]]; then destpath="${option%/}" else destpath="$(pwd)/${option%/}" fi fi fi fi done if ( preflight ); then sshbackup fi fi done < "$listfile" else if ( preflight ); then sshbackup fi fi # **** end of script **** exit 0