Skip to content

Instantly share code, notes, and snippets.

@jimhansson
Last active August 29, 2015 14:17
Show Gist options
  • Save jimhansson/fe4bd29dcd2fb12a34eb to your computer and use it in GitHub Desktop.
Save jimhansson/fe4bd29dcd2fb12a34eb to your computer and use it in GitHub Desktop.
If I ever loose it again
#!/bin/bash
#
# btrfs-snap - make periodic snapshots of btrfs filesystem
#
# Copyright (C) 2010 Birger Monsen birger@birger.sh
#
# This program is distributed under the GNU General Public License
# http://www.gnu.org/licenses/gpl.txt
#
LOG_FACILITY=local0
VERSION="1.0"
prog=${0##*/}
SENTINEL=/tmp/btrfs-snap
DELAY=5
MAXWAITS=5
USAGE="Usage: ${prog} -h for usage help
${prog} -V for version
${prog} <mountpoint> <prefix> <count>"
SYNOPSIS="${prog} <mountpoint> <prefix> <count>
<mountpoint> is the mountpoint of the btrfs file system to make a
snapshot of
<prefix> is the prefix to be used in the name of the snapshot.
E.g. hourly, daily, weekly...
<count> The number of snapshots with the given prefix to keep.
btrfs-snap / hourly 24
would make a snapshot in /.snapshot called hourly_<date>_<time>
where <date> is on the form YYYY-MM-DD and <time> is on the form
HH:MM:SS. This format makes shure snapshot names sort correctly in
cronological order even when sorted alphabetically. The 24 newest
snapshots matching the prefix are kept around. The rest are deleted.
Snapshots are always created in a directory called .snapshot at the
top level of the given mount point.
Example usage for a system with 2 btrfs file systems mounted as
/ and /home (remember to make these scripts executable):
/etc/cron.hourly/btrfs-snap
#!/bin/bash
${0} / hourly 24
${0} /home hourly 24
/etc/cron.daily/btrfs-snap
#!/bin/bash
${0} / daily 7
${0} /home daily 7
/etc/cron.weekly/btrfs-snap
#!/bin/bash
${0} /home weekly 4
Remember that at the moment snapshots cannot be made read-only, but you
should not modify the snapshots created by this script, as they will
get deleted without any notice. To restore a file, just copy it back from
a snapshot to the main branch."
while getopts "hV" arg; do
case "${arg}" in
h )
echo "$SYNOPSIS"
exit 0
;;
V )
echo "${prog} Version ${VERSION}"
exit 0
;;
* )
echo "$USAGE"
exit 1
;;
esac
done
if [ $# -ne 3 ] ; then
echo "$USAGE"
exit 1
fi
if [ -f /etc/sysconfig/btrfs-snap ] ; then
. /etc/sysconfig/btrfs-snap
fi
mp=$1
pf=$2
cnt=$(( $3+1 ))
mount -t btrfs | cut -d " " -f 3 | grep "^${mp}$" > /dev/null
if [ $? -ne 0 ] ; then
echo "Error: ${mp} is not a btrfs mountpoint"
exit 1
fi
if [ ! -d "${mp}/.snapshot" ]; then
logger -p ${LOG_FACILITY}.info -t ${prog} "Creating ${mp}/.snapshot"
mkdir "${mp}/.snapshot"
fi
dt=`date +'%Y-%m-%d_%H:%M:%S'`
while [ -e $SENTINEL ]; do
MAXWAITS=$(($MAXWAITS-1))
if [[ $MAXWAITS == 0 ]]; then
logger -p ${LOG_FACILITY}.err -t ${prog} "Giving up, waited too long"
exit;
fi
sleep $DELAY
done
touch $SENTINEL
## If snapshot count is higher than the limit, don't create a snapshot
## This should prevent runaway snapshots
if [[ `ls -dr ${mp}/.snapshot/${pf}_* | wc -l` -gt ${cnt} ]]; then
logger -p ${LOG_FACILITY}.err -t ${prog} "Too many snapshots " ${mp}
else
out=`btrfs subvol snapshot ${mp} ${mp}/.snapshot/${pf}_${dt} 2>&1`
if [ $? -eq 0 ] ; then
logger -p ${LOG_FACILITY}.info -t ${prog} "${out}"
else
logger -p ${LOG_FACILITY}.err -t ${prog} "${out}"
fi
fi
ls -dr ${mp}/.snapshot/${pf}_* | tail -n +${cnt} | while read snap ; do
sleep $DELAY # We don't want to remove snapshots too fast
out=`btrfs subvolume delete ${snap} 2>&1`
if [ $? -eq 0 ] ; then
logger -p ${LOG_FACILITY}.info -t ${prog} "${out}"
else
logger -p ${LOG_FACILITY}.err -t ${prog} "${out}"
fi
done
rm $SENTINEL
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment