66 Commits

Author SHA1 Message Date
Laurent 9a87c1d4e4 Merge pull request #23 from robru/simplify-logfiles
Simplify logfile parsing and drop unreachable codepath.
2013-12-06 08:39:40 -08:00
Robert Bruce Park 808767dc66 Merge @laurent22/master. 2013-11-26 22:05:46 -08:00
Laurent Cozic c854cd17c6 Restoring $(basename -- "$DEST")
In case the destination is later on generated in a different way,
also makes the code and intention more explicit.
2013-11-27 12:36:54 +08:00
Robert Bruce Park bff263ab57 Simplify logfile parsing and drop unreachable codepath. 2013-11-26 13:46:26 -08:00
Robert Bruce Park d73b3ffe43 Yet more quotes! 2013-11-26 13:13:58 -08:00
Robert Bruce Park b16c3cf4ce Even more quotes. 2013-11-26 13:11:53 -08:00
Robert Bruce Park e7fc37076c Rebase on @laurent22/master. 2013-11-26 13:11:00 -08:00
Robert Bruce Park 4720f404af Extra quotes everywhere! 2013-11-26 13:08:52 -08:00
Robert Bruce Park 2f0092ac9f Use -n and -z for easier string emptiness checks. 2013-11-26 13:04:30 -08:00
Robert Bruce Park 40e5ce4721 Use bash : noop for efficiency. 2013-11-26 13:02:29 -08:00
Robert Bruce Park e5f939222e Determine $APPNAME programmatically. 2013-11-26 12:59:00 -08:00
Robert Bruce Park 0db8b3a913 Define trivial functions on one line only. 2013-11-26 12:55:17 -08:00
Robert Bruce Park c3f15c7834 Simplify symlink creation. 2013-11-26 12:48:49 -08:00
Robert Bruce Park 4da7172099 Redundant. 2013-11-26 12:46:15 -08:00
Robert Bruce Park 45875055a4 Simpler absolute paths. 2013-11-26 12:45:12 -08:00
Robert Bruce Park 16fd955e6c Drop some single-use variables. 2013-11-26 12:43:58 -08:00
Robert Bruce Park 08d090f19c Sort fn_find_backups newest first. 2013-11-26 12:41:42 -08:00
Laurent Cozic 2e413d82d7 Merge branch 'master' of https://github.com/laurent22/rsync-time-backup 2013-11-26 03:44:06 +08:00
Laurent cb252f7545 Update README.md
Mentioned level of testing.
2013-11-26 03:40:23 +08:00
Laurent 5d1027fd78 Merge pull request #21 from efournie/efournie-master
Force deleting INPROGRESS_FILE

