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