#!/bin/sh # smoothback.sh v.1.1 # http://smoothback.net # Originally written and distributed by Dayid Alan # Published under the Pancake Public License v.1.0 # available at: http://code.dayid.org/ppl/ppl.txt # # This script is set to backup a remote system to your machine. # Logs are stored in ${home}/logs. ########################################################################################## # These variables definitely need to be modified: # Set the remote machine or hostname: bkup='emiline' # Set arguments for rsync to pass: # -n is for --dry-run: this just shows what would be done. # You should remove -n if you want this script to do something. rsyncopt="-c -g -l -o -r --stats -t -u -z --exclude=\".hide\"" ########################################################################################## # These variables may need to be modified: # Name for backups to be kept under: name="${bkup}" # 1=send e-mail, 0=do not mailb="1" # Subject for mail output: mailsub="$0 output" # Who to send the mail to: mailuser=`whoami` mailtmp="${HOME}/.$$" # If you use hardlinks, along with the backup $name from above, you will end up having directories e.g.,: # /usr/backup/hostname/ & /usr/backup/hostname.1/ # and so on, where as the number rises, the backup is older. # Set the destination folders on the local machine (one dir, no trailing /) path="/usr/backup/${name}" # Set how many days of backups to keep with hardlinks (0 means none) num1="3" # Set the directories to be synced: full path, space seperated, no trailing / dir="/usr/home /etc /root" # Set the user to login to the remote machine as: (current user by default) user=`id -un` # Set parent dir for logs/pid, no trailing / home="${HOME}" # Find where nice and rsync commands are located: lnice=`which nice` lrsync=`which rsync` # Set how much to nice the rsync process (here, -19 nices to 19, *not* -19) hownice="-19" # Set number of runs to do before using the ${rsyncopt} (7 times by default) # This does not apply if you are using hardlinks. num="7" # Set the numer of lines to keep when cleaning out the logfile (5 by default) keep="5" # Set the location and name for the smoothback logfile: (~/log/smoothback.log by default) logfile="${bkup}.log" # No trailing / logdir="${home}/logs" pid="${home}/.${bkup}.pid" ########################################################################################## # These variables should not need to be modified: # Set the long rsync command: prsync="${lnice} ${hownice} ${lrsync} ${rsyncopt}" # Set arguments for rsync to pass on alt-time periods: rsyncalt="--delete" # Set the argument to pass to rsync for the hardlinks: hl="--delete --ignore-existing" hl2="" allowed=`expr ${num} + ${keep}` log="${logdir}/${logfile}" num3="${num1}" num4="${num1}" ########################################################################################## # You should not modify below this point. clear [ -d ${path} ] || mkdir -p ${path} # Check for path, create if needed [ -d ${logdir} ] || mkdir -p ${logdir} 2> /dev/null [ -f ${log} ] || touch ${log} # Check for logfile, create if needed [ "${mailb}" -eq "1" ] || mailtmp="/dev/null" # If not using mail, set mailtmp to null if [ -f ${pid} ] # Check for PID file then # Use the information from PID file to see if this script is running: proc=`awk '{ print $1 }' ${pid}` && runtest=`ps ax | awk '{ print $1 }' | fgrep ^${proc} | grep -v grep | wc -l` # If still running, fail and give warning; if dead, remove the pid file and restart [ "${runtest}" -gt "0" ] && echo "`date` Sync failed due to ${pid}" >> ${log} && exit 1 \ || rm -f ${pid} && clear && echo "Stale lockfile. Restarting in 3 seconds..." && sleep 3 && /bin/sh $0 else echo $$ > ${pid} # Create PID file if needed [ "${num1}" -ge "1" ] && rsyncalt="" || hl="" # Blank rsyncalt if using hardlinks. Blank hl if not. while [ "${num1}" -ge "1" ]; do num2=`expr ${num1} - 1` # If numhl is less than 1, hardlinks are off, none of this section is processed. if [ "${num1}" -eq "1" ] # While the number is greater than or equal to one, do this loop: # If the number is 1, then move path to path.1 - this should happen last. then [ -d ${path} ] && rsync -au --delete --link-dest="${path}" ${path}/ ${path}.1/ && echo "Moving ${path} to ${path}.1" else [ -d ${path}.${num2} ] || mkdir -p ${path}.${num2} # If the next directory exists we continue. If not we create it. # We move the next-to-oldest directory to the oldest's position: rsync -au --delete --link-dest="${path}" ${path}.${num2}/ ${path}.${num1}/ && echo "Moving ${path}.${num2} to ${path}.${num1}" # For each dir we're going to sync, add the oldest copies of them to --link-dest: for location in ${dir}; do [ -d ${path}.${num1}${location} ] || mkdir -p ${path}.${num1}${location}; done fi num1="${num2}" # Set the next value for num1 done # Using the logfile, see how many times the script has run with a regular sync: runtimes=`wc -l ${log} | awk '{ print $1 }'` # On the Xth time the script runs, use the ${rsyncalt} argument if [ "${runtimes}" -gt "${allowed}" ] # Set use to use the rsyncalt argument & rotate the log then use="${prsync} ${rsyncalt} ${hl}" && tail -n ${keep} ${log} > ${home}/$$ && mv ${home}/$$ ${log} && \ echo "`date` -- Log Rotated --" >> ${log} && echo -n "`date` Core update with ${rsyncalt}:" >> ${log} # Set use to not use rsyncalt: else use="${prsync} ${hl}" && echo -n "`date` Core update:" >> ${log} fi # For each directory to backup, do this: for place in ${dir}; do # Check for the path/dir to exist. If so, continue; if not, create it. [ -d ${path}${place} ] || mkdir -p ${path}${place} && echo "Creating ${path}${place}" # Now process each directory and echo the status out to the log. while [ "${num3}" -ge "1" ]; do hl2="${hl2} --link-dest="${path}.${num3}${place}"" && num3=`expr ${num3} - 1`; done ${use} ${hl2} ${user}@${bkup}:${place}/ ${path}${place}/ 1>>${mailtmp} 2>&1 && echo -n "${place} successful " >> ${log} || echo -n "${place} failed " >> ${log} num3="${num4}" done # Add a newline to the log file and put the date we completed at. echo "...complete @ `date`" >> ${log} # If mail is on, send the mail: [ "${mailb}" -eq "1" ] && cat ${mailtmp} | mail -s "${mailsub}" ${mailuser} # Remove the pid file rm -f ${pid}; [ "${mailb}" -eq "1" ] && rm -f ${mailtmp} fi