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