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