#!/usr/bin/env bash # ################################################## # My Generic sync script. # version="2.1.0" # Sets version variable # scriptTemplateVersion="1.1.1" # Version of scriptTemplate.sh that this script is based on # v.1.1.0 - Added 'debug' option # v.1.1.1 - Moved all shared variables to Utils # # This script will give you the option of using rsync # or Unison. Rsync is for one-way syncing, Unison is for # two-way syncing. # # Depending on what flags are passed to the script and # what information is written in the config file, this script # will perform different behavior. # # USAGE: # # 1) IMPORTANT: Copy this script and rename it for your purpose before running. # 2) Run the script. This will create a blank config file for you and then exit. # 3) Enter your information within the config file # 4) Run the script again. # # TO DO: # * Add SSH functionality # # DISCLAIMER: # I am a novice programmer and I bear no responsibility whatsoever # if this (or any other) script that I write wipes your computer, # destroys your data, crashes your car, or otherwise causes mayhem # and destruction. USE AT YOUR OWN RISK. # # # HISTORY: # * 2015-01-02 - v1.0.0 - First Creation # * 2015-01-03 - v1.1.0 - Added support for using roots in Unison .prf # * 2015-03-10 - v1.1.1 - Updated script template version # - Removed $logFile from config. Default is now '~/library/logs/' # * 2015-03-15 - v2.0.0 - Added support for encrypted config files. # * 2015-03-21 - v2.1.0 - Added support for extended RSYNC configurations. # # ################################################## # Source Scripting Utilities # Source Scripting Utilities # ----------------------------------- # If these can't be found, update the path to the file # ----------------------------------- scriptPath="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" if [ -f "${scriptPath}/../lib/utils.sh" ]; then source "${scriptPath}/../lib/utils.sh" else echo "Please find the file util.sh and add a reference to it in this script. Exiting." exit 1 fi # trapCleanup Function # ----------------------------------- # Any actions that should be taken if the script is prematurely # exited. Always call this function at the top of your script. # ----------------------------------- function trapCleanup() { echo "" if is_dir "${tmpDir}"; then rm -r "${tmpDir}" fi die "Exit trapped." # Edit this if you like. } # Set Flags # ----------------------------------- # Flags which can be overridden by user input. # Default values are below # ----------------------------------- quiet=0 printLog=0 verbose=0 force=0 strict=0 debug=0 editConfig=0 mountTest=0 # Set Temp Directory # ----------------------------------- # Create temp directory with three random numbers and the process ID # in the name. This directory is removed automatically at exit. # ----------------------------------- tmpDir="/tmp/${scriptName}.$RANDOM.$RANDOM.$RANDOM.$$" (umask 077 && mkdir "${tmpDir}") || { die "Could not create temporary directory! Exiting." } # Logging # ----------------------------------- # Log is only used when the '-l' flag is set. # # To never save a logfile change variable to '/dev/null' # Save to Desktop use: $HOME/Desktop/${scriptBasename}.log # Save to standard user log location use: $HOME/Library/Logs/${scriptBasename}.log # ----------------------------------- logFile="$HOME/Library/Logs/${scriptBasename}.log" # Configuration file(s) # ----------------------------------- # This script calls for a configuration file. # This is its location. Default is the location # where it will be automatically created.` # ----------------------------------- tmpConfig="${tmpDir}/${scriptName}.cfg" newConfig="./${scriptName}.cfg" encConfig="../etc/${scriptName}.cfg.enc" ############## Begin Script Functions Here ################### # Create new copy of the script if template is being executed function newCopy() { if [ "${scriptName}" = "syncTemplate.sh" ]; then input "name your new script:" read newname verbose "Copying SyncTemplate.sh to ${newname}" cp "${scriptPath}"/"${scriptName}" "${scriptPath}"/"${newname}" && verbose "cp ${scriptPath}/${scriptName} ${scriptPath}/${newname}" success "${newname} created." safeExit fi } function encryptConfig() { # If a non-encrypted config file exists (ie - it was being edited) we encrypt it if is_file "${newConfig}"; then verbose "${newConfig} exists" seek_confirmation "Are you ready to encrypt your config file?" if is_confirmed; then if is_file "${encConfig}"; then rm "${encConfig}" && verbose "Existing encoded config file exists. Running: rm ${encConfig}" fi if is_empty ${PASS}; then # Look for password from CLI verbose "openssl enc -aes-256-cbc -salt -in ${newConfig} -out ${encConfig}" openssl enc -aes-256-cbc -salt -in "${newConfig}" -out "${encConfig}" else verbose "openssl enc -aes-256-cbc -salt -in ${newConfig} -out ${encConfig} -k [PASSWORD]" openssl enc -aes-256-cbc -salt -in "${newConfig}" -out "${encConfig}" -k ${PASS} fi rm "${newConfig}" && verbose "rm ${newConfig}" success "Encoded the config file." safeExit else warning "You need to encrypt your config file before proceeding" safeExit fi fi } function createTempConfig() { # If we find the encoded config file, we decrypt it to the temp location if is_file "${encConfig}"; then if is_empty ${PASS}; then # Look for password from CLI verbose "openssl enc -aes-256-cbc -d -in ${encConfig} -out ${tmpConfig}" openssl enc -aes-256-cbc -d -in "${encConfig}" -out "${tmpConfig}" else verbose "openssl enc -aes-256-cbc -d -in ${encConfig} -out ${tmpConfig} -k [PASSWORD]" openssl enc -aes-256-cbc -d -in "${encConfig}" -out "${tmpConfig}" -k ${PASS} fi fi } function sourceConfiguration() { # Here we source the Config file or create a new one if none exists. if is_file "${tmpConfig}"; then source "${tmpConfig}" && verbose "source ${tmpConfig}" else seek_confirmation "Config file does not exist. Would you like to create one?" if is_not_confirmed; then die "No config file." else touch "${newConfig}" && verbose "touch ${newConfig}" cat >"${newConfig}" <&2; safeExit ;; --version) echo "$(basename $0) $version"; safeExit ;; -p|--password) shift; echo "Enter Pass: "; stty -echo; read PASS; stty echo; echo ;; -v|--verbose) verbose=1 ;; -l|--log) printLog=1 ;; -c|--config) editConfig=1 ;; -d|--debug) debug=1 ;; -q|--quiet) quiet=1 ;; -s|--strict) strict=1;; -f|--force) force=1 ;; -n|--dryrun) DRYRUN=n ;; -m|--mounttest) mountTest=1 ;; -z|--compress) COMPRESS=z ;; --endopts) shift; break ;; *) warning "invalid option: $1.\n"; usage >&2; safeExit ;; # *) die "invalid option: '$1'." ;; esac shift done ############## End Options and Usage ################### # ############# ############# ############# # ## TIME TO RUN THE SCRIPT ## # ## ## # ## You shouldn't need to edit anything ## # ## beneath this line ## # ## ## # ############# ############# ############# # Trap bad exits with your cleanup function trap trapCleanup EXIT INT TERM # Exit on error. Append ||true if you expect an error. set -o errexit # Exit on empty variable if [ "${strict}" == "1" ]; then set -o nounset fi # Run in debug mode, if set if [ "${debug}" == "1" ]; then set -x fi # Bash will remember & return the highest exitcode in a chain of pipes. # This way you can catch the error in case mysqldump fails in `mysqldump |gzip` set -o pipefail # Set timer for script to start STARTTIME=$(date +"%s") header "${scriptName} Begun" newCopy encryptConfig createTempConfig editConfiguration sourceConfiguration hostCheck MethodCheck moutDrives testSources runRsync runUnison unmountDrives # Time the script by logging the end time ENDTIME=$(date +"%s") TOTALTIME=$(($ENDTIME-$STARTTIME)) notifyPushover header "${scriptName} completed in $(convertsecs $TOTALTIME)" safeExit # Exit cleanly