#!/bin/sh ############################################################################### # name: zfsrestored.sh # # Script for restoring the filesystem from backup. Used in conjunection with # zfsdumpd.sh (available on BigAdmin) # Read full description: # http://www.sun.com/bigadmin/content/submitted/zfsdumpd_zfsrestored.jsp ############################################################################### # The backup DIR needs to be same as the one in zfsdump DIR=/var/zfsbk Usage() { cat <<-EOF Usage: $1 [-d backup_dir] [-n] [-r] [-z zfs] -d = where to restore -n = do not back up to a temporary dir before restore -r = recursively restore -z = file system to restore in format of tank/home. Only one file system is supported at this time. EOF } GetBackupfileprefixFromZfsname () { c=0 for str in `echo $1 | awk -F/ '{ for( i=1 ; i <= NF ; i++ ){print $i}}` do c=`expr $c + 1` if [ $c -eq 1 ] then file_prefix="$str" else file_prefix="${file_prefix}_$str" fi done echo $file_prefix } GetZfsnameFromSnapshot () { c=0 for str in `echo $1 | awk -F/ '{print $NF}' | awk -F. '{print $1}' \ | awk -F_ '{ for( i=1 ; i <= NF ; i++ ){ print $i}}` do c=`expr $c + 1` if [ $c -eq 1 ] then zfsname="$str" else zfsname="${zfsname}/$str" fi done echo $zfsname } CheckBackupNeed () { each_zfs=$1 pass=0 if echo $POOLS | grep -w $each_zfs > /dev/null then : else file_prefix=`GetBackupfileprefixFromZfsname $each_zfs` if find "$DIR" | grep "$file_prefix\." >/dev/null 2>&1 then : else echo "Please backup $each_zfs" pass=1 fi fi [ $pass -eq 1 ] && exit 2 } CheckBackupNeeds () { pass=0 for each_zfs in $ZFSs do if echo $POOLS | grep -w $each_zfs > /dev/null then : else file_prefix=`GetBackupfileprefixFromZfsname $each_zfs` if find "$DIR" | grep "$file_prefix\." >/dev/null 2>&1 then : else echo "Please backup $each_zfs" pass=1 fi fi done [ $pass -eq 1 ] && exit 2 } RestoreSingleCurrentZfs () { each_zfs=$1 if echo $POOLS | grep -w $each_zfs > /dev/null then echo "Warning: $each_zfs is not allowed to restore. You may use zfs receive $each_zfs/xxx" else file_prefix=`GetBackupfileprefixFromZfsname $each_zfs` BACKUPSNAPSHOT=`find "$DIR" | grep "$file_prefix\."` if zfs receive $each_zfs < $BACKUPSNAPSHOT; then echo "$each_zfs is restored from $BACKUPSNAPSHOT" fi fi } RestoreSingleBackupZfs () { file_prefix=`GetBackupfileprefixFromZfsname $1` if find "$DIR" | egrep "${file_prefix}\." >/dev/null 2>&1 then snapshot=`find "$DIR" | egrep "${file_prefix}\." | head -n 1` zfsname=`GetZfsnameFromSnapshot $snapshot` if zfs receive $zfsname < "$snapshot"; then echo "$zfsname is restored from $snapshot." fi else echo "Error: Backup file $file_prefix.* does not exist in $DIR" exit 2 fi } RestoreBasedonCurrentZfss () { for myzfs in $ZFSs; do RestoreSingleCurrentZfs $myzfs done } RestoreBasedonBackupZfss () { file_prefix=`GetBackupfileprefixFromZfsname $1` if find "$DIR" | egrep "${file_prefix}_|${file_prefix}\." >/dev/null 2>&1 then for snapshot in `find "$DIR" | egrep "${file_prefix}_|${file_prefix}\."` do zfsname=`GetZfsnameFromSnapshot $snapshot` if zfs receive $zfsname < "$snapshot"; then echo "$zfsname is restored from $snapshot." fi done else echo "Error: Backup file $file_prefix.* does not exist in $DIR" exit 2 fi } ############################################################################### # main() ############################################################################### recursive=1 nobackup=1 while getopts 'd:nrz:' opt 2>/dev/null do case "$opt" in d) DIR="$OPTARG";; n) nobackup=0;; r) recursive=0;; z) zfs="$OPTARG";; \?) Usage $0; exit ;; esac done [ $# -ne `expr $OPTIND - 1` ] && Usage $0 && exit 2 [ -d $DIR ] || mkdir -p $DIR DIRTMP=${DIR}_tmp [ -d $DIRTMP ] || mkdir -p $DIRTMP POOLS=`zpool list -o name | grep -vw NAME` if [ "X$zfs" != X ] then if echo $zfs | egrep "^/|/$" > /dev/null then echo "The format of zfs is tank/home/norma" exit 2 fi if [ $recursive -eq 0 ] then if ZFSs=`zfs list -t filesystem -o name -r $zfs 2>/dev/null | grep -vw NAME` then CheckBackupNeeds [ $nobackup -eq 1 ] && zfsdumpd.sh -d $DIRTMP -r -z $zfs zfs destroy -r $zfs if RestoreBasedonCurrentZfss; then echo "\nYou may empty $DIRTMP after checking the restoration." fi else RestoreBasedonBackupZfss $zfs fi else if zfs list -t filesystem -o name $zfs >/dev/null 2>&1 then if echo $POOLS | grep -w $zfs > /dev/null then echo "Error: $zfs is not allowed to restore directly. Please use 'zfs receive $zfs/xxx'" exit 2 fi CheckBackupNeed $zfs [ $nobackup -eq 1 ] && zfsdumpd.sh -d $DIRTMP -z $zfs pid=$$ zfs rename $zfs ${zfs}_$pid RestoreSingleCurrentZfs $zfs zfs_c=`echo $zfs | nawk -F'/' '{print NF}'` zfs_c=`expr $zfs_c + 1` for zpid in `zfs list -t filesystem -o name -r ${zfs}_$pid | grep ${zfs}_${pid}/` do if [ `echo $zpid | nawk -F'/' '{print NF}'` -eq $zfs_c ]; then zfs rename $zpid `echo $zpid | sed "s,^${zfs}_$pid,$zfs,"` fi done zfs destroy -r ${zfs}_$pid echo "\nYou may empty $DIRTMP after checking the restoration." else RestoreSingleBackupZfs $zfs fi fi else for zfs in $POOLS do ZFSs=`zfs list -t filesystem -o name -r $zfs | grep -vw NAME` CheckBackupNeeds done [ $nobackup -eq 1 ] && zfsdumpd.sh -d $DIRTMP for zfs in $POOLS do ZFSs=`zfs list -t filesystem -o name -r $zfs | grep -vw NAME` zfs destroy -r $zfs RestoreBasedonCurrentZfs done echo "\nYou may empty $DIRTMP after checking the restoration." fi ############################################################################## ### This script is submitted to BigAdmin by a user of the BigAdmin community. ### Sun Microsystems, Inc. is not responsible for the ### contents or the code enclosed. ### ### ### Copyright 2008 Sun Microsystems, Inc. ALL RIGHTS RESERVED ### Use of this software is authorized pursuant to the ### terms of the license found at ### http://www.sun.com/bigadmin/common/berkeley_license.html ##############################################################################