xref: /freebsd-src/sys/contrib/openzfs/tests/zfs-tests/include/libtest.shlib (revision c6767dc1f236f20eecd75790afd42829345153da)
1eda14cbcSMatt Macy#
2eda14cbcSMatt Macy# CDDL HEADER START
3eda14cbcSMatt Macy#
4eda14cbcSMatt Macy# The contents of this file are subject to the terms of the
5eda14cbcSMatt Macy# Common Development and Distribution License (the "License").
6eda14cbcSMatt Macy# You may not use this file except in compliance with the License.
7eda14cbcSMatt Macy#
8eda14cbcSMatt Macy# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9271171e0SMartin Matuska# or https://opensource.org/licenses/CDDL-1.0.
10eda14cbcSMatt Macy# See the License for the specific language governing permissions
11eda14cbcSMatt Macy# and limitations under the License.
12eda14cbcSMatt Macy#
13eda14cbcSMatt Macy# When distributing Covered Code, include this CDDL HEADER in each
14eda14cbcSMatt Macy# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15eda14cbcSMatt Macy# If applicable, add the following below this CDDL HEADER, with the
16eda14cbcSMatt Macy# fields enclosed by brackets "[]" replaced with your own identifying
17eda14cbcSMatt Macy# information: Portions Copyright [yyyy] [name of copyright owner]
18eda14cbcSMatt Macy#
19eda14cbcSMatt Macy# CDDL HEADER END
20eda14cbcSMatt Macy#
21eda14cbcSMatt Macy
22eda14cbcSMatt Macy#
23eda14cbcSMatt Macy# Copyright (c) 2009, Sun Microsystems Inc. All rights reserved.
24eda14cbcSMatt Macy# Copyright (c) 2012, 2020, Delphix. All rights reserved.
25eda14cbcSMatt Macy# Copyright (c) 2017, Tim Chase. All rights reserved.
26eda14cbcSMatt Macy# Copyright (c) 2017, Nexenta Systems Inc. All rights reserved.
27eda14cbcSMatt Macy# Copyright (c) 2017, Lawrence Livermore National Security LLC.
28eda14cbcSMatt Macy# Copyright (c) 2017, Datto Inc. All rights reserved.
29eda14cbcSMatt Macy# Copyright (c) 2017, Open-E Inc. All rights reserved.
3021b492edSMartin Matuska# Copyright (c) 2021, The FreeBSD Foundation.
31*c6767dc1SMartin Matuska# Copyright (c) 2025, Klara, Inc.
32eda14cbcSMatt Macy# Use is subject to license terms.
33eda14cbcSMatt Macy#
34eda14cbcSMatt Macy
35716fd348SMartin Matuska. ${STF_SUITE}/include/tunables.cfg
36716fd348SMartin Matuska
37eda14cbcSMatt Macy. ${STF_TOOLS}/include/logapi.shlib
38eda14cbcSMatt Macy. ${STF_SUITE}/include/math.shlib
39eda14cbcSMatt Macy. ${STF_SUITE}/include/blkdev.shlib
40eda14cbcSMatt Macy
41*c6767dc1SMartin Matuska
42a2b560ccSMartin Matuska# On AlmaLinux 9 we will see $PWD = '.' instead of the full path.  This causes
43a2b560ccSMartin Matuska# some tests to fail.  Fix it up here.
44a2b560ccSMartin Matuskaif [ "$PWD" = "." ] ; then
45a2b560ccSMartin Matuska	PWD="$(readlink -f $PWD)"
46a2b560ccSMartin Matuskafi
47a2b560ccSMartin Matuska
48eda14cbcSMatt Macy#
49eda14cbcSMatt Macy# Apply constrained path when available.  This is required since the
50eda14cbcSMatt Macy# PATH may have been modified by sudo's secure_path behavior.
51eda14cbcSMatt Macy#
52eda14cbcSMatt Macyif [ -n "$STF_PATH" ]; then
539db44a8eSMartin Matuska	export PATH="$STF_PATH"
54eda14cbcSMatt Macyfi
55eda14cbcSMatt Macy
56eda14cbcSMatt Macy#
57eda14cbcSMatt Macy# Generic dot version comparison function
58eda14cbcSMatt Macy#
59eda14cbcSMatt Macy# Returns success when version $1 is greater than or equal to $2.
60eda14cbcSMatt Macy#
61eda14cbcSMatt Macyfunction compare_version_gte
62eda14cbcSMatt Macy{
63716fd348SMartin Matuska	[ "$(printf "$1\n$2" | sort -V | tail -n1)" = "$1" ]
64eda14cbcSMatt Macy}
65eda14cbcSMatt Macy
664fefe1b7SMartin Matuska# Helper function used by linux_version() and freebsd_version()
6775e1fea6SMartin Matuska# $1, if provided, should be a MAJOR, MAJOR.MINOR or MAJOR.MINOR.PATCH
6875e1fea6SMartin Matuska# version number
694fefe1b7SMartin Matuskafunction kernel_version
70eda14cbcSMatt Macy{
71eda14cbcSMatt Macy	typeset ver="$1"
72eda14cbcSMatt Macy
7375e1fea6SMartin Matuska	[ -z "$ver" ] && case "$UNAME" in
7475e1fea6SMartin Matuska	Linux)
7575e1fea6SMartin Matuska		# Linux version numbers are X.Y.Z followed by optional
7675e1fea6SMartin Matuska		# vendor/distro specific stuff
7775e1fea6SMartin Matuska		#   RHEL7:       3.10.0-1160.108.1.el7.x86_64
7875e1fea6SMartin Matuska		#   Fedora 37:   6.5.12-100.fc37.x86_64
7975e1fea6SMartin Matuska		#   Debian 12.6: 6.1.0-22-amd64
8075e1fea6SMartin Matuska		ver=$(uname -r | grep -Eo "^[0-9]+\.[0-9]+\.[0-9]+")
8175e1fea6SMartin Matuska		;;
8275e1fea6SMartin Matuska	FreeBSD)
8375e1fea6SMartin Matuska		# FreeBSD version numbers are X.Y-BRANCH-pZ. Depending on
8475e1fea6SMartin Matuska		# branch, -pZ may not be present, but this is typically only
8575e1fea6SMartin Matuska		# on pre-release or true .0 releases, so can be assumed 0
8675e1fea6SMartin Matuska		# if not present.
8775e1fea6SMartin Matuska		# eg:
8875e1fea6SMartin Matuska		#   13.2-RELEASE-p4
8975e1fea6SMartin Matuska		#   14.1-RELEASE
9075e1fea6SMartin Matuska		#   15.0-CURRENT
9175e1fea6SMartin Matuska		ver=$(uname -r | \
9275e1fea6SMartin Matuska		    grep -Eo "[0-9]+\.[0-9]+(-[A-Z0-9]+-p[0-9]+)?" | \
9375e1fea6SMartin Matuska		    sed -E "s/-[^-]+-p/./")
9475e1fea6SMartin Matuska		;;
9575e1fea6SMartin Matuska	*)
9675e1fea6SMartin Matuska		# Unknown system
9775e1fea6SMartin Matuska		log_fail "Don't know how to get kernel version for '$UNAME'"
9875e1fea6SMartin Matuska		;;
9975e1fea6SMartin Matuska	esac
100eda14cbcSMatt Macy
101716fd348SMartin Matuska	typeset version major minor _
102716fd348SMartin Matuska	IFS='.' read -r version major minor _ <<<"$ver"
103eda14cbcSMatt Macy
104716fd348SMartin Matuska	[ -z "$version" ] && version=0
105716fd348SMartin Matuska	[ -z "$major" ] && major=0
106716fd348SMartin Matuska	[ -z "$minor" ] && minor=0
107eda14cbcSMatt Macy
108716fd348SMartin Matuska	echo $((version * 100000 + major * 1000 + minor))
109eda14cbcSMatt Macy}
110eda14cbcSMatt Macy
1114fefe1b7SMartin Matuska# Linux kernel version comparison function
1124fefe1b7SMartin Matuska#
1134fefe1b7SMartin Matuska# $1 Linux version ("4.10", "2.6.32") or blank for installed Linux version
1144fefe1b7SMartin Matuska#
1154fefe1b7SMartin Matuska# Used for comparison: if [ $(linux_version) -ge $(linux_version "2.6.32") ]
1164fefe1b7SMartin Matuskafunction linux_version {
1174fefe1b7SMartin Matuska	kernel_version "$1"
1184fefe1b7SMartin Matuska}
1194fefe1b7SMartin Matuska
1204fefe1b7SMartin Matuska# FreeBSD version comparison function
1214fefe1b7SMartin Matuska#
1224fefe1b7SMartin Matuska# $1 FreeBSD version ("13.2", "14.0") or blank for installed FreeBSD version
1234fefe1b7SMartin Matuska#
1244fefe1b7SMartin Matuska# Used for comparison: if [ $(freebsd_version) -ge $(freebsd_version "13.2") ]
1254fefe1b7SMartin Matuskafunction freebsd_version {
1264fefe1b7SMartin Matuska	kernel_version "$1"
1274fefe1b7SMartin Matuska}
1284fefe1b7SMartin Matuska
129eda14cbcSMatt Macy# Determine if this is a Linux test system
130eda14cbcSMatt Macy#
131eda14cbcSMatt Macy# Return 0 if platform Linux, 1 if otherwise
132eda14cbcSMatt Macy
133eda14cbcSMatt Macyfunction is_linux
134eda14cbcSMatt Macy{
135716fd348SMartin Matuska	[ "$UNAME" = "Linux" ]
136eda14cbcSMatt Macy}
137eda14cbcSMatt Macy
138eda14cbcSMatt Macy# Determine if this is an illumos test system
139eda14cbcSMatt Macy#
140eda14cbcSMatt Macy# Return 0 if platform illumos, 1 if otherwise
141eda14cbcSMatt Macyfunction is_illumos
142eda14cbcSMatt Macy{
143716fd348SMartin Matuska	[ "$UNAME" = "illumos" ]
144eda14cbcSMatt Macy}
145eda14cbcSMatt Macy
146eda14cbcSMatt Macy# Determine if this is a FreeBSD test system
147eda14cbcSMatt Macy#
148eda14cbcSMatt Macy# Return 0 if platform FreeBSD, 1 if otherwise
149eda14cbcSMatt Macy
150eda14cbcSMatt Macyfunction is_freebsd
151eda14cbcSMatt Macy{
152716fd348SMartin Matuska	[ "$UNAME" = "FreeBSD" ]
153eda14cbcSMatt Macy}
154eda14cbcSMatt Macy
155eda14cbcSMatt Macy# Determine if this is a 32-bit system
156eda14cbcSMatt Macy#
157eda14cbcSMatt Macy# Return 0 if platform is 32-bit, 1 if otherwise
158eda14cbcSMatt Macy
159eda14cbcSMatt Macyfunction is_32bit
160eda14cbcSMatt Macy{
161716fd348SMartin Matuska	[ $(getconf LONG_BIT) = "32" ]
162eda14cbcSMatt Macy}
163eda14cbcSMatt Macy
164eda14cbcSMatt Macy# Determine if kmemleak is enabled
165eda14cbcSMatt Macy#
166eda14cbcSMatt Macy# Return 0 if kmemleak is enabled, 1 if otherwise
167eda14cbcSMatt Macy
168eda14cbcSMatt Macyfunction is_kmemleak
169eda14cbcSMatt Macy{
170716fd348SMartin Matuska	is_linux && [ -e /sys/kernel/debug/kmemleak ]
171eda14cbcSMatt Macy}
172eda14cbcSMatt Macy
173eda14cbcSMatt Macy# Determine whether a dataset is mounted
174eda14cbcSMatt Macy#
175eda14cbcSMatt Macy# $1 dataset name
176eda14cbcSMatt Macy# $2 filesystem type; optional - defaulted to zfs
177eda14cbcSMatt Macy#
178eda14cbcSMatt Macy# Return 0 if dataset is mounted; 1 if unmounted; 2 on error
179eda14cbcSMatt Macy
180eda14cbcSMatt Macyfunction ismounted
181eda14cbcSMatt Macy{
182eda14cbcSMatt Macy	typeset fstype=$2
183eda14cbcSMatt Macy	[[ -z $fstype ]] && fstype=zfs
184716fd348SMartin Matuska	typeset out dir name
185eda14cbcSMatt Macy
186eda14cbcSMatt Macy	case $fstype in
187eda14cbcSMatt Macy		zfs)
188eda14cbcSMatt Macy			if [[ "$1" == "/"* ]] ; then
189716fd348SMartin Matuska				! zfs mount | awk -v fs="$1" '$2 == fs {exit 1}'
190eda14cbcSMatt Macy			else
191716fd348SMartin Matuska				! zfs mount | awk -v ds="$1" '$1 == ds {exit 1}'
192eda14cbcSMatt Macy			fi
193eda14cbcSMatt Macy		;;
194eda14cbcSMatt Macy		ufs|nfs)
195eda14cbcSMatt Macy			if is_freebsd; then
196eda14cbcSMatt Macy				mount -pt $fstype | while read dev dir _t _flags; do
197eda14cbcSMatt Macy					[[ "$1" == "$dev" || "$1" == "$dir" ]] && return 0
198eda14cbcSMatt Macy				done
199eda14cbcSMatt Macy			else
200716fd348SMartin Matuska				out=$(df -F $fstype $1 2>/dev/null) || return
201eda14cbcSMatt Macy
202eda14cbcSMatt Macy				dir=${out%%\(*}
203eda14cbcSMatt Macy				dir=${dir%% *}
204eda14cbcSMatt Macy				name=${out##*\(}
205eda14cbcSMatt Macy				name=${name%%\)*}
206eda14cbcSMatt Macy				name=${name%% *}
207eda14cbcSMatt Macy
208eda14cbcSMatt Macy				[[ "$1" == "$dir" || "$1" == "$name" ]] && return 0
209eda14cbcSMatt Macy			fi
210eda14cbcSMatt Macy		;;
211eda14cbcSMatt Macy		ext*)
212716fd348SMartin Matuska			df -t $fstype $1 > /dev/null 2>&1
213eda14cbcSMatt Macy		;;
214eda14cbcSMatt Macy		zvol)
215eda14cbcSMatt Macy			if [[ -L "$ZVOL_DEVDIR/$1" ]]; then
216eda14cbcSMatt Macy				link=$(readlink -f $ZVOL_DEVDIR/$1)
217eda14cbcSMatt Macy				[[ -n "$link" ]] && \
218eda14cbcSMatt Macy					mount | grep -q "^$link" && \
219eda14cbcSMatt Macy						return 0
220eda14cbcSMatt Macy			fi
221eda14cbcSMatt Macy		;;
222716fd348SMartin Matuska		*)
223716fd348SMartin Matuska			false
224716fd348SMartin Matuska		;;
225eda14cbcSMatt Macy	esac
226eda14cbcSMatt Macy}
227eda14cbcSMatt Macy
228eda14cbcSMatt Macy# Return 0 if a dataset is mounted; 1 otherwise
229eda14cbcSMatt Macy#
230eda14cbcSMatt Macy# $1 dataset name
231eda14cbcSMatt Macy# $2 filesystem type; optional - defaulted to zfs
232eda14cbcSMatt Macy
233eda14cbcSMatt Macyfunction mounted
234eda14cbcSMatt Macy{
235eda14cbcSMatt Macy	ismounted $1 $2
236eda14cbcSMatt Macy}
237eda14cbcSMatt Macy
238eda14cbcSMatt Macy# Return 0 if a dataset is unmounted; 1 otherwise
239eda14cbcSMatt Macy#
240eda14cbcSMatt Macy# $1 dataset name
241eda14cbcSMatt Macy# $2 filesystem type; optional - defaulted to zfs
242eda14cbcSMatt Macy
243eda14cbcSMatt Macyfunction unmounted
244eda14cbcSMatt Macy{
245716fd348SMartin Matuska	! ismounted $1 $2
246eda14cbcSMatt Macy}
247eda14cbcSMatt Macy
248eda14cbcSMatt Macyfunction default_setup
249eda14cbcSMatt Macy{
250eda14cbcSMatt Macy	default_setup_noexit "$@"
251eda14cbcSMatt Macy
252eda14cbcSMatt Macy	log_pass
253eda14cbcSMatt Macy}
254eda14cbcSMatt Macy
255eda14cbcSMatt Macyfunction default_setup_no_mountpoint
256eda14cbcSMatt Macy{
257eda14cbcSMatt Macy	default_setup_noexit "$1" "$2" "$3" "yes"
258eda14cbcSMatt Macy
259eda14cbcSMatt Macy	log_pass
260eda14cbcSMatt Macy}
261eda14cbcSMatt Macy
262eda14cbcSMatt Macy#
263eda14cbcSMatt Macy# Given a list of disks, setup storage pools and datasets.
264eda14cbcSMatt Macy#
265eda14cbcSMatt Macyfunction default_setup_noexit
266eda14cbcSMatt Macy{
267eda14cbcSMatt Macy	typeset disklist=$1
268eda14cbcSMatt Macy	typeset container=$2
269eda14cbcSMatt Macy	typeset volume=$3
270eda14cbcSMatt Macy	typeset no_mountpoint=$4
271eda14cbcSMatt Macy	log_note begin default_setup_noexit
272eda14cbcSMatt Macy
273eda14cbcSMatt Macy	if is_global_zone; then
274eda14cbcSMatt Macy		if poolexists $TESTPOOL ; then
275eda14cbcSMatt Macy			destroy_pool $TESTPOOL
276eda14cbcSMatt Macy		fi
277eda14cbcSMatt Macy		[[ -d /$TESTPOOL ]] && rm -rf /$TESTPOOL
278eda14cbcSMatt Macy		log_must zpool create -f $TESTPOOL $disklist
279eda14cbcSMatt Macy	else
280eda14cbcSMatt Macy		reexport_pool
281eda14cbcSMatt Macy	fi
282eda14cbcSMatt Macy
283eda14cbcSMatt Macy	rm -rf $TESTDIR  || log_unresolved Could not remove $TESTDIR
284eda14cbcSMatt Macy	mkdir -p $TESTDIR || log_unresolved Could not create $TESTDIR
285eda14cbcSMatt Macy
286eda14cbcSMatt Macy	log_must zfs create $TESTPOOL/$TESTFS
287eda14cbcSMatt Macy	if [[ -z $no_mountpoint ]]; then
288eda14cbcSMatt Macy		log_must zfs set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
289eda14cbcSMatt Macy	fi
290eda14cbcSMatt Macy
291eda14cbcSMatt Macy	if [[ -n $container ]]; then
292eda14cbcSMatt Macy		rm -rf $TESTDIR1  || \
293eda14cbcSMatt Macy			log_unresolved Could not remove $TESTDIR1
294eda14cbcSMatt Macy		mkdir -p $TESTDIR1 || \
295eda14cbcSMatt Macy			log_unresolved Could not create $TESTDIR1
296eda14cbcSMatt Macy
297eda14cbcSMatt Macy		log_must zfs create $TESTPOOL/$TESTCTR
298eda14cbcSMatt Macy		log_must zfs set canmount=off $TESTPOOL/$TESTCTR
299eda14cbcSMatt Macy		log_must zfs create $TESTPOOL/$TESTCTR/$TESTFS1
300eda14cbcSMatt Macy		if [[ -z $no_mountpoint ]]; then
301eda14cbcSMatt Macy			log_must zfs set mountpoint=$TESTDIR1 \
302eda14cbcSMatt Macy			    $TESTPOOL/$TESTCTR/$TESTFS1
303eda14cbcSMatt Macy		fi
304eda14cbcSMatt Macy	fi
305eda14cbcSMatt Macy
306eda14cbcSMatt Macy	if [[ -n $volume ]]; then
307eda14cbcSMatt Macy		if is_global_zone ; then
308eda14cbcSMatt Macy			log_must zfs create -V $VOLSIZE $TESTPOOL/$TESTVOL
309eda14cbcSMatt Macy			block_device_wait
310eda14cbcSMatt Macy		else
311eda14cbcSMatt Macy			log_must zfs create $TESTPOOL/$TESTVOL
312eda14cbcSMatt Macy		fi
313eda14cbcSMatt Macy	fi
314eda14cbcSMatt Macy}
315eda14cbcSMatt Macy
316eda14cbcSMatt Macy#
317eda14cbcSMatt Macy# Given a list of disks, setup a storage pool, file system and
318eda14cbcSMatt Macy# a container.
319eda14cbcSMatt Macy#
320eda14cbcSMatt Macyfunction default_container_setup
321eda14cbcSMatt Macy{
322eda14cbcSMatt Macy	typeset disklist=$1
323eda14cbcSMatt Macy
324eda14cbcSMatt Macy	default_setup "$disklist" "true"
325eda14cbcSMatt Macy}
326eda14cbcSMatt Macy
327eda14cbcSMatt Macy#
328eda14cbcSMatt Macy# Given a list of disks, setup a storage pool,file system
329eda14cbcSMatt Macy# and a volume.
330eda14cbcSMatt Macy#
331eda14cbcSMatt Macyfunction default_volume_setup
332eda14cbcSMatt Macy{
333eda14cbcSMatt Macy	typeset disklist=$1
334eda14cbcSMatt Macy
335eda14cbcSMatt Macy	default_setup "$disklist" "" "true"
336eda14cbcSMatt Macy}
337eda14cbcSMatt Macy
338eda14cbcSMatt Macy#
339eda14cbcSMatt Macy# Given a list of disks, setup a storage pool,file system,
340eda14cbcSMatt Macy# a container and a volume.
341eda14cbcSMatt Macy#
342eda14cbcSMatt Macyfunction default_container_volume_setup
343eda14cbcSMatt Macy{
344eda14cbcSMatt Macy	typeset disklist=$1
345eda14cbcSMatt Macy
346eda14cbcSMatt Macy	default_setup "$disklist" "true" "true"
347eda14cbcSMatt Macy}
348eda14cbcSMatt Macy
349eda14cbcSMatt Macy#
350eda14cbcSMatt Macy# Create a snapshot on a filesystem or volume. Defaultly create a snapshot on
351eda14cbcSMatt Macy# filesystem
352eda14cbcSMatt Macy#
353eda14cbcSMatt Macy# $1 Existing filesystem or volume name. Default, $TESTPOOL/$TESTFS
354eda14cbcSMatt Macy# $2 snapshot name. Default, $TESTSNAP
355eda14cbcSMatt Macy#
356eda14cbcSMatt Macyfunction create_snapshot
357eda14cbcSMatt Macy{
358eda14cbcSMatt Macy	typeset fs_vol=${1:-$TESTPOOL/$TESTFS}
359eda14cbcSMatt Macy	typeset snap=${2:-$TESTSNAP}
360eda14cbcSMatt Macy
361eda14cbcSMatt Macy	[[ -z $fs_vol ]] && log_fail "Filesystem or volume's name is undefined."
362eda14cbcSMatt Macy	[[ -z $snap ]] && log_fail "Snapshot's name is undefined."
363eda14cbcSMatt Macy
364eda14cbcSMatt Macy	if snapexists $fs_vol@$snap; then
365eda14cbcSMatt Macy		log_fail "$fs_vol@$snap already exists."
366eda14cbcSMatt Macy	fi
367eda14cbcSMatt Macy	datasetexists $fs_vol || \
368eda14cbcSMatt Macy		log_fail "$fs_vol must exist."
369eda14cbcSMatt Macy
370eda14cbcSMatt Macy	log_must zfs snapshot $fs_vol@$snap
371eda14cbcSMatt Macy}
372eda14cbcSMatt Macy
373eda14cbcSMatt Macy#
374eda14cbcSMatt Macy# Create a clone from a snapshot, default clone name is $TESTCLONE.
375eda14cbcSMatt Macy#
376eda14cbcSMatt Macy# $1 Existing snapshot, $TESTPOOL/$TESTFS@$TESTSNAP is default.
377eda14cbcSMatt Macy# $2 Clone name, $TESTPOOL/$TESTCLONE is default.
378eda14cbcSMatt Macy#
379eda14cbcSMatt Macyfunction create_clone   # snapshot clone
380eda14cbcSMatt Macy{
381eda14cbcSMatt Macy	typeset snap=${1:-$TESTPOOL/$TESTFS@$TESTSNAP}
382eda14cbcSMatt Macy	typeset clone=${2:-$TESTPOOL/$TESTCLONE}
383eda14cbcSMatt Macy
384eda14cbcSMatt Macy	[[ -z $snap ]] && \
385eda14cbcSMatt Macy		log_fail "Snapshot name is undefined."
386eda14cbcSMatt Macy	[[ -z $clone ]] && \
387eda14cbcSMatt Macy		log_fail "Clone name is undefined."
388eda14cbcSMatt Macy
389eda14cbcSMatt Macy	log_must zfs clone $snap $clone
390eda14cbcSMatt Macy}
391eda14cbcSMatt Macy
392eda14cbcSMatt Macy#
393eda14cbcSMatt Macy# Create a bookmark of the given snapshot.  Defaultly create a bookmark on
394eda14cbcSMatt Macy# filesystem.
395eda14cbcSMatt Macy#
396eda14cbcSMatt Macy# $1 Existing filesystem or volume name. Default, $TESTFS
397eda14cbcSMatt Macy# $2 Existing snapshot name. Default, $TESTSNAP
398eda14cbcSMatt Macy# $3 bookmark name. Default, $TESTBKMARK
399eda14cbcSMatt Macy#
400eda14cbcSMatt Macyfunction create_bookmark
401eda14cbcSMatt Macy{
402eda14cbcSMatt Macy	typeset fs_vol=${1:-$TESTFS}
403eda14cbcSMatt Macy	typeset snap=${2:-$TESTSNAP}
404eda14cbcSMatt Macy	typeset bkmark=${3:-$TESTBKMARK}
405eda14cbcSMatt Macy
406eda14cbcSMatt Macy	[[ -z $fs_vol ]] && log_fail "Filesystem or volume's name is undefined."
407eda14cbcSMatt Macy	[[ -z $snap ]] && log_fail "Snapshot's name is undefined."
408eda14cbcSMatt Macy	[[ -z $bkmark ]] && log_fail "Bookmark's name is undefined."
409eda14cbcSMatt Macy
410eda14cbcSMatt Macy	if bkmarkexists $fs_vol#$bkmark; then
411eda14cbcSMatt Macy		log_fail "$fs_vol#$bkmark already exists."
412eda14cbcSMatt Macy	fi
413eda14cbcSMatt Macy	datasetexists $fs_vol || \
414eda14cbcSMatt Macy		log_fail "$fs_vol must exist."
415eda14cbcSMatt Macy	snapexists $fs_vol@$snap || \
416eda14cbcSMatt Macy		log_fail "$fs_vol@$snap must exist."
417eda14cbcSMatt Macy
418eda14cbcSMatt Macy	log_must zfs bookmark $fs_vol@$snap $fs_vol#$bkmark
419eda14cbcSMatt Macy}
420eda14cbcSMatt Macy
421eda14cbcSMatt Macy#
422eda14cbcSMatt Macy# Create a temporary clone result of an interrupted resumable 'zfs receive'
423eda14cbcSMatt Macy# $1 Destination filesystem name. Must not exist, will be created as the result
424eda14cbcSMatt Macy#    of this function along with its %recv temporary clone
425eda14cbcSMatt Macy# $2 Source filesystem name. Must not exist, will be created and destroyed
426eda14cbcSMatt Macy#
427eda14cbcSMatt Macyfunction create_recv_clone
428eda14cbcSMatt Macy{
429eda14cbcSMatt Macy	typeset recvfs="$1"
430eda14cbcSMatt Macy	typeset sendfs="${2:-$TESTPOOL/create_recv_clone}"
431eda14cbcSMatt Macy	typeset snap="$sendfs@snap1"
432eda14cbcSMatt Macy	typeset incr="$sendfs@snap2"
433eda14cbcSMatt Macy	typeset mountpoint="$TESTDIR/create_recv_clone"
434eda14cbcSMatt Macy	typeset sendfile="$TESTDIR/create_recv_clone.zsnap"
435eda14cbcSMatt Macy
436eda14cbcSMatt Macy	[[ -z $recvfs ]] && log_fail "Recv filesystem's name is undefined."
437eda14cbcSMatt Macy
438eda14cbcSMatt Macy	datasetexists $recvfs && log_fail "Recv filesystem must not exist."
439eda14cbcSMatt Macy	datasetexists $sendfs && log_fail "Send filesystem must not exist."
440eda14cbcSMatt Macy
441c03c5b1cSMartin Matuska	log_must zfs create -o compression=off -o mountpoint="$mountpoint" $sendfs
442eda14cbcSMatt Macy	log_must zfs snapshot $snap
443eda14cbcSMatt Macy	log_must eval "zfs send $snap | zfs recv -u $recvfs"
444eda14cbcSMatt Macy	log_must mkfile 1m "$mountpoint/data"
445eda14cbcSMatt Macy	log_must zfs snapshot $incr
446eda14cbcSMatt Macy	log_must eval "zfs send -i $snap $incr | dd bs=10K count=1 \
447eda14cbcSMatt Macy	    iflag=fullblock > $sendfile"
448eda14cbcSMatt Macy	log_mustnot eval "zfs recv -su $recvfs < $sendfile"
449eda14cbcSMatt Macy	destroy_dataset "$sendfs" "-r"
450eda14cbcSMatt Macy	log_must rm -f "$sendfile"
451eda14cbcSMatt Macy
452eda14cbcSMatt Macy	if [[ $(get_prop 'inconsistent' "$recvfs/%recv") -ne 1 ]]; then
453eda14cbcSMatt Macy		log_fail "Error creating temporary $recvfs/%recv clone"
454eda14cbcSMatt Macy	fi
455eda14cbcSMatt Macy}
456eda14cbcSMatt Macy
457eda14cbcSMatt Macyfunction default_mirror_setup
458eda14cbcSMatt Macy{
459eda14cbcSMatt Macy	default_mirror_setup_noexit $1 $2 $3
460eda14cbcSMatt Macy
461eda14cbcSMatt Macy	log_pass
462eda14cbcSMatt Macy}
463eda14cbcSMatt Macy
464eda14cbcSMatt Macy#
465eda14cbcSMatt Macy# Given a pair of disks, set up a storage pool and dataset for the mirror
466eda14cbcSMatt Macy# @parameters: $1 the primary side of the mirror
467eda14cbcSMatt Macy#   $2 the secondary side of the mirror
468eda14cbcSMatt Macy# @uses: ZPOOL ZFS TESTPOOL TESTFS
469eda14cbcSMatt Macyfunction default_mirror_setup_noexit
470eda14cbcSMatt Macy{
471eda14cbcSMatt Macy	readonly func="default_mirror_setup_noexit"
472eda14cbcSMatt Macy	typeset primary=$1
473eda14cbcSMatt Macy	typeset secondary=$2
474eda14cbcSMatt Macy
475eda14cbcSMatt Macy	[[ -z $primary ]] && \
476eda14cbcSMatt Macy		log_fail "$func: No parameters passed"
477eda14cbcSMatt Macy	[[ -z $secondary ]] && \
478eda14cbcSMatt Macy		log_fail "$func: No secondary partition passed"
479eda14cbcSMatt Macy	[[ -d /$TESTPOOL ]] && rm -rf /$TESTPOOL
480eda14cbcSMatt Macy	log_must zpool create -f $TESTPOOL mirror $@
481eda14cbcSMatt Macy	log_must zfs create $TESTPOOL/$TESTFS
482eda14cbcSMatt Macy	log_must zfs set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
483eda14cbcSMatt Macy}
484eda14cbcSMatt Macy
485eda14cbcSMatt Macy#
486eda14cbcSMatt Macy# Destroy the configured testpool mirrors.
487eda14cbcSMatt Macy# the mirrors are of the form ${TESTPOOL}{number}
488eda14cbcSMatt Macy# @uses: ZPOOL ZFS TESTPOOL
489eda14cbcSMatt Macyfunction destroy_mirrors
490eda14cbcSMatt Macy{
491eda14cbcSMatt Macy	default_cleanup_noexit
492eda14cbcSMatt Macy
493eda14cbcSMatt Macy	log_pass
494eda14cbcSMatt Macy}
495eda14cbcSMatt Macy
496c03c5b1cSMartin Matuskafunction default_raidz_setup
497c03c5b1cSMartin Matuska{
498c03c5b1cSMartin Matuska	default_raidz_setup_noexit "$*"
499c03c5b1cSMartin Matuska
500c03c5b1cSMartin Matuska	log_pass
501c03c5b1cSMartin Matuska}
502c03c5b1cSMartin Matuska
503eda14cbcSMatt Macy#
504eda14cbcSMatt Macy# Given a minimum of two disks, set up a storage pool and dataset for the raid-z
505eda14cbcSMatt Macy# $1 the list of disks
506eda14cbcSMatt Macy#
507c03c5b1cSMartin Matuskafunction default_raidz_setup_noexit
508eda14cbcSMatt Macy{
509eda14cbcSMatt Macy	typeset disklist="$*"
510eda14cbcSMatt Macy	disks=(${disklist[*]})
511eda14cbcSMatt Macy
512eda14cbcSMatt Macy	if [[ ${#disks[*]} -lt 2 ]]; then
513eda14cbcSMatt Macy		log_fail "A raid-z requires a minimum of two disks."
514eda14cbcSMatt Macy	fi
515eda14cbcSMatt Macy
516eda14cbcSMatt Macy	[[ -d /$TESTPOOL ]] && rm -rf /$TESTPOOL
517eda14cbcSMatt Macy	log_must zpool create -f $TESTPOOL raidz $disklist
518eda14cbcSMatt Macy	log_must zfs create $TESTPOOL/$TESTFS
519eda14cbcSMatt Macy	log_must zfs set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
520eda14cbcSMatt Macy}
521eda14cbcSMatt Macy
522eda14cbcSMatt Macy#
523eda14cbcSMatt Macy# Common function used to cleanup storage pools and datasets.
524eda14cbcSMatt Macy#
525eda14cbcSMatt Macy# Invoked at the start of the test suite to ensure the system
526eda14cbcSMatt Macy# is in a known state, and also at the end of each set of
527eda14cbcSMatt Macy# sub-tests to ensure errors from one set of tests doesn't
528eda14cbcSMatt Macy# impact the execution of the next set.
529eda14cbcSMatt Macy
530eda14cbcSMatt Macyfunction default_cleanup
531eda14cbcSMatt Macy{
532eda14cbcSMatt Macy	default_cleanup_noexit
533eda14cbcSMatt Macy
534eda14cbcSMatt Macy	log_pass
535eda14cbcSMatt Macy}
536eda14cbcSMatt Macy
537eda14cbcSMatt Macy#
538eda14cbcSMatt Macy# Utility function used to list all available pool names.
539eda14cbcSMatt Macy#
540eda14cbcSMatt Macy# NOTE: $KEEP is a variable containing pool names, separated by a newline
541eda14cbcSMatt Macy# character, that must be excluded from the returned list.
542eda14cbcSMatt Macy#
543eda14cbcSMatt Macyfunction get_all_pools
544eda14cbcSMatt Macy{
545eda14cbcSMatt Macy	zpool list -H -o name | grep -Fvx "$KEEP" | grep -v "$NO_POOLS"
546eda14cbcSMatt Macy}
547eda14cbcSMatt Macy
548eda14cbcSMatt Macyfunction default_cleanup_noexit
549eda14cbcSMatt Macy{
550eda14cbcSMatt Macy	typeset pool=""
551eda14cbcSMatt Macy	#
552eda14cbcSMatt Macy	# Destroying the pool will also destroy any
553eda14cbcSMatt Macy	# filesystems it contains.
554eda14cbcSMatt Macy	#
555eda14cbcSMatt Macy	if is_global_zone; then
556eda14cbcSMatt Macy		zfs unmount -a > /dev/null 2>&1
557eda14cbcSMatt Macy		ALL_POOLS=$(get_all_pools)
558eda14cbcSMatt Macy		# Here, we loop through the pools we're allowed to
559eda14cbcSMatt Macy		# destroy, only destroying them if it's safe to do
560eda14cbcSMatt Macy		# so.
561eda14cbcSMatt Macy		while [ ! -z ${ALL_POOLS} ]
562eda14cbcSMatt Macy		do
563eda14cbcSMatt Macy			for pool in ${ALL_POOLS}
564eda14cbcSMatt Macy			do
565eda14cbcSMatt Macy				if safe_to_destroy_pool $pool ;
566eda14cbcSMatt Macy				then
567eda14cbcSMatt Macy					destroy_pool $pool
568eda14cbcSMatt Macy				fi
569eda14cbcSMatt Macy			done
570eda14cbcSMatt Macy			ALL_POOLS=$(get_all_pools)
571eda14cbcSMatt Macy		done
572eda14cbcSMatt Macy
573eda14cbcSMatt Macy		zfs mount -a
574eda14cbcSMatt Macy	else
575eda14cbcSMatt Macy		typeset fs=""
576eda14cbcSMatt Macy		for fs in $(zfs list -H -o name \
577eda14cbcSMatt Macy		    | grep "^$ZONE_POOL/$ZONE_CTR[01234]/"); do
578eda14cbcSMatt Macy			destroy_dataset "$fs" "-Rf"
579eda14cbcSMatt Macy		done
580eda14cbcSMatt Macy
581eda14cbcSMatt Macy		# Need cleanup here to avoid garbage dir left.
582eda14cbcSMatt Macy		for fs in $(zfs list -H -o name); do
583eda14cbcSMatt Macy			[[ $fs == /$ZONE_POOL ]] && continue
584eda14cbcSMatt Macy			[[ -d $fs ]] && log_must rm -rf $fs/*
585eda14cbcSMatt Macy		done
586eda14cbcSMatt Macy
587eda14cbcSMatt Macy		#
588eda14cbcSMatt Macy		# Reset the $ZONE_POOL/$ZONE_CTR[01234] file systems property to
589eda14cbcSMatt Macy		# the default value
590eda14cbcSMatt Macy		#
591eda14cbcSMatt Macy		for fs in $(zfs list -H -o name); do
592eda14cbcSMatt Macy			if [[ $fs == $ZONE_POOL/$ZONE_CTR[01234] ]]; then
593eda14cbcSMatt Macy				log_must zfs set reservation=none $fs
594eda14cbcSMatt Macy				log_must zfs set recordsize=128K $fs
595eda14cbcSMatt Macy				log_must zfs set mountpoint=/$fs $fs
596716fd348SMartin Matuska				typeset enc=$(get_prop encryption $fs)
597716fd348SMartin Matuska				if [ -z "$enc" ] || [ "$enc" = "off" ]; then
598eda14cbcSMatt Macy					log_must zfs set checksum=on $fs
599eda14cbcSMatt Macy				fi
600eda14cbcSMatt Macy				log_must zfs set compression=off $fs
601eda14cbcSMatt Macy				log_must zfs set atime=on $fs
602eda14cbcSMatt Macy				log_must zfs set devices=off $fs
603eda14cbcSMatt Macy				log_must zfs set exec=on $fs
604eda14cbcSMatt Macy				log_must zfs set setuid=on $fs
605eda14cbcSMatt Macy				log_must zfs set readonly=off $fs
606eda14cbcSMatt Macy				log_must zfs set snapdir=hidden $fs
607eda14cbcSMatt Macy				log_must zfs set aclmode=groupmask $fs
608eda14cbcSMatt Macy				log_must zfs set aclinherit=secure $fs
609eda14cbcSMatt Macy			fi
610eda14cbcSMatt Macy		done
611eda14cbcSMatt Macy	fi
612eda14cbcSMatt Macy
613eda14cbcSMatt Macy	[[ -d $TESTDIR ]] && \
614eda14cbcSMatt Macy		log_must rm -rf $TESTDIR
615eda14cbcSMatt Macy
616eda14cbcSMatt Macy	disk1=${DISKS%% *}
617eda14cbcSMatt Macy	if is_mpath_device $disk1; then
618eda14cbcSMatt Macy		delete_partitions
619eda14cbcSMatt Macy	fi
620eda14cbcSMatt Macy
621eda14cbcSMatt Macy	rm -f $TEST_BASE_DIR/{err,out}
622eda14cbcSMatt Macy}
623eda14cbcSMatt Macy
624eda14cbcSMatt Macy
625eda14cbcSMatt Macy#
626eda14cbcSMatt Macy# Common function used to cleanup storage pools, file systems
627eda14cbcSMatt Macy# and containers.
628eda14cbcSMatt Macy#
629eda14cbcSMatt Macyfunction default_container_cleanup
630eda14cbcSMatt Macy{
631eda14cbcSMatt Macy	if ! is_global_zone; then
632eda14cbcSMatt Macy		reexport_pool
633eda14cbcSMatt Macy	fi
634eda14cbcSMatt Macy
635716fd348SMartin Matuska	ismounted $TESTPOOL/$TESTCTR/$TESTFS1 &&
636eda14cbcSMatt Macy	    log_must zfs unmount $TESTPOOL/$TESTCTR/$TESTFS1
637eda14cbcSMatt Macy
638eda14cbcSMatt Macy	destroy_dataset "$TESTPOOL/$TESTCTR/$TESTFS1" "-R"
639eda14cbcSMatt Macy	destroy_dataset "$TESTPOOL/$TESTCTR" "-Rf"
640eda14cbcSMatt Macy
641eda14cbcSMatt Macy	[[ -e $TESTDIR1 ]] && \
642716fd348SMartin Matuska	    log_must rm -rf $TESTDIR1
643eda14cbcSMatt Macy
644eda14cbcSMatt Macy	default_cleanup
645eda14cbcSMatt Macy}
646eda14cbcSMatt Macy
647eda14cbcSMatt Macy#
648eda14cbcSMatt Macy# Common function used to cleanup snapshot of file system or volume. Default to
649eda14cbcSMatt Macy# delete the file system's snapshot
650eda14cbcSMatt Macy#
651eda14cbcSMatt Macy# $1 snapshot name
652eda14cbcSMatt Macy#
653eda14cbcSMatt Macyfunction destroy_snapshot
654eda14cbcSMatt Macy{
655eda14cbcSMatt Macy	typeset snap=${1:-$TESTPOOL/$TESTFS@$TESTSNAP}
656eda14cbcSMatt Macy
657eda14cbcSMatt Macy	if ! snapexists $snap; then
658eda14cbcSMatt Macy		log_fail "'$snap' does not exist."
659eda14cbcSMatt Macy	fi
660eda14cbcSMatt Macy
661eda14cbcSMatt Macy	#
662eda14cbcSMatt Macy	# For the sake of the value which come from 'get_prop' is not equal
663eda14cbcSMatt Macy	# to the really mountpoint when the snapshot is unmounted. So, firstly
664eda14cbcSMatt Macy	# check and make sure this snapshot's been mounted in current system.
665eda14cbcSMatt Macy	#
666eda14cbcSMatt Macy	typeset mtpt=""
667eda14cbcSMatt Macy	if ismounted $snap; then
668eda14cbcSMatt Macy		mtpt=$(get_prop mountpoint $snap)
669eda14cbcSMatt Macy	fi
670eda14cbcSMatt Macy
671eda14cbcSMatt Macy	destroy_dataset "$snap"
672eda14cbcSMatt Macy	[[ $mtpt != "" && -d $mtpt ]] && \
673eda14cbcSMatt Macy		log_must rm -rf $mtpt
674eda14cbcSMatt Macy}
675eda14cbcSMatt Macy
676eda14cbcSMatt Macy#
677eda14cbcSMatt Macy# Common function used to cleanup clone.
678eda14cbcSMatt Macy#
679eda14cbcSMatt Macy# $1 clone name
680eda14cbcSMatt Macy#
681eda14cbcSMatt Macyfunction destroy_clone
682eda14cbcSMatt Macy{
683eda14cbcSMatt Macy	typeset clone=${1:-$TESTPOOL/$TESTCLONE}
684eda14cbcSMatt Macy
685eda14cbcSMatt Macy	if ! datasetexists $clone; then
686eda14cbcSMatt Macy		log_fail "'$clone' does not existed."
687eda14cbcSMatt Macy	fi
688eda14cbcSMatt Macy
689eda14cbcSMatt Macy	# With the same reason in destroy_snapshot
690eda14cbcSMatt Macy	typeset mtpt=""
691eda14cbcSMatt Macy	if ismounted $clone; then
692eda14cbcSMatt Macy		mtpt=$(get_prop mountpoint $clone)
693eda14cbcSMatt Macy	fi
694eda14cbcSMatt Macy
695eda14cbcSMatt Macy	destroy_dataset "$clone"
696eda14cbcSMatt Macy	[[ $mtpt != "" && -d $mtpt ]] && \
697eda14cbcSMatt Macy		log_must rm -rf $mtpt
698eda14cbcSMatt Macy}
699eda14cbcSMatt Macy
700eda14cbcSMatt Macy#
701eda14cbcSMatt Macy# Common function used to cleanup bookmark of file system or volume.  Default
702eda14cbcSMatt Macy# to delete the file system's bookmark.
703eda14cbcSMatt Macy#
704eda14cbcSMatt Macy# $1 bookmark name
705eda14cbcSMatt Macy#
706eda14cbcSMatt Macyfunction destroy_bookmark
707eda14cbcSMatt Macy{
708eda14cbcSMatt Macy	typeset bkmark=${1:-$TESTPOOL/$TESTFS#$TESTBKMARK}
709eda14cbcSMatt Macy
710eda14cbcSMatt Macy	if ! bkmarkexists $bkmark; then
711eda14cbcSMatt Macy		log_fail "'$bkmarkp' does not existed."
712eda14cbcSMatt Macy	fi
713eda14cbcSMatt Macy
714eda14cbcSMatt Macy	destroy_dataset "$bkmark"
715eda14cbcSMatt Macy}
716eda14cbcSMatt Macy
717eda14cbcSMatt Macy# Return 0 if a snapshot exists; $? otherwise
718eda14cbcSMatt Macy#
719eda14cbcSMatt Macy# $1 - snapshot name
720eda14cbcSMatt Macy
721eda14cbcSMatt Macyfunction snapexists
722eda14cbcSMatt Macy{
723eda14cbcSMatt Macy	zfs list -H -t snapshot "$1" > /dev/null 2>&1
724eda14cbcSMatt Macy}
725eda14cbcSMatt Macy
726eda14cbcSMatt Macy#
727eda14cbcSMatt Macy# Return 0 if a bookmark exists; $? otherwise
728eda14cbcSMatt Macy#
729eda14cbcSMatt Macy# $1 - bookmark name
730eda14cbcSMatt Macy#
731eda14cbcSMatt Macyfunction bkmarkexists
732eda14cbcSMatt Macy{
733eda14cbcSMatt Macy	zfs list -H -t bookmark "$1" > /dev/null 2>&1
734eda14cbcSMatt Macy}
735eda14cbcSMatt Macy
736eda14cbcSMatt Macy#
737eda14cbcSMatt Macy# Return 0 if a hold exists; $? otherwise
738eda14cbcSMatt Macy#
739eda14cbcSMatt Macy# $1 - hold tag
740eda14cbcSMatt Macy# $2 - snapshot name
741eda14cbcSMatt Macy#
742eda14cbcSMatt Macyfunction holdexists
743eda14cbcSMatt Macy{
744716fd348SMartin Matuska	! zfs holds "$2" | awk -v t="$1" '$2 ~ t { exit 1 }'
745eda14cbcSMatt Macy}
746eda14cbcSMatt Macy
747eda14cbcSMatt Macy#
748eda14cbcSMatt Macy# Set a property to a certain value on a dataset.
749eda14cbcSMatt Macy# Sets a property of the dataset to the value as passed in.
750eda14cbcSMatt Macy# @param:
751eda14cbcSMatt Macy#	$1 dataset who's property is being set
752eda14cbcSMatt Macy#	$2 property to set
753eda14cbcSMatt Macy#	$3 value to set property to
754eda14cbcSMatt Macy# @return:
755eda14cbcSMatt Macy#	0 if the property could be set.
756eda14cbcSMatt Macy#	non-zero otherwise.
757eda14cbcSMatt Macy# @use: ZFS
758eda14cbcSMatt Macy#
759eda14cbcSMatt Macyfunction dataset_setprop
760eda14cbcSMatt Macy{
761eda14cbcSMatt Macy	typeset fn=dataset_setprop
762eda14cbcSMatt Macy
763eda14cbcSMatt Macy	if (($# < 3)); then
764eda14cbcSMatt Macy		log_note "$fn: Insufficient parameters (need 3, had $#)"
765eda14cbcSMatt Macy		return 1
766eda14cbcSMatt Macy	fi
767eda14cbcSMatt Macy	typeset output=
768eda14cbcSMatt Macy	output=$(zfs set $2=$3 $1 2>&1)
769eda14cbcSMatt Macy	typeset rv=$?
770eda14cbcSMatt Macy	if ((rv != 0)); then
771eda14cbcSMatt Macy		log_note "Setting property on $1 failed."
772eda14cbcSMatt Macy		log_note "property $2=$3"
773eda14cbcSMatt Macy		log_note "Return Code: $rv"
774eda14cbcSMatt Macy		log_note "Output: $output"
775eda14cbcSMatt Macy		return $rv
776eda14cbcSMatt Macy	fi
777eda14cbcSMatt Macy	return 0
778eda14cbcSMatt Macy}
779eda14cbcSMatt Macy
780eda14cbcSMatt Macy#
781eda14cbcSMatt Macy# Check a numeric assertion
782eda14cbcSMatt Macy# @parameter: $@ the assertion to check
783eda14cbcSMatt Macy# @output: big loud notice if assertion failed
784eda14cbcSMatt Macy# @use: log_fail
785eda14cbcSMatt Macy#
786eda14cbcSMatt Macyfunction assert
787eda14cbcSMatt Macy{
788eda14cbcSMatt Macy	(($@)) || log_fail "$@"
789eda14cbcSMatt Macy}
790eda14cbcSMatt Macy
791eda14cbcSMatt Macy#
792eda14cbcSMatt Macy# Function to format partition size of a disk
793eda14cbcSMatt Macy# Given a disk cxtxdx reduces all partitions
794eda14cbcSMatt Macy# to 0 size
795eda14cbcSMatt Macy#
796eda14cbcSMatt Macyfunction zero_partitions #<whole_disk_name>
797eda14cbcSMatt Macy{
798eda14cbcSMatt Macy	typeset diskname=$1
799eda14cbcSMatt Macy	typeset i
800eda14cbcSMatt Macy
801eda14cbcSMatt Macy	if is_freebsd; then
802eda14cbcSMatt Macy		gpart destroy -F $diskname
803eda14cbcSMatt Macy	elif is_linux; then
804eda14cbcSMatt Macy		DSK=$DEV_DSKDIR/$diskname
805eda14cbcSMatt Macy		DSK=$(echo $DSK | sed -e "s|//|/|g")
806eda14cbcSMatt Macy		log_must parted $DSK -s -- mklabel gpt
807eda14cbcSMatt Macy		blockdev --rereadpt $DSK 2>/dev/null
808eda14cbcSMatt Macy		block_device_wait
809eda14cbcSMatt Macy	else
810eda14cbcSMatt Macy		for i in 0 1 3 4 5 6 7
811eda14cbcSMatt Macy		do
812eda14cbcSMatt Macy			log_must set_partition $i "" 0mb $diskname
813eda14cbcSMatt Macy		done
814eda14cbcSMatt Macy	fi
815eda14cbcSMatt Macy
816eda14cbcSMatt Macy	return 0
817eda14cbcSMatt Macy}
818eda14cbcSMatt Macy
819eda14cbcSMatt Macy#
820eda14cbcSMatt Macy# Given a slice, size and disk, this function
821eda14cbcSMatt Macy# formats the slice to the specified size.
822eda14cbcSMatt Macy# Size should be specified with units as per
823eda14cbcSMatt Macy# the `format` command requirements eg. 100mb 3gb
824eda14cbcSMatt Macy#
825eda14cbcSMatt Macy# NOTE: This entire interface is problematic for the Linux parted utility
826eda14cbcSMatt Macy# which requires the end of the partition to be specified.  It would be
827eda14cbcSMatt Macy# best to retire this interface and replace it with something more flexible.
828eda14cbcSMatt Macy# At the moment a best effort is made.
829eda14cbcSMatt Macy#
830eda14cbcSMatt Macy# arguments: <slice_num> <slice_start> <size_plus_units>  <whole_disk_name>
831eda14cbcSMatt Macyfunction set_partition
832eda14cbcSMatt Macy{
833eda14cbcSMatt Macy	typeset -i slicenum=$1
834eda14cbcSMatt Macy	typeset start=$2
835eda14cbcSMatt Macy	typeset size=$3
836eda14cbcSMatt Macy	typeset disk=${4#$DEV_DSKDIR/}
837eda14cbcSMatt Macy	disk=${disk#$DEV_RDSKDIR/}
838eda14cbcSMatt Macy
839716fd348SMartin Matuska	case "$UNAME" in
840eda14cbcSMatt Macy	Linux)
841eda14cbcSMatt Macy		if [[ -z $size || -z $disk ]]; then
842eda14cbcSMatt Macy			log_fail "The size or disk name is unspecified."
843eda14cbcSMatt Macy		fi
844eda14cbcSMatt Macy		disk=$DEV_DSKDIR/$disk
845eda14cbcSMatt Macy		typeset size_mb=${size%%[mMgG]}
846eda14cbcSMatt Macy
847eda14cbcSMatt Macy		size_mb=${size_mb%%[mMgG][bB]}
848eda14cbcSMatt Macy		if [[ ${size:1:1} == 'g' ]]; then
849eda14cbcSMatt Macy			((size_mb = size_mb * 1024))
850eda14cbcSMatt Macy		fi
851eda14cbcSMatt Macy
852eda14cbcSMatt Macy		# Create GPT partition table when setting slice 0 or
853eda14cbcSMatt Macy		# when the device doesn't already contain a GPT label.
854eda14cbcSMatt Macy		parted $disk -s -- print 1 >/dev/null
855eda14cbcSMatt Macy		typeset ret_val=$?
856eda14cbcSMatt Macy		if [[ $slicenum -eq 0 || $ret_val -ne 0 ]]; then
857716fd348SMartin Matuska			if ! parted $disk -s -- mklabel gpt; then
858eda14cbcSMatt Macy				log_note "Failed to create GPT partition table on $disk"
859eda14cbcSMatt Macy				return 1
860eda14cbcSMatt Macy			fi
861eda14cbcSMatt Macy		fi
862eda14cbcSMatt Macy
863eda14cbcSMatt Macy		# When no start is given align on the first cylinder.
864eda14cbcSMatt Macy		if [[ -z "$start" ]]; then
865eda14cbcSMatt Macy			start=1
866eda14cbcSMatt Macy		fi
867eda14cbcSMatt Macy
868eda14cbcSMatt Macy		# Determine the cylinder size for the device and using
869eda14cbcSMatt Macy		# that calculate the end offset in cylinders.
870eda14cbcSMatt Macy		typeset -i cly_size_kb=0
871716fd348SMartin Matuska		cly_size_kb=$(parted -m $disk -s -- unit cyl print |
872716fd348SMartin Matuska			awk -F '[:k.]' 'NR == 3 {print $4}')
873eda14cbcSMatt Macy		((end = (size_mb * 1024 / cly_size_kb) + start))
874eda14cbcSMatt Macy
875eda14cbcSMatt Macy		parted $disk -s -- \
876eda14cbcSMatt Macy		    mkpart part$slicenum ${start}cyl ${end}cyl
877eda14cbcSMatt Macy		typeset ret_val=$?
878eda14cbcSMatt Macy		if [[ $ret_val -ne 0 ]]; then
879eda14cbcSMatt Macy			log_note "Failed to create partition $slicenum on $disk"
880eda14cbcSMatt Macy			return 1
881eda14cbcSMatt Macy		fi
882eda14cbcSMatt Macy
883eda14cbcSMatt Macy		blockdev --rereadpt $disk 2>/dev/null
884eda14cbcSMatt Macy		block_device_wait $disk
885eda14cbcSMatt Macy		;;
886eda14cbcSMatt Macy	FreeBSD)
887eda14cbcSMatt Macy		if [[ -z $size || -z $disk ]]; then
888eda14cbcSMatt Macy			log_fail "The size or disk name is unspecified."
889eda14cbcSMatt Macy		fi
890eda14cbcSMatt Macy		disk=$DEV_DSKDIR/$disk
891eda14cbcSMatt Macy
892eda14cbcSMatt Macy		if [[ $slicenum -eq 0 ]] || ! gpart show $disk >/dev/null 2>&1; then
893eda14cbcSMatt Macy			gpart destroy -F $disk >/dev/null 2>&1
894716fd348SMartin Matuska			if ! gpart create -s GPT $disk; then
895eda14cbcSMatt Macy				log_note "Failed to create GPT partition table on $disk"
896eda14cbcSMatt Macy				return 1
897eda14cbcSMatt Macy			fi
898eda14cbcSMatt Macy		fi
899eda14cbcSMatt Macy
900eda14cbcSMatt Macy		typeset index=$((slicenum + 1))
901eda14cbcSMatt Macy
902eda14cbcSMatt Macy		if [[ -n $start ]]; then
903eda14cbcSMatt Macy			start="-b $start"
904eda14cbcSMatt Macy		fi
905eda14cbcSMatt Macy		gpart add -t freebsd-zfs $start -s $size -i $index $disk
906eda14cbcSMatt Macy		if [[ $ret_val -ne 0 ]]; then
907eda14cbcSMatt Macy			log_note "Failed to create partition $slicenum on $disk"
908eda14cbcSMatt Macy			return 1
909eda14cbcSMatt Macy		fi
910eda14cbcSMatt Macy
911eda14cbcSMatt Macy		block_device_wait $disk
912eda14cbcSMatt Macy		;;
913eda14cbcSMatt Macy	*)
914eda14cbcSMatt Macy		if [[ -z $slicenum || -z $size || -z $disk ]]; then
915eda14cbcSMatt Macy			log_fail "The slice, size or disk name is unspecified."
916eda14cbcSMatt Macy		fi
917eda14cbcSMatt Macy
918eda14cbcSMatt Macy		typeset format_file=/var/tmp/format_in.$$
919eda14cbcSMatt Macy
920eda14cbcSMatt Macy		echo "partition" >$format_file
921eda14cbcSMatt Macy		echo "$slicenum" >> $format_file
922eda14cbcSMatt Macy		echo "" >> $format_file
923eda14cbcSMatt Macy		echo "" >> $format_file
924eda14cbcSMatt Macy		echo "$start" >> $format_file
925eda14cbcSMatt Macy		echo "$size" >> $format_file
926eda14cbcSMatt Macy		echo "label" >> $format_file
927eda14cbcSMatt Macy		echo "" >> $format_file
928eda14cbcSMatt Macy		echo "q" >> $format_file
929eda14cbcSMatt Macy		echo "q" >> $format_file
930eda14cbcSMatt Macy
931eda14cbcSMatt Macy		format -e -s -d $disk -f $format_file
932eda14cbcSMatt Macy		typeset ret_val=$?
933eda14cbcSMatt Macy		rm -f $format_file
934eda14cbcSMatt Macy		;;
935eda14cbcSMatt Macy	esac
936eda14cbcSMatt Macy
937eda14cbcSMatt Macy	if [[ $ret_val -ne 0 ]]; then
938eda14cbcSMatt Macy		log_note "Unable to format $disk slice $slicenum to $size"
939eda14cbcSMatt Macy		return 1
940eda14cbcSMatt Macy	fi
941eda14cbcSMatt Macy	return 0
942eda14cbcSMatt Macy}
943eda14cbcSMatt Macy
944eda14cbcSMatt Macy#
945eda14cbcSMatt Macy# Delete all partitions on all disks - this is specifically for the use of multipath
946eda14cbcSMatt Macy# devices which currently can only be used in the test suite as raw/un-partitioned
947eda14cbcSMatt Macy# devices (ie a zpool cannot be created on a whole mpath device that has partitions)
948eda14cbcSMatt Macy#
949eda14cbcSMatt Macyfunction delete_partitions
950eda14cbcSMatt Macy{
951eda14cbcSMatt Macy	typeset disk
952eda14cbcSMatt Macy
953eda14cbcSMatt Macy	if [[ -z $DISKSARRAY ]]; then
954eda14cbcSMatt Macy		DISKSARRAY=$DISKS
955eda14cbcSMatt Macy	fi
956eda14cbcSMatt Macy
957eda14cbcSMatt Macy	if is_linux; then
958eda14cbcSMatt Macy		typeset -i part
959eda14cbcSMatt Macy		for disk in $DISKSARRAY; do
960eda14cbcSMatt Macy			for (( part = 1; part < MAX_PARTITIONS; part++ )); do
961eda14cbcSMatt Macy				typeset partition=${disk}${SLICE_PREFIX}${part}
962eda14cbcSMatt Macy				parted $DEV_DSKDIR/$disk -s rm $part > /dev/null 2>&1
963eda14cbcSMatt Macy				if lsblk | grep -qF ${partition}; then
964eda14cbcSMatt Macy					log_fail "Partition ${partition} not deleted"
965eda14cbcSMatt Macy				else
966eda14cbcSMatt Macy					log_note "Partition ${partition} deleted"
967eda14cbcSMatt Macy				fi
968eda14cbcSMatt Macy			done
969eda14cbcSMatt Macy		done
970eda14cbcSMatt Macy	elif is_freebsd; then
971eda14cbcSMatt Macy		for disk in $DISKSARRAY; do
972eda14cbcSMatt Macy			if gpart destroy -F $disk; then
973eda14cbcSMatt Macy				log_note "Partitions for ${disk} deleted"
974eda14cbcSMatt Macy			else
975eda14cbcSMatt Macy				log_fail "Partitions for ${disk} not deleted"
976eda14cbcSMatt Macy			fi
977eda14cbcSMatt Macy		done
978eda14cbcSMatt Macy	fi
979eda14cbcSMatt Macy}
980eda14cbcSMatt Macy
981eda14cbcSMatt Macy#
982eda14cbcSMatt Macy# Get the end cyl of the given slice
983eda14cbcSMatt Macy#
984eda14cbcSMatt Macyfunction get_endslice #<disk> <slice>
985eda14cbcSMatt Macy{
986eda14cbcSMatt Macy	typeset disk=$1
987eda14cbcSMatt Macy	typeset slice=$2
988eda14cbcSMatt Macy	if [[ -z $disk || -z $slice ]] ; then
989eda14cbcSMatt Macy		log_fail "The disk name or slice number is unspecified."
990eda14cbcSMatt Macy	fi
991eda14cbcSMatt Macy
992716fd348SMartin Matuska	case "$UNAME" in
993eda14cbcSMatt Macy	Linux)
994eda14cbcSMatt Macy		endcyl=$(parted -s $DEV_DSKDIR/$disk -- unit cyl print | \
995dae17134SMartin Matuska			awk "/part${slice}/"' {sub(/cyl/, "", $3); print $3}')
996eda14cbcSMatt Macy		((endcyl = (endcyl + 1)))
997eda14cbcSMatt Macy		;;
998eda14cbcSMatt Macy	FreeBSD)
999eda14cbcSMatt Macy		disk=${disk#/dev/zvol/}
1000eda14cbcSMatt Macy		disk=${disk%p*}
1001eda14cbcSMatt Macy		slice=$((slice + 1))
1002eda14cbcSMatt Macy		endcyl=$(gpart show $disk | \
1003eda14cbcSMatt Macy			awk -v slice=$slice '$3 == slice { print $1 + $2 }')
1004eda14cbcSMatt Macy		;;
1005eda14cbcSMatt Macy	*)
1006eda14cbcSMatt Macy		disk=${disk#/dev/dsk/}
1007eda14cbcSMatt Macy		disk=${disk#/dev/rdsk/}
1008eda14cbcSMatt Macy		disk=${disk%s*}
1009eda14cbcSMatt Macy
1010eda14cbcSMatt Macy		typeset -i ratio=0
1011eda14cbcSMatt Macy		ratio=$(prtvtoc /dev/rdsk/${disk}s2 | \
1012716fd348SMartin Matuska		    awk '/sectors\/cylinder/ {print $2}')
1013eda14cbcSMatt Macy
1014eda14cbcSMatt Macy		if ((ratio == 0)); then
1015eda14cbcSMatt Macy			return
1016eda14cbcSMatt Macy		fi
1017eda14cbcSMatt Macy
1018eda14cbcSMatt Macy		typeset -i endcyl=$(prtvtoc -h /dev/rdsk/${disk}s2 |
1019716fd348SMartin Matuska		    awk -v token="$slice" '$1 == token {print $6}')
1020eda14cbcSMatt Macy
1021eda14cbcSMatt Macy		((endcyl = (endcyl + 1) / ratio))
1022eda14cbcSMatt Macy		;;
1023eda14cbcSMatt Macy	esac
1024eda14cbcSMatt Macy
1025eda14cbcSMatt Macy	echo $endcyl
1026eda14cbcSMatt Macy}
1027eda14cbcSMatt Macy
1028eda14cbcSMatt Macy
1029eda14cbcSMatt Macy#
1030eda14cbcSMatt Macy# Given a size,disk and total slice number,  this function formats the
1031eda14cbcSMatt Macy# disk slices from 0 to the total slice number with the same specified
1032eda14cbcSMatt Macy# size.
1033eda14cbcSMatt Macy#
1034eda14cbcSMatt Macyfunction partition_disk	#<slice_size> <whole_disk_name>	<total_slices>
1035eda14cbcSMatt Macy{
1036eda14cbcSMatt Macy	typeset -i i=0
1037eda14cbcSMatt Macy	typeset slice_size=$1
1038eda14cbcSMatt Macy	typeset disk_name=$2
1039eda14cbcSMatt Macy	typeset total_slices=$3
1040eda14cbcSMatt Macy	typeset cyl
1041eda14cbcSMatt Macy
1042eda14cbcSMatt Macy	zero_partitions $disk_name
1043eda14cbcSMatt Macy	while ((i < $total_slices)); do
1044eda14cbcSMatt Macy		if ! is_linux; then
1045eda14cbcSMatt Macy			if ((i == 2)); then
1046eda14cbcSMatt Macy				((i = i + 1))
1047eda14cbcSMatt Macy				continue
1048eda14cbcSMatt Macy			fi
1049eda14cbcSMatt Macy		fi
1050eda14cbcSMatt Macy		log_must set_partition $i "$cyl" $slice_size $disk_name
1051eda14cbcSMatt Macy		cyl=$(get_endslice $disk_name $i)
1052eda14cbcSMatt Macy		((i = i+1))
1053eda14cbcSMatt Macy	done
1054eda14cbcSMatt Macy}
1055eda14cbcSMatt Macy
1056eda14cbcSMatt Macy#
1057eda14cbcSMatt Macy# This function continues to write to a filenum number of files into dirnum
1058eda14cbcSMatt Macy# number of directories until either file_write returns an error or the
1059eda14cbcSMatt Macy# maximum number of files per directory have been written.
1060eda14cbcSMatt Macy#
1061eda14cbcSMatt Macy# Usage:
1062eda14cbcSMatt Macy# fill_fs [destdir] [dirnum] [filenum] [bytes] [num_writes] [data]
1063eda14cbcSMatt Macy#
1064eda14cbcSMatt Macy# Return value: 0 on success
1065eda14cbcSMatt Macy#		non 0 on error
1066eda14cbcSMatt Macy#
1067eda14cbcSMatt Macy# Where :
1068eda14cbcSMatt Macy#	destdir:    is the directory where everything is to be created under
1069eda14cbcSMatt Macy#	dirnum:	    the maximum number of subdirectories to use, -1 no limit
1070eda14cbcSMatt Macy#	filenum:    the maximum number of files per subdirectory
1071eda14cbcSMatt Macy#	bytes:	    number of bytes to write
1072eda14cbcSMatt Macy#	num_writes: number of types to write out bytes
1073eda14cbcSMatt Macy#	data:	    the data that will be written
1074eda14cbcSMatt Macy#
1075eda14cbcSMatt Macy#	E.g.
1076eda14cbcSMatt Macy#	fill_fs /testdir 20 25 1024 256 0
1077eda14cbcSMatt Macy#
1078eda14cbcSMatt Macy# Note: bytes * num_writes equals the size of the testfile
1079eda14cbcSMatt Macy#
1080eda14cbcSMatt Macyfunction fill_fs # destdir dirnum filenum bytes num_writes data
1081eda14cbcSMatt Macy{
1082eda14cbcSMatt Macy	typeset destdir=${1:-$TESTDIR}
1083eda14cbcSMatt Macy	typeset -i dirnum=${2:-50}
1084eda14cbcSMatt Macy	typeset -i filenum=${3:-50}
1085eda14cbcSMatt Macy	typeset -i bytes=${4:-8192}
1086eda14cbcSMatt Macy	typeset -i num_writes=${5:-10240}
1087eda14cbcSMatt Macy	typeset data=${6:-0}
1088eda14cbcSMatt Macy
1089eda14cbcSMatt Macy	mkdir -p $destdir/{1..$dirnum}
1090eda14cbcSMatt Macy	for f in $destdir/{1..$dirnum}/$TESTFILE{1..$filenum}; do
1091eda14cbcSMatt Macy		file_write -o create -f $f -b $bytes -c $num_writes -d $data \
1092716fd348SMartin Matuska		|| return
1093eda14cbcSMatt Macy	done
1094eda14cbcSMatt Macy}
1095eda14cbcSMatt Macy
1096716fd348SMartin Matuska# Get the specified dataset property in parsable format or fail
1097eda14cbcSMatt Macyfunction get_prop # property dataset
1098eda14cbcSMatt Macy{
1099eda14cbcSMatt Macy	typeset prop=$1
1100eda14cbcSMatt Macy	typeset dataset=$2
1101eda14cbcSMatt Macy
1102716fd348SMartin Matuska	zfs get -Hpo value "$prop" "$dataset" || log_fail "zfs get $prop $dataset"
1103eda14cbcSMatt Macy}
1104eda14cbcSMatt Macy
1105716fd348SMartin Matuska# Get the specified pool property in parsable format or fail
1106eda14cbcSMatt Macyfunction get_pool_prop # property pool
1107eda14cbcSMatt Macy{
1108eda14cbcSMatt Macy	typeset prop=$1
1109eda14cbcSMatt Macy	typeset pool=$2
1110eda14cbcSMatt Macy
1111716fd348SMartin Matuska	zpool get -Hpo value "$prop" "$pool" || log_fail "zpool get $prop $pool"
1112eda14cbcSMatt Macy}
1113eda14cbcSMatt Macy
1114eda14cbcSMatt Macy# Return 0 if a pool exists; $? otherwise
1115eda14cbcSMatt Macy#
1116eda14cbcSMatt Macy# $1 - pool name
1117eda14cbcSMatt Macy
1118eda14cbcSMatt Macyfunction poolexists
1119eda14cbcSMatt Macy{
1120eda14cbcSMatt Macy	typeset pool=$1
1121eda14cbcSMatt Macy
1122eda14cbcSMatt Macy	if [[ -z $pool ]]; then
1123eda14cbcSMatt Macy		log_note "No pool name given."
1124eda14cbcSMatt Macy		return 1
1125eda14cbcSMatt Macy	fi
1126eda14cbcSMatt Macy
1127eda14cbcSMatt Macy	zpool get name "$pool" > /dev/null 2>&1
1128eda14cbcSMatt Macy}
1129eda14cbcSMatt Macy
1130eda14cbcSMatt Macy# Return 0 if all the specified datasets exist; $? otherwise
1131eda14cbcSMatt Macy#
1132eda14cbcSMatt Macy# $1-n  dataset name
1133eda14cbcSMatt Macyfunction datasetexists
1134eda14cbcSMatt Macy{
1135eda14cbcSMatt Macy	if (($# == 0)); then
1136eda14cbcSMatt Macy		log_note "No dataset name given."
1137eda14cbcSMatt Macy		return 1
1138eda14cbcSMatt Macy	fi
1139eda14cbcSMatt Macy
1140716fd348SMartin Matuska	zfs get name "$@" > /dev/null 2>&1
1141eda14cbcSMatt Macy}
1142eda14cbcSMatt Macy
1143eda14cbcSMatt Macy# return 0 if none of the specified datasets exists, otherwise return 1.
1144eda14cbcSMatt Macy#
1145eda14cbcSMatt Macy# $1-n  dataset name
1146eda14cbcSMatt Macyfunction datasetnonexists
1147eda14cbcSMatt Macy{
1148eda14cbcSMatt Macy	if (($# == 0)); then
1149eda14cbcSMatt Macy		log_note "No dataset name given."
1150eda14cbcSMatt Macy		return 1
1151eda14cbcSMatt Macy	fi
1152eda14cbcSMatt Macy
1153eda14cbcSMatt Macy	while (($# > 0)); do
1154eda14cbcSMatt Macy		zfs list -H -t filesystem,snapshot,volume $1 > /dev/null 2>&1 \
1155eda14cbcSMatt Macy		    && return 1
1156eda14cbcSMatt Macy		shift
1157eda14cbcSMatt Macy	done
1158eda14cbcSMatt Macy
1159eda14cbcSMatt Macy	return 0
1160eda14cbcSMatt Macy}
1161eda14cbcSMatt Macy
1162716fd348SMartin Matuska# FreeBSD breaks exports(5) at whitespace and doesn't process escapes
1163716fd348SMartin Matuska# Solaris just breaks
1164716fd348SMartin Matuska#
1165716fd348SMartin Matuska# cf. https://github.com/openzfs/zfs/pull/13165#issuecomment-1059845807
1166716fd348SMartin Matuska#
1167716fd348SMartin Matuska# Linux can have spaces (which are \OOO-escaped),
1168716fd348SMartin Matuska# but can't have backslashes because they're parsed recursively
1169716fd348SMartin Matuskafunction shares_can_have_whitespace
1170716fd348SMartin Matuska{
1171716fd348SMartin Matuska	is_linux
1172716fd348SMartin Matuska}
1173716fd348SMartin Matuska
1174eda14cbcSMatt Macyfunction is_shared_freebsd
1175eda14cbcSMatt Macy{
1176eda14cbcSMatt Macy	typeset fs=$1
1177eda14cbcSMatt Macy
1178716fd348SMartin Matuska	pgrep -q mountd && showmount -E | grep -qx "$fs"
1179eda14cbcSMatt Macy}
1180eda14cbcSMatt Macy
1181eda14cbcSMatt Macyfunction is_shared_illumos
1182eda14cbcSMatt Macy{
1183eda14cbcSMatt Macy	typeset fs=$1
1184eda14cbcSMatt Macy	typeset mtpt
1185eda14cbcSMatt Macy
1186eda14cbcSMatt Macy	for mtpt in `share | awk '{print $2}'` ; do
1187eda14cbcSMatt Macy		if [[ $mtpt == $fs ]] ; then
1188eda14cbcSMatt Macy			return 0
1189eda14cbcSMatt Macy		fi
1190eda14cbcSMatt Macy	done
1191eda14cbcSMatt Macy
1192eda14cbcSMatt Macy	typeset stat=$(svcs -H -o STA nfs/server:default)
1193eda14cbcSMatt Macy	if [[ $stat != "ON" ]]; then
1194eda14cbcSMatt Macy		log_note "Current nfs/server status: $stat"
1195eda14cbcSMatt Macy	fi
1196eda14cbcSMatt Macy
1197eda14cbcSMatt Macy	return 1
1198eda14cbcSMatt Macy}
1199eda14cbcSMatt Macy
1200eda14cbcSMatt Macyfunction is_shared_linux
1201eda14cbcSMatt Macy{
1202eda14cbcSMatt Macy	typeset fs=$1
1203716fd348SMartin Matuska	! exportfs -s | awk -v fs="${fs//\\/\\\\}" '/^\// && $1 == fs {exit 1}'
1204eda14cbcSMatt Macy}
1205eda14cbcSMatt Macy
1206eda14cbcSMatt Macy#
1207eda14cbcSMatt Macy# Given a mountpoint, or a dataset name, determine if it is shared via NFS.
1208eda14cbcSMatt Macy#
1209eda14cbcSMatt Macy# Returns 0 if shared, 1 otherwise.
1210eda14cbcSMatt Macy#
1211eda14cbcSMatt Macyfunction is_shared
1212eda14cbcSMatt Macy{
1213eda14cbcSMatt Macy	typeset fs=$1
1214eda14cbcSMatt Macy	typeset mtpt
1215eda14cbcSMatt Macy
1216eda14cbcSMatt Macy	if [[ $fs != "/"* ]] ; then
1217eda14cbcSMatt Macy		if datasetnonexists "$fs" ; then
1218eda14cbcSMatt Macy			return 1
1219eda14cbcSMatt Macy		else
1220eda14cbcSMatt Macy			mtpt=$(get_prop mountpoint "$fs")
1221716fd348SMartin Matuska			case "$mtpt" in
1222eda14cbcSMatt Macy				none|legacy|-) return 1
1223eda14cbcSMatt Macy					;;
1224eda14cbcSMatt Macy				*)	fs=$mtpt
1225eda14cbcSMatt Macy					;;
1226eda14cbcSMatt Macy			esac
1227eda14cbcSMatt Macy		fi
1228eda14cbcSMatt Macy	fi
1229eda14cbcSMatt Macy
1230716fd348SMartin Matuska	case "$UNAME" in
1231eda14cbcSMatt Macy	FreeBSD)	is_shared_freebsd "$fs"	;;
1232eda14cbcSMatt Macy	Linux)		is_shared_linux "$fs"	;;
1233eda14cbcSMatt Macy	*)		is_shared_illumos "$fs"	;;
1234eda14cbcSMatt Macy	esac
1235eda14cbcSMatt Macy}
1236eda14cbcSMatt Macy
1237eda14cbcSMatt Macyfunction is_exported_illumos
1238eda14cbcSMatt Macy{
1239eda14cbcSMatt Macy	typeset fs=$1
1240716fd348SMartin Matuska	typeset mtpt _
1241eda14cbcSMatt Macy
1242716fd348SMartin Matuska	while read -r mtpt _; do
1243716fd348SMartin Matuska		[ "$mtpt" = "$fs" ] && return
1244716fd348SMartin Matuska	done < /etc/dfs/sharetab
1245eda14cbcSMatt Macy
1246eda14cbcSMatt Macy	return 1
1247eda14cbcSMatt Macy}
1248eda14cbcSMatt Macy
1249eda14cbcSMatt Macyfunction is_exported_freebsd
1250eda14cbcSMatt Macy{
1251eda14cbcSMatt Macy	typeset fs=$1
1252716fd348SMartin Matuska	typeset mtpt _
1253eda14cbcSMatt Macy
1254716fd348SMartin Matuska	while read -r mtpt _; do
1255716fd348SMartin Matuska		[ "$mtpt" = "$fs" ] && return
1256716fd348SMartin Matuska	done < /etc/zfs/exports
1257eda14cbcSMatt Macy
1258eda14cbcSMatt Macy	return 1
1259eda14cbcSMatt Macy}
1260eda14cbcSMatt Macy
1261eda14cbcSMatt Macyfunction is_exported_linux
1262eda14cbcSMatt Macy{
1263eda14cbcSMatt Macy	typeset fs=$1
1264716fd348SMartin Matuska	typeset mtpt _
1265eda14cbcSMatt Macy
1266716fd348SMartin Matuska	while read -r mtpt _; do
1267716fd348SMartin Matuska		[ "$(printf "$mtpt")" = "$fs" ] && return
1268716fd348SMartin Matuska	done < /etc/exports.d/zfs.exports
1269eda14cbcSMatt Macy
1270eda14cbcSMatt Macy	return 1
1271eda14cbcSMatt Macy}
1272eda14cbcSMatt Macy
1273eda14cbcSMatt Macy#
1274eda14cbcSMatt Macy# Given a mountpoint, or a dataset name, determine if it is exported via
1275eda14cbcSMatt Macy# the os-specific NFS exports file.
1276eda14cbcSMatt Macy#
1277eda14cbcSMatt Macy# Returns 0 if exported, 1 otherwise.
1278eda14cbcSMatt Macy#
1279eda14cbcSMatt Macyfunction is_exported
1280eda14cbcSMatt Macy{
1281eda14cbcSMatt Macy	typeset fs=$1
1282eda14cbcSMatt Macy	typeset mtpt
1283eda14cbcSMatt Macy
1284eda14cbcSMatt Macy	if [[ $fs != "/"* ]] ; then
1285eda14cbcSMatt Macy		if datasetnonexists "$fs" ; then
1286eda14cbcSMatt Macy			return 1
1287eda14cbcSMatt Macy		else
1288eda14cbcSMatt Macy			mtpt=$(get_prop mountpoint "$fs")
1289eda14cbcSMatt Macy			case $mtpt in
1290eda14cbcSMatt Macy				none|legacy|-) return 1
1291eda14cbcSMatt Macy					;;
1292eda14cbcSMatt Macy				*)	fs=$mtpt
1293eda14cbcSMatt Macy					;;
1294eda14cbcSMatt Macy			esac
1295eda14cbcSMatt Macy		fi
1296eda14cbcSMatt Macy	fi
1297eda14cbcSMatt Macy
1298716fd348SMartin Matuska	case "$UNAME" in
1299eda14cbcSMatt Macy	FreeBSD)	is_exported_freebsd "$fs"	;;
1300eda14cbcSMatt Macy	Linux)		is_exported_linux "$fs"	;;
1301eda14cbcSMatt Macy	*)		is_exported_illumos "$fs"	;;
1302eda14cbcSMatt Macy	esac
1303eda14cbcSMatt Macy}
1304eda14cbcSMatt Macy
1305eda14cbcSMatt Macy#
1306eda14cbcSMatt Macy# Given a dataset name determine if it is shared via SMB.
1307eda14cbcSMatt Macy#
1308eda14cbcSMatt Macy# Returns 0 if shared, 1 otherwise.
1309eda14cbcSMatt Macy#
1310eda14cbcSMatt Macyfunction is_shared_smb
1311eda14cbcSMatt Macy{
1312eda14cbcSMatt Macy	typeset fs=$1
1313eda14cbcSMatt Macy
1314716fd348SMartin Matuska	datasetexists "$fs" || return
1315eda14cbcSMatt Macy
1316eda14cbcSMatt Macy	if is_linux; then
1317c7046f76SMartin Matuska		net usershare list | grep -xFq "${fs//[-\/]/_}"
1318eda14cbcSMatt Macy	else
1319716fd348SMartin Matuska		log_note "SMB on $UNAME currently unsupported by the test framework"
1320eda14cbcSMatt Macy		return 1
1321eda14cbcSMatt Macy	fi
1322eda14cbcSMatt Macy}
1323eda14cbcSMatt Macy
1324eda14cbcSMatt Macy#
1325eda14cbcSMatt Macy# Given a mountpoint, determine if it is not shared via NFS.
1326eda14cbcSMatt Macy#
1327eda14cbcSMatt Macy# Returns 0 if not shared, 1 otherwise.
1328eda14cbcSMatt Macy#
1329eda14cbcSMatt Macyfunction not_shared
1330eda14cbcSMatt Macy{
1331716fd348SMartin Matuska	! is_shared $1
1332eda14cbcSMatt Macy}
1333eda14cbcSMatt Macy
1334eda14cbcSMatt Macy#
1335eda14cbcSMatt Macy# Given a dataset determine if it is not shared via SMB.
1336eda14cbcSMatt Macy#
1337eda14cbcSMatt Macy# Returns 0 if not shared, 1 otherwise.
1338eda14cbcSMatt Macy#
1339eda14cbcSMatt Macyfunction not_shared_smb
1340eda14cbcSMatt Macy{
1341716fd348SMartin Matuska	! is_shared_smb $1
1342eda14cbcSMatt Macy}
1343eda14cbcSMatt Macy
1344eda14cbcSMatt Macy#
1345eda14cbcSMatt Macy# Helper function to unshare a mountpoint.
1346eda14cbcSMatt Macy#
1347eda14cbcSMatt Macyfunction unshare_fs #fs
1348eda14cbcSMatt Macy{
1349eda14cbcSMatt Macy	typeset fs=$1
1350eda14cbcSMatt Macy
1351716fd348SMartin Matuska	if is_shared $fs || is_shared_smb $fs; then
1352716fd348SMartin Matuska		log_must zfs unshare $fs
1353eda14cbcSMatt Macy	fi
1354eda14cbcSMatt Macy}
1355eda14cbcSMatt Macy
1356eda14cbcSMatt Macy#
1357eda14cbcSMatt Macy# Helper function to share a NFS mountpoint.
1358eda14cbcSMatt Macy#
1359eda14cbcSMatt Macyfunction share_nfs #fs
1360eda14cbcSMatt Macy{
1361eda14cbcSMatt Macy	typeset fs=$1
1362eda14cbcSMatt Macy
1363716fd348SMartin Matuska	is_shared "$fs" && return
1364716fd348SMartin Matuska
1365716fd348SMartin Matuska	case "$UNAME" in
1366716fd348SMartin Matuska	Linux)
1367716fd348SMartin Matuska		log_must exportfs "*:$fs"
1368716fd348SMartin Matuska		;;
1369716fd348SMartin Matuska	FreeBSD)
1370716fd348SMartin Matuska		typeset mountd
1371716fd348SMartin Matuska		read -r mountd < /var/run/mountd.pid
1372716fd348SMartin Matuska		log_must eval "printf '%s\t\n' \"$fs\" >> /etc/zfs/exports"
1373716fd348SMartin Matuska		log_must kill -s HUP "$mountd"
1374716fd348SMartin Matuska		;;
1375716fd348SMartin Matuska	*)
1376716fd348SMartin Matuska		log_must share -F nfs "$fs"
1377716fd348SMartin Matuska		;;
1378716fd348SMartin Matuska	esac
1379eda14cbcSMatt Macy
1380eda14cbcSMatt Macy	return 0
1381eda14cbcSMatt Macy}
1382eda14cbcSMatt Macy
1383eda14cbcSMatt Macy#
1384eda14cbcSMatt Macy# Helper function to unshare a NFS mountpoint.
1385eda14cbcSMatt Macy#
1386eda14cbcSMatt Macyfunction unshare_nfs #fs
1387eda14cbcSMatt Macy{
1388eda14cbcSMatt Macy	typeset fs=$1
1389eda14cbcSMatt Macy
1390716fd348SMartin Matuska	! is_shared "$fs" && return
1391716fd348SMartin Matuska
1392716fd348SMartin Matuska	case "$UNAME" in
1393716fd348SMartin Matuska	Linux)
1394716fd348SMartin Matuska		log_must exportfs -u "*:$fs"
1395716fd348SMartin Matuska		;;
1396716fd348SMartin Matuska	FreeBSD)
1397716fd348SMartin Matuska		typeset mountd
1398716fd348SMartin Matuska		read -r mountd < /var/run/mountd.pid
1399716fd348SMartin Matuska		awk -v fs="${fs//\\/\\\\}" '$1 != fs' /etc/zfs/exports > /etc/zfs/exports.$$
1400716fd348SMartin Matuska		log_must mv /etc/zfs/exports.$$ /etc/zfs/exports
1401716fd348SMartin Matuska		log_must kill -s HUP "$mountd"
1402716fd348SMartin Matuska		;;
1403716fd348SMartin Matuska	*)
1404eda14cbcSMatt Macy		log_must unshare -F nfs $fs
1405716fd348SMartin Matuska		;;
1406716fd348SMartin Matuska	esac
1407eda14cbcSMatt Macy
1408eda14cbcSMatt Macy	return 0
1409eda14cbcSMatt Macy}
1410eda14cbcSMatt Macy
1411eda14cbcSMatt Macy#
1412eda14cbcSMatt Macy# Helper function to show NFS shares.
1413eda14cbcSMatt Macy#
1414eda14cbcSMatt Macyfunction showshares_nfs
1415eda14cbcSMatt Macy{
1416716fd348SMartin Matuska	case "$UNAME" in
1417716fd348SMartin Matuska	Linux)
1418716fd348SMartin Matuska		exportfs -v
1419716fd348SMartin Matuska		;;
1420716fd348SMartin Matuska	FreeBSD)
1421716fd348SMartin Matuska		showmount
1422716fd348SMartin Matuska		;;
1423716fd348SMartin Matuska	*)
1424eda14cbcSMatt Macy		share -F nfs
1425716fd348SMartin Matuska		;;
1426716fd348SMartin Matuska	esac
1427eda14cbcSMatt Macy}
1428eda14cbcSMatt Macy
1429eda14cbcSMatt Macyfunction check_nfs
1430eda14cbcSMatt Macy{
1431716fd348SMartin Matuska	case "$UNAME" in
1432716fd348SMartin Matuska	Linux)
1433716fd348SMartin Matuska		exportfs -s
1434716fd348SMartin Matuska		;;
1435716fd348SMartin Matuska	FreeBSD)
1436eda14cbcSMatt Macy		showmount -e
1437716fd348SMartin Matuska		;;
1438716fd348SMartin Matuska	*)
1439eda14cbcSMatt Macy		log_unsupported "Unknown platform"
1440716fd348SMartin Matuska		;;
1441716fd348SMartin Matuska	esac || log_unsupported "The NFS utilities are not installed"
1442eda14cbcSMatt Macy}
1443eda14cbcSMatt Macy
1444eda14cbcSMatt Macy#
1445eda14cbcSMatt Macy# Check NFS server status and trigger it online.
1446eda14cbcSMatt Macy#
1447eda14cbcSMatt Macyfunction setup_nfs_server
1448eda14cbcSMatt Macy{
1449eda14cbcSMatt Macy	# Cannot share directory in non-global zone.
1450eda14cbcSMatt Macy	#
1451eda14cbcSMatt Macy	if ! is_global_zone; then
1452eda14cbcSMatt Macy		log_note "Cannot trigger NFS server by sharing in LZ."
1453eda14cbcSMatt Macy		return
1454eda14cbcSMatt Macy	fi
1455eda14cbcSMatt Macy
1456eda14cbcSMatt Macy	if is_linux; then
1457eda14cbcSMatt Macy		#
1458eda14cbcSMatt Macy		# Re-synchronize /var/lib/nfs/etab with /etc/exports and
1459eda14cbcSMatt Macy		# /etc/exports.d./* to provide a clean test environment.
1460eda14cbcSMatt Macy		#
1461716fd348SMartin Matuska		log_must exportfs -r
1462eda14cbcSMatt Macy
1463eda14cbcSMatt Macy		log_note "NFS server must be started prior to running ZTS."
1464eda14cbcSMatt Macy		return
1465eda14cbcSMatt Macy	elif is_freebsd; then
1466716fd348SMartin Matuska		log_must kill -s HUP $(</var/run/mountd.pid)
1467eda14cbcSMatt Macy
1468eda14cbcSMatt Macy		log_note "NFS server must be started prior to running ZTS."
1469eda14cbcSMatt Macy		return
1470eda14cbcSMatt Macy	fi
1471eda14cbcSMatt Macy
1472eda14cbcSMatt Macy	typeset nfs_fmri="svc:/network/nfs/server:default"
1473eda14cbcSMatt Macy	if [[ $(svcs -Ho STA $nfs_fmri) != "ON" ]]; then
1474eda14cbcSMatt Macy		#
1475eda14cbcSMatt Macy		# Only really sharing operation can enable NFS server
1476eda14cbcSMatt Macy		# to online permanently.
1477eda14cbcSMatt Macy		#
1478eda14cbcSMatt Macy		typeset dummy=/tmp/dummy
1479eda14cbcSMatt Macy
1480eda14cbcSMatt Macy		if [[ -d $dummy ]]; then
1481eda14cbcSMatt Macy			log_must rm -rf $dummy
1482eda14cbcSMatt Macy		fi
1483eda14cbcSMatt Macy
1484eda14cbcSMatt Macy		log_must mkdir $dummy
1485eda14cbcSMatt Macy		log_must share $dummy
1486eda14cbcSMatt Macy
1487eda14cbcSMatt Macy		#
1488eda14cbcSMatt Macy		# Waiting for fmri's status to be the final status.
1489eda14cbcSMatt Macy		# Otherwise, in transition, an asterisk (*) is appended for
1490eda14cbcSMatt Macy		# instances, unshare will reverse status to 'DIS' again.
1491eda14cbcSMatt Macy		#
1492eda14cbcSMatt Macy		# Waiting for 1's at least.
1493eda14cbcSMatt Macy		#
1494eda14cbcSMatt Macy		log_must sleep 1
1495eda14cbcSMatt Macy		timeout=10
1496eda14cbcSMatt Macy		while [[ timeout -ne 0 && $(svcs -Ho STA $nfs_fmri) == *'*' ]]
1497eda14cbcSMatt Macy		do
1498eda14cbcSMatt Macy			log_must sleep 1
1499eda14cbcSMatt Macy
1500eda14cbcSMatt Macy			((timeout -= 1))
1501eda14cbcSMatt Macy		done
1502eda14cbcSMatt Macy
1503eda14cbcSMatt Macy		log_must unshare $dummy
1504eda14cbcSMatt Macy		log_must rm -rf $dummy
1505eda14cbcSMatt Macy	fi
1506eda14cbcSMatt Macy
1507eda14cbcSMatt Macy	log_note "Current NFS status: '$(svcs -Ho STA,FMRI $nfs_fmri)'"
1508eda14cbcSMatt Macy}
1509eda14cbcSMatt Macy
1510eda14cbcSMatt Macy#
1511eda14cbcSMatt Macy# To verify whether calling process is in global zone
1512eda14cbcSMatt Macy#
1513eda14cbcSMatt Macy# Return 0 if in global zone, 1 in non-global zone
1514eda14cbcSMatt Macy#
1515eda14cbcSMatt Macyfunction is_global_zone
1516eda14cbcSMatt Macy{
1517eda14cbcSMatt Macy	if is_linux || is_freebsd; then
1518eda14cbcSMatt Macy		return 0
1519eda14cbcSMatt Macy	else
1520eda14cbcSMatt Macy		typeset cur_zone=$(zonename 2>/dev/null)
1521716fd348SMartin Matuska		[ $cur_zone = "global" ]
1522eda14cbcSMatt Macy	fi
1523eda14cbcSMatt Macy}
1524eda14cbcSMatt Macy
1525eda14cbcSMatt Macy#
1526eda14cbcSMatt Macy# Verify whether test is permitted to run from
1527eda14cbcSMatt Macy# global zone, local zone, or both
1528eda14cbcSMatt Macy#
1529eda14cbcSMatt Macy# $1 zone limit, could be "global", "local", or "both"(no limit)
1530eda14cbcSMatt Macy#
1531eda14cbcSMatt Macy# Return 0 if permitted, otherwise exit with log_unsupported
1532eda14cbcSMatt Macy#
1533eda14cbcSMatt Macyfunction verify_runnable # zone limit
1534eda14cbcSMatt Macy{
1535eda14cbcSMatt Macy	typeset limit=$1
1536eda14cbcSMatt Macy
1537eda14cbcSMatt Macy	[[ -z $limit ]] && return 0
1538eda14cbcSMatt Macy
1539eda14cbcSMatt Macy	if is_global_zone ; then
1540eda14cbcSMatt Macy		case $limit in
1541eda14cbcSMatt Macy			global|both)
1542eda14cbcSMatt Macy				;;
1543eda14cbcSMatt Macy			local)	log_unsupported "Test is unable to run from "\
1544eda14cbcSMatt Macy					"global zone."
1545eda14cbcSMatt Macy				;;
1546eda14cbcSMatt Macy			*)	log_note "Warning: unknown limit $limit - " \
1547eda14cbcSMatt Macy					"use both."
1548eda14cbcSMatt Macy				;;
1549eda14cbcSMatt Macy		esac
1550eda14cbcSMatt Macy	else
1551eda14cbcSMatt Macy		case $limit in
1552eda14cbcSMatt Macy			local|both)
1553eda14cbcSMatt Macy				;;
1554eda14cbcSMatt Macy			global)	log_unsupported "Test is unable to run from "\
1555eda14cbcSMatt Macy					"local zone."
1556eda14cbcSMatt Macy				;;
1557eda14cbcSMatt Macy			*)	log_note "Warning: unknown limit $limit - " \
1558eda14cbcSMatt Macy					"use both."
1559eda14cbcSMatt Macy				;;
1560eda14cbcSMatt Macy		esac
1561eda14cbcSMatt Macy
1562eda14cbcSMatt Macy		reexport_pool
1563eda14cbcSMatt Macy	fi
1564eda14cbcSMatt Macy
1565eda14cbcSMatt Macy	return 0
1566eda14cbcSMatt Macy}
1567eda14cbcSMatt Macy
1568eda14cbcSMatt Macy# Return 0 if create successfully or the pool exists; $? otherwise
1569eda14cbcSMatt Macy# Note: In local zones, this function should return 0 silently.
1570eda14cbcSMatt Macy#
1571eda14cbcSMatt Macy# $1 - pool name
1572eda14cbcSMatt Macy# $2-n - [keyword] devs_list
1573eda14cbcSMatt Macy
1574eda14cbcSMatt Macyfunction create_pool #pool devs_list
1575eda14cbcSMatt Macy{
1576eda14cbcSMatt Macy	typeset pool=${1%%/*}
1577eda14cbcSMatt Macy
1578eda14cbcSMatt Macy	shift
1579eda14cbcSMatt Macy
1580eda14cbcSMatt Macy	if [[ -z $pool ]]; then
1581eda14cbcSMatt Macy		log_note "Missing pool name."
1582eda14cbcSMatt Macy		return 1
1583eda14cbcSMatt Macy	fi
1584eda14cbcSMatt Macy
1585eda14cbcSMatt Macy	if poolexists $pool ; then
1586eda14cbcSMatt Macy		destroy_pool $pool
1587eda14cbcSMatt Macy	fi
1588eda14cbcSMatt Macy
1589eda14cbcSMatt Macy	if is_global_zone ; then
1590eda14cbcSMatt Macy		[[ -d /$pool ]] && rm -rf /$pool
1591eda14cbcSMatt Macy		log_must zpool create -f $pool $@
1592eda14cbcSMatt Macy	fi
1593eda14cbcSMatt Macy
1594eda14cbcSMatt Macy	return 0
1595eda14cbcSMatt Macy}
1596eda14cbcSMatt Macy
1597eda14cbcSMatt Macy# Return 0 if destroy successfully or the pool exists; $? otherwise
1598eda14cbcSMatt Macy# Note: In local zones, this function should return 0 silently.
1599eda14cbcSMatt Macy#
1600eda14cbcSMatt Macy# $1 - pool name
1601eda14cbcSMatt Macy# Destroy pool with the given parameters.
1602eda14cbcSMatt Macy
1603eda14cbcSMatt Macyfunction destroy_pool #pool
1604eda14cbcSMatt Macy{
1605eda14cbcSMatt Macy	typeset pool=${1%%/*}
1606eda14cbcSMatt Macy	typeset mtpt
1607eda14cbcSMatt Macy
1608eda14cbcSMatt Macy	if [[ -z $pool ]]; then
1609eda14cbcSMatt Macy		log_note "No pool name given."
1610eda14cbcSMatt Macy		return 1
1611eda14cbcSMatt Macy	fi
1612eda14cbcSMatt Macy
1613eda14cbcSMatt Macy	if is_global_zone ; then
1614eda14cbcSMatt Macy		if poolexists "$pool" ; then
1615eda14cbcSMatt Macy			mtpt=$(get_prop mountpoint "$pool")
1616eda14cbcSMatt Macy
1617eda14cbcSMatt Macy			# At times, syseventd/udev activity can cause attempts
1618eda14cbcSMatt Macy			# to destroy a pool to fail with EBUSY. We retry a few
1619eda14cbcSMatt Macy			# times allowing failures before requiring the destroy
1620eda14cbcSMatt Macy			# to succeed.
1621eda14cbcSMatt Macy			log_must_busy zpool destroy -f $pool
1622eda14cbcSMatt Macy
1623eda14cbcSMatt Macy			[[ -d $mtpt ]] && \
1624eda14cbcSMatt Macy				log_must rm -rf $mtpt
1625eda14cbcSMatt Macy		else
1626eda14cbcSMatt Macy			log_note "Pool does not exist. ($pool)"
1627eda14cbcSMatt Macy			return 1
1628eda14cbcSMatt Macy		fi
1629eda14cbcSMatt Macy	fi
1630eda14cbcSMatt Macy
1631eda14cbcSMatt Macy	return 0
1632eda14cbcSMatt Macy}
1633eda14cbcSMatt Macy
1634eda14cbcSMatt Macy# Return 0 if created successfully; $? otherwise
1635eda14cbcSMatt Macy#
1636eda14cbcSMatt Macy# $1 - dataset name
1637eda14cbcSMatt Macy# $2-n - dataset options
1638eda14cbcSMatt Macy
1639eda14cbcSMatt Macyfunction create_dataset #dataset dataset_options
1640eda14cbcSMatt Macy{
1641eda14cbcSMatt Macy	typeset dataset=$1
1642eda14cbcSMatt Macy
1643eda14cbcSMatt Macy	shift
1644eda14cbcSMatt Macy
1645eda14cbcSMatt Macy	if [[ -z $dataset ]]; then
1646eda14cbcSMatt Macy		log_note "Missing dataset name."
1647eda14cbcSMatt Macy		return 1
1648eda14cbcSMatt Macy	fi
1649eda14cbcSMatt Macy
1650eda14cbcSMatt Macy	if datasetexists $dataset ; then
1651eda14cbcSMatt Macy		destroy_dataset $dataset
1652eda14cbcSMatt Macy	fi
1653eda14cbcSMatt Macy
1654eda14cbcSMatt Macy	log_must zfs create $@ $dataset
1655eda14cbcSMatt Macy
1656eda14cbcSMatt Macy	return 0
1657eda14cbcSMatt Macy}
1658eda14cbcSMatt Macy
1659eda14cbcSMatt Macy# Return 0 if destroy successfully or the dataset exists; $? otherwise
1660eda14cbcSMatt Macy# Note: In local zones, this function should return 0 silently.
1661eda14cbcSMatt Macy#
1662eda14cbcSMatt Macy# $1 - dataset name
1663eda14cbcSMatt Macy# $2 - custom arguments for zfs destroy
1664eda14cbcSMatt Macy# Destroy dataset with the given parameters.
1665eda14cbcSMatt Macy
1666716fd348SMartin Matuskafunction destroy_dataset # dataset [args]
1667eda14cbcSMatt Macy{
1668eda14cbcSMatt Macy	typeset dataset=$1
1669eda14cbcSMatt Macy	typeset mtpt
1670eda14cbcSMatt Macy	typeset args=${2:-""}
1671eda14cbcSMatt Macy
1672eda14cbcSMatt Macy	if [[ -z $dataset ]]; then
1673eda14cbcSMatt Macy		log_note "No dataset name given."
1674eda14cbcSMatt Macy		return 1
1675eda14cbcSMatt Macy	fi
1676eda14cbcSMatt Macy
1677eda14cbcSMatt Macy	if is_global_zone ; then
1678eda14cbcSMatt Macy		if datasetexists "$dataset" ; then
1679eda14cbcSMatt Macy			mtpt=$(get_prop mountpoint "$dataset")
1680eda14cbcSMatt Macy			log_must_busy zfs destroy $args $dataset
1681eda14cbcSMatt Macy
1682716fd348SMartin Matuska			[ -d $mtpt ] && log_must rm -rf $mtpt
1683eda14cbcSMatt Macy		else
1684eda14cbcSMatt Macy			log_note "Dataset does not exist. ($dataset)"
1685eda14cbcSMatt Macy			return 1
1686eda14cbcSMatt Macy		fi
1687eda14cbcSMatt Macy	fi
1688eda14cbcSMatt Macy
1689eda14cbcSMatt Macy	return 0
1690eda14cbcSMatt Macy}
1691eda14cbcSMatt Macy
1692eda14cbcSMatt Macy#
1693eda14cbcSMatt Macy# Reexport TESTPOOL & TESTPOOL(1-4)
1694eda14cbcSMatt Macy#
1695eda14cbcSMatt Macyfunction reexport_pool
1696eda14cbcSMatt Macy{
1697eda14cbcSMatt Macy	typeset -i cntctr=5
1698eda14cbcSMatt Macy	typeset -i i=0
1699eda14cbcSMatt Macy
1700eda14cbcSMatt Macy	while ((i < cntctr)); do
1701eda14cbcSMatt Macy		if ((i == 0)); then
1702eda14cbcSMatt Macy			TESTPOOL=$ZONE_POOL/$ZONE_CTR$i
1703eda14cbcSMatt Macy			if ! ismounted $TESTPOOL; then
1704eda14cbcSMatt Macy				log_must zfs mount $TESTPOOL
1705eda14cbcSMatt Macy			fi
1706eda14cbcSMatt Macy		else
1707eda14cbcSMatt Macy			eval TESTPOOL$i=$ZONE_POOL/$ZONE_CTR$i
1708eda14cbcSMatt Macy			if eval ! ismounted \$TESTPOOL$i; then
1709eda14cbcSMatt Macy				log_must eval zfs mount \$TESTPOOL$i
1710eda14cbcSMatt Macy			fi
1711eda14cbcSMatt Macy		fi
1712eda14cbcSMatt Macy		((i += 1))
1713eda14cbcSMatt Macy	done
1714eda14cbcSMatt Macy}
1715eda14cbcSMatt Macy
1716eda14cbcSMatt Macy#
1717eda14cbcSMatt Macy# Verify a given disk or pool state
1718eda14cbcSMatt Macy#
1719eda14cbcSMatt Macy# Return 0 is pool/disk matches expected state, 1 otherwise
1720eda14cbcSMatt Macy#
1721eda14cbcSMatt Macyfunction check_state # pool disk state{online,offline,degraded}
1722eda14cbcSMatt Macy{
1723eda14cbcSMatt Macy	typeset pool=$1
1724eda14cbcSMatt Macy	typeset disk=${2#$DEV_DSKDIR/}
1725eda14cbcSMatt Macy	typeset state=$3
1726eda14cbcSMatt Macy
1727eda14cbcSMatt Macy	[[ -z $pool ]] || [[ -z $state ]] \
1728eda14cbcSMatt Macy	    && log_fail "Arguments invalid or missing"
1729eda14cbcSMatt Macy
1730eda14cbcSMatt Macy	if [[ -z $disk ]]; then
1731eda14cbcSMatt Macy		#check pool state only
1732716fd348SMartin Matuska		zpool get -H -o value health $pool | grep -qi "$state"
1733eda14cbcSMatt Macy	else
1734716fd348SMartin Matuska		zpool status -v $pool | grep "$disk" | grep -qi "$state"
1735eda14cbcSMatt Macy	fi
1736eda14cbcSMatt Macy}
1737eda14cbcSMatt Macy
1738eda14cbcSMatt Macy#
1739eda14cbcSMatt Macy# Get the mountpoint of snapshot
1740eda14cbcSMatt Macy# For the snapshot use <mp_filesystem>/.zfs/snapshot/<snap>
1741eda14cbcSMatt Macy# as its mountpoint
1742eda14cbcSMatt Macy#
1743eda14cbcSMatt Macyfunction snapshot_mountpoint
1744eda14cbcSMatt Macy{
1745eda14cbcSMatt Macy	typeset dataset=${1:-$TESTPOOL/$TESTFS@$TESTSNAP}
1746eda14cbcSMatt Macy
1747eda14cbcSMatt Macy	if [[ $dataset != *@* ]]; then
1748eda14cbcSMatt Macy		log_fail "Error name of snapshot '$dataset'."
1749eda14cbcSMatt Macy	fi
1750eda14cbcSMatt Macy
1751eda14cbcSMatt Macy	typeset fs=${dataset%@*}
1752eda14cbcSMatt Macy	typeset snap=${dataset#*@}
1753eda14cbcSMatt Macy
1754eda14cbcSMatt Macy	if [[ -z $fs || -z $snap ]]; then
1755eda14cbcSMatt Macy		log_fail "Error name of snapshot '$dataset'."
1756eda14cbcSMatt Macy	fi
1757eda14cbcSMatt Macy
1758eda14cbcSMatt Macy	echo $(get_prop mountpoint $fs)/.zfs/snapshot/$snap
1759eda14cbcSMatt Macy}
1760eda14cbcSMatt Macy
1761eda14cbcSMatt Macy#
1762eda14cbcSMatt Macy# Given a device and 'ashift' value verify it's correctly set on every label
1763eda14cbcSMatt Macy#
1764eda14cbcSMatt Macyfunction verify_ashift # device ashift
1765eda14cbcSMatt Macy{
1766eda14cbcSMatt Macy	typeset device="$1"
1767eda14cbcSMatt Macy	typeset ashift="$2"
1768eda14cbcSMatt Macy
1769716fd348SMartin Matuska	zdb -e -lll $device | awk -v ashift=$ashift '
1770716fd348SMartin Matuska	    /ashift: / {
1771eda14cbcSMatt Macy	        if (ashift != $2)
1772eda14cbcSMatt Macy	            exit 1;
1773eda14cbcSMatt Macy	        else
1774eda14cbcSMatt Macy	            count++;
1775716fd348SMartin Matuska	    }
1776716fd348SMartin Matuska	    END {
1777716fd348SMartin Matuska	        exit (count != 4);
1778eda14cbcSMatt Macy	    }'
1779eda14cbcSMatt Macy}
1780eda14cbcSMatt Macy
1781eda14cbcSMatt Macy#
1782eda14cbcSMatt Macy# Given a pool and file system, this function will verify the file system
1783eda14cbcSMatt Macy# using the zdb internal tool. Note that the pool is exported and imported
1784eda14cbcSMatt Macy# to ensure it has consistent state.
1785eda14cbcSMatt Macy#
1786eda14cbcSMatt Macyfunction verify_filesys # pool filesystem dir
1787eda14cbcSMatt Macy{
1788eda14cbcSMatt Macy	typeset pool="$1"
1789eda14cbcSMatt Macy	typeset filesys="$2"
1790eda14cbcSMatt Macy	typeset zdbout="/tmp/zdbout.$$"
1791eda14cbcSMatt Macy
1792eda14cbcSMatt Macy	shift
1793eda14cbcSMatt Macy	shift
1794eda14cbcSMatt Macy	typeset dirs=$@
1795eda14cbcSMatt Macy	typeset search_path=""
1796eda14cbcSMatt Macy
1797eda14cbcSMatt Macy	log_note "Calling zdb to verify filesystem '$filesys'"
1798eda14cbcSMatt Macy	zfs unmount -a > /dev/null 2>&1
1799eda14cbcSMatt Macy	log_must zpool export $pool
1800eda14cbcSMatt Macy
1801eda14cbcSMatt Macy	if [[ -n $dirs ]] ; then
1802eda14cbcSMatt Macy		for dir in $dirs ; do
1803eda14cbcSMatt Macy			search_path="$search_path -d $dir"
1804eda14cbcSMatt Macy		done
1805eda14cbcSMatt Macy	fi
1806eda14cbcSMatt Macy
1807eda14cbcSMatt Macy	log_must zpool import $search_path $pool
1808eda14cbcSMatt Macy
1809716fd348SMartin Matuska	if ! zdb -cudi $filesys > $zdbout 2>&1; then
1810eda14cbcSMatt Macy		log_note "Output: zdb -cudi $filesys"
1811eda14cbcSMatt Macy		cat $zdbout
1812716fd348SMartin Matuska		rm -f $zdbout
1813eda14cbcSMatt Macy		log_fail "zdb detected errors with: '$filesys'"
1814eda14cbcSMatt Macy	fi
1815eda14cbcSMatt Macy
1816eda14cbcSMatt Macy	log_must zfs mount -a
1817eda14cbcSMatt Macy	log_must rm -rf $zdbout
1818eda14cbcSMatt Macy}
1819eda14cbcSMatt Macy
1820eda14cbcSMatt Macy#
1821eda14cbcSMatt Macy# Given a pool issue a scrub and verify that no checksum errors are reported.
1822eda14cbcSMatt Macy#
1823eda14cbcSMatt Macyfunction verify_pool
1824eda14cbcSMatt Macy{
1825eda14cbcSMatt Macy	typeset pool=${1:-$TESTPOOL}
1826eda14cbcSMatt Macy
1827eda14cbcSMatt Macy	log_must zpool scrub $pool
1828eda14cbcSMatt Macy	log_must wait_scrubbed $pool
1829eda14cbcSMatt Macy
1830eda14cbcSMatt Macy	typeset -i cksum=$(zpool status $pool | awk '
1831eda14cbcSMatt Macy	    !NF { isvdev = 0 }
1832eda14cbcSMatt Macy	    isvdev { errors += $NF }
1833eda14cbcSMatt Macy	    /CKSUM$/ { isvdev = 1 }
1834eda14cbcSMatt Macy	    END { print errors }
1835eda14cbcSMatt Macy	')
1836eda14cbcSMatt Macy	if [[ $cksum != 0 ]]; then
1837eda14cbcSMatt Macy		log_must zpool status -v
1838eda14cbcSMatt Macy	        log_fail "Unexpected CKSUM errors found on $pool ($cksum)"
1839eda14cbcSMatt Macy	fi
1840eda14cbcSMatt Macy}
1841eda14cbcSMatt Macy
1842eda14cbcSMatt Macy#
1843eda14cbcSMatt Macy# Given a pool, and this function list all disks in the pool
1844eda14cbcSMatt Macy#
1845eda14cbcSMatt Macyfunction get_disklist # pool
1846eda14cbcSMatt Macy{
1847716fd348SMartin Matuska	echo $(zpool iostat -v $1 | awk '(NR > 4) {print $1}' | \
1848716fd348SMartin Matuska	    grep -vEe '^-----' -e "^(mirror|raidz[1-3]|draid[1-3]|spare|log|cache|special|dedup)|\-[0-9]$")
1849eda14cbcSMatt Macy}
1850eda14cbcSMatt Macy
1851eda14cbcSMatt Macy#
1852eda14cbcSMatt Macy# Given a pool, and this function list all disks in the pool with their full
1853eda14cbcSMatt Macy# path (like "/dev/sda" instead of "sda").
1854eda14cbcSMatt Macy#
1855eda14cbcSMatt Macyfunction get_disklist_fullpath # pool
1856eda14cbcSMatt Macy{
1857716fd348SMartin Matuska	get_disklist "-P $1"
1858eda14cbcSMatt Macy}
1859eda14cbcSMatt Macy
1860eda14cbcSMatt Macy
1861eda14cbcSMatt Macy
1862eda14cbcSMatt Macy# /**
1863eda14cbcSMatt Macy#  This function kills a given list of processes after a time period. We use
1864eda14cbcSMatt Macy#  this in the stress tests instead of STF_TIMEOUT so that we can have processes
1865eda14cbcSMatt Macy#  run for a fixed amount of time, yet still pass. Tests that hit STF_TIMEOUT
1866eda14cbcSMatt Macy#  would be listed as FAIL, which we don't want : we're happy with stress tests
1867eda14cbcSMatt Macy#  running for a certain amount of time, then finishing.
1868eda14cbcSMatt Macy#
1869eda14cbcSMatt Macy# @param $1 the time in seconds after which we should terminate these processes
1870eda14cbcSMatt Macy# @param $2..$n the processes we wish to terminate.
1871eda14cbcSMatt Macy# */
1872eda14cbcSMatt Macyfunction stress_timeout
1873eda14cbcSMatt Macy{
1874eda14cbcSMatt Macy	typeset -i TIMEOUT=$1
1875eda14cbcSMatt Macy	shift
1876eda14cbcSMatt Macy	typeset cpids="$@"
1877eda14cbcSMatt Macy
1878eda14cbcSMatt Macy	log_note "Waiting for child processes($cpids). " \
1879eda14cbcSMatt Macy		"It could last dozens of minutes, please be patient ..."
1880eda14cbcSMatt Macy	log_must sleep $TIMEOUT
1881eda14cbcSMatt Macy
1882eda14cbcSMatt Macy	log_note "Killing child processes after ${TIMEOUT} stress timeout."
1883eda14cbcSMatt Macy	typeset pid
1884eda14cbcSMatt Macy	for pid in $cpids; do
1885716fd348SMartin Matuska		ps -p $pid > /dev/null 2>&1 &&
1886eda14cbcSMatt Macy			log_must kill -USR1 $pid
1887eda14cbcSMatt Macy	done
1888eda14cbcSMatt Macy}
1889eda14cbcSMatt Macy
1890eda14cbcSMatt Macy#
1891eda14cbcSMatt Macy# Verify a given hotspare disk is inuse or avail
1892eda14cbcSMatt Macy#
1893eda14cbcSMatt Macy# Return 0 is pool/disk matches expected state, 1 otherwise
1894eda14cbcSMatt Macy#
1895eda14cbcSMatt Macyfunction check_hotspare_state # pool disk state{inuse,avail}
1896eda14cbcSMatt Macy{
1897eda14cbcSMatt Macy	typeset pool=$1
1898eda14cbcSMatt Macy	typeset disk=${2#$DEV_DSKDIR/}
1899eda14cbcSMatt Macy	typeset state=$3
1900eda14cbcSMatt Macy
1901eda14cbcSMatt Macy	cur_state=$(get_device_state $pool $disk "spares")
1902eda14cbcSMatt Macy
1903716fd348SMartin Matuska	[ $state = $cur_state ]
1904eda14cbcSMatt Macy}
1905eda14cbcSMatt Macy
1906eda14cbcSMatt Macy#
1907eda14cbcSMatt Macy# Wait until a hotspare transitions to a given state or times out.
1908eda14cbcSMatt Macy#
1909eda14cbcSMatt Macy# Return 0 when  pool/disk matches expected state, 1 on timeout.
1910eda14cbcSMatt Macy#
1911eda14cbcSMatt Macyfunction wait_hotspare_state # pool disk state timeout
1912eda14cbcSMatt Macy{
1913eda14cbcSMatt Macy	typeset pool=$1
1914eda14cbcSMatt Macy	typeset disk=${2#*$DEV_DSKDIR/}
1915eda14cbcSMatt Macy	typeset state=$3
1916eda14cbcSMatt Macy	typeset timeout=${4:-60}
1917eda14cbcSMatt Macy	typeset -i i=0
1918eda14cbcSMatt Macy
1919eda14cbcSMatt Macy	while [[ $i -lt $timeout ]]; do
1920eda14cbcSMatt Macy		if check_hotspare_state $pool $disk $state; then
1921eda14cbcSMatt Macy			return 0
1922eda14cbcSMatt Macy		fi
1923eda14cbcSMatt Macy
1924eda14cbcSMatt Macy		i=$((i+1))
1925eda14cbcSMatt Macy		sleep 1
1926eda14cbcSMatt Macy	done
1927eda14cbcSMatt Macy
1928eda14cbcSMatt Macy	return 1
1929eda14cbcSMatt Macy}
1930eda14cbcSMatt Macy
1931eda14cbcSMatt Macy#
1932eda14cbcSMatt Macy# Verify a given vdev disk is inuse or avail
1933eda14cbcSMatt Macy#
1934eda14cbcSMatt Macy# Return 0 is pool/disk matches expected state, 1 otherwise
1935eda14cbcSMatt Macy#
1936be181ee2SMartin Matuskafunction check_vdev_state # pool disk state{online,offline,unavail,removed}
1937eda14cbcSMatt Macy{
1938eda14cbcSMatt Macy	typeset pool=$1
1939eda14cbcSMatt Macy	typeset disk=${2#*$DEV_DSKDIR/}
1940eda14cbcSMatt Macy	typeset state=$3
1941eda14cbcSMatt Macy
1942eda14cbcSMatt Macy	cur_state=$(get_device_state $pool $disk)
1943eda14cbcSMatt Macy
1944716fd348SMartin Matuska	[ $state = $cur_state ]
1945eda14cbcSMatt Macy}
1946eda14cbcSMatt Macy
1947eda14cbcSMatt Macy#
1948eda14cbcSMatt Macy# Wait until a vdev transitions to a given state or times out.
1949eda14cbcSMatt Macy#
1950eda14cbcSMatt Macy# Return 0 when  pool/disk matches expected state, 1 on timeout.
1951eda14cbcSMatt Macy#
1952eda14cbcSMatt Macyfunction wait_vdev_state # pool disk state timeout
1953eda14cbcSMatt Macy{
1954eda14cbcSMatt Macy	typeset pool=$1
1955eda14cbcSMatt Macy	typeset disk=${2#*$DEV_DSKDIR/}
1956eda14cbcSMatt Macy	typeset state=$3
1957eda14cbcSMatt Macy	typeset timeout=${4:-60}
1958eda14cbcSMatt Macy	typeset -i i=0
1959eda14cbcSMatt Macy
1960eda14cbcSMatt Macy	while [[ $i -lt $timeout ]]; do
1961eda14cbcSMatt Macy		if check_vdev_state $pool $disk $state; then
1962eda14cbcSMatt Macy			return 0
1963eda14cbcSMatt Macy		fi
1964eda14cbcSMatt Macy
1965eda14cbcSMatt Macy		i=$((i+1))
1966eda14cbcSMatt Macy		sleep 1
1967eda14cbcSMatt Macy	done
1968eda14cbcSMatt Macy
1969eda14cbcSMatt Macy	return 1
1970eda14cbcSMatt Macy}
1971eda14cbcSMatt Macy
1972eda14cbcSMatt Macy#
1973eda14cbcSMatt Macy# Check the output of 'zpool status -v <pool>',
1974eda14cbcSMatt Macy# and to see if the content of <token> contain the <keyword> specified.
1975eda14cbcSMatt Macy#
1976eda14cbcSMatt Macy# Return 0 is contain, 1 otherwise
1977eda14cbcSMatt Macy#
1978eda14cbcSMatt Macyfunction check_pool_status # pool token keyword <verbose>
1979eda14cbcSMatt Macy{
1980eda14cbcSMatt Macy	typeset pool=$1
1981eda14cbcSMatt Macy	typeset token=$2
1982eda14cbcSMatt Macy	typeset keyword=$3
1983eda14cbcSMatt Macy	typeset verbose=${4:-false}
1984eda14cbcSMatt Macy
1985716fd348SMartin Matuska	scan=$(zpool status -v "$pool" 2>/dev/null | awk -v token="$token:" '$1==token')
1986eda14cbcSMatt Macy	if [[ $verbose == true ]]; then
1987eda14cbcSMatt Macy		log_note $scan
1988eda14cbcSMatt Macy	fi
1989716fd348SMartin Matuska	echo $scan | grep -qi "$keyword"
1990eda14cbcSMatt Macy}
1991eda14cbcSMatt Macy
1992eda14cbcSMatt Macy#
1993eda14cbcSMatt Macy# The following functions are instance of check_pool_status()
1994eda14cbcSMatt Macy#	is_pool_resilvering - to check if the pool resilver is in progress
1995eda14cbcSMatt Macy#	is_pool_resilvered - to check if the pool resilver is completed
1996eda14cbcSMatt Macy#	is_pool_scrubbing - to check if the pool scrub is in progress
1997eda14cbcSMatt Macy#	is_pool_scrubbed - to check if the pool scrub is completed
1998eda14cbcSMatt Macy#	is_pool_scrub_stopped - to check if the pool scrub is stopped
1999eda14cbcSMatt Macy#	is_pool_scrub_paused - to check if the pool scrub has paused
2000eda14cbcSMatt Macy#	is_pool_removing - to check if the pool removing is a vdev
2001eda14cbcSMatt Macy#	is_pool_removed - to check if the pool remove is completed
2002eda14cbcSMatt Macy#	is_pool_discarding - to check if the pool checkpoint is being discarded
2003e639e0d2SMartin Matuska#	is_pool_replacing - to check if the pool is performing a replacement
2004eda14cbcSMatt Macy#
2005eda14cbcSMatt Macyfunction is_pool_resilvering #pool <verbose>
2006eda14cbcSMatt Macy{
2007eda14cbcSMatt Macy	check_pool_status "$1" "scan" \
20087877fdebSMatt Macy	    "resilver[ ()0-9A-Za-z:_-]* in progress since" $2
2009eda14cbcSMatt Macy}
2010eda14cbcSMatt Macy
2011eda14cbcSMatt Macyfunction is_pool_resilvered #pool <verbose>
2012eda14cbcSMatt Macy{
2013eda14cbcSMatt Macy	check_pool_status "$1" "scan" "resilvered " $2
2014eda14cbcSMatt Macy}
2015eda14cbcSMatt Macy
2016eda14cbcSMatt Macyfunction is_pool_scrubbing #pool <verbose>
2017eda14cbcSMatt Macy{
2018eda14cbcSMatt Macy	check_pool_status "$1" "scan" "scrub in progress since " $2
2019eda14cbcSMatt Macy}
2020eda14cbcSMatt Macy
2021c0a83fe0SMartin Matuskafunction is_pool_error_scrubbing #pool <verbose>
2022c0a83fe0SMartin Matuska{
2023c0a83fe0SMartin Matuska	check_pool_status "$1" "scrub" "error scrub in progress since " $2
2024c0a83fe0SMartin Matuska	return $?
2025c0a83fe0SMartin Matuska}
2026c0a83fe0SMartin Matuska
2027eda14cbcSMatt Macyfunction is_pool_scrubbed #pool <verbose>
2028eda14cbcSMatt Macy{
2029eda14cbcSMatt Macy	check_pool_status "$1" "scan" "scrub repaired" $2
2030eda14cbcSMatt Macy}
2031eda14cbcSMatt Macy
2032eda14cbcSMatt Macyfunction is_pool_scrub_stopped #pool <verbose>
2033eda14cbcSMatt Macy{
2034eda14cbcSMatt Macy	check_pool_status "$1" "scan" "scrub canceled" $2
2035eda14cbcSMatt Macy}
2036eda14cbcSMatt Macy
2037c0a83fe0SMartin Matuskafunction is_pool_error_scrub_stopped #pool <verbose>
2038c0a83fe0SMartin Matuska{
2039c0a83fe0SMartin Matuska	check_pool_status "$1" "scrub" "error scrub canceled on " $2
2040c0a83fe0SMartin Matuska	return $?
2041c0a83fe0SMartin Matuska}
2042c0a83fe0SMartin Matuska
2043eda14cbcSMatt Macyfunction is_pool_scrub_paused #pool <verbose>
2044eda14cbcSMatt Macy{
2045eda14cbcSMatt Macy	check_pool_status "$1" "scan" "scrub paused since " $2
2046eda14cbcSMatt Macy}
2047eda14cbcSMatt Macy
2048c0a83fe0SMartin Matuskafunction is_pool_error_scrub_paused #pool <verbose>
2049c0a83fe0SMartin Matuska{
2050c0a83fe0SMartin Matuska	check_pool_status "$1" "scrub" "error scrub paused since " $2
2051c0a83fe0SMartin Matuska	return $?
2052c0a83fe0SMartin Matuska}
2053c0a83fe0SMartin Matuska
2054eda14cbcSMatt Macyfunction is_pool_removing #pool
2055eda14cbcSMatt Macy{
2056eda14cbcSMatt Macy	check_pool_status "$1" "remove" "in progress since "
2057eda14cbcSMatt Macy}
2058eda14cbcSMatt Macy
2059eda14cbcSMatt Macyfunction is_pool_removed #pool
2060eda14cbcSMatt Macy{
2061eda14cbcSMatt Macy	check_pool_status "$1" "remove" "completed on"
2062eda14cbcSMatt Macy}
2063eda14cbcSMatt Macy
2064eda14cbcSMatt Macyfunction is_pool_discarding #pool
2065eda14cbcSMatt Macy{
2066eda14cbcSMatt Macy	check_pool_status "$1" "checkpoint" "discarding"
2067eda14cbcSMatt Macy}
2068e639e0d2SMartin Matuskafunction is_pool_replacing #pool
2069e639e0d2SMartin Matuska{
2070e639e0d2SMartin Matuska	zpool status "$1" | grep -qE 'replacing-[0-9]+'
2071e639e0d2SMartin Matuska}
2072eda14cbcSMatt Macy
2073eda14cbcSMatt Macyfunction wait_for_degraded
2074eda14cbcSMatt Macy{
2075eda14cbcSMatt Macy	typeset pool=$1
2076eda14cbcSMatt Macy	typeset timeout=${2:-30}
2077eda14cbcSMatt Macy	typeset t0=$SECONDS
2078eda14cbcSMatt Macy
2079eda14cbcSMatt Macy	while :; do
2080eda14cbcSMatt Macy		[[ $(get_pool_prop health $pool) == "DEGRADED" ]] && break
2081eda14cbcSMatt Macy		log_note "$pool is not yet degraded."
2082eda14cbcSMatt Macy		sleep 1
2083eda14cbcSMatt Macy		if ((SECONDS - t0 > $timeout)); then
2084eda14cbcSMatt Macy			log_note "$pool not degraded after $timeout seconds."
2085eda14cbcSMatt Macy			return 1
2086eda14cbcSMatt Macy		fi
2087eda14cbcSMatt Macy	done
2088eda14cbcSMatt Macy
2089eda14cbcSMatt Macy	return 0
2090eda14cbcSMatt Macy}
2091eda14cbcSMatt Macy
2092eda14cbcSMatt Macy#
2093eda14cbcSMatt Macy# Use create_pool()/destroy_pool() to clean up the information in
2094eda14cbcSMatt Macy# in the given disk to avoid slice overlapping.
2095eda14cbcSMatt Macy#
2096eda14cbcSMatt Macyfunction cleanup_devices #vdevs
2097eda14cbcSMatt Macy{
2098eda14cbcSMatt Macy	typeset pool="foopool$$"
2099eda14cbcSMatt Macy
2100eda14cbcSMatt Macy	for vdev in $@; do
2101eda14cbcSMatt Macy		zero_partitions $vdev
2102eda14cbcSMatt Macy	done
2103eda14cbcSMatt Macy
2104eda14cbcSMatt Macy	poolexists $pool && destroy_pool $pool
2105eda14cbcSMatt Macy	create_pool $pool $@
2106eda14cbcSMatt Macy	destroy_pool $pool
2107eda14cbcSMatt Macy
2108eda14cbcSMatt Macy	return 0
2109eda14cbcSMatt Macy}
2110eda14cbcSMatt Macy
2111eda14cbcSMatt Macy#/**
2112eda14cbcSMatt Macy# A function to find and locate free disks on a system or from given
2113eda14cbcSMatt Macy# disks as the parameter. It works by locating disks that are in use
2114eda14cbcSMatt Macy# as swap devices and dump devices, and also disks listed in /etc/vfstab
2115eda14cbcSMatt Macy#
2116eda14cbcSMatt Macy# $@ given disks to find which are free, default is all disks in
2117eda14cbcSMatt Macy# the test system
2118eda14cbcSMatt Macy#
2119eda14cbcSMatt Macy# @return a string containing the list of available disks
2120eda14cbcSMatt Macy#*/
2121eda14cbcSMatt Macyfunction find_disks
2122eda14cbcSMatt Macy{
2123eda14cbcSMatt Macy	# Trust provided list, no attempt is made to locate unused devices.
2124eda14cbcSMatt Macy	if is_linux || is_freebsd; then
2125eda14cbcSMatt Macy		echo "$@"
2126eda14cbcSMatt Macy		return
2127eda14cbcSMatt Macy	fi
2128eda14cbcSMatt Macy
2129eda14cbcSMatt Macy
2130eda14cbcSMatt Macy	sfi=/tmp/swaplist.$$
2131eda14cbcSMatt Macy	dmpi=/tmp/dumpdev.$$
2132eda14cbcSMatt Macy	max_finddisksnum=${MAX_FINDDISKSNUM:-6}
2133eda14cbcSMatt Macy
2134eda14cbcSMatt Macy	swap -l > $sfi
2135eda14cbcSMatt Macy	dumpadm > $dmpi 2>/dev/null
2136eda14cbcSMatt Macy
2137716fd348SMartin Matuska	disks=${@:-$(echo "" | format -e 2>/dev/null | awk '
2138eda14cbcSMatt MacyBEGIN { FS="."; }
2139eda14cbcSMatt Macy
2140eda14cbcSMatt Macy/^Specify disk/{
2141eda14cbcSMatt Macy	searchdisks=0;
2142eda14cbcSMatt Macy}
2143eda14cbcSMatt Macy
2144eda14cbcSMatt Macy{
2145716fd348SMartin Matuska	if (searchdisks && $2 !~ "^$"){
2146716fd348SMartin Matuska		split($2,arr," ");
2147eda14cbcSMatt Macy		print arr[1];
2148eda14cbcSMatt Macy	}
2149eda14cbcSMatt Macy}
2150eda14cbcSMatt Macy
2151eda14cbcSMatt Macy/^AVAILABLE DISK SELECTIONS:/{
2152eda14cbcSMatt Macy	searchdisks=1;
2153eda14cbcSMatt Macy}
2154716fd348SMartin Matuska')}
2155eda14cbcSMatt Macy
2156eda14cbcSMatt Macy	unused=""
2157eda14cbcSMatt Macy	for disk in $disks; do
2158eda14cbcSMatt Macy	# Check for mounted
2159716fd348SMartin Matuska		grep -q "${disk}[sp]" /etc/mnttab && continue
2160eda14cbcSMatt Macy	# Check for swap
2161716fd348SMartin Matuska		grep -q "${disk}[sp]" $sfi && continue
2162eda14cbcSMatt Macy	# check for dump device
2163716fd348SMartin Matuska		grep -q "${disk}[sp]" $dmpi && continue
2164eda14cbcSMatt Macy	# check to see if this disk hasn't been explicitly excluded
2165eda14cbcSMatt Macy	# by a user-set environment variable
2166716fd348SMartin Matuska		echo "${ZFS_HOST_DEVICES_IGNORE}" | grep -q "${disk}" && continue
2167eda14cbcSMatt Macy		unused_candidates="$unused_candidates $disk"
2168eda14cbcSMatt Macy	done
2169716fd348SMartin Matuska	rm $sfi $dmpi
2170eda14cbcSMatt Macy
2171eda14cbcSMatt Macy# now just check to see if those disks do actually exist
2172eda14cbcSMatt Macy# by looking for a device pointing to the first slice in
2173eda14cbcSMatt Macy# each case. limit the number to max_finddisksnum
2174eda14cbcSMatt Macy	count=0
2175eda14cbcSMatt Macy	for disk in $unused_candidates; do
2176eda14cbcSMatt Macy		if is_disk_device $DEV_DSKDIR/${disk}s0 && \
2177eda14cbcSMatt Macy		    [ $count -lt $max_finddisksnum ]; then
2178eda14cbcSMatt Macy			unused="$unused $disk"
2179eda14cbcSMatt Macy			# do not impose limit if $@ is provided
2180eda14cbcSMatt Macy			[[ -z $@ ]] && ((count = count + 1))
2181eda14cbcSMatt Macy		fi
2182eda14cbcSMatt Macy	done
2183eda14cbcSMatt Macy
2184eda14cbcSMatt Macy# finally, return our disk list
2185eda14cbcSMatt Macy	echo $unused
2186eda14cbcSMatt Macy}
2187eda14cbcSMatt Macy
2188eda14cbcSMatt Macyfunction add_user_freebsd #<group_name> <user_name> <basedir>
2189eda14cbcSMatt Macy{
2190eda14cbcSMatt Macy	typeset group=$1
2191eda14cbcSMatt Macy	typeset user=$2
2192eda14cbcSMatt Macy	typeset basedir=$3
2193eda14cbcSMatt Macy
2194eda14cbcSMatt Macy	# Check to see if the user exists.
2195eda14cbcSMatt Macy	if id $user > /dev/null 2>&1; then
2196eda14cbcSMatt Macy		return 0
2197eda14cbcSMatt Macy	fi
2198eda14cbcSMatt Macy
2199eda14cbcSMatt Macy	# Assign 1000 as the base uid
2200eda14cbcSMatt Macy	typeset -i uid=1000
2201eda14cbcSMatt Macy	while true; do
2202eda14cbcSMatt Macy		pw useradd -u $uid -g $group -d $basedir/$user -m -n $user
2203716fd348SMartin Matuska		case $? in
2204eda14cbcSMatt Macy			0) break ;;
2205eda14cbcSMatt Macy			# The uid is not unique
2206eda14cbcSMatt Macy			65) ((uid += 1)) ;;
2207eda14cbcSMatt Macy			*) return 1 ;;
2208eda14cbcSMatt Macy		esac
2209eda14cbcSMatt Macy		if [[ $uid == 65000 ]]; then
2210eda14cbcSMatt Macy			log_fail "No user id available under 65000 for $user"
2211eda14cbcSMatt Macy		fi
2212eda14cbcSMatt Macy	done
2213eda14cbcSMatt Macy
2214eda14cbcSMatt Macy	# Silence MOTD
2215eda14cbcSMatt Macy	touch $basedir/$user/.hushlogin
2216eda14cbcSMatt Macy
2217eda14cbcSMatt Macy	return 0
2218eda14cbcSMatt Macy}
2219eda14cbcSMatt Macy
2220eda14cbcSMatt Macy#
2221eda14cbcSMatt Macy# Delete the specified user.
2222eda14cbcSMatt Macy#
2223eda14cbcSMatt Macy# $1 login name
2224eda14cbcSMatt Macy#
2225eda14cbcSMatt Macyfunction del_user_freebsd #<logname>
2226eda14cbcSMatt Macy{
2227eda14cbcSMatt Macy	typeset user=$1
2228eda14cbcSMatt Macy
2229eda14cbcSMatt Macy	if id $user > /dev/null 2>&1; then
2230eda14cbcSMatt Macy		log_must pw userdel $user
2231eda14cbcSMatt Macy	fi
2232eda14cbcSMatt Macy
2233eda14cbcSMatt Macy	return 0
2234eda14cbcSMatt Macy}
2235eda14cbcSMatt Macy
2236eda14cbcSMatt Macy#
2237eda14cbcSMatt Macy# Select valid gid and create specified group.
2238eda14cbcSMatt Macy#
2239eda14cbcSMatt Macy# $1 group name
2240eda14cbcSMatt Macy#
2241eda14cbcSMatt Macyfunction add_group_freebsd #<group_name>
2242eda14cbcSMatt Macy{
2243eda14cbcSMatt Macy	typeset group=$1
2244eda14cbcSMatt Macy
2245eda14cbcSMatt Macy	# See if the group already exists.
2246eda14cbcSMatt Macy	if pw groupshow $group >/dev/null 2>&1; then
2247eda14cbcSMatt Macy		return 0
2248eda14cbcSMatt Macy	fi
2249eda14cbcSMatt Macy
2250eda14cbcSMatt Macy	# Assign 1000 as the base gid
2251eda14cbcSMatt Macy	typeset -i gid=1000
2252eda14cbcSMatt Macy	while true; do
2253eda14cbcSMatt Macy		pw groupadd -g $gid -n $group > /dev/null 2>&1
2254716fd348SMartin Matuska		case $? in
2255eda14cbcSMatt Macy			0) return 0 ;;
2256eda14cbcSMatt Macy			# The gid is not  unique
2257eda14cbcSMatt Macy			65) ((gid += 1)) ;;
2258eda14cbcSMatt Macy			*) return 1 ;;
2259eda14cbcSMatt Macy		esac
2260eda14cbcSMatt Macy		if [[ $gid == 65000 ]]; then
2261eda14cbcSMatt Macy			log_fail "No user id available under 65000 for $group"
2262eda14cbcSMatt Macy		fi
2263eda14cbcSMatt Macy	done
2264eda14cbcSMatt Macy}
2265eda14cbcSMatt Macy
2266eda14cbcSMatt Macy#
2267eda14cbcSMatt Macy# Delete the specified group.
2268eda14cbcSMatt Macy#
2269eda14cbcSMatt Macy# $1 group name
2270eda14cbcSMatt Macy#
2271eda14cbcSMatt Macyfunction del_group_freebsd #<group_name>
2272eda14cbcSMatt Macy{
2273eda14cbcSMatt Macy	typeset group=$1
2274eda14cbcSMatt Macy
2275eda14cbcSMatt Macy	pw groupdel -n $group > /dev/null 2>&1
2276716fd348SMartin Matuska	case $? in
2277eda14cbcSMatt Macy		# Group does not exist, or was deleted successfully.
2278eda14cbcSMatt Macy		0|6|65) return 0 ;;
2279eda14cbcSMatt Macy		# Name already exists as a group name
2280eda14cbcSMatt Macy		9) log_must pw groupdel $group ;;
2281eda14cbcSMatt Macy		*) return 1 ;;
2282eda14cbcSMatt Macy	esac
2283eda14cbcSMatt Macy
2284eda14cbcSMatt Macy	return 0
2285eda14cbcSMatt Macy}
2286eda14cbcSMatt Macy
2287eda14cbcSMatt Macyfunction add_user_illumos #<group_name> <user_name> <basedir>
2288eda14cbcSMatt Macy{
2289eda14cbcSMatt Macy	typeset group=$1
2290eda14cbcSMatt Macy	typeset user=$2
2291eda14cbcSMatt Macy	typeset basedir=$3
2292eda14cbcSMatt Macy
2293eda14cbcSMatt Macy	log_must useradd -g $group -d $basedir/$user -m $user
2294eda14cbcSMatt Macy
2295eda14cbcSMatt Macy	return 0
2296eda14cbcSMatt Macy}
2297eda14cbcSMatt Macy
2298eda14cbcSMatt Macyfunction del_user_illumos #<user_name>
2299eda14cbcSMatt Macy{
2300eda14cbcSMatt Macy	typeset user=$1
2301eda14cbcSMatt Macy
2302eda14cbcSMatt Macy	if id $user > /dev/null 2>&1; then
2303eda14cbcSMatt Macy		log_must_retry "currently used" 6 userdel $user
2304eda14cbcSMatt Macy	fi
2305eda14cbcSMatt Macy
2306eda14cbcSMatt Macy	return 0
2307eda14cbcSMatt Macy}
2308eda14cbcSMatt Macy
2309eda14cbcSMatt Macyfunction add_group_illumos #<group_name>
2310eda14cbcSMatt Macy{
2311eda14cbcSMatt Macy	typeset group=$1
2312eda14cbcSMatt Macy
2313eda14cbcSMatt Macy	typeset -i gid=100
2314eda14cbcSMatt Macy	while true; do
2315eda14cbcSMatt Macy		groupadd -g $gid $group > /dev/null 2>&1
2316716fd348SMartin Matuska		case $? in
2317eda14cbcSMatt Macy			0) return 0 ;;
2318eda14cbcSMatt Macy			# The gid is not  unique
2319eda14cbcSMatt Macy			4) ((gid += 1)) ;;
2320eda14cbcSMatt Macy			*) return 1 ;;
2321eda14cbcSMatt Macy		esac
2322eda14cbcSMatt Macy	done
2323eda14cbcSMatt Macy}
2324eda14cbcSMatt Macy
2325eda14cbcSMatt Macyfunction del_group_illumos #<group_name>
2326eda14cbcSMatt Macy{
2327eda14cbcSMatt Macy	typeset group=$1
2328eda14cbcSMatt Macy
2329eda14cbcSMatt Macy	groupmod -n $grp $grp > /dev/null 2>&1
2330716fd348SMartin Matuska	case $? in
2331eda14cbcSMatt Macy		# Group does not exist.
2332eda14cbcSMatt Macy		6) return 0 ;;
2333eda14cbcSMatt Macy		# Name already exists as a group name
2334eda14cbcSMatt Macy		9) log_must groupdel $grp ;;
2335eda14cbcSMatt Macy		*) return 1 ;;
2336eda14cbcSMatt Macy	esac
2337eda14cbcSMatt Macy}
2338eda14cbcSMatt Macy
2339eda14cbcSMatt Macyfunction add_user_linux #<group_name> <user_name> <basedir>
2340eda14cbcSMatt Macy{
2341eda14cbcSMatt Macy	typeset group=$1
2342eda14cbcSMatt Macy	typeset user=$2
2343eda14cbcSMatt Macy	typeset basedir=$3
2344eda14cbcSMatt Macy
2345eda14cbcSMatt Macy	log_must useradd -g $group -d $basedir/$user -m $user
2346eda14cbcSMatt Macy
2347eda14cbcSMatt Macy	# Add new users to the same group and the command line utils.
2348eda14cbcSMatt Macy	# This allows them to be run out of the original users home
2349eda14cbcSMatt Macy	# directory as long as it permissioned to be group readable.
2350716fd348SMartin Matuska	cmd_group=$(stat --format="%G" $(command -v zfs))
2351eda14cbcSMatt Macy	log_must usermod -a -G $cmd_group $user
2352eda14cbcSMatt Macy
2353eda14cbcSMatt Macy	return 0
2354eda14cbcSMatt Macy}
2355eda14cbcSMatt Macy
2356eda14cbcSMatt Macyfunction del_user_linux #<user_name>
2357eda14cbcSMatt Macy{
2358eda14cbcSMatt Macy	typeset user=$1
2359eda14cbcSMatt Macy
2360eda14cbcSMatt Macy	if id $user > /dev/null 2>&1; then
2361eda14cbcSMatt Macy		log_must_retry "currently used" 6 userdel $user
2362eda14cbcSMatt Macy	fi
2363eda14cbcSMatt Macy}
2364eda14cbcSMatt Macy
2365eda14cbcSMatt Macyfunction add_group_linux #<group_name>
2366eda14cbcSMatt Macy{
2367eda14cbcSMatt Macy	typeset group=$1
2368eda14cbcSMatt Macy
2369eda14cbcSMatt Macy	# Assign 100 as the base gid, a larger value is selected for
2370eda14cbcSMatt Macy	# Linux because for many distributions 1000 and under are reserved.
2371eda14cbcSMatt Macy	while true; do
2372eda14cbcSMatt Macy		groupadd $group > /dev/null 2>&1
2373716fd348SMartin Matuska		case $? in
2374eda14cbcSMatt Macy			0) return 0 ;;
2375eda14cbcSMatt Macy			*) return 1 ;;
2376eda14cbcSMatt Macy		esac
2377eda14cbcSMatt Macy	done
2378eda14cbcSMatt Macy}
2379eda14cbcSMatt Macy
2380eda14cbcSMatt Macyfunction del_group_linux #<group_name>
2381eda14cbcSMatt Macy{
2382eda14cbcSMatt Macy	typeset group=$1
2383eda14cbcSMatt Macy
2384eda14cbcSMatt Macy	getent group $group > /dev/null 2>&1
2385716fd348SMartin Matuska	case $? in
2386eda14cbcSMatt Macy		# Group does not exist.
2387eda14cbcSMatt Macy		2) return 0 ;;
2388eda14cbcSMatt Macy		# Name already exists as a group name
2389eda14cbcSMatt Macy		0) log_must groupdel $group ;;
2390eda14cbcSMatt Macy		*) return 1 ;;
2391eda14cbcSMatt Macy	esac
2392eda14cbcSMatt Macy
2393eda14cbcSMatt Macy	return 0
2394eda14cbcSMatt Macy}
2395eda14cbcSMatt Macy
2396eda14cbcSMatt Macy#
2397eda14cbcSMatt Macy# Add specified user to specified group
2398eda14cbcSMatt Macy#
2399eda14cbcSMatt Macy# $1 group name
2400eda14cbcSMatt Macy# $2 user name
2401eda14cbcSMatt Macy# $3 base of the homedir (optional)
2402eda14cbcSMatt Macy#
2403eda14cbcSMatt Macyfunction add_user #<group_name> <user_name> <basedir>
2404eda14cbcSMatt Macy{
2405eda14cbcSMatt Macy	typeset group=$1
2406eda14cbcSMatt Macy	typeset user=$2
2407eda14cbcSMatt Macy	typeset basedir=${3:-"/var/tmp"}
2408eda14cbcSMatt Macy
2409eda14cbcSMatt Macy	if ((${#group} == 0 || ${#user} == 0)); then
2410eda14cbcSMatt Macy		log_fail "group name or user name are not defined."
2411eda14cbcSMatt Macy	fi
2412eda14cbcSMatt Macy
2413716fd348SMartin Matuska	case "$UNAME" in
2414eda14cbcSMatt Macy	FreeBSD)
2415eda14cbcSMatt Macy		add_user_freebsd "$group" "$user" "$basedir"
2416eda14cbcSMatt Macy		;;
2417eda14cbcSMatt Macy	Linux)
2418eda14cbcSMatt Macy		add_user_linux "$group" "$user" "$basedir"
2419eda14cbcSMatt Macy		;;
2420eda14cbcSMatt Macy	*)
2421eda14cbcSMatt Macy		add_user_illumos "$group" "$user" "$basedir"
2422eda14cbcSMatt Macy		;;
2423eda14cbcSMatt Macy	esac
2424eda14cbcSMatt Macy
2425eda14cbcSMatt Macy	return 0
2426eda14cbcSMatt Macy}
2427eda14cbcSMatt Macy
2428eda14cbcSMatt Macy#
2429eda14cbcSMatt Macy# Delete the specified user.
2430eda14cbcSMatt Macy#
2431eda14cbcSMatt Macy# $1 login name
2432eda14cbcSMatt Macy# $2 base of the homedir (optional)
2433eda14cbcSMatt Macy#
2434eda14cbcSMatt Macyfunction del_user #<logname> <basedir>
2435eda14cbcSMatt Macy{
2436eda14cbcSMatt Macy	typeset user=$1
2437eda14cbcSMatt Macy	typeset basedir=${2:-"/var/tmp"}
2438eda14cbcSMatt Macy
2439eda14cbcSMatt Macy	if ((${#user} == 0)); then
2440eda14cbcSMatt Macy		log_fail "login name is necessary."
2441eda14cbcSMatt Macy	fi
2442eda14cbcSMatt Macy
2443716fd348SMartin Matuska	case "$UNAME" in
2444eda14cbcSMatt Macy	FreeBSD)
2445eda14cbcSMatt Macy		del_user_freebsd "$user"
2446eda14cbcSMatt Macy		;;
2447eda14cbcSMatt Macy	Linux)
2448eda14cbcSMatt Macy		del_user_linux "$user"
2449eda14cbcSMatt Macy		;;
2450eda14cbcSMatt Macy	*)
2451eda14cbcSMatt Macy		del_user_illumos "$user"
2452eda14cbcSMatt Macy		;;
2453eda14cbcSMatt Macy	esac
2454eda14cbcSMatt Macy
2455eda14cbcSMatt Macy	[[ -d $basedir/$user ]] && rm -fr $basedir/$user
2456eda14cbcSMatt Macy
2457eda14cbcSMatt Macy	return 0
2458eda14cbcSMatt Macy}
2459eda14cbcSMatt Macy
2460eda14cbcSMatt Macy#
2461eda14cbcSMatt Macy# Select valid gid and create specified group.
2462eda14cbcSMatt Macy#
2463eda14cbcSMatt Macy# $1 group name
2464eda14cbcSMatt Macy#
2465eda14cbcSMatt Macyfunction add_group #<group_name>
2466eda14cbcSMatt Macy{
2467eda14cbcSMatt Macy	typeset group=$1
2468eda14cbcSMatt Macy
2469eda14cbcSMatt Macy	if ((${#group} == 0)); then
2470eda14cbcSMatt Macy		log_fail "group name is necessary."
2471eda14cbcSMatt Macy	fi
2472eda14cbcSMatt Macy
2473716fd348SMartin Matuska	case "$UNAME" in
2474eda14cbcSMatt Macy	FreeBSD)
2475eda14cbcSMatt Macy		add_group_freebsd "$group"
2476eda14cbcSMatt Macy		;;
2477eda14cbcSMatt Macy	Linux)
2478eda14cbcSMatt Macy		add_group_linux "$group"
2479eda14cbcSMatt Macy		;;
2480eda14cbcSMatt Macy	*)
2481eda14cbcSMatt Macy		add_group_illumos "$group"
2482eda14cbcSMatt Macy		;;
2483eda14cbcSMatt Macy	esac
2484eda14cbcSMatt Macy
2485eda14cbcSMatt Macy	return 0
2486eda14cbcSMatt Macy}
2487eda14cbcSMatt Macy
2488eda14cbcSMatt Macy#
2489eda14cbcSMatt Macy# Delete the specified group.
2490eda14cbcSMatt Macy#
2491eda14cbcSMatt Macy# $1 group name
2492eda14cbcSMatt Macy#
2493eda14cbcSMatt Macyfunction del_group #<group_name>
2494eda14cbcSMatt Macy{
2495eda14cbcSMatt Macy	typeset group=$1
2496eda14cbcSMatt Macy
2497eda14cbcSMatt Macy	if ((${#group} == 0)); then
2498eda14cbcSMatt Macy		log_fail "group name is necessary."
2499eda14cbcSMatt Macy	fi
2500eda14cbcSMatt Macy
2501716fd348SMartin Matuska	case "$UNAME" in
2502eda14cbcSMatt Macy	FreeBSD)
2503eda14cbcSMatt Macy		del_group_freebsd "$group"
2504eda14cbcSMatt Macy		;;
2505eda14cbcSMatt Macy	Linux)
2506eda14cbcSMatt Macy		del_group_linux "$group"
2507eda14cbcSMatt Macy		;;
2508eda14cbcSMatt Macy	*)
2509eda14cbcSMatt Macy		del_group_illumos "$group"
2510eda14cbcSMatt Macy		;;
2511eda14cbcSMatt Macy	esac
2512eda14cbcSMatt Macy
2513eda14cbcSMatt Macy	return 0
2514eda14cbcSMatt Macy}
2515eda14cbcSMatt Macy
2516eda14cbcSMatt Macy#
2517eda14cbcSMatt Macy# This function will return true if it's safe to destroy the pool passed
2518eda14cbcSMatt Macy# as argument 1. It checks for pools based on zvols and files, and also
2519eda14cbcSMatt Macy# files contained in a pool that may have a different mountpoint.
2520eda14cbcSMatt Macy#
2521eda14cbcSMatt Macyfunction safe_to_destroy_pool { # $1 the pool name
2522eda14cbcSMatt Macy
2523eda14cbcSMatt Macy	typeset pool=""
2524eda14cbcSMatt Macy	typeset DONT_DESTROY=""
2525eda14cbcSMatt Macy
2526eda14cbcSMatt Macy	# We check that by deleting the $1 pool, we're not
2527eda14cbcSMatt Macy	# going to pull the rug out from other pools. Do this
2528eda14cbcSMatt Macy	# by looking at all other pools, ensuring that they
2529eda14cbcSMatt Macy	# aren't built from files or zvols contained in this pool.
2530eda14cbcSMatt Macy
2531eda14cbcSMatt Macy	for pool in $(zpool list -H -o name)
2532eda14cbcSMatt Macy	do
2533eda14cbcSMatt Macy		ALTMOUNTPOOL=""
2534eda14cbcSMatt Macy
2535eda14cbcSMatt Macy		# this is a list of the top-level directories in each of the
2536eda14cbcSMatt Macy		# files that make up the path to the files the pool is based on
2537716fd348SMartin Matuska		FILEPOOL=$(zpool status -v $pool | awk -v pool="/$1/" '$0 ~ pool {print $1}')
2538eda14cbcSMatt Macy
2539eda14cbcSMatt Macy		# this is a list of the zvols that make up the pool
2540716fd348SMartin Matuska		ZVOLPOOL=$(zpool status -v $pool | awk -v zvols="$ZVOL_DEVDIR/$1$" '$0 ~ zvols {print $1}')
2541eda14cbcSMatt Macy
2542eda14cbcSMatt Macy		# also want to determine if it's a file-based pool using an
2543eda14cbcSMatt Macy		# alternate mountpoint...
2544eda14cbcSMatt Macy		POOL_FILE_DIRS=$(zpool status -v $pool | \
2545716fd348SMartin Matuska					awk '/\// {print $1}' | \
2546716fd348SMartin Matuska					awk -F/ '!/dev/ {print $2}')
2547eda14cbcSMatt Macy
2548eda14cbcSMatt Macy		for pooldir in $POOL_FILE_DIRS
2549eda14cbcSMatt Macy		do
2550eda14cbcSMatt Macy			OUTPUT=$(zfs list -H -r -o mountpoint $1 | \
2551716fd348SMartin Matuska					awk -v pd="${pooldir}$" '$0 ~ pd {print $1}')
2552eda14cbcSMatt Macy
2553eda14cbcSMatt Macy			ALTMOUNTPOOL="${ALTMOUNTPOOL}${OUTPUT}"
2554eda14cbcSMatt Macy		done
2555eda14cbcSMatt Macy
2556eda14cbcSMatt Macy
2557eda14cbcSMatt Macy		if [ ! -z "$ZVOLPOOL" ]
2558eda14cbcSMatt Macy		then
2559eda14cbcSMatt Macy			DONT_DESTROY="true"
2560eda14cbcSMatt Macy			log_note "Pool $pool is built from $ZVOLPOOL on $1"
2561eda14cbcSMatt Macy		fi
2562eda14cbcSMatt Macy
2563eda14cbcSMatt Macy		if [ ! -z "$FILEPOOL" ]
2564eda14cbcSMatt Macy		then
2565eda14cbcSMatt Macy			DONT_DESTROY="true"
2566eda14cbcSMatt Macy			log_note "Pool $pool is built from $FILEPOOL on $1"
2567eda14cbcSMatt Macy		fi
2568eda14cbcSMatt Macy
2569eda14cbcSMatt Macy		if [ ! -z "$ALTMOUNTPOOL" ]
2570eda14cbcSMatt Macy		then
2571eda14cbcSMatt Macy			DONT_DESTROY="true"
2572eda14cbcSMatt Macy			log_note "Pool $pool is built from $ALTMOUNTPOOL on $1"
2573eda14cbcSMatt Macy		fi
2574eda14cbcSMatt Macy	done
2575eda14cbcSMatt Macy
2576eda14cbcSMatt Macy	if [ -z "${DONT_DESTROY}" ]
2577eda14cbcSMatt Macy	then
2578eda14cbcSMatt Macy		return 0
2579eda14cbcSMatt Macy	else
2580eda14cbcSMatt Macy		log_note "Warning: it is not safe to destroy $1!"
2581eda14cbcSMatt Macy		return 1
2582eda14cbcSMatt Macy	fi
2583eda14cbcSMatt Macy}
2584eda14cbcSMatt Macy
2585eda14cbcSMatt Macy#
2586eda14cbcSMatt Macy# Verify zfs operation with -p option work as expected
2587eda14cbcSMatt Macy# $1 operation, value could be create, clone or rename
2588eda14cbcSMatt Macy# $2 dataset type, value could be fs or vol
2589eda14cbcSMatt Macy# $3 dataset name
2590eda14cbcSMatt Macy# $4 new dataset name
2591eda14cbcSMatt Macy#
2592eda14cbcSMatt Macyfunction verify_opt_p_ops
2593eda14cbcSMatt Macy{
2594eda14cbcSMatt Macy	typeset ops=$1
2595eda14cbcSMatt Macy	typeset datatype=$2
2596eda14cbcSMatt Macy	typeset dataset=$3
2597eda14cbcSMatt Macy	typeset newdataset=$4
2598eda14cbcSMatt Macy
2599eda14cbcSMatt Macy	if [[ $datatype != "fs" && $datatype != "vol" ]]; then
2600eda14cbcSMatt Macy		log_fail "$datatype is not supported."
2601eda14cbcSMatt Macy	fi
2602eda14cbcSMatt Macy
2603eda14cbcSMatt Macy	# check parameters accordingly
2604eda14cbcSMatt Macy	case $ops in
2605eda14cbcSMatt Macy		create)
2606eda14cbcSMatt Macy			newdataset=$dataset
2607eda14cbcSMatt Macy			dataset=""
2608eda14cbcSMatt Macy			if [[ $datatype == "vol" ]]; then
2609eda14cbcSMatt Macy				ops="create -V $VOLSIZE"
2610eda14cbcSMatt Macy			fi
2611eda14cbcSMatt Macy			;;
2612eda14cbcSMatt Macy		clone)
2613eda14cbcSMatt Macy			if [[ -z $newdataset ]]; then
2614eda14cbcSMatt Macy				log_fail "newdataset should not be empty" \
2615eda14cbcSMatt Macy					"when ops is $ops."
2616eda14cbcSMatt Macy			fi
2617eda14cbcSMatt Macy			log_must datasetexists $dataset
2618eda14cbcSMatt Macy			log_must snapexists $dataset
2619eda14cbcSMatt Macy			;;
2620eda14cbcSMatt Macy		rename)
2621eda14cbcSMatt Macy			if [[ -z $newdataset ]]; then
2622eda14cbcSMatt Macy				log_fail "newdataset should not be empty" \
2623eda14cbcSMatt Macy					"when ops is $ops."
2624eda14cbcSMatt Macy			fi
2625eda14cbcSMatt Macy			log_must datasetexists $dataset
2626eda14cbcSMatt Macy			;;
2627eda14cbcSMatt Macy		*)
2628eda14cbcSMatt Macy			log_fail "$ops is not supported."
2629eda14cbcSMatt Macy			;;
2630eda14cbcSMatt Macy	esac
2631eda14cbcSMatt Macy
2632eda14cbcSMatt Macy	# make sure the upper level filesystem does not exist
2633eda14cbcSMatt Macy	destroy_dataset "${newdataset%/*}" "-rRf"
2634eda14cbcSMatt Macy
2635eda14cbcSMatt Macy	# without -p option, operation will fail
2636eda14cbcSMatt Macy	log_mustnot zfs $ops $dataset $newdataset
2637eda14cbcSMatt Macy	log_mustnot datasetexists $newdataset ${newdataset%/*}
2638eda14cbcSMatt Macy
2639eda14cbcSMatt Macy	# with -p option, operation should succeed
2640eda14cbcSMatt Macy	log_must zfs $ops -p $dataset $newdataset
2641eda14cbcSMatt Macy	block_device_wait
2642eda14cbcSMatt Macy
2643eda14cbcSMatt Macy	if ! datasetexists $newdataset ; then
2644eda14cbcSMatt Macy		log_fail "-p option does not work for $ops"
2645eda14cbcSMatt Macy	fi
2646eda14cbcSMatt Macy
2647eda14cbcSMatt Macy	# when $ops is create or clone, redo the operation still return zero
2648eda14cbcSMatt Macy	if [[ $ops != "rename" ]]; then
2649eda14cbcSMatt Macy		log_must zfs $ops -p $dataset $newdataset
2650eda14cbcSMatt Macy	fi
2651eda14cbcSMatt Macy
2652eda14cbcSMatt Macy	return 0
2653eda14cbcSMatt Macy}
2654eda14cbcSMatt Macy
2655eda14cbcSMatt Macy#
2656eda14cbcSMatt Macy# Get configuration of pool
2657eda14cbcSMatt Macy# $1 pool name
2658eda14cbcSMatt Macy# $2 config name
2659eda14cbcSMatt Macy#
2660eda14cbcSMatt Macyfunction get_config
2661eda14cbcSMatt Macy{
2662eda14cbcSMatt Macy	typeset pool=$1
2663eda14cbcSMatt Macy	typeset config=$2
2664eda14cbcSMatt Macy
2665eda14cbcSMatt Macy	if ! poolexists "$pool" ; then
2666eda14cbcSMatt Macy		return 1
2667eda14cbcSMatt Macy	fi
2668716fd348SMartin Matuska	if [ "$(get_pool_prop cachefile "$pool")" = "none" ]; then
2669716fd348SMartin Matuska		zdb -e $pool
2670eda14cbcSMatt Macy	else
2671716fd348SMartin Matuska		zdb -C $pool
2672716fd348SMartin Matuska	fi | awk -F: -v cfg="$config:" '$0 ~ cfg {sub(/^'\''/, $2); sub(/'\''$/, $2); print $2}'
2673eda14cbcSMatt Macy}
2674eda14cbcSMatt Macy
2675eda14cbcSMatt Macy#
2676eda14cbcSMatt Macy# Privated function. Random select one of items from arguments.
2677eda14cbcSMatt Macy#
2678eda14cbcSMatt Macy# $1 count
2679eda14cbcSMatt Macy# $2-n string
2680eda14cbcSMatt Macy#
2681eda14cbcSMatt Macyfunction _random_get
2682eda14cbcSMatt Macy{
2683eda14cbcSMatt Macy	typeset cnt=$1
2684eda14cbcSMatt Macy	shift
2685eda14cbcSMatt Macy
2686eda14cbcSMatt Macy	typeset str="$@"
2687eda14cbcSMatt Macy	typeset -i ind
2688eda14cbcSMatt Macy	((ind = RANDOM % cnt + 1))
2689eda14cbcSMatt Macy
2690716fd348SMartin Matuska	echo "$str" | cut -f $ind -d ' '
2691eda14cbcSMatt Macy}
2692eda14cbcSMatt Macy
2693eda14cbcSMatt Macy#
2694eda14cbcSMatt Macy# Random select one of item from arguments which include NONE string
2695eda14cbcSMatt Macy#
2696eda14cbcSMatt Macyfunction random_get_with_non
2697eda14cbcSMatt Macy{
2698eda14cbcSMatt Macy	typeset -i cnt=$#
2699eda14cbcSMatt Macy	((cnt =+ 1))
2700eda14cbcSMatt Macy
2701eda14cbcSMatt Macy	_random_get "$cnt" "$@"
2702eda14cbcSMatt Macy}
2703eda14cbcSMatt Macy
2704eda14cbcSMatt Macy#
2705eda14cbcSMatt Macy# Random select one of item from arguments which doesn't include NONE string
2706eda14cbcSMatt Macy#
2707eda14cbcSMatt Macyfunction random_get
2708eda14cbcSMatt Macy{
2709eda14cbcSMatt Macy	_random_get "$#" "$@"
2710eda14cbcSMatt Macy}
2711eda14cbcSMatt Macy
2712eda14cbcSMatt Macy#
2713eda14cbcSMatt Macy# The function will generate a dataset name with specific length
2714eda14cbcSMatt Macy# $1, the length of the name
2715eda14cbcSMatt Macy# $2, the base string to construct the name
2716eda14cbcSMatt Macy#
2717eda14cbcSMatt Macyfunction gen_dataset_name
2718eda14cbcSMatt Macy{
2719eda14cbcSMatt Macy	typeset -i len=$1
2720eda14cbcSMatt Macy	typeset basestr="$2"
2721eda14cbcSMatt Macy	typeset -i baselen=${#basestr}
2722eda14cbcSMatt Macy	typeset -i iter=0
2723eda14cbcSMatt Macy	typeset l_name=""
2724eda14cbcSMatt Macy
2725eda14cbcSMatt Macy	if ((len % baselen == 0)); then
2726eda14cbcSMatt Macy		((iter = len / baselen))
2727eda14cbcSMatt Macy	else
2728eda14cbcSMatt Macy		((iter = len / baselen + 1))
2729eda14cbcSMatt Macy	fi
2730eda14cbcSMatt Macy	while ((iter > 0)); do
2731eda14cbcSMatt Macy		l_name="${l_name}$basestr"
2732eda14cbcSMatt Macy
2733eda14cbcSMatt Macy		((iter -= 1))
2734eda14cbcSMatt Macy	done
2735eda14cbcSMatt Macy
2736eda14cbcSMatt Macy	echo $l_name
2737eda14cbcSMatt Macy}
2738eda14cbcSMatt Macy
2739eda14cbcSMatt Macy#
2740eda14cbcSMatt Macy# Get cksum tuple of dataset
2741eda14cbcSMatt Macy# $1 dataset name
2742eda14cbcSMatt Macy#
2743eda14cbcSMatt Macy# sample zdb output:
2744eda14cbcSMatt Macy# Dataset data/test [ZPL], ID 355, cr_txg 2413856, 31.0K, 7 objects, rootbp
2745eda14cbcSMatt Macy# DVA[0]=<0:803046400:200> DVA[1]=<0:81199000:200> [L0 DMU objset] fletcher4
2746eda14cbcSMatt Macy# lzjb LE contiguous unique double size=800L/200P birth=2413856L/2413856P
2747eda14cbcSMatt Macy# fill=7 cksum=11ce125712:643a9c18ee2:125e25238fca0:254a3f74b59744
2748eda14cbcSMatt Macyfunction datasetcksum
2749eda14cbcSMatt Macy{
2750eda14cbcSMatt Macy	typeset cksum
2751eda14cbcSMatt Macy	sync
2752e92ffd9bSMartin Matuska	sync_all_pools
2753716fd348SMartin Matuska	zdb -vvv $1 | awk -F= -v ds="^Dataset $1 "'\\[' '$0 ~ ds && /cksum/ {print $7}'
2754eda14cbcSMatt Macy}
2755eda14cbcSMatt Macy
2756eda14cbcSMatt Macy#
2757eda14cbcSMatt Macy# Get the given disk/slice state from the specific field of the pool
2758eda14cbcSMatt Macy#
2759eda14cbcSMatt Macyfunction get_device_state #pool disk field("", "spares","logs")
2760eda14cbcSMatt Macy{
2761eda14cbcSMatt Macy	typeset pool=$1
2762eda14cbcSMatt Macy	typeset disk=${2#$DEV_DSKDIR/}
2763eda14cbcSMatt Macy	typeset field=${3:-$pool}
2764eda14cbcSMatt Macy
2765716fd348SMartin Matuska	zpool status -v "$pool" 2>/dev/null | \
2766716fd348SMartin Matuska		awk -v device=$disk -v pool=$pool -v field=$field \
2767eda14cbcSMatt Macy		'BEGIN {startconfig=0; startfield=0; }
2768eda14cbcSMatt Macy		/config:/ {startconfig=1}
2769eda14cbcSMatt Macy		(startconfig==1) && ($1==field) {startfield=1; next;}
2770eda14cbcSMatt Macy		(startfield==1) && ($1==device) {print $2; exit;}
2771eda14cbcSMatt Macy		(startfield==1) &&
2772716fd348SMartin Matuska		($1==field || $1 ~ "^spares$" || $1 ~ "^logs$") {startfield=0}'
2773eda14cbcSMatt Macy}
2774eda14cbcSMatt Macy
2775eda14cbcSMatt Macy#
2776eda14cbcSMatt Macy# get the root filesystem name if it's zfsroot system.
2777eda14cbcSMatt Macy#
2778eda14cbcSMatt Macy# return: root filesystem name
2779eda14cbcSMatt Macyfunction get_rootfs
2780eda14cbcSMatt Macy{
2781eda14cbcSMatt Macy	typeset rootfs=""
2782eda14cbcSMatt Macy
2783eda14cbcSMatt Macy	if is_freebsd; then
2784eda14cbcSMatt Macy		rootfs=$(mount -p | awk '$2 == "/" && $3 == "zfs" {print $1}')
2785eda14cbcSMatt Macy	elif ! is_linux; then
2786716fd348SMartin Matuska		rootfs=$(awk '$2 == "/" && $3 == "zfs" {print $1}' \
2787eda14cbcSMatt Macy			/etc/mnttab)
2788eda14cbcSMatt Macy	fi
2789eda14cbcSMatt Macy	if [[ -z "$rootfs" ]]; then
2790eda14cbcSMatt Macy		log_fail "Can not get rootfs"
2791eda14cbcSMatt Macy	fi
2792716fd348SMartin Matuska	if datasetexists $rootfs; then
2793eda14cbcSMatt Macy		echo $rootfs
2794eda14cbcSMatt Macy	else
2795eda14cbcSMatt Macy		log_fail "This is not a zfsroot system."
2796eda14cbcSMatt Macy	fi
2797eda14cbcSMatt Macy}
2798eda14cbcSMatt Macy
2799eda14cbcSMatt Macy#
2800eda14cbcSMatt Macy# get the rootfs's pool name
2801eda14cbcSMatt Macy# return:
2802eda14cbcSMatt Macy#       rootpool name
2803eda14cbcSMatt Macy#
2804eda14cbcSMatt Macyfunction get_rootpool
2805eda14cbcSMatt Macy{
2806716fd348SMartin Matuska	typeset rootfs=$(get_rootfs)
2807eda14cbcSMatt Macy	echo ${rootfs%%/*}
2808eda14cbcSMatt Macy}
2809eda14cbcSMatt Macy
2810eda14cbcSMatt Macy#
2811eda14cbcSMatt Macy# To verify if the require numbers of disks is given
2812eda14cbcSMatt Macy#
2813eda14cbcSMatt Macyfunction verify_disk_count
2814eda14cbcSMatt Macy{
2815eda14cbcSMatt Macy	typeset -i min=${2:-1}
2816eda14cbcSMatt Macy
2817716fd348SMartin Matuska	typeset -i count=$(echo "$1" | wc -w)
2818eda14cbcSMatt Macy
2819eda14cbcSMatt Macy	if ((count < min)); then
2820eda14cbcSMatt Macy		log_untested "A minimum of $min disks is required to run." \
2821eda14cbcSMatt Macy			" You specified $count disk(s)"
2822eda14cbcSMatt Macy	fi
2823eda14cbcSMatt Macy}
2824eda14cbcSMatt Macy
2825eda14cbcSMatt Macyfunction ds_is_volume
2826eda14cbcSMatt Macy{
2827eda14cbcSMatt Macy	typeset type=$(get_prop type $1)
2828716fd348SMartin Matuska	[ $type = "volume" ]
2829eda14cbcSMatt Macy}
2830eda14cbcSMatt Macy
2831eda14cbcSMatt Macyfunction ds_is_filesystem
2832eda14cbcSMatt Macy{
2833eda14cbcSMatt Macy	typeset type=$(get_prop type $1)
2834716fd348SMartin Matuska	[ $type = "filesystem" ]
2835eda14cbcSMatt Macy}
2836eda14cbcSMatt Macy
2837eda14cbcSMatt Macy#
2838eda14cbcSMatt Macy# Check if Trusted Extensions are installed and enabled
2839eda14cbcSMatt Macy#
2840eda14cbcSMatt Macyfunction is_te_enabled
2841eda14cbcSMatt Macy{
2842716fd348SMartin Matuska	svcs -H -o state labeld 2>/dev/null | grep -q "enabled"
2843eda14cbcSMatt Macy}
2844eda14cbcSMatt Macy
28451f1e2261SMartin Matuska# Return the number of CPUs (cross-platform)
28461f1e2261SMartin Matuskafunction get_num_cpus
28471f1e2261SMartin Matuska{
28481f1e2261SMartin Matuska	if is_linux ; then
28491f1e2261SMartin Matuska		grep -c '^processor' /proc/cpuinfo
28501f1e2261SMartin Matuska	elif is_freebsd; then
28511f1e2261SMartin Matuska		sysctl -n kern.smp.cpus
28521f1e2261SMartin Matuska	else
28531f1e2261SMartin Matuska		psrinfo | wc -l
28541f1e2261SMartin Matuska	fi
28551f1e2261SMartin Matuska}
28561f1e2261SMartin Matuska
2857eda14cbcSMatt Macy# Utility function to determine if a system has multiple cpus.
2858eda14cbcSMatt Macyfunction is_mp
2859eda14cbcSMatt Macy{
28601f1e2261SMartin Matuska	[[ $(get_num_cpus) -gt 1 ]]
2861eda14cbcSMatt Macy}
2862eda14cbcSMatt Macy
2863eda14cbcSMatt Macyfunction get_cpu_freq
2864eda14cbcSMatt Macy{
2865eda14cbcSMatt Macy	if is_linux; then
2866eda14cbcSMatt Macy		lscpu | awk '/CPU MHz/ { print $3 }'
2867eda14cbcSMatt Macy	elif is_freebsd; then
2868eda14cbcSMatt Macy		sysctl -n hw.clockrate
2869eda14cbcSMatt Macy	else
2870eda14cbcSMatt Macy		psrinfo -v 0 | awk '/processor operates at/ {print $6}'
2871eda14cbcSMatt Macy	fi
2872eda14cbcSMatt Macy}
2873eda14cbcSMatt Macy
2874eda14cbcSMatt Macy# Run the given command as the user provided.
2875eda14cbcSMatt Macyfunction user_run
2876eda14cbcSMatt Macy{
2877eda14cbcSMatt Macy	typeset user=$1
2878eda14cbcSMatt Macy	shift
2879eda14cbcSMatt Macy
28809db44a8eSMartin Matuska	log_note "user: $user"
28819db44a8eSMartin Matuska	log_note "cmd: $*"
28829db44a8eSMartin Matuska
28839db44a8eSMartin Matuska	typeset out=$TEST_BASE_DIR/out
28849db44a8eSMartin Matuska	typeset err=$TEST_BASE_DIR/err
28859db44a8eSMartin Matuska
28869db44a8eSMartin Matuska	sudo -Eu $user env PATH="$PATH" ksh <<<"$*" >$out 2>$err
28879db44a8eSMartin Matuska	typeset res=$?
28889db44a8eSMartin Matuska	log_note "out: $(<$out)"
28899db44a8eSMartin Matuska	log_note "err: $(<$err)"
28909db44a8eSMartin Matuska	return $res
2891eda14cbcSMatt Macy}
2892eda14cbcSMatt Macy
2893eda14cbcSMatt Macy#
2894eda14cbcSMatt Macy# Check if the pool contains the specified vdevs
2895eda14cbcSMatt Macy#
2896eda14cbcSMatt Macy# $1 pool
2897eda14cbcSMatt Macy# $2..n <vdev> ...
2898eda14cbcSMatt Macy#
2899eda14cbcSMatt Macy# Return 0 if the vdevs are contained in the pool, 1 if any of the specified
2900eda14cbcSMatt Macy# vdevs is not in the pool, and 2 if pool name is missing.
2901eda14cbcSMatt Macy#
2902eda14cbcSMatt Macyfunction vdevs_in_pool
2903eda14cbcSMatt Macy{
2904eda14cbcSMatt Macy	typeset pool=$1
2905eda14cbcSMatt Macy	typeset vdev
2906eda14cbcSMatt Macy
2907eda14cbcSMatt Macy	if [[ -z $pool ]]; then
2908eda14cbcSMatt Macy		log_note "Missing pool name."
2909eda14cbcSMatt Macy		return 2
2910eda14cbcSMatt Macy	fi
2911eda14cbcSMatt Macy
2912eda14cbcSMatt Macy	shift
2913eda14cbcSMatt Macy
2914eda14cbcSMatt Macy	# We could use 'zpool list' to only get the vdevs of the pool but we
2915eda14cbcSMatt Macy	# can't reference a mirror/raidz vdev using its ID (i.e mirror-0),
2916eda14cbcSMatt Macy	# therefore we use the 'zpool status' output.
2917eda14cbcSMatt Macy	typeset tmpfile=$(mktemp)
2918eda14cbcSMatt Macy	zpool status -v "$pool" | grep -A 1000 "config:" >$tmpfile
2919716fd348SMartin Matuska	for vdev in "$@"; do
2920716fd348SMartin Matuska		grep -wq ${vdev##*/} $tmpfile || return 1
2921eda14cbcSMatt Macy	done
2922eda14cbcSMatt Macy
2923eda14cbcSMatt Macy	rm -f $tmpfile
2924716fd348SMartin Matuska	return 0
2925eda14cbcSMatt Macy}
2926eda14cbcSMatt Macy
2927eda14cbcSMatt Macyfunction get_max
2928eda14cbcSMatt Macy{
2929eda14cbcSMatt Macy	typeset -l i max=$1
2930eda14cbcSMatt Macy	shift
2931eda14cbcSMatt Macy
2932eda14cbcSMatt Macy	for i in "$@"; do
2933eda14cbcSMatt Macy		max=$((max > i ? max : i))
2934eda14cbcSMatt Macy	done
2935eda14cbcSMatt Macy
2936eda14cbcSMatt Macy	echo $max
2937eda14cbcSMatt Macy}
2938eda14cbcSMatt Macy
2939eda14cbcSMatt Macy# Write data that can be compressed into a directory
2940eda14cbcSMatt Macyfunction write_compressible
2941eda14cbcSMatt Macy{
2942eda14cbcSMatt Macy	typeset dir=$1
2943eda14cbcSMatt Macy	typeset megs=$2
2944eda14cbcSMatt Macy	typeset nfiles=${3:-1}
2945eda14cbcSMatt Macy	typeset bs=${4:-1024k}
2946eda14cbcSMatt Macy	typeset fname=${5:-file}
2947eda14cbcSMatt Macy
2948eda14cbcSMatt Macy	[[ -d $dir ]] || log_fail "No directory: $dir"
2949eda14cbcSMatt Macy
2950eda14cbcSMatt Macy	# Under Linux fio is not currently used since its behavior can
2951eda14cbcSMatt Macy	# differ significantly across versions.  This includes missing
2952eda14cbcSMatt Macy	# command line options and cases where the --buffer_compress_*
2953eda14cbcSMatt Macy	# options fail to behave as expected.
2954eda14cbcSMatt Macy	if is_linux; then
2955eda14cbcSMatt Macy		typeset file_bytes=$(to_bytes $megs)
2956eda14cbcSMatt Macy		typeset bs_bytes=4096
2957eda14cbcSMatt Macy		typeset blocks=$(($file_bytes / $bs_bytes))
2958eda14cbcSMatt Macy
2959eda14cbcSMatt Macy		for (( i = 0; i < $nfiles; i++ )); do
2960eda14cbcSMatt Macy			truncate -s $file_bytes $dir/$fname.$i
2961eda14cbcSMatt Macy
2962eda14cbcSMatt Macy			# Write every third block to get 66% compression.
2963eda14cbcSMatt Macy			for (( j = 0; j < $blocks; j += 3 )); do
2964eda14cbcSMatt Macy				dd if=/dev/urandom of=$dir/$fname.$i \
2965eda14cbcSMatt Macy				    seek=$j bs=$bs_bytes count=1 \
2966eda14cbcSMatt Macy				    conv=notrunc >/dev/null 2>&1
2967eda14cbcSMatt Macy			done
2968eda14cbcSMatt Macy		done
2969eda14cbcSMatt Macy	else
2970716fd348SMartin Matuska		command -v fio > /dev/null || log_unsupported "fio missing"
2971716fd348SMartin Matuska		log_must eval fio \
2972eda14cbcSMatt Macy		    --name=job \
2973eda14cbcSMatt Macy		    --fallocate=0 \
2974eda14cbcSMatt Macy		    --minimal \
2975eda14cbcSMatt Macy		    --randrepeat=0 \
2976eda14cbcSMatt Macy		    --buffer_compress_percentage=66 \
2977eda14cbcSMatt Macy		    --buffer_compress_chunk=4096 \
2978716fd348SMartin Matuska		    --directory="$dir" \
2979716fd348SMartin Matuska		    --numjobs="$nfiles" \
2980716fd348SMartin Matuska		    --nrfiles="$nfiles" \
2981eda14cbcSMatt Macy		    --rw=write \
2982716fd348SMartin Matuska		    --bs="$bs" \
2983716fd348SMartin Matuska		    --filesize="$megs" \
2984716fd348SMartin Matuska		    "--filename_format='$fname.\$jobnum' >/dev/null"
2985eda14cbcSMatt Macy	fi
2986eda14cbcSMatt Macy}
2987eda14cbcSMatt Macy
2988eda14cbcSMatt Macyfunction get_objnum
2989eda14cbcSMatt Macy{
2990eda14cbcSMatt Macy	typeset pathname=$1
2991eda14cbcSMatt Macy	typeset objnum
2992eda14cbcSMatt Macy
2993eda14cbcSMatt Macy	[[ -e $pathname ]] || log_fail "No such file or directory: $pathname"
2994eda14cbcSMatt Macy	if is_freebsd; then
2995eda14cbcSMatt Macy		objnum=$(stat -f "%i" $pathname)
2996eda14cbcSMatt Macy	else
2997eda14cbcSMatt Macy		objnum=$(stat -c %i $pathname)
2998eda14cbcSMatt Macy	fi
2999eda14cbcSMatt Macy	echo $objnum
3000eda14cbcSMatt Macy}
3001eda14cbcSMatt Macy
3002eda14cbcSMatt Macy#
3003eda14cbcSMatt Macy# Sync data to the pool
3004eda14cbcSMatt Macy#
3005eda14cbcSMatt Macy# $1 pool name
3006eda14cbcSMatt Macy# $2 boolean to force uberblock (and config including zpool cache file) update
3007eda14cbcSMatt Macy#
3008eda14cbcSMatt Macyfunction sync_pool #pool <force>
3009eda14cbcSMatt Macy{
3010eda14cbcSMatt Macy	typeset pool=${1:-$TESTPOOL}
3011eda14cbcSMatt Macy	typeset force=${2:-false}
3012eda14cbcSMatt Macy
3013eda14cbcSMatt Macy	if [[ $force == true ]]; then
3014eda14cbcSMatt Macy		log_must zpool sync -f $pool
3015eda14cbcSMatt Macy	else
3016eda14cbcSMatt Macy		log_must zpool sync $pool
3017eda14cbcSMatt Macy	fi
3018eda14cbcSMatt Macy
3019eda14cbcSMatt Macy	return 0
3020eda14cbcSMatt Macy}
3021eda14cbcSMatt Macy
3022eda14cbcSMatt Macy#
3023e92ffd9bSMartin Matuska# Sync all pools
3024e92ffd9bSMartin Matuska#
3025e92ffd9bSMartin Matuska# $1 boolean to force uberblock (and config including zpool cache file) update
3026e92ffd9bSMartin Matuska#
3027e92ffd9bSMartin Matuskafunction sync_all_pools #<force>
3028e92ffd9bSMartin Matuska{
3029e92ffd9bSMartin Matuska	typeset force=${1:-false}
3030e92ffd9bSMartin Matuska
3031e92ffd9bSMartin Matuska	if [[ $force == true ]]; then
3032e92ffd9bSMartin Matuska		log_must zpool sync -f
3033e92ffd9bSMartin Matuska	else
3034e92ffd9bSMartin Matuska		log_must zpool sync
3035e92ffd9bSMartin Matuska	fi
3036e92ffd9bSMartin Matuska
3037e92ffd9bSMartin Matuska	return 0
3038e92ffd9bSMartin Matuska}
3039e92ffd9bSMartin Matuska
3040e92ffd9bSMartin Matuska#
3041eda14cbcSMatt Macy# Wait for zpool 'freeing' property drops to zero.
3042eda14cbcSMatt Macy#
3043eda14cbcSMatt Macy# $1 pool name
3044eda14cbcSMatt Macy#
3045eda14cbcSMatt Macyfunction wait_freeing #pool
3046eda14cbcSMatt Macy{
3047eda14cbcSMatt Macy	typeset pool=${1:-$TESTPOOL}
3048eda14cbcSMatt Macy	while true; do
3049eda14cbcSMatt Macy		[[ "0" == "$(zpool list -Ho freeing $pool)" ]] && break
3050eda14cbcSMatt Macy		log_must sleep 1
3051eda14cbcSMatt Macy	done
3052eda14cbcSMatt Macy}
3053eda14cbcSMatt Macy
3054eda14cbcSMatt Macy#
3055eda14cbcSMatt Macy# Wait for every device replace operation to complete
3056eda14cbcSMatt Macy#
3057eda14cbcSMatt Macy# $1 pool name
3058e639e0d2SMartin Matuska# $2 timeout
3059eda14cbcSMatt Macy#
3060e639e0d2SMartin Matuskafunction wait_replacing #pool timeout
3061eda14cbcSMatt Macy{
3062e639e0d2SMartin Matuska	typeset timeout=${2:-300}
3063eda14cbcSMatt Macy	typeset pool=${1:-$TESTPOOL}
3064e639e0d2SMartin Matuska	for (( timer = 0; timer < $timeout; timer++ )); do
3065e639e0d2SMartin Matuska		is_pool_replacing $pool || break;
3066e639e0d2SMartin Matuska		sleep 1;
3067eda14cbcSMatt Macy	done
3068eda14cbcSMatt Macy}
3069eda14cbcSMatt Macy
3070eda14cbcSMatt Macy# Wait for a pool to be scrubbed
3071eda14cbcSMatt Macy#
3072eda14cbcSMatt Macy# $1 pool name
3073c03c5b1cSMartin Matuska# $2 timeout
3074eda14cbcSMatt Macy#
3075c03c5b1cSMartin Matuskafunction wait_scrubbed #pool timeout
3076eda14cbcSMatt Macy{
3077c03c5b1cSMartin Matuska       typeset timeout=${2:-300}
3078eda14cbcSMatt Macy       typeset pool=${1:-$TESTPOOL}
3079c03c5b1cSMartin Matuska       for (( timer = 0; timer < $timeout; timer++ )); do
3080c03c5b1cSMartin Matuska               is_pool_scrubbed $pool && break;
3081c03c5b1cSMartin Matuska               sleep 1;
3082eda14cbcSMatt Macy       done
3083eda14cbcSMatt Macy}
3084eda14cbcSMatt Macy
3085eda14cbcSMatt Macy# Backup the zed.rc in our test directory so that we can edit it for our test.
3086eda14cbcSMatt Macy#
3087eda14cbcSMatt Macy# Returns: Backup file name.  You will need to pass this to zed_rc_restore().
3088eda14cbcSMatt Macyfunction zed_rc_backup
3089eda14cbcSMatt Macy{
3090eda14cbcSMatt Macy	zedrc_backup="$(mktemp)"
3091eda14cbcSMatt Macy	cp $ZEDLET_DIR/zed.rc $zedrc_backup
3092eda14cbcSMatt Macy	echo $zedrc_backup
3093eda14cbcSMatt Macy}
3094eda14cbcSMatt Macy
3095eda14cbcSMatt Macyfunction zed_rc_restore
3096eda14cbcSMatt Macy{
3097eda14cbcSMatt Macy	mv $1 $ZEDLET_DIR/zed.rc
3098eda14cbcSMatt Macy}
3099eda14cbcSMatt Macy
3100eda14cbcSMatt Macy#
3101eda14cbcSMatt Macy# Setup custom environment for the ZED.
3102eda14cbcSMatt Macy#
3103eda14cbcSMatt Macy# $@ Optional list of zedlets to run under zed.
3104eda14cbcSMatt Macyfunction zed_setup
3105eda14cbcSMatt Macy{
3106eda14cbcSMatt Macy	if ! is_linux; then
3107716fd348SMartin Matuska		log_unsupported "No zed on $UNAME"
3108eda14cbcSMatt Macy	fi
3109eda14cbcSMatt Macy
3110eda14cbcSMatt Macy	if [[ ! -d $ZEDLET_DIR ]]; then
3111eda14cbcSMatt Macy		log_must mkdir $ZEDLET_DIR
3112eda14cbcSMatt Macy	fi
3113eda14cbcSMatt Macy
3114eda14cbcSMatt Macy	if [[ ! -e $VDEVID_CONF ]]; then
3115eda14cbcSMatt Macy		log_must touch $VDEVID_CONF
3116eda14cbcSMatt Macy	fi
3117eda14cbcSMatt Macy
3118eda14cbcSMatt Macy	if [[ -e $VDEVID_CONF_ETC ]]; then
3119eda14cbcSMatt Macy		log_fail "Must not have $VDEVID_CONF_ETC file present on system"
3120eda14cbcSMatt Macy	fi
3121eda14cbcSMatt Macy	EXTRA_ZEDLETS=$@
3122eda14cbcSMatt Macy
3123eda14cbcSMatt Macy	# Create a symlink for /etc/zfs/vdev_id.conf file.
3124eda14cbcSMatt Macy	log_must ln -s $VDEVID_CONF $VDEVID_CONF_ETC
3125eda14cbcSMatt Macy
3126eda14cbcSMatt Macy	# Setup minimal ZED configuration.  Individual test cases should
3127eda14cbcSMatt Macy	# add additional ZEDLETs as needed for their specific test.
3128eda14cbcSMatt Macy	log_must cp ${ZEDLET_ETC_DIR}/zed.rc $ZEDLET_DIR
3129eda14cbcSMatt Macy	log_must cp ${ZEDLET_ETC_DIR}/zed-functions.sh $ZEDLET_DIR
3130eda14cbcSMatt Macy
3131eda14cbcSMatt Macy	# Scripts must only be user writable.
3132eda14cbcSMatt Macy	if [[ -n "$EXTRA_ZEDLETS" ]] ; then
3133eda14cbcSMatt Macy		saved_umask=$(umask)
3134eda14cbcSMatt Macy		log_must umask 0022
3135eda14cbcSMatt Macy		for i in $EXTRA_ZEDLETS ; do
3136eda14cbcSMatt Macy			log_must cp ${ZEDLET_LIBEXEC_DIR}/$i $ZEDLET_DIR
3137eda14cbcSMatt Macy		done
3138eda14cbcSMatt Macy		log_must umask $saved_umask
3139eda14cbcSMatt Macy	fi
3140eda14cbcSMatt Macy
3141eda14cbcSMatt Macy	# Customize the zed.rc file to enable the full debug log.
3142eda14cbcSMatt Macy	log_must sed -i '/\#ZED_DEBUG_LOG=.*/d' $ZEDLET_DIR/zed.rc
3143eda14cbcSMatt Macy	echo "ZED_DEBUG_LOG=$ZED_DEBUG_LOG" >>$ZEDLET_DIR/zed.rc
3144eda14cbcSMatt Macy
3145eda14cbcSMatt Macy}
3146eda14cbcSMatt Macy
3147eda14cbcSMatt Macy#
3148eda14cbcSMatt Macy# Cleanup custom ZED environment.
3149eda14cbcSMatt Macy#
3150eda14cbcSMatt Macy# $@ Optional list of zedlets to remove from our test zed.d directory.
3151eda14cbcSMatt Macyfunction zed_cleanup
3152eda14cbcSMatt Macy{
3153eda14cbcSMatt Macy	if ! is_linux; then
3154eda14cbcSMatt Macy		return
3155eda14cbcSMatt Macy	fi
3156eda14cbcSMatt Macy
3157716fd348SMartin Matuska	for extra_zedlet; do
3158716fd348SMartin Matuska		log_must rm -f ${ZEDLET_DIR}/$extra_zedlet
3159eda14cbcSMatt Macy	done
3160716fd348SMartin Matuska	log_must rm -fd ${ZEDLET_DIR}/zed.rc ${ZEDLET_DIR}/zed-functions.sh ${ZEDLET_DIR}/all-syslog.sh ${ZEDLET_DIR}/all-debug.sh ${ZEDLET_DIR}/state \
3161716fd348SMartin Matuska	                $ZED_LOG $ZED_DEBUG_LOG $VDEVID_CONF_ETC $VDEVID_CONF \
3162716fd348SMartin Matuska	                $ZEDLET_DIR
3163eda14cbcSMatt Macy}
3164eda14cbcSMatt Macy
3165eda14cbcSMatt Macy#
3166c03c5b1cSMartin Matuska# Check if ZED is currently running; if so, returns PIDs
3167c03c5b1cSMartin Matuska#
3168c03c5b1cSMartin Matuskafunction zed_check
3169c03c5b1cSMartin Matuska{
3170c03c5b1cSMartin Matuska	if ! is_linux; then
3171c03c5b1cSMartin Matuska		return
3172c03c5b1cSMartin Matuska	fi
3173c03c5b1cSMartin Matuska	zedpids="$(pgrep -x zed)"
3174c03c5b1cSMartin Matuska	zedpids2="$(pgrep -x lt-zed)"
3175c03c5b1cSMartin Matuska	echo ${zedpids} ${zedpids2}
3176c03c5b1cSMartin Matuska}
3177c03c5b1cSMartin Matuska
3178c03c5b1cSMartin Matuska#
3179eda14cbcSMatt Macy# Check if ZED is currently running, if not start ZED.
3180eda14cbcSMatt Macy#
3181eda14cbcSMatt Macyfunction zed_start
3182eda14cbcSMatt Macy{
3183eda14cbcSMatt Macy	if ! is_linux; then
3184eda14cbcSMatt Macy		return
3185eda14cbcSMatt Macy	fi
3186eda14cbcSMatt Macy
3187eda14cbcSMatt Macy	# ZEDLET_DIR=/var/tmp/zed
3188eda14cbcSMatt Macy	if [[ ! -d $ZEDLET_DIR ]]; then
3189eda14cbcSMatt Macy		log_must mkdir $ZEDLET_DIR
3190eda14cbcSMatt Macy	fi
3191eda14cbcSMatt Macy
3192eda14cbcSMatt Macy	# Verify the ZED is not already running.
3193c03c5b1cSMartin Matuska	zedpids=$(zed_check)
3194c03c5b1cSMartin Matuska	if [ -n "$zedpids" ]; then
3195c03c5b1cSMartin Matuska		# We never, ever, really want it to just keep going if zed
3196c03c5b1cSMartin Matuska		# is already running - usually this implies our test cases
3197c03c5b1cSMartin Matuska		# will break very strangely because whatever we wanted to
3198c03c5b1cSMartin Matuska		# configure zed for won't be listening to our changes in the
3199c03c5b1cSMartin Matuska		# tmpdir
3200c03c5b1cSMartin Matuska		log_fail "ZED already running - ${zedpids}"
3201eda14cbcSMatt Macy	else
3202eda14cbcSMatt Macy		log_note "Starting ZED"
3203eda14cbcSMatt Macy		# run ZED in the background and redirect foreground logging
3204eda14cbcSMatt Macy		# output to $ZED_LOG.
3205eda14cbcSMatt Macy		log_must truncate -s 0 $ZED_DEBUG_LOG
320616038816SMartin Matuska		log_must eval "zed -vF -d $ZEDLET_DIR -P $PATH" \
320716038816SMartin Matuska		    "-s $ZEDLET_DIR/state -j 1 2>$ZED_LOG &"
3208eda14cbcSMatt Macy	fi
3209eda14cbcSMatt Macy
3210eda14cbcSMatt Macy	return 0
3211eda14cbcSMatt Macy}
3212eda14cbcSMatt Macy
3213eda14cbcSMatt Macy#
3214eda14cbcSMatt Macy# Kill ZED process
3215eda14cbcSMatt Macy#
3216eda14cbcSMatt Macyfunction zed_stop
3217eda14cbcSMatt Macy{
3218eda14cbcSMatt Macy	if ! is_linux; then
3219c03c5b1cSMartin Matuska		return ""
3220eda14cbcSMatt Macy	fi
3221eda14cbcSMatt Macy
3222eda14cbcSMatt Macy	log_note "Stopping ZED"
322316038816SMartin Matuska	while true; do
3224c03c5b1cSMartin Matuska		zedpids=$(zed_check)
3225c03c5b1cSMartin Matuska		[ ! -n "$zedpids" ] && break
322616038816SMartin Matuska
322716038816SMartin Matuska		log_must kill $zedpids
3228eda14cbcSMatt Macy		sleep 1
3229eda14cbcSMatt Macy	done
3230eda14cbcSMatt Macy	return 0
3231eda14cbcSMatt Macy}
3232eda14cbcSMatt Macy
3233eda14cbcSMatt Macy#
3234eda14cbcSMatt Macy# Drain all zevents
3235eda14cbcSMatt Macy#
3236eda14cbcSMatt Macyfunction zed_events_drain
3237eda14cbcSMatt Macy{
3238eda14cbcSMatt Macy	while [ $(zpool events -H | wc -l) -ne 0 ]; do
3239eda14cbcSMatt Macy		sleep 1
3240eda14cbcSMatt Macy		zpool events -c >/dev/null
3241eda14cbcSMatt Macy	done
3242eda14cbcSMatt Macy}
3243eda14cbcSMatt Macy
3244eda14cbcSMatt Macy# Set a variable in zed.rc to something, un-commenting it in the process.
3245eda14cbcSMatt Macy#
3246eda14cbcSMatt Macy# $1 variable
3247eda14cbcSMatt Macy# $2 value
3248eda14cbcSMatt Macyfunction zed_rc_set
3249eda14cbcSMatt Macy{
3250eda14cbcSMatt Macy	var="$1"
3251eda14cbcSMatt Macy	val="$2"
3252eda14cbcSMatt Macy	# Remove the line
3253eda14cbcSMatt Macy	cmd="'/$var/d'"
3254eda14cbcSMatt Macy	eval sed -i $cmd $ZEDLET_DIR/zed.rc
3255eda14cbcSMatt Macy
3256eda14cbcSMatt Macy	# Add it at the end
3257eda14cbcSMatt Macy	echo "$var=$val" >> $ZEDLET_DIR/zed.rc
3258eda14cbcSMatt Macy}
3259eda14cbcSMatt Macy
3260eda14cbcSMatt Macy
3261eda14cbcSMatt Macy#
3262eda14cbcSMatt Macy# Check is provided device is being active used as a swap device.
3263eda14cbcSMatt Macy#
3264eda14cbcSMatt Macyfunction is_swap_inuse
3265eda14cbcSMatt Macy{
3266eda14cbcSMatt Macy	typeset device=$1
3267eda14cbcSMatt Macy
3268eda14cbcSMatt Macy	if [[ -z $device ]] ; then
3269eda14cbcSMatt Macy		log_note "No device specified."
3270eda14cbcSMatt Macy		return 1
3271eda14cbcSMatt Macy	fi
3272eda14cbcSMatt Macy
3273716fd348SMartin Matuska	case "$UNAME" in
3274716fd348SMartin Matuska	Linux)
3275716fd348SMartin Matuska		swapon -s | grep -wq $(readlink -f $device)
3276716fd348SMartin Matuska		;;
3277716fd348SMartin Matuska	FreeBSD)
3278716fd348SMartin Matuska		swapctl -l | grep -wq $device
3279716fd348SMartin Matuska		;;
3280716fd348SMartin Matuska	*)
3281716fd348SMartin Matuska		swap -l | grep -wq $device
3282716fd348SMartin Matuska		;;
3283716fd348SMartin Matuska	esac
3284eda14cbcSMatt Macy}
3285eda14cbcSMatt Macy
3286eda14cbcSMatt Macy#
3287eda14cbcSMatt Macy# Setup a swap device using the provided device.
3288eda14cbcSMatt Macy#
3289eda14cbcSMatt Macyfunction swap_setup
3290eda14cbcSMatt Macy{
3291eda14cbcSMatt Macy	typeset swapdev=$1
3292eda14cbcSMatt Macy
3293716fd348SMartin Matuska	case "$UNAME" in
3294716fd348SMartin Matuska	Linux)
3295eda14cbcSMatt Macy		log_must eval "mkswap $swapdev > /dev/null 2>&1"
3296eda14cbcSMatt Macy		log_must swapon $swapdev
3297716fd348SMartin Matuska		;;
3298716fd348SMartin Matuska	FreeBSD)
3299eda14cbcSMatt Macy		log_must swapctl -a $swapdev
3300716fd348SMartin Matuska		;;
3301716fd348SMartin Matuska	*)
3302eda14cbcSMatt Macy    log_must swap -a $swapdev
3303716fd348SMartin Matuska		;;
3304716fd348SMartin Matuska	esac
3305eda14cbcSMatt Macy
3306eda14cbcSMatt Macy	return 0
3307eda14cbcSMatt Macy}
3308eda14cbcSMatt Macy
3309eda14cbcSMatt Macy#
3310eda14cbcSMatt Macy# Cleanup a swap device on the provided device.
3311eda14cbcSMatt Macy#
3312eda14cbcSMatt Macyfunction swap_cleanup
3313eda14cbcSMatt Macy{
3314eda14cbcSMatt Macy	typeset swapdev=$1
3315eda14cbcSMatt Macy
3316eda14cbcSMatt Macy	if is_swap_inuse $swapdev; then
3317eda14cbcSMatt Macy		if is_linux; then
3318eda14cbcSMatt Macy			log_must swapoff $swapdev
3319eda14cbcSMatt Macy		elif is_freebsd; then
3320eda14cbcSMatt Macy			log_must swapoff $swapdev
3321eda14cbcSMatt Macy		else
3322eda14cbcSMatt Macy			log_must swap -d $swapdev
3323eda14cbcSMatt Macy		fi
3324eda14cbcSMatt Macy	fi
3325eda14cbcSMatt Macy
3326eda14cbcSMatt Macy	return 0
3327eda14cbcSMatt Macy}
3328eda14cbcSMatt Macy
3329eda14cbcSMatt Macy#
3330eda14cbcSMatt Macy# Set a global system tunable (64-bit value)
3331eda14cbcSMatt Macy#
3332eda14cbcSMatt Macy# $1 tunable name (use a NAME defined in tunables.cfg)
3333eda14cbcSMatt Macy# $2 tunable values
3334eda14cbcSMatt Macy#
3335eda14cbcSMatt Macyfunction set_tunable64
3336eda14cbcSMatt Macy{
3337eda14cbcSMatt Macy	set_tunable_impl "$1" "$2" Z
3338eda14cbcSMatt Macy}
3339eda14cbcSMatt Macy
3340eda14cbcSMatt Macy#
3341eda14cbcSMatt Macy# Set a global system tunable (32-bit value)
3342eda14cbcSMatt Macy#
3343eda14cbcSMatt Macy# $1 tunable name (use a NAME defined in tunables.cfg)
3344eda14cbcSMatt Macy# $2 tunable values
3345eda14cbcSMatt Macy#
3346eda14cbcSMatt Macyfunction set_tunable32
3347eda14cbcSMatt Macy{
3348eda14cbcSMatt Macy	set_tunable_impl "$1" "$2" W
3349eda14cbcSMatt Macy}
3350eda14cbcSMatt Macy
3351eda14cbcSMatt Macyfunction set_tunable_impl
3352eda14cbcSMatt Macy{
3353eda14cbcSMatt Macy	typeset name="$1"
3354eda14cbcSMatt Macy	typeset value="$2"
3355eda14cbcSMatt Macy	typeset mdb_cmd="$3"
3356eda14cbcSMatt Macy
3357eda14cbcSMatt Macy	eval "typeset tunable=\$$name"
3358eda14cbcSMatt Macy	case "$tunable" in
3359eda14cbcSMatt Macy	UNSUPPORTED)
3360716fd348SMartin Matuska		log_unsupported "Tunable '$name' is unsupported on $UNAME"
3361eda14cbcSMatt Macy		;;
3362eda14cbcSMatt Macy	"")
3363eda14cbcSMatt Macy		log_fail "Tunable '$name' must be added to tunables.cfg"
3364eda14cbcSMatt Macy		;;
3365eda14cbcSMatt Macy	*)
3366eda14cbcSMatt Macy		;;
3367eda14cbcSMatt Macy	esac
3368eda14cbcSMatt Macy
3369eda14cbcSMatt Macy	[[ -z "$value" ]] && return 1
3370eda14cbcSMatt Macy	[[ -z "$mdb_cmd" ]] && return 1
3371eda14cbcSMatt Macy
3372716fd348SMartin Matuska	case "$UNAME" in
3373eda14cbcSMatt Macy	Linux)
3374716fd348SMartin Matuska		typeset zfs_tunables="/sys/module/zfs/parameters"
3375716fd348SMartin Matuska		echo "$value" >"$zfs_tunables/$tunable"
3376eda14cbcSMatt Macy		;;
3377eda14cbcSMatt Macy	FreeBSD)
3378eda14cbcSMatt Macy		sysctl vfs.zfs.$tunable=$value
3379eda14cbcSMatt Macy		;;
3380eda14cbcSMatt Macy	SunOS)
3381eda14cbcSMatt Macy		echo "${tunable}/${mdb_cmd}0t${value}" | mdb -kw
3382eda14cbcSMatt Macy		;;
3383eda14cbcSMatt Macy	esac
3384eda14cbcSMatt Macy}
3385eda14cbcSMatt Macy
338647bb16f8SMartin Matuskafunction save_tunable
338747bb16f8SMartin Matuska{
338847bb16f8SMartin Matuska	[[ ! -d $TEST_BASE_DIR ]] && return 1
338947bb16f8SMartin Matuska	[[ -e $TEST_BASE_DIR/tunable-$1 ]] && return 2
339047bb16f8SMartin Matuska	echo "$(get_tunable """$1""")" > "$TEST_BASE_DIR"/tunable-"$1"
339147bb16f8SMartin Matuska}
339247bb16f8SMartin Matuska
339347bb16f8SMartin Matuskafunction restore_tunable
339447bb16f8SMartin Matuska{
339547bb16f8SMartin Matuska	[[ ! -e $TEST_BASE_DIR/tunable-$1 ]] && return 1
339647bb16f8SMartin Matuska	val="$(cat $TEST_BASE_DIR/tunable-"""$1""")"
339747bb16f8SMartin Matuska	set_tunable64 "$1" "$val"
339847bb16f8SMartin Matuska	rm $TEST_BASE_DIR/tunable-$1
339947bb16f8SMartin Matuska}
340047bb16f8SMartin Matuska
3401eda14cbcSMatt Macy#
3402eda14cbcSMatt Macy# Get a global system tunable
3403eda14cbcSMatt Macy#
3404eda14cbcSMatt Macy# $1 tunable name (use a NAME defined in tunables.cfg)
3405eda14cbcSMatt Macy#
3406eda14cbcSMatt Macyfunction get_tunable
3407eda14cbcSMatt Macy{
3408eda14cbcSMatt Macy	get_tunable_impl "$1"
3409eda14cbcSMatt Macy}
3410eda14cbcSMatt Macy
3411eda14cbcSMatt Macyfunction get_tunable_impl
3412eda14cbcSMatt Macy{
3413eda14cbcSMatt Macy	typeset name="$1"
3414eda14cbcSMatt Macy	typeset module="${2:-zfs}"
34151f1e2261SMartin Matuska	typeset check_only="$3"
3416eda14cbcSMatt Macy
3417eda14cbcSMatt Macy	eval "typeset tunable=\$$name"
3418eda14cbcSMatt Macy	case "$tunable" in
3419eda14cbcSMatt Macy	UNSUPPORTED)
34201f1e2261SMartin Matuska		if [ -z "$check_only" ] ; then
3421716fd348SMartin Matuska			log_unsupported "Tunable '$name' is unsupported on $UNAME"
34221f1e2261SMartin Matuska		else
34231f1e2261SMartin Matuska			return 1
34241f1e2261SMartin Matuska		fi
3425eda14cbcSMatt Macy		;;
3426eda14cbcSMatt Macy	"")
34271f1e2261SMartin Matuska		if [ -z "$check_only" ] ; then
3428eda14cbcSMatt Macy			log_fail "Tunable '$name' must be added to tunables.cfg"
34291f1e2261SMartin Matuska		else
34301f1e2261SMartin Matuska			return 1
34311f1e2261SMartin Matuska		fi
3432eda14cbcSMatt Macy		;;
3433eda14cbcSMatt Macy	*)
3434eda14cbcSMatt Macy		;;
3435eda14cbcSMatt Macy	esac
3436eda14cbcSMatt Macy
3437716fd348SMartin Matuska	case "$UNAME" in
3438eda14cbcSMatt Macy	Linux)
3439eda14cbcSMatt Macy		typeset zfs_tunables="/sys/module/$module/parameters"
3440eda14cbcSMatt Macy		cat $zfs_tunables/$tunable
3441eda14cbcSMatt Macy		;;
3442eda14cbcSMatt Macy	FreeBSD)
3443eda14cbcSMatt Macy		sysctl -n vfs.zfs.$tunable
3444eda14cbcSMatt Macy		;;
3445eda14cbcSMatt Macy	SunOS)
3446eda14cbcSMatt Macy		[[ "$module" -eq "zfs" ]] || return 1
3447eda14cbcSMatt Macy		;;
3448eda14cbcSMatt Macy	esac
3449eda14cbcSMatt Macy}
3450eda14cbcSMatt Macy
34511f1e2261SMartin Matuska# Does a tunable exist?
34521f1e2261SMartin Matuska#
34531f1e2261SMartin Matuska# $1: Tunable name
34541f1e2261SMartin Matuskafunction tunable_exists
34551f1e2261SMartin Matuska{
34561f1e2261SMartin Matuska	get_tunable_impl $1 "zfs" 1
34571f1e2261SMartin Matuska}
34581f1e2261SMartin Matuska
3459eda14cbcSMatt Macy#
34607a7741afSMartin Matuska# Compute xxh128sum for given file or stdin if no file given.
3461eda14cbcSMatt Macy# Note: file path must not contain spaces
3462eda14cbcSMatt Macy#
34637a7741afSMartin Matuskafunction xxh128digest
3464eda14cbcSMatt Macy{
34657a7741afSMartin Matuska	xxh128sum $1 | awk '{print $1}'
3466eda14cbcSMatt Macy}
3467eda14cbcSMatt Macy
3468eda14cbcSMatt Macy#
34697a7741afSMartin Matuska# Compare the xxhash128 digest of two files.
3470eda14cbcSMatt Macy#
34717a7741afSMartin Matuskafunction cmp_xxh128 {
34727a7741afSMartin Matuska	typeset file1=$1
34737a7741afSMartin Matuska	typeset file2=$2
3474eda14cbcSMatt Macy
34757a7741afSMartin Matuska	typeset sum1=$(xxh128digest $file1)
34767a7741afSMartin Matuska	typeset sum2=$(xxh128digest $file2)
34777a7741afSMartin Matuska	test "$sum1" = "$sum2"
3478eda14cbcSMatt Macy}
3479eda14cbcSMatt Macy
3480eda14cbcSMatt Macyfunction new_fs #<args>
3481eda14cbcSMatt Macy{
3482716fd348SMartin Matuska	case "$UNAME" in
3483eda14cbcSMatt Macy	FreeBSD)
3484eda14cbcSMatt Macy		newfs "$@"
3485eda14cbcSMatt Macy		;;
3486eda14cbcSMatt Macy	*)
3487eda14cbcSMatt Macy		echo y | newfs -v "$@"
3488eda14cbcSMatt Macy		;;
3489eda14cbcSMatt Macy	esac
3490eda14cbcSMatt Macy}
3491eda14cbcSMatt Macy
3492eda14cbcSMatt Macyfunction stat_size #<path>
3493eda14cbcSMatt Macy{
3494eda14cbcSMatt Macy	typeset path=$1
3495eda14cbcSMatt Macy
3496716fd348SMartin Matuska	case "$UNAME" in
3497eda14cbcSMatt Macy	FreeBSD)
3498eda14cbcSMatt Macy		stat -f %z "$path"
3499eda14cbcSMatt Macy		;;
3500eda14cbcSMatt Macy	*)
3501eda14cbcSMatt Macy		stat -c %s "$path"
3502eda14cbcSMatt Macy		;;
3503eda14cbcSMatt Macy	esac
3504eda14cbcSMatt Macy}
3505eda14cbcSMatt Macy
3506271171e0SMartin Matuskafunction stat_mtime #<path>
3507271171e0SMartin Matuska{
3508271171e0SMartin Matuska	typeset path=$1
3509271171e0SMartin Matuska
3510271171e0SMartin Matuska	case "$UNAME" in
3511271171e0SMartin Matuska	FreeBSD)
3512271171e0SMartin Matuska		stat -f %m "$path"
3513271171e0SMartin Matuska		;;
3514271171e0SMartin Matuska	*)
3515271171e0SMartin Matuska		stat -c %Y "$path"
3516271171e0SMartin Matuska		;;
3517271171e0SMartin Matuska	esac
3518271171e0SMartin Matuska}
3519271171e0SMartin Matuska
35202faf504dSMartin Matuskafunction stat_ctime #<path>
35212faf504dSMartin Matuska{
35222faf504dSMartin Matuska	typeset path=$1
35232faf504dSMartin Matuska
3524716fd348SMartin Matuska	case "$UNAME" in
35252faf504dSMartin Matuska	FreeBSD)
35262faf504dSMartin Matuska		stat -f %c "$path"
35272faf504dSMartin Matuska		;;
35282faf504dSMartin Matuska	*)
35292faf504dSMartin Matuska		stat -c %Z "$path"
35302faf504dSMartin Matuska		;;
35312faf504dSMartin Matuska	esac
35322faf504dSMartin Matuska}
35332faf504dSMartin Matuska
35342faf504dSMartin Matuskafunction stat_crtime #<path>
35352faf504dSMartin Matuska{
35362faf504dSMartin Matuska	typeset path=$1
35372faf504dSMartin Matuska
3538716fd348SMartin Matuska	case "$UNAME" in
35392faf504dSMartin Matuska	FreeBSD)
35402faf504dSMartin Matuska		stat -f %B "$path"
35412faf504dSMartin Matuska		;;
35422faf504dSMartin Matuska	*)
35432faf504dSMartin Matuska		stat -c %W "$path"
35442faf504dSMartin Matuska		;;
35452faf504dSMartin Matuska	esac
35462faf504dSMartin Matuska}
35472faf504dSMartin Matuska
3548e92ffd9bSMartin Matuskafunction stat_generation #<path>
3549e92ffd9bSMartin Matuska{
3550e92ffd9bSMartin Matuska	typeset path=$1
3551e92ffd9bSMartin Matuska
3552716fd348SMartin Matuska	case "$UNAME" in
3553e92ffd9bSMartin Matuska	Linux)
3554e92ffd9bSMartin Matuska		getversion "${path}"
3555e92ffd9bSMartin Matuska		;;
3556e92ffd9bSMartin Matuska	*)
3557e92ffd9bSMartin Matuska		stat -f %v "${path}"
3558e92ffd9bSMartin Matuska		;;
3559e92ffd9bSMartin Matuska	esac
3560e92ffd9bSMartin Matuska}
3561e92ffd9bSMartin Matuska
3562eda14cbcSMatt Macy# Run a command as if it was being run in a TTY.
3563eda14cbcSMatt Macy#
3564eda14cbcSMatt Macy# Usage:
3565eda14cbcSMatt Macy#
3566eda14cbcSMatt Macy#    faketty command
3567eda14cbcSMatt Macy#
3568eda14cbcSMatt Macyfunction faketty
3569eda14cbcSMatt Macy{
3570eda14cbcSMatt Macy    if is_freebsd; then
3571eda14cbcSMatt Macy        script -q /dev/null env "$@"
3572eda14cbcSMatt Macy    else
3573eda14cbcSMatt Macy        script --return --quiet -c "$*" /dev/null
3574eda14cbcSMatt Macy    fi
3575eda14cbcSMatt Macy}
3576eda14cbcSMatt Macy
3577eda14cbcSMatt Macy#
3578eda14cbcSMatt Macy# Produce a random permutation of the integers in a given range (inclusive).
3579eda14cbcSMatt Macy#
3580eda14cbcSMatt Macyfunction range_shuffle # begin end
3581eda14cbcSMatt Macy{
3582eda14cbcSMatt Macy	typeset -i begin=$1
3583eda14cbcSMatt Macy	typeset -i end=$2
3584eda14cbcSMatt Macy
3585eda14cbcSMatt Macy	seq ${begin} ${end} | sort -R
3586eda14cbcSMatt Macy}
3587eda14cbcSMatt Macy
3588eda14cbcSMatt Macy#
3589eda14cbcSMatt Macy# Cross-platform xattr helpers
3590eda14cbcSMatt Macy#
3591eda14cbcSMatt Macy
3592eda14cbcSMatt Macyfunction get_xattr # name path
3593eda14cbcSMatt Macy{
3594eda14cbcSMatt Macy	typeset name=$1
3595eda14cbcSMatt Macy	typeset path=$2
3596eda14cbcSMatt Macy
3597716fd348SMartin Matuska	case "$UNAME" in
3598eda14cbcSMatt Macy	FreeBSD)
3599eda14cbcSMatt Macy		getextattr -qq user "${name}" "${path}"
3600eda14cbcSMatt Macy		;;
3601eda14cbcSMatt Macy	*)
3602eda14cbcSMatt Macy		attr -qg "${name}" "${path}"
3603eda14cbcSMatt Macy		;;
3604eda14cbcSMatt Macy	esac
3605eda14cbcSMatt Macy}
3606eda14cbcSMatt Macy
3607eda14cbcSMatt Macyfunction set_xattr # name value path
3608eda14cbcSMatt Macy{
3609eda14cbcSMatt Macy	typeset name=$1
3610eda14cbcSMatt Macy	typeset value=$2
3611eda14cbcSMatt Macy	typeset path=$3
3612eda14cbcSMatt Macy
3613716fd348SMartin Matuska	case "$UNAME" in
3614eda14cbcSMatt Macy	FreeBSD)
3615eda14cbcSMatt Macy		setextattr user "${name}" "${value}" "${path}"
3616eda14cbcSMatt Macy		;;
3617eda14cbcSMatt Macy	*)
3618eda14cbcSMatt Macy		attr -qs "${name}" -V "${value}" "${path}"
3619eda14cbcSMatt Macy		;;
3620eda14cbcSMatt Macy	esac
3621eda14cbcSMatt Macy}
3622eda14cbcSMatt Macy
3623eda14cbcSMatt Macyfunction set_xattr_stdin # name value
3624eda14cbcSMatt Macy{
3625eda14cbcSMatt Macy	typeset name=$1
3626eda14cbcSMatt Macy	typeset path=$2
3627eda14cbcSMatt Macy
3628716fd348SMartin Matuska	case "$UNAME" in
3629eda14cbcSMatt Macy	FreeBSD)
3630eda14cbcSMatt Macy		setextattr -i user "${name}" "${path}"
3631eda14cbcSMatt Macy		;;
3632eda14cbcSMatt Macy	*)
3633eda14cbcSMatt Macy		attr -qs "${name}" "${path}"
3634eda14cbcSMatt Macy		;;
3635eda14cbcSMatt Macy	esac
3636eda14cbcSMatt Macy}
3637eda14cbcSMatt Macy
3638eda14cbcSMatt Macyfunction rm_xattr # name path
3639eda14cbcSMatt Macy{
3640eda14cbcSMatt Macy	typeset name=$1
3641eda14cbcSMatt Macy	typeset path=$2
3642eda14cbcSMatt Macy
3643716fd348SMartin Matuska	case "$UNAME" in
3644eda14cbcSMatt Macy	FreeBSD)
3645eda14cbcSMatt Macy		rmextattr -q user "${name}" "${path}"
3646eda14cbcSMatt Macy		;;
3647eda14cbcSMatt Macy	*)
3648eda14cbcSMatt Macy		attr -qr "${name}" "${path}"
3649eda14cbcSMatt Macy		;;
3650eda14cbcSMatt Macy	esac
3651eda14cbcSMatt Macy}
3652eda14cbcSMatt Macy
3653eda14cbcSMatt Macyfunction ls_xattr # path
3654eda14cbcSMatt Macy{
3655eda14cbcSMatt Macy	typeset path=$1
3656eda14cbcSMatt Macy
3657716fd348SMartin Matuska	case "$UNAME" in
3658eda14cbcSMatt Macy	FreeBSD)
3659eda14cbcSMatt Macy		lsextattr -qq user "${path}"
3660eda14cbcSMatt Macy		;;
3661eda14cbcSMatt Macy	*)
3662eda14cbcSMatt Macy		attr -ql "${path}"
3663eda14cbcSMatt Macy		;;
3664eda14cbcSMatt Macy	esac
3665eda14cbcSMatt Macy}
3666eda14cbcSMatt Macy
366721b492edSMartin Matuskafunction punch_hole # offset length file
366821b492edSMartin Matuska{
366921b492edSMartin Matuska	typeset offset=$1
367021b492edSMartin Matuska	typeset length=$2
367121b492edSMartin Matuska	typeset file=$3
367221b492edSMartin Matuska
3673716fd348SMartin Matuska	case "$UNAME" in
367421b492edSMartin Matuska	FreeBSD)
367521b492edSMartin Matuska		truncate -d -o $offset -l $length "$file"
367621b492edSMartin Matuska		;;
367721b492edSMartin Matuska	Linux)
367821b492edSMartin Matuska		fallocate --punch-hole --offset $offset --length $length "$file"
367921b492edSMartin Matuska		;;
368021b492edSMartin Matuska	*)
368121b492edSMartin Matuska		false
368221b492edSMartin Matuska		;;
368321b492edSMartin Matuska	esac
368421b492edSMartin Matuska}
368521b492edSMartin Matuska
3686716fd348SMartin Matuskafunction zero_range # offset length file
3687716fd348SMartin Matuska{
3688716fd348SMartin Matuska	typeset offset=$1
3689716fd348SMartin Matuska	typeset length=$2
3690716fd348SMartin Matuska	typeset file=$3
3691716fd348SMartin Matuska
3692716fd348SMartin Matuska	case "$UNAME" in
3693716fd348SMartin Matuska	Linux)
3694716fd348SMartin Matuska		fallocate --zero-range --offset $offset --length $length "$file"
3695716fd348SMartin Matuska		;;
3696716fd348SMartin Matuska	*)
3697716fd348SMartin Matuska		false
3698716fd348SMartin Matuska		;;
3699716fd348SMartin Matuska	esac
3700716fd348SMartin Matuska}
3701716fd348SMartin Matuska
3702eda14cbcSMatt Macy#
37037877fdebSMatt Macy# Wait for the specified arcstat to reach non-zero quiescence.
37047877fdebSMatt Macy# If echo is 1 echo the value after reaching quiescence, otherwise
37057877fdebSMatt Macy# if echo is 0 print the arcstat we are waiting on.
37067877fdebSMatt Macy#
37077877fdebSMatt Macyfunction arcstat_quiescence # stat echo
37087877fdebSMatt Macy{
37097877fdebSMatt Macy	typeset stat=$1
37107877fdebSMatt Macy	typeset echo=$2
37117877fdebSMatt Macy	typeset do_once=true
37127877fdebSMatt Macy
37137877fdebSMatt Macy	if [[ $echo -eq 0 ]]; then
37147877fdebSMatt Macy		echo "Waiting for arcstat $1 quiescence."
37157877fdebSMatt Macy	fi
37167877fdebSMatt Macy
37177877fdebSMatt Macy	while $do_once || [ $stat1 -ne $stat2 ] || [ $stat2 -eq 0 ]; do
3718*c6767dc1SMartin Matuska		typeset stat1=$(kstat arcstats.$stat)
3719b7198dcfSMartin Matuska		sleep 0.5
3720*c6767dc1SMartin Matuska		typeset stat2=$(kstat arcstats.$stat)
37217877fdebSMatt Macy		do_once=false
37227877fdebSMatt Macy	done
37237877fdebSMatt Macy
37247877fdebSMatt Macy	if [[ $echo -eq 1 ]]; then
37257877fdebSMatt Macy		echo $stat2
37267877fdebSMatt Macy	fi
37277877fdebSMatt Macy}
37287877fdebSMatt Macy
37297877fdebSMatt Macyfunction arcstat_quiescence_noecho # stat
37307877fdebSMatt Macy{
37317877fdebSMatt Macy	typeset stat=$1
37327877fdebSMatt Macy	arcstat_quiescence $stat 0
37337877fdebSMatt Macy}
37347877fdebSMatt Macy
37357877fdebSMatt Macyfunction arcstat_quiescence_echo # stat
37367877fdebSMatt Macy{
37377877fdebSMatt Macy	typeset stat=$1
37387877fdebSMatt Macy	arcstat_quiescence $stat 1
37397877fdebSMatt Macy}
37407877fdebSMatt Macy
37417877fdebSMatt Macy#
3742eda14cbcSMatt Macy# Given an array of pids, wait until all processes
3743eda14cbcSMatt Macy# have completed and check their return status.
3744eda14cbcSMatt Macy#
3745eda14cbcSMatt Macyfunction wait_for_children #children
3746eda14cbcSMatt Macy{
3747eda14cbcSMatt Macy	rv=0
3748eda14cbcSMatt Macy	children=("$@")
3749eda14cbcSMatt Macy	for child in "${children[@]}"
3750eda14cbcSMatt Macy	do
3751eda14cbcSMatt Macy		child_exit=0
3752eda14cbcSMatt Macy		wait ${child} || child_exit=$?
3753eda14cbcSMatt Macy		if [ $child_exit -ne 0 ]; then
3754eda14cbcSMatt Macy			echo "child ${child} failed with ${child_exit}"
3755eda14cbcSMatt Macy			rv=1
3756eda14cbcSMatt Macy		fi
3757eda14cbcSMatt Macy	done
3758eda14cbcSMatt Macy	return $rv
3759eda14cbcSMatt Macy}
3760c03c5b1cSMartin Matuska
3761c03c5b1cSMartin Matuska#
3762c03c5b1cSMartin Matuska# Compare two directory trees recursively in a manner similar to diff(1), but
3763c03c5b1cSMartin Matuska# using rsync. If there are any discrepancies, a summary of the differences are
3764c03c5b1cSMartin Matuska# output and a non-zero error is returned.
3765c03c5b1cSMartin Matuska#
3766c03c5b1cSMartin Matuska# If you're comparing a directory after a ZIL replay, you should set
3767c03c5b1cSMartin Matuska# LIBTEST_DIFF_ZIL_REPLAY=1 or use replay_directory_diff which will cause
3768c03c5b1cSMartin Matuska# directory_diff to ignore mtime changes (the ZIL replay won't fix up mtime
3769c03c5b1cSMartin Matuska# information).
3770c03c5b1cSMartin Matuska#
3771c03c5b1cSMartin Matuskafunction directory_diff # dir_a dir_b
3772c03c5b1cSMartin Matuska{
3773c03c5b1cSMartin Matuska	dir_a="$1"
3774c03c5b1cSMartin Matuska	dir_b="$2"
3775c03c5b1cSMartin Matuska	zil_replay="${LIBTEST_DIFF_ZIL_REPLAY:-0}"
3776c03c5b1cSMartin Matuska
3777c03c5b1cSMartin Matuska	# If one of the directories doesn't exist, return 2. This is to match the
3778c03c5b1cSMartin Matuska	# semantics of diff.
3779c03c5b1cSMartin Matuska	if ! [ -d "$dir_a" -a -d "$dir_b" ]; then
3780c03c5b1cSMartin Matuska		return 2
3781c03c5b1cSMartin Matuska	fi
3782c03c5b1cSMartin Matuska
3783c03c5b1cSMartin Matuska	# Run rsync with --dry-run --itemize-changes to get something akin to diff
3784c03c5b1cSMartin Matuska	# output, but rsync is far more thorough in detecting differences (diff
3785c03c5b1cSMartin Matuska	# doesn't compare file metadata, and cannot handle special files).
3786c03c5b1cSMartin Matuska	#
3787c03c5b1cSMartin Matuska	# Also make sure to filter out non-user.* xattrs when comparing. On
3788c03c5b1cSMartin Matuska	# SELinux-enabled systems the copied tree will probably have different
3789c03c5b1cSMartin Matuska	# SELinux labels.
3790c03c5b1cSMartin Matuska	args=("-nicaAHX" '--filter=-x! user.*' "--delete")
3791c03c5b1cSMartin Matuska
3792c03c5b1cSMartin Matuska	# NOTE: Quite a few rsync builds do not support --crtimes which would be
3793c03c5b1cSMartin Matuska	# necessary to verify that creation times are being maintained properly.
3794c03c5b1cSMartin Matuska	# Unfortunately because of this we cannot use it unconditionally but we can
3795c03c5b1cSMartin Matuska	# check if this rsync build supports it and use it then. This check is
3796c03c5b1cSMartin Matuska	# based on the same check in the rsync test suite (testsuite/crtimes.test).
3797c03c5b1cSMartin Matuska	#
3798c03c5b1cSMartin Matuska	# We check ctimes even with zil_replay=1 because the ZIL does store
3799c03c5b1cSMartin Matuska	# creation times and we should make sure they match (if the creation times
3800c03c5b1cSMartin Matuska	# do not match there is a "c" entry in one of the columns).
3801716fd348SMartin Matuska	if rsync --version | grep -q "[, ] crtimes"; then
3802c03c5b1cSMartin Matuska		args+=("--crtimes")
3803c03c5b1cSMartin Matuska	else
3804716fd348SMartin Matuska		log_note "This rsync package does not support --crtimes (-N)."
3805c03c5b1cSMartin Matuska	fi
3806c03c5b1cSMartin Matuska
3807c03c5b1cSMartin Matuska	# If we are testing a ZIL replay, we need to ignore timestamp changes.
3808c03c5b1cSMartin Matuska	# Unfortunately --no-times doesn't do what we want -- it will still tell
3809c03c5b1cSMartin Matuska	# you if the timestamps don't match but rsync will set the timestamps to
3810c03c5b1cSMartin Matuska	# the current time (leading to an itemised change entry). It's simpler to
3811c03c5b1cSMartin Matuska	# just filter out those lines.
3812c03c5b1cSMartin Matuska	if [ "$zil_replay" -eq 0 ]; then
3813c03c5b1cSMartin Matuska		filter=("cat")
3814c03c5b1cSMartin Matuska	else
3815c03c5b1cSMartin Matuska		# Different rsync versions have different numbers of columns. So just
3816c03c5b1cSMartin Matuska		# require that aside from the first two, all other columns must be
3817c03c5b1cSMartin Matuska		# blank (literal ".") or a timestamp field ("[tT]").
3818c03c5b1cSMartin Matuska		filter=("grep" "-v" '^\..[.Tt]\+ ')
3819c03c5b1cSMartin Matuska	fi
3820c03c5b1cSMartin Matuska
3821c03c5b1cSMartin Matuska	diff="$(rsync "${args[@]}" "$dir_a/" "$dir_b/" | "${filter[@]}")"
3822c03c5b1cSMartin Matuska	rv=0
3823c03c5b1cSMartin Matuska	if [ -n "$diff" ]; then
3824c03c5b1cSMartin Matuska		echo "$diff"
3825c03c5b1cSMartin Matuska		rv=1
3826c03c5b1cSMartin Matuska	fi
3827c03c5b1cSMartin Matuska	return $rv
3828c03c5b1cSMartin Matuska}
3829c03c5b1cSMartin Matuska
3830c03c5b1cSMartin Matuska#
3831c03c5b1cSMartin Matuska# Compare two directory trees recursively, without checking whether the mtimes
3832c03c5b1cSMartin Matuska# match (creation times will be checked if the available rsync binary supports
3833c03c5b1cSMartin Matuska# it). This is necessary for ZIL replay checks (because the ZIL does not
3834c03c5b1cSMartin Matuska# contain mtimes and thus after a ZIL replay, mtimes won't match).
3835c03c5b1cSMartin Matuska#
3836c03c5b1cSMartin Matuska# This is shorthand for LIBTEST_DIFF_ZIL_REPLAY=1 directory_diff <...>.
3837c03c5b1cSMartin Matuska#
3838c03c5b1cSMartin Matuskafunction replay_directory_diff # dir_a dir_b
3839c03c5b1cSMartin Matuska{
3840c03c5b1cSMartin Matuska	LIBTEST_DIFF_ZIL_REPLAY=1 directory_diff "$@"
3841716fd348SMartin Matuska}
3842716fd348SMartin Matuska
3843716fd348SMartin Matuska#
3844716fd348SMartin Matuska# Put coredumps into $1/core.{basename}
3845716fd348SMartin Matuska#
3846716fd348SMartin Matuska# Output must be saved and passed to pop_coredump_pattern on cleanup
3847716fd348SMartin Matuska#
3848716fd348SMartin Matuskafunction push_coredump_pattern # dir
3849716fd348SMartin Matuska{
3850716fd348SMartin Matuska	ulimit -c unlimited
3851716fd348SMartin Matuska	case "$UNAME" in
3852716fd348SMartin Matuska	Linux)
3853716fd348SMartin Matuska		cat /proc/sys/kernel/core_pattern /proc/sys/kernel/core_uses_pid
3854716fd348SMartin Matuska		echo "$1/core.%e" >/proc/sys/kernel/core_pattern &&
3855716fd348SMartin Matuska		    echo 0 >/proc/sys/kernel/core_uses_pid
3856716fd348SMartin Matuska		;;
3857716fd348SMartin Matuska	FreeBSD)
3858716fd348SMartin Matuska		sysctl -n kern.corefile
3859716fd348SMartin Matuska		sysctl kern.corefile="$1/core.%N" >/dev/null
3860716fd348SMartin Matuska		;;
3861716fd348SMartin Matuska	*)
3862716fd348SMartin Matuska		# Nothing to output – set only for this shell
3863716fd348SMartin Matuska		coreadm -p "$1/core.%f"
3864716fd348SMartin Matuska		;;
3865716fd348SMartin Matuska	esac
3866716fd348SMartin Matuska}
3867716fd348SMartin Matuska
3868716fd348SMartin Matuska#
3869716fd348SMartin Matuska# Put coredumps back into the default location
3870716fd348SMartin Matuska#
3871716fd348SMartin Matuskafunction pop_coredump_pattern
3872716fd348SMartin Matuska{
3873716fd348SMartin Matuska	[ -s "$1" ] || return 0
3874716fd348SMartin Matuska	case "$UNAME" in
3875716fd348SMartin Matuska	Linux)
3876716fd348SMartin Matuska		typeset pat pid
3877716fd348SMartin Matuska		{ read -r pat; read -r pid; } < "$1"
3878716fd348SMartin Matuska		echo "$pat" >/proc/sys/kernel/core_pattern &&
3879716fd348SMartin Matuska		    echo "$pid" >/proc/sys/kernel/core_uses_pid
3880716fd348SMartin Matuska		;;
3881716fd348SMartin Matuska	FreeBSD)
3882716fd348SMartin Matuska		sysctl kern.corefile="$(<"$1")" >/dev/null
3883716fd348SMartin Matuska		;;
3884716fd348SMartin Matuska	esac
3885c03c5b1cSMartin Matuska}
3886*c6767dc1SMartin Matuska
3887*c6767dc1SMartin Matuska. ${STF_SUITE}/include/kstat.shlib
3888