Compare commits
59 Commits
tyriis-master
...
v1.1
| Author | SHA1 | Date | |
|---|---|---|---|
| 9a87c1d4e4 | |||
| 808767dc66 | |||
| c854cd17c6 | |||
| bff263ab57 | |||
| d73b3ffe43 | |||
| b16c3cf4ce | |||
| e7fc37076c | |||
| 4720f404af | |||
| 2f0092ac9f | |||
| 40e5ce4721 | |||
| e5f939222e | |||
| 0db8b3a913 | |||
| c3f15c7834 | |||
| 4da7172099 | |||
| 45875055a4 | |||
| 16fd955e6c | |||
| 08d090f19c | |||
| 2e413d82d7 | |||
| cb252f7545 | |||
| 5d1027fd78 | |||
| 928b32f83e | |||
| b8fb75bbc0 | |||
| 9ece9fbec3 | |||
| 392b8089a5 | |||
| d31b689f6b | |||
| 81d6b4fb99 | |||
| 12784d1d32 | |||
| f5a4275a04 | |||
| a474f139f5 | |||
| 28735b1815 | |||
| f011e1a7ab | |||
| 9b9a564447 | |||
| ae7998025a | |||
| e092d5c2fd | |||
| 2ade9de422 | |||
| 85fea581a6 | |||
| 324a3ffc9a | |||
| 12deac25d6 | |||
| 855c77a83f | |||
| 4250423d98 | |||
| 0c679903af | |||
| 584e3a9b4b | |||
| 19446c24b9 | |||
| bda24be003 | |||
| 8bb5b3f265 | |||
| a67efdd0f1 | |||
| 32e71ce9aa | |||
| 72df5bf33e | |||
| fe0bfde041 | |||
| 8a2e91813b | |||
| c505ecbfb8 | |||
| 159d8b6416 | |||
| 2fd6b109f0 | |||
| d425a05528 | |||
| c23f47164e | |||
| 99258d80ab | |||
| 27a0a1881f | |||
| 8318db90c5 | |||
| a40a733902 |
@@ -1,6 +1,6 @@
|
|||||||
# Rsync time backup
|
# Rsync time backup
|
||||||
|
|
||||||
Time Machine style backup with rsync. Should work on Linux, Mac OS X and Windows with Cygwin.
|
Time Machine style backup with rsync. Should work on Linux (tested on some distros), Mac OS X (fully tested) and Windows with Cygwin (not tested yet but feeback would be welcome).
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|
||||||
@@ -36,18 +36,20 @@ An optional exclude file can be provided as a third parameter. It should be comp
|
|||||||
|
|
||||||
* Exclude file - support for pattern-based exclusion via the `--exclude-from` rsync parameter.
|
* Exclude file - support for pattern-based exclusion via the `--exclude-from` rsync parameter.
|
||||||
|
|
||||||
* The application is one bash script that can be easily edited.
|
* Automatically purge old backups - within 24 hours, all backups are kept. Within one month, the most recent backup for each day is kept. For all previous backups, the most recent of each month is kept.
|
||||||
|
|
||||||
|
* "latest" symlink that points to the latest successful backup.
|
||||||
|
|
||||||
|
* The application is just one bash script that can be easily edited.
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
* Check if there's enough space in the destination before doing the backup. Also automatically delete old backups.
|
* Minor changes (see TODO comments in the source).
|
||||||
|
|
||||||
* Manage the backups in a way similar to Time Machine - hourly backups for the past 24 hours; daily backups for the past month; weekly backups for the previous months.
|
* Backup to remote drive?
|
||||||
|
|
||||||
# LICENSE
|
# LICENSE
|
||||||
|
|
||||||
[MIT](http://opensource.org/licenses/MIT)
|
[MIT](http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
|
||||||
[](https://bitdeli.com/free "Bitdeli Badge")
|
[](https://bitdeli.com/free "Bitdeli Badge")
|
||||||
|
|
||||||
|
|||||||
+110
-93
@@ -1,42 +1,64 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
APPNAME=$(basename $0 | sed "s/\.sh$//")
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Log functions
|
# Log functions
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
fn_log_info() {
|
fn_log_info() { echo "$APPNAME: $1"; }
|
||||||
echo "rsync_tmbackup: $1"
|
fn_log_warn() { echo "$APPNAME: [WARNING] $1"; }
|
||||||
}
|
fn_log_error() { echo "$APPNAME: [ERROR] $1"; }
|
||||||
|
|
||||||
fn_log_warn() {
|
|
||||||
echo "rsync_tmbackup: [WARNING] $1"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn_log_error() {
|
|
||||||
echo "rsync_tmbackup: [ERROR] $1"
|
|
||||||
}
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Make sure everything really stops when CTRL+C is pressed
|
# Make sure everything really stops when CTRL+C is pressed
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
fn_terminate_script() {
|
fn_terminate_script() {
|
||||||
echo "rsync_tmbackup: SIGINT caught."
|
fn_log_info "SIGINT caught."
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
trap 'fn_terminate_script' SIGINT
|
trap 'fn_terminate_script' SIGINT
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Small utility functions for reducing code duplication
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
fn_parse_date() {
|
||||||
|
# Converts YYYY-MM-DD-HHMMSS to YYYY-MM-DD HH:MM:SS and then to Unix Epoch.
|
||||||
|
case "$OSTYPE" in
|
||||||
|
linux*) date -d "${1:0:10} ${1:11:2}:${1:13:2}:${1:15:2}" +%s ;;
|
||||||
|
darwin*) date -j -f "%Y-%m-%d-%H%M%S" "$1" "+%s" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
fn_find_backups() {
|
||||||
|
find "$DEST_FOLDER" -type d -name "????-??-??-??????" -prune | sort -r
|
||||||
|
}
|
||||||
|
|
||||||
|
fn_expire_backup() {
|
||||||
|
# Double-check that we're on a backup destination to be completely
|
||||||
|
# sure we're deleting the right folder
|
||||||
|
if [ -z "$(fn_find_backup_marker "$(dirname -- "$1")")" ]; then
|
||||||
|
fn_log_error "$1 is not on a backup destination - aborting."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
fn_log_info "Expiring $1"
|
||||||
|
rm -rf -- "$1"
|
||||||
|
}
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Source and destination information
|
# Source and destination information
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
SRC_FOLDER=${1%/}
|
SRC_FOLDER="${1%/}"
|
||||||
DEST_FOLDER=${2%/}
|
DEST_FOLDER="${2%/}"
|
||||||
EXCLUSION_FILE=$3
|
EXCLUSION_FILE="$3"
|
||||||
|
|
||||||
for arg in "$SRC_FOLDER" "$DEST_FOLDER" "$EXCLUSION_FILE"; do
|
for ARG in "$SRC_FOLDER" "$DEST_FOLDER" "$EXCLUSION_FILE"; do
|
||||||
if [[ "$arg" == *"'"* ]]; then
|
if [[ "$ARG" == *"'"* ]]; then
|
||||||
fn_log_error 'Arguments may not have any single quote characters.'
|
fn_log_error 'Arguments may not have any single quote characters.'
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@@ -48,24 +70,14 @@ done
|
|||||||
|
|
||||||
# TODO: check that the destination supports hard links
|
# TODO: check that the destination supports hard links
|
||||||
|
|
||||||
fn_backup_marker_path() {
|
fn_backup_marker_path() { echo "$1/backup.marker"; }
|
||||||
echo "$1/backup.marker"
|
fn_find_backup_marker() { find "$(fn_backup_marker_path "$1")" 2>/dev/null; }
|
||||||
}
|
|
||||||
|
|
||||||
fn_is_backup_destination() {
|
if [ -z "$(fn_find_backup_marker "$DEST_FOLDER")" ]; then
|
||||||
DEST_MARKER_FILE="$(fn_backup_marker_path $1)"
|
|
||||||
if [ -f "$DEST_MARKER_FILE" ]; then
|
|
||||||
echo "1"
|
|
||||||
else
|
|
||||||
echo "0"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
if [ "$(fn_is_backup_destination $DEST_FOLDER)" != "1" ]; then
|
|
||||||
fn_log_info "Safety check failed - the destination does not appear to be a backup folder or drive (marker file not found)."
|
fn_log_info "Safety check failed - the destination does not appear to be a backup folder or drive (marker file not found)."
|
||||||
fn_log_info "If it is indeed a backup folder, you may add the marker file by running the following command:"
|
fn_log_info "If it is indeed a backup folder, you may add the marker file by running the following command:"
|
||||||
fn_log_info ""
|
fn_log_info ""
|
||||||
fn_log_info "touch \"$(fn_backup_marker_path $DEST_FOLDER)\""
|
fn_log_info "touch \"$(fn_backup_marker_path "$DEST_FOLDER")\""
|
||||||
fn_log_info ""
|
fn_log_info ""
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@@ -74,14 +86,17 @@ fi
|
|||||||
# Setup additional variables
|
# Setup additional variables
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
BACKUP_FOLDER_PATTERN="^[[:digit:]][[:digit:]][[:digit:]][[:digit:]]-[[:digit:]][[:digit:]]-[[:digit:]][[:digit:]]-[[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]]$"
|
# Date logic
|
||||||
NOW=$(date +"%Y-%m-%d-%H%M%S")
|
NOW=$(date +"%Y-%m-%d-%H%M%S")
|
||||||
PROFILE_FOLDER="$HOME/.rsync_tmbackup"
|
EPOCH=$(date "+%s")
|
||||||
LOG_FILE="$PROFILE_FOLDER/$NOW.log"
|
KEEP_ALL_DATE=$(($EPOCH - 86400)) # 1 day ago
|
||||||
DEST=$DEST_FOLDER/$NOW
|
KEEP_DAILIES_DATE=$(($EPOCH - 2678400)) # 31 days ago
|
||||||
LAST_TIME=$(ls -1 -- "$DEST_FOLDER" | grep "$BACKUP_FOLDER_PATTERN" | tail -n 1)
|
|
||||||
PREVIOUS_DEST=$DEST_FOLDER/$LAST_TIME
|
export IFS=$'\n' # Better for handling spaces in filenames.
|
||||||
INPROGRESS_FILE=$DEST_FOLDER/backup.inprogress
|
PROFILE_FOLDER="$HOME/.$APPNAME"
|
||||||
|
DEST="$DEST_FOLDER/$NOW"
|
||||||
|
PREVIOUS_DEST="$(fn_find_backups | head -n 1)"
|
||||||
|
INPROGRESS_FILE="$DEST_FOLDER/backup.inprogress"
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Create profile folder if it doesn't exist
|
# Create profile folder if it doesn't exist
|
||||||
@@ -97,38 +112,35 @@ fi
|
|||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
if [ -f "$INPROGRESS_FILE" ]; then
|
if [ -f "$INPROGRESS_FILE" ]; then
|
||||||
if [ "$LAST_TIME" != "" ]; then
|
if [ -n "$PREVIOUS_DEST" ]; then
|
||||||
# - Last backup is moved to current backup folder so that it can be resumed.
|
# - Last backup is moved to current backup folder so that it can be resumed.
|
||||||
# - 2nd to last backup becomes last backup.
|
# - 2nd to last backup becomes last backup.
|
||||||
fn_log_info "$INPROGRESS_FILE already exists - the previous backup failed or was interrupted. Backup will resume from there."
|
fn_log_info "$INPROGRESS_FILE already exists - the previous backup failed or was interrupted. Backup will resume from there."
|
||||||
LINE_COUNT=$(ls -1 -- "$DEST_FOLDER" | grep "$BACKUP_FOLDER_PATTERN" | tail -n 2 | wc -l)
|
|
||||||
mv -- "$PREVIOUS_DEST" "$DEST"
|
mv -- "$PREVIOUS_DEST" "$DEST"
|
||||||
if [ "$LINE_COUNT" -gt 1 ]; then
|
if [ "$(fn_find_backups | wc -l)" -gt 1 ]; then
|
||||||
SECOND_LAST_TIME=$(ls -1 -- "$DEST_FOLDER" | grep "$BACKUP_FOLDER_PATTERN" | tail -n 2 | head -n 1)
|
PREVIOUS_DEST="$(fn_find_backups | sed -n '2p')"
|
||||||
LAST_TIME=$SECOND_LAST_TIME
|
|
||||||
else
|
else
|
||||||
LAST_TIME=""
|
PREVIOUS_DEST=""
|
||||||
fi
|
fi
|
||||||
PREVIOUS_DEST=$DEST_FOLDER/$LAST_TIME
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Run in a loop to handle the "No space left on device" logic.
|
# Run in a loop to handle the "No space left on device" logic.
|
||||||
while [ "1" ]; do
|
while : ; do
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Check if we are doing an incremental backup (if previous backup exists) or not
|
# Check if we are doing an incremental backup (if previous backup exists).
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
LINK_DEST_OPTION=""
|
LINK_DEST_OPTION=""
|
||||||
if [ "$LAST_TIME" == "" ]; then
|
if [ -z "$PREVIOUS_DEST" ]; then
|
||||||
fn_log_info "No previous backup - creating new one."
|
fn_log_info "No previous backup - creating new one."
|
||||||
else
|
else
|
||||||
# If the path is relative, it needs to be relative to the destination. To keep
|
# If the path is relative, it needs to be relative to the destination. To keep
|
||||||
# it simple, just use an absolute path. See http://serverfault.com/a/210058/118679
|
# it simple, just use an absolute path. See http://serverfault.com/a/210058/118679
|
||||||
PREVIOUS_DEST=`cd \`dirname -- "$PREVIOUS_DEST"\`; pwd`"/"`basename -- "$PREVIOUS_DEST"`
|
PREVIOUS_DEST="$(cd "$PREVIOUS_DEST"; pwd)"
|
||||||
fn_log_info "Previous backup found - doing incremental backup from $PREVIOUS_DEST"
|
fn_log_info "Previous backup found - doing incremental backup from $PREVIOUS_DEST"
|
||||||
LINK_DEST_OPTION="--link-dest=$PREVIOUS_DEST"
|
LINK_DEST_OPTION="--link-dest='$PREVIOUS_DEST'"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
@@ -140,6 +152,35 @@ while [ "1" ]; do
|
|||||||
mkdir -p -- "$DEST"
|
mkdir -p -- "$DEST"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Purge certain old backups before beginning new backup.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Default value for $PREV ensures that the most recent backup is never deleted.
|
||||||
|
PREV="0000-00-00-000000"
|
||||||
|
for FILENAME in $(fn_find_backups | sort -r); do
|
||||||
|
BACKUP_DATE=$(basename "$FILENAME")
|
||||||
|
TIMESTAMP=$(fn_parse_date $BACKUP_DATE)
|
||||||
|
|
||||||
|
# Skip if failed to parse date...
|
||||||
|
if [ -z "$TIMESTAMP" ]; then
|
||||||
|
fn_log_warn "Could not parse date: $FILENAME"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $TIMESTAMP -ge $KEEP_ALL_DATE ]; then
|
||||||
|
true
|
||||||
|
elif [ $TIMESTAMP -ge $KEEP_DAILIES_DATE ]; then
|
||||||
|
# Delete all but the most recent of each day.
|
||||||
|
[ "${BACKUP_DATE:0:10}" == "${PREV:0:10}" ] && fn_expire_backup "$FILENAME"
|
||||||
|
else
|
||||||
|
# Delete all but the most recent of each month.
|
||||||
|
[ "${BACKUP_DATE:0:7}" == "${PREV:0:7}" ] && fn_expire_backup "$FILENAME"
|
||||||
|
fi
|
||||||
|
|
||||||
|
PREV=$BACKUP_DATE
|
||||||
|
done
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Start backup
|
# Start backup
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
@@ -155,14 +196,12 @@ while [ "1" ]; do
|
|||||||
CMD="$CMD --numeric-ids"
|
CMD="$CMD --numeric-ids"
|
||||||
CMD="$CMD --links"
|
CMD="$CMD --links"
|
||||||
CMD="$CMD --hard-links"
|
CMD="$CMD --hard-links"
|
||||||
CMD="$CMD --delete"
|
|
||||||
CMD="$CMD --delete-excluded"
|
|
||||||
CMD="$CMD --one-file-system"
|
CMD="$CMD --one-file-system"
|
||||||
CMD="$CMD --archive"
|
CMD="$CMD --archive"
|
||||||
CMD="$CMD --itemize-changes"
|
CMD="$CMD --itemize-changes"
|
||||||
CMD="$CMD --verbose"
|
CMD="$CMD --verbose"
|
||||||
CMD="$CMD --log-file '$LOG_FILE'"
|
CMD="$CMD --log-file '$LOG_FILE'"
|
||||||
if [ "$EXCLUSION_FILE" != "" ]; then
|
if [ -n "$EXCLUSION_FILE" ]; then
|
||||||
# We've already checked that $EXCLUSION_FILE doesn't contain a single quote
|
# We've already checked that $EXCLUSION_FILE doesn't contain a single quote
|
||||||
CMD="$CMD --exclude-from '$EXCLUSION_FILE'"
|
CMD="$CMD --exclude-from '$EXCLUSION_FILE'"
|
||||||
fi
|
fi
|
||||||
@@ -182,49 +221,20 @@ while [ "1" ]; do
|
|||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
# TODO: find better way to check for out of space condition without parsing log.
|
# TODO: find better way to check for out of space condition without parsing log.
|
||||||
grep --quiet "No space left on device (28)" "$LOG_FILE"
|
NO_SPACE_LEFT="$(grep "No space left on device (28)\|Result too large (34)" "$LOG_FILE")"
|
||||||
NO_SPACE_LEFT="$?"
|
|
||||||
if [ "$NO_SPACE_LEFT" != "0" ]; then
|
|
||||||
# This error might also happen if there is no space left
|
|
||||||
grep --quiet "Result too large (34)" "$LOG_FILE"
|
|
||||||
NO_SPACE_LEFT="$?"
|
|
||||||
fi
|
|
||||||
|
|
||||||
rm -- "$LOG_FILE"
|
|
||||||
|
|
||||||
if [ "$NO_SPACE_LEFT" == "0" ]; then
|
|
||||||
# TODO: -y flag
|
|
||||||
read -p "It looks like there is no space left on the destination. Delete old backup? (Y/n) " yn
|
|
||||||
case $yn in
|
|
||||||
[Nn]* ) exit 0;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
|
rm -- "$LOG_FILE"
|
||||||
|
|
||||||
|
if [ -n "$NO_SPACE_LEFT" ]; then
|
||||||
fn_log_warn "No space left on device - removing oldest backup and resuming."
|
fn_log_warn "No space left on device - removing oldest backup and resuming."
|
||||||
|
|
||||||
BACKUP_FOLDER_COUNT=$(ls -1 $DEST_FOLDER | grep "$BACKUP_FOLDER_PATTERN" | wc -l)
|
if [[ "$(fn_find_backups | wc -l)" -lt "2" ]]; then
|
||||||
if [ "$BACKUP_FOLDER_COUNT" -lt "2" ]; then
|
|
||||||
fn_log_error "No space left on device, and no old backup to delete."
|
fn_log_error "No space left on device, and no old backup to delete."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
OLDEST_BACKUP=$(ls -1 $DEST_FOLDER | grep "$BACKUP_FOLDER_PATTERN" | head -n 1)
|
fn_expire_backup "$(fn_find_backups | tail -n 1)"
|
||||||
if [ "$OLDEST_BACKUP" == "" ]; then
|
|
||||||
fn_log_error "No space left on device, and cannot get path to oldest backup to delete."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
OLD_BACKUP_PATH="$DEST_FOLDER/$OLDEST_BACKUP"
|
|
||||||
|
|
||||||
# Double-check that we're on a backup destination to be completely sure we're deleting the right folder
|
|
||||||
OLD_BACKUP_PARENT_PATH=$(dirname -- "$OLD_BACKUP_PATH")
|
|
||||||
if [ "$(fn_is_backup_destination $OLD_BACKUP_PARENT_PATH)" != "1" ]; then
|
|
||||||
fn_log_error "'$OLD_BACKUP_PATH' is not on a backup destination - aborting."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
fn_log_info "Deleting '$OLD_BACKUP_PATH'..."
|
|
||||||
rm -rf -- "$OLD_BACKUP_PATH"
|
|
||||||
|
|
||||||
# Resume backup
|
# Resume backup
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
@@ -233,8 +243,15 @@ while [ "1" ]; do
|
|||||||
fn_log_error "Exited with error code $RSYNC_EXIT_CODE"
|
fn_log_error "Exited with error code $RSYNC_EXIT_CODE"
|
||||||
exit $RSYNC_EXIT_CODE
|
exit $RSYNC_EXIT_CODE
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rm -- "$INPROGRESS_FILE"
|
# -----------------------------------------------------------------------------
|
||||||
|
# Add symlink to last successful backup
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
rm -rf -- "$DEST_FOLDER/latest"
|
||||||
|
ln -vs -- "$(basename -- "$DEST")" "$DEST_FOLDER/latest"
|
||||||
|
|
||||||
|
rm -f -- "$INPROGRESS_FILE"
|
||||||
# TODO: grep for "^rsync error:.*$" in log
|
# TODO: grep for "^rsync error:.*$" in log
|
||||||
fn_log_info "Backup completed without errors."
|
fn_log_info "Backup completed without errors."
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
Reference in New Issue
Block a user