diff --git a/timemachine b/timemachine index 27c7c38..510bc3a 100755 --- a/timemachine +++ b/timemachine @@ -31,12 +31,12 @@ SSH_ARGS="-oStrictHostKeyChecking=no -oLogLevel=QUIET -q" ################################################################################ print_usage() { - echo "Usage: ${MY_NAME} [-vd] -- [rsync opts]" + echo "Usage: ${MY_NAME} [-vd] ... -- [rsync opts]" echo - echo " ${MY_NAME} [-vdpi] : -- [rsync opts]" - echo " ${MY_NAME} [-vdpi] @: -- [rsync opts]" - echo " ${MY_NAME} [-vdpi] : -- [rsync opts]" + echo " ${MY_NAME} [-vdpi] ... : -- [rsync opts]" + echo " ${MY_NAME} [-vdpi] ... @: -- [rsync opts]" + echo " ${MY_NAME} [-vdpi] ... : -- [rsync opts]" echo echo " ${MY_NAME} [-vdpi] : -- [rsync opts]" @@ -59,7 +59,7 @@ print_usage() { echo echo "Required arguments:" - echo " Local source directory" + echo " ... One or more local source directories" echo " Local destination directory." echo " : SSH host and source/destination directory on server" echo " @: SSH user, SSH host and source/destination directory on server" @@ -81,10 +81,12 @@ print_usage() { echo "Examples:" echo " Simply back up one directory recursively" echo " timemachine /home/user /data" + echo " Back up multiple directories" + echo " timemachine /home/user /etc /var/log /data" echo " Do the same, but be verbose" - echo " timemachine -v /home/user /data" + echo " timemachine -v /home/user /etc /data" echo " Append rsync options and be very verbose" - echo " timemachine -d /home/user /data -- --progress --verbose" + echo " timemachine -d /home/user /etc /data -- --progress --verbose" echo " Log to file" echo " timemachine -v /home/user /data > /var/log/timemachine.log 2> /var/log/timemachine.err" echo @@ -355,26 +357,60 @@ done ################################################################################ if [ "${#}" -lt "2" ]; then - logerr " and are required." + logerr "At least one and are required." logerr "See -h for help." exit 1 fi -if is_remote "${1}"; then - if is_remote "${2}"; then - logerr "Source and Target cannot both be remote locations." - logerr "See -h for help." - exit 1 +# Extract destination (last argument) and sources (all but last) +DEST="" +SOURCES="" +arg_count="${#}" +i=1 +for arg in "${@}"; do + if [ "${i}" -eq "${arg_count}" ]; then + DEST="${arg}" + else + if [ -z "${SOURCES}" ]; then + SOURCES="${arg}" + else + SOURCES="${SOURCES} ${arg}" + fi fi + i=$((i + 1)) +done + +# Validate that we don't have multiple remote sources +remote_source_count=0 +for src in ${SOURCES}; do + if is_remote "${src}"; then + remote_source_count=$((remote_source_count + 1)) + fi +done + +if [ "${remote_source_count}" -gt 1 ]; then + logerr "Multiple remote sources are not supported." + logerr "See -h for help." + exit 1 fi -if ! dir_exists "${1}"; then - logerr "Source directory does not exist: ${1}" +if [ "${remote_source_count}" -gt 0 ] && is_remote "${DEST}"; then + logerr "Source and Target cannot both be remote locations." logerr "See -h for help." exit 1 fi -if ! dir_exists "${2}"; then - logerr "Target directory does not exist: ${2}" + +# Validate all source directories exist +for src in ${SOURCES}; do + if ! dir_exists "${src}"; then + logerr "Source directory does not exist: ${src}" + logerr "See -h for help." + exit 1 + fi +done + +if ! dir_exists "${DEST}"; then + logerr "Target directory does not exist: ${DEST}" logerr "See -h for help." exit 1 fi @@ -390,11 +426,8 @@ fi # Main Entrypoint ################################################################################ -# Get arguments and remove them afterwards to have ${@} contain -# all additional rsync options -SRC="${1}" -DEST="${2}" -shift 2 +# Remove destination from arguments and handle -- separator +shift "${arg_count}" [ "${#}" -ge 1 ] && [ "${1}" = "--" ] && shift # Name of the backup directory @@ -422,12 +455,22 @@ RSYNC_PARTIAL=".partial" BTYPE= +# Build escaped source arguments +ESCAPED_SOURCES="" +for src in ${SOURCES}; do + if [ -z "${ESCAPED_SOURCES}" ]; then + ESCAPED_SOURCES="$( escape_path "${src}" )" + else + ESCAPED_SOURCES="${ESCAPED_SOURCES} $( escape_path "${src}" )" + fi +done + # Only link destination if it already exists if link_exists "${DEST}/${BACKUP_LATEST}"; then BTYPE="incremental" logmsg "Starting incremental backup" - logmsg "\$ rsync $* $( escape_path "${SRC}" ) $( escape_path "${DEST}/${BACKUP_INPROGRESS}" )" + logmsg "\$ rsync $* ${ESCAPED_SOURCES} $( escape_path "${DEST}/${BACKUP_INPROGRESS}" )" cmd="rsync \ -e \"ssh ${SSH_ARGS}\" \ @@ -442,12 +485,12 @@ if link_exists "${DEST}/${BACKUP_LATEST}"; then --partial-dir=${RSYNC_PARTIAL} \ --link-dest=../${BACKUP_LATEST} \ $* \ - $( escape_path "${SRC}" ) $( escape_path "${DEST}/${BACKUP_INPROGRESS}" )" + ${ESCAPED_SOURCES} $( escape_path "${DEST}/${BACKUP_INPROGRESS}" )" else BTYPE="full" logmsg "Starting full backup" - logmsg "\$ rsync $* $( escape_path "${SRC}" ) $( escape_path "${DEST}/${BACKUP_INPROGRESS}" )" + logmsg "\$ rsync $* ${ESCAPED_SOURCES} $( escape_path "${DEST}/${BACKUP_INPROGRESS}" )" cmd="rsync \ -e \"ssh ${SSH_ARGS}\" \ @@ -461,7 +504,7 @@ else --delete-excluded \ --partial-dir=${RSYNC_PARTIAL} \ $* \ - $( escape_path "${SRC}" ) $( escape_path "${DEST}/${BACKUP_INPROGRESS}" )" + ${ESCAPED_SOURCES} $( escape_path "${DEST}/${BACKUP_INPROGRESS}" )" fi if ! eval "${cmd}"; then