Periodic ZFS snapshots – 2-clause BSD license
Someone found my old ZFS snapshot script rather useful and wanted to improve it. Unfortunately I used the GPLv2 license in the original script. To accommodate my friend, I have re-released the snapshot script under the 2-clause BSD license. Feel free to use whichever license, 2-clause BSD or GPLv2, that suits your needs.
#!/bin/sh # Shell script for creating periodic ZFS snapshots. # Copyright © 2012, Trond Endrestøl <Trond.Endrestol@ximalas.info> # All rights reserved. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # 1. Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # This script creates a monthly snapshot at midnight on the first day of every month. # Should the snapshot exist, the old snapshot will be removed and recreated. # Next, this script will create a daily snapshot at midnight, # and hourly snapshots for the hours 01 to 23, # and finally minutely snapshots for the minutes 01 to 59. # Should the snapshot exist, the old snapshot will be removed and recreated. # This script is supposed to be run by cron every minute. # Example of invocation of this script from the system /etc/crontab: # * * * * * root /path/to/create-periodic-zfs-snapshots.sh zpool/filesystem # Example of invocation of this script from a user's crontab: # * * * * * /path/to/create-periodic-zfs-snapshots.sh zpool/filesystem # Tested on FreeBSD/amd64 9.0-STABLE. # A suitable PATH is nice to have, though most of the commands are given using absolute file names. PATH=/bin:/sbin:/usr/bin:/usr/sbin export PATH # Make sure we have been given one, and only one, file system on the command line. if [ "${#}" -ne 1 ]; then echo "Usage: ${0} zpool[/dataset]" >/dev/stderr; exit 1; fi # Make sure the file system exist. if ! /sbin/zfs list -H -t filesystem ${1} >/dev/null 2>/dev/null; then echo "${0}: cannot find the file system ${1}" >/dev/stderr; exit 1; fi # I prefer to use English names on months and weekdays. export LANG=C export LC_ALL=${LANG} export LC_COLLATE=${LANG} export LC_CTYPE=${LANG} export LC_MESSAGES=${LANG} export LC_MONETARY=${LANG} export LC_NUMERIC=${LANG} export LC_TIME=${LANG} # Extract the necessary details on the present. month=`/bin/date +%B | /usr/bin/tr "[:upper:]" "[:lower:]"` weekday=`/bin/date +%A | /usr/bin/tr "[:upper:]" "[:lower:]"` day=`/bin/date +%d` hour=`/bin/date +%H` minute=`/bin/date +%M` # The monthly snapshot will ALWAYS be created when appropriate. if [ ${day} -eq 1 -a ${hour} -eq 0 -a ${minute} -eq 0 ]; then snapshot="${1}@${month}"; # Destroy the monthly snapshot, if it exist. if /sbin/zfs list -H -t snapshot ${snapshot} >/dev/null 2>/dev/null; then /sbin/zfs destroy ${snapshot}; zfs_destroy=${?}; if [ ${zfs_destroy} -ne 0 ]; then exit ${zfs_destroy}; fi; fi; # Create the monthly snapshot. /sbin/zfs snapshot ${snapshot}; zfs_snapshot=${?}; if [ ${zfs_snapshot} -ne 0 ]; then exit ${zfs_snapshot}; fi; fi # Pick weekday, hour, or minute. if [ ${hour} -eq 0 -a ${minute} -eq 0 ]; then snapshot="${1}@${weekday}"; elif [ ${minute} -eq 0 ]; then snapshot="${1}@hourly${hour}"; else snapshot="${1}@minute${minute}"; fi # Destroy the snapshot, if it exist. if /sbin/zfs list -H -t snapshot ${snapshot} >/dev/null 2>/dev/null; then /sbin/zfs destroy ${snapshot}; zfs_destroy=${?}; if [ ${zfs_destroy} -ne 0 ]; then exit ${zfs_destroy}; fi; fi # Create the snapshot. /sbin/zfs snapshot ${snapshot} exit ${?} # EOF of create-periodic-zfs-snapshots.sh.