Skip to content

Instantly share code, notes, and snippets.

@ntrrgc
Last active April 6, 2020 20:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ntrrgc/292960aa666c8f32ab072879c0af4048 to your computer and use it in GitHub Desktop.
Save ntrrgc/292960aa666c8f32ab072879c0af4048 to your computer and use it in GitHub Desktop.
My backup script for synology NAS, with safety checks for archival
#!/bin/bash
set -eu
found_not_mounted=0
function check_not_empty() {
local path="$1"
if [ ! -d "$path" ]; then
found_not_mounted=1
echo "ERROR: $path does not exist!"
elif [ ! "$(ls -A "$path")" ]; then
found_not_mounted=1
echo "ERROR: $path is empty!"
fi
}
# Check all fancy encrypted volumes to backup are properly mounted!
check_not_empty /nas
check_not_empty /nas/Archive
check_not_empty /nas/Dibujos
check_not_empty /nas/FileHistory
if [ "$found_not_mounted" -ne 0 ]; then
echo "Please make sure /nas is mounted and all encrypted volumes in the NAS Shared Folders are also properly mounted."
exit 1
fi
DRIVE_GLOB="/run/media/ntrrgc/NAS-*"
DRIVE=""
for drive in $(ls -1 -d $DRIVE_GLOB); do
if [ -z "$DRIVE" ]; then
DRIVE="$drive"
else
echo "Ambiguous drive selection, there are more than one possible NAS backup drives!"
ls -1 -d $DRIVE_GLOB
exit 1
fi
done
if [ -z "$DRIVE" ]; then
echo "Plug and mount a NAS backup drive in $DRIVE_GLOB!"
exit 1
fi
echo "Backing up NAS in $DRIVE..."
sleep 3s # to confirm... enough time to ^C if it goes haywire
export RSYNC_PASSWORD=YOUR_SYNOLOGY_RYSNC_PASS
RSYNC_EXCLUDE_OPTS=(--exclude '*@SynoEAStream' --exclude '*@SynoResource' --exclude '@eaDir' --exclude '#recycle')
RSYNC_SRC="rsync://ntrrgc@mami.local"
DRY_RUN_EXCLUDE=(grep -vi 'Thumbs.db')
found_deletions=0
deletions_msg=""
function archive_check() {
local nas_path="$1" # must NOT start or end with /
mkdir -p /tmp/backup-nas-dry-run/"$nas_path"
local dry_run_file="/tmp/backup-nas-dry-run/$nas_path/dry-run.txt"
echo "Checking for deletions in $nas_path..."
rsync -aXx "${RSYNC_EXCLUDE_OPTS[@]}" --delete --inplace -nv "$RSYNC_SRC/$nas_path/" "$DRIVE/$nas_path" > "$dry_run_file" 2>&1
if cat "$dry_run_file" | "${DRY_RUN_EXCLUDE[@]}" | grep '^deleting '; then
found_deletions=1
local count=$(cat "$dry_run_file" | "${DRY_RUN_EXCLUDE[@]}" | grep -c '^deleting ')
deletions_msg="${deletions_msg}$count deletions have been found in $nas_path."$'\n'
fi
}
function request_delete_confirmation() {
if [[ "$found_deletions" -ne 0 ]]; then
deletions_msg="${deletions_msg}Please check everything is right and confirm to continue the backup with the deletions."
telegram-notify send "$deletions_msg"
echo "You can check the full dry-run logs in /tmp/backup-nas-dry-run. Type 'yes' to continue with the backup deleting the files above from the backup drive."
echo -n "Continue? "
read answer
if [[ "$answer" != "yes" ]]; then
echo "Cancelling backup."
exit 1
fi
fi
}
function sync_folder() {
local nas_path="$1" # must NOT start or end with /
# --inplace should make synchronization of big files (e.g. disk images) faster
rsync -aXx --info=progress2 \
"${RSYNC_EXCLUDE_OPTS[@]}" \
--delete --inplace \
"$RSYNC_SRC/$nas_path/" "$DRIVE/$nas_path/"
}
# Deleting files from the backup in these directories will need confirmation (they are intended to be mostly addition-only).
archive_check Archive
archive_check Dibujos
archive_check photo
request_delete_confirmation
sync_folder Archive
sync_folder Dibujos
sync_folder photo
sync_folder homes
sync_folder FileHistory
date | sudo tee "$DRIVE/last-backup-date.txt" > /dev/null
if safely-remove "$DRIVE"; then
telegram-notify send "Finished backing up NAS into $DRIVE. You can now unplug the drive."
else
telegram-notify send "Finished backing up NAS into $DRIVE. COULDN'T UNMOUNT THE DEVICE, IT MAY STILL BE IN USE."
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment