Der Usage-Aufruf und die Help-Ausgabe sind noch unvollständig. Auch bin ich mir noch nicht ganz sicher über die Struktur des Archives und der zugehörigen Symlinks.
Außerdem hab ich noch keine Versionsverwaltung für die Snapshots eingebaut. Wieviele Snapshots hebe ich auf, automatisches Löschen von älteren, und ich glaube, es sind die Snapshots noch grundsätzlich ro (was auf dem externen Medium auch so sein soll, aber lokal können sie ruhig rw sein...). Hier wird auch noch über die Commandline zum Auswählen werden.
Das Skript such außerdem - sofern -r angegeben ist, also der Snapshot auch remote gesichert werden soll - beginnend beim jüngsten Snapshot lokal und remote, ob es zwei gleiche Snapshots findet. Ist dem so, wird dieser Snapshot herangezogen um das Diff für »btrfs send« mit dem Current-Snapshot zu erstellen. Gibt es keine zwei gleichen Snapshots lokal und remote, dann wird entweder eine Fehlermeldung ausgegeben oder - wenn »-i« in der Commandline ausgewählt ist - ein Initialer Snapshot nach remote übertragen.
Das heißt also, wenn zwar auf der externen Platte Snapshots vorhanden sind, aber kein gleicher wie lokal, wird ein neuer initialer Snapshot erzeugt. Wenn gar kein Snapshot remote vorhanden ist, wird ebenfalls ein neuer Initialer Snapshot erzeugt. (aber nur wenn eben -i angegeben ist!!!)
Was ich noch einbauen werde ist die Möglichkeit mittels Commandline-option dem Snapshot noch ein Kommentar anzuhängen und eine Benachrichtigung per Mail, wenn etwas schief gelaufen ist, damit dieses Skript auch im Cronjob seinen Dienst verrichten kann.
Dazu muss aber noch eine quiet-Option eingebaut werden, sonst gibts jedesmal eine Benachrichtigung, wenn cron es aufruft. Und das will ich auch nicht.
Aber prinzipiell funktioniert es schon einmal pipifein.
Code: Alles auswählen
# cat /usr/local/bin/mkbackup_btrfs
#!/bin/bash
#
CONFFILE="/etc/btrfsbck.conf"
SOURCE="/var/cache/btrfs_pool_SYSTEM"
ARCHIVLOCAL="$SOURCE/archive-local"
SNAPDEST="/var/cache/backup"
LOGFILE="/var/log/backupscript.log"
# If REMOTE=1, the local snapshot in the ARCHIVLOCAL is transferred to a remote Mountpoint.
# Set »-r« on the commandline to activate it
REMOTE=0
# If INIT=1, the Remote Backup is initiated. One copy of your subvolume is transferred and one is stored local, so next backup-run
# only the difference between the last and the current state is transferred (takes a long time, if a big subvolume is initiated first)
# Set »-i« on the commandline to activate it.
# If init is not activated, a error results, if the remote backup doesn't exist!
INIT=0
usage() { echo "Usage: $0 [-r][-i][-c <Config-File>]" 1>&2; exit 1; }
while getopts ":c:irs:p:" o; do
case "${o}" in
c)
CONFFILE=${OPTARG}
;;
i)
INIT=1
;;
r)
REMOTE=1
;;
*)
usage
;;
esac
done
shift $((OPTIND-1))
SOURCE="`awk -F "=" '$1 ~ /^SOURCE/{gsub(/"/,"",$0);print $2}' "$CONFFILE"`"
ARCHIVLOCAL="`awk -F "=" '$1 ~ /^ARCHIVLOCAL/{gsub(/"/,"",$0);print src"/"$2}' src=$SOURCE "$CONFFILE"`"
SNAPDEST="`awk -F "=" '$1 ~ /^SNAPDEST/{gsub(/"/,"",$0);print $2}' "$CONFFILE"`"
LOGFILE="`awk -F "=" '$1 ~ /^LOGFILE/{gsub(/"/,"",$0);print $2}' "$CONFFILE"`"
# Create subdirectories, if missing
[ ! -d "$SOURCE" ] && mkdir -p "$SOURCE"
[ ! -d "$ARCHIVLOCAL" ] && mkdir -p "$ARCHIVLOCAL"
[ ! -d "$SNAPDEST" ] && mkdir -p "$SNAPDEST"
#if [ -z "${REMOTE}" ] ]; then
# usage
#fi
# Test, if subdirectories exist really
[ -d "${SOURCE}" ] || { echo $SOURCE nonexistent; exit 1; }
[ -d "${ARCHIVLOCAL}" ] || { echo $ARCHIVLOCAL nonexistent; exit 2; }
[ -d "${SNAPDEST}" ] || { echo $SNAPDEST nonexistent; exit 3; }
echo "Local backup-snapshots in '${ARCHIVLOCAL}/'"
# Einlesen des Config-Files in die Arrays
TOBACKUP=(`awk -F " " 'BEGIN{ORS=" "}$1 ~ /^backup/{print src"/"$2}' src="$SOURCE" "$CONFFILE"`)
TOARCHIV=(`awk -F " " 'BEGIN{ORS=" "}$1 ~ /^backup/{print arloc"/"$2}' arloc="$ARCHIVLOCAL" "$CONFFILE"`)
SNAPSHOT=(`awk -F " " 'BEGIN{ORS=" "}$1 ~ /^backup/{print sdst"/"$3}' sdst="$SNAPDEST" "$CONFFILE"`)
SNAPNAME=(`awk -F " " 'BEGIN{ORS=" "}$1 ~ /^backup/{print $2}' "$CONFFILE"`)
# How many Subvols in the Stream
typeset -i BACKUPNR=0
count=0
while [ "x${TOBACKUP[count]}" != "x" ]
do
count=$(( $count + 1 ))
done
typeset -i BACKUPCT=$count
# Create local Archive, ro (for btrfs send) and rw
DATE=`date +%Y-%m-%dT%H:%M:%S`
while [ ${BACKUPNR} -lt ${BACKUPCT} ] ; do
SNAPSRC[${BACKUPNR}]="${TOARCHIV[${BACKUPNR}]}.${DATE}"
SNAPDST[${BACKUPNR}]="${SNAPSHOT[${BACKUPNR}]}/${SNAPNAME[${BACKUPNR}]}.${DATE}"
if [ -d "${SNAPDST[${BACKUPNR}]}" ]; then
SNAPDST[${BACKUPNR}]="${SNAPSHOT[${BACKUPNR}]}/${SNAPNAME[${BACKUPNR}]}.`date +%Y-%m-%d`.`date +%H:%M:%S`"
fi
echo -n "create source snapshot[${SNAPNAME[${BACKUPNR}]}]..."
mkdir -p $(dirname "${SNAPSRC[${BACKUPNR}]}")
btrfs subvolume snapshot "${TOBACKUP[${BACKUPNR}]}" "${SNAPSRC[${BACKUPNR}]}" >> ${LOGFILE} 2>&1 && echo "ok."|| exit ${BACKUPNR}
rm "${TOARCHIV[${BACKUPNR}]}.LAST" >> "${LOGFILE}" 2>&1 #&& echo "remove-link '${SNAPNAME[${BACKUPNR}]}.LAST' ok."
mv "${TOARCHIV[${BACKUPNR}]}.CURRENT" "${TOARCHIV[${BACKUPNR}]}.LAST" >> "${LOGFILE}" 2>&1 && echo "create-link '${SNAPNAME[${BACKUPNR}]}.LAST' ok."
ln -sf "$(basename "${SNAPNAME[$BACKUPNR]}").${DATE}" "${TOARCHIV[${BACKUPNR}]}.CURRENT" \
>> "${LOGFILE}" 2>&1 && echo "create-link '$(basename "${SNAPNAME[$BACKUPNR]}").${DATE}.CURRENT' ok."
BACKUPNR=${BACKUPNR}+1
done
sync
function _getsnap () {
n=$1
[ "${SNAPNAME[$1]}" = "" ] && return 0
typeset -i i
# for ((i=0; i<$BACKUPCT; i++))
# do
SNAPSLOCAL=(`ls "${ARCHIVLOCAL}/$(dirname "${SNAPNAME[$n]}")" 2>/dev/null | \
grep "$(basename ${SNAPNAME[$n]})"|grep -v "CURRENT$\|LAST$\|$(basename "${SNAPNAME[$n]}")$"| \
sed -e "s/^/$(dirname "${SNAPNAME[$n]}")\//" | sort -r`)
SNAPSREMOT=(`ls "${SNAPSHOT[$n]}/$(dirname "${SNAPNAME[$n]}")" 2>/dev/null | \
grep "$(basename ${SNAPNAME[$n]})"|grep -v "CURRENT$\|LAST$\|$(basename "${SNAPNAME[$n]}")$"| \
sed -e "s/^/$(dirname "${SNAPNAME[$n]}")\//" | sort -r`)
# done
#echo "LOCAL ${SNAPSLOCAL[*]} ENDLOCAL"
#echo "REMOT ${SNAPSREMOT[*]} ENDREMOT"
typeset -i i=0
typeset -i j=0
while :
do
if [ "${SNAPSLOCAL[$i]}" = "${SNAPSREMOT[$j]}" ] ; then ret=1; printf "%s" "${SNAPSLOCAL[$i]} ${SNAPSREMOT[$j]}"; return 0; break; fi
if [ "${SNAPSLOCAL[$i]}" = "" ] ; then let j++; i=0; else let i++; fi
if [ "${SNAPSREMOT[$j]}" = "" ] ; then ret=0; printf "%s" "${SNAPSLOCAL[0]} ${SNAPSREMOT[0]}"; return 1;break; fi
done
}
if [ $REMOTE -eq 1 ] ;then
typeset -i BACKUPNR=0
# Transfer Local Archive to remote
while [ ${BACKUPNR} -lt ${BACKUPCT} ] ; do
echo -n "transfer [${SNAPNAME[${BACKUPNR}]}.CURRENT]..."
X=$(_getsnap $BACKUPNR)
if [ $? -eq 1 ] ;then
SNAPL=$(echo $X|cut -d " " -f1)
SNAPR=$(echo $X|cut -d " " -f2)
if [ $INIT -eq 1 ] ;then
echo -n "initialize remote-stream ..."
btrfs property set -ts "${ARCHIVLOCAL}/${SNAPL}" ro true
[ ! -d "${SNAPSHOT[${BACKUPNR}]}/$(dirname "${SNAPNAME[$BACKUPNR]}")" ] && mkdir -p "${SNAPSHOT[${BACKUPNR}]}/$(dirname "${SNAPNAME[$BACKUPNR]}")"
btrfs send "${ARCHIVLOCAL}/${SNAPL}" 2>>"$LOGFILE" \
| btrfs receive "${SNAPSHOT[${BACKUPNR}]}/$(dirname "${SNAPNAME[$BACKUPNR]}")" >> "${LOGFILE}" 2>&1 && echo "ok"
else
printf "%s\n" "$SNAPL - $SNAPR"
printf "%s\n" "$SNAPL nonexistent on ${SNAPSHOT[$i]}"
fi
else
SNAPL=$(echo $X|cut -d " " -f1)
SNAPR=$(echo $X|cut -d " " -f2)
echo -n "send difference $SNAPL ..."
btrfs property set -ts "${ARCHIVLOCAL}/${SNAPL}" ro true
btrfs property set -ts "${SNAPSRC[${BACKUPNR}]}" ro true
btrfs send -p "${ARCHIVLOCAL}/${SNAPL}" "${SNAPSRC[${BACKUPNR}]}" | btrfs receive "${SNAPSHOT[${BACKUPNR}]}" >> ${LOGFILE} 2>&1 && echo "ok"
fi
let BACKUPNR++;
done
fi
exit 0
Code: Alles auswählen
###########################################################
## Configfile for mkbackup_btrfs ##########################
###########################################################
# This Program works with systemd's ability "automount".
# Here an example for /etc/fstab-lines you need for, (or you mount the filesystems manually)
# /dev/sda is the local drive, /dev/sdb is an external HDD (USB for example)
#
# /dev/sda2 /mnt/btrfspool btrfs defaults,noauto,comment=systemd.automount,noatime,compress=lzo,space_cache 0 0
# /dev/sdb5 /mnt/remote-pool btrfs defaults,noauto,comment=systemd.automount,noatime,compress=lzo,space_cache,subvol="backup" 0 0
#
# Be sure, /mnt/btrfspool mounts the root-pool of the btrfs-volume. If you have set some subvolume as default,
# you have to extend the options with ",subvol="0"!!!
# Mountpoint where the btrfs-pool which is the root filesystem ist mounted without subvolumes
# SOURCE="/mnt/btrfspool"
SOURCE="/var/cache/btrfs_pool_SYSTEM"
# Subdirectory in the btrfs-pool, which holds local snapshots for fast restoring, optional boot from
# The Variable $ARCHIVLOCAL results after parsing in $SOURCE/$ARCHIVLOCAL" in the example in "/mnt/btrfspool/archive-pool"
# ARCHIVLOCAL="archiv-pool"
ARCHIVLOCAL="local-pool"
# Mountpoint where the backup of the local archive is backed up. This is the mountpoint from an external HDD,
# or where a btrfs from an remote-computer is mountet with sshfs
# (the ability to work with ssh directly has to be done in future!!)
# SNAPDEST=/mnt/remote-pool"
SNAPDEST="/var/cache/backup"
# Location of the Logfile
# LOGFILE="/var/log/mkbackup_btrfs.log"
LOGFILE="/var/log/mkbackup_btrfs.log"
# Subvols to get backed up. Delimiter is Tab!!
# Start the line with "backup". The <SUBVOLUME> is the path from the btrfsroot. It wil get stored in the same hierarchy in the
# local pool and also the remote pool
# The <BACKUP-POOL-REMOTE> ist a directory in the $SNAPDEST-Mountpoint. If nonexistent, the script creats it!
# backup <SUBVOLUME> <BACKUP-POOL-REMOTE>
backup @debian-jessie venus
backup @var venus
backup @home venus
backup @home/user1 venus
backup @home/user2 venus
backup @VM venus
backup @multimedia venus
backup @multimedia/Audio venus
backup @multimedia/Video venus
Also wenn ich die Zeile »backup @home venus« weglasse und nur »backup @home/user1 venus« angebe.
Der Plan ist, dass die Verzeichnishierarchie im Pool angelegt wird.
lg scientific
PS: smutbert, du wirst im Skript sicher einiges von die wiedererkennen
