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 by Delphix. All rights reserved. 29 # 30 31 . ${STF_TOOLS}/contrib/include/logapi.shlib 32 33 ZFS=${ZFS:-/usr/sbin/zfs} 34 ZPOOL=${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 43 function 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 84 function 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 96 function 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 107 function splitline 108 { 109 $ECHO $1 | $SED "s/,/ /g" 110 } 111 112 function 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 # 122 function 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 # 170 function 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 # 181 function 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 # 192 function 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 # 206 function 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 # 229 function create_clone # snapshot clone 230 { 231 typeset snap=${1:-$TESTPOOL/$TESTFS@$TESTSNAP} 232 typeset clone=${2:-$TESTPOOL/$TESTCLONE} 233 234 [[ -z $snap ]] && \ 235 log_fail "Snapshot name is undefined." 236 [[ -z $clone ]] && \ 237 log_fail "Clone name is undefined." 238 239 log_must $ZFS clone $snap $clone 240 } 241 242 function 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 254 function 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 277 function 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 298 function 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 316 function 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 # 327 function 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 352 function default_cleanup 353 { 354 default_cleanup_noexit 355 356 log_pass 357 } 358 359 function 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 # 441 function 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 # 469 function 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 # 499 function 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 524 function 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 # 542 function 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 # 575 function 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 # 609 function 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 # 619 function 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 # 636 function 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 # 668 function 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 $AWK -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 # 702 function 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 # 746 function 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 # 790 function 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 # 811 function 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 838 function 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 854 function 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 873 function 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 # 894 function 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 # 932 function 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 # 947 function 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 # 962 function 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 # 1014 function 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 # 1031 function 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 1072 function 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 1101 function 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 # 1136 function 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 # 1243 function 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 # 1269 function 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 # 1286 function 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 # 1309 function 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 # 1346 function get_disklist # pool 1347 { 1348 typeset disklist="" 1349 1350 disklist=$($ZPOOL iostat -v $1 | $AWK '(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 # 1360 function 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 # */ 1383 function 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 # 1408 function 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 # 1427 function 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 # 1446 function 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 # 1466 function 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 | $AWK -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 # 1487 function is_pool_resilvering #pool 1488 { 1489 check_pool_status "$1" "scan" "resilver in progress since " 1490 return $? 1491 } 1492 1493 function is_pool_resilvered #pool 1494 { 1495 check_pool_status "$1" "scan" "resilvered " 1496 return $? 1497 } 1498 1499 function is_pool_scrubbing #pool 1500 { 1501 check_pool_status "$1" "scan" "scrub in progress since " 1502 return $? 1503 } 1504 1505 function is_pool_scrubbed #pool 1506 { 1507 check_pool_status "$1" "scan" "scrub repaired" 1508 return $? 1509 } 1510 1511 function 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 # 1521 function 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 # 1542 function 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 # 1582 function 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 1614 function 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 # 1654 function 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 #*/ 1676 function 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 #!/usr/xpg4/bin/awk -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 } 1710 EOF 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 # 1766 function 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 # 1787 function 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 # 1810 function 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 # 1837 function 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 # 1862 function 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 # 1932 function 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 # 1944 function 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 # 1975 function 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 # 1989 function 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 # 2010 function 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 # 2031 function 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 # 2060 function 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 # 2072 function 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 # 2083 function 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 # 2109 function 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 # 2178 function 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 # 2210 function _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 # 2226 function 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 # 2237 function random_get 2238 { 2239 _random_get "$#" "$@" 2240 } 2241 2242 # 2243 # Detect if the current system support slog 2244 # 2245 function 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 # 2269 function 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 2300 function 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 # 2313 function 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 # 2323 function 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 $AWK -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 # 2346 function 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 # 2365 function 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 # 2413 function 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 2423 function 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 # 2444 function 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 # 2469 function get_substr #src_str pos offset 2470 { 2471 typeset pos offset 2472 2473 $ECHO $1 | \ 2474 $AWK -v pos=$2 -v offset=$3 '{print substr($0, pos, offset)}' 2475 } 2476 2477 # 2478 # Check if the given device is physical device 2479 # 2480 function 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 # 2492 function 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 # 2509 function 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 # 2519 function get_word_count 2520 { 2521 $ECHO $1 | $WC -w 2522 } 2523 2524 # 2525 # To verify if the require numbers of disks is given 2526 # 2527 function 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 2539 function ds_is_volume 2540 { 2541 typeset type=$(get_prop type $1) 2542 [[ $type = "volume" ]] && return 0 2543 return 1 2544 } 2545 2546 function ds_is_filesystem 2547 { 2548 typeset type=$(get_prop type $1) 2549 [[ $type = "filesystem" ]] && return 0 2550 return 1 2551 } 2552 2553 function 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 # 2563 function 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 }