157 lines
4.0 KiB
Bash
Executable File
157 lines
4.0 KiB
Bash
Executable File
#!/bin/bash
|
|
# ----------------------------------------------------------------------
|
|
# mikes handy rotating-filesystem-snapshot utility
|
|
# ----------------------------------------------------------------------
|
|
# this needs to be a lot more general, but the basic idea is it makes
|
|
# rotating backup-snapshots of /home whenever called
|
|
# ----------------------------------------------------------------------
|
|
|
|
#unset PATH # suggestion from H. Milz: avoid accidental use of $PATH
|
|
|
|
# ------------- system commands used by this script --------------------
|
|
|
|
###BEGIN: generic tool checker
|
|
# FIXME: To reuse this function, be sure to edit this line (space separated
|
|
# list).
|
|
needed_tools="id echo mount rm mv cp touch rsync"
|
|
#
|
|
# One shall not need edit anything below this line
|
|
###
|
|
checktools() {
|
|
# This functions attempts to be generic enough to be reused in any program
|
|
# that needs to check that specific tools are present on the system
|
|
# and can be found in the PATH
|
|
var=$(echo $1 | tr '[:lower:]' '[:upper:]')
|
|
echo -n "# Looking for $1... "
|
|
local_var="$(which $1)"
|
|
eval $var="$local_var"
|
|
if [ -z "$local_var" ]
|
|
then
|
|
echo 'NOT FOUND!'
|
|
NOTFOUND="$NOTFOUND$1 "
|
|
DIE=1
|
|
else
|
|
echo "$local_var"
|
|
FOUND="$FOUND$1 "
|
|
fi
|
|
unset local_var
|
|
}
|
|
|
|
for tool in $needed_tools
|
|
do
|
|
checktools "$tool"
|
|
done
|
|
|
|
echo
|
|
echo "# Found $FOUND"
|
|
echo
|
|
|
|
if [ -n "$DIE" ]
|
|
then
|
|
echo "Some tools were not found, please check your installation" >&2
|
|
echo "Needed tools: $needed_tools" >&2
|
|
echo -n "Not found:" >&2
|
|
for tool in $NOTFOUND
|
|
do
|
|
echo -n " $tool" >&2
|
|
done
|
|
echo '!' >&2
|
|
exit 127
|
|
fi
|
|
###END: generic tool checker
|
|
|
|
for config in /etc/remote-backup/*/config
|
|
do
|
|
if [ ! -e "$config" ]
|
|
then
|
|
echo "No backups defined, dying." >&2
|
|
exit 128
|
|
fi
|
|
source /etc/remote-backup/defaults.conf
|
|
source "$config"
|
|
|
|
echo "Debut de backup de ${REMOTE_LOCATION} vers ${SNAPSHOT_RW}/${NAME}/ a $(date)"
|
|
|
|
# ------------- the script itself --------------------------------------
|
|
|
|
# make sure we're running as root
|
|
if [ ! $UID -eq 0 ]
|
|
then
|
|
$ECHO "Sorry, must be root. Exiting..."
|
|
exit
|
|
fi
|
|
|
|
if [[ "$REMOUNT" == "true" ]]
|
|
then
|
|
# attempt to remount the RW mount point as RW; else abort
|
|
$MOUNT -o remount,rw "$MOUNT_DEVICE" "$SNAPSHOT_RW" ;
|
|
if (( $? ))
|
|
then
|
|
$ECHO "snapshot: could not remount $SNAPSHOT_RW readwrite"
|
|
exit
|
|
fi
|
|
fi
|
|
|
|
if [ ! -d "$SNAPSHOT_RW/$NAME" ]
|
|
then
|
|
mkdir -p "$SNAPSHOT_RW/$NAME"
|
|
fi
|
|
|
|
# rotating snapshots of /home (fixme: this should be more general)
|
|
|
|
# step 1: delete the oldest snapshot, if it exists:
|
|
if [ -d "$SNAPSHOT_RW/$NAME/daily.${MAX_ROTATE}" ]
|
|
then
|
|
$RM -rf "$SNAPSHOT_RW/$NAME/daily.${MAX_ROTATE}"
|
|
fi
|
|
|
|
# step 2: shift the middle snapshots(s) back by one, if they exist
|
|
for backup_number in $(seq $((${MAX_ROTATE}-1)) -1 1)
|
|
do
|
|
if [ -d "$SNAPSHOT_RW/$NAME/daily.${backup_number}" ]
|
|
then
|
|
$MV "$SNAPSHOT_RW/$NAME/daily.${backup_number}" \
|
|
"$SNAPSHOT_RW/$NAME/daily.$((${backup_number}+1))"
|
|
fi
|
|
done
|
|
|
|
# step 3: make a hard-link-only (except for dirs) copy of the latest snapshot,
|
|
# if that exists
|
|
if [ -d "$SNAPSHOT_RW/$NAME/daily.0" ]
|
|
then
|
|
$CP -al "$SNAPSHOT_RW/$NAME/daily.0" "$SNAPSHOT_RW/$NAME/daily.1"
|
|
fi
|
|
|
|
# step 4: rsync from the system into the latest snapshot (notice that
|
|
# rsync behaves like cp --remove-destination by default, so the destination
|
|
# is unlinked first. If it were not so, this would copy over the other
|
|
# snapshot(s) too!
|
|
$RSYNC \
|
|
-a \
|
|
--delete \
|
|
--delete-excluded \
|
|
--exclude-from="$EXCLUDES" \
|
|
--bwlimit="$BWLIMIT" \
|
|
"${REMOTE_LOCATION}" \
|
|
"$SNAPSHOT_RW/$NAME/daily.0"
|
|
|
|
# step 5: update the mtime of daily.0 to reflect the snapshot time
|
|
$TOUCH "$SNAPSHOT_RW/$NAME/daily.0"
|
|
|
|
# and thats it for home.
|
|
|
|
# now remount the RW snapshot mountpoint as readonly
|
|
if [[ "$REMOUNT" == "true" ]]
|
|
then
|
|
$MOUNT -o remount,ro "$MOUNT_DEVICE" "$SNAPSHOT_RW"
|
|
if (( $? ))
|
|
then
|
|
$ECHO "snapshot: could not remount $SNAPSHOT_RW readonly"
|
|
exit
|
|
fi
|
|
fi
|
|
|
|
echo "Fin de backup de ${REMOTE_LOCATION} vers ${SNAPSHOT_RW}/${NAME}/ a $(date)"
|
|
echo '-----------------------------------------------------------------------'
|
|
done
|