Skip to content

zfs_backup


#!/bin/ksh93 -p
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
# Script to back up file systems based on the names of their snapshots.
#
#
# Usage: zfs_backup [ -p namespec ] source [[user@]host]destination
#
# If sending to a remote system this is done via ssh so the users needs
# to have the "ZFS File System Management" profile.
#

snapname=day

function remote_dest
{
        if [[ ${dest_host:-${this_host}} == ${this_host} ]]
        then
                if [[ $1 == "-n" ]]
                then
                        shift
                fi
                $@
        else
                echo ssh -CxA -o CompressionLevel=9 $dest_host $@ >&2
                ssh -CxA -o CompressionLevel=9 $dest_host $@
        fi
        return $?
}

function do_pans
{
        typeset depth=0
        typeset -a arr

        while read snapshot
        do

                if ! test_snap $snapshot
                then
                        while (( depth >= 0))
                        do
                                send_snap $snapshot $arr[$depth]
                                let depth=depth-1
                        done
                        return
                else
                        arr[depth]=$snapshot
                        let depth=depth+1
                fi
        done
        send_snap  $snapshot
        while (( depth >= 0))
        do
                send_snap $snapshot $arr[$depth]
                let depth=depth-1
        done
}

typeset -ft do_snap
function do_snap
{
        typeset snapshot
        typeset fs=$1
        typeset last_sn

        while read snapshot
        do
                typeset xfs=${snapshot%@*}
                typeset sn=${snapshot#*@}

                if [[ ${fs} != ${xfs} ]]
                then
                        continue
                fi

                if [[ ${sn#${snapname}} == ${sn} ]]
                then
                        continue
                fi
                if [[ "$last_sn" != "" ]]
                then
                        if ! remote_dest -n pfexec /usr/sbin/zfs list ${dest_fs}${fs#${src}}@${snapshot#*@} > /dev/null 2>&1
                        then
                                
                                echo pfexec /usr/sbin/zfs send -i $last_sn ${snapshot} remote_dest pfexec /usr/sbin/zfs receive ${zFORCE:+-F} ${dest_fs}${fs#${src}} || exit
                                pfexec /usr/sbin/zfs send -i $last_sn ${snapshot} |\
                                        remote_dest "${BUFFER} pfexec /usr/sbin/zfs receive ${zFORCE:+-F} ${dest_fs}${fs#${src}}" || exit
                        fi
                else
                        if ! remote_dest -n pfexec /usr/sbin/zfs list ${dest_fs}${fs#${src}} > /dev/null 2>&1 
                        then
                                echo pfexec /usr/sbin/zfs send  ${snapshot}
                                pfexec /usr/sbin/zfs send  ${snapshot} | \
                                        remote_dest "${BUFFER} pfexec /usr/sbin/zfs receive  ${dest_fs}${fs#${src}}"
                        fi
                fi
                last_sn=${snapshot}
        done
}

function do_fs
{
        typeset x
        while read x
        do
                echo $x
                (pfexec /usr/sbin/zfs list -o name -H -t snapshot -r $x | do_snap $x) < /dev/null
        done

}

function usage
{
        print "USAGE: $0 [ -p prefix ] from to" >&2
        exit
}

while getopts p:F c
do
        case $c in
        p) snapname=$OPTARG ;;
        F) zFORCE=F ;;
        \?) usage; exit ;;
        esac
done

shift $(($OPTIND – 1))

(( $# < 1 )) && usage
src=$1
dest_fs=${2#*:}
dest_host=${2%:*}
if [[ $dest_host == $2 ]]
then
        dest_host=""
fi

this_host=$(uname -n)

if [[ ${dest_host:-${this_host}} == ${this_host} ]]
then
        BUFFER=""
else
        BUFFER="/usr/local/bin/buffer -v |"
fi

pfexec /usr/sbin/zfs list -r -o name -H -t filesystem $src| do_fs

One Comment

Trackbacks & Pingbacks

  1. Rolling incremental backups « Chris Gerhard's Blog

Leave a comment