#!/bin/bash
#
#    Author: Mike La Spina
#      Date: Dec 12, 2008
#   Version: 0.4
#   Rev-0.3: Improved GNU and path exec requirements with predefined VAR to exec pointers.
#	      Changed logonly default to 1 	
#   Rev-0.2: Added logging mode variable.
#   Rev-0.1: Year and Day inverted fix. 
#  Function: Provides a grandfather father son snapshot rollup by destroying out of scope snapshots.
#Disclaimer: Use at your own risk - this script is tested but may not produce the same results in some environments. 
#    Rights: You may freely use and modify this script provided you acknowledge the original author(s).
#     Notes: The date and expr functions require the GNU versions found in /usr/bin/gnu/	  
#
#Input parms:1
#		 fs_list - a file name var of which the file contains a list of comma delimed zfs paths to include for rollups.
#		 
	
fs_list=$1
snaplist1=tempwork1.txt
zfsgfslog=zfsgfsrollup.log

# Exec path pointers
GNU_DATE=/usr/gnu/bin/date
GNU_EXPR=/usr/gnu/bin/expr
ZFS=/usr/sbin/zfs
PFEXEC=/usr/bin/pfexec

# Init Global Vars
logonly=1
zfspath="" 
PreviousSnapDate=""
PreviousSnap=""
CurrentYear="$( $GNU_DATE +%y )"
CurrentMonth="$( $GNU_DATE +%m )"
CurrentDay="$( $GNU_DATE +%d )"




# Walk the existing snaps spec'd by the input fs path list and destroy the snapshots that are out of GFS scope 
while read zfspath
do

	if [ "$zfspath" != "" ]
		then
		$ZFS list -o name -t snapshot | grep "$zfspath" > $snaplist1
		while read snaps
		do
			stringpos=0
			let stringpos=$($GNU_EXPR index "$snaps" @)+1
			SnapDate=$( $GNU_EXPR substr $snaps $stringpos 8 )
			let stringpos=$($GNU_EXPR index "$snaps" @)+10
	       	SnapTime=$( $GNU_EXPR substr $snaps $stringpos 5 )
			SnapDay="$(echo $SnapDate | cut -d- -f1)"
			SnapMonth="$(echo $SnapDate | cut -d- -f2)"	  
			SnapYear="$(echo $SnapDate | cut -d- -f3)"

			#We need to flip the date around due to the --date format processing yy-mm-dd
			SnapDate="$SnapYear-$SnapMonth-$SnapDay"

			if [ "$snaps" != "$( $ZFS list -o origin | grep "$snaps" )" ]
				then
				if [ "$PreviousSnapDate" = "$SnapDate" ] # Is there more than 1 snap for the same day to destroy?
					then	
					if [ "$($GNU_DATE +%y-%m-%d)" != "$SnapDate" ] #Never destroy todays snapshots!
						then
						if [ $logonly = 0 ]
							then
							# The script is designed to run once a day, if thats not the case the next if clause could generate does not exist errors
							# since this if clause removes the snapshot first.
							$PFEXEC $ZFS destroy $PreviousSnap
							echo "$PreviousSnap -> snapshot destroyed." >> $zfsgfslog
						else
							echo "$PreviousSnap -> logonly mode action -> snapshot destroyed." >> $zfsgfslog
						fi
					fi
				fi
	
				if [ "$SnapYear" = "$($GNU_DATE --date "$SnapDate +1 day" +%y)" ]
					then
					if [ "$SnapMonth" = "$($GNU_DATE --date "$SnapDate +1 day" +%m)" ] # If it's not a month end snapshot then continue.
						then
						if [ 5 != "$($GNU_DATE --date "$SnapDate" +%w)" ] # If it's not a friday snapshot then continue.
							then
							if [ "$($GNU_DATE +%j)" -gt "$($GNU_DATE --date "$SnapDate +4 days" +%j)" ] #Never destroy this weeks daily snapshots.
								then
								if [ $logonly = 0 ]
									then
									$PFEXEC $ZFS destroy $snaps
									echo "$snaps -> snapshot destroyed." >> $zfsgfslog
								else
									echo "$snaps -> logonly mode action -> snapshot destroyed." >> $zfsgfslog
								fi
							fi
						else
							if [ "$($GNU_DATE +%m)" -gt "$($GNU_DATE --date "$SnapDate" +%m )" ] #Last months weekly can be destroyed.
								then
								if [ $logonly = 0 ]
									then
									$PFEXEC $ZFS destroy $snaps
									echo "$snaps -> snapshot destroyed." >> $zfsgfslog
								else
									echo "$snaps -> logonly mode action -> snapshot destroyed." >> $zfsgfslog
								fi
							fi
						fi
					fi
				fi
			else  
				depends=$( $ZFS list -o name,origin | grep "$snaps" )
				echo "$depends -> these zfs objects are dependants, thus the destroy request is not possible." >> $zfsgfslog	
			fi

			PreviousSnapDate=$SnapDate	
			PreviousSnap=$snaps

		done < $snaplist1
	fi

done < $fs_list

rm $snaplist1

exit 0
  
  



 
 
