aboutsummaryrefslogtreecommitdiff
path: root/rsync-backup.sh
diff options
context:
space:
mode:
authorEinhard Leichtfuß <alguien@respiranto.de>2019-04-04 00:04:37 +0200
committerEinhard Leichtfuß <alguien@respiranto.de>2019-04-04 00:04:37 +0200
commitab0cff3bb36721e982301e14435c0f4c8f313995 (patch)
tree44702cebd2019a383e574db3f1ffbd94db670092 /rsync-backup.sh
parent7831ff7b87b2a100ec04611eadefa0a9370f5057 (diff)
Add remote backup functionality
Create wrapper functions that take a host and a function with named arguments. The supplied function is the to be executed on the specified host, which may be the empty string signifying local execution. These wrapper functions essentially export the to be run function and any of its recursive dependencies, further the named arguments as variables, to the remote host, and run the function remotely. That is, if the host is non-local. Also, - use appropriate function names to differentiate between destination and source host wherever applicable. - add comments, - enhance TODO and README, - rename some variables in order to increase consistency, - move some global declarations further upward, - make variables readonly when reasonable, - use named return and exit codes, - add a general `ask'-function.
Diffstat (limited to 'rsync-backup.sh')
-rwxr-xr-xrsync-backup.sh299
1 files changed, 0 insertions, 299 deletions
diff --git a/rsync-backup.sh b/rsync-backup.sh
deleted file mode 100755
index 0c48018..0000000
--- a/rsync-backup.sh
+++ /dev/null
@@ -1,299 +0,0 @@
-#!/bin/bash
-#
-# rsync-backup.sh - a backup script using rsync.
-#
-# Copyright 2015 - 2018 Einhard Leichtfuß
-#
-# This file is part of rsync-backup.
-#
-# rsync-backup is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published
-# by the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# rsync-backup is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with rsync-backup. If not, see <https://www.gnu.org/licenses/>.
-#
-
-RSYNC=rsync
-
-typeset -a rsync_args
-typeset -a rsync_inc_args
-typeset -A bakpath
-typeset filter_file_all # Applied after specific filter.
-typeset -A filter_file
-
-# Default arguments for rsync (-rptogAXlHS, --timeout, --info).
-rsync_args=(
- --recursive
- --perms --times --owner --group
- --acls --xattrs
- --links
- --hard-links
- --sparse
- --timeout=60
- #-vv
- --info=progress2
- )
-
-# Supplemental arguments for rsync; only used when an actual incremental
-# update is performed, i.e. when --link-dest is used.
-rsync_inc_args=(
- --fuzzy --fuzzy
- )
-
-filter_file_all=/etc/rsync-backup/filter
-
-config=/etc/rsync-backup/backup.conf
-source "$config"
-
-src=/home/respiranto/txt/bash/rsync-backup/src
-dest=/home/respiranto/txt/bash/rsync-backup/dest
-
-typeset -l reply
-typeset -i i n
-
-# RSYNC args.
-# basic args: --recursive --perms --times --owner --group --links
-# extra args: --sparse --acls --xattrs --hard-links --timeout=60
-# --fuzzy --fuzzy
-# --filter="merge <file>"
-# likely: --compress
-# --partial{,dir=DIR}
-# --progress
-# possibly: --devices --specials
-# --max-size=SIZE-OF-FILE
-# --one-file-system
-# --log-file=FILE --log-file-format=FORMAT
-# --human-readable
-# unlikely: --omit-{dir,link}-times --update (!--inplace) --delete
-# --exclude
-# great: --link-dest=DIR (timestamps?)
-# testing: --verbose --dry-run (-vn)
-# interesting: --sockopts --itemize-changes --out-format=FORMAT
-# --stats
-
-function main
-{
- # In case of a non-matching wildcard, return nothing.
- shopt -s nullglob
- # Include dotfiles (except . and ..) in regex matching.
- shopt -s dotglob
-
- get_args "$@" || return $?
-
- check_paths || return $?
-
- # Change the separation char to $'\n' to avoid confusion with filenames
- # containing spaces (default is $' \t\n').
- IFS=$'\n'
-
- find_existing_backup_dirs || return $?
-
- perform_backup || return $?
-
- refresh_symlinks || return $?
-}
-
-
-function get_args
-{
- if [ $# -eq 0 ]
- then
- echo "Usage: $0 <src> [<dest>]"
- return 1
- fi
-
- dirpath="$(realpath "$1")"
-
- if [ $# -gt 1 ]
- then
- bakpath="$(realpath $2)"
- elif test -v bakpath[$dirpath]
- then
- bakpath="${bakpath[$dirpath]}"
- else
- echo "Error: Backup path for $dirpath not configured."
- return 1
- fi
-
- filter_args=()
- if test -v filter_file[$dirpath] && test -f "${filter_file[$dirpath]}"
- then
- filter_args+=("--filter=merge ${filter_file[$dirpath]}")
- fi
- if test -v filter_file_all -a -f "$filter_file_all"
- then
- filter_args+=("--filter=merge ${filter_file_all}")
- fi
-}
-
-
-function check_paths
-{
- # Test whether the dirs exist already.
- if ! test -d "$dirpath"
- then
- echo "Source (\"$dirpath\") does not exist."
- return 1
- fi
-
- if ! test -d "$bakpath"
- then
- echo "Target (\"$bakpath\") does not exist."
- echo -n "Do you want do create it [y/N]? "
- read reply
- if [[ "$reply" != "y" && "$reply" != "yes" ]]
- then
- return 1
- fi
-
- if ! mkdir -p "$bakpath"
- then
- echo "Backup creation has failed."
- echo "\"$bakpath\" could not be created."
- return 1
- fi
- fi
-}
-
-
-function find_existing_backup_dirs
-{
- n=0
- for file in `ls "$bakpath"`; do
- if test -d $bakpath/$file \
- && [[ "$file" =~ ^[0-9]{4}-[0-1][0-9]-[0-3][0-9]_[0-2][0-9]([0-5][0-9]){2}.backup$ ]]
- then
- dirs[n]="$file"
- n+=1
- fi
- done
-}
-
-
-# $1 path
-# $2 error message: string
-function clear_file
-{
- if test -e "$1" -o -L "$1"; then
- echo "It seems like the last backup process failed or you have created" \
- "the file \"$1\" manually."
- echo -n "Do you want to delete it [y/N]? "
- read reply
- if [[ "$reply" == "y" || "$reply" == "yes" ]]
- then
- printf "Deleting"
- if rm -rf "$1"; then
- printf " - done\n"
- return 0
- else
- printf '\n%s\n' "$2"
- printf 'The file \"%s\" could not be deleted.\n' "$1"
- return 1
- fi
- else
- printf '%s\n' "$2"
- printf '%s %s\n' "Please remove the above mentioned file manually" \
- "or run this script once more."
- return 1
- fi
- fi
- return 0
-}
-
-
-function perform_backup
-{
- bakdate=`date +%Y-%m-%d_%H%M%S.backup`
- finaldir="$bakpath/$bakdate"
- tempdir="$bakpath/new.backup"
- clear_file "$tempdir" "Backup creation has failed." || return 1
- clear_file "$finaldir" "Backup creation has failed." || return 1
-
- # note: $n == ${#dirs[@]}
- printf 'Starting backup nr. %u.\n' "$n"
- if [ $n -eq 0 ]
- then
- # Perform first backup, not incremental.
- $RSYNC "${rsync_args[@]}" \
- "${filter_args[@]}" \
- "$dirpath"/ "$tempdir" \
- || return 1
- else
- # Perform incremental backup on the basis of the last.
- $RSYNC "${rsync_args[@]}" \
- "${rsync_inc_args[@]}" --link-dest="${bakpath}/${dirs[n-1]}" \
- "${filter_args[@]}" \
- "$dirpath"/ "$tempdir" \
- || return 1
- fi
-
- mv "$tempdir" "$finaldir" || return 1
- printf '\nCreating of backup nr. %u succesfully executed.\n' "$n"
-}
-
-
-function refresh_symlinks
-{
- linkdir="$bakpath/latest"
- if test -L "$linkdir"
- then
- rm "$linkdir"
- ln -s "$bakdate" "$linkdir"
- elif clear_file "$linkdir" "Creation of softlink \"$linkdir\" failed."
- then
- ln -s "$bakdate" "$linkdir"
- fi
-
- # by_number
- numdir="$bakpath/by_number"
- if ! test -d "$numdir"
- then
- if clear_file "$numdir" "Creating directory $numdir failed."
- then
- mkdir "$numdir"
- else
- return 1
- fi
- fi
-
- for file in "$numdir"/*
- do
- if test -L "$file"
- then
- rm "$file"
- else
- if ! clear_file "$file" "Setting up numbered softlinks failed."
- then
- return 1
- fi
- fi
- done
-
- dirs[$n]="$bakdate" # Set last dir on current.
-
- max_digits=${#n}
- zeros[max_digits]=''
- i=$max_digits-1
- while [ $i -ge 1 ]
- do
- zeros[i]=${zeros[i+1]}0
- i+=-1
- done
-
- i=0
- while [ $i -le $n ]
- do
- ln -s "../${dirs[i]}" "$numdir/${zeros[${#i}]}$i"
- i+=1
- done
-}
-
-
-main "$@"