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 2007 Sun Microsystems, Inc.  All rights reserved.
25# Use is subject to license terms.
26
27. $STF_SUITE/include/libtest.kshlib
28
29#
30# Execute arguments and record them to the log file.
31# Notice: EXPECT_HISTORY need be defined.
32#
33# $1-n arguments for execution.
34#
35function exec_record
36{
37	[[ -z $EXPECT_HISTORY ]] && log_fail "EXPECT_HISTORY is undefined."
38
39	typeset long_hist
40	typeset user='root'
41	typeset opt
42	while getopts ":lu:" opt; do
43		case $opt in
44			l)	long_hist=1;;
45			u)	user=$OPTARG ;;
46		esac
47	done
48	shift $(($OPTIND -1))
49
50	if [[ $user == 'root' ]]; then
51		log_must "$@"
52	else
53		log_must $SU $user -c "$@"
54	fi
55	user_id=$(id -u $user)
56
57	typeset cmdline="$@"
58	# Remove "eval" ">*" & "<*" for 'zfs send' and 'zfs receive'.
59	cmdline=${cmdline#eval}
60	cmdline=${cmdline%%\>*}
61	cmdline=${cmdline%%\<*}
62
63	# Remove additional blank
64	cmdline=${cmdline## }
65	cmdline=${cmdline%% }
66
67	# Get the basename of command. i.e: /usr/sbin/zpool -> zpool
68	typeset cmd=$($ECHO $cmdline | $AWK '{print $1}')
69	eval cmdline=\${cmdline#$cmd}
70	cmd=${cmd##*/}
71
72	# Write basic history to file
73	print -n $cmd $cmdline >> $EXPECT_HISTORY
74	if [[ -n $long_hist ]]; then
75		# Write long history to file
76		hn=$($HOSTNAME)
77		zn=$($ZONENAME)
78		[ "$zn" = "global" ] && zn=""
79		[ -n "$zn" ] && zn=":$zn"
80		print -n " [user $user_id ($user) on $hn$zn]" >> $EXPECT_HISTORY
81	fi
82	# Plus enter in the end of line
83	print >> $EXPECT_HISTORY
84}
85
86#
87# Format 'zpool history' output to specified file.
88#
89# $1 pool name
90# $2 output file.
91# $3 option
92#
93function format_history
94{
95	typeset pool=$1
96	typeset outfile=$2
97	typeset option=$3
98
99	[[ -z $pool || -z $outfile ]] && \
100		log_fail "Usage: format_history <pool> <outfile> [option]"
101
102	typeset temp_history=$TMPDIR/temp_history.format_history.${TESTCASE_ID}
103	$ZPOOL history $option $pool > $temp_history
104
105	# Truncate output file
106	$CAT /dev/null > $outfile
107
108	typeset line
109	typeset -i n=0
110	while read line; do
111		# Ignore the first line and empty line
112		if [[ $n -eq 0 || -z $line ]]; then
113			n=1; continue
114		fi
115		$ECHO ${line#* } >> $outfile
116	done < $temp_history
117
118	$RM -f $temp_history
119}
120
121#
122# Get the additional pool history.
123#
124# $1 pool name
125# $2 additional history file
126# $3 option
127#
128function additional_history
129{
130	typeset pool=$1
131	typeset add_his_file=$2
132	typeset option=$3
133
134	if [[ -z $pool || -z $add_his_file ]]; then
135		log_fail "Usage: additional_history <pool> " \
136			"<additional_history_file> [option]"
137	fi
138
139	typeset temp_history=$TMPDIR/temp_history.additional_history.${TESTCASE_ID}
140	# Current current history
141	format_history $pool $temp_history $option
142	# Figure out new history
143	$DIFF $temp_history $REAL_HISTORY | $GREP "^<" | $SED 's/^<[ ]*//' > \
144		$add_his_file
145
146	$CP $temp_history $REAL_HISTORY
147	$RM -f $temp_history
148}
149
150#
151# Get given dataset id
152#
153# $1 dataset name
154#
155function get_dataset_id
156{
157	typeset ds=$1
158
159	#
160	# The zdb information looks like:
161	#
162	# Dataset pool/fs [ZPL], ID 21, cr_txg 6, 18.0K, 4 objects
163	#
164	typeset dst_id=$($ZDB $ds | $GREP "^Dataset $ds " | \
165			$AWK -F\, '{print $2}' | $AWK '{print $2}')
166
167	$ECHO $dst_id
168}
169
170#
171# Special case of verify_history, but only for destroyed datasets.  This is
172# needed because get_dataset_id depends on still having the original dataset
173# in order to obtain its dataset id.
174#
175function verify_destroyed #<his_file> <ds_id>
176{
177	typeset his_file=$1
178	typeset ds_id=$2
179
180	$GREP -E "\[txg:[0-9]+\] destroy [^ ]+ \($ds_id\)" $his_file \
181		> /dev/null 2>&1
182	(($? == 0)) && return 0
183	return 1
184}
185
186#
187# Verify directly executed commands in a history file.  This differs from
188# verify_history in that it checks for explicit commands as opposed to
189# internally generated commands.
190#
191function verify_direct_history #<his_file> <subcmd> <ds>
192{
193	typeset his_file=$1
194	typeset subcmd=$2
195	typeset ds=$3
196
197	$GREP "zfs ${subcmd} ${ds}" ${his_file} > /dev/null 2>&1
198	(($? == 0)) && return 0
199	return 1
200}
201
202# This function mostly just helps to collapse the case statement
203# in verify_history.  It returns whether the line matches (1==true).
204function verify_history_line
205{
206	typeset line=$1
207	typeset subcmd=$2
208	typeset ds=$3
209	typeset keyword=$4
210
211	typeset dst_id=$(get_dataset_id $ds)
212	log_note "Line: '$line'"
213	log_note "Checking cmd($subcmd) for $ds, keyword='$keyword'"
214	$ECHO $line | $GREP -E "\[txg:[0-9]+\] $subcmd $ds \($dst_id\)" | \
215		$GREP $keyword >/dev/null 2>&1
216	[[ $? == 0 ]] && return 1
217	return 0
218}
219
220#
221# Scan history file and check if it include expected internal history
222# information
223#
224# $1 history file
225# $2 subcmd
226# $3 dataset
227# $4 keyword
228#
229function verify_history #<his_file> <subcmd> <ds> [keyword]
230{
231	typeset his_file=$1
232	typeset subcmd=$2
233	typeset ds=$3
234	typeset keyword=$4
235
236	typeset line found=0
237	log_note "Test1"
238	while read line; do
239		case $subcmd in
240		snapshot|rollback|inherit)
241			# [txg:12] snapshot system/foo@0 (46)
242			keyword="$subcmd"
243			verify_history_line "$line" $subcmd $ds $keyword
244			[[ $? == 0 ]] && return 0
245			;;
246		allow)
247			# [txg:10] permission update testpool.1477/testfs.1477 (40) s-$@basic snapshot
248			_subcmd="permission update"
249			verify_history_line "$line" "$_subcmd" $ds "$keyword"
250			[[ $? == 0 ]] && return 0
251			;;
252		unallow)
253			# [txg:174] permission remove testpool.1477/testfs.1477 (40) El$ @set
254			_subcmd="permission remove"
255			verify_history_line "$line" "$_subcmd" $ds "$keyword"
256			[[ $? == 0 ]] && return 0
257			;;
258		*)
259			;;
260		esac
261	done < $his_file
262	return 1
263}
264