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