Avoids waiting for user input if rm is aliased to rm -i
2013-11-25 10:17:53 -08:00
Eric Fournie 928b32f83e Force deleting INPROGRESS_FILE (avoids waiting for user input if rm is aliased to rm -i) 2013-11-25 14:47:18 +00:00
Laurent Cozic b8fb75bbc0 Removed dangerous and unneeded delete flags.
Since there's normally nothing in the destination directory, the
delete flags are not really needed.
2013-11-24 17:23:00 +08:00
Robert Bruce Park 9ece9fbec3 Fix spaces in filenames. 2013-11-23 01:18:08 -08:00
Robert Bruce Park 392b8089a5 Add a simple script for running rsync_tmbackup.sh from cron. 2013-11-23 01:07:31 -08:00
Laurent Cozic d31b689f6b Removed old backup deletion prompt, and formatting tweaks.
- Removed old backup deletion prompt as it's not really needed.
- Made all variables uppercase for consistency.
- Used double square brackets in `if` statements.
2013-11-16 22:50:10 +08:00
Laurent Cozic 81d6b4fb99 Merge branch 'master' of https://github.com/laurent22/rsync-time-backup 2013-11-16 22:20:07 +08:00
Laurent 12784d1d32 Merge pull request #14 from robru/master
Time Machine style backup pruning.
2013-11-16 06:17:54 -08:00
Robert Bruce Park f5a4275a04 Merge master. 2013-11-15 23:07:01 -08:00
Robert Bruce Park a474f139f5 Stop creating "latest" symlink (implemented in a different branch).
This reverts commit 28735b1815.
2013-11-15 23:02:24 -08:00
Robert Bruce Park 28735b1815 Create "latest" symlink pointing at the most recent completed backup. 2013-11-15 12:01:52 -08:00
Robert Bruce Park f011e1a7ab More elegant cross-platform date logic. 2013-11-15 11:08:28 -08:00
Robert Bruce Park 9b9a564447 More robust date handling.
Previously the date handling expiry logic had a bug where if you had
backups that were a year apart to the day, it wouldn't notice the
difference in year and only notice that the month was the same, and
expire the older one (eg, if you had a backup on 2012-04-01 and
another on 2013-04-01, it'd delete the one from 2012. This commit
makes it compare the full date string instead of just the month, so
that it more robustly keeps older backups.
2013-11-15 10:35:04 -08:00
Robert Bruce Park ae7998025a Add MacOSX compatibility. 2013-11-15 10:24:52 -08:00
Laurent Cozic e092d5c2fd Updated list of features in README 2013-11-15 18:06:49 +08:00
Laurent Cozic 2ade9de422 Fixed latest backup symlink issues
Code was in the wrong place (link being added when the backup failed only).
Also made the symlink relative to the current folder so that the drive
can be mounted with a different path.
2013-11-15 17:20:16 +08:00
Laurent 85fea581a6 Merge pull request #15 from mumrah/master
Add a "latest" symlink when backup is successful
2013-11-15 01:16:05 -08:00
Robert Bruce Park 324a3ffc9a Whitespace fix, oops. 2013-11-14 19:36:32 -08:00
Robert Bruce Park 12deac25d6 Correctly handle most recent backup if it's older than 24hs.
Code was assuming that you'd run backups hourly, eg, so you'd have
many backups within the last 24 hours. Code assumed that by the time
you found a backup more than 24h old, you'd already have a value for
$prev set. In the event that your most recent backup is more than 24
hours old, $prev would not be set and bash would get an error "unary
operator expected" when it tried to compare the day of the newest
backup to the empty $prev value.

I fix this by setting a default value for $prev, one that cannot be
mistaken for an existing backup because it does not represent a valid
date. This ensures that the most recent backup is correctly preserved
regardless of it's age.
2013-11-14 19:31:22 -08:00
Robert Bruce Park 855c77a83f Simplify fn_is_backup_destination implementation. 2013-11-14 19:03:26 -08:00
Robert Bruce Park 4250423d98 Make fn_expire_backup more robust. 2013-11-14 18:50:34 -08:00
David Arthur 0c679903af Fixed
Brain fart
2013-11-13 15:52:24 -05:00
Robert Bruce Park 584e3a9b4b Drop BACKUP_FOLDER_PATTERN since it's now only used in one place. 2013-11-13 10:53:13 -08:00
Robert Bruce Park 19446c24b9 Take the training wheels off ;-) 2013-11-13 10:34:47 -08:00
David Arthur bda24be003 Add a "latest" symlink when backup is successful 2013-11-13 13:29:08 -05:00
Robert Bruce Park 8bb5b3f265 Rearrange function definitions. 2013-11-13 10:21:47 -08:00
Robert Bruce Park a67efdd0f1 Implement fn_expire_backups to reduce code duplication. 2013-11-13 10:17:41 -08:00
Robert Bruce Park 32e71ce9aa Implement fn_find_backups to reduce code duplication. 2013-11-13 10:16:27 -08:00
Robert Bruce Park 72df5bf33e Rebase on master. 2013-11-13 09:16:31 -08:00
Robert Bruce Park fe0bfde041 More robust path handling. 2013-11-13 09:12:50 -08:00
Laurent 8a2e91813b Update README.md
Now done: "Check if there's enough space in the destination before doing the backup. Also automatically delete old backups."
2013-11-13 17:57:51 +08:00
Laurent Cozic c505ecbfb8 Merge branch 'master' of https://github.com/rastkov/rsync-time-backup into rastkov-master
Conflicts:
	rsync_tmbackup.sh
2013-11-13 17:51:15 +08:00
Laurent Cozic 159d8b6416 Merge branch 'master' of https://github.com/laurent22/rsync-time-backup
Conflicts:
	rsync_tmbackup.sh
