Skip to content

Instantly share code, notes, and snippets.

@PhrozenByte
Created January 15, 2023 15:01
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save PhrozenByte/78ae546db81cbc09f71b298159c6d66d to your computer and use it in GitHub Desktop.
Save PhrozenByte/78ae546db81cbc09f71b298159c6d66d to your computer and use it in GitHub Desktop.
Converts rdiff-backup backups to Borg Backup.
#!/bin/bash
# rdiff-backup-to-borg
# Converts rdiff-backup backups to Borg Backup
#
# This script was created to ease switching from `rdiff-backup` to `borg`. It
# restores all increments of a rdiff-backup repository and backs it up using
# Borg Backup.
#
# More info about Borg Backup: <https://borgbackup.readthedocs.io>
# More info about rdiff-backup: <https://rdiff-backup.net/>
#
# Copyright (C) 2023 Daniel Rudolf (<https://www.daniel-rudolf.de>)
# License: The MIT License <http://opensource.org/licenses/MIT>
#
# SPDX-License-Identifier: MIT
export LC_ALL=C
print_usage() {
echo "Usage:"
echo " $(basename "$0") <BORG_REPOSITORY> <RDIFF_REPOSITORY>..."
echo " $(basename "$0") --list <RDIFF_REPOSITORY>..."
}
# parse parameters
BORG_BACKUP=
BACKUP_PREFIX=
LIST_ACTION=
while [ $# -gt 0 ]; do
if [ "$1" == "--help" ]; then
print_usage
exit 0
elif [ "$1" == "-l" ] || [ "$1" == "--list" ]; then
LIST_ACTION="y"
shift
break
elif [ "$1" == "-p" ] || [ "$1" == "--prefix" ]; then
if [ -z "${2:-}" ]; then
echo "Missing required value for option '--prefix'" >&2
exit 1
fi
BACKUP_PREFIX="$2-"
shift 2
elif [ -z "$BORG_BACKUP" ]; then
BORG_BACKUP="$1"
shift
break
fi
done
# list rdiff-backup increments
if [ -n "$LIST_ACTION" ]; then
INDEX=0
for REPO in "$@"; do
REPO_NAME="$(basename "$REPO")"
while read -r BACKUP; do
[ -z "$BACKUP" ] || echo "$((++INDEX)) $REPO_NAME $BACKUP"
done <<< "$(rdiff-backup -l "$REPO" \
| sed -ne 's/^ increments\.\(.*\)\.dir .*$/\1/p')"
BACKUP_CURRENT="$(basename "$REPO/rdiff-backup-data/current_mirror."*".data")"
BACKUP_CURRENT="${BACKUP_CURRENT:15:-5}"
echo "$((++INDEX)) $REPO_NAME $BACKUP_CURRENT (latest)"
done
exit
fi
# add rdiff-backup increments to Borg repository
if [ -z "$BORG_BACKUP" ]; then
print_usage >&2
exit 1
fi
if [ -e "$BORG_BACKUP" ]; then
if [ ! -d "$BORG_BACKUP" ]; then
echo "Invalid Borg repository '$BORG_BACKUP': Not a directory" >&2
exit 1
elif ! grep -qF "Borg Backup repository" "$BORG_BACKUP/README" 2> /dev/null; then
echo "Invalid Borg repository '$BORG_BACKUP': Not a Borg repository" >&2
exit 1
fi
else
echo "Creating Borg repository..."
mkdir "$BORG_BACKUP"
borg init --encryption=repokey "$BORG_BACKUP"
echo
fi
RESTORE="$(mktemp -d)"
trap "rm -rf ${RESTORE@Q}" ERR EXIT
OLD_PWD="$PWD"
for REPO in "$@"; do
echo "################################################################################"
echo "Accessing rdiff-backup repository '$REPO'..."
BACKUP_INFO="$(rdiff-backup -l "$REPO")"
BACKUP_COUNT="$(sed -ne '1 s/^Found \([0-9]*\) increments:$/\1/p' <<< "$BACKUP_INFO")"
((BACKUP_COUNT++))
echo "Found $BACKUP_COUNT rdiff-backup snapshot(s):"
BACKUPS=()
if (( "$BACKUP_COUNT" > 1 )); then
readarray -t BACKUPS <<< "$(sed -ne 's/^ increments\.\(.*\)\.dir .*$/\1/p' <<< "$BACKUP_INFO")"
printf -- '- %s\n' "${BACKUPS[@]}"
fi
BACKUP_CURRENT="$(basename "$REPO/rdiff-backup-data/current_mirror."*".data")"
BACKUP_CURRENT="${BACKUP_CURRENT:15:-5}"
BACKUPS+=( "$BACKUP_CURRENT" )
printf -- '- %s (latest)\n' "$BACKUP_CURRENT"
BACKUP_INDEX="$((BACKUP_COUNT - 1))"
for BACKUP in "${BACKUPS[@]}"; do
echo
echo "Restoring rdiff-backup snapshot '$BACKUP' (#$BACKUP_INDEX)..."
rdiff-backup -r "${BACKUP_INDEX}B" \
--exclude-sockets \
"$REPO" \
"$RESTORE/$BACKUP"
echo "Creating Borg backup of '$BACKUP'..."
cd "$RESTORE/$BACKUP"
borg create -v --stats --show-rc --progress --compression=lz4 \
--timestamp="$(date -d "$BACKUP" -u +'%Y-%m-%dT%H:%M:%S')" \
--comment="rdiff-backup" \
"$BORG_BACKUP"::"$BACKUP_PREFIX$BACKUP" \
.
echo "Removing rdiff-backup snapshot '$BACKUP'..."
cd "$OLD_PWD"
rm -rf "$RESTORE/$BACKUP"
((BACKUP_INDEX--))
done
echo
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment