1# 2# CDDL HEADER START 3# 4# The contents of this file are subject to the terms of the 5# Common Development and Distribution License (the "License"). 6# You may not use this file except in compliance with the License. 7# 8# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9# or http://www.opensolaris.org/os/licensing. 10# See the License for the specific language governing permissions 11# and limitations under the License. 12# 13# When distributing Covered Code, include this CDDL HEADER in each 14# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15# If applicable, add the following below this CDDL HEADER, with the 16# fields enclosed by brackets "[]" replaced with your own identifying 17# information: Portions Copyright [yyyy] [name of copyright owner] 18# 19# CDDL HEADER END 20# 21 22# 23# Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24# Use is subject to license terms. 25# 26 27# 28# Copyright (c) 2012, 2015 by Delphix. All rights reserved. 29# 30 31. ${STF_TOOLS}/contrib/include/logapi.shlib 32 33ZFS=${ZFS:-/usr/sbin/zfs} 34ZPOOL=${ZPOOL:-/usr/sbin/zpool} 35 36# Determine whether a dataset is mounted 37# 38# $1 dataset name 39# $2 filesystem type; optional - defaulted to zfs 40# 41# Return 0 if dataset is mounted; 1 if unmounted; 2 on error 42 43function ismounted 44{ 45 typeset fstype=$2 46 [[ -z $fstype ]] && fstype=zfs 47 typeset out dir name ret 48 49 case $fstype in 50 zfs) 51 if [[ "$1" == "/"* ]] ; then 52 for out in $($ZFS mount | $AWK '{print $2}'); do 53 [[ $1 == $out ]] && return 0 54 done 55 else 56 for out in $($ZFS mount | $AWK '{print $1}'); do 57 [[ $1 == $out ]] && return 0 58 done 59 fi 60 ;; 61 ufs|nfs) 62 out=$($DF -F $fstype $1 2>/dev/null) 63 ret=$? 64 (($ret != 0)) && return $ret 65 66 dir=${out%%\(*} 67 dir=${dir%% *} 68 name=${out##*\(} 69 name=${name%%\)*} 70 name=${name%% *} 71 72 [[ "$1" == "$dir" || "$1" == "$name" ]] && return 0 73 ;; 74 esac 75 76 return 1 77} 78 79# Return 0 if a dataset is mounted; 1 otherwise 80# 81# $1 dataset name 82# $2 filesystem type; optional - defaulted to zfs 83 84function mounted 85{ 86 ismounted $1 $2 87 (($? == 0)) && return 0 88 return 1 89} 90 91# Return 0 if a dataset is unmounted; 1 otherwise 92# 93# $1 dataset name 94# $2 filesystem type; optional - defaulted to zfs 95 96function unmounted 97{ 98 ismounted $1 $2 99 (($? == 1)) && return 0 100 return 1 101} 102 103# split line on "," 104# 105# $1 - line to split 106 107function splitline 108{ 109 $ECHO $1 | $SED "s/,/ /g" 110} 111 112function default_setup 113{ 114 default_setup_noexit "$@" 115 116 log_pass 117} 118 119# 120# Given a list of disks, setup storage pools and datasets. 121# 122function default_setup_noexit 123{ 124 typeset disklist=$1 125 typeset container=$2 126 typeset volume=$3 127 128 if is_global_zone; then 129 if poolexists $TESTPOOL ; then 130 destroy_pool $TESTPOOL 131 fi 132 [[ -d /$TESTPOOL ]] && $RM -rf /$TESTPOOL 133 log_must $ZPOOL create -f $TESTPOOL $disklist 134 else 135 reexport_pool 136 fi 137 138 $RM -rf $TESTDIR || log_unresolved Could not remove $TESTDIR 139 $MKDIR -p $TESTDIR || log_unresolved Could not create $TESTDIR 140 141 log_must $ZFS create $TESTPOOL/$TESTFS 142 log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS 143 144 if [[ -n $container ]]; then 145 $RM -rf $TESTDIR1 || \ 146 log_unresolved Could not remove $TESTDIR1 147 $MKDIR -p $TESTDIR1 || \ 148 log_unresolved Could not create $TESTDIR1 149 150 log_must $ZFS create $TESTPOOL/$TESTCTR 151 log_must $ZFS set canmount=off $TESTPOOL/$TESTCTR 152 log_must $ZFS create $TESTPOOL/$TESTCTR/$TESTFS1 153 log_must $ZFS set mountpoint=$TESTDIR1 \ 154 $TESTPOOL/$TESTCTR/$TESTFS1 155 fi 156 157 if [[ -n $volume ]]; then 158 if is_global_zone ; then 159 log_must $ZFS create -V $VOLSIZE $TESTPOOL/$TESTVOL 160 else 161 log_must $ZFS create $TESTPOOL/$TESTVOL 162 fi 163 fi 164} 165 166# 167# Given a list of disks, setup a storage pool, file system and 168# a container. 169# 170function default_container_setup 171{ 172 typeset disklist=$1 173 174 default_setup "$disklist" "true" 175} 176 177# 178# Given a list of disks, setup a storage pool,file system 179# and a volume. 180# 181function default_volume_setup 182{ 183 typeset disklist=$1 184 185 default_setup "$disklist" "" "true" 186} 187 188# 189# Given a list of disks, setup a storage pool,file system, 190# a container and a volume. 191# 192function default_container_volume_setup 193{ 194 typeset disklist=$1 195 196 default_setup "$disklist" "true" "true" 197} 198 199# 200# Create a snapshot on a filesystem or volume. Defaultly create a snapshot on 201# filesystem 202# 203# $1 Existing filesystem or volume name. Default, $TESTFS 204# $2 snapshot name. Default, $TESTSNAP 205# 206function create_snapshot 207{ 208 typeset fs_vol=${1:-$TESTFS} 209 typeset snap=${2:-$TESTSNAP} 210 211 [[ -z $fs_vol ]] && log_fail "Filesystem or volume's name is undefined." 212 [[ -z $snap ]] && log_fail "Snapshot's name is undefined." 213 214 if snapexists $fs_vol@$snap; then 215 log_fail "$fs_vol@$snap already exists." 216 fi 217 datasetexists $fs_vol || \ 218 log_fail "$fs_vol must exist." 219 220 log_must $ZFS snapshot $fs_vol@$snap 221} 222 223# 224# Create a clone from a snapshot, default clone name is $TESTCLONE. 225# 226# $1 Existing snapshot, $TESTPOOL/$TESTFS@$TESTSNAP is default. 227# $2 Clone name, $TESTPOOL/$TESTCLONE is default. 228# 229function create_clone # snapshot clone 230{ 231 typeset snap=${1:-$TESTPOOL/$TESTFS@$TESTSNAP} 232 typeset clone=${2:-$TESTPOOL/$TESTCLONE} 233 234 [[ -z $snap ]] && \ 235 log_fail "Snapshot name is undefined." 236 [[ -z $clone ]] && \ 237 log_fail "Clone name is undefined." 238 239 log_must $ZFS clone $snap $clone 240} 241 242function default_mirror_setup 243{ 244 default_mirror_setup_noexit $1 $2 $3 245 246 log_pass 247} 248 249# 250# Given a pair of disks, set up a storage pool and dataset for the mirror 251# @parameters: $1 the primary side of the mirror 252# $2 the secondary side of the mirror 253# @uses: ZPOOL ZFS TESTPOOL TESTFS 254function default_mirror_setup_noexit 255{ 256 readonly func="default_mirror_setup_noexit" 257 typeset primary=$1 258 typeset secondary=$2 259 260 [[ -z $primary ]] && \ 261 log_fail "$func: No parameters passed" 262 [[ -z $secondary ]] && \ 263 log_fail "$func: No secondary partition passed" 264 [[ -d /$TESTPOOL ]] && $RM -rf /$TESTPOOL 265 log_must $ZPOOL create -f $TESTPOOL mirror $@ 266 log_must $ZFS create $TESTPOOL/$TESTFS 267 log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS 268} 269 270# 271# create a number of mirrors. 272# We create a number($1) of 2 way mirrors using the pairs of disks named 273# on the command line. These mirrors are *not* mounted 274# @parameters: $1 the number of mirrors to create 275# $... the devices to use to create the mirrors on 276# @uses: ZPOOL ZFS TESTPOOL 277function setup_mirrors 278{ 279 typeset -i nmirrors=$1 280 281 shift 282 while ((nmirrors > 0)); do 283 log_must test -n "$1" -a -n "$2" 284 [[ -d /$TESTPOOL$nmirrors ]] && $RM -rf /$TESTPOOL$nmirrors 285 log_must $ZPOOL create -f $TESTPOOL$nmirrors mirror $1 $2 286 shift 2 287 ((nmirrors = nmirrors - 1)) 288 done 289} 290 291# 292# create a number of raidz pools. 293# We create a number($1) of 2 raidz pools using the pairs of disks named 294# on the command line. These pools are *not* mounted 295# @parameters: $1 the number of pools to create 296# $... the devices to use to create the pools on 297# @uses: ZPOOL ZFS TESTPOOL 298function setup_raidzs 299{ 300 typeset -i nraidzs=$1 301 302 shift 303 while ((nraidzs > 0)); do 304 log_must test -n "$1" -a -n "$2" 305 [[ -d /$TESTPOOL$nraidzs ]] && $RM -rf /$TESTPOOL$nraidzs 306 log_must $ZPOOL create -f $TESTPOOL$nraidzs raidz $1 $2 307 shift 2 308 ((nraidzs = nraidzs - 1)) 309 done 310} 311 312# 313# Destroy the configured testpool mirrors. 314# the mirrors are of the form ${TESTPOOL}{number} 315# @uses: ZPOOL ZFS TESTPOOL 316function destroy_mirrors 317{ 318 default_cleanup_noexit 319 320 log_pass 321} 322 323# 324# Given a minimum of two disks, set up a storage pool and dataset for the raid-z 325# $1 the list of disks 326# 327function default_raidz_setup 328{ 329 typeset disklist="$*" 330 disks=(${disklist[*]}) 331 332 if [[ ${#disks[*]} -lt 2 ]]; then 333 log_fail "A raid-z requires a minimum of two disks." 334 fi 335 336 [[ -d /$TESTPOOL ]] && $RM -rf /$TESTPOOL 337 log_must $ZPOOL create -f $TESTPOOL raidz $1 $2 $3 338 log_must $ZFS create $TESTPOOL/$TESTFS 339 log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS 340 341 log_pass 342} 343 344# 345# Common function used to cleanup storage pools and datasets. 346# 347# Invoked at the start of the test suite to ensure the system 348# is in a known state, and also at the end of each set of 349# sub-tests to ensure errors from one set of tests doesn't 350# impact the execution of the next set. 351 352function default_cleanup 353{ 354 default_cleanup_noexit 355 356 log_pass 357} 358 359function default_cleanup_noexit 360{ 361 typeset exclude="" 362 typeset pool="" 363 # 364 # Destroying the pool will also destroy any 365 # filesystems it contains. 366 # 367 if is_global_zone; then 368 $ZFS unmount -a > /dev/null 2>&1 369 exclude=`eval $ECHO \"'(${KEEP})'\"` 370 ALL_POOLS=$($ZPOOL list -H -o name \ 371 | $GREP -v "$NO_POOLS" | $EGREP -v "$exclude") 372 # Here, we loop through the pools we're allowed to 373 # destroy, only destroying them if it's safe to do 374 # so. 375 while [ ! -z ${ALL_POOLS} ] 376 do 377 for pool in ${ALL_POOLS} 378 do 379 if safe_to_destroy_pool $pool ; 380 then 381 destroy_pool $pool 382 fi 383 ALL_POOLS=$($ZPOOL list -H -o name \ 384 | $GREP -v "$NO_POOLS" \ 385 | $EGREP -v "$exclude") 386 done 387 done 388 389 $ZFS mount -a 390 else 391 typeset fs="" 392 for fs in $($ZFS list -H -o name \ 393 | $GREP "^$ZONE_POOL/$ZONE_CTR[01234]/"); do 394 datasetexists $fs && \ 395 log_must $ZFS destroy -Rf $fs 396 done 397 398 # Need cleanup here to avoid garbage dir left. 399 for fs in $($ZFS list -H -o name); do 400 [[ $fs == /$ZONE_POOL ]] && continue 401 [[ -d $fs ]] && log_must $RM -rf $fs/* 402 done 403 404 # 405 # Reset the $ZONE_POOL/$ZONE_CTR[01234] file systems property to 406 # the default value 407 # 408 for fs in $($ZFS list -H -o name); do 409 if [[ $fs == $ZONE_POOL/$ZONE_CTR[01234] ]]; then 410 log_must $ZFS set reservation=none $fs 411 log_must $ZFS set recordsize=128K $fs 412 log_must $ZFS set mountpoint=/$fs $fs 413 typeset enc="" 414 enc=$(get_prop encryption $fs) 415 if [[ $? -ne 0 ]] || [[ -z "$enc" ]] || \ 416 [[ "$enc" == "off" ]]; then 417 log_must $ZFS set checksum=on $fs 418 fi 419 log_must $ZFS set compression=off $fs 420 log_must $ZFS set atime=on $fs 421 log_must $ZFS set devices=off $fs 422 log_must $ZFS set exec=on $fs 423 log_must $ZFS set setuid=on $fs 424 log_must $ZFS set readonly=off $fs 425 log_must $ZFS set snapdir=hidden $fs 426 log_must $ZFS set aclmode=groupmask $fs 427 log_must $ZFS set aclinherit=secure $fs 428 fi 429 done 430 fi 431 432 [[ -d $TESTDIR ]] && \ 433 log_must $RM -rf $TESTDIR 434} 435 436 437# 438# Common function used to cleanup storage pools, file systems 439# and containers. 440# 441function default_container_cleanup 442{ 443 if ! is_global_zone; then 444 reexport_pool 445 fi 446 447 ismounted $TESTPOOL/$TESTCTR/$TESTFS1 448 [[ $? -eq 0 ]] && \ 449 log_must $ZFS unmount $TESTPOOL/$TESTCTR/$TESTFS1 450 451 datasetexists $TESTPOOL/$TESTCTR/$TESTFS1 && \ 452 log_must $ZFS destroy -R $TESTPOOL/$TESTCTR/$TESTFS1 453 454 datasetexists $TESTPOOL/$TESTCTR && \ 455 log_must $ZFS destroy -Rf $TESTPOOL/$TESTCTR 456 457 [[ -e $TESTDIR1 ]] && \ 458 log_must $RM -rf $TESTDIR1 > /dev/null 2>&1 459 460 default_cleanup 461} 462 463# 464# Common function used to cleanup snapshot of file system or volume. Default to 465# delete the file system's snapshot 466# 467# $1 snapshot name 468# 469function destroy_snapshot 470{ 471 typeset snap=${1:-$TESTPOOL/$TESTFS@$TESTSNAP} 472 473 if ! snapexists $snap; then 474 log_fail "'$snap' does not existed." 475 fi 476 477 # 478 # For the sake of the value which come from 'get_prop' is not equal 479 # to the really mountpoint when the snapshot is unmounted. So, firstly 480 # check and make sure this snapshot's been mounted in current system. 481 # 482 typeset mtpt="" 483 if ismounted $snap; then 484 mtpt=$(get_prop mountpoint $snap) 485 (($? != 0)) && \ 486 log_fail "get_prop mountpoint $snap failed." 487 fi 488 489 log_must $ZFS destroy $snap 490 [[ $mtpt != "" && -d $mtpt ]] && \ 491 log_must $RM -rf $mtpt 492} 493 494# 495# Common function used to cleanup clone. 496# 497# $1 clone name 498# 499function destroy_clone 500{ 501 typeset clone=${1:-$TESTPOOL/$TESTCLONE} 502 503 if ! datasetexists $clone; then 504 log_fail "'$clone' does not existed." 505 fi 506 507 # With the same reason in destroy_snapshot 508 typeset mtpt="" 509 if ismounted $clone; then 510 mtpt=$(get_prop mountpoint $clone) 511 (($? != 0)) && \ 512 log_fail "get_prop mountpoint $clone failed." 513 fi 514 515 log_must $ZFS destroy $clone 516 [[ $mtpt != "" && -d $mtpt ]] && \ 517 log_must $RM -rf $mtpt 518} 519 520# Return 0 if a snapshot exists; $? otherwise 521# 522# $1 - snapshot name 523 524function snapexists 525{ 526 $ZFS list -H -t snapshot "$1" > /dev/null 2>&1 527 return $? 528} 529 530# 531# Set a property to a certain value on a dataset. 532# Sets a property of the dataset to the value as passed in. 533# @param: 534# $1 dataset who's property is being set 535# $2 property to set 536# $3 value to set property to 537# @return: 538# 0 if the property could be set. 539# non-zero otherwise. 540# @use: ZFS 541# 542function dataset_setprop 543{ 544 typeset fn=dataset_setprop 545 546 if (($# < 3)); then 547 log_note "$fn: Insufficient parameters (need 3, had $#)" 548 return 1 549 fi 550 typeset output= 551 output=$($ZFS set $2=$3 $1 2>&1) 552 typeset rv=$? 553 if ((rv != 0)); then 554 log_note "Setting property on $1 failed." 555 log_note "property $2=$3" 556 log_note "Return Code: $rv" 557 log_note "Output: $output" 558 return $rv 559 fi 560 return 0 561} 562 563# 564# Assign suite defined dataset properties. 565# This function is used to apply the suite's defined default set of 566# properties to a dataset. 567# @parameters: $1 dataset to use 568# @uses: ZFS COMPRESSION_PROP CHECKSUM_PROP 569# @returns: 570# 0 if the dataset has been altered. 571# 1 if no pool name was passed in. 572# 2 if the dataset could not be found. 573# 3 if the dataset could not have it's properties set. 574# 575function dataset_set_defaultproperties 576{ 577 typeset dataset="$1" 578 579 [[ -z $dataset ]] && return 1 580 581 typeset confset= 582 typeset -i found=0 583 for confset in $($ZFS list); do 584 if [[ $dataset = $confset ]]; then 585 found=1 586 break 587 fi 588 done 589 [[ $found -eq 0 ]] && return 2 590 if [[ -n $COMPRESSION_PROP ]]; then 591 dataset_setprop $dataset compression $COMPRESSION_PROP || \ 592 return 3 593 log_note "Compression set to '$COMPRESSION_PROP' on $dataset" 594 fi 595 if [[ -n $CHECKSUM_PROP ]]; then 596 dataset_setprop $dataset checksum $CHECKSUM_PROP || \ 597 return 3 598 log_note "Checksum set to '$CHECKSUM_PROP' on $dataset" 599 fi 600 return 0 601} 602 603# 604# Check a numeric assertion 605# @parameter: $@ the assertion to check 606# @output: big loud notice if assertion failed 607# @use: log_fail 608# 609function assert 610{ 611 (($@)) || log_fail "$@" 612} 613 614# 615# Function to format partition size of a disk 616# Given a disk cxtxdx reduces all partitions 617# to 0 size 618# 619function zero_partitions #<whole_disk_name> 620{ 621 typeset diskname=$1 622 typeset i 623 624 for i in 0 1 3 4 5 6 7 625 do 626 set_partition $i "" 0mb $diskname 627 done 628} 629 630# 631# Given a slice, size and disk, this function 632# formats the slice to the specified size. 633# Size should be specified with units as per 634# the `format` command requirements eg. 100mb 3gb 635# 636function set_partition #<slice_num> <slice_start> <size_plus_units> <whole_disk_name> 637{ 638 typeset -i slicenum=$1 639 typeset start=$2 640 typeset size=$3 641 typeset disk=$4 642 [[ -z $slicenum || -z $size || -z $disk ]] && \ 643 log_fail "The slice, size or disk name is unspecified." 644 typeset format_file=/var/tmp/format_in.$$ 645 646 $ECHO "partition" >$format_file 647 $ECHO "$slicenum" >> $format_file 648 $ECHO "" >> $format_file 649 $ECHO "" >> $format_file 650 $ECHO "$start" >> $format_file 651 $ECHO "$size" >> $format_file 652 $ECHO "label" >> $format_file 653 $ECHO "" >> $format_file 654 $ECHO "q" >> $format_file 655 $ECHO "q" >> $format_file 656 657 $FORMAT -e -s -d $disk -f $format_file 658 typeset ret_val=$? 659 $RM -f $format_file 660 [[ $ret_val -ne 0 ]] && \ 661 log_fail "Unable to format $disk slice $slicenum to $size" 662 return 0 663} 664 665# 666# Get the end cyl of the given slice 667# 668function get_endslice #<disk> <slice> 669{ 670 typeset disk=$1 671 typeset slice=$2 672 if [[ -z $disk || -z $slice ]] ; then 673 log_fail "The disk name or slice number is unspecified." 674 fi 675 676 disk=${disk#/dev/dsk/} 677 disk=${disk#/dev/rdsk/} 678 disk=${disk%s*} 679 680 typeset -i ratio=0 681 ratio=$($PRTVTOC /dev/rdsk/${disk}s2 | \ 682 $GREP "sectors\/cylinder" | \ 683 $AWK '{print $2}') 684 685 if ((ratio == 0)); then 686 return 687 fi 688 689 typeset -i endcyl=$($PRTVTOC -h /dev/rdsk/${disk}s2 | 690 $NAWK -v token="$slice" '{if ($1==token) print $6}') 691 692 ((endcyl = (endcyl + 1) / ratio)) 693 echo $endcyl 694} 695 696 697# 698# Given a size,disk and total slice number, this function formats the 699# disk slices from 0 to the total slice number with the same specified 700# size. 701# 702function partition_disk #<slice_size> <whole_disk_name> <total_slices> 703{ 704 typeset -i i=0 705 typeset slice_size=$1 706 typeset disk_name=$2 707 typeset total_slices=$3 708 typeset cyl 709 710 zero_partitions $disk_name 711 while ((i < $total_slices)); do 712 if ((i == 2)); then 713 ((i = i + 1)) 714 continue 715 fi 716 set_partition $i "$cyl" $slice_size $disk_name 717 cyl=$(get_endslice $disk_name $i) 718 ((i = i+1)) 719 done 720} 721 722# 723# This function continues to write to a filenum number of files into dirnum 724# number of directories until either $FILE_WRITE returns an error or the 725# maximum number of files per directory have been written. 726# 727# Usage: 728# fill_fs [destdir] [dirnum] [filenum] [bytes] [num_writes] [data] 729# 730# Return value: 0 on success 731# non 0 on error 732# 733# Where : 734# destdir: is the directory where everything is to be created under 735# dirnum: the maximum number of subdirectories to use, -1 no limit 736# filenum: the maximum number of files per subdirectory 737# bytes: number of bytes to write 738# num_writes: numer of types to write out bytes 739# data: the data that will be writen 740# 741# E.g. 742# file_fs /testdir 20 25 1024 256 0 743# 744# Note: bytes * num_writes equals the size of the testfile 745# 746function fill_fs # destdir dirnum filenum bytes num_writes data 747{ 748 typeset destdir=${1:-$TESTDIR} 749 typeset -i dirnum=${2:-50} 750 typeset -i filenum=${3:-50} 751 typeset -i bytes=${4:-8192} 752 typeset -i num_writes=${5:-10240} 753 typeset -i data=${6:-0} 754 755 typeset -i odirnum=1 756 typeset -i idirnum=0 757 typeset -i fn=0 758 typeset -i retval=0 759 760 log_must $MKDIR -p $destdir/$idirnum 761 while (($odirnum > 0)); do 762 if ((dirnum >= 0 && idirnum >= dirnum)); then 763 odirnum=0 764 break 765 fi 766 $FILE_WRITE -o create -f $destdir/$idirnum/$TESTFILE.$fn \ 767 -b $bytes -c $num_writes -d $data 768 retval=$? 769 if (($retval != 0)); then 770 odirnum=0 771 break 772 fi 773 if (($fn >= $filenum)); then 774 fn=0 775 ((idirnum = idirnum + 1)) 776 log_must $MKDIR -p $destdir/$idirnum 777 else 778 ((fn = fn + 1)) 779 fi 780 done 781 return $retval 782} 783 784# 785# Simple function to get the specified property. If unable to 786# get the property then exits. 787# 788# Note property is in 'parsable' format (-p) 789# 790function get_prop # property dataset 791{ 792 typeset prop_val 793 typeset prop=$1 794 typeset dataset=$2 795 796 prop_val=$($ZFS get -pH -o value $prop $dataset 2>/dev/null) 797 if [[ $? -ne 0 ]]; then 798 log_note "Unable to get $prop property for dataset " \ 799 "$dataset" 800 return 1 801 fi 802 803 $ECHO $prop_val 804 return 0 805} 806 807# 808# Simple function to get the specified property of pool. If unable to 809# get the property then exits. 810# 811function get_pool_prop # property pool 812{ 813 typeset prop_val 814 typeset prop=$1 815 typeset pool=$2 816 817 if poolexists $pool ; then 818 prop_val=$($ZPOOL get $prop $pool 2>/dev/null | $TAIL -1 | \ 819 $AWK '{print $3}') 820 if [[ $? -ne 0 ]]; then 821 log_note "Unable to get $prop property for pool " \ 822 "$pool" 823 return 1 824 fi 825 else 826 log_note "Pool $pool not exists." 827 return 1 828 fi 829 830 $ECHO $prop_val 831 return 0 832} 833 834# Return 0 if a pool exists; $? otherwise 835# 836# $1 - pool name 837 838function poolexists 839{ 840 typeset pool=$1 841 842 if [[ -z $pool ]]; then 843 log_note "No pool name given." 844 return 1 845 fi 846 847 $ZPOOL get name "$pool" > /dev/null 2>&1 848 return $? 849} 850 851# Return 0 if all the specified datasets exist; $? otherwise 852# 853# $1-n dataset name 854function datasetexists 855{ 856 if (($# == 0)); then 857 log_note "No dataset name given." 858 return 1 859 fi 860 861 while (($# > 0)); do 862 $ZFS get name $1 > /dev/null 2>&1 || \ 863 return $? 864 shift 865 done 866 867 return 0 868} 869 870# return 0 if none of the specified datasets exists, otherwise return 1. 871# 872# $1-n dataset name 873function datasetnonexists 874{ 875 if (($# == 0)); then 876 log_note "No dataset name given." 877 return 1 878 fi 879 880 while (($# > 0)); do 881 $ZFS list -H -t filesystem,snapshot,volume $1 > /dev/null 2>&1 \ 882 && return 1 883 shift 884 done 885 886 return 0 887} 888 889# 890# Given a mountpoint, or a dataset name, determine if it is shared. 891# 892# Returns 0 if shared, 1 otherwise. 893# 894function is_shared 895{ 896 typeset fs=$1 897 typeset mtpt 898 899 if [[ $fs != "/"* ]] ; then 900 if datasetnonexists "$fs" ; then 901 return 1 902 else 903 mtpt=$(get_prop mountpoint "$fs") 904 case $mtpt in 905 none|legacy|-) return 1 906 ;; 907 *) fs=$mtpt 908 ;; 909 esac 910 fi 911 fi 912 913 for mtpt in `$SHARE | $AWK '{print $2}'` ; do 914 if [[ $mtpt == $fs ]] ; then 915 return 0 916 fi 917 done 918 919 typeset stat=$($SVCS -H -o STA nfs/server:default) 920 if [[ $stat != "ON" ]]; then 921 log_note "Current nfs/server status: $stat" 922 fi 923 924 return 1 925} 926 927# 928# Given a mountpoint, determine if it is not shared. 929# 930# Returns 0 if not shared, 1 otherwise. 931# 932function not_shared 933{ 934 typeset fs=$1 935 936 is_shared $fs 937 if (($? == 0)); then 938 return 1 939 fi 940 941 return 0 942} 943 944# 945# Helper function to unshare a mountpoint. 946# 947function unshare_fs #fs 948{ 949 typeset fs=$1 950 951 is_shared $fs 952 if (($? == 0)); then 953 log_must $ZFS unshare $fs 954 fi 955 956 return 0 957} 958 959# 960# Check NFS server status and trigger it online. 961# 962function setup_nfs_server 963{ 964 # Cannot share directory in non-global zone. 965 # 966 if ! is_global_zone; then 967 log_note "Cannot trigger NFS server by sharing in LZ." 968 return 969 fi 970 971 typeset nfs_fmri="svc:/network/nfs/server:default" 972 if [[ $($SVCS -Ho STA $nfs_fmri) != "ON" ]]; then 973 # 974 # Only really sharing operation can enable NFS server 975 # to online permanently. 976 # 977 typeset dummy=/tmp/dummy 978 979 if [[ -d $dummy ]]; then 980 log_must $RM -rf $dummy 981 fi 982 983 log_must $MKDIR $dummy 984 log_must $SHARE $dummy 985 986 # 987 # Waiting for fmri's status to be the final status. 988 # Otherwise, in transition, an asterisk (*) is appended for 989 # instances, unshare will reverse status to 'DIS' again. 990 # 991 # Waiting for 1's at least. 992 # 993 log_must $SLEEP 1 994 timeout=10 995 while [[ timeout -ne 0 && $($SVCS -Ho STA $nfs_fmri) == *'*' ]] 996 do 997 log_must $SLEEP 1 998 999 ((timeout -= 1)) 1000 done 1001 1002 log_must $UNSHARE $dummy 1003 log_must $RM -rf $dummy 1004 fi 1005 1006 log_note "Current NFS status: '$($SVCS -Ho STA,FMRI $nfs_fmri)'" 1007} 1008 1009# 1010# To verify whether calling process is in global zone 1011# 1012# Return 0 if in global zone, 1 in non-global zone 1013# 1014function is_global_zone 1015{ 1016 typeset cur_zone=$($ZONENAME 2>/dev/null) 1017 if [[ $cur_zone != "global" ]]; then 1018 return 1 1019 fi 1020 return 0 1021} 1022 1023# 1024# Verify whether test is permitted to run from 1025# global zone, local zone, or both 1026# 1027# $1 zone limit, could be "global", "local", or "both"(no limit) 1028# 1029# Return 0 if permitted, otherwise exit with log_unsupported 1030# 1031function verify_runnable # zone limit 1032{ 1033 typeset limit=$1 1034 1035 [[ -z $limit ]] && return 0 1036 1037 if is_global_zone ; then 1038 case $limit in 1039 global|both) 1040 ;; 1041 local) log_unsupported "Test is unable to run from "\ 1042 "global zone." 1043 ;; 1044 *) log_note "Warning: unknown limit $limit - " \ 1045 "use both." 1046 ;; 1047 esac 1048 else 1049 case $limit in 1050 local|both) 1051 ;; 1052 global) log_unsupported "Test is unable to run from "\ 1053 "local zone." 1054 ;; 1055 *) log_note "Warning: unknown limit $limit - " \ 1056 "use both." 1057 ;; 1058 esac 1059 1060 reexport_pool 1061 fi 1062 1063 return 0 1064} 1065 1066# Return 0 if create successfully or the pool exists; $? otherwise 1067# Note: In local zones, this function should return 0 silently. 1068# 1069# $1 - pool name 1070# $2-n - [keyword] devs_list 1071 1072function create_pool #pool devs_list 1073{ 1074 typeset pool=${1%%/*} 1075 1076 shift 1077 1078 if [[ -z $pool ]]; then 1079 log_note "Missing pool name." 1080 return 1 1081 fi 1082 1083 if poolexists $pool ; then 1084 destroy_pool $pool 1085 fi 1086 1087 if is_global_zone ; then 1088 [[ -d /$pool ]] && $RM -rf /$pool 1089 log_must $ZPOOL create -f $pool $@ 1090 fi 1091 1092 return 0 1093} 1094 1095# Return 0 if destroy successfully or the pool exists; $? otherwise 1096# Note: In local zones, this function should return 0 silently. 1097# 1098# $1 - pool name 1099# Destroy pool with the given parameters. 1100 1101function destroy_pool #pool 1102{ 1103 typeset pool=${1%%/*} 1104 typeset mtpt 1105 1106 if [[ -z $pool ]]; then 1107 log_note "No pool name given." 1108 return 1 1109 fi 1110 1111 if is_global_zone ; then 1112 if poolexists "$pool" ; then 1113 mtpt=$(get_prop mountpoint "$pool") 1114 1115 # At times, syseventd activity can cause attempts to 1116 # destroy a pool to fail with EBUSY. We retry a few 1117 # times allowing failures before requiring the destroy 1118 # to succeed. 1119 typeset -i wait_time=10 ret=1 count=0 1120 must="" 1121 while [[ $ret -ne 0 ]]; do 1122 $must $ZPOOL destroy -f $pool 1123 ret=$? 1124 [[ $ret -eq 0 ]] && break 1125 log_note "zpool destroy failed with $ret" 1126 [[ count++ -ge 7 ]] && must=log_must 1127 $SLEEP $wait_time 1128 done 1129 1130 [[ -d $mtpt ]] && \ 1131 log_must $RM -rf $mtpt 1132 else 1133 log_note "Pool does not exist. ($pool)" 1134 return 1 1135 fi 1136 fi 1137 1138 return 0 1139} 1140 1141# 1142# Firstly, create a pool with 5 datasets. Then, create a single zone and 1143# export the 5 datasets to it. In addition, we also add a ZFS filesystem 1144# and a zvol device to the zone. 1145# 1146# $1 zone name 1147# $2 zone root directory prefix 1148# $3 zone ip 1149# 1150function zfs_zones_setup #zone_name zone_root zone_ip 1151{ 1152 typeset zone_name=${1:-$(hostname)-z} 1153 typeset zone_root=${2:-"/zone_root"} 1154 typeset zone_ip=${3:-"10.1.1.10"} 1155 typeset prefix_ctr=$ZONE_CTR 1156 typeset pool_name=$ZONE_POOL 1157 typeset -i cntctr=5 1158 typeset -i i=0 1159 1160 # Create pool and 5 container within it 1161 # 1162 [[ -d /$pool_name ]] && $RM -rf /$pool_name 1163 log_must $ZPOOL create -f $pool_name $DISKS 1164 while ((i < cntctr)); do 1165 log_must $ZFS create $pool_name/$prefix_ctr$i 1166 ((i += 1)) 1167 done 1168 1169 # create a zvol 1170 log_must $ZFS create -V 1g $pool_name/zone_zvol 1171 1172 # 1173 # If current system support slog, add slog device for pool 1174 # 1175 if verify_slog_support ; then 1176 typeset sdevs="/var/tmp/sdev1 /var/tmp/sdev2" 1177 log_must $MKFILE 100M $sdevs 1178 log_must $ZPOOL add $pool_name log mirror $sdevs 1179 fi 1180 1181 # this isn't supported just yet. 1182 # Create a filesystem. In order to add this to 1183 # the zone, it must have it's mountpoint set to 'legacy' 1184 # log_must $ZFS create $pool_name/zfs_filesystem 1185 # log_must $ZFS set mountpoint=legacy $pool_name/zfs_filesystem 1186 1187 [[ -d $zone_root ]] && \ 1188 log_must $RM -rf $zone_root/$zone_name 1189 [[ ! -d $zone_root ]] && \ 1190 log_must $MKDIR -p -m 0700 $zone_root/$zone_name 1191 1192 # Create zone configure file and configure the zone 1193 # 1194 typeset zone_conf=/tmp/zone_conf.$$ 1195 $ECHO "create" > $zone_conf 1196 $ECHO "set zonepath=$zone_root/$zone_name" >> $zone_conf 1197 $ECHO "set autoboot=true" >> $zone_conf 1198 i=0 1199 while ((i < cntctr)); do 1200 $ECHO "add dataset" >> $zone_conf 1201 $ECHO "set name=$pool_name/$prefix_ctr$i" >> \ 1202 $zone_conf 1203 $ECHO "end" >> $zone_conf 1204 ((i += 1)) 1205 done 1206 1207 # add our zvol to the zone 1208 $ECHO "add device" >> $zone_conf 1209 $ECHO "set match=/dev/zvol/dsk/$pool_name/zone_zvol" >> $zone_conf 1210 $ECHO "end" >> $zone_conf 1211 1212 # add a corresponding zvol rdsk to the zone 1213 $ECHO "add device" >> $zone_conf 1214 $ECHO "set match=/dev/zvol/rdsk/$pool_name/zone_zvol" >> $zone_conf 1215 $ECHO "end" >> $zone_conf 1216 1217 # once it's supported, we'll add our filesystem to the zone 1218 # $ECHO "add fs" >> $zone_conf 1219 # $ECHO "set type=zfs" >> $zone_conf 1220 # $ECHO "set special=$pool_name/zfs_filesystem" >> $zone_conf 1221 # $ECHO "set dir=/export/zfs_filesystem" >> $zone_conf 1222 # $ECHO "end" >> $zone_conf 1223 1224 $ECHO "verify" >> $zone_conf 1225 $ECHO "commit" >> $zone_conf 1226 log_must $ZONECFG -z $zone_name -f $zone_conf 1227 log_must $RM -f $zone_conf 1228 1229 # Install the zone 1230 $ZONEADM -z $zone_name install 1231 if (($? == 0)); then 1232 log_note "SUCCESS: $ZONEADM -z $zone_name install" 1233 else 1234 log_fail "FAIL: $ZONEADM -z $zone_name install" 1235 fi 1236 1237 # Install sysidcfg file 1238 # 1239 typeset sysidcfg=$zone_root/$zone_name/root/etc/sysidcfg 1240 $ECHO "system_locale=C" > $sysidcfg 1241 $ECHO "terminal=dtterm" >> $sysidcfg 1242 $ECHO "network_interface=primary {" >> $sysidcfg 1243 $ECHO "hostname=$zone_name" >> $sysidcfg 1244 $ECHO "}" >> $sysidcfg 1245 $ECHO "name_service=NONE" >> $sysidcfg 1246 $ECHO "root_password=mo791xfZ/SFiw" >> $sysidcfg 1247 $ECHO "security_policy=NONE" >> $sysidcfg 1248 $ECHO "timezone=US/Eastern" >> $sysidcfg 1249 1250 # Boot this zone 1251 log_must $ZONEADM -z $zone_name boot 1252} 1253 1254# 1255# Reexport TESTPOOL & TESTPOOL(1-4) 1256# 1257function reexport_pool 1258{ 1259 typeset -i cntctr=5 1260 typeset -i i=0 1261 1262 while ((i < cntctr)); do 1263 if ((i == 0)); then 1264 TESTPOOL=$ZONE_POOL/$ZONE_CTR$i 1265 if ! ismounted $TESTPOOL; then 1266 log_must $ZFS mount $TESTPOOL 1267 fi 1268 else 1269 eval TESTPOOL$i=$ZONE_POOL/$ZONE_CTR$i 1270 if eval ! ismounted \$TESTPOOL$i; then 1271 log_must eval $ZFS mount \$TESTPOOL$i 1272 fi 1273 fi 1274 ((i += 1)) 1275 done 1276} 1277 1278# 1279# Verify a given disk is online or offline 1280# 1281# Return 0 is pool/disk matches expected state, 1 otherwise 1282# 1283function check_state # pool disk state{online,offline} 1284{ 1285 typeset pool=$1 1286 typeset disk=${2#/dev/dsk/} 1287 typeset state=$3 1288 1289 $ZPOOL status -v $pool | grep "$disk" \ 1290 | grep -i "$state" > /dev/null 2>&1 1291 1292 return $? 1293} 1294 1295# 1296# Get the mountpoint of snapshot 1297# For the snapshot use <mp_filesystem>/.zfs/snapshot/<snap> 1298# as its mountpoint 1299# 1300function snapshot_mountpoint 1301{ 1302 typeset dataset=${1:-$TESTPOOL/$TESTFS@$TESTSNAP} 1303 1304 if [[ $dataset != *@* ]]; then 1305 log_fail "Error name of snapshot '$dataset'." 1306 fi 1307 1308 typeset fs=${dataset%@*} 1309 typeset snap=${dataset#*@} 1310 1311 if [[ -z $fs || -z $snap ]]; then 1312 log_fail "Error name of snapshot '$dataset'." 1313 fi 1314 1315 $ECHO $(get_prop mountpoint $fs)/.zfs/snapshot/$snap 1316} 1317 1318# 1319# Given a pool and file system, this function will verify the file system 1320# using the zdb internal tool. Note that the pool is exported and imported 1321# to ensure it has consistent state. 1322# 1323function verify_filesys # pool filesystem dir 1324{ 1325 typeset pool="$1" 1326 typeset filesys="$2" 1327 typeset zdbout="/tmp/zdbout.$$" 1328 1329 shift 1330 shift 1331 typeset dirs=$@ 1332 typeset search_path="" 1333 1334 log_note "Calling $ZDB to verify filesystem '$filesys'" 1335 $ZFS unmount -a > /dev/null 2>&1 1336 log_must $ZPOOL export $pool 1337 1338 if [[ -n $dirs ]] ; then 1339 for dir in $dirs ; do 1340 search_path="$search_path -d $dir" 1341 done 1342 fi 1343 1344 log_must $ZPOOL import $search_path $pool 1345 1346 $ZDB -cudi $filesys > $zdbout 2>&1 1347 if [[ $? != 0 ]]; then 1348 log_note "Output: $ZDB -cudi $filesys" 1349 $CAT $zdbout 1350 log_fail "$ZDB detected errors with: '$filesys'" 1351 fi 1352 1353 log_must $ZFS mount -a 1354 log_must $RM -rf $zdbout 1355} 1356 1357# 1358# Given a pool, and this function list all disks in the pool 1359# 1360function get_disklist # pool 1361{ 1362 typeset disklist="" 1363 1364 disklist=$($ZPOOL iostat -v $1 | $NAWK '(NR >4) {print $1}' | \ 1365 $GREP -v "\-\-\-\-\-" | \ 1366 $EGREP -v -e "^(mirror|raidz1|raidz2|spare|log|cache)$") 1367 1368 $ECHO $disklist 1369} 1370 1371# /** 1372# This function kills a given list of processes after a time period. We use 1373# this in the stress tests instead of STF_TIMEOUT so that we can have processes 1374# run for a fixed amount of time, yet still pass. Tests that hit STF_TIMEOUT 1375# would be listed as FAIL, which we don't want : we're happy with stress tests 1376# running for a certain amount of time, then finishing. 1377# 1378# @param $1 the time in seconds after which we should terminate these processes 1379# @param $2..$n the processes we wish to terminate. 1380# */ 1381function stress_timeout 1382{ 1383 typeset -i TIMEOUT=$1 1384 shift 1385 typeset cpids="$@" 1386 1387 log_note "Waiting for child processes($cpids). " \ 1388 "It could last dozens of minutes, please be patient ..." 1389 log_must $SLEEP $TIMEOUT 1390 1391 log_note "Killing child processes after ${TIMEOUT} stress timeout." 1392 typeset pid 1393 for pid in $cpids; do 1394 $PS -p $pid > /dev/null 2>&1 1395 if (($? == 0)); then 1396 log_must $KILL -USR1 $pid 1397 fi 1398 done 1399} 1400 1401# 1402# Verify a given hotspare disk is inuse or avail 1403# 1404# Return 0 is pool/disk matches expected state, 1 otherwise 1405# 1406function check_hotspare_state # pool disk state{inuse,avail} 1407{ 1408 typeset pool=$1 1409 typeset disk=${2#/dev/dsk/} 1410 typeset state=$3 1411 1412 cur_state=$(get_device_state $pool $disk "spares") 1413 1414 if [[ $state != ${cur_state} ]]; then 1415 return 1 1416 fi 1417 return 0 1418} 1419 1420# 1421# Verify a given slog disk is inuse or avail 1422# 1423# Return 0 is pool/disk matches expected state, 1 otherwise 1424# 1425function check_slog_state # pool disk state{online,offline,unavail} 1426{ 1427 typeset pool=$1 1428 typeset disk=${2#/dev/dsk/} 1429 typeset state=$3 1430 1431 cur_state=$(get_device_state $pool $disk "logs") 1432 1433 if [[ $state != ${cur_state} ]]; then 1434 return 1 1435 fi 1436 return 0 1437} 1438 1439# 1440# Verify a given vdev disk is inuse or avail 1441# 1442# Return 0 is pool/disk matches expected state, 1 otherwise 1443# 1444function check_vdev_state # pool disk state{online,offline,unavail} 1445{ 1446 typeset pool=$1 1447 typeset disk=${2#/dev/dsk/} 1448 typeset state=$3 1449 1450 cur_state=$(get_device_state $pool $disk) 1451 1452 if [[ $state != ${cur_state} ]]; then 1453 return 1 1454 fi 1455 return 0 1456} 1457 1458# 1459# Check the output of 'zpool status -v <pool>', 1460# and to see if the content of <token> contain the <keyword> specified. 1461# 1462# Return 0 is contain, 1 otherwise 1463# 1464function check_pool_status # pool token keyword 1465{ 1466 typeset pool=$1 1467 typeset token=$2 1468 typeset keyword=$3 1469 1470 $ZPOOL status -v "$pool" 2>/dev/null | $NAWK -v token="$token:" ' 1471 ($1==token) {print $0}' \ 1472 | $GREP -i "$keyword" > /dev/null 2>&1 1473 1474 return $? 1475} 1476 1477# 1478# These 5 following functions are instance of check_pool_status() 1479# is_pool_resilvering - to check if the pool is resilver in progress 1480# is_pool_resilvered - to check if the pool is resilver completed 1481# is_pool_scrubbing - to check if the pool is scrub in progress 1482# is_pool_scrubbed - to check if the pool is scrub completed 1483# is_pool_scrub_stopped - to check if the pool is scrub stopped 1484# 1485function is_pool_resilvering #pool 1486{ 1487 check_pool_status "$1" "scan" "resilver in progress since " 1488 return $? 1489} 1490 1491function is_pool_resilvered #pool 1492{ 1493 check_pool_status "$1" "scan" "resilvered " 1494 return $? 1495} 1496 1497function is_pool_scrubbing #pool 1498{ 1499 check_pool_status "$1" "scan" "scrub in progress since " 1500 return $? 1501} 1502 1503function is_pool_scrubbed #pool 1504{ 1505 check_pool_status "$1" "scan" "scrub repaired" 1506 return $? 1507} 1508 1509function is_pool_scrub_stopped #pool 1510{ 1511 check_pool_status "$1" "scan" "scrub canceled" 1512 return $? 1513} 1514 1515# 1516# Use create_pool()/destroy_pool() to clean up the infomation in 1517# in the given disk to avoid slice overlapping. 1518# 1519function cleanup_devices #vdevs 1520{ 1521 typeset pool="foopool$$" 1522 1523 if poolexists $pool ; then 1524 destroy_pool $pool 1525 fi 1526 1527 create_pool $pool $@ 1528 destroy_pool $pool 1529 1530 return 0 1531} 1532 1533# 1534# Verify the rsh connectivity to each remote host in RHOSTS. 1535# 1536# Return 0 if remote host is accessible; otherwise 1. 1537# $1 remote host name 1538# $2 username 1539# 1540function verify_rsh_connect #rhost, username 1541{ 1542 typeset rhost=$1 1543 typeset username=$2 1544 typeset rsh_cmd="$RSH -n" 1545 typeset cur_user= 1546 1547 $GETENT hosts $rhost >/dev/null 2>&1 1548 if (($? != 0)); then 1549 log_note "$rhost cannot be found from" \ 1550 "administrative database." 1551 return 1 1552 fi 1553 1554 $PING $rhost 3 >/dev/null 2>&1 1555 if (($? != 0)); then 1556 log_note "$rhost is not reachable." 1557 return 1 1558 fi 1559 1560 if ((${#username} != 0)); then 1561 rsh_cmd="$rsh_cmd -l $username" 1562 cur_user="given user \"$username\"" 1563 else 1564 cur_user="current user \"`$LOGNAME`\"" 1565 fi 1566 1567 if ! $rsh_cmd $rhost $TRUE; then 1568 log_note "$RSH to $rhost is not accessible" \ 1569 "with $cur_user." 1570 return 1 1571 fi 1572 1573 return 0 1574} 1575 1576# 1577# Verify the remote host connection via rsh after rebooting 1578# $1 remote host 1579# 1580function verify_remote 1581{ 1582 rhost=$1 1583 1584 # 1585 # The following loop waits for the remote system rebooting. 1586 # Each iteration will wait for 150 seconds. there are 1587 # total 5 iterations, so the total timeout value will 1588 # be 12.5 minutes for the system rebooting. This number 1589 # is an approxiate number. 1590 # 1591 typeset -i count=0 1592 while ! verify_rsh_connect $rhost; do 1593 sleep 150 1594 ((count = count + 1)) 1595 if ((count > 5)); then 1596 return 1 1597 fi 1598 done 1599 return 0 1600} 1601 1602# 1603# Replacement function for /usr/bin/rsh. This function will include 1604# the /usr/bin/rsh and meanwhile return the execution status of the 1605# last command. 1606# 1607# $1 usrname passing down to -l option of /usr/bin/rsh 1608# $2 remote machine hostname 1609# $3... command string 1610# 1611 1612function rsh_status 1613{ 1614 typeset ruser=$1 1615 typeset rhost=$2 1616 typeset -i ret=0 1617 typeset cmd_str="" 1618 typeset rsh_str="" 1619 1620 shift; shift 1621 cmd_str="$@" 1622 1623 err_file=/tmp/${rhost}.$$.err 1624 if ((${#ruser} == 0)); then 1625 rsh_str="$RSH -n" 1626 else 1627 rsh_str="$RSH -n -l $ruser" 1628 fi 1629 1630 $rsh_str $rhost /usr/bin/ksh -c "'$cmd_str; \ 1631 print -u 2 \"status=\$?\"'" \ 1632 >/dev/null 2>$err_file 1633 ret=$? 1634 if (($ret != 0)); then 1635 $CAT $err_file 1636 $RM -f $std_file $err_file 1637 log_fail "$RSH itself failed with exit code $ret..." 1638 fi 1639 1640 ret=$($GREP -v 'print -u 2' $err_file | $GREP 'status=' | \ 1641 $CUT -d= -f2) 1642 (($ret != 0)) && $CAT $err_file >&2 1643 1644 $RM -f $err_file >/dev/null 2>&1 1645 return $ret 1646} 1647 1648# 1649# Get the SUNWstc-fs-zfs package installation path in a remote host 1650# $1 remote host name 1651# 1652function get_remote_pkgpath 1653{ 1654 typeset rhost=$1 1655 typeset pkgpath="" 1656 1657 pkgpath=$($RSH -n $rhost "$PKGINFO -l SUNWstc-fs-zfs | $GREP BASEDIR: |\ 1658 $CUT -d: -f2") 1659 1660 $ECHO $pkgpath 1661} 1662 1663#/** 1664# A function to find and locate free disks on a system or from given 1665# disks as the parameter. It works by locating disks that are in use 1666# as swap devices and dump devices, and also disks listed in /etc/vfstab 1667# 1668# $@ given disks to find which are free, default is all disks in 1669# the test system 1670# 1671# @return a string containing the list of available disks 1672#*/ 1673function find_disks 1674{ 1675 sfi=/tmp/swaplist.$$ 1676 dmpi=/tmp/dumpdev.$$ 1677 max_finddisksnum=${MAX_FINDDISKSNUM:-6} 1678 1679 $SWAP -l > $sfi 1680 $DUMPADM > $dmpi 2>/dev/null 1681 1682# write an awk script that can process the output of format 1683# to produce a list of disks we know about. Note that we have 1684# to escape "$2" so that the shell doesn't interpret it while 1685# we're creating the awk script. 1686# ------------------- 1687 $CAT > /tmp/find_disks.awk <<EOF 1688#!/bin/nawk -f 1689 BEGIN { FS="."; } 1690 1691 /^Specify disk/{ 1692 searchdisks=0; 1693 } 1694 1695 { 1696 if (searchdisks && \$2 !~ "^$"){ 1697 split(\$2,arr," "); 1698 print arr[1]; 1699 } 1700 } 1701 1702 /^AVAILABLE DISK SELECTIONS:/{ 1703 searchdisks=1; 1704 } 1705EOF 1706#--------------------- 1707 1708 $CHMOD 755 /tmp/find_disks.awk 1709 disks=${@:-$($ECHO "" | $FORMAT -e 2>/dev/null | /tmp/find_disks.awk)} 1710 $RM /tmp/find_disks.awk 1711 1712 unused="" 1713 for disk in $disks; do 1714 # Check for mounted 1715 $GREP "${disk}[sp]" /etc/mnttab >/dev/null 1716 (($? == 0)) && continue 1717 # Check for swap 1718 $GREP "${disk}[sp]" $sfi >/dev/null 1719 (($? == 0)) && continue 1720 # check for dump device 1721 $GREP "${disk}[sp]" $dmpi >/dev/null 1722 (($? == 0)) && continue 1723 # check to see if this disk hasn't been explicitly excluded 1724 # by a user-set environment variable 1725 $ECHO "${ZFS_HOST_DEVICES_IGNORE}" | $GREP "${disk}" > /dev/null 1726 (($? == 0)) && continue 1727 unused_candidates="$unused_candidates $disk" 1728 done 1729 $RM $sfi 1730 $RM $dmpi 1731 1732# now just check to see if those disks do actually exist 1733# by looking for a device pointing to the first slice in 1734# each case. limit the number to max_finddisksnum 1735 count=0 1736 for disk in $unused_candidates; do 1737 if [ -b /dev/dsk/${disk}s0 ]; then 1738 if [ $count -lt $max_finddisksnum ]; then 1739 unused="$unused $disk" 1740 # do not impose limit if $@ is provided 1741 [[ -z $@ ]] && ((count = count + 1)) 1742 fi 1743 fi 1744 done 1745 1746# finally, return our disk list 1747 $ECHO $unused 1748} 1749 1750# 1751# Add specified user to specified group 1752# 1753# $1 group name 1754# $2 user name 1755# $3 base of the homedir (optional) 1756# 1757function add_user #<group_name> <user_name> <basedir> 1758{ 1759 typeset gname=$1 1760 typeset uname=$2 1761 typeset basedir=${3:-"/var/tmp"} 1762 1763 if ((${#gname} == 0 || ${#uname} == 0)); then 1764 log_fail "group name or user name are not defined." 1765 fi 1766 1767 log_must $USERADD -g $gname -d $basedir/$uname -m $uname 1768 1769 return 0 1770} 1771 1772# 1773# Delete the specified user. 1774# 1775# $1 login name 1776# $2 base of the homedir (optional) 1777# 1778function del_user #<logname> <basedir> 1779{ 1780 typeset user=$1 1781 typeset basedir=${2:-"/var/tmp"} 1782 1783 if ((${#user} == 0)); then 1784 log_fail "login name is necessary." 1785 fi 1786 1787 if $ID $user > /dev/null 2>&1; then 1788 log_must $USERDEL $user 1789 fi 1790 1791 [[ -d $basedir/$user ]] && $RM -fr $basedir/$user 1792 1793 return 0 1794} 1795 1796# 1797# Select valid gid and create specified group. 1798# 1799# $1 group name 1800# 1801function add_group #<group_name> 1802{ 1803 typeset group=$1 1804 1805 if ((${#group} == 0)); then 1806 log_fail "group name is necessary." 1807 fi 1808 1809 # Assign 100 as the base gid 1810 typeset -i gid=100 1811 while true; do 1812 $GROUPADD -g $gid $group > /dev/null 2>&1 1813 typeset -i ret=$? 1814 case $ret in 1815 0) return 0 ;; 1816 # The gid is not unique 1817 4) ((gid += 1)) ;; 1818 *) return 1 ;; 1819 esac 1820 done 1821} 1822 1823# 1824# Delete the specified group. 1825# 1826# $1 group name 1827# 1828function del_group #<group_name> 1829{ 1830 typeset grp=$1 1831 if ((${#grp} == 0)); then 1832 log_fail "group name is necessary." 1833 fi 1834 1835 $GROUPMOD -n $grp $grp > /dev/null 2>&1 1836 typeset -i ret=$? 1837 case $ret in 1838 # Group does not exist. 1839 6) return 0 ;; 1840 # Name already exists as a group name 1841 9) log_must $GROUPDEL $grp ;; 1842 *) return 1 ;; 1843 esac 1844 1845 return 0 1846} 1847 1848# 1849# This function will return true if it's safe to destroy the pool passed 1850# as argument 1. It checks for pools based on zvols and files, and also 1851# files contained in a pool that may have a different mountpoint. 1852# 1853function safe_to_destroy_pool { # $1 the pool name 1854 1855 typeset pool="" 1856 typeset DONT_DESTROY="" 1857 1858 # We check that by deleting the $1 pool, we're not 1859 # going to pull the rug out from other pools. Do this 1860 # by looking at all other pools, ensuring that they 1861 # aren't built from files or zvols contained in this pool. 1862 1863 for pool in $($ZPOOL list -H -o name) 1864 do 1865 ALTMOUNTPOOL="" 1866 1867 # this is a list of the top-level directories in each of the 1868 # files that make up the path to the files the pool is based on 1869 FILEPOOL=$($ZPOOL status -v $pool | $GREP /$1/ | \ 1870 $AWK '{print $1}') 1871 1872 # this is a list of the zvols that make up the pool 1873 ZVOLPOOL=$($ZPOOL status -v $pool | $GREP "/dev/zvol/dsk/$1$" \ 1874 | $AWK '{print $1}') 1875 1876 # also want to determine if it's a file-based pool using an 1877 # alternate mountpoint... 1878 POOL_FILE_DIRS=$($ZPOOL status -v $pool | \ 1879 $GREP / | $AWK '{print $1}' | \ 1880 $AWK -F/ '{print $2}' | $GREP -v "dev") 1881 1882 for pooldir in $POOL_FILE_DIRS 1883 do 1884 OUTPUT=$($ZFS list -H -r -o mountpoint $1 | \ 1885 $GREP "${pooldir}$" | $AWK '{print $1}') 1886 1887 ALTMOUNTPOOL="${ALTMOUNTPOOL}${OUTPUT}" 1888 done 1889 1890 1891 if [ ! -z "$ZVOLPOOL" ] 1892 then 1893 DONT_DESTROY="true" 1894 log_note "Pool $pool is built from $ZVOLPOOL on $1" 1895 fi 1896 1897 if [ ! -z "$FILEPOOL" ] 1898 then 1899 DONT_DESTROY="true" 1900 log_note "Pool $pool is built from $FILEPOOL on $1" 1901 fi 1902 1903 if [ ! -z "$ALTMOUNTPOOL" ] 1904 then 1905 DONT_DESTROY="true" 1906 log_note "Pool $pool is built from $ALTMOUNTPOOL on $1" 1907 fi 1908 done 1909 1910 if [ -z "${DONT_DESTROY}" ] 1911 then 1912 return 0 1913 else 1914 log_note "Warning: it is not safe to destroy $1!" 1915 return 1 1916 fi 1917} 1918 1919# 1920# Get the available ZFS compression options 1921# $1 option type zfs_set|zfs_compress 1922# 1923function get_compress_opts 1924{ 1925 typeset COMPRESS_OPTS 1926 typeset GZIP_OPTS="gzip gzip-1 gzip-2 gzip-3 gzip-4 gzip-5 \ 1927 gzip-6 gzip-7 gzip-8 gzip-9" 1928 1929 if [[ $1 == "zfs_compress" ]] ; then 1930 COMPRESS_OPTS="on lzjb" 1931 elif [[ $1 == "zfs_set" ]] ; then 1932 COMPRESS_OPTS="on off lzjb" 1933 fi 1934 typeset valid_opts="$COMPRESS_OPTS" 1935 $ZFS get 2>&1 | $GREP gzip >/dev/null 2>&1 1936 if [[ $? -eq 0 ]]; then 1937 valid_opts="$valid_opts $GZIP_OPTS" 1938 fi 1939 $ECHO "$valid_opts" 1940} 1941 1942# 1943# Verify zfs operation with -p option work as expected 1944# $1 operation, value could be create, clone or rename 1945# $2 dataset type, value could be fs or vol 1946# $3 dataset name 1947# $4 new dataset name 1948# 1949function verify_opt_p_ops 1950{ 1951 typeset ops=$1 1952 typeset datatype=$2 1953 typeset dataset=$3 1954 typeset newdataset=$4 1955 1956 if [[ $datatype != "fs" && $datatype != "vol" ]]; then 1957 log_fail "$datatype is not supported." 1958 fi 1959 1960 # check parameters accordingly 1961 case $ops in 1962 create) 1963 newdataset=$dataset 1964 dataset="" 1965 if [[ $datatype == "vol" ]]; then 1966 ops="create -V $VOLSIZE" 1967 fi 1968 ;; 1969 clone) 1970 if [[ -z $newdataset ]]; then 1971 log_fail "newdataset should not be empty" \ 1972 "when ops is $ops." 1973 fi 1974 log_must datasetexists $dataset 1975 log_must snapexists $dataset 1976 ;; 1977 rename) 1978 if [[ -z $newdataset ]]; then 1979 log_fail "newdataset should not be empty" \ 1980 "when ops is $ops." 1981 fi 1982 log_must datasetexists $dataset 1983 log_mustnot snapexists $dataset 1984 ;; 1985 *) 1986 log_fail "$ops is not supported." 1987 ;; 1988 esac 1989 1990 # make sure the upper level filesystem does not exist 1991 if datasetexists ${newdataset%/*} ; then 1992 log_must $ZFS destroy -rRf ${newdataset%/*} 1993 fi 1994 1995 # without -p option, operation will fail 1996 log_mustnot $ZFS $ops $dataset $newdataset 1997 log_mustnot datasetexists $newdataset ${newdataset%/*} 1998 1999 # with -p option, operation should succeed 2000 log_must $ZFS $ops -p $dataset $newdataset 2001 if ! datasetexists $newdataset ; then 2002 log_fail "-p option does not work for $ops" 2003 fi 2004 2005 # when $ops is create or clone, redo the operation still return zero 2006 if [[ $ops != "rename" ]]; then 2007 log_must $ZFS $ops -p $dataset $newdataset 2008 fi 2009 2010 return 0 2011} 2012 2013# 2014# Get configuration of pool 2015# $1 pool name 2016# $2 config name 2017# 2018function get_config 2019{ 2020 typeset pool=$1 2021 typeset config=$2 2022 typeset alt_root 2023 2024 if ! poolexists "$pool" ; then 2025 return 1 2026 fi 2027 alt_root=$($ZPOOL list -H $pool | $AWK '{print $NF}') 2028 if [[ $alt_root == "-" ]]; then 2029 value=$($ZDB -C $pool | $GREP "$config:" | $AWK -F: \ 2030 '{print $2}') 2031 else 2032 value=$($ZDB -e $pool | $GREP "$config:" | $AWK -F: \ 2033 '{print $2}') 2034 fi 2035 if [[ -n $value ]] ; then 2036 value=${value#'} 2037 value=${value%'} 2038 fi 2039 echo $value 2040 2041 return 0 2042} 2043 2044# 2045# Privated function. Random select one of items from arguments. 2046# 2047# $1 count 2048# $2-n string 2049# 2050function _random_get 2051{ 2052 typeset cnt=$1 2053 shift 2054 2055 typeset str="$@" 2056 typeset -i ind 2057 ((ind = RANDOM % cnt + 1)) 2058 2059 typeset ret=$($ECHO "$str" | $CUT -f $ind -d ' ') 2060 $ECHO $ret 2061} 2062 2063# 2064# Random select one of item from arguments which include NONE string 2065# 2066function random_get_with_non 2067{ 2068 typeset -i cnt=$# 2069 ((cnt =+ 1)) 2070 2071 _random_get "$cnt" "$@" 2072} 2073 2074# 2075# Random select one of item from arguments which doesn't include NONE string 2076# 2077function random_get 2078{ 2079 _random_get "$#" "$@" 2080} 2081 2082# 2083# Detect if the current system support slog 2084# 2085function verify_slog_support 2086{ 2087 typeset dir=/tmp/disk.$$ 2088 typeset pool=foo.$$ 2089 typeset vdev=$dir/a 2090 typeset sdev=$dir/b 2091 2092 $MKDIR -p $dir 2093 $MKFILE 64M $vdev $sdev 2094 2095 typeset -i ret=0 2096 if ! $ZPOOL create -n $pool $vdev log $sdev > /dev/null 2>&1; then 2097 ret=1 2098 fi 2099 $RM -r $dir 2100 2101 return $ret 2102} 2103 2104# 2105# The function will generate a dataset name with specific length 2106# $1, the length of the name 2107# $2, the base string to construct the name 2108# 2109function gen_dataset_name 2110{ 2111 typeset -i len=$1 2112 typeset basestr="$2" 2113 typeset -i baselen=${#basestr} 2114 typeset -i iter=0 2115 typeset l_name="" 2116 2117 if ((len % baselen == 0)); then 2118 ((iter = len / baselen)) 2119 else 2120 ((iter = len / baselen + 1)) 2121 fi 2122 while ((iter > 0)); do 2123 l_name="${l_name}$basestr" 2124 2125 ((iter -= 1)) 2126 done 2127 2128 $ECHO $l_name 2129} 2130 2131# 2132# Get cksum tuple of dataset 2133# $1 dataset name 2134# 2135# sample zdb output: 2136# Dataset data/test [ZPL], ID 355, cr_txg 2413856, 31.0K, 7 objects, rootbp 2137# DVA[0]=<0:803046400:200> DVA[1]=<0:81199000:200> [L0 DMU objset] fletcher4 2138# lzjb LE contiguous unique double size=800L/200P birth=2413856L/2413856P 2139# fill=7 cksum=11ce125712:643a9c18ee2:125e25238fca0:254a3f74b59744 2140function datasetcksum 2141{ 2142 typeset cksum 2143 $SYNC 2144 cksum=$($ZDB -vvv $1 | $GREP "^Dataset $1 \[" | $GREP "cksum" \ 2145 | $AWK -F= '{print $7}') 2146 $ECHO $cksum 2147} 2148 2149# 2150# Get cksum of file 2151# #1 file path 2152# 2153function checksum 2154{ 2155 typeset cksum 2156 cksum=$($CKSUM $1 | $AWK '{print $1}') 2157 $ECHO $cksum 2158} 2159 2160# 2161# Get the given disk/slice state from the specific field of the pool 2162# 2163function get_device_state #pool disk field("", "spares","logs") 2164{ 2165 typeset pool=$1 2166 typeset disk=${2#/dev/dsk/} 2167 typeset field=${3:-$pool} 2168 2169 state=$($ZPOOL status -v "$pool" 2>/dev/null | \ 2170 $NAWK -v device=$disk -v pool=$pool -v field=$field \ 2171 'BEGIN {startconfig=0; startfield=0; } 2172 /config:/ {startconfig=1} 2173 (startconfig==1) && ($1==field) {startfield=1; next;} 2174 (startfield==1) && ($1==device) {print $2; exit;} 2175 (startfield==1) && 2176 ($1==field || $1 ~ "^spares$" || $1 ~ "^logs$") {startfield=0}') 2177 echo $state 2178} 2179 2180 2181# 2182# print the given directory filesystem type 2183# 2184# $1 directory name 2185# 2186function get_fstype 2187{ 2188 typeset dir=$1 2189 2190 if [[ -z $dir ]]; then 2191 log_fail "Usage: get_fstype <directory>" 2192 fi 2193 2194 # 2195 # $ df -n / 2196 # / : ufs 2197 # 2198 $DF -n $dir | $AWK '{print $3}' 2199} 2200 2201# 2202# Given a disk, label it to VTOC regardless what label was on the disk 2203# $1 disk 2204# 2205function labelvtoc 2206{ 2207 typeset disk=$1 2208 if [[ -z $disk ]]; then 2209 log_fail "The disk name is unspecified." 2210 fi 2211 typeset label_file=/var/tmp/labelvtoc.$$ 2212 typeset arch=$($UNAME -p) 2213 2214 if [[ $arch == "i386" ]]; then 2215 $ECHO "label" > $label_file 2216 $ECHO "0" >> $label_file 2217 $ECHO "" >> $label_file 2218 $ECHO "q" >> $label_file 2219 $ECHO "q" >> $label_file 2220 2221 $FDISK -B $disk >/dev/null 2>&1 2222 # wait a while for fdisk finishes 2223 $SLEEP 60 2224 elif [[ $arch == "sparc" ]]; then 2225 $ECHO "label" > $label_file 2226 $ECHO "0" >> $label_file 2227 $ECHO "" >> $label_file 2228 $ECHO "" >> $label_file 2229 $ECHO "" >> $label_file 2230 $ECHO "q" >> $label_file 2231 else 2232 log_fail "unknown arch type" 2233 fi 2234 2235 $FORMAT -e -s -d $disk -f $label_file 2236 typeset -i ret_val=$? 2237 $RM -f $label_file 2238 # 2239 # wait the format to finish 2240 # 2241 $SLEEP 60 2242 if ((ret_val != 0)); then 2243 log_fail "unable to label $disk as VTOC." 2244 fi 2245 2246 return 0 2247} 2248 2249# 2250# check if the system was installed as zfsroot or not 2251# return: 0 ture, otherwise false 2252# 2253function is_zfsroot 2254{ 2255 $DF -n / | $GREP zfs > /dev/null 2>&1 2256 return $? 2257} 2258 2259# 2260# get the root filesystem name if it's zfsroot system. 2261# 2262# return: root filesystem name 2263function get_rootfs 2264{ 2265 typeset rootfs="" 2266 rootfs=$($AWK '{if ($2 == "/" && $3 == "zfs") print $1}' \ 2267 /etc/mnttab) 2268 if [[ -z "$rootfs" ]]; then 2269 log_fail "Can not get rootfs" 2270 fi 2271 $ZFS list $rootfs > /dev/null 2>&1 2272 if (($? == 0)); then 2273 $ECHO $rootfs 2274 else 2275 log_fail "This is not a zfsroot system." 2276 fi 2277} 2278 2279# 2280# get the rootfs's pool name 2281# return: 2282# rootpool name 2283# 2284function get_rootpool 2285{ 2286 typeset rootfs="" 2287 typeset rootpool="" 2288 rootfs=$($AWK '{if ($2 == "/" && $3 =="zfs") print $1}' \ 2289 /etc/mnttab) 2290 if [[ -z "$rootfs" ]]; then 2291 log_fail "Can not get rootpool" 2292 fi 2293 $ZFS list $rootfs > /dev/null 2>&1 2294 if (($? == 0)); then 2295 rootpool=`$ECHO $rootfs | awk -F\/ '{print $1}'` 2296 $ECHO $rootpool 2297 else 2298 log_fail "This is not a zfsroot system." 2299 fi 2300} 2301 2302# 2303# Get the sub string from specified source string 2304# 2305# $1 source string 2306# $2 start position. Count from 1 2307# $3 offset 2308# 2309function get_substr #src_str pos offset 2310{ 2311 typeset pos offset 2312 2313 $ECHO $1 | \ 2314 $NAWK -v pos=$2 -v offset=$3 '{print substr($0, pos, offset)}' 2315} 2316 2317# 2318# Check if the given device is physical device 2319# 2320function is_physical_device #device 2321{ 2322 typeset device=${1#/dev/dsk/} 2323 device=${device#/dev/rdsk/} 2324 2325 $ECHO $device | $EGREP "^c[0-F]+([td][0-F]+)+$" > /dev/null 2>&1 2326 return $? 2327} 2328 2329# 2330# Get the directory path of given device 2331# 2332function get_device_dir #device 2333{ 2334 typeset device=$1 2335 2336 if ! $(is_physical_device $device) ; then 2337 if [[ $device != "/" ]]; then 2338 device=${device%/*} 2339 fi 2340 $ECHO $device 2341 else 2342 $ECHO "/dev/dsk" 2343 fi 2344} 2345 2346# 2347# Get the package name 2348# 2349function get_package_name 2350{ 2351 typeset dirpath=${1:-$STC_NAME} 2352 2353 echo "SUNWstc-${dirpath}" | /usr/bin/sed -e "s/\//-/g" 2354} 2355 2356# 2357# Get the word numbers from a string separated by white space 2358# 2359function get_word_count 2360{ 2361 $ECHO $1 | $WC -w 2362} 2363 2364# 2365# To verify if the require numbers of disks is given 2366# 2367function verify_disk_count 2368{ 2369 typeset -i min=${2:-1} 2370 2371 typeset -i count=$(get_word_count "$1") 2372 2373 if ((count < min)); then 2374 log_untested "A minimum of $min disks is required to run." \ 2375 " You specified $count disk(s)" 2376 fi 2377} 2378 2379function ds_is_volume 2380{ 2381 typeset type=$(get_prop type $1) 2382 [[ $type = "volume" ]] && return 0 2383 return 1 2384} 2385 2386function ds_is_filesystem 2387{ 2388 typeset type=$(get_prop type $1) 2389 [[ $type = "filesystem" ]] && return 0 2390 return 1 2391} 2392 2393function ds_is_snapshot 2394{ 2395 typeset type=$(get_prop type $1) 2396 [[ $type = "snapshot" ]] && return 0 2397 return 1 2398} 2399 2400# 2401# Check if Trusted Extensions are installed and enabled 2402# 2403function is_te_enabled 2404{ 2405 $SVCS -H -o state labeld 2>/dev/null | $GREP "enabled" 2406 if (($? != 0)); then 2407 return 1 2408 else 2409 return 0 2410 fi 2411} 2412 2413# Utility function to determine if a system has multiple cpus. 2414function is_mp 2415{ 2416 (($($PSRINFO | $WC -l) > 1)) 2417} 2418 2419function get_cpu_freq 2420{ 2421 $PSRINFO -v 0 | $AWK '/processor operates at/ {print $6}' 2422} 2423 2424# Run the given command as the user provided. 2425function user_run 2426{ 2427 typeset user=$1 2428 shift 2429 2430 eval \$SU \$user -c \"$@\" > /tmp/out 2>/tmp/err 2431 return $? 2432} 2433 2434# 2435# Check if the pool contains the specified vdevs 2436# 2437# $1 pool 2438# $2..n <vdev> ... 2439# 2440# Return 0 if the vdevs are contained in the pool, 1 if any of the specified 2441# vdevs is not in the pool, and 2 if pool name is missing. 2442# 2443function vdevs_in_pool 2444{ 2445 typeset pool=$1 2446 typeset vdev 2447 2448 if [[ -z $pool ]]; then 2449 log_note "Missing pool name." 2450 return 2 2451 fi 2452 2453 shift 2454 2455 typeset tmpfile=$($MKTEMP) 2456 $ZPOOL list -Hv "$pool" >$tmpfile 2457 for vdev in $@; do 2458 $GREP -w ${vdev##*/} $tmpfile >/dev/null 2>&1 2459 [[ $? -ne 0 ]] && return 1 2460 done 2461 2462 $RM -f $tmpfile 2463 2464 return 0; 2465} 2466