#!/usr/bin/env bash # # destination - functions acting on the destination host. # # Copyright 2015 - 2019 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 . # # Setup working directory on the destination files system. # # requires: create_new_dir # function dest_prepare_initial { create_new_dir "$dest_path" || return $? create_new_dir "${dest_path}/work" || return $? return $RET_SUCCESS } # Setup working directory on the destination file system, check for too new # (future) backups and refresh the 'latest' symlink. # # requires: assert_is_dir, dest_list_backup_dirs, create_new_dir # $dest_path # # $1: old date: date in $DATEFMT # $2: new date: date in $DATEFMT # function dest_prepare_incremental { local work_dir="${dest_path}/work" local old_date="$1" local new_date="$2" local latest assert_is_dir "$dest_path" || return $? latest="$(dest_list_backup_dirs | tail -1)" if [[ "$old_date" != "$latest" ]] then error "Dates of last backup do not match on source and destination." debug_error "source: ${old_date} | dest: ${latest}" return $RET_FILE_ERR fi if ! [[ "$latest" < "$new_date" ]] then error "Latest backup on destination not older than source." return $RET_FILE_ERR fi # Refresh 'latest' symlink in case it was obsoleted or corrupted. ln -sfT "$latest" "${dest_path}/latest" || return $RET_ERROR create_new_dir "$work_dir" || return $? return $RET_SUCCESS } # Finalize the backup creation on the destination host. # # requires: dest_refresh_symlinks # `-> assert_is_dir, dest_list_backup_dirs, # replace_symlink_target, create_dir # $dest_path (self, <- dest_refresh_symlinks), # # $1: old date: date in $DATEFMT # $2: new date: date in $DATEFMT # function dest_finalize { local old_date="$1" local new_date="$2" message "Finish installment of new backup..." mv -T "${dest_path}/work/${new_date}" "${dest_path}/${new_date}" \ || return $RET_ERROR message "Remove auxiliary directory tree..." rm -rf "${dest_path}/work/${old_date}" || return $RET_ERROR rmdir "${dest_path}/work" || return $RET_ERROR dest_refresh_symlinks || return $? message 'Successfully finished installment of new backup.' } # Print existing backup directories. # Must be run on destination host. # # requires: $dest_path # function dest_list_backup_dirs { find "$dest_path" -mindepth 1 -maxdepth 1 -type d \ -regextype posix-extended -regex \ '.*/[0-9]{4}-[0-1][0-9]-[0-3][0-9]_[0-2][0-9]([0-5][0-9]){2}' \ -printf '%f\n' \ | LC_ALL=C sort if [[ ${PIPESTATUS[0]} -eq 0 && ${PIPESTATUS[1]} -eq 0 ]] then return $RET_SUCCESS else return $RET_ERROR fi } # Create symbolic links to backup directories. # # requires: assert_is_dir, dest_list_backup_dirs, replace_symlink_target, # create_dir # $dest_path # function dest_refresh_symlinks { local -i i local -i n local -a backup_dirs local link local ret assert_is_dir "$dest_path" || return $? backup_dirs=( $(dest_list_backup_dirs || return $?) ) n=${#backup_dirs[@]} replace_symlink_target "${dest_path}/latest" "${backup_dirs[n-1]}" \ || return $? ## by_number numdir="${dest_path}/by_number" create_dir "$numdir" || return $? # Remove old symlinks. find "$numdir" -mindepth 1 -maxdepth 1 -type l -regextype posix-extended \ -regex '.*/[0-9]*' -delete || return $RET_ERROR for (( i = 0; i < n; i++ )) do ln -s "../${backup_dirs[i]}" "$(printf "%s/%.${#n}u" "$numdir" $i)" \ || return $RET_FILE_ERR done return $RET_SUCCESS } # vi: ft=bash ts=2 sw=2 noet