#!/bin/bash
# A Simple Server Sync Script
### Required packages
# rsync -- runs the data sync process
# cifs-utils -- for windows/smb shares
# sshfs -- for ssh mounts
# msmtp -- for email notifications
### User-defined variables
# Name the backup job
BackupName="Client Name Backup"
# The path where logs should be stored
LogFolder="$HOME/Logs/client"
# The path to the source/root folder to be backed up
SourcePath="/media/clientmounts/client-name"
# The path to the backup target/repository
TargetPath="/media/repo-name/client-name/sync"
# The command used to mount the backup source
SourceMountCommand="sshfs hostname.domain:../../media/local $SourcePath"
# The command used to mount the backup target
TargetMountCommand="sudo mount -a"
# Email notification settings
SMTP_From="sender@domain.com"
SMTP_To="recipient@domain.com"
### End of user-defined variables
LogFile="$LogFolder/backup.log"
ReportFile=$(mktemp)
Output=$(mktemp)
### Functions
Say() {
echo "$1"
echo "$(date +%b%d) | $(date +%H:%M) | $1" >> $LogFile
echo "$(date +%b%d) | $(date +%H:%M) | $1" >> $ReportFile ;}
Fail() { Say "$1" ; SendNotify ; exit ;}
SayHead() {
Say "============================"
Say "Starting $BackupName"
Say "============================" ;}
SayFoot() {
Say "============================"
Say "Finished $BackupName"
Say "============================"
Say "Running time: $Time"
Say "============================" ;}
MountPath() {
case $1 in
Source) $SourceMountCommand &&
if [ ! -d $SourcePath ]
then Fail "There was a problem mounting backup source."
fi ;;
Target) $TargetMountCommand &&
if [ ! -d $TargetPath ]
then Fail "There was a problem mounting backup target."
fi ;;
esac ;}
Check() {
if [ ! -d $2 ]
then MountPath $1 || Fail "Failed to mount backup $1."
fi ;}
ProcessArgs() {
cd $TargetPath
rm -rf $1.backup.7
mv $1.backup.6 $1.backup.7
mv $1.backup.5 $1.backup.6
mv $1.backup.4 $1.backup.5
mv $1.backup.3 $1.backup.4
mv $1.backup.2 $1.backup.3
mv $1.backup.1 $1.backup.2
mv $1.backup.0 $1.backup.1
Say "Syncing '$1'."
rsync -a --delete --link-dest=../$1.backup.1 $SourcePath/$1/ $1.backup.0/ &>$LogFolder/rsync-$1.log &&
Say "Completed syncing '$1'." ;}
Backup() {
for arg in $* ; do
Check Source $SourcePath/$arg || Fail "Failed to mount source share(s)."
Check Target $TargetPath || Fail "Failed to mount target folder(s)."
ProcessArgs $arg || Say "There were errors syncing '$arg'."
done ;}
SendNotify() {
echo "To: $SMTP_To" >> $Output
echo "From: $SMTP_From" >> $Output
echo "Subject: $BackupName" >> $Output
echo "" >> $Output
cat $ReportFile >> $Output
cat $Output | msmtp $SMTP_To || Say "SMTP notification failed."
shred $Output
shred $ReportFile ;}
# The SendNotify function requires msmtp package
# and a properly-configured ~/.msmtprc
# For example, your ~/.msmtprc file should
# look something like this:
# defaults
# auth on
# tls on
# tls_trust_file /etc/ssl/certs/ca-certificates.crt
# logfile ~/.msmtp.log
#
# account default
# host smtp.office365.com
# port 587
# from sender@domainname.com
# user sender@domainname.com
# password password
# If you put your password in this file
# you will need to 'chmod 600 ~/.msmtprc'
# to protect the file. Alternatively, you can use
# 'passwordeval' with an encrypted key file.
# That line would look something like:
# passwordeval "gpg -d --quiet --for-your-eyes-only ~/keyfile.gpg | sed -e '$a\'"
### Commands
# If your source and target mounts are in /etc/fstab
# This line should take care of mounting needs
#sudo mount -a
mkdir -p $LogFolder
SayHead
Backup share1 share2 share3
# Running time of the script is recorded at the end
Duration=$SECONDS
Time="$(($Duration / 60)) minutes and $((Duration % 60)) seconds"
SayFoot
SendNotify