2013-11-13 17:47:58 +08:00
Laurent Cozic 2fd6b109f0 Using find instead of ls to find the last and second last directory used for backup. 2013-11-13 17:46:20 +08:00
Robert Bruce Park d425a05528 Initial implementation of Time Machine style backup pruning.
Within 24 hours, all backups are kept. Within 1 month, only the most
recent backup for each day is kept. For all previous backups, only the
most recent of each month is kept.

This is not *quite* the same as Time Machine, but this implementation
is a lot easier to do since it is based on string comparisons of the
dates and doesn't require any "hard" date logic.

Also this commit just 'echo's what will be deleted, and does not
actually delete anything yet because I am still testing it.
2013-11-13 00:01:17 -08:00
Laurent Cozic c23f47164e Merge branch 'master' of https://github.com/tyriis/rsync-time-backup into tyriis-master
Changed regex for grep iirc POSIX mode

Conflicts:
	rsync_tmbackup.sh
2013-11-12 15:50:02 +08:00
Laurent Cozic 9128fa2a6f Merge branch 'master' of https://github.com/tyriis/rsync-time-backup into tyriis-master
Conflicts:
	rsync_tmbackup.sh
2013-11-12 15:40:00 +08:00
Laurent Cozic 1f5aabc31f Merge branch 'master' of https://github.com/laurent22/rsync-time-backup
Conflicts:
	rsync_tmbackup.sh
