1# vim: filetype=sh
2#
3# CDDL HEADER START
4#
5# The contents of this file are subject to the terms of the
6# Common Development and Distribution License (the "License").
7# You may not use this file except in compliance with the License.
8#
9# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10# or http://www.opensolaris.org/os/licensing.
11# See the License for the specific language governing permissions
12# and limitations under the License.
13#
14# When distributing Covered Code, include this CDDL HEADER in each
15# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16# If applicable, add the following below this CDDL HEADER, with the
17# fields enclosed by brackets "[]" replaced with your own identifying
18# information: Portions Copyright [yyyy] [name of copyright owner]
19#
20# CDDL HEADER END
21#
22
23#
24# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
25# Use is subject to license terms.
26#
27# ident	"@(#)zfs_rollback_common.kshlib	1.6	08/05/14 SMI"
28#
29
30. $STF_SUITE/include/libtest.kshlib
31
32# Get file sum
33#
34# $1 full file name
35function getsum #fname
36{
37	(( ${#1} == 0 )) && \
38		log_fail "Need give file name."
39	return $($SUM $1 | $AWK '{print $1}')
40}
41
42# Define global variable checksum, get the original file sum.
43#
44origsum=$(getsum /etc/passwd)
45
46#
47# Setup or recover the test environment. Firstly, copy /etc/passwd to ZFS file
48# system or volume, then make a snapshot or clone. Repeat up to three times.
49#
50# $1 number of snapshot. Note: Currently only support three snapshots.
51# $2 indicate if it is necessary to create clone
52#
53function setup_snap_env
54{
55	typeset -i cnt=${1:-3}
56	typeset createclone=${2:-"false"}
57
58	if datasetnonexists $FS; then
59		log_must $ZFS create $FS
60		log_must $ZFS set mountpoint=$TESTDIR $FS
61	fi
62	# Volume can't be created in Local Zone.
63	if datasetnonexists $VOL && is_global_zone; then
64		log_must $ZFS create -V $VOLSIZE $VOL
65	fi
66
67	# Make sure $VOL is volume
68	typeset type=$(get_prop type $VOL)
69	if datasetexists $VOL && \
70		[[ $type == 'volume' ]]; then
71		#
72		# At the first time, Make a UFS file system in volume and
73		# mount it. Otherwise, only check if this ufs file system
74		# was mounted.
75		#
76		log_must eval "$ECHO "y" | \
77			$NEWFS /dev/zvol/$VOL > /dev/null 2>&1"
78
79		[[ ! -d $TESTDIR1 ]] && log_must $MKDIR $TESTDIR1
80
81		# Make sure the ufs filesystem hasn't been mounted,
82		# then mount the new ufs filesystem.
83		$MOUNT | grep -q "/dev/zvol/$VOL" > /dev/null 2>&1
84		if (( $? != 0 )); then
85			log_must $MOUNT \
86				/dev/zvol/$TESTPOOL/$TESTVOL $TESTDIR1
87		fi
88	fi
89
90	# Separately Create three snapshots for file system & volume
91	typeset -i ind=0
92	typeset dtst
93	for dtst in $FS $VOL; do
94		# Volume can be created in Local Zone.
95		if [[ $dtst == $VOL ]]; then
96			if ! is_global_zone; then
97				break
98			fi
99		fi
100
101		ind=0
102		while (( ind < cnt )); do
103			case $dtst in
104			$FS)
105				eval typeset snap=\$FSSNAP$ind
106				eval typeset clone=\$FSCLONE$ind
107				eval typeset fname=\$TESTDIR/\$TESTFILE$ind
108				;;
109			$VOL)
110				eval typeset snap=\$VOLSNAP$ind
111				eval typeset clone=\$VOLCLONE$ind
112				eval typeset fname=\$TESTDIR1/\$TESTFILE$ind
113				;;
114			esac
115
116			if datasetnonexists $snap; then
117				log_must $CP /etc/passwd $fname
118				#
119				# Take the snapshot with the zvol unmounted so
120				# that its filesystem's state will be
121				# consistent.
122				#
123				mount -u -o ro /dev/zvol/$TESTPOOL/$TESTVOL
124				log_must $ZFS snapshot $snap
125				mount -u -o rw /dev/zvol/$TESTPOOL/$TESTVOL
126			fi
127			if [[ $createclone == "true" ]]; then
128				if datasetnonexists $clone; then
129					log_must $ZFS clone $snap $clone
130				fi
131			fi
132			(( ind += 1 ))
133		done
134	done
135}
136
137function setup_clone_env
138{
139	setup_snap_env $1 "true"
140}
141
142#
143# Clean up the test environmnet
144#
145# $1 number of snapshot Note: Currently only support three snapshots.
146#
147function cleanup_env
148{
149	typeset -i cnt=${1:-3}
150	typeset -i ind=0
151	typeset dtst
152	typeset snap
153
154	$PKILL ${DD##*/}
155
156	$MOUNT | grep -q "/dev/zvol/$VOL" > /dev/null 2>&1
157	if (( $? == 0 )); then
158		log_must $UMOUNT -f $TESTDIR1
159	fi
160
161	[[ -d $TESTDIR ]] && log_must $RM -rf $TESTDIR/*
162	[[ -d $TESTDIR1 ]] && log_must $RM -rf $TESTDIR1/*
163
164	for dtst in $FS $VOL; do
165		for snap in $TESTSNAP $TESTSNAP1 $TESTSNAP2; do
166			if snapexists $dtst@$snap; then
167				 log_must $ZFS destroy -Rf $dtst@$snap
168			fi
169		done
170	done
171
172	# Restore original test environment
173	if datasetnonexists $FS ; then
174		log_must $ZFS create $FS
175	fi
176	if datasetnonexists $VOL ; then
177		if is_global_zone ; then
178			log_must $ZFS create -V $VOLSIZE $VOL
179		else
180			log_must $ZFS create $VOL
181		fi
182	fi
183}
184
185#
186# check if the specified files have specified status.
187#
188# $1 expected status
189# $2-n full file name
190# If it is true return 0, else return 1
191#
192function file_status
193{
194	(( $# == 0 )) && \
195		log_fail "The file name is not defined."
196
197	typeset opt
198	case $1 in
199		exist)	opt="-e" ;;
200		nonexist) opt="! -e" ;;
201		*) 	log_fail "Unsupported file status." ;;
202	esac
203
204	shift
205	while (( $# > 0 )); do
206		eval [[ $opt $1 ]] || return 1
207		shift
208	done
209
210	return 0
211}
212
213function files_exist
214{
215	file_status "exist" $@
216}
217
218function files_nonexist
219{
220	file_status "nonexist" $@
221}
222
223#
224# According to snapshot check if the file system was recovered to the right
225# point.
226#
227# $1 snapshot. fs@snap or vol@snap
228#
229function check_files
230{
231	typeset dtst=$1
232
233	if [[ $(get_prop type $dtst) != snapshot ]]; then
234		log_fail "Parameter must be a snapshot."
235	fi
236
237	typeset fsvol=${dtst%%@*}
238	typeset snap=${dtst##*@}
239	if [[ $(get_prop type $fsvol) == "filesystem" ]]; then
240		ind=""
241	else
242		ind="1"
243	fi
244
245	eval typeset file0=\$TESTDIR$ind/\$TESTFILE0
246	eval typeset file1=\$TESTDIR$ind/\$TESTFILE1
247	eval typeset file2=\$TESTDIR$ind/\$TESTFILE2
248
249	case $snap in
250		$TESTSNAP2)
251			log_must files_exist $file0 $file1 $file2
252
253			typeset sum0=$(getsum $file0)
254			typeset sum1=$(getsum $file1)
255			typeset sum2=$(getsum $file2)
256			if [[ $sum0 != $origsum || \
257				$sum1 != $origsum || sum2 != $origsum ]]
258			then
259				log_fail "After rollback, file sum is changed."
260			fi
261			;;
262		$TESTSNAP1)
263			log_must files_exist $file0 $file1
264			log_must files_nonexist $file2
265
266			typeset sum0=$(getsum $file0)
267			typeset sum1=$(getsum $file1)
268			if [[ $sum0 != $origsum || $sum1 != $origsum ]]
269			then
270				log_fail "After rollback, file sum is changed."
271			fi
272			;;
273		$TESTSNAP)
274			log_must files_exist $file0
275			log_must files_nonexist $file1 $file2
276
277			typeset sum0=$(getsum $file0)
278			if [[ $sum0 != $origsum ]]; then
279				log_fail "After rollback, file sum is changed."
280			fi
281			;;
282	esac
283}
284
285# According to dataset type, write file to different directories.
286#
287# $1 dataset
288#
289function write_mountpoint_dir
290{
291	typeset dtst=$1
292	typeset dir
293
294	if [[ $dtst == $FS ]]; then
295		dir=$TESTDIR
296		log_must ismounted $dir
297	else
298		dir=$TESTDIR1
299		log_must ismounted $dir "ufs"
300	fi
301	$DD if=/dev/urandom of=$dir/$TESTFILE1 &
302	log_must $SLEEP 3
303}
304