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 whence -p stc_genutils > /dev/null 2>&1
  28 if (( $? != 0 )); then
  29         print -u2 "nfs-util.kshlib: stc_genutils command not found!"
  30         exit 1
  31 fi
  32 STC_GENUTILS_TMPDIR=$(stc_genutils tmpdir)
  33 if (( $? != 0 )); then
  34         print -u2 "nfs-util.kshlib: directory $STC_GENUTILS_TMPDIR not exist" \
  35                 " and cannot create it!"
  36         exit 1
  37 fi
  38 STC_GENUTILS_DEBUG=$(stc_genutils debug)
  39 
  40 #
  41 # Function to remotely execute one or more commands, using korn shell.
  42 #       Usage: RSH user machine  command_string (rest of line)
  43 #       user            target user on remote system
  44 #       machine         remote machine to execute command
  45 #       command_string  any desired command(s) (korn shell)
  46 #       STC_GENUTILS_DEBUG      global to enable debugging mode
  47 #       UNIX_RES        global to detect failures, if unix standard is followed
  48 #                       for return codes (0=OK, !0=failure).
  49 #       This function in addition to execute remote command, adds code for
  50 #       getting the return code from last operation, and to trace the remote
  51 #       execution as enabled by set -x (depending on $STC_GENUTILS_DEBUG).
  52 #
  53 #                             NOTES
  54 #       Take care to no redirect stderr to stdout as that will cause
  55 #       a very messy output in debug mode, and possible test failures.
  56 #
  57 #       This library uses Korn shell (ksh) syntax only, and must be invoked in
  58 #       ksh scripts only.
  59 function RSH
  60 {
  61         typeset FNAME=RSH
  62         typeset SETD=""
  63 
  64         [[ :$STC_GENUTILS_DEBUG: == \
  65             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
  66                 set -x && \
  67                 typeset SETD="export STC_GENUTILS_DEBUG=$STC_GENUTILS_DEBUG; set -x; "
  68 
  69         (( $# < 3 )) && \
  70                 echo "Usage: $FNAME ruser remotehost \"rcmd args\"" && \
  71                 return 1
  72         
  73         typeset ruser=$1
  74         typeset rmach=$2
  75         shift; shift
  76         typeset rcmd="${SETD}$@"
  77         typeset -i ret=0
  78 
  79         # by default, expect UNIX standard result codes
  80         typeset UNIX_RES=${UNIX_RES:="1"}
  81 
  82         typeset file=$STC_GENUTILS_TMPDIR/$rmach.$$.out
  83         typeset file2=$STC_GENUTILS_TMPDIR/exec.$$.result
  84 
  85         ssh -o "StrictHostKeyChecking no" $ruser@$rmach /usr/bin/ksh -c "'$rcmd; \
  86                 print -u 2 \"returned=(\$?)\"'" \
  87                 > $file 2>$file2
  88         ret=$?
  89         #
  90         # Since the server may reboot in some tests and when
  91         # that happens ssh can return 255 (remote down) and
  92         # we may want to ignore that error
  93         #
  94         if (( $ret != 0 && $ret != 255 )); then
  95                 echo "ERROR: the rsh command failed, returned=$ret"
  96                 cat $file2
  97                 rm -f $file $file2
  98                 return $ret
  99         fi
 100         
 101         cat $file
 102         ret=$(grep -v 'print -u 2' $file2 | grep 'returned=(' | \
 103                 sed 's/^.*returned=(//' | sed 's/).*$//')
 104         if [[ $UNIX_RES != 1 ]]; then
 105                 if (( $ret == 0 )); then
 106                         ret=1
 107                         cat $file2 >&2
 108                 else
 109                         ret=0
 110                 fi
 111         else
 112                 (( $ret != 0 )) || \
 113                     [[ :$STC_GENUTILS_DEBUG: == \
 114                         @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] \
 115                         && cat $file2 >&2
 116         fi
 117         rm -f $file $file2 > /dev/null 2>&1
 118         [[ :$STC_GENUTILS_DEBUG: == :RSH: ]] && set +x
 119 
 120         return $ret
 121 }
 122 
 123 #
 124 # Usage: set_nfs_param <parameter> <value> <file>
 125 #       parameter    :  parameter which value will be changed
 126 #       value        :  the value will be set
 127 #       file         :  which file will be changed
 128 # This function is used to set/change the value of a parameter.
 129 # The format must be like this, paramter=value, in this file.
 130 # If value="-",  parameter  will be commented out from the file.
 131 #
 132 function set_nfs_param
 133 {
 134         typeset FNAME=set_nfs_param
 135         [[ :$STC_GENUTILS_DEBUG: == \
 136             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
 137                 set -vx
 138 
 139         if (( $# != 3 )) ; then
 140                 print -u 2 "usage: $FNAME <parameter> <value> <file>"
 141                 return 2
 142         fi
 143         typeset parameter=$1
 144         typeset value=$2
 145         typeset file=$3
 146         if [[ ! -w $file  ]] ; then
 147                 print -u 2 "The file <$file> doesn't exist or isn't writable"
 148                 return 2
 149         fi
 150         if [[ $value == "-" ]] ; then
 151                 perl -i -p -e "s/^$parameter/#$parameter/g" $file
 152         else
 153                 perl -i -p -e "s/^#?$parameter=.*/$parameter=$value/g" $file
 154         fi
 155         if (( $? != 0 )) ; then
 156                 print -u 2 "change the nfs config file <$file> failed"
 157                 return 2
 158         fi
 159 }
 160 
 161 #
 162 # Function to check and exit if the current zone is a non-global zone.
 163 # Usage: ck_zone [err_msg]
 164 #       err_msg (optional); if provided, it will be added to the output
 165 #
 166 # This function is to verify if the current zone is a global zone
 167 #       Yes, it just returns 0 without any messages printed;
 168 #       No, it prints an error message and exit
 169 #
 170 function ck_zone
 171 {
 172         typeset FNAME=ck_zone
 173         [[ :$STC_GENUTILS_DEBUG: == \
 174             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
 175                 set -vx
 176 
 177         typeset ErrMsg=$1
 178         [[ -z $ErrMsg ]] && \
 179                 ErrMsg="This test is not supported in non-global zone."
 180 
 181         typeset zn=$(/usr/bin/zonename)
 182         if [[ $zn != global ]]; then
 183                 echo "$FNAME: current zonename is <$zn>"
 184                 echo "\t$ErrMsg"
 185                 exit 4
 186         fi
 187         return 0
 188 }
 189 
 190 #
 191 # Function to print test system information.
 192 # If $1 is provided, the function will print the info of remote host ($1).
 193 # Make sure the remote host can be accessed with root before invocation.
 194 # If there's no parameter, the function will print local host information.
 195 #
 196 # Usage: print_system_info  [hostname]
 197 #       hostname(optional):     the name of remote system
 198 #
 199 function print_system_info
 200 {
 201         host=$1
 202 
 203         if [[ $host == "" ]]; then
 204                 echo "`hostname` info:"
 205                 echo "\tuname:\t\t`uname -a` \n\tisainfo:\t`isainfo` \
 206                         \n\tzonename:\t`zonename`"
 207         else
 208                 echo "$host info:"
 209                 RSH root $host \
 210                 "echo \"\tuname:\t\t\`uname -a\` \n\tisainfo:\t\`isainfo\` \
 211                         \n\tzonename:\t\`zonename\`\" "
 212         fi
 213 }
 214 
 215 #
 216 # Function to create sub ZFS pool on specific file or volume
 217 # Usage: create_zpool pname fname|vname [size]
 218 #
 219 #       pname: name of zfs pool need to be created
 220 #       fname|vname: name of file or volume that the zfs pool is created on
 221 #       size:   size of volume
 222 #
 223 function create_zpool
 224 {
 225         typeset FNAME=create_zpool
 226         [[ :$STC_GENUTILS_DEBUG: == \
 227             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
 228                 set -x
 229 
 230         getopts fv opt
 231         case $opt in
 232         f) # create pool on file
 233                 typeset pname=$2
 234                 typeset fname=$3
 235                 zpool create -f $pname $fname > $STC_GENUTILS_TMPDIR/$FNAME.zpc.$$ 2>&1
 236                 if (( $? != 0 )); then
 237                         echo "$FNAME: failed to create zpool -"
 238                         cat $STC_GENUTILS_TMPDIR/$FNAME.zpc.$$
 239                         zpool status $pname
 240                         rm -f $STC_GENUTILS_TMPDIR/$FNAME.zpc.$$
 241                         return 2
 242                 fi
 243         ;;
 244         v) # create pool on volume
 245                 typeset pname=$2
 246                 typeset vname=$3
 247                 typeset size=$4 # size is in the form of 5m/2g
 248                 echo "$FNAME: Setting test filesystems with ZFS ..."
 249                 zpool status | grep "$vname" | grep ONLINE >/dev/null 2>&1
 250                 if (( $? != 0 )); then
 251                         zfs create -V $size $vname > $STC_GENUTILS_TMPDIR/$FNAME.zfsc.$$ 2>&1
 252                         if (( $? != 0 )); then
 253                                 echo "$FNAME: failed to create volume -"
 254                                 cat $STC_GENUTILS_TMPDIR/$FNAME.zfsc.$$
 255                                 grep "same dev" $STC_GENUTILS_TMPDIR/$FNAME.zfsc.$$ \
 256                                         > /dev/null 2>&1
 257                                 (( $? == 0 )) && zpool status
 258                                 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
 259                                 return 2
 260                         fi
 261                         zpool create -f $pname /dev/zvol/dsk/$vname \
 262                                 > $STC_GENUTILS_TMPDIR/$FNAME.zpc.$$ 2>&1
 263                         if (( $? != 0 )); then
 264                                 echo "$FNAME: failed to create sub zpool -"
 265                                 cat $STC_GENUTILS_TMPDIR/$FNAME.zpc.$$
 266                                 grep "same dev" $STC_GENUTILS_TMPDIR/$FNAME.zpc.$$ \
 267                                         > /dev/null 2>&1
 268                                 (( $? == 0 )) && zpool status
 269                                 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
 270                                 return 2
 271                         fi
 272                 fi
 273         ;;
 274         *)
 275                 echo "$FNAME: ERROR - incorrect usage."
 276                 return 2
 277         ;;
 278         esac
 279 
 280         rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
 281 }
 282 
 283 #
 284 # Function to create ZFS filesystem in provided zfs pool.
 285 # Usage: create_zfs_fs Zpool mountpoint [FSsize] [FSmopt]
 286 #
 287 #       Zpool: zfs pool where ZFS filesystem is created
 288 #       mountpoint: the mount point new filesystem is mounted on
 289 #       FSsize: size is in the form of 5m/2g
 290 #       FSmopt: remount option
 291 #
 292 function create_zfs_fs {
 293         typeset FNAME=create_zfs_fs
 294         [[ :$STC_GENUTILS_DEBUG: == \
 295             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
 296                 set -x
 297 
 298         typeset Zpool=$1
 299         typeset FSname=$2
 300         (( $# >= 3 )) && typeset FSsize=$3
 301         (( $# == 4 )) && typeset FSmopt=$4
 302 
 303         typeset -u Zname=$(basename $FSname)
 304         zfs create $Zpool/$Zname > $STC_GENUTILS_TMPDIR/$FNAME.czfs.$$ 2>&1
 305         if (( $? != 0 )); then
 306                 echo "$FNAME: failed to <zfs create $Zpool/$Zname>"
 307                 cat $STC_GENUTILS_TMPDIR/$FNAME.czfs.$$
 308                 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
 309                 return 2
 310         fi
 311         [[ ! -d $FSname ]] && mkdir -p $FSname
 312         zfs set mountpoint=$FSname $Zpool/$Zname \
 313                 > $STC_GENUTILS_TMPDIR/$FNAME.szfs.$$ 2>&1
 314         if (( $? != 0 )); then
 315                 echo "$FNAME: failed to \c"
 316                 echo "<zfs set mountpoint=$FSname $Zpool/$Zname>"
 317                 cat $STC_GENUTILS_TMPDIR/$FNAME.szfs.$$
 318                 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
 319                 return 2
 320         fi
 321         chmod 0777 $FSname
 322         ACLs=write_xattr/write_attributes/write_acl/add_file:allow
 323         chmod A+everyone@:${ACLs} $FSname
 324 
 325         if [[ -n $FSsize ]]; then
 326                 zfs set quota=$FSsize $Zpool/$Zname \
 327                         > $STC_GENUTILS_TMPDIR/$FNAME.qzfs.$$ 2>&1
 328                 if (( $? != 0 )); then
 329                         echo "$FNAME: failed to \c"
 330                         echo "<zfs set quota=$FSsize $Zpool/$Zname>"
 331                         cat $STC_GENUTILS_TMPDIR/$FNAME.qzfs.$$
 332                         rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
 333                         return 2
 334                 fi
 335                 unset FSsize
 336         fi
 337         if [[ -n $FSmopt ]]; then
 338                 zfs umount $Zpool/$Zname > $STC_GENUTILS_TMPDIR/$FNAME.mzfs.$$ 2>&1
 339                 zfs mount -o $FSmopt $Zpool/$Zname \
 340                         >> $STC_GENUTILS_TMPDIR/$FNAME.mzfs.$$ 2>&1
 341                 if (( $? != 0 )); then
 342                         echo "$FNAME: failed to \c"
 343                         echo "<zfs mount -o $FSmopt $Zpool/$Zname>"
 344                         cat $STC_GENUTILS_TMPDIR/$FNAME.mzfs.$$
 345                         rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
 346                         return 2
 347                 fi
 348                 unset FSmopt
 349         fi
 350 
 351         rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
 352         return 0
 353 }
 354 
 355 #
 356 # Function to create LOFI filesystem with provided options.
 357 # Usage: create_lofi_fs lofile mountpoint [FSsize] [FSmopt]
 358 #
 359 #       lofile: lofi file where LOFI filesystem is created
 360 #       mountpoint: the mount point new filesystem is mounted on
 361 #       FSsize: size is in the form of 5m/2g, default is 5m
 362 #       FSmopt: mount option, default is rw
 363 #
 364 function create_lofi_fs {
 365         typeset FNAME=create_lofi_fs
 366         [[ :$STC_GENUTILS_DEBUG: == \
 367             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
 368                 set -x
 369 
 370         typeset LFname=$1
 371         typeset FSname=$2
 372         typeset FSsize=5m
 373         typeset FSmopt="rw"
 374         (( $# >= 3 )) && FSsize=$3
 375         (( $# == 4 )) && FSmopt=$4
 376 
 377         [[ -f $LFname ]] && rm -f $LFname
 378         mkfile $FSsize $LFname > $STC_GENUTILS_TMPDIR/$FNAME.mkfile.$$ 2>&1
 379         if (( $? != 0 )); then
 380                 echo "$FNAME: failed to <mkfile $FSsize $LFname>"
 381                 cat $STC_GENUTILS_TMPDIR/$FNAME.mkfile.$$
 382                 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
 383                 return 2
 384         fi
 385         lofiadm -a $LFname > $STC_GENUTILS_TMPDIR/$FNAME.lofi.$$ 2>&1
 386         if (( $? != 0 )); then
 387                 echo "$FNAME: failed to <lofiadm -a $LFname>"
 388                 cat $STC_GENUTILS_TMPDIR/$FNAME.lofi.$$
 389                 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
 390                 return 2
 391         fi
 392         typeset LDEV=$(head -1 $STC_GENUTILS_TMPDIR/$FNAME.lofi.$$ | awk '{print $1}')
 393         echo "y" | newfs -i 10240 $LDEV > $STC_GENUTILS_TMPDIR/$FNAME.newfs.$$ 2>&1
 394         if (( $? != 0 )); then
 395                 echo "$FNAME: failed to <newfs -i 10240 $LDEV>"
 396                 cat $STC_GENUTILS_TMPDIR/$FNAME.newfs.$$
 397                 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
 398                 return 2
 399         fi
 400         [[ ! -d $FSname ]] && mkdir -p $FSname
 401         typeset fstype="ufs"
 402         [[ $FSmopt == *"noxattr"* ]] && fstype="tmpfs"
 403         mount -F $fstype -o $FSmopt $LDEV $FSname > \
 404                                 $STC_GENUTILS_TMPDIR/$FNAME.mnt.$$ 2>&1
 405         if (( $? != 0 )); then
 406                 echo "$FNAME: failed to <mount -F $fstype -o $FSmopt $LDEV $FSname>"
 407                 cat $STC_GENUTILS_TMPDIR/$FNAME.mnt.$$
 408                 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
 409                 return 2
 410         fi
 411         chmod 0777 $FSname
 412 
 413         rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
 414         return 0
 415 }
 416 
 417 #
 418 # Function to destroy LOFI filesystem.
 419 # Usage: destroy_lofi_fs mountpoint
 420 #
 421 #       mountpoint: mount point the filesystem is mounted on
 422 #
 423 function destroy_lofi_fs {
 424         typeset FNAME=destroy_lofi_fs
 425         [[ :$STC_GENUTILS_DEBUG: == \
 426             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
 427                 set -x
 428 
 429         typeset FSname=$1
 430         typeset LDEV=$(df -k $FSname | awk '{print $1}' | \
 431                         grep -v "^Filesystem$")
 432 
 433         umount -f $FSname > $STC_GENUTILS_TMPDIR/$FNAME.umnt.$$ 2>&1
 434         if (( $? != 0 )); then
 435                 echo "$FNAME: WARNING, umount $FSname failed."
 436                 cat $STC_GENUTILS_TMPDIR/$FNAME.umnt.$$
 437                 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
 438                 return 2
 439         fi
 440         typeset LFname=$(lofiadm $LDEV 2>$STC_GENUTILS_TMPDIR/$FNAME.file.$$)
 441         if (( $? != 0 )); then
 442                 echo "$FNAME: WARNING, lofiadm $LDEV failed."
 443                 cat $STC_GENUTILS_TMPDIR/$FNAME.file.$$
 444                 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
 445                 return 2
 446         fi
 447         lofiadm -d $LDEV > $STC_GENUTILS_TMPDIR/$FNAME.lofi.$$ 2>&1
 448         if (( $? != 0 )); then
 449                 echo "$FNAME: WARNING, lofiadm -d $LDEV failed."
 450                 cat $STC_GENUTILS_TMPDIR/$FNAME.lofi.$$
 451                 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
 452                 return 2
 453         fi
 454 
 455         rm -fr $STC_GENUTILS_TMPDIR/$FNAME.*.$$ $LFname $FSname
 456         return 0
 457 }
 458 
 459 #
 460 # Function to create UFS filesystem from zfs volume in provided zfs pool.
 461 # Usage: create_ufs_fs Zpool mountpoint [FSsize] [FSmopt]
 462 #
 463 #       Zpool: zfs pool where zfs volume is created
 464 #       mountpoint: the mount point new filesystem is mounted on
 465 #       FSsize: size is in the form of 5m/2g, default is 5m
 466 #       FSmopt: mount option, default is rw
 467 #
 468 function create_ufs_fs {
 469         typeset FNAME=create_ufs_fs
 470         [[ :$STC_GENUTILS_DEBUG: == \
 471             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
 472                 set -x
 473 
 474         typeset Zpool=$1
 475         typeset FSname=$2
 476         typeset FSsize=5m
 477         typeset FSmopt="rw"
 478         (( $# >= 3 )) && FSsize=$3
 479         (( $# == 4 )) && FSmopt=$4
 480 
 481         typeset -u Vname=$(basename $FSname)
 482         zfs create -V $FSsize $Zpool/$Vname > $STC_GENUTILS_TMPDIR/$FNAME.czfs.$$ 2>&1
 483         if (( $? != 0 )); then
 484                 echo "$FNAME: failed to <zfs create -V $FSsize $Zpool/$Vname>"
 485                 cat $STC_GENUTILS_TMPDIR/$FNAME.czfs.$$
 486                 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
 487                 return 2
 488         fi
 489         echo "y" | newfs -i 10240 /dev/zvol/rdsk/$Zpool/$Vname > \
 490                                         $STC_GENUTILS_TMPDIR/$FNAME.newfs.$$ 2>&1
 491         if (( $? != 0 )); then
 492                 echo "$FNAME: failed to <newfs /dev/zvol/rdsk/$Zpool/$Vname>"
 493                 cat $STC_GENUTILS_TMPDIR/$FNAME.newfs.$$
 494                 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
 495                 return 2
 496         fi
 497         [[ ! -d $FSname ]] && mkdir -p $FSname
 498         mount -F ufs -o $FSmopt /dev/zvol/dsk/$Zpool/$Vname $FSname > \
 499                                                 $STC_GENUTILS_TMPDIR/$FNAME.mnt.$$ 2>&1
 500         if (( $? != 0 )); then
 501                 echo "$FNAME: failed to <mount /dev/zvol/dsk/$Zpool/$Vname $FSname>"
 502                 cat $STC_GENUTILS_TMPDIR/$FNAME.mnt.$$
 503                 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
 504                 return 2
 505         fi
 506         chmod 0777 $FSname
 507 
 508         rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
 509         return 0
 510 }
 511 
 512 #
 513 # Function to destroy UFS filesystem.
 514 # Usage: destroy_ufs_fs mountpoint
 515 #
 516 #       mountpoint: mount point the filesystem is mounted on
 517 #
 518 function destroy_ufs_fs {
 519         typeset FNAME=destroy_ufs_fs
 520         [[ :$STC_GENUTILS_DEBUG: == \
 521             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
 522                 set -x
 523 
 524         typeset FSname=$1
 525         typeset BDEV=$(df -k $FSname | awk '{print $1}' | \
 526                         grep -v "^Filesystem$")
 527 
 528         umount -f $FSname > $STC_GENUTILS_TMPDIR/$FNAME.umnt.$$ 2>&1
 529         if (( $? != 0 )); then
 530                 echo "$FNAME: WARNING, umount $FSname failed."
 531                 cat $STC_GENUTILS_TMPDIR/$FNAME.umnt.$$
 532                 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
 533                 return 2
 534         fi
 535         typeset Zvol=${BDEV##*/dsk/}
 536         zfs destroy -f $Zvol > $STC_GENUTILS_TMPDIR/$FNAME.dzfs.$$ 2>&1
 537         if (( $? != 0 )); then
 538                 echo "$FNAME: WARNING, zfs destroy $Zvol failed."
 539                 cat $STC_GENUTILS_TMPDIR/$FNAME.dzfs.$$
 540                 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
 541                 return 2
 542         fi
 543 
 544         rm -fr $STC_GENUTILS_TMPDIR/$FNAME.*.$$ $Fname $FSname
 545         return 0
 546 }
 547 
 548 #
 549 # Function to verify a specified condition
 550 # Usage: wait_now max_TIMER the_condition [interval]
 551 #
 552 # max_TIMER: the maximum timer to wait
 553 # condition: the condition to break the wait:
 554 #       "true"  wait_now{} returns 0
 555 #       "false" wait_now{} continues until the TIMER
 556 # interval: the interval between check condition
 557 #
 558 function wait_now {
 559         typeset FNAME=wait_now
 560         [[ :$STC_GENUTILS_DEBUG: == \
 561             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
 562                 set -x
 563 
 564         (( $# < 2 || $# > 3 )) && \
 565                 echo "Usage: $FNAME max_TIMER condition interval" && \
 566                 return -1
 567 
 568         typeset -i Timer=$1 interval
 569         typeset Wcond="$2"
 570         [[ -n $3 ]] && interval=$3 || interval=1
 571 
 572         typeset -i i=0
 573         while (( i < Timer ))
 574         do
 575                 eval ${Wcond}
 576                 [[ $? -eq 0 ]] && return 0
 577                 sleep $interval
 578                 let i+=interval
 579         done
 580         return $i
 581 }
 582 
 583 #
 584 # Funtion to check return code of the last command.
 585 # If the return code is equal to zero, it does nothing; if not,
 586 # it prints an error message and an optional logfile on stderr,
 587 # and return that error code.
 588 #
 589 # If a logfile is passed, it is removed automatically when the
 590 # function exits. User can use -n option to ask not to remove
 591 # that file.
 592 # Usage:  ckresult <-n> <retcode> <errmsg> <logfile>
 593 #       -n      - don't remove logfile if the check passed
 594 #       retcode - the return code to be checked
 595 #       errmsg  - error message if $retcode is non-zero
 596 #       logfile - logfile of the command of interest. This
 597 #                         argument is optional.
 598 # Return: the same as $retcode, the return code to be checked
 599 #
 600 function ckresult {
 601         not_remove=0
 602         if [[ $1 == "-n" ]]; then
 603                 not_remove=1
 604                 shift 1
 605         fi
 606 
 607         retcode=$1
 608         errmsg="$2"
 609         logfile=$3
 610 
 611         # print $errmsg on stderr if $retcode is non-zero
 612         if (( retcode != 0 )); then
 613                 if (( $# >= 3 )) && [[ -f $logfile ]]; then
 614                         cat $logfile
 615                         rm -f $logfile
 616                 fi
 617                 print -u2 "$errmsg"
 618         fi
 619 
 620         # remove the logfile
 621         [[ -f "$logfile" ]] && ((not_remove == 0)) && rm -f $logfile
 622 
 623         return $retcode
 624 }
 625 
 626 #
 627 # get_hostname_remote - get the host name on a remote machine
 628 #       Based on the name service configruation in
 629 #       /etc/nsswitch.conf, different name maybe occur for
 630 #       the same host on different host. i.e. nodename vs FQDN
 631 # Usage:  get_hostname_remote <hostname> <remotehost>
 632 #       hostname - the host to be resolved on the remote host
 633 #       remotehost - the host which resolves hostname
 634 #
 635 function get_hostname_remote {
 636         typeset FNAME=get_hostname_remote
 637         typeset ip name
 638 
 639         [[ :$STC_GENUTILS_DEBUG: == \
 640             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
 641                 set -x
 642 
 643         if (( $# < 2 )) ; then
 644                 echo "usage: $FNAME <hostname> <remotehost>"
 645                 return 1
 646         fi
 647 
 648         ip=$(getent ipnodes $1 | head -1 | awk '{print $1}')
 649         (( $? != 0 )) && return 1
 650         name=$(RSH root $2 "getent ipnodes $ip" \
 651                 2>$STC_GENUTILS_TMPDIR/rsh.out.$$)
 652         if (( $? != 0 )); then
 653                 echo "$FNAME: run getent ipnodes on $2 failed:"
 654                 cat $STC_GENUTILS_TMPDIR/rsh.out.$$
 655                 rm $STC_GENUTILS_TMPDIR/rsh.out.$$
 656                 return 1
 657         fi
 658         typeset retval=$(echo "$name" | head -1 | awk '{print $NF}')
 659 
 660         # check the return value
 661         if [[ -z $retval ]]; then
 662                 echo "$FNAME: did not get host name of $1 on $2:"
 663                 cat $STC_GENUTILS_TMPDIR/rsh.out.$$
 664                 rm $STC_GENUTILS_TMPDIR/rsh.out.$$
 665                 return 1
 666         fi
 667         ping $retval > $STC_GENUTILS_TMPDIR/ping.out.$$ 2>&1
 668         if (( $? != 0 )); then
 669                 echo "$FNAME: $retval not responding to pings:"
 670                 cat $STC_GENUTILS_TMPDIR/ping.out.$$
 671                 rm $STC_GENUTILS_TMPDIR/rsh.out.$$ $STC_GENUTILS_TMPDIR/ping.out.$$
 672                 return 1
 673         fi
 674 
 675         echo $retval
 676         rm $STC_GENUTILS_TMPDIR/rsh.out.$$ $STC_GENUTILS_TMPDIR/ping.out.$$
 677         return 0
 678 }
 679 
 680 #
 681 # set_nfs_property - set property via "sharectl set" command
 682 # if sharectl is available
 683 # Usage: set_nfs_property <property> <value> [file]
 684 #       property - property name
 685 #       value    - property value
 686 #       file     - the file to save old value. It is optional.
 687 #
 688 function set_nfs_property {
 689         typeset FNAME=set_nfs_property
 690         [[ :$STC_GENUTILS_DEBUG: == \
 691             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
 692                 set -x
 693 
 694         if (( $# < 2 )); then
 695                 echo "Usage: $FNAME <property> <value> [file]"
 696                 return 1
 697         fi
 698 
 699         typeset property=$1
 700         typeset value=$2
 701         typeset file=$3
 702         typeset cur_value
 703         typeset envvar
 704 
 705         typeset -l l_property
 706         typeset -u u_property
 707         typeset errmsg="$property: this property is unsupported by $FNAME now,"
 708         errmsg="$errmsg please add more codes to it for your requirement."
 709 
 710         case $property in
 711         nfsmapid_domain | NFSMAPID_DOMAIN)
 712                 l_property=nfsmapid_domain
 713                 u_property=NFSMAPID_DOMAIN
 714                 ;;
 715         server_versmax | NFS_SERVER_VERSMAX)
 716                 l_property=server_versmax
 717                 u_property=NFS_SERVER_VERSMAX
 718                 ;;
 719         server_versmin | NFS_SERVER_VERSMIN)
 720                 l_property=server_versmin
 721                 u_property=NFS_SERVER_VERSMIN
 722                 ;;
 723         server_delegation | NFS_SERVER_DELEGATION)
 724                 l_property=server_delegation
 725                 u_property=NFS_SERVER_DELEGATION
 726                 ;;
 727         *)
 728                 print -u2 "$errmsg"
 729                 return 1
 730         esac
 731 
 732         typeset logfile=$STC_GENUTILS_TMPDIR/$FNAME.$$
 733         if [[ -n $file ]]; then
 734             # get current value
 735             typeset -i ret=0
 736             if [[ -x /usr/sbin/sharectl ]]; then
 737                 cur_value=$(sharectl get -p $l_property nfs 2>$logfile)
 738                 ret=$?
 739             else
 740                 cur_value=$(grep -i "^[ |       ]*${u_property}=" \
 741                         /etc/default/nfs 2>$logfile)
 742             fi
 743             ckresult $ret "failed to get $property" $logfile || return 1
 744             cur_value=${cur_value##*=}
 745 
 746             # generate a env variable name for it
 747             envvar="ORIG_$l_property"
 748 
 749             # save the value into file
 750             echo "$envvar=$cur_value" >> $file
 751         fi
 752 
 753         # set new value
 754         if [[ -x /usr/sbin/sharectl ]]; then
 755             sharectl set -p $l_property=$value nfs > $logfile
 756         else
 757             grep -vi "^[ |      ]*${u_property}=" /etc/default/nfs \
 758                 > $STC_GENUTILS_TMPDIR/$FNAME.nfs.$$
 759             echo "$u_property=$value" >> $STC_GENUTILS_TMPDIR/$FNAME.nfs.$$
 760             mv $STC_GENUTILS_TMPDIR/$FNAME.nfs.$$ /etc/default/nfs
 761             chown root:sys /etc/default/nfs
 762             if [[ $u_property == NFSMAPID_DOMAIN ]]; then
 763                 svcadm restart mapid > $logfile
 764                 [[ -z $value ]] || wait_now 10 \
 765                         "[[ \$(cat /var/run/nfs4_domain) == $value ]]"
 766             fi
 767         fi
 768         ckresult $? "failed to set $property to $value" $logfile || return 1
 769 }
 770 
 771 #
 772 # restore_nfs_property - restore property via "sharectl set" command
 773 # if sharectl is available
 774 # Usage: restore_nfs_property <property> <file>
 775 #       property - property name
 776 #       file     - the file contains the old value
 777 #
 778 function restore_nfs_property {
 779         typeset FNAME=restore_nfs_property
 780         [[ :$STC_GENUTILS_DEBUG: == \
 781             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
 782                 set -x
 783 
 784         if (( $# < 2 )); then
 785                 echo "Usage: $FNAME <property> <file>"
 786                 return 1
 787         fi
 788 
 789         typeset -l property
 790         typeset file=$2
 791         typeset envvar
 792         typeset value
 793 
 794         case $1 in
 795         nfsmapid_domain | NFSMAPID_DOMAIN)
 796                 property=nfsmapid_domain
 797                 def_value=domain
 798                 ;;
 799         server_versmax | NFS_SERVER_VERSMAX)
 800                 property=server_versmax
 801                 def_value=4
 802                 ;;
 803         server_versmin | NFS_SERVER_VERSMIN)
 804                 property=server_versmin
 805                 def_value=2
 806                 ;;
 807         server_delegation | NFS_SERVER_DELEGATION)
 808                 property=server_delegation
 809                 def_value=on
 810                 ;;
 811         esac
 812         
 813         # generate env variable name we need
 814         envvar="ORIG_$property"
 815 
 816         # get its value from file
 817         typeset logfile=$STC_GENUTILS_TMPDIR/$FNAME.$$
 818         value=$(grep $envvar $file 2>$logfile)
 819         ckresult $? "failed to get $envvar from $file" $logfile || return 1
 820         value=${value##$envvar=}        
 821         [[ $value == "" ]] && value=$def_value
 822 
 823         set_nfs_property $property "$value"
 824 }
 825 
 826 #
 827 # sharemgr_share - share one dir using sharemgr if it is available
 828 # Usage: sharemgr_share <group> <directory> [share_options]
 829 #
 830 function sharemgr_share {
 831         typeset FNAME=sharemgr_share
 832         [[ :$STC_GENUTILS_DEBUG: == \
 833             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
 834                 set -x
 835 
 836         typeset tgrp=$1
 837         typeset dir=$2
 838         typeset opts=${3:-"rw"}
 839 
 840         typeset -i ret=0
 841         typeset i=0
 842         typeset j=0
 843 
 844         # if there is no sharemgr, use share instead
 845         if [[ ! -x /usr/sbin/sharemgr ]]; then
 846                 share -F nfs -o $opts $dir
 847                 return $?
 848         fi
 849 
 850         #
 851         # divide options into groups, using "sec" as keywords
 852         # Example:
 853         #   input:  "anon=0,ro,sec=krb5,rw,sec=krb5:krb5p,ro=snake"
 854         #   output: "sec=sys,anon=0,ro" "sec=krb5,rw" "sec=krb5:krb5p,ro=snake"
 855         #
 856         while [[ -n $opts ]]; do
 857                 opt_group[$i]=${opts%%,sec=*}
 858                 [[ ${opt_group[$i]} == $opts ]] && break
 859                 opts=${opts#${opt_group[$i]},}
 860                 (( i += 1 ))
 861         done
 862         if [[ $opt_group[0] != "sec="* ]]; then
 863                 opt_group[0]="sec=sys,${opt_group[0]}"
 864         fi
 865 
 866         #
 867         # extract options that are not sec flavour specific,
 868         # Example:
 869         #   input:  "sec=sys,anon=0,ro" "sec=krb5,rw" "sec=krb5:krb5p,ro=snake"
 870         #   output: "sec=sys ro" "sec=krb5 rw" "sec=krb5:krb5p ro=snake"
 871         #           and "anon=0"
 872         #
 873         i=0
 874         while (( i < ${#opt_group[*]} )); do
 875                 opts=$(echo ${opt_group[$i]} | tr , ' ')
 876                 opt_group[$i]=""
 877                 for o in $opts; do
 878                         if echo $o | egrep "sec=|rw|ro|root=|window=" \
 879                                 >/dev/null; then
 880                                 # sec flavour specific options
 881                                 opt_group[$i]="${opt_group[$i]} $o"
 882                         else
 883                                 # global options, like anon, etc.
 884                                 if ! echo $opt_global | grep $o >/dev/null; then
 885                                         opt_global="$opt_global $o"
 886                                 fi
 887                         fi
 888                 done
 889                 (( i += 1 ))
 890         done
 891 
 892         #
 893         # divide a single definition for multiple sec flavours into
 894         # multiple ones
 895         # Example:
 896         #       input:  "sec=sys ro" "sec=krb5 rw" "sec=krb5:krb5p ro=snake"
 897         #       output: "sec=sys ro" "sec=krb5 rw" "sec=krb5 ro=snake"
 898         #               "sec=krb5p ro=snake"
 899         #
 900         i=0
 901         j=0
 902         while (( i < ${#opt_group[*]} )); do
 903                 if ! echo ${opt_group[$i]} |awk '{print $1}' |grep ":" \
 904                         >/dev/null; then
 905                         opt_group2[$j]=${opt_group[$i]}
 906                         (( j += 1 ))
 907                 else
 908                         # contains multiple sec flavours
 909                         flavours=$(echo ${opt_group[$i]} | awk '{print $1}')
 910                         tmp=${opt_group[$i]}
 911                         tmp=${tmp# *}
 912                         rest=${tmp#$flavours}
 913                         flavours=${flavours##*=}
 914                         flavours=$(echo $flavours | tr : ' ')
 915                         for f in $flavours; do
 916                                 opt_group2[$j]="sec=$f $rest"
 917                                 (( j += 1 ))
 918                         done
 919                 fi
 920                 (( i += 1 ))
 921         done
 922 
 923         #
 924         # use sharemgr to share the directory
 925         # Example:
 926         #   input: share anon=0,ro,sec=krb5,rw,ro=snake,sec=krb5p,ro=snake /tmp
 927         #   output:
 928         #       sharemgr add-share -s /tmp $tgrp
 929         #       sharemgr set -P nfs -p anon=0 -s /tmp $tgrp
 930         #       sharemgr set -P nfs -S sys  -p ro=* -s /tmp $tgrp
 931         #       sharemgr set -P nfs -S krb5  -p rw=* -p ro=snake -s /tmp $tgrp
 932         #       sharemgr set -P nfs -S krb5p  -p ro=snake -s /tmp $tgrp
 933         #
 934         if sharemgr list | grep $tgrp >/dev/null 2>&1; then
 935                 sharemgr remove-share -f -s $dir $tgrp > /dev/null 2>&1
 936         else
 937                 sharemgr create -P nfs $tgrp
 938         fi
 939         sharemgr add-share -s $dir $tgrp
 940         ((ret |= $?))
 941 
 942         typeset property=""
 943         for o in $opt_global; do
 944                 if [[ $o == nosuid ]]; then
 945                         o="nosuid=true"
 946                 elif [[ $o == nosub ]]; then
 947                         o="nosub=true"
 948                 elif [[ $o == public ]]; then
 949                         o="public=true"
 950                 elif [[ $o == aclok ]]; then
 951                         o="aclok=true"
 952                 elif [[ $o == log ]]; then
 953                         o="log=global"
 954                 fi
 955                 property="$property -p $o"
 956         done
 957         if [[ -n $property ]]; then
 958                 sharemgr set -P nfs $property -s $dir $tgrp
 959                 ((ret |= $?))
 960         fi
 961 
 962         typeset flavour=""
 963         i=0
 964         while (( i < ${#opt_group2[*]} )); do
 965                 flavour=""
 966                 property=""
 967                 flavour=$(echo ${opt_group2[$i]} | awk '{print $1}')
 968                 tmp=${opt_group2[$i]}
 969                 tmp=$(echo $tmp | sed "s/^ *//")
 970                 optlist=${tmp##$flavour}
 971                 
 972                 [[ -z $optlist ]] && optlist="rw"
 973                 for o in $optlist; do
 974                         if [[ $o == "rw" ]]; then
 975                                 o="rw=*"
 976                         elif [[ $o == "ro" ]]; then
 977                                 o="ro=*"
 978                         fi
 979                         property="$property -p $o"
 980                 done
 981 
 982                 flavour=${flavour##sec=}
 983                 sharemgr set -P nfs -S $flavour $property -s $dir $tgrp
 984                 ((ret |= $?))
 985 
 986                 (( i += 1 ))
 987         done
 988 
 989         return $ret
 990 }
 991 
 992 #
 993 # sharemgr_unshare - unshare the passed directory. If sharemgr is available,
 994 #       the passed share group is deleted too.
 995 # Usage: sharemgr_unshare <group> <directory>
 996 #
 997 function sharemgr_unshare {
 998         typeset FNAME=sharemgr_unshare
 999         [[ :$STC_GENUTILS_DEBUG: == \
1000             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1001                 set -x
1002 
1003         typeset tgrp=$1
1004         typeset dir=$2
1005 
1006         if [[ ! -x /usr/sbin/sharemgr ]]; then
1007                 unshare $dir
1008         else
1009                 sharemgr delete -f $tgrp
1010         fi
1011 }
1012 
1013 #
1014 # zfs_share - share one dir using zfs share
1015 # Usage: zfs_share <directory> [share_options]
1016 #
1017 function zfs_share {
1018         typeset FNAME=zfs_share
1019         [[ :$STC_GENUTILS_DEBUG: == \
1020             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1021                 set -x
1022 
1023         typeset dir=$1
1024         typeset opts=${2:-"rw"}
1025 
1026         if [[ -z $dir ]]; then
1027                 echo "$FNAME Error: exported diretory name not found"
1028                 return 1
1029         fi
1030 
1031         typeset -i ret=0
1032         typeset zfs_mntpnt_flag=1
1033 
1034         typeset mntpnt=$(zfs list -H -o mountpoint)
1035         mntpnt=$(echo $mntpnt | tr -s "\n" " ")
1036         if [[ " $mntpnt " == *" $dir "* ]]; then
1037                 zfs_mntpnt_flag=0
1038         fi
1039 
1040         if (( zfs_mntpnt_flag == 0 )); then
1041                 typeset fs=$(zfs list -H -o name,mountpoint | \
1042                         grep "${dir}$" | awk '{print $1}')
1043 
1044                 zfs set sharenfs="$opts" $fs
1045                 ret=$?
1046 
1047                 typeset sharedir=$(share | awk '{print $2}' | grep -w "$dir")
1048                 sharedir=$(echo $sharedir | tr -s "\n" " ")
1049                 if [[ " $sharedir " != *" $dir "* ]]; then
1050                         zfs share $fs
1051                         ((ret |= $?))
1052                 fi
1053         else
1054                 share -F nfs -o $opts $dir
1055                 ret=$?
1056         fi
1057 
1058         return $ret
1059 }
1060 
1061 #
1062 # zfs_unshare - unshare one dir using zfs set sharenfs=off
1063 # Usage: zfs_unshare <directory>
1064 #
1065 function zfs_unshare {
1066         typeset FNAME=zfs_unshare
1067         [[ :$STC_GENUTILS_DEBUG: == \
1068             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1069                 set -x
1070 
1071         typeset dir=$1
1072         [[ -z $dir ]] && return 1
1073 
1074         typeset -i ret=0
1075         typeset -i zfs_mntpnt_flag=1
1076 
1077         typeset fs=$(zfs list -H -o name,mountpoint | \
1078                         grep "${dir}$" | awk '{print $1}')
1079         typeset share_status=$(zfs get -H -o value sharenfs $fs)
1080 
1081         typeset mntpnt=$(zfs list -H -o mountpoint)
1082         mntpnt=$(echo $mntpnt | tr -s "\n" " ")
1083         if [[ " $mntpnt " == *" $dir "* ]]; then
1084                 zfs_mntpnt_flag=0
1085         fi
1086 
1087         if [[ $share_status != "off" ]] && (( zfs_mntpnt_flag == 0 )); then
1088                 zfs set sharenfs=off $fs
1089                 ret=$?
1090         else
1091                 unshare $dir
1092                 ret=$?
1093         fi
1094 
1095         return $ret
1096 }
1097 
1098 
1099 #
1100 # auto_unshare - unshare one dir automatically by looking up its group
1101 # If its group is zfs, use zfs_unshare();
1102 # else if sharemgr is available and its group is default or other one,
1103 # use sharemgr remove-share;
1104 # else use unshare.
1105 #
1106 # If misc share is done, unshare should be done according to the table shows:
1107 # +--------------------+----------------------+---------------------+-------+
1108 # |                    |sharemgr::remove-share|zfs::set sharenfs=off|unshare|
1109 # +--------------------+----------------------+---------------------+-------+
1110 # |sharemgr::add-share |            Y         |          Y          |    N  |
1111 # |zfs::set sharenfs=on|            N         |          Y          |    N  |
1112 # |share               |            Y         |          Y          |    Y  |
1113 # +--------------------+----------------------+---------------------+-------+
1114 #
1115 # Usage: auto_unshare <directory>
1116 #
1117 function auto_unshare {
1118         typeset FNAME=auto_unshare
1119         [[ :$STC_GENUTILS_DEBUG: == \
1120             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1121                 set -x
1122 
1123         typeset -i ret=0
1124         typeset dir=$1
1125 
1126         # strip last '/' of dir, e.g dir=/var/tmp/
1127         # after strip, dir=/var/tmp
1128         [[ $dir == */ ]] && dir=$(dirname ${dir}/FAKEFILE.$$)
1129 
1130         # if dir is not shared, return 0 directly       
1131         typeset shstr=$(share | awk '{print $2}' | tr '\n' ' ')
1132         [[ " $shstr " != *" $dir "* ]] && return 0
1133 
1134         # if sharemgr is not existed, use zfs_unshare
1135         # zfs_unshare will check dir is zfs or not
1136         if [[ ! -x /usr/sbin/sharemgr ]]; then
1137                 zfs_unshare $dir
1138                 return $?
1139         fi
1140 
1141         typeset sharedfile=$STC_GENUTILS_TMPDIR/sharedfile.out.$$
1142         typeset tmpfile=$STC_GENUTILS_TMPDIR/tmpfile.out.$$
1143 
1144         # format all shared entries and save them to file
1145         typeset igroup=""
1146         for igroup in $(sharemgr list | tr -s '\n' ' '); do
1147                 sharemgr show $igroup | sed '1d' | tr -d '\t' > $tmpfile
1148                 while read line; do
1149                         echo ${line}@${igroup} >> $sharedfile
1150                 done < $tmpfile
1151         done
1152         rm -f $tmpfile
1153 
1154         # lookup dir resides in which group
1155         typeset shdir=""
1156         igroup=""
1157         while read line; do
1158                 shdir=$(echo $line | awk -F@ '{print $1}')
1159                 if [[ @$shdir@ == *@$dir@* ]]; then
1160                         igroup=$(echo $line | awk -F"@" '{print $2}')
1161                         break
1162                 fi
1163         done < $sharedfile
1164         rm -f $sharedfile
1165         
1166         # unshare dir according to its group    
1167         if [[ $igroup == "zfs" ]]; then
1168                 zfs_unshare $dir
1169         elif [[ -n $igroup ]]; then
1170                 sharemgr remove-share -f -s $dir $igroup
1171         else
1172                 unshare $dir
1173         fi
1174         ret=$?
1175         if (( ret != 0 )); then
1176                 echo "ERROR: unshare $dir failed, returned $ret"
1177         fi
1178 
1179         return $ret
1180 }
1181 
1182 #
1183 # Function to get share options from a standard entry
1184 # saved in /etc/dfs/dfstab
1185 # Usage: get_shareoptions <share entry>
1186 #
1187 # e.g.
1188 # get_shareoptions share -F nfs -o rw /tmp  # rw
1189 # get_shareoptions share -o ro=client1 /tmp # ro=client1
1190 # get_shareoptions share /tmp               # rw
1191 #
1192 function get_shareoptions {
1193         typeset FNAME=get_shareoptions
1194         [[ :$STC_GENUTILS_DEBUG: == \
1195             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1196                 set -x
1197 
1198         set -A a_opt $@
1199         typeset a_opt_len=${#a_opt[*]}
1200         typeset -i i=0
1201         typeset options=""
1202         while (( i < a_opt_len )); do
1203                 if [[ ${a_opt[$i]} == "-o" ]]; then
1204                         (( i+= 1 ))
1205                         options=${a_opt[$i]}
1206                         break
1207                 fi
1208                 (( i+= 1 ))
1209         done
1210         [[ -z $options ]] && options="rw"
1211         echo "$options"
1212 }
1213 
1214 #
1215 # Function to check if running as root.
1216 # Usage: is_root [testname] [tmessage]
1217 #
1218 #       testname  optional; if provided, add to the output
1219 #       tmessage  optional; if provided, must follow testname
1220 #
1221 # The main purpose of testname and message is to provide a line that emulates
1222 # an assertion, so that the failure is captured in the summary and reported.
1223 # On success, it just returns 0, on failure, a message is printed, and exit.
1224 #
1225 function is_root {
1226         typeset FNAME=is_root
1227         [[ :$STC_GENUTILS_DEBUG: == \
1228             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1229                 set -x
1230 
1231         typeset TName=$1
1232         [[ -n $TName ]] && TName="$TName: "
1233         typeset Msg=$2
1234         typeset Stat=""
1235         [[ -n $Msg ]] && Stat="\tTest UNINITIATED: " || Msg="\c"
1236         id | grep "0(root)" > /dev/null 2>&1
1237         if (( $? != 0 )); then
1238                 echo "$TName$Msg"
1239                 echo "${Stat}Must run the tests as root."
1240                 exit 6
1241         fi
1242         return 0
1243 }
1244 
1245 # RUN_CHECK - run a command and check its return code. It prints out
1246 #       error information if the return code is not equal to the expected
1247 #       one.
1248 #
1249 #       The expected return code is 0 by default. If user specifies "-n"
1250 #       option(for negative checking purpose), however, the expected return
1251 #       code is a non-zero value.
1252 #
1253 #       If the check fails, the function prints out the failed command,
1254 #       its stdout otupt, and its stderr ouput.
1255 #
1256 #       The function uses its internal log files and removes them by default.
1257 #       User can pass stdout log file and stderr log file via -o and -e
1258 #       options. In that cases, these files won't be deleted automatically.
1259 #
1260 # Usage: RUN_CHECK [-n] [-o outlog] [-e errlog] <command> [args ...]
1261 #       -n              negatvie checking
1262 #       -o outlog       user specified outlog
1263 #       -e errlog       user specified errlog
1264 #       command         command to be executed
1265 #       args            args passed to the command
1266 #
1267 # WARNING:
1268 #       Quote characters in args are silently discarded by shell when
1269 #       command and args are passed to RUN_CHECK(). If these quotes matters,
1270 #       you can't use RUN_CHECK().
1271 #
1272 #       For example, you can't use RUN_CHECK() to run the following command:
1273 #
1274 #          runat /tmp/testfile "echo hello > attr"
1275 #
1276 #       Because if quote characters are removed, the command becomes a quite
1277 #       different one:
1278 #
1279 #          runat /tmp/testfile echo hello > attr
1280 #
1281 function RUN_CHECK {
1282         typeset FNAME=RUN_CHECK
1283         [[ :$STC_GENUTILS_DEBUG: == \
1284             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1285                 set -x
1286 
1287         typeset outlog
1288         typeset errlog
1289         typeset keep_outlog=0
1290         typeset keep_errlog=0
1291         typeset neg_check=0
1292         typeset debug=0
1293 
1294         if [[ -n $STC_GENUTILS_DEBUG ]]; then
1295                 case $STC_GENUTILS_DEBUG in
1296                         *RUN_CHECK_ALL*) debug=2
1297                         ;;
1298                         *RUN_CHECK_CMD*) debug=1
1299                         ;;
1300                         ?)
1301                         ;;
1302                 esac
1303         fi
1304 
1305         while getopts o:e:d:n flag; do
1306                 case $flag in
1307                         o) outlog=$OPTARG
1308                            keep_outlog=1
1309                         ;;
1310                         e) errlog=$OPTARG
1311                            keep_errlog=1
1312                         ;;
1313                         n) neg_check=1
1314                         ;;
1315                         ?) echo "$FNAME: invalid option" >&2
1316                            return 1
1317                         ;;
1318                 esac
1319         done
1320         shift $((OPTIND - 1))
1321         typeset cmd="$@"
1322         if [[ -z $cmd ]]; then
1323                 echo "$FNAME: should specify command name" >&2
1324                 return 1
1325         fi
1326 
1327         if ((keep_outlog == 0)); then
1328                 outlog=$(mktemp -p $STC_GENUTILS_TMPDIR $$.log.XXXXXX)
1329         fi
1330         if ((keep_errlog == 0)); then
1331                 errlog=$(mktemp -p $STC_GENUTILS_TMPDIR $$.log.XXXXXX)
1332         fi
1333 
1334         if [[ -z $outlog || -z $errlog ]]; then
1335                 echo "$FNAME: invalid logfile name" >&2
1336                 echo "$FNAME: \toutlog=<$outlog>,errlog=<$errlog>" >&2
1337                 return 1
1338         fi
1339 
1340         eval $cmd 1>$outlog 2>$errlog
1341         typeset ret=$?
1342         typeset check_result="FAIL"
1343         if (( neg_check == 0 )); then
1344                 # positive checking
1345                 (( ret == 0 )) && check_result="PASS"
1346         else
1347                 # negative checking
1348                 (( ret != 0 )) && check_result="PASS"
1349         fi
1350         
1351         cat $outlog
1352 
1353         if [[ $check_result == "FAIL" ]]; then
1354                 echo "command | [FAIL] $cmd" >&2
1355                 sed "s/^/stdout  | /" $outlog >&2
1356                 sed "s/^/stderr  | /" $errlog >&2
1357         elif (( debug == 1 )); then
1358                 echo "command | [OK] $cmd" >&2
1359         elif (( debug == 2 )); then
1360                 echo "command | [OK] $cmd" >&2
1361                 sed "s/^/stdout  | /" $outlog >&2
1362                 sed "s/^/stderr  | /" $errlog >&2
1363         fi
1364 
1365         # remove logfiles
1366         (( keep_outlog == 0 )) && rm -f $outlog
1367         (( keep_errlog == 0 )) && rm -f $errlog
1368 
1369         [[ $check_result == "PASS" ]] && return 0
1370         [[ $check_result == "FAIL" ]] && return 1
1371 }
1372 
1373 # RUN_CHECKNEG - Run a command and check its return code to verify
1374 #       it fails as expected. This a warpper around RUN_CHECK.
1375 #
1376 # Usage: RUN_CHECKNEG [-o outlog] [-e errlog] <command> [args ...]
1377 #       -o outlog    user specified outlog
1378 #       -e errlog    user specified errlog
1379 #       command args the command to be executed, and its args
1380 #
1381 function RUN_CHECKNEG {
1382         RUN_CHECK -n $@
1383 }
1384 
1385 #
1386 # Get free userid or groupid on client and servers
1387 # Usage:
1388 #       get_free_id <database> [server 1] ... [server n]
1389 #       database: passwd or group
1390 # If successful, print id and return 0
1391 # else return 1
1392 #
1393 function get_free_id {
1394         typeset FNAME=get_free_id
1395         [[ :$STC_GENUTILS_DEBUG: == \
1396             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1397                 set -x
1398         
1399         typeset database=$1
1400         # check databse: passwd or group
1401         if [[ $database != "passwd" && $database != "group" ]]; then
1402                 echo "ERROR: invalid database."
1403                 return 1
1404         fi
1405         shift
1406 
1407         typeset -i id=$((RANDOM + 50000))
1408         [[ $database == "group" ]] && id=$((RANDOM/10 + 1000))
1409 
1410         typeset getentcmd="/usr/bin/getent $database"
1411 
1412         typeset servers=$@ # server1 server2 ... serverN
1413         typeset nserver=$#
1414 
1415         typeset -i ret=1
1416         typeset -i i=0
1417         typeset -i counter=0
1418         while (( i < 1000 )); do # try 1000 times
1419                 # check id on client
1420                 $getentcmd $id > /dev/null 2>&1
1421                 if (( $? == 0 )); then
1422                         (( id += 1 ))
1423                         ((  i += 1 ))
1424                         continue
1425                 fi
1426 
1427                 # check id on servers one bye one
1428                 counter=$nserver
1429                 for srv in $servers; do
1430                         [[ -z $srv ]] && break
1431 
1432                         RSH root $srv "$getentcmd $id | grep $id" \
1433                                 > $STC_GENUTILS_TMPDIR/rsh.out.$$ \
1434                                 2> $STC_GENUTILS_TMPDIR/rsh.err.$$
1435                         (( $? == 0 )) && break
1436                         #
1437                         # $? == 0, id exists on srv
1438                         # $? != 0, maybe due to
1439                         # - RSH itself failed
1440                         # - id does not exist on srv
1441                         # Only id does not exist on srv, counter -= 1
1442                         #
1443                         grep "rsh command failed" \
1444                                 $STC_GENUTILS_TMPDIR/rsh.out.$$ \
1445                                 $STC_GENUTILS_TMPDIR/rsh.err.$$ > /dev/null 2>&1
1446                         if (( $? == 0 )); then
1447                                 echo "ERROR: run <RSH root $srv $getentcmd $id> failed"
1448                                 cat $STC_GENUTILS_TMPDIR/rsh.out.$$
1449                                 cat $STC_GENUTILS_TMPDIR/rsh.err.$$
1450                                 break
1451                         fi
1452 
1453                         # confirm id on srv is not equale to current id
1454                         srvid=$(cat $STC_GENUTILS_TMPDIR/rsh.out.$$ | awk -F: '{print $3}')
1455                         [[ $srvid == $id ]] && break
1456 
1457                         (( counter -= 1 ))
1458                 done
1459 
1460                 if (( counter == 0 )); then
1461                         ret=0
1462                         break
1463                 fi
1464 
1465                 (( id += 1 ))
1466                 ((  i += 1 ))
1467         done
1468 
1469         rm -f $STC_GENUTILS_TMPDIR/rsh.out.$$ $STC_GENUTILS_TMPDIR/rsh.err.$$
1470         echo $id
1471         return $ret
1472 }
1473 
1474 #
1475 # Get free uid on client and servers
1476 # Usage:
1477 #       get_free_uid <server 1> [server 2] ... [server n]
1478 # If sucessful, print free uid and return 0
1479 # else return 1
1480 #
1481 function get_free_uid {
1482         typeset FNAME=get_free_uid
1483         [[ :$STC_GENUTILS_DEBUG: == \
1484             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1485                 STC_GENUTILS_DEBUG=$STC_GENUTILS_DEBUG:get_free_id && set -x
1486 
1487         get_free_id passwd $@
1488         return $?
1489 }
1490 
1491 #
1492 # Get free gid on client and servers
1493 # Usage:
1494 #       get_free_gid <server 1> [server 2] ... [server n]
1495 # If sucessful, print free uid and return 0
1496 # else return 1
1497 #
1498 function get_free_gid {
1499         typeset FNAME=get_free_gid
1500         [[ :$STC_GENUTILS_DEBUG: == \
1501             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1502                 STC_GENUTILS_DEBUG=$STC_GENUTILS_DEBUG:get_free_id && set -x
1503 
1504         get_free_id group $@
1505         return $?
1506 }
1507 
1508 #
1509 # Check user or group exists on client and remote servers.
1510 # If it does exist with the same id(uid or gid) on all hosts, return 0,
1511 # else return non-zero.
1512 # 1 - invalid database
1513 #   - argument <name> is null
1514 #   - run RSH failed
1515 # 2 - user or group does not exsit on client
1516 #   - uid or gid is unmatched between client and one server
1517 #
1518 # Usage: check_user_group <database> <name> [server 1] [server 2] ... [server n]
1519 #
1520 function check_user_group {
1521         typeset FNAME=check_user_group
1522         [[ :$STC_GENUTILS_DEBUG: == \
1523             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1524                 set -x
1525 
1526         typeset database=$1
1527         # check databse: passwd or group
1528         if [[ $database != "passwd" && $database != "group" ]]; then
1529                 echo "ERROR: invalid database."
1530                 return 1
1531         fi
1532         shift
1533 
1534         typeset key="user"
1535         [[ $database == "group" ]] && key="group"
1536 
1537         typeset name=$1
1538         if [[ -z $name ]]; then
1539                 echo "ERROR: $key name<$name> is necessary."
1540                 return 1
1541         fi
1542         shift
1543 
1544         typeset counter=$#
1545         typeset servers=$@
1546         
1547         typeset getentcmd="/usr/bin/getent $database $name"
1548         typeset -i ret=0
1549 
1550         # check user/group on client
1551         typeset clntid=$($getentcmd | awk -F: '{print $3}')
1552         [[ -z $clntid ]] && return 2
1553 
1554         # check user/group with clntid on servers
1555         typeset srvid=0
1556         for srv in $servers; do
1557                 RSH root $srv "$getentcmd" \
1558                         > $STC_GENUTILS_TMPDIR/rsh.out.$$
1559                         2> $STC_GENUTILS_TMPDIR/rsh.err.$$
1560                 if (( $? != 0 )); then
1561                         ret=1
1562                         echo "ERROR: run <RSH root $srv getentcmd> failed"
1563                         cat $STC_GENUTILS_TMPDIR/rsh.out.$$
1564                         cat $STC_GENUTILS_TMPDIR/rsh.err.$$
1565                         break
1566                 fi
1567 
1568                 srvid=$(cat $STC_GENUTILS_TMPDIR/rsh.out.$$ | awk -F: '{print $3}')
1569                 if [[ $srvid != $clntid ]]; then
1570                         ret=2
1571                         echo "INFO: $key id is unmatched,"
1572                         echo "      $key id on server<$srv>: $srvid"
1573                         echo "      $key id on client<$(hostname)>: $clntid"
1574                         break
1575                 fi
1576         done
1577 
1578         rm -f $STC_GENUTILS_TMPDIR/rsh.*.$$
1579         return $ret
1580 }
1581 
1582 function chk_user {
1583         typeset FNAME=chk_user
1584         [[ :$STC_GENUTILS_DEBUG: == \
1585             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1586                 STC_GENUTILS_DEBUG=$STC_GENUTILS_DEBUG:check_user_group && set -x
1587 
1588         check_user_group passwd $@
1589         return $?
1590 }
1591 
1592 function chk_group {
1593         typeset FNAME=chk_group
1594         [[ :$STC_GENUTILS_DEBUG: == \
1595             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1596                 STC_GENUTILS_DEBUG=$STC_GENUTILS_DEBUG:check_user_group && set -x
1597 
1598         check_user_group group $@
1599         return $?
1600 }
1601 
1602 #
1603 # Select valid uid and create specified user in specified group
1604 # on local host and remote servers.
1605 #
1606 # Usage: add_user [-g group] <user name> [server 1] [server 2] ... [server n]
1607 # e.g.
1608 #        add_user usr1 srv1 srv2   # add to localhost, srv1, srv2
1609 #        add_user -g goo usr2 srv1 # add to localhost, srv1 with group "goo"
1610 #        add_user usr3             # only add to localhost
1611 #
1612 function add_user {
1613         typeset FNAME=add_user
1614         [[ :$STC_GENUTILS_DEBUG: == \
1615             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1616                 set -x
1617 
1618         typeset grp=""
1619         if [[ $1 == "-g" ]]; then
1620                 shift
1621                 grp=$1
1622                 shift
1623         fi
1624 
1625         typeset user=$1
1626         if [[ -z $user ]]; then
1627                 echo "ERROR: user name<$user> is necessary."
1628                 return 1
1629         fi
1630         shift
1631 
1632         typeset counter=$#
1633         typeset servers=$@
1634 
1635         typeset grpopt=""
1636         if [[ -n $grp ]]; then
1637                 getent group $grp > /dev/null 2>&1
1638                 if (( $? == 0 )); then
1639                         grpopt="-g $grp"
1640                 else
1641                         echo "ERROR: group name<$grp> doesn't exist."
1642                         return 1
1643                 fi
1644         fi
1645 
1646         typeset myuid=$(get_free_uid $servers)
1647         if (( $? != 0 )); then
1648                 echo "ERROR: get free uid failed."
1649                 return 1
1650         fi
1651 
1652         # add to server
1653         typeset -i ret=0
1654         for srv in $servers; do
1655                 RSH root $srv \
1656                         "/usr/sbin/userdel $user;" \
1657                         "/usr/sbin/useradd -u $myuid $grpopt -d /tmp -m $user" \
1658                         > /dev/null 2>&1
1659                 if (( $? == 0 )); then
1660                         (( counter -= 1 ))
1661                 else
1662                         ret=1
1663                         break
1664                 fi
1665         done
1666 
1667         # add to client
1668         if (( counter == 0 )); then
1669                 /usr/sbin/userdel $user >/dev/null 2>&1
1670                 /usr/sbin/useradd -u $myuid $grpopt -d /tmp -m $user
1671                 ret=$?
1672         fi
1673 
1674         # print uid for possible use outside
1675         (( ret == 0 )) && echo $myuid
1676 
1677         return $ret
1678 }
1679 
1680 
1681 #
1682 # Select valid gid and create specified group with gid
1683 # on local host and remote servers.
1684 #
1685 # Usage: add_group <group name> [server 1] [server 2] ... [server n]
1686 # e.g.
1687 #        add_group Tgrp01 srv1 srv2 # add to localhost, srv1, srv2
1688 #        add_group Tgrp01           # only add to localhost
1689 #
1690 function add_group {
1691         typeset FNAME=add_group
1692         [[ :$STC_GENUTILS_DEBUG: == \
1693             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1694                 set -x
1695         
1696         typeset grp=$1
1697         if [[ -z $grp ]]; then
1698                 echo "ERROR: group name<$grp> is necessary."
1699                 return 1
1700         fi
1701         shift
1702 
1703         typeset counter=$#
1704         typeset servers=$@
1705 
1706         typeset mygid=$(get_free_gid $servers)
1707         if (( $? != 0 )); then
1708                 echo "ERROR: get free gid failed."
1709                 return 1
1710         fi
1711 
1712         # add to servers
1713         typeset -i ret=0
1714         for srv in $servers; do
1715                 RSH root $srv \
1716                         "/usr/sbin/groupdel $grp; " \
1717                         "/usr/sbin/groupadd -g $mygid $grp" \
1718                         > /dev/null 2>&1
1719                 if (( $? == 0 )); then
1720                         (( counter -= 1 ))
1721                 else
1722                         ret=1
1723                         break
1724                 fi
1725         done
1726 
1727         # add to client
1728         if (( counter == 0 )); then
1729                 /usr/sbin/groupdel $grp > /dev/null 2>&1
1730                 /usr/sbin/groupadd -g $mygid $grp
1731                 ret=$?
1732         fi
1733 
1734         # print gid for possible use outside
1735         (( ret == 0 )) && echo $mygid
1736 
1737         return $ret
1738 }
1739 
1740 #
1741 # Delete specified user or group on local host and remote servers.
1742 #
1743 # Usage: delete_user_group <database > <name> [server 1] [server 2] ... [server n]
1744 #
1745 function delete_user_group {
1746         typeset FNAME=delete_user_group
1747         [[ :$STC_GENUTILS_DEBUG: == \
1748             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1749                 set -x
1750 
1751         typeset database=$1
1752         # check databse: passwd or group
1753         if [[ $database != "passwd" && $database != "group" ]]; then
1754                 echo "ERROR: invalid database."
1755                 return 1
1756         fi
1757         shift
1758 
1759         typeset name=$1
1760         if [[ -z $name ]]; then
1761                 typeset key="user"
1762                 [[ $database == "group" ]] && key="group"
1763                 echo "ERROR: $key name<$name> is necessary."
1764                 return 1
1765         fi
1766         shift
1767 
1768         typeset getentcmd="/usr/bin/getent $database $name"
1769         if [[ $database == "passwd" ]]; then
1770                 typeset delcmd="/usr/sbin/userdel $name"
1771         else
1772                 typeset delcmd="/usr/sbin/groupdel $name"
1773         fi
1774 
1775         typeset counter=$#
1776         typeset servers=$@
1777 
1778         for srv in $servers; do
1779                 # check user or group does exsit on srv
1780                 RSH root $srv "$getentcmd | grep $name" \
1781                         > /dev/null 2>&1
1782                 if (( $? != 0 )); then
1783                         (( counter -= 1 ))
1784                         continue
1785                 fi
1786 
1787                 # delete user or group on srv once user exsits
1788                 RSH root $srv "$delcmd > /dev/null" \
1789                         > /dev/null 2>&1
1790                 if (( $? == 0 )); then
1791                         (( counter -= 1 ))
1792                 else
1793                         break
1794                 fi
1795         done
1796 
1797         # If user or group are deleted on all remote servers,
1798         # then we delete it on client
1799         if (( counter == 0 )); then
1800                 # check user or group does exist on client, if not, return 0
1801                 $getentcmd | grep $name > /dev/null 2>&1
1802                 (( $? != 0 )) && return 0
1803 
1804                 $delcmd > /dev/null 2>&1
1805                 return $?
1806         fi
1807 
1808         return 1
1809 
1810 }
1811 
1812 #
1813 # Delete specified user on local host and remote servers.
1814 #
1815 # Usage: del_user <user name> [server 1] [server 2] ... [server n]
1816 #
1817 function del_user {
1818         typeset FNAME=del_user
1819         [[ :$STC_GENUTILS_DEBUG: == \
1820             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1821                 STC_GENUTILS_DEBUG=$STC_GENUTILS_DEBUG:delete_user_group && set -x
1822 
1823         delete_user_group passwd $@
1824         return $?
1825 }
1826 
1827 #
1828 # Delete specified group on local host and remote servers.
1829 #
1830 # Usage: del_group <group name> [server 1] [server 2] ... [server n]
1831 #
1832 function del_group {
1833         typeset FNAME=del_group
1834         [[ :$STC_GENUTILS_DEBUG: == \
1835             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1836                 STC_GENUTILS_DEBUG=$STC_GENUTILS_DEBUG:delete_user_group && set -x
1837 
1838         delete_user_group group $@
1839         return $?
1840 }
1841 
1842 #
1843 # Function to check if the specific system variable is set and it is
1844 # accessible for nfs test suite.
1845 #
1846 function check_system {
1847         typeset VAR=$1
1848         eval system=\${$VAR}
1849 
1850         if [[ -z $system ]]; then
1851                 echo "$VAR is not set, exiting."
1852                 exit 1
1853         fi
1854 
1855         /usr/sbin/ping $system > /dev/null 2>&1
1856         if (( $? != 0 )); then
1857                 echo "$system not responding to pings, exiting"
1858                 exit 1
1859         fi
1860 
1861         RSH root $system /bin/true > $STC_GENUTILS_TMPDIR/ckrsh.$$ 2>&1
1862         if (( $? != 0 )); then
1863                 echo "Failed to <rsh> to $system, exiting."
1864                 cat $STC_GENUTILS_TMPDIR/ckrsh.$$
1865                 rm -f $STC_GENUTILS_TMPDIR/ckrsh.$$
1866                 exit 1
1867         fi
1868         rm -f $STC_GENUTILS_TMPDIR/ckrsh.$$
1869 }
1870 
1871 #
1872 # Function to get zone id
1873 #   Usage: get_zone_id <host>
1874 #
1875 function get_zone_id {
1876         typeset FNAME=get_zone_id
1877         [[ :$STC_GENUTILS_DEBUG: == \
1878             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1879                 set -x
1880 
1881         typeset host=$1
1882 
1883         # Check host is localhost or not
1884         typeset ip1=$(getent ipnodes $host | head -1 | awk '{print $1}')
1885         typeset ip2=$(getent ipnodes $(hostname) | head -1 | awk '{print $1}')
1886         if [[ $ip1 == $ip2 ]]; then
1887                 typeset zone_id=$(zoneadm -z $(zonename) list -p | awk -F: '{print $1}')
1888                 echo $zone_id
1889                 return 0
1890         fi
1891 
1892         RSH root $host \
1893                 "/usr/sbin/zoneadm -z \$(/usr/bin/zonename) list -p" \
1894                 > $STC_GENUTILS_TMPDIR/$FNAME.rsh.$$ 2>&1
1895         if (( $? != 0 )); then
1896                 echo "$FNAME: rsh to host<$host> failed"
1897                 cat $STC_GENUTILS_TMPDIR/$FNAME.rsh.$$
1898                 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
1899                 return 2
1900         fi
1901         typeset zone_id=$(cat $STC_GENUTILS_TMPDIR/$FNAME.rsh.$$ | awk -F: '{print $1}')
1902 
1903         rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
1904         echo $zone_id
1905         return 0
1906 }
1907 
1908 #
1909 # Function to reboot rhost and make sure rsh is available again
1910 #
1911 # A standard model to reboot a remote host for us is:
1912 # 1) before reboot rhost:
1913 #    1.1 ping rhost [OK] # this step needn't checking as we will do 1.2
1914 #    1.2 rsh to create script for rebooting [OK]
1915 # 2) rhost is rebooting:
1916 #    2.1 ping rhost [FAIL] # rhost is down
1917 # 3) after rhost rebooted:
1918 #    3.1 ping rhost [OK]   # rhost is up again
1919 #    3.2 rsh rhost to test something [OK]
1920 #
1921 # Usage: reboot_rhost <timer> <rhost> [ boot_arguments ]
1922 # Return: if reboot successfully, return 0;
1923 #         if create reboot script on rhost failed, return 1;
1924 #         if rhost is not down in 90s after reboot, return 2;
1925 #         if rhost is not up again in $timer seconds, return 3;
1926 #         if rsh is not available again, return 4.
1927 #
1928 function reboot_rhost {
1929         typeset FNAME=reboot_rhost
1930         [[ :$STC_GENUTILS_DEBUG: == \
1931             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1932                 set -x
1933 
1934         typeset timer=$1
1935         typeset rhost=$2
1936         shift 2
1937         typeset boot_args=$@
1938 
1939         #
1940         # Check rhost is non-global zone or not
1941         #
1942         RSH root $rhost "/usr/bin/zonename" > $STC_GENUTILS_TMPDIR/$FNAME.rsh.$$ 2>&1
1943         if (( $? != 0 )); then
1944                 echo "$FNAME: rsh to rhost<$rhost> failed"
1945                 cat $STC_GENUTILS_TMPDIR/$FNAME.rsh.$$
1946                 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
1947                 return 5
1948         fi
1949         typeset zone_name=$(cat $STC_GENUTILS_TMPDIR/$FNAME.rsh.$$)
1950         typeset -i iszone=1
1951         [[ $zone_name != global ]] && iszone=0
1952 
1953         #
1954         # Get current zone id if rhost is non-global zone
1955         #
1956         if (( iszone == 0 )); then
1957                 typeset zone_id=$(get_zone_id $rhost)
1958                 if (( $? != 0 )); then
1959                         echo "$FNAME: get zone id for rhost<$rhost> failed"
1960                         echo $zone_id
1961                         rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
1962                         return 6
1963                 fi
1964         fi
1965 
1966         #
1967         # Create rebooting script on rhost and let it run by 'at'
1968         # Notice: To let rhost sleep 10 before reboot is to avoid rsh timeout
1969         #
1970         typeset f2reboot=$STC_GENUTILS_TMPDIR/reboot_by_$(hostname)
1971         RSH root $rhost \
1972                 "echo \"#! /usr/bin/ksh -p\" > $f2reboot; \
1973                  echo \"/usr/bin/sleep 10\" >> $f2reboot; \
1974                  echo \"/usr/sbin/reboot $boot_args\"  >> $f2reboot; \
1975                  chmod 0755 $f2reboot; \
1976                  at -k -f $f2reboot now" \
1977                 > $STC_GENUTILS_TMPDIR/$FNAME.rsh.$$ 2>&1
1978         if (( $? != 0 )); then
1979                 echo "$FNAME: setup job for rebooting on rhost<$rhost> failed"
1980                 cat  $STC_GENUTILS_TMPDIR/$FNAME.rsh.$$
1981                 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
1982                 return 1
1983         fi
1984 
1985         [[ :$STC_GENUTILS_DEBUG: == \
1986             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1987                 echo "[$(date +'%Y-%m-%d %H:%M:%S')] \c" && \
1988                 echo "rhost<$rhost> will reboot in 10s..."
1989 
1990         #
1991         # Check rhost is back if rhost is non-global zone
1992         # as reboot a non-global zone is very fast actually
1993         #
1994         # Notice:
1995         # Function get_zone_id() will use RSH, so we don't have to check rsh
1996         # on rhost is available again after reboot.
1997         #
1998         if (( iszone == 0 )); then
1999                 sleep 10
2000                 typeset zone_id2=0
2001                 typeset -i i=0
2002                 typeset -i flag=1
2003                 while (( i < $timer )); do
2004                         zone_id2=$(get_zone_id $rhost)
2005                         if [[ $? == 0 && $zone_id != $zone_id2 ]]; then
2006                                 flag=0
2007                                 break
2008                         fi
2009 
2010                         sleep 10
2011                         (( i += 10 ))
2012                 done
2013 
2014                 if (( flag != 0 )); then
2015                         echo "$FNAME: reboot rhost<$rhost> failed in ${timer}s,"
2016                         echo "\t rhost is a non-global zone,"
2017                         echo "\t and seems never come back, please check it manually"
2018                         rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
2019                         return 3
2020                 fi
2021 
2022                 [[ :$STC_GENUTILS_DEBUG: == \
2023                     @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2024                         echo "[$(date +'%Y-%m-%d %H:%M:%S')] \c" && \
2025                         echo "rhost<$rhost> is up again..."
2026 
2027                 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
2028                 return 0
2029         fi
2030 
2031         #
2032         # Wait for rhost is down
2033         # for ping, the default value of timeout is 20 seconds,
2034         # we set it to be 5 seconds to save time.
2035         #
2036         wait_now 90 "! ping $rhost 5 > /dev/null 2>&1" 5
2037         if (( $? != 0 )); then
2038                 echo "$FNAME: reboot rhost<$rhost> failed, it seems not down in 90s."
2039                 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
2040                 return 2
2041         fi
2042 
2043         [[ :$STC_GENUTILS_DEBUG: == \
2044             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2045                 echo "[$(date +'%Y-%m-%d %H:%M:%S')] \c" && \
2046                 echo "rhost<$rhost> is down..."
2047 
2048         #
2049         # Wait for rhost is up
2050         # If timer = 600, the max timeout is:
2051         # 5 * (600 / 10) + 600 = 900 seconds
2052         #
2053         wait_now $timer "ping $rhost 5 > /dev/null 2>&1" 10
2054         if (( $? != 0 )); then
2055                 echo "$FNAME: reboot rhost<$rhost> failed,"
2056                 echo "\t it is not responding to pings in ${timer}s,"
2057                 echo "\t and seems never come back, please check it manually"
2058                 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
2059                 return 3
2060         fi
2061 
2062         [[ :$STC_GENUTILS_DEBUG: == \
2063             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2064                 echo "[$(date +'%Y-%m-%d %H:%M:%S')] \c" && \
2065                 echo "rhost<$rhost> is up again..."
2066 
2067         sleep 30 # wait for services on rhost start
2068 
2069         #
2070         # Check rsh on rhost is available again
2071         # If rsh is not availbale, rsh will timeout in N (about 200) seconds, then
2072         # if we call "wait_now $timer 'RSH ...' $interval" will have to wait for
2073         # N * (( $timer / $interval )) + $timer seconds.
2074         #
2075         wait_now 90 \
2076                 "RSH root $rhost true > $STC_GENUTILS_TMPDIR/$FNAME.rsh.$$ 2>&1" 30
2077         if (( $? != 0 )); then
2078                 echo "$FNAME: reboot rhost<$rhost> failed,"
2079                 echo "\t rsh is not available after reboot in 90s,"
2080                 echo "\t please check it manually"
2081                 cat $STC_GENUTILS_TMPDIR/$FNAME.rsh.$$
2082                 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
2083                 return 4
2084         fi
2085 
2086         [[ :$STC_GENUTILS_DEBUG: == \
2087             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2088                 echo "[$(date +'%Y-%m-%d %H:%M:%S')] \c" && \
2089                 echo "rsh on rhost<$rhost> is available again!"
2090 
2091         rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
2092         return 0
2093 }
2094 
2095 #
2096 # Function to chech if the passed argument is a device name or not.
2097 #   Usage: is_device_name <name>
2098 #
2099 function is_device_name {
2100         typeset FNAME=is_device_name
2101         [[ :$STC_GENUTILS_DEBUG: == \
2102             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2103                 set -x
2104 
2105         typeset name=$1
2106         name=/dev/dsk/$name
2107 
2108         ls ${name}* >/dev/null 2>&1
2109         return $?
2110 }
2111 
2112 # Description
2113 #       A function to get the name of the test case which is generated
2114 #       dynamically.
2115 # Usage:
2116 #       get_casename prefix index
2117 # Return:
2118 #       The function returns the name of the case.
2119 #
2120 function get_casename {
2121         typeset FNAME=get_casename
2122         [[ :$STC_GENUTILS_DEBUG: == \
2123             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2124                 set -x
2125 
2126         typeset prefix=$1
2127         typeset ind=$2
2128         if (( $ind < 10 )); then
2129                 tname=${prefix}00${ind}
2130         elif (( $ind < 100 )); then
2131                 tname=${prefix}0${ind}
2132         else
2133                 tname=${prefix}${ind}
2134         fi
2135         echo $tname
2136 }
2137 
2138 # Description:
2139 #       A function to extract the assertion information from the test source file.
2140 # Usage:
2141 #       extract_assertion_info test_src_filename
2142 # Return:
2143 #       The function only prints the info, nothing is returned.
2144 #
2145 function extract_assertion_info {
2146         typeset FNAME=extract_assertion_info
2147         [[ :$STC_GENUTILS_DEBUG: == \
2148             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2149                 set -x
2150 
2151         typeset FILE=$1
2152         echo "==================================================================="
2153         nawk \
2154             '$2 ~ /__stc_assertion_start/,/__stc_assertion_end/ { print $0}' \
2155             $FILE | sed -e 's/^#//' -e '/__stc_assertion_/d'
2156         echo "==================================================================="
2157 }
2158 
2159 #
2160 # Description
2161 #       A function used to block the network communication between two machines
2162 # Usage:
2163 #       ipf_network
2164 #               -t timeout         // timeout before restore ipfilter setting
2165 #               -f blockflagfile   // restore ipfilter setting once the flagfile
2166 #                                     removed 
2167 #               -k feedbackfile    // remove the feedbackfile once ipfilter was
2168 #                                     applied, used to tell user the network already
2169 #                                     blocked   
2170 #               -v ip_version      // ipv4 or ipv6.
2171 #               -r rules           // ipfilter rules where hostname rather than ip is used.
2172 #       example: ipf_network -s flowerbud -t 100 -f /tmp/blockflagfile 
2173 #               -r "block in from flowerpot"
2174 #               -r "pass in from flowerpot to port != 513
2175 # Return:
2176 #       0: success
2177 #       other: failure
2178 # Notes: 
2179 #       This function calls smf_fmri_transition_state() and smf_get_state()
2180 #       functions which locate in include/libsmf.shlib of STC genutils tool,
2181 #       so the caller should source the lib file before using this function.
2182 #
2183 function ipf_network
2184 {
2185         typeset FNAME=ipf_network
2186         [[ :$STC_GENUTILS_DEBUG: == \
2187             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2188                 set -x
2189 
2190         typeset IPF_TIMEOUT=90
2191         typeset blockflagfile=""
2192         typeset feedbackfile=""
2193         typeset enabled=0
2194         typeset rulesfile="$STC_GENUTILS_TMPDIR/ipf_cmd_file"
2195         typeset IPF_FMRI=svc:/network/ipfilter:default
2196         
2197         rm -f $rulesfile
2198         while getopts "t:f:k:v:r:" opt; do
2199                 case $opt in
2200                         t) timeout=$OPTARG;;
2201                         f) blockflagfile=$OPTARG;;
2202                         k) feedbackfile=$OPTARG;;
2203                         v) ip_version=$OPTARG;;
2204                         r) echo $OPTARG >> $rulesfile;;
2205                         ?) echo "undefined argument"; return 1;;
2206                 esac
2207         done
2208 
2209         echo "Start to ipf_network... "
2210         typeset -i ret_v4 ret_v6=0
2211         [[ `smf_get_state $IPF_FMRI` == online ]] && enabled=1
2212         if (( $enabled != 1 )); then
2213                 echo "ipfilter service is not online"
2214                 RUN_CHECK smf_fmri_transition_state do \
2215                         $IPF_FMRI online $IPF_TIMEOUT || return 1
2216                 sleep 5
2217         else
2218                 # backup original rules
2219                 ipfstat -i > $STC_GENUTILS_TMPDIR/ipfilter_in
2220                 grep "empty list for ipfilter" $STC_GENUTILS_TMPDIR/ipfilter_in \
2221                         || mv $STC_GENUTILS_TMPDIR/ipfilter_in $STC_GENUTILS_TMPDIR/ipfilter_ori
2222                 ipfstat -o > $STC_GENUTILS_TMPDIR/ipfilter_out; ret_v4=$?
2223                 grep "empty list for ipfilter" $STC_GENUTILS_TMPDIR/ipfilter_out \
2224                         || cat $STC_GENUTILS_TMPDIR/ipfilter_out >> $STC_GENUTILS_TMPDIR/ipfilter_ori
2225                 rm -f $STC_GENUTILS_TMPDIR/ipfilter_in $STC_GENUTILS_TMPDIR/ipfilter_out
2226                 if [[ $ip_version == ipv6 ]]; then 
2227                         ipfstat -6 -i > $STC_GENUTILS_TMPDIR/ipfilter_in_v6
2228                         grep "empty list for ipfilter" $STC_GENUTILS_TMPDIR/ipfilter_in_v6 \
2229                                 || mv $STC_GENUTILS_TMPDIR/ipfilter_in_v6 $STC_GENUTILS_TMPDIR/ipfilter_ori_v6
2230                         ipfstat -6 -o > $STC_GENUTILS_TMPDIR/ipfilter_out_v6; ret_v6=$?
2231                         grep "empty list for ipfilter" $STC_GENUTILS_TMPDIR/ipfilter_out_v6 \
2232                                 || cat $STC_GENUTILS_TMPDIR/ipfilter_out_v6 >> $STC_GENUTILS_TMPDIR/ipfilter_ori_v6
2233                         rm -f $STC_GENUTILS_TMPDIR/ipfilter_in_v6 $STC_GENUTILS_TMPDIR/ipfilter_out_v6
2234                 fi
2235                 if (( $ret_v4 != 0 )) || (( $ret_v6 != 0 )); then
2236                         echo "failed to backup original ipfilter rules"
2237                         cat $STC_GENUTILS_TMPDIR/ipfilter_ori $STC_GENUTILS_TMPDIR/ipfilter_ori_v6
2238                         rm -f $STC_GENUTILS_TMPDIR/ipfilter_in \
2239                                 $STC_GENUTILS_TMPDIR/ipfilter_ori_v6
2240                                 $rulesfile 
2241                         return 1
2242                 fi
2243         fi
2244 
2245         echo "apply new rules"
2246         ipf -Fa -f $rulesfile > $STC_GENUTILS_TMPDIR/ipf.out.$$ 2>&1
2247         ret_v4=$?
2248         if [[ $ip_version == ipv6 ]]; then 
2249                 ipf -6 -Fa -f $rulesfile >> $STC_GENUTILS_TMPDIR/ipf.out.$$ 2>&1
2250                 ret_v6=$?
2251         fi
2252         if (( $ret_v4 != 0 )) || (( $ret_v6 != 0 )); then
2253                 echo "failed to apply new rules"
2254                 cat $STC_GENUTILS_TMPDIR/ipf.out.$$
2255                 rm -f $STC_GENUTILS_TMPDIR/ipf.out.$$ \
2256                         $STC_GENUTILS_TMPDIR/ipfilter_ori \
2257                         $STC_GENUTILS_TMPDIR/ipfilter_ori_v6
2258                 return 1
2259         fi
2260 
2261         RUN_CHECK smf_fmri_transition_state check \
2262                 $IPF_FMRI online $IPF_TIMEOUT || return 1
2263         sleep 5
2264 
2265         # remove the feedbackfile to tell user network already blocked
2266         [[ -n $feedbackfile ]] && rm $feedbackfile
2267         
2268         # wait blockflagfile removed or timeout
2269         if [[ -n $blockflagfile ]]; then
2270                 wait_now $timeout "[[ ! -f $blockflagfile ]]" > /dev/null 2>&1
2271         else
2272                 sleep $timeout
2273                 rm -f $blockflagfile
2274         fi
2275 
2276         # restore ipfilter settings
2277         echo "restore ipfilter settings"
2278         if (( $enabled != 1 )); then
2279                 echo "disable ipfilter service on $host"
2280                 RUN_CHECK smf_fmri_transition_state do \
2281                         $IPF_FMRI disabled $IPF_TIMEOUT || return 1
2282         else
2283                 echo "apply original rules on $host"
2284                 RUN_CHECK ipf -Fa -f $STC_GENUTILS_TMPDIR/ipfilter_ori || return 1
2285                 if [[ $ip_version == ipv6 ]]; then 
2286                         ipf -6 -Fa -f $STC_GENUTILS_TMPDIR/ipfilter_ori_v6 || return 1
2287                 fi
2288                 RUN_CHECK smf_fmri_transition_state check \
2289                         $IPF_FMRI online $IPF_TIMEOUT || return 1
2290         fi
2291         sleep 5
2292 
2293         echo "ipf_network finished"
2294         rm -f $STC_GENUTILS_TMPDIR/ipf.out.$$ $rulesfile
2295         return 0
2296 }
2297 
2298 #
2299 # Function: get_zpool_name
2300 #   get the zpool name of a zfs filesystem and print out
2301 # Usage:
2302 #   get_zpool_name <fs name>
2303 # Return:
2304 #   always return 0 unless fs name is null string
2305 #
2306 function get_zpool_name {
2307         typeset FNAME=get_zpool_name
2308         [[ :$STC_GENUTILS_DEBUG: == \
2309             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2310                 set -x
2311 
2312         typeset fs_name=$1
2313         [[ -z $fs_name ]] && return 1
2314         typeset zpool_name=$(echo $fs_name | awk -F\/ '{print $1}')
2315 
2316         echo $zpool_name
2317         return 0
2318 }
2319 
2320 #
2321 # Function: get_zpool_stat
2322 #   get the status of a zpool and print out
2323 # Usage:
2324 #   get_zpool_stat <zpool name>
2325 # Return:
2326 #   return 0 if successful
2327 #
2328 function get_zpool_stat {
2329         typeset FNAME=get_zpool_stat
2330         [[ :$STC_GENUTILS_DEBUG: == \
2331             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2332                 set -x
2333 
2334         typeset zpool_name=$1
2335         [[ -z $zpool_name ]] && return 1
2336 
2337         typeset zpool_stat=""
2338         typeset f1=$STC_GENUTILS_TMPDIR/get_zpool_stat.out.$$
2339         typeset f2=$STC_GENUTILS_TMPDIR/get_zpool_stat.err.$$
2340 
2341         /usr/sbin/zpool list -H -o health $zpool_name > $f1 2>$f2
2342         typeset -i rc=$?
2343         (( rc == 0 )) && zpool_stat=$(cat $f1) || zpool_stat=$(cat $f2)
2344         echo $zpool_stat
2345         rm -f $f1 $f2
2346         return $rc
2347 }
2348 
2349 #
2350 # ------------------
2351 # Function: get_fstype
2352 # ------------------
2353 # This function is to check what type of filesystem of a directory,
2354 # then print related information out as such format,"
2355 # <FAIL|OKAY> <fs type> <fs name | <zpool name> [zpool stat]>"
2356 # and return 0 if OKAY or return 1 if FAIL."
2357 #
2358 # Usage: get_fstype <directory name>"
2359 # e.g.  get_fstype /export/foo   # print OKAY zfs rpool ONLINE"
2360 # e.g.  get_fstype /ufsdisk/d1   # print OKAY ufs /dev/dsk/c0t1d0s3"
2361 # e.g.  get_fstype /tmp/dirxxx   # print OKAY tmpfs swap"
2362 # e.g.  get_fstype /proc/12345   # print OKAY proc proc"
2363 # e.g.  get_fstype /home         # print OKAY autofs auto.home"
2364 # e.g.  get_fstype /ws/onnv-gate # print OKAY nfs onnv.sfbay:/export/onnv-gate
2365 #
2366 # Return 0 and print related information if successful, otherwise return 1
2367 #
2368 function get_fstype {
2369         typeset FNAME=get_fstype
2370         [[ :$STC_GENUTILS_DEBUG: == \
2371             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2372                 set -x
2373 
2374         [[ $# != 1 ]] && echo "ERROR: No directory privided" && return 1
2375 
2376         typeset dir=$1
2377         [[ -z $dir ]] && return 1
2378         typeset basepath=$dir
2379         typeset strout=""
2380 
2381         #
2382         # get base path of dir which does not exist
2383         #
2384         if [[ ! -d $dir ]]; then
2385                 typeset pdir=""              # dir begins with  a relative path
2386                 [[ $dir == /* ]] && pdir="/" # dir begins with an absolute path
2387                 typeset d=""
2388                 for d in $(echo $dir | sed 's%/% %g'); do
2389                         if [[ -z $pdir ]]; then
2390                                 pdir=$d
2391                         else
2392                                 [[ $pdir == "/" ]] && pdir=/$d || pdir=$pdir/$d
2393                         fi
2394 
2395                         if [[ ! -d $pdir ]]; then
2396                                 basepath=$(dirname $pdir)
2397                                 break
2398                         fi
2399                 done
2400         fi
2401 
2402         #
2403         # get filesystem type: ufs, zfs, tmpfs, ...
2404         #
2405         typeset fs_type=$(/usr/sbin/df -n $basepath | awk '{print $3}')
2406 
2407         #
2408         # get filesystem name
2409         # e.g.
2410         # +---------+---------+-------------------+
2411         # | dir     | fs_type | fs_name           |
2412         # +---------+---------+-------------------+
2413         # | /root   | ufs     | /dev/dsk/c0t4d0s0 |
2414         # | /tmp    | tmpfs   | swap              |
2415         # | /export | zfs     | rpool/export      |
2416         # | /proc   | proc    | proc              |
2417         # +---------+---------+-------------------+
2418         #
2419         typeset fs_name=$(/usr/sbin/df $basepath | awk -F\( '{print $2}' \
2420                                 | awk -F\) '{print $1}')
2421 
2422         if [[ $fs_type == "zfs" ]]; then
2423                 strout=$fs_type
2424 
2425                 zpool_name=$(get_zpool_name $fs_name)
2426                 if (( $? != 0 )); then
2427                         echo "FAIL $strout \n$zpool_name"
2428                         return 1
2429                 fi
2430                 strout="$strout $zpool_name"
2431 
2432                 zpool_stat=$(get_zpool_stat $zpool_name)
2433                 if (( $? != 0 )); then
2434                         echo "FAIL $strout \n$zpool_stat"
2435                         return 1
2436                 fi
2437                 strout="$strout $zpool_stat"
2438         else
2439                 strout="$fs_type $fs_name"
2440         fi
2441 
2442         echo OKAY $strout
2443         return 0
2444 }
2445 
2446 # check_knfs - function to check if the client can use kerberos to
2447 #         access nfs server successfully. If <client> is set to
2448 #         "localhost", then we don't need to call rsh for the check.
2449 #         <client> can be set to multiple machines
2450 # Usage:  check_knfs <server> <client>
2451 # Return: 0 on success, 1 on error, 2 if not supported
2452 function check_knfs {
2453         typeset FNAME=check_knfs
2454         [[ :$STC_GENUTILS_DEBUG: == \
2455             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2456                 set -x
2457 
2458         typeset server=$1
2459         typeset clients=$2
2460         typeset KRB5_SHRDIR=$ZONE_PATH/krb5_shr
2461         typeset KRB5_MNTDIR=$ZONE_PATH/krb5_mnt
2462         typeset logfile=$STC_GENUTILS_TMPDIR/$FNAME.$$
2463 
2464         # the server is always a remote machine
2465         SRV_CMD="RSH root $server"
2466         # share with krb5 authentication
2467         $SRV_CMD "mkdir -p $KRB5_SHRDIR && \
2468             share -o sec=krb5 $KRB5_SHRDIR && sleep 2" \
2469             > $logfile 2>&1
2470         ckresult $? "$FNAME: failed to share $KRB5_SHRDIR on $server" $logfile \
2471             || return 1
2472 
2473         for clt in $clients; do
2474                 [[ $clt == localhost ]] && \
2475                         CLT_CMD=RUN_CHECK || CLT_CMD="RSH root $clt"
2476 
2477                 # mount it and check mount options
2478                 $CLT_CMD "mkdir -p $KRB5_MNTDIR" || return 1
2479                 $CLT_CMD "mount -o sec=krb5 $server:$KRB5_SHRDIR $KRB5_MNTDIR" \
2480                         > $logfile 2>&1
2481                 # verify if mount succeeded
2482                 $CLT_CMD "mount -p | grep $server:$KRB5_SHRDIR | grep sec=krb5" \
2483                     >> $logfile 2>&1
2484                 ckresult $? "$FNAME: failed to mount $server:$KRB5_SHRDIR on $clt" \
2485                         $logfile || return 1
2486 
2487                 # clean up
2488                 $CLT_CMD "umount -f $KRB5_MNTDIR && rm -rf $KRB5_MNTDIR"
2489         done
2490 
2491         $SRV_CMD "unshare $KRB5_SHRDIR && rm -rf $KRB5_SHRDIR" \
2492             2>$logfile
2493         ckresult $? "$FNAME: failed to unshare $server:$KRB5_SHRDIR" $logfile
2494 
2495         return 0
2496 }
2497 
2498 #
2499 # Function get_DNS_INFO
2500 #
2501 #   get dns domain or nameserver from /etc/resolv.conf,
2502 #   if fails, then set it to default value which is specified
2503 #   as the third parameter.
2504 # Usage:
2505 #   get_DNS_INFO <key> <host> <default>
2506 #   key  - key should be "domain" or "nameserver",
2507 #          if key is "domain", we get dns domain;
2508 #          if key is "nameserver", we get dns nameserver.
2509 #   host - hostname, if it's local host, just set to "localhost".
2510 #   default - default value for domain or nameserver.
2511 # Return:
2512 #   if key is valid, return 0 and print domain or nameserver.
2513 #
2514 function get_DNS_INFO {
2515         typeset FNAME=get_DNS_INFO
2516         [[ :$STC_GENUTILS_DEBUG: == \
2517             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2518                 set -x
2519 
2520         typeset -l key=$1
2521         typeset -l host=$2
2522         typeset default=$3
2523         typeset CMD=""
2524         [[ $host != localhost ]] && CMD="RSH root $host "
2525 
2526         case $key in
2527         domain)
2528                 typeset domain=$(${CMD}egrep "^$key" /etc/resolv.conf 2>/dev/null \
2529                         | awk '{print $2}')
2530                 [[ -z $domain ]] && domain=$default
2531                 typeset -l str=$domain
2532         ;;
2533 
2534         nameserver)
2535                 typeset nameserver=$(${CMD}nslookup www.sun.com 2>/dev/null \
2536                         | egrep "^Server:" | awk '{print $2}')
2537                 [[ -z $nameserver ]] && nameserver=$default
2538                 typeset -l str=$nameserver
2539         ;;
2540 
2541         *)
2542                 print -u2 "$FNAME: invalid key, must be domain or nameserver"
2543                 return 1
2544         ;;
2545         esac
2546 
2547         echo $str
2548         return 0
2549 }
2550 
2551 #
2552 # Function: is_IPv6
2553 #   Check if current system communicate with remote system via IPv6
2554 # Usage:
2555 #   is_IPv6 <remote_host>
2556 # Return:
2557 #   0 and print IPv4 address
2558 #   1 and print IPv6 address
2559 #   2 and print error message
2560 #
2561 function is_IPv6 {
2562         typeset FNAME=is_IPv6
2563         [[ :$STC_GENUTILS_DEBUG: == \
2564             @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2565                 set -x
2566 
2567         typeset rhost=$1
2568         typeset rhost_ip=""
2569         typeset -i ret=0
2570 
2571         getent ipnodes $rhost | grep -i $rhost > $STC_GENUTILS_TMPDIR/getent.$$ 2>&1
2572         if (( $? != 0 )); then
2573                 echo "failed to get <$rshost>'s IP:"
2574                 cat $STC_GENUTILS_TMPDIR/getent.$$
2575                 rm -f $STC_GENUTILS_TMPDIR/getent.$$
2576                 return 2
2577         fi
2578 
2579         rhost_ip=$(head -1 $STC_GENUTILS_TMPDIR/getent.$$ | awk '{print $1}')
2580         [[ $rhost_ip == *":"* ]] && ret=1
2581         echo "$rhost_ip"
2582         rm -f $STC_GENUTILS_TMPDIR/getent.$$
2583         return $ret
2584 }
2585