david/sshbackup
david
/
sshbackup
Archived
1
0
Fork 0
This repository has been archived on 2023-12-23. You can view files and clone it, but cannot push or open issues or pull requests.
sshbackup/sshbackup

405 lines
10 KiB
Bash
Executable File

#!/bin/bash
# ************************************* #
# #
# sshbackup #
# #
# ************************************* #
# **** function definitions ****
bashtrap()
{
echo
echo "CTRL+C detected."
echo "commiting suicide."
exit 1
}
usage()
{
echo
echo "usage: sshbackup <options> 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 <file> list of sources and destinations"
echo " -c, --config <file> alternate config file [~/.sshbackup]"
echo " -s, --sshkey <file> alternate sshkey [~/.ssh/id_rsa]"
echo " -b, --bandwidth <kbps> bandwidth limit in kbit/s"
echo
echo " -d, --deploy <hostname> deploy settings to remote host"
echo " -n, --no-root run without root privileges"
echo
}
version()
{
echo
echo -e "vesion: \033[1;37m$version\033[0m"
echo "author: $author"
echo
}
pipewrap()
{
echo $1
local lockfile=$2;
while true; do
if [ ! -e $lockfile ]; then
return 0
fi
read -t 1 line
if [ $? -eq 0 ]; then
echo $line
fi
done
}
sshsudo()
{
local machine=$1
local password=""
local script=$2
local arguments=$3
read -s -p "please enter your [sudo] password for $machine:" password
echo
local remotescript=/tmp/sshsudo_`date +%s`
sshpass -p "$password" scp -q "$script" "$machine:'$remotescript'"
sshpass -p "$password" ssh -q "machine" "sudo -K"
local lockfile=`mktemp`
eval pipewrap '$password' '$lockfile' | (sshpass -p "$password" ssh -q "$machine" "sudo -S '$remotescript' $arguments"; rm "$lockfile")
sshpass -p $password ssh -q "$machine" rm $remotescript
}
interactive()
{
tty -s
return $?
}
amiroot()
{
if [ $(id -u) -eq 0 ]; then
return 0
else
return 1
fi
}
findhome()
{
#get executing user id
local userid=$(id -u)
#find out where executing users $HOME is
while read line; do
line=$(echo $line | sed 's/ //g')
line=$(echo $line | sed 's/:/ /g')
if [ $(echo $line | awk '{print $3}') -eq $userid ]; then
local home=$(echo $line | awk '{print $6}')
fi
done < /etc/passwd
#return home directory
echo $home
}
preflight()
{
#amiroot?
if ( ! amiroot ) && [ $noroot -eq 0 ]; then
echo "aborting mission. you need be root or use the --no-root option."
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 there is a remote source or destination check for ssh key
if [[ $sourcepath =~ .*@.* ]] || [[ $destpath =~ .*@.* ]]; then
#find the executing users home directory
local home=$(findhome)
#if $sshkeyfile is not set use this path
if [ -z $sshkeyfile ]; then
sshkeyfile="$home/.ssh/id_rsa"
fi
if [ -r $sshkeyfile ]; then
#ssh key found
:
else
if ( interactive ); then
echo "no ssh key found"
echo -e "do you want to create a ssh key pair? [y/n] \c"
read choice
if [ -z $choice ]; then
echo "aborting mission. no ssh key found."
return 1
elif [ $choice == "y" ] || [ $choice == "Y" ]; then
#creating ssh key pair
ssh-keygen
#TODO: key should also be deployed to remote side
return 1 #for now i'll break up here
fi
else
echo "aborting mission. no ssh key found."
return 1
fi
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
#bandwidth limit
if [ $limit -gt 0 ]; then
limit=$((limit/8))
cmdopt="$cmdopt --bwlimit=$limit"
fi
#run rsync
$localcmd $cmdopt -e "ssh -q -i $sshkeyfile" --rsync-path="$remotecmd" $sourcepath $destpath/0
if [ $? -ne "0" ]; then
echo "an error occured while running backup for $sourcepath"
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
}
# **** config section ****
version="0.4.0"
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"
versions=999
config=0
sshkey=0
bandwidth=0
limit=0
list=0
noroot=0
deploy=0
options=$*
# **** start of script ****
#initialize bashtrap
trap bashtrap INT
# **** option handler ****
#end script if no options are given
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
;;
-b|--bandwidth)
bandwidth=1
;;
-n|--no-root)
noroot=1
;;
-d|--deploy)
deploy=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 [ $bandwidth -eq 1 ]; then
if [ -z "${option//[0-9]/}" ]; then
limit=$option
else
echo "aborting mission. unknown bandwidth limit given. [$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
elif [ $deploy -eq 1 ]; then
#TODO: do nothing for now
:
deploy=0
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
#read config if there is one
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
exit 0
# **** end of script ****