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, 2014 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 log_must $ZPOOL destroy -f $pool 1115 1116 [[ -d $mtpt ]] && \ 1117 log_must $RM -rf $mtpt 1118 else 1119 log_note "Pool not exist. ($pool)" 1120 return 1 1121 fi 1122 fi 1123 1124 return 0 1125} 1126 1127# 1128# Firstly, create a pool with 5 datasets. Then, create a single zone and 1129# export the 5 datasets to it. In addition, we also add a ZFS filesystem 1130# and a zvol device to the zone. 1131# 1132# $1 zone name 1133# $2 zone root directory prefix 1134# $3 zone ip 1135# 1136function zfs_zones_setup #zone_name zone_root zone_ip 1137{ 1138 typeset zone_name=${1:-$(hostname)-z} 1139 typeset zone_root=${2:-"/zone_root"} 1140 typeset zone_ip=${3:-"10.1.1.10"} 1141 typeset prefix_ctr=$ZONE_CTR 1142 typeset pool_name=$ZONE_POOL 1143 typeset -i cntctr=5 1144 typeset -i i=0 1145 1146 # Create pool and 5 container within it 1147 # 1148 [[ -d /$pool_name ]] && $RM -rf /$pool_name 1149 log_must $ZPOOL create -f $pool_name $DISKS 1150 while ((i < cntctr)); do 1151 log_must $ZFS create $pool_name/$prefix_ctr$i 1152 ((i += 1)) 1153 done 1154 1155 # create a zvol 1156 log_must $ZFS create -V 1g $pool_name/zone_zvol 1157 1158 # 1159 # If current system support slog, add slog device for pool 1160 # 1161 if verify_slog_support ; then 1162 typeset sdevs="/var/tmp/sdev1 /var/tmp/sdev2" 1163 log_must $MKFILE 100M $sdevs 1164 log_must $ZPOOL add $pool_name log mirror $sdevs 1165 fi 1166 1167 # this isn't supported just yet. 1168 # Create a filesystem. In order to add this to 1169 # the zone, it must have it's mountpoint set to 'legacy' 1170 # log_must $ZFS create $pool_name/zfs_filesystem 1171 # log_must $ZFS set mountpoint=legacy $pool_name/zfs_filesystem 1172 1173 [[ -d $zone_root ]] && \ 1174 log_must $RM -rf $zone_root/$zone_name 1175 [[ ! -d $zone_root ]] && \ 1176 log_must $MKDIR -p -m 0700 $zone_root/$zone_name 1177 1178 # Create zone configure file and configure the zone 1179 # 1180 typeset zone_conf=/tmp/zone_conf.$$ 1181 $ECHO "create" > $zone_conf 1182 $ECHO "set zonepath=$zone_root/$zone_name" >> $zone_conf 1183 $ECHO "set autoboot=true" >> $zone_conf 1184 i=0 1185 while ((i < cntctr)); do 1186 $ECHO "add dataset" >> $zone_conf 1187 $ECHO "set name=$pool_name/$prefix_ctr$i" >> \ 1188 $zone_conf 1189 $ECHO "end" >> $zone_conf 1190 ((i += 1)) 1191 done 1192 1193 # add our zvol to the zone 1194 $ECHO "add device" >> $zone_conf 1195 $ECHO "set match=/dev/zvol/dsk/$pool_name/zone_zvol" >> $zone_conf 1196 $ECHO "end" >> $zone_conf 1197 1198 # add a corresponding zvol rdsk to the zone 1199 $ECHO "add device" >> $zone_conf 1200 $ECHO "set match=/dev/zvol/rdsk/$pool_name/zone_zvol" >> $zone_conf 1201 $ECHO "end" >> $zone_conf 1202 1203 # once it's supported, we'll add our filesystem to the zone 1204 # $ECHO "add fs" >> $zone_conf 1205 # $ECHO "set type=zfs" >> $zone_conf 1206 # $ECHO "set special=$pool_name/zfs_filesystem" >> $zone_conf 1207 # $ECHO "set dir=/export/zfs_filesystem" >> $zone_conf 1208 # $ECHO "end" >> $zone_conf 1209 1210 $ECHO "verify" >> $zone_conf 1211 $ECHO "commit" >> $zone_conf 1212 log_must $ZONECFG -z $zone_name -f $zone_conf 1213 log_must $RM -f $zone_conf 1214 1215 # Install the zone 1216 $ZONEADM -z $zone_name install 1217 if (($? == 0)); then 1218 log_note "SUCCESS: $ZONEADM -z $zone_name install" 1219 else 1220 log_fail "FAIL: $ZONEADM -z $zone_name install" 1221 fi 1222 1223 # Install sysidcfg file 1224 # 1225 typeset sysidcfg=$zone_root/$zone_name/root/etc/sysidcfg 1226 $ECHO "system_locale=C" > $sysidcfg 1227 $ECHO "terminal=dtterm" >> $sysidcfg 1228 $ECHO "network_interface=primary {" >> $sysidcfg 1229 $ECHO "hostname=$zone_name" >> $sysidcfg 1230 $ECHO "}" >> $sysidcfg 1231 $ECHO "name_service=NONE" >> $sysidcfg 1232 $ECHO "root_password=mo791xfZ/SFiw" >> $sysidcfg 1233 $ECHO "security_policy=NONE" >> $sysidcfg 1234 $ECHO "timezone=US/Eastern" >> $sysidcfg 1235 1236 # Boot this zone 1237 log_must $ZONEADM -z $zone_name boot 1238} 1239 1240# 1241# Reexport TESTPOOL & TESTPOOL(1-4) 1242# 1243function reexport_pool 1244{ 1245 typeset -i cntctr=5 1246 typeset -i i=0 1247 1248 while ((i < cntctr)); do 1249 if ((i == 0)); then 1250 TESTPOOL=$ZONE_POOL/$ZONE_CTR$i 1251 if ! ismounted $TESTPOOL; then 1252 log_must $ZFS mount $TESTPOOL 1253 fi 1254 else 1255 eval TESTPOOL$i=$ZONE_POOL/$ZONE_CTR$i 1256 if eval ! ismounted \$TESTPOOL$i; then 1257 log_must eval $ZFS mount \$TESTPOOL$i 1258 fi 1259 fi 1260 ((i += 1)) 1261 done 1262} 1263 1264# 1265# Verify a given disk is online or offline 1266# 1267# Return 0 is pool/disk matches expected state, 1 otherwise 1268# 1269function check_state # pool disk state{online,offline} 1270{ 1271 typeset pool=$1 1272 typeset disk=${2#/dev/dsk/} 1273 typeset state=$3 1274 1275 $ZPOOL status -v $pool | grep "$disk" \ 1276 | grep -i "$state" > /dev/null 2>&1 1277 1278 return $? 1279} 1280 1281# 1282# Get the mountpoint of snapshot 1283# For the snapshot use <mp_filesystem>/.zfs/snapshot/<snap> 1284# as its mountpoint 1285# 1286function snapshot_mountpoint 1287{ 1288 typeset dataset=${1:-$TESTPOOL/$TESTFS@$TESTSNAP} 1289 1290 if [[ $dataset != *@* ]]; then 1291 log_fail "Error name of snapshot '$dataset'." 1292 fi 1293 1294 typeset fs=${dataset%@*} 1295 typeset snap=${dataset#*@} 1296 1297 if [[ -z $fs || -z $snap ]]; then 1298 log_fail "Error name of snapshot '$dataset'." 1299 fi 1300 1301 $ECHO $(get_prop mountpoint $fs)/.zfs/snapshot/$snap 1302} 1303 1304# 1305# Given a pool and file system, this function will verify the file system 1306# using the zdb internal tool. Note that the pool is exported and imported 1307# to ensure it has consistent state. 1308# 1309function verify_filesys # pool filesystem dir 1310{ 1311 typeset pool="$1" 1312 typeset filesys="$2" 1313 typeset zdbout="/tmp/zdbout.$$" 1314 1315 shift 1316 shift 1317 typeset dirs=$@ 1318 typeset search_path="" 1319 1320 log_note "Calling $ZDB to verify filesystem '$filesys'" 1321 $ZFS unmount -a > /dev/null 2>&1 1322 log_must $ZPOOL export $pool 1323 1324 if [[ -n $dirs ]] ; then 1325 for dir in $dirs ; do 1326 search_path="$search_path -d $dir" 1327 done 1328 fi 1329 1330 log_must $ZPOOL import $search_path $pool 1331 1332 $ZDB -cudi $filesys > $zdbout 2>&1 1333 if [[ $? != 0 ]]; then 1334 log_note "Output: $ZDB -cudi $filesys" 1335 $CAT $zdbout 1336 log_fail "$ZDB detected errors with: '$filesys'" 1337 fi 1338 1339 log_must $ZFS mount -a 1340 log_must $RM -rf $zdbout 1341} 1342 1343# 1344# Given a pool, and this function list all disks in the pool 1345# 1346function get_disklist # pool 1347{ 1348 typeset disklist="" 1349 1350 disklist=$($ZPOOL iostat -v $1 | $NAWK '(NR >4) {print $1}' | \ 1351 $GREP -v "\-\-\-\-\-" | \ 1352 $EGREP -v -e "^(mirror|raidz1|raidz2|spare|log|cache)$") 1353 1354 $ECHO $disklist 1355} 1356 1357# 1358# Destroy all existing metadevices and state database 1359# 1360function destroy_metas 1361{ 1362 typeset metad 1363 1364 for metad in $($METASTAT -p | $AWK '{print $1}'); do 1365 log_must $METACLEAR -rf $metad 1366 done 1367 1368 for metad in $($METADB | $CUT -f6 | $GREP dev | $UNIQ); do 1369 log_must $METADB -fd $metad 1370 done 1371} 1372 1373# /** 1374# This function kills a given list of processes after a time period. We use 1375# this in the stress tests instead of STF_TIMEOUT so that we can have processes 1376# run for a fixed amount of time, yet still pass. Tests that hit STF_TIMEOUT 1377# would be listed as FAIL, which we don't want : we're happy with stress tests 1378# running for a certain amount of time, then finishing. 1379# 1380# @param $1 the time in seconds after which we should terminate these processes 1381# @param $2..$n the processes we wish to terminate. 1382# */ 1383function stress_timeout 1384{ 1385 typeset -i TIMEOUT=$1 1386 shift 1387 typeset cpids="$@" 1388 1389 log_note "Waiting for child processes($cpids). " \ 1390 "It could last dozens of minutes, please be patient ..." 1391 log_must $SLEEP $TIMEOUT 1392 1393 log_note "Killing child processes after ${TIMEOUT} stress timeout." 1394 typeset pid 1395 for pid in $cpids; do 1396 $PS -p $pid > /dev/null 2>&1 1397 if (($? == 0)); then 1398 log_must $KILL -USR1 $pid 1399 fi 1400 done 1401} 1402 1403# 1404# Verify a given hotspare disk is inuse or avail 1405# 1406# Return 0 is pool/disk matches expected state, 1 otherwise 1407# 1408function check_hotspare_state # pool disk state{inuse,avail} 1409{ 1410 typeset pool=$1 1411 typeset disk=${2#/dev/dsk/} 1412 typeset state=$3 1413 1414 cur_state=$(get_device_state $pool $disk "spares") 1415 1416 if [[ $state != ${cur_state} ]]; then 1417 return 1 1418 fi 1419 return 0 1420} 1421 1422# 1423# Verify a given slog disk is inuse or avail 1424# 1425# Return 0 is pool/disk matches expected state, 1 otherwise 1426# 1427function check_slog_state # pool disk state{online,offline,unavail} 1428{ 1429 typeset pool=$1 1430 typeset disk=${2#/dev/dsk/} 1431 typeset state=$3 1432 1433 cur_state=$(get_device_state $pool $disk "logs") 1434 1435 if [[ $state != ${cur_state} ]]; then 1436 return 1 1437 fi 1438 return 0 1439} 1440 1441# 1442# Verify a given vdev disk is inuse or avail 1443# 1444# Return 0 is pool/disk matches expected state, 1 otherwise 1445# 1446function check_vdev_state # pool disk state{online,offline,unavail} 1447{ 1448 typeset pool=$1 1449 typeset disk=${2#/dev/dsk/} 1450 typeset state=$3 1451 1452 cur_state=$(get_device_state $pool $disk) 1453 1454 if [[ $state != ${cur_state} ]]; then 1455 return 1 1456 fi 1457 return 0 1458} 1459 1460# 1461# Check the output of 'zpool status -v <pool>', 1462# and to see if the content of <token> contain the <keyword> specified. 1463# 1464# Return 0 is contain, 1 otherwise 1465# 1466function check_pool_status # pool token keyword 1467{ 1468 typeset pool=$1 1469 typeset token=$2 1470 typeset keyword=$3 1471 1472 $ZPOOL status -v "$pool" 2>/dev/null | $NAWK -v token="$token:" ' 1473 ($1==token) {print $0}' \ 1474 | $GREP -i "$keyword" > /dev/null 2>&1 1475 1476 return $? 1477} 1478 1479# 1480# These 5 following functions are instance of check_pool_status() 1481# is_pool_resilvering - to check if the pool is resilver in progress 1482# is_pool_resilvered - to check if the pool is resilver completed 1483# is_pool_scrubbing - to check if the pool is scrub in progress 1484# is_pool_scrubbed - to check if the pool is scrub completed 1485# is_pool_scrub_stopped - to check if the pool is scrub stopped 1486# 1487function is_pool_resilvering #pool 1488{ 1489 check_pool_status "$1" "scan" "resilver in progress since " 1490 return $? 1491} 1492 1493function is_pool_resilvered #pool 1494{ 1495 check_pool_status "$1" "scan" "resilvered " 1496 return $? 1497} 1498 1499function is_pool_scrubbing #pool 1500{ 1501 check_pool_status "$1" "scan" "scrub in progress since " 1502 return $? 1503} 1504 1505function is_pool_scrubbed #pool 1506{ 1507 check_pool_status "$1" "scan" "scrub repaired" 1508 return $? 1509} 1510 1511function is_pool_scrub_stopped #pool 1512{ 1513 check_pool_status "$1" "scan" "scrub canceled" 1514 return $? 1515} 1516 1517# 1518# Use create_pool()/destroy_pool() to clean up the infomation in 1519# in the given disk to avoid slice overlapping. 1520# 1521function cleanup_devices #vdevs 1522{ 1523 typeset pool="foopool$$" 1524 1525 if poolexists $pool ; then 1526 destroy_pool $pool 1527 fi 1528 1529 create_pool $pool $@ 1530 destroy_pool $pool 1531 1532 return 0 1533} 1534 1535# 1536# Verify the rsh connectivity to each remote host in RHOSTS. 1537# 1538# Return 0 if remote host is accessible; otherwise 1. 1539# $1 remote host name 1540# $2 username 1541# 1542function verify_rsh_connect #rhost, username 1543{ 1544 typeset rhost=$1 1545 typeset username=$2 1546 typeset rsh_cmd="$RSH -n" 1547 typeset cur_user= 1548 1549 $GETENT hosts $rhost >/dev/null 2>&1 1550 if (($? != 0)); then 1551 log_note "$rhost cannot be found from" \ 1552 "administrative database." 1553 return 1 1554 fi 1555 1556 $PING $rhost 3 >/dev/null 2>&1 1557 if (($? != 0)); then 1558 log_note "$rhost is not reachable." 1559 return 1 1560 fi 1561 1562 if ((${#username} != 0)); then 1563 rsh_cmd="$rsh_cmd -l $username" 1564 cur_user="given user \"$username\"" 1565 else 1566 cur_user="current user \"`$LOGNAME`\"" 1567 fi 1568 1569 if ! $rsh_cmd $rhost $TRUE; then 1570 log_note "$RSH to $rhost is not accessible" \ 1571 "with $cur_user." 1572 return 1 1573 fi 1574 1575 return 0 1576} 1577 1578# 1579# Verify the remote host connection via rsh after rebooting 1580# $1 remote host 1581# 1582function verify_remote 1583{ 1584 rhost=$1 1585 1586 # 1587 # The following loop waits for the remote system rebooting. 1588 # Each iteration will wait for 150 seconds. there are 1589 # total 5 iterations, so the total timeout value will 1590 # be 12.5 minutes for the system rebooting. This number 1591 # is an approxiate number. 1592 # 1593 typeset -i count=0 1594 while ! verify_rsh_connect $rhost; do 1595 sleep 150 1596 ((count = count + 1)) 1597 if ((count > 5)); then 1598 return 1 1599 fi 1600 done 1601 return 0 1602} 1603 1604# 1605# Replacement function for /usr/bin/rsh. This function will include 1606# the /usr/bin/rsh and meanwhile return the execution status of the 1607# last command. 1608# 1609# $1 usrname passing down to -l option of /usr/bin/rsh 1610# $2 remote machine hostname 1611# $3... command string 1612# 1613 1614function rsh_status 1615{ 1616 typeset ruser=$1 1617 typeset rhost=$2 1618 typeset -i ret=0 1619 typeset cmd_str="" 1620 typeset rsh_str="" 1621 1622 shift; shift 1623 cmd_str="$@" 1624 1625 err_file=/tmp/${rhost}.$$.err 1626 if ((${#ruser} == 0)); then 1627 rsh_str="$RSH -n" 1628 else 1629 rsh_str="$RSH -n -l $ruser" 1630 fi 1631 1632 $rsh_str $rhost /usr/bin/ksh -c "'$cmd_str; \ 1633 print -u 2 \"status=\$?\"'" \ 1634 >/dev/null 2>$err_file 1635 ret=$? 1636 if (($ret != 0)); then 1637 $CAT $err_file 1638 $RM -f $std_file $err_file 1639 log_fail "$RSH itself failed with exit code $ret..." 1640 fi 1641 1642 ret=$($GREP -v 'print -u 2' $err_file | $GREP 'status=' | \ 1643 $CUT -d= -f2) 1644 (($ret != 0)) && $CAT $err_file >&2 1645 1646 $RM -f $err_file >/dev/null 2>&1 1647 return $ret 1648} 1649 1650# 1651# Get the SUNWstc-fs-zfs package installation path in a remote host 1652# $1 remote host name 1653# 1654function get_remote_pkgpath 1655{ 1656 typeset rhost=$1 1657 typeset pkgpath="" 1658 1659 pkgpath=$($RSH -n $rhost "$PKGINFO -l SUNWstc-fs-zfs | $GREP BASEDIR: |\ 1660 $CUT -d: -f2") 1661 1662 $ECHO $pkgpath 1663} 1664 1665#/** 1666# A function to find and locate free disks on a system or from given 1667# disks as the parameter. It works by locating disks that are in use 1668# as swap devices, SVM devices, and dump devices, and also disks 1669# listed in /etc/vfstab 1670# 1671# $@ given disks to find which are free, default is all disks in 1672# the test system 1673# 1674# @return a string containing the list of available disks 1675#*/ 1676function find_disks 1677{ 1678 sfi=/tmp/swaplist.$$ 1679 msi=/tmp/metastat.$$ 1680 dmpi=/tmp/dumpdev.$$ 1681 max_finddisksnum=${MAX_FINDDISKSNUM:-6} 1682 1683 $SWAP -l > $sfi 1684 $METASTAT -c > $msi 2>/dev/null 1685 $DUMPADM > $dmpi 2>/dev/null 1686 1687# write an awk script that can process the output of format 1688# to produce a list of disks we know about. Note that we have 1689# to escape "$2" so that the shell doesn't interpret it while 1690# we're creating the awk script. 1691# ------------------- 1692 $CAT > /tmp/find_disks.awk <<EOF 1693#!/bin/nawk -f 1694 BEGIN { FS="."; } 1695 1696 /^Specify disk/{ 1697 searchdisks=0; 1698 } 1699 1700 { 1701 if (searchdisks && \$2 !~ "^$"){ 1702 split(\$2,arr," "); 1703 print arr[1]; 1704 } 1705 } 1706 1707 /^AVAILABLE DISK SELECTIONS:/{ 1708 searchdisks=1; 1709 } 1710EOF 1711#--------------------- 1712 1713 $CHMOD 755 /tmp/find_disks.awk 1714 disks=${@:-$($ECHO "" | $FORMAT -e 2>/dev/null | /tmp/find_disks.awk)} 1715 $RM /tmp/find_disks.awk 1716 1717 unused="" 1718 for disk in $disks; do 1719 # Check for mounted 1720 $GREP "${disk}[sp]" /etc/mnttab >/dev/null 1721 (($? == 0)) && continue 1722 # Check for swap 1723 $GREP "${disk}[sp]" $sfi >/dev/null 1724 (($? == 0)) && continue 1725 # Check for SVM 1726 $GREP "${disk}" $msi >/dev/null 1727 (($? == 0)) && continue 1728 # check for dump device 1729 $GREP "${disk}[sp]" $dmpi >/dev/null 1730 (($? == 0)) && continue 1731 # check to see if this disk hasn't been explicitly excluded 1732 # by a user-set environment variable 1733 $ECHO "${ZFS_HOST_DEVICES_IGNORE}" | $GREP "${disk}" > /dev/null 1734 (($? == 0)) && continue 1735 unused_candidates="$unused_candidates $disk" 1736 done 1737 $RM $sfi 1738 $RM $msi 1739 $RM $dmpi 1740 1741# now just check to see if those disks do actually exist 1742# by looking for a device pointing to the first slice in 1743# each case. limit the number to max_finddisksnum 1744 count=0 1745 for disk in $unused_candidates; do 1746 if [ -b /dev/dsk/${disk}s0 ]; then 1747 if [ $count -lt $max_finddisksnum ]; then 1748 unused="$unused $disk" 1749 # do not impose limit if $@ is provided 1750 [[ -z $@ ]] && ((count = count + 1)) 1751 fi 1752 fi 1753 done 1754 1755# finally, return our disk list 1756 $ECHO $unused 1757} 1758 1759# 1760# Add specified user to specified group 1761# 1762# $1 group name 1763# $2 user name 1764# $3 base of the homedir (optional) 1765# 1766function add_user #<group_name> <user_name> <basedir> 1767{ 1768 typeset gname=$1 1769 typeset uname=$2 1770 typeset basedir=${3:-"/var/tmp"} 1771 1772 if ((${#gname} == 0 || ${#uname} == 0)); then 1773 log_fail "group name or user name are not defined." 1774 fi 1775 1776 log_must $USERADD -g $gname -d $basedir/$uname -m $uname 1777 1778 return 0 1779} 1780 1781# 1782# Delete the specified user. 1783# 1784# $1 login name 1785# $2 base of the homedir (optional) 1786# 1787function del_user #<logname> <basedir> 1788{ 1789 typeset user=$1 1790 typeset basedir=${2:-"/var/tmp"} 1791 1792 if ((${#user} == 0)); then 1793 log_fail "login name is necessary." 1794 fi 1795 1796 if $ID $user > /dev/null 2>&1; then 1797 log_must $USERDEL $user 1798 fi 1799 1800 [[ -d $basedir/$user ]] && $RM -fr $basedir/$user 1801 1802 return 0 1803} 1804 1805# 1806# Select valid gid and create specified group. 1807# 1808# $1 group name 1809# 1810function add_group #<group_name> 1811{ 1812 typeset group=$1 1813 1814 if ((${#group} == 0)); then 1815 log_fail "group name is necessary." 1816 fi 1817 1818 # Assign 100 as the base gid 1819 typeset -i gid=100 1820 while true; do 1821 $GROUPADD -g $gid $group > /dev/null 2>&1 1822 typeset -i ret=$? 1823 case $ret in 1824 0) return 0 ;; 1825 # The gid is not unique 1826 4) ((gid += 1)) ;; 1827 *) return 1 ;; 1828 esac 1829 done 1830} 1831 1832# 1833# Delete the specified group. 1834# 1835# $1 group name 1836# 1837function del_group #<group_name> 1838{ 1839 typeset grp=$1 1840 if ((${#grp} == 0)); then 1841 log_fail "group name is necessary." 1842 fi 1843 1844 $GROUPMOD -n $grp $grp > /dev/null 2>&1 1845 typeset -i ret=$? 1846 case $ret in 1847 # Group does not exist. 1848 6) return 0 ;; 1849 # Name already exists as a group name 1850 9) log_must $GROUPDEL $grp ;; 1851 *) return 1 ;; 1852 esac 1853 1854 return 0 1855} 1856 1857# 1858# This function will return true if it's safe to destroy the pool passed 1859# as argument 1. It checks for pools based on zvols and files, and also 1860# files contained in a pool that may have a different mountpoint. 1861# 1862function safe_to_destroy_pool { # $1 the pool name 1863 1864 typeset pool="" 1865 typeset DONT_DESTROY="" 1866 1867 # We check that by deleting the $1 pool, we're not 1868 # going to pull the rug out from other pools. Do this 1869 # by looking at all other pools, ensuring that they 1870 # aren't built from files or zvols contained in this pool. 1871 1872 for pool in $($ZPOOL list -H -o name) 1873 do 1874 ALTMOUNTPOOL="" 1875 1876 # this is a list of the top-level directories in each of the 1877 # files that make up the path to the files the pool is based on 1878 FILEPOOL=$($ZPOOL status -v $pool | $GREP /$1/ | \ 1879 $AWK '{print $1}') 1880 1881 # this is a list of the zvols that make up the pool 1882 ZVOLPOOL=$($ZPOOL status -v $pool | $GREP "/dev/zvol/dsk/$1$" \ 1883 | $AWK '{print $1}') 1884 1885 # also want to determine if it's a file-based pool using an 1886 # alternate mountpoint... 1887 POOL_FILE_DIRS=$($ZPOOL status -v $pool | \ 1888 $GREP / | $AWK '{print $1}' | \ 1889 $AWK -F/ '{print $2}' | $GREP -v "dev") 1890 1891 for pooldir in $POOL_FILE_DIRS 1892 do 1893 OUTPUT=$($ZFS list -H -r -o mountpoint $1 | \ 1894 $GREP "${pooldir}$" | $AWK '{print $1}') 1895 1896 ALTMOUNTPOOL="${ALTMOUNTPOOL}${OUTPUT}" 1897 done 1898 1899 1900 if [ ! -z "$ZVOLPOOL" ] 1901 then 1902 DONT_DESTROY="true" 1903 log_note "Pool $pool is built from $ZVOLPOOL on $1" 1904 fi 1905 1906 if [ ! -z "$FILEPOOL" ] 1907 then 1908 DONT_DESTROY="true" 1909 log_note "Pool $pool is built from $FILEPOOL on $1" 1910 fi 1911 1912 if [ ! -z "$ALTMOUNTPOOL" ] 1913 then 1914 DONT_DESTROY="true" 1915 log_note "Pool $pool is built from $ALTMOUNTPOOL on $1" 1916 fi 1917 done 1918 1919 if [ -z "${DONT_DESTROY}" ] 1920 then 1921 return 0 1922 else 1923 log_note "Warning: it is not safe to destroy $1!" 1924 return 1 1925 fi 1926} 1927 1928# 1929# Get IP address of hostname 1930# $1 hostname 1931# 1932function getipbyhost 1933{ 1934 typeset ip 1935 ip=`$ARP $1 2>/dev/null | $AWK -F\) '{print $1}' \ 1936 | $AWK -F\('{print $2}'` 1937 $ECHO $ip 1938} 1939 1940# 1941# Setup iSCSI initiator to target 1942# $1 target hostname 1943# 1944function iscsi_isetup 1945{ 1946 # check svc:/network/iscsi_initiator:default state, try to enable it 1947 # if the state is not ON 1948 typeset ISCSII_FMRI="svc:/network/iscsi_initiator:default" 1949 if [[ "ON" != $($SVCS -H -o sta $ISCSII_FMRI) ]]; then 1950 log_must $SVCADM enable $ISCSII_FMRI 1951 1952 typeset -i retry=20 1953 while [[ "ON" != $($SVCS -H -o sta $ISCSII_FMRI) && \ 1954 ($retry -ne 0) ]] 1955 do 1956 ((retry = retry - 1)) 1957 $SLEEP 1 1958 done 1959 1960 if [[ "ON" != $($SVCS -H -o sta $ISCSII_FMRI) ]]; then 1961 log_fail "$ISCSII_FMRI service can not be enabled!" 1962 fi 1963 fi 1964 1965 log_must $ISCSIADM add discovery-address $(getipbyhost $1) 1966 log_must $ISCSIADM modify discovery --sendtargets enable 1967 log_must $DEVFSADM -i iscsi 1968} 1969 1970# 1971# Check whether iscsi parameter is set as remote 1972# 1973# return 0 if iscsi is set as remote, otherwise 1 1974# 1975function check_iscsi_remote 1976{ 1977 if [[ $iscsi == "remote" ]] ; then 1978 return 0 1979 else 1980 return 1 1981 fi 1982} 1983 1984# 1985# Check if a volume is a valide iscsi target 1986# $1 volume name 1987# return 0 if suceeds, otherwise, return 1 1988# 1989function is_iscsi_target 1990{ 1991 typeset dataset=$1 1992 typeset target targets 1993 1994 [[ -z $dataset ]] && return 1 1995 1996 targets=$($ISCSITADM list target | $GREP "Target:" | $AWK '{print $2}') 1997 [[ -z $targets ]] && return 1 1998 1999 for target in $targets; do 2000 [[ $dataset == $target ]] && return 0 2001 done 2002 2003 return 1 2004} 2005 2006# 2007# Get the iSCSI name of a target 2008# $1 target name 2009# 2010function iscsi_name 2011{ 2012 typeset target=$1 2013 typeset name 2014 2015 [[ -z $target ]] && log_fail "No parameter." 2016 2017 if ! is_iscsi_target $target ; then 2018 log_fail "Not a target." 2019 fi 2020 2021 name=$($ISCSITADM list target $target | $GREP "iSCSI Name:" \ 2022 | $AWK '{print $2}') 2023 2024 return $name 2025} 2026 2027# 2028# check svc:/system/iscsitgt:default state, try to enable it if the state 2029# is not ON 2030# 2031function iscsitgt_setup 2032{ 2033 log_must $RM -f $ISCSITGTFILE 2034 if [[ "ON" == $($SVCS -H -o sta $ISCSITGT_FMRI) ]]; then 2035 log_note "iscsitgt is already enabled" 2036 return 2037 fi 2038 2039 log_must $SVCADM enable -t $ISCSITGT_FMRI 2040 2041 typeset -i retry=20 2042 while [[ "ON" != $($SVCS -H -o sta $ISCSITGT_FMRI) && \ 2043 ($retry -ne 0) ]] 2044 do 2045 $SLEEP 1 2046 ((retry = retry - 1)) 2047 done 2048 2049 if [[ "ON" != $($SVCS -H -o sta $ISCSITGT_FMRI) ]]; then 2050 log_fail "$ISCSITGT_FMRI service can not be enabled!" 2051 fi 2052 2053 log_must $TOUCH $ISCSITGTFILE 2054} 2055 2056# 2057# set DISABLED state of svc:/system/iscsitgt:default 2058# which is the most suiteable state if $ISCSITGTFILE exists 2059# 2060function iscsitgt_cleanup 2061{ 2062 if [[ -e $ISCSITGTFILE ]]; then 2063 log_must $SVCADM disable $ISCSITGT_FMRI 2064 log_must $RM -f $ISCSITGTFILE 2065 fi 2066} 2067 2068# 2069# Close iSCSI initiator to target 2070# $1 target hostname 2071# 2072function iscsi_iclose 2073{ 2074 log_must $ISCSIADM modify discovery --sendtargets disable 2075 log_must $ISCSIADM remove discovery-address $(getipbyhost $1) 2076 $DEVFSADM -Cv 2077} 2078 2079# 2080# Get the available ZFS compression options 2081# $1 option type zfs_set|zfs_compress 2082# 2083function get_compress_opts 2084{ 2085 typeset COMPRESS_OPTS 2086 typeset GZIP_OPTS="gzip gzip-1 gzip-2 gzip-3 gzip-4 gzip-5 \ 2087 gzip-6 gzip-7 gzip-8 gzip-9" 2088 2089 if [[ $1 == "zfs_compress" ]] ; then 2090 COMPRESS_OPTS="on lzjb" 2091 elif [[ $1 == "zfs_set" ]] ; then 2092 COMPRESS_OPTS="on off lzjb" 2093 fi 2094 typeset valid_opts="$COMPRESS_OPTS" 2095 $ZFS get 2>&1 | $GREP gzip >/dev/null 2>&1 2096 if [[ $? -eq 0 ]]; then 2097 valid_opts="$valid_opts $GZIP_OPTS" 2098 fi 2099 $ECHO "$valid_opts" 2100} 2101 2102# 2103# Verify zfs operation with -p option work as expected 2104# $1 operation, value could be create, clone or rename 2105# $2 dataset type, value could be fs or vol 2106# $3 dataset name 2107# $4 new dataset name 2108# 2109function verify_opt_p_ops 2110{ 2111 typeset ops=$1 2112 typeset datatype=$2 2113 typeset dataset=$3 2114 typeset newdataset=$4 2115 2116 if [[ $datatype != "fs" && $datatype != "vol" ]]; then 2117 log_fail "$datatype is not supported." 2118 fi 2119 2120 # check parameters accordingly 2121 case $ops in 2122 create) 2123 newdataset=$dataset 2124 dataset="" 2125 if [[ $datatype == "vol" ]]; then 2126 ops="create -V $VOLSIZE" 2127 fi 2128 ;; 2129 clone) 2130 if [[ -z $newdataset ]]; then 2131 log_fail "newdataset should not be empty" \ 2132 "when ops is $ops." 2133 fi 2134 log_must datasetexists $dataset 2135 log_must snapexists $dataset 2136 ;; 2137 rename) 2138 if [[ -z $newdataset ]]; then 2139 log_fail "newdataset should not be empty" \ 2140 "when ops is $ops." 2141 fi 2142 log_must datasetexists $dataset 2143 log_mustnot snapexists $dataset 2144 ;; 2145 *) 2146 log_fail "$ops is not supported." 2147 ;; 2148 esac 2149 2150 # make sure the upper level filesystem does not exist 2151 if datasetexists ${newdataset%/*} ; then 2152 log_must $ZFS destroy -rRf ${newdataset%/*} 2153 fi 2154 2155 # without -p option, operation will fail 2156 log_mustnot $ZFS $ops $dataset $newdataset 2157 log_mustnot datasetexists $newdataset ${newdataset%/*} 2158 2159 # with -p option, operation should succeed 2160 log_must $ZFS $ops -p $dataset $newdataset 2161 if ! datasetexists $newdataset ; then 2162 log_fail "-p option does not work for $ops" 2163 fi 2164 2165 # when $ops is create or clone, redo the operation still return zero 2166 if [[ $ops != "rename" ]]; then 2167 log_must $ZFS $ops -p $dataset $newdataset 2168 fi 2169 2170 return 0 2171} 2172 2173# 2174# Get configuration of pool 2175# $1 pool name 2176# $2 config name 2177# 2178function get_config 2179{ 2180 typeset pool=$1 2181 typeset config=$2 2182 typeset alt_root 2183 2184 if ! poolexists "$pool" ; then 2185 return 1 2186 fi 2187 alt_root=$($ZPOOL list -H $pool | $AWK '{print $NF}') 2188 if [[ $alt_root == "-" ]]; then 2189 value=$($ZDB -C $pool | $GREP "$config:" | $AWK -F: \ 2190 '{print $2}') 2191 else 2192 value=$($ZDB -e $pool | $GREP "$config:" | $AWK -F: \ 2193 '{print $2}') 2194 fi 2195 if [[ -n $value ]] ; then 2196 value=${value#'} 2197 value=${value%'} 2198 fi 2199 echo $value 2200 2201 return 0 2202} 2203 2204# 2205# Privated function. Random select one of items from arguments. 2206# 2207# $1 count 2208# $2-n string 2209# 2210function _random_get 2211{ 2212 typeset cnt=$1 2213 shift 2214 2215 typeset str="$@" 2216 typeset -i ind 2217 ((ind = RANDOM % cnt + 1)) 2218 2219 typeset ret=$($ECHO "$str" | $CUT -f $ind -d ' ') 2220 $ECHO $ret 2221} 2222 2223# 2224# Random select one of item from arguments which include NONE string 2225# 2226function random_get_with_non 2227{ 2228 typeset -i cnt=$# 2229 ((cnt =+ 1)) 2230 2231 _random_get "$cnt" "$@" 2232} 2233 2234# 2235# Random select one of item from arguments which doesn't include NONE string 2236# 2237function random_get 2238{ 2239 _random_get "$#" "$@" 2240} 2241 2242# 2243# Detect if the current system support slog 2244# 2245function verify_slog_support 2246{ 2247 typeset dir=/tmp/disk.$$ 2248 typeset pool=foo.$$ 2249 typeset vdev=$dir/a 2250 typeset sdev=$dir/b 2251 2252 $MKDIR -p $dir 2253 $MKFILE 64M $vdev $sdev 2254 2255 typeset -i ret=0 2256 if ! $ZPOOL create -n $pool $vdev log $sdev > /dev/null 2>&1; then 2257 ret=1 2258 fi 2259 $RM -r $dir 2260 2261 return $ret 2262} 2263 2264# 2265# The function will generate a dataset name with specific length 2266# $1, the length of the name 2267# $2, the base string to construct the name 2268# 2269function gen_dataset_name 2270{ 2271 typeset -i len=$1 2272 typeset basestr="$2" 2273 typeset -i baselen=${#basestr} 2274 typeset -i iter=0 2275 typeset l_name="" 2276 2277 if ((len % baselen == 0)); then 2278 ((iter = len / baselen)) 2279 else 2280 ((iter = len / baselen + 1)) 2281 fi 2282 while ((iter > 0)); do 2283 l_name="${l_name}$basestr" 2284 2285 ((iter -= 1)) 2286 done 2287 2288 $ECHO $l_name 2289} 2290 2291# 2292# Get cksum tuple of dataset 2293# $1 dataset name 2294# 2295# sample zdb output: 2296# Dataset data/test [ZPL], ID 355, cr_txg 2413856, 31.0K, 7 objects, rootbp 2297# DVA[0]=<0:803046400:200> DVA[1]=<0:81199000:200> [L0 DMU objset] fletcher4 2298# lzjb LE contiguous unique double size=800L/200P birth=2413856L/2413856P 2299# fill=7 cksum=11ce125712:643a9c18ee2:125e25238fca0:254a3f74b59744 2300function datasetcksum 2301{ 2302 typeset cksum 2303 $SYNC 2304 cksum=$($ZDB -vvv $1 | $GREP "^Dataset $1 \[" | $GREP "cksum" \ 2305 | $AWK -F= '{print $7}') 2306 $ECHO $cksum 2307} 2308 2309# 2310# Get cksum of file 2311# #1 file path 2312# 2313function checksum 2314{ 2315 typeset cksum 2316 cksum=$($CKSUM $1 | $AWK '{print $1}') 2317 $ECHO $cksum 2318} 2319 2320# 2321# Get the given disk/slice state from the specific field of the pool 2322# 2323function get_device_state #pool disk field("", "spares","logs") 2324{ 2325 typeset pool=$1 2326 typeset disk=${2#/dev/dsk/} 2327 typeset field=${3:-$pool} 2328 2329 state=$($ZPOOL status -v "$pool" 2>/dev/null | \ 2330 $NAWK -v device=$disk -v pool=$pool -v field=$field \ 2331 'BEGIN {startconfig=0; startfield=0; } 2332 /config:/ {startconfig=1} 2333 (startconfig==1) && ($1==field) {startfield=1; next;} 2334 (startfield==1) && ($1==device) {print $2; exit;} 2335 (startfield==1) && 2336 ($1==field || $1 ~ "^spares$" || $1 ~ "^logs$") {startfield=0}') 2337 echo $state 2338} 2339 2340 2341# 2342# print the given directory filesystem type 2343# 2344# $1 directory name 2345# 2346function get_fstype 2347{ 2348 typeset dir=$1 2349 2350 if [[ -z $dir ]]; then 2351 log_fail "Usage: get_fstype <directory>" 2352 fi 2353 2354 # 2355 # $ df -n / 2356 # / : ufs 2357 # 2358 $DF -n $dir | $AWK '{print $3}' 2359} 2360 2361# 2362# Given a disk, label it to VTOC regardless what label was on the disk 2363# $1 disk 2364# 2365function labelvtoc 2366{ 2367 typeset disk=$1 2368 if [[ -z $disk ]]; then 2369 log_fail "The disk name is unspecified." 2370 fi 2371 typeset label_file=/var/tmp/labelvtoc.$$ 2372 typeset arch=$($UNAME -p) 2373 2374 if [[ $arch == "i386" ]]; then 2375 $ECHO "label" > $label_file 2376 $ECHO "0" >> $label_file 2377 $ECHO "" >> $label_file 2378 $ECHO "q" >> $label_file 2379 $ECHO "q" >> $label_file 2380 2381 $FDISK -B $disk >/dev/null 2>&1 2382 # wait a while for fdisk finishes 2383 $SLEEP 60 2384 elif [[ $arch == "sparc" ]]; then 2385 $ECHO "label" > $label_file 2386 $ECHO "0" >> $label_file 2387 $ECHO "" >> $label_file 2388 $ECHO "" >> $label_file 2389 $ECHO "" >> $label_file 2390 $ECHO "q" >> $label_file 2391 else 2392 log_fail "unknown arch type" 2393 fi 2394 2395 $FORMAT -e -s -d $disk -f $label_file 2396 typeset -i ret_val=$? 2397 $RM -f $label_file 2398 # 2399 # wait the format to finish 2400 # 2401 $SLEEP 60 2402 if ((ret_val != 0)); then 2403 log_fail "unable to label $disk as VTOC." 2404 fi 2405 2406 return 0 2407} 2408 2409# 2410# check if the system was installed as zfsroot or not 2411# return: 0 ture, otherwise false 2412# 2413function is_zfsroot 2414{ 2415 $DF -n / | $GREP zfs > /dev/null 2>&1 2416 return $? 2417} 2418 2419# 2420# get the root filesystem name if it's zfsroot system. 2421# 2422# return: root filesystem name 2423function get_rootfs 2424{ 2425 typeset rootfs="" 2426 rootfs=$($AWK '{if ($2 == "/" && $3 == "zfs") print $1}' \ 2427 /etc/mnttab) 2428 if [[ -z "$rootfs" ]]; then 2429 log_fail "Can not get rootfs" 2430 fi 2431 $ZFS list $rootfs > /dev/null 2>&1 2432 if (($? == 0)); then 2433 $ECHO $rootfs 2434 else 2435 log_fail "This is not a zfsroot system." 2436 fi 2437} 2438 2439# 2440# get the rootfs's pool name 2441# return: 2442# rootpool name 2443# 2444function get_rootpool 2445{ 2446 typeset rootfs="" 2447 typeset rootpool="" 2448 rootfs=$($AWK '{if ($2 == "/" && $3 =="zfs") print $1}' \ 2449 /etc/mnttab) 2450 if [[ -z "$rootfs" ]]; then 2451 log_fail "Can not get rootpool" 2452 fi 2453 $ZFS list $rootfs > /dev/null 2>&1 2454 if (($? == 0)); then 2455 rootpool=`$ECHO $rootfs | awk -F\/ '{print $1}'` 2456 $ECHO $rootpool 2457 else 2458 log_fail "This is not a zfsroot system." 2459 fi 2460} 2461 2462# 2463# Get the sub string from specified source string 2464# 2465# $1 source string 2466# $2 start position. Count from 1 2467# $3 offset 2468# 2469function get_substr #src_str pos offset 2470{ 2471 typeset pos offset 2472 2473 $ECHO $1 | \ 2474 $NAWK -v pos=$2 -v offset=$3 '{print substr($0, pos, offset)}' 2475} 2476 2477# 2478# Check if the given device is physical device 2479# 2480function is_physical_device #device 2481{ 2482 typeset device=${1#/dev/dsk/} 2483 device=${device#/dev/rdsk/} 2484 2485 $ECHO $device | $EGREP "^c[0-F]+([td][0-F]+)+$" > /dev/null 2>&1 2486 return $? 2487} 2488 2489# 2490# Get the directory path of given device 2491# 2492function get_device_dir #device 2493{ 2494 typeset device=$1 2495 2496 if ! $(is_physical_device $device) ; then 2497 if [[ $device != "/" ]]; then 2498 device=${device%/*} 2499 fi 2500 $ECHO $device 2501 else 2502 $ECHO "/dev/dsk" 2503 fi 2504} 2505 2506# 2507# Get the package name 2508# 2509function get_package_name 2510{ 2511 typeset dirpath=${1:-$STC_NAME} 2512 2513 echo "SUNWstc-${dirpath}" | /usr/bin/sed -e "s/\//-/g" 2514} 2515 2516# 2517# Get the word numbers from a string separated by white space 2518# 2519function get_word_count 2520{ 2521 $ECHO $1 | $WC -w 2522} 2523 2524# 2525# To verify if the require numbers of disks is given 2526# 2527function verify_disk_count 2528{ 2529 typeset -i min=${2:-1} 2530 2531 typeset -i count=$(get_word_count "$1") 2532 2533 if ((count < min)); then 2534 log_untested "A minimum of $min disks is required to run." \ 2535 " You specified $count disk(s)" 2536 fi 2537} 2538 2539function ds_is_volume 2540{ 2541 typeset type=$(get_prop type $1) 2542 [[ $type = "volume" ]] && return 0 2543 return 1 2544} 2545 2546function ds_is_filesystem 2547{ 2548 typeset type=$(get_prop type $1) 2549 [[ $type = "filesystem" ]] && return 0 2550 return 1 2551} 2552 2553function ds_is_snapshot 2554{ 2555 typeset type=$(get_prop type $1) 2556 [[ $type = "snapshot" ]] && return 0 2557 return 1 2558} 2559 2560# 2561# Check if Trusted Extensions are installed and enabled 2562# 2563function is_te_enabled 2564{ 2565 $SVCS -H -o state labeld 2>/dev/null | $GREP "enabled" 2566 if (($? != 0)); then 2567 return 1 2568 else 2569 return 0 2570 fi 2571} 2572 2573# Utility function to determine if a system has multiple cpus. 2574function is_mp 2575{ 2576 (($($PSRINFO | $WC -l) > 1)) 2577} 2578 2579# Run the given command as the user provided. 2580function user_run 2581{ 2582 typeset user=$1 2583 shift 2584 2585 eval \$SU \$user -c \"$@\" > /tmp/out 2>/tmp/err 2586 return $? 2587} 2588 2589# 2590# Check if the pool contains the specified vdevs 2591# 2592# $1 pool 2593# $2..n <vdev> ... 2594# 2595# Return 0 if the vdevs are contained in the pool, 1 if any of the specified 2596# vdevs is not in the pool, and 2 if pool name is missing. 2597# 2598function vdevs_in_pool 2599{ 2600 typeset pool=$1 2601 typeset vdev 2602 2603 if [[ -z $pool ]]; then 2604 log_note "Missing pool name." 2605 return 2 2606 fi 2607 2608 shift 2609 2610 typeset tmpfile=$($MKTEMP) 2611 $ZPOOL list -Hv "$pool" >$tmpfile 2612 for vdev in $@; do 2613 $GREP -w ${vdev##*/} $tmpfile >/dev/null 2>&1 2614 [[ $? -ne 0 ]] && return 1 2615 done 2616 2617 $RM -f $tmpfile 2618 2619 return 0; 2620} 2621