2013-11-12 15:31:20 +08:00
Laurent Cozic b481985f2a Move more setup code inside loop 2013-11-12 11:14:02 +08:00
Laurent 00ba40b617 Merge pull request #11 from Flimm/master
Deal with arguments with special characters better
2013-11-07 01:06:50 -08:00
David D Lowe 24540f33ee Handle source and dest arguments with spaces 2013-11-07 08:51:12 +00:00
rastkov 99258d80ab Update rsync_tmbackup.sh
Set LAST_TIME, LINE_CONUT and SECOND_LAST_TIME based on `uname -s` output for Mac OS compatibility.
2013-11-01 14:32:59 +01:00
rastkov 27a0a1881f Update rsync_tmbackup.sh
Using find with regex instead of glob
2013-11-01 08:48:21 +01:00
nils biesalski c046c4dd42 Changed regex for grep iirc POSIX mode
http://stackoverflow.com/questions/6901171/is-d-not-supported-by-greps-basic-expressions
2013-10-31 13:51:08 +01:00
David D Lowe 396b42d483 Deal with arguments with special characters better
Script now handles filenames with special characters (such as spaces,
hard tabs, newlines, double quotes and a dash prefix). The only
exceptions are filenames with single quotes. In this case, the script
will fail early with a clear error message.
2013-10-30 13:45:48 +00:00
rastkov 8318db90c5 Update rsync_tmbackup.sh 2013-10-29 12:15:38 +01:00
rastkov a40a733902 Update rsync_tmbackup.sh
Using find instead of ls to find the last and second last directory used for backup.
2013-10-29 12:07:30 +01:00
2 changed files with 150 additions and 123 deletions
+8 -6
View File
@@ -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)
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/laurent22/rsync-time-backup/trend.png)](https://bitdeli.com/free "Bitdeli Badge") [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/laurent22/rsync-time-backup/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
+142 -117
View File
@@ -1,39 +1,68 @@
#!/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 "[RB INFO] $1" fn_log_warn() { echo "$APPNAME: [WARNING] $1"; }
} fn_log_error() { echo "$APPNAME: [ERROR] $1"; }
fn_log_warn() {
echo "[RB WARN] $1"
}
fn_log_error() {
echo "[RB 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 "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
if [[ "$ARG" == *"'"* ]]; then
fn_log_error 'Arguments may not have any single quote characters.'
exit 1
fi
done
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Check that the destination drive is a backup drive # Check that the destination drive is a backup drive
@@ -41,24 +70,14 @@ EXCLUSION_FILE=$3
# 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
@@ -67,14 +86,17 @@ fi
# Setup additional variables # Setup additional variables
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
BACKUP_FOLDER_PATTERN="\d\d\d\d-\d\d-\d\d-\d\d\d\d\d\d" # 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
@@ -90,52 +112,79 @@ 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 [ "$(fn_find_backups | wc -l)" -gt 1 ]; then
if [ "$LINE_COUNT" -gt 1 ]; then PREVIOUS_DEST="$(fn_find_backups | sed -n '2p')"
SECOND_LAST_TIME=$(ls -1 $DEST_FOLDER | grep "$BACKUP_FOLDER_PATTERN" | tail -n 2 | head -n 1)
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.
# Check if we are doing an incremental backup (if previous backup exists) or not while : ; do
# -----------------------------------------------------------------------------
LINK_DEST_OPTION="" # -----------------------------------------------------------------------------
if [ "$LAST_TIME" == "" ]; then # Check if we are doing an incremental backup (if previous backup exists).
fn_log_info "No previous backup - creating new one." # -----------------------------------------------------------------------------
else
# 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
PREVIOUS_DEST=`cd \`dirname "$PREVIOUS_DEST"\`; pwd`"/"`basename "$PREVIOUS_DEST"`
fn_log_info "Previous backup found - doing incremental backup from $PREVIOUS_DEST"
LINK_DEST_OPTION="--link-dest=$PREVIOUS_DEST"
fi
# ----------------------------------------------------------------------------- LINK_DEST_OPTION=""
# Create destination folder if it doesn't already exists if [ -z "$PREVIOUS_DEST" ]; then
# ----------------------------------------------------------------------------- fn_log_info "No previous backup - creating new one."
else
# 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
PREVIOUS_DEST="$(cd "$PREVIOUS_DEST"; pwd)"
fn_log_info "Previous backup found - doing incremental backup from $PREVIOUS_DEST"
LINK_DEST_OPTION="--link-dest='$PREVIOUS_DEST'"
fi
if [ ! -d "$DEST" ]; then # -----------------------------------------------------------------------------
fn_log_info "Creating destination $DEST" # Create destination folder if it doesn't already exists
mkdir -p $DEST # -----------------------------------------------------------------------------
fi
# ----------------------------------------------------------------------------- if [ ! -d "$DEST" ]; then
# Start backup fn_log_info "Creating destination $DEST"
# ----------------------------------------------------------------------------- mkdir -p -- "$DEST"
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
# -----------------------------------------------------------------------------
# Run in a loop to handle the "No space left on device" logic
while [ "1" ]; do
LOG_FILE="$PROFILE_FOLDER/$(date +"%Y-%m-%d-%H%M%S").log" LOG_FILE="$PROFILE_FOLDER/$(date +"%Y-%m-%d-%H%M%S").log"
fn_log_info "Starting backup..." fn_log_info "Starting backup..."
@@ -147,25 +196,23 @@ 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 --progress"
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
CMD="$CMD --exclude-from \"$EXCLUSION_FILE\"" # We've already checked that $EXCLUSION_FILE doesn't contain a single quote
CMD="$CMD --exclude-from '$EXCLUSION_FILE'"
fi fi
CMD="$CMD $LINK_DEST_OPTION" CMD="$CMD $LINK_DEST_OPTION"
CMD="$CMD $SRC_FOLDER/ $DEST/" CMD="$CMD -- '$SRC_FOLDER/' '$DEST/'"
CMD="$CMD | grep -E '^deleting|[^/]$'" CMD="$CMD | grep -E '^deleting|[^/]$'"
fn_log_info "Running command:" fn_log_info "Running command:"
fn_log_info "$CMD" fn_log_info "$CMD"
touch $INPROGRESS_FILE touch -- "$INPROGRESS_FILE"
eval $CMD eval $CMD
RSYNC_EXIT_CODE=$? RSYNC_EXIT_CODE=$?
@@ -174,50 +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
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
# TODO: handle case where only two backup folders are left. In which case, need to remove --link-dest option fn_expire_backup "$(fn_find_backups | tail -n 1)"
OLDEST_BACKUP=$(ls -1 $DEST_FOLDER | grep "$BACKUP_FOLDER_PATTERN" | head -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
@@ -226,8 +243,16 @@ 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
fn_log_info "Backup completed without errors." fn_log_info "Backup completed without errors."
exit 0 exit 0
done done