#! /bin/sh tstamp=`date +%Y%m%d-%H%M%S` label_pfx="zbk-" usrlabel=$1 maxnum=$2 zpool="zroot" # names of the DATASETs to exclude (datasets, not mountpoints!) excludes="/usr/ports /usr/src /backups" usage () { echo Usage: echo "zfssnap [label [maxnum]]" echo "default label: 'default'" echo "default maxnum: infinite" echo "Takes a ZFS snapshot with given custom label." echo "If maxnum specified, keeps the so-many newest snaps only." echo echo "Optional envvars:" echo "EXCLUDES list of dataset paths to exclude from snaps. Overrides default." echo "EXTRA_EXCLUDES list of dataset paths to exclude from snaps. Extends default." echo "default excluded DATASET paths:" echo $excludes } # build list of dataset paths to exclude if [ "x$EXCLUDES" != x ] then excludes=$EXCLUDES elif [ "x$EXTRA_EXCLUDES" != x ] then excludes="$excludes $EXTRA_EXCLUDES" fi # label if [ "x$usrlabel" != "x" ] then if echo "$usrlabel" | grep -qiE '^([a-z0-9]{1,10})$' then label_pfx="$label_pfx$usrlabel" else echo "Invalid label '$usrlabel'! Quitting." usage exit 1 fi else label_pfx="${label_pfx}default" fi # maxnum if [ "x$maxnum" != "x" ] then if ! echo "$maxnum" | grep -qE '^[0-9]+$' then echo "Invalid maxnum '$maxnum'! Terminating." usage exit 1 fi fi # add timestamp to label label="${label_pfx}-$tstamp" # take recursive snap zfs snapshot -r $zpool@$label || exit $? # exclude folders for xm in $excludes do # let this fail, the ds might not exist zfs destroy -r $zpool$xm@$label done # prune dbs if requested if [ "x$maxnum" != x ] then ls /.zfs/snapshot/ | sort -rt- -k 3,4 | awk -v maxnum=$maxnum -v matchlabel=$label_pfx 'BEGIN {x=0} $0 ~ "^"matchlabel { x++; if (x>maxnum) print}' | while read snapname do zfs destroy -r $zpool@$snapname || exit $? done fi