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