#!/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 " -c, --config alternate config file [~/.sshbackup]" echo " -l, --list list of sources and destinations" 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? if [ $(whoami) != "root" ]; 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 $destinationpath ]; then echo "aborting mission. no destination path given." return 1 fi #if remote source or destination check for sshkey if [[ $sourcepath =~ .*@.* ]] || [[ $destinationpath =~ .*@.* ]]; 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 "$destinationpath/0" ]; do if [ -d "$destinationpath/$num" ]; then mv $destinationpath/$num $destinationpath/$((num+1)) fi let num-- done #create destinationpath if not existing mkdir -p $destinationpath/0 #add link-destination option if existing if [ -d $destinationpath/1 ]; then cmdopt="$cmdopt --link-dest=$destinationpath/1" fi #run rsync $localcmd $cmdopt -e "ssh -q -i $sshkeyfile" --rsync-path="$remotecmd" $sourcepath $destinationpath/0 if [ $? -ne "0" ]; then return 1 fi #removing obsolet version(s) local i=1 while [ -d $destinationpath/$((versions+i)) ]; do rm -rf $destinationpath/$((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 "$destinationpath" ]; then if [[ $option =~ ^/.* ]]; then destinationpath="${option%/}" else destinationpath="$(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="" destinationpath="" 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 "$destinationpath" ]; then if [[ $option =~ ^/.* ]]; then destinationpath="${option%/}" else destinationpath="$(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