1 #! /usr/bin/ksh -p
   2 #
   3 # CDDL HEADER START
   4 #
   5 # The contents of this file are subject to the terms of the
   6 # Common Development and Distribution License (the "License").
   7 # You may not use this file except in compliance with the License.
   8 #
   9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10 # or http://www.opensolaris.org/os/licensing.
  11 # See the License for the specific language governing permissions
  12 # and limitations under the License.
  13 #
  14 # When distributing Covered Code, include this CDDL HEADER in each
  15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16 # If applicable, add the following below this CDDL HEADER, with the
  17 # fields enclosed by brackets "[]" replaced with your own identifying
  18 # information: Portions Copyright [yyyy] [name of copyright owner]
  19 #
  20 # CDDL HEADER END
  21 #
  22 
  23 #
  24 # Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  25 # Use is subject to license terms.
  26 #
  27 
  28 [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
  29 
  30 NAME=$(basename $0)
  31 CDIR=$(pwd)
  32 
  33 . $TESTROOT/libsmf.shlib
  34 
  35 # proc to check if running as root
  36 # Usage: is_root [testname] [tmessage]
  37 #       testname  optional; if provided, add to the output
  38 #       tmessage  optional; if provided, must be followed by testname
  39 # The main purpose of testname and message is to provide a line that emulates
  40 # an assertion, so that the failure is captured in the summary and reported.
  41 # On success, it just returns 0, on failure, a message is printed, and
  42 # exit UNINITIATED is issued.
  43 function is_root
  44 {
  45         [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
  46         TName=$1
  47         [[ -n $TName ]] && TName="$TName: "
  48         Msg=$2
  49         Stat=""
  50         [[ -n $Msg ]] && Stat="\tTest UNINITIATED: " || Msg="\c"
  51         id | grep "0(root)" > /dev/null 2>&1
  52         if (( $? != 0 )); then
  53                 echo "$TName$Msg"
  54                 echo "${Stat}Must run the tests as root."
  55                 exit $UNINITIATED
  56         fi
  57         return 0
  58 }
  59 
  60 # proc to get a field from ls -l (owner or group) and print it to stdout
  61 # Usage: get_val position filepath
  62 #       gets ${position}th parameter from "ls -l ${filepath}
  63 function get_val
  64 {
  65         [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
  66 
  67         if (( $# != 2 )); then
  68                 echo "error_bad_#_parameters"
  69                 return 1
  70         fi
  71         pos=$1
  72         path=$2
  73 
  74         ls -l $path > $TMPDIR/getval.out 2> $TMPDIR/getval.err
  75         res=$?
  76         if [[ $DEBUG != 0 ]]; then
  77                 cat $TMPDIR/getval.out >&2
  78                 cat $TMPDIR/getval.err >&2
  79         fi
  80         if (( res != 0 )); then
  81                 if [[ $DEBUG == 0 ]]; then
  82                         echo "stdout was:" >&2
  83                         cat $TMPDIR/getval.out >&2
  84                         echo "stderr was:" >&2
  85                         cat $TMPDIR/getval.err >&2
  86                 fi
  87                 rm -f $TMPDIR/getval.out $TMPDIR/getval.err 2> /dev/null
  88                 return $res
  89         fi
  90         out=$(awk "{print \$$pos}" $TMPDIR/getval.out 2> $TMPDIR/getval.err)
  91         res=$?
  92         [[ $DEBUG != 0 ]] && echo $out >&2
  93         (( res != 0 )) && cat $TMPDIR/getval.err >&2
  94         rm -f $TMPDIR/getval.out $TMPDIR/getval.err 2> /dev/null
  95         echo $out
  96 
  97         return $res
  98 }
  99 
 100 
 101 # proc to get a field from getfacl and print it to stdout
 102 # Usage: get_val field_key filepath
 103 #       looks for the field_key, and prints its value
 104 #example get_acl_val user:root /aPath/myfile
 105 function get_acl_val
 106 {
 107         [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
 108 
 109         if (( $# != 2 )); then
 110                 echo "error_bad_#_parameters"
 111                 return 1
 112         fi
 113         key=$1
 114         path=$2
 115 
 116         getfacl $path > $TMPDIR/getval.out 2> $TMPDIR/getval.err
 117         res=$?
 118         if [[ $DEBUG != 0 ]]; then
 119                 cat $TMPDIR/getval.out >&2
 120                 cat $TMPDIR/getval.err >&2
 121         fi
 122         if (( res != 0 )); then
 123                 if [[ $DEBUG == 0 ]]; then
 124                         echo "stdout was:" >&2
 125                         cat $TMPDIR/getval.out >&2
 126                         echo "stderr was:" >&2
 127                         cat $TMPDIR/getval.err >&2
 128                 fi
 129                 rm -f $TMPDIR/getval.out $TMPDIR/getval.err 2> /dev/null
 130                 return $res
 131         fi
 132         out=$(grep "$key" $TMPDIR/getval.out | awk '{print $1}' \
 133                 2> $TMPDIR/getval.err)
 134         res=$?
 135         [[ $DEBUG != 0 ]] && echo "stdout was: <$out>" >&2
 136         (( res != 0 )) && cat $TMPDIR/getval.err >&2
 137         rm -f $TMPDIR/getval.out $TMPDIR/getval.err 2> /dev/null
 138         temp=$(echo $out | awk -F: '{print $2}')
 139         [[ -n $temp ]] && echo $temp
 140 
 141         return $res
 142 }
 143 
 144 # proc to check result and print out failure messages
 145 # Usage: ckres test_operation status expected_st op_result_msg
 146 #       test_operation  string describing operation tested
 147 #       status          result (status) from operation
 148 #       expected_st     expected result (status)
 149 #       op_result_msg   file or string diagnostic to print if failure
 150 # test_code can be used to substitute FAIL. Also, expected_st
 151 # can take several values separated by '|' and behave as true if any of the
 152 # values matches $status.
 153 
 154 function ckres
 155 {
 156         [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
 157 
 158         op=$1
 159         st=$2
 160         expt=$3
 161         if [[ -n $4 ]]; then
 162                 res=$4
 163                 # if $res is an operation output file, get its content
 164                 if [[ -f $res ]]; then
 165                         res=$(cat $res)
 166                 else
 167                         # is a string, get all components from $4 to last
 168                         shift; shift; shift
 169                         res="$@"
 170                 fi
 171         fi
 172         tmp=$(echo $expt | sed 's/|/ /g')
 173         expt=$tmp
 174         code="FAIL"
 175         # if exported var for code different from FAIL
 176         [[ -n $ckres_code ]] && code=$ckres_code
 177         ret=$(echo $expt | grep "$st")
 178         if (( $? != 0 )); then
 179                 echo "\tTest $code: $op returned ($st), expected ($expt)"
 180                 [[ -n $res ]] && echo "\t\tres = $res\n"
 181         else
 182                 echo "\tTest PASS"
 183         fi
 184         return $st
 185 }
 186 
 187 # proc to check result and print out failure messages. It is a improved version
 188 # of the original ckres().
 189 # Usage: ckres2 <-s> test_operation status expected_st op_result_msg logfile
 190 #               result_str
 191 #       -s              output nothing if the check passes
 192 #       test_operation  string describing operation tested
 193 #       status          result (status) from operation
 194 #       expected_st     expected result (status)
 195 #       op_result_msg   user-specified error message to print if it fails
 196 #       logfile         the file which contains diagnostic information
 197 #       result_str      Alternative result string to use instead of FAIL
 198 # expected_st can take several values separated by '|' and behave as true
 199 # if any of them is matched against.
 200 #
 201 # Compared with the original ckres(), it has the following new features:
 202 #
 203 # 1) User-specified error message and logfile are represented by two different
 204 #    arguments now. The format of the failure message is:
 205 #
 206 #    <content of logfile>
 207 #    \tTest FAIL
 208 #    \t\terr=$msg
 209 #
 210 # 2) User can specify alternative result string on failure with the $result_str
 211 #    argument. This is useful in testcase-specific setup code, where the result
 212 #    string should be "UNRESOLVED", instead of "FAIL".
 213 # 3) If alternative result string is "ERROR" or "WARNING", the failure message
 214 #    has a different format:
 215 #
 216 #    <content of logfile>
 217 #    ERROR: $msg
 218 #
 219 #    This is useful in setup code unrelated to specific testcase.
 220 # 4) If -s option is specified, ckres output nothing if the check passes.
 221 #    This is useful in that one can call ckres2() multiple times to in
 222 #    different checking steps in a single testcase.
 223 # 5) More helpful return value. ckres2() returns 0 if result string matches
 224 #    the expected one; and 1 if not.
 225 # 6) More strict checking. ckres2() checks if result string matches EXACTLY
 226 #    with the expected string.
 227 
 228 function ckres2
 229 {
 230         [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
 231 
 232         subcheck=0
 233         if [[ $1 == -s ]]; then
 234                 subcheck=1
 235                 shift
 236         fi
 237 
 238         op=$1
 239         res=$2
 240         exp=$3
 241         msg=$4
 242         [[ -n $5 ]] && errlog=$5
 243         [[ -n $6 ]] && alt_str=$6
 244 
 245         # set error string. Use $alt_str if user specified it.
 246         code=FAIL
 247         [[ -n $alt_str ]] && code=$alt_str
 248 
 249         matched=0
 250         echo "$exp" | grep "|" > /dev/null
 251         if (( $? == 1 )); then
 252                 [[ $exp == $res ]] && matched=1
 253         else
 254                 i=1
 255                 while true; do
 256                         var=$(echo "$exp" | cut -d\| -f$i)
 257                         # if we have run through all the values
 258                         [[ -z $var ]] && break
 259                         # if we find a matched value
 260                         [[ $var == $res ]] && matched=1 && break
 261                         # continue the loop
 262                         i=$((i + 1))
 263                 done
 264         fi
 265 
 266         if (( matched == 0 )); then
 267                 # error log
 268                 [[ -f $errlog ]] && cat $errlog && rm -f $errlog
 269 
 270                 # summary of operation result
 271                 if [[ $code == ERROR || $code == WARNING ]]; then
 272                         echo "$code: $msg\n"
 273                 else
 274                         echo "\tTest $code: $op returned ($res), expected ($exp)"
 275                         # user-specified error message
 276                         [[ -n $msg ]] && echo "\t\terr = $msg\n"
 277                 fi
 278 
 279                 return 1
 280         else
 281                 [[ -f $errlog ]] && rm -f $errlog
 282                 (( subcheck != 1 )) && echo "\tTest PASS"
 283                 return 0
 284         fi
 285 }
 286 
 287 # proc to check return code and print out failure messages
 288 # if return-code is 0, this function simply return back 0.
 289 # Usage: ckreturn [-r] return_code error_message [err_detail_file]
 290 #               [result_string]
 291 #       -r              Invert the test logic (failure becomes return_code = 0)
 292 #       return_code     Return code to check
 293 #       error_message   The fail message to print at FAIL
 294 #       err_detail_file The file to cat out if exists, on failure
 295 #       result_string   Alternative result string to use instead of FAIL
 296 #
 297 #                       A result string of "WARNING" or "ERROR" will prevent
 298 #                       the use of the assertion result format (\tTest XXX: msg)
 299 
 300 function ckreturn
 301 {
 302         [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
 303         USAGE=\
 304 "Usage: ckreturn [-r] return_code error_message [err_detail_file] \
 305 \t\t\t[result_string]\n\
 306 \tif -r is specified, error condition becomes return_code = 0,\n\
 307 \tif result_string is not specified, \"FAIL\" is assumed."
 308         typeset n=$#
 309         typeset inv_flg=0
 310         # requested negative logic (rc == 0)?
 311         if [[ $1 == -r ]]; then
 312                 n=$((n - 1))
 313                 inv_flg=1
 314                 shift
 315         fi
 316         # verify needed args are provided and get them
 317         (( n < 2 || n > 4 )) && echo $USAGE && exit $OTHER
 318         typeset rc=$1
 319         typeset msg=$2
 320         typeset cf=""
 321         (( n >= 3 )) && cf=$3
 322         typeset res="FAIL"
 323         (( n >= 4 )) && res=$4
 324 
 325         #check if appropriate error condition is present
 326         typeset tst=0
 327         if (( inv_flg == 0 )); then
 328                 (( rc != 0 )) && tst=1
 329         else # -r was specified
 330                 (( rc == 0 )) && tst=1
 331         fi
 332 
 333         # on error, cat info file and print Test result message
 334         if (( tst == 1 )); then
 335                 [[ -n $cf && -f $cf ]] && cat $cf && rm -f $cf
 336                 typeset TEST="\tTest "
 337                 [[ $res == @(WARNING|ERROR) ]] && TEST=""
 338                 echo "$TEST$res: $msg"
 339         fi
 340         #propagate original return code
 341         return $rc
 342 }
 343 
 344 
 345 # Proc to poll until a condition is met or the specified timeout expires.
 346 # If condition's returned value met the criteria supplied, is considered
 347 # successful and the polling finishes, otherwise keep polling after a second
 348 # delay until timeout expires.
 349 # The returned value is that of the condition passed (as a string).
 350 # Usage: poll timeout test condition
 351 #       timeout         timeout in seconds
 352 #       criteria        success criteria for returned code of condition
 353 #       condition       condition to be polling on
 354 
 355 function poll
 356 {
 357         [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
 358         
 359         timeout=$1
 360         criteria=$2
 361         shift
 362         shift
 363         condition=$@
 364         # change return code ($?) in criteria to $st
 365         criteria=$(echo $criteria | sed 's/\$\?/\$st/g')
 366 
 367         # loop until condition is met or timeout is reached
 368         i=0
 369         while (( i < timeout ))
 370         do
 371                 sleep 1
 372                 i=$((i + 1))
 373                 eval $condition > /dev/null 2>&1
 374                 st=$?
 375                 eval [[ $criteria ]] && break
 376         done
 377         return $st
 378 }
 379 
 380 
 381 # proc to print string describing assertion.
 382 #       Usage: assertion assertion_name description_msg expected value
 383 #       also global variable NAME must contain the name of the current test file
 384 function assertion
 385 {
 386         Aname=$1
 387         ASSERTION=$2
 388         shift
 389         shift
 390         Expected=$@
 391         echo "$NAME{$Aname}: $ASSERTION, expect $Expected"
 392 }
 393 
 394 # proc to get domain by hostname, using korn shell
 395 #       Usage: get_domain hostname FQDN(optional)
 396 #       hostname       hostname of the machine
 397 #       FQDN           a flag, if set, return full fully qualified domain name
 398 #       DEBUG           global to enable debugging mode
 399 #
 400 function get_domain
 401 {
 402         [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
 403          mach=$1
 404          FQDN=$2
 405          ns="dig"
 406 
 407          [[ -z $mach ]] && return 1
 408          res=$(getent hosts $mach)
 409          (( $? != 0 )) && return 1
 410          ipaddr=$(echo $res | nawk '{print $1}')
 411          $ns @$DNS_SERVER +noqu -x $ipaddr > $TMPDIR/$ns.out.$$ 2>&1
 412          res=$(cat $TMPDIR/$ns.out.$$ | grep 'PTR')
 413          ret=$?
 414          [[ $ret != 0 && -n $DEBUG && $DEBUG != 0 ]] \
 415              && cat $TMPDIR/$ns.out.$$ >&2
 416          rm -f $TMPDIR/$ns.out.$$
 417          (( ret != 0 )) && return 1
 418 
 419          res=$(echo $res | nawk '{print $5}' | tr "[:upper:]" "[:lower:]")
 420          res=${res%.}
 421          if [[ $FQDN != FQDN ]]; then
 422                  mn1=$(echo $res | cut -d. -f1)
 423                  res=$(echo $res | sed "s/$mn1.//")
 424          fi
 425 
 426          echo $res
 427          return $ret
 428 }
 429 
 430 
 431 # proc to remotely execute one or more commands, using korn shell.
 432 #       Usage: execute machine user command_string(rest of line)
 433 #       machine         remote machine to execute command
 434 #       user            target user on remote system
 435 #       command_string  any desired command(s) (korn shell)
 436 #       DEBUG           global to enable debugging mode
 437 #       UNIX_RES        global to detect failures, if unix standard is followed
 438 #                       for return codes (0=OK, !0=failure).
 439 #       This proc in addition to execute remote command, adds code for
 440 #       getting the return code from last operation, and to trace
 441 #       the remote execution asenabled by set -x (depending on $DEBUG).
 442 #
 443 # note: Take care of not redirection stderr to stdout as that will cause
 444 #       a very messy output in debug mode, and possible test failures.
 445 
 446 function execute
 447 {
 448         [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
 449         
 450         rmach=$1
 451         ruser=$2
 452         shift; shift
 453         SETD=""
 454         [[ -n $DEBUG && $DEBUG != 0 ]] \
 455                 && SETD="DEBUG=$DEBUG; export DEBUG; set -x; "
 456         rcmd="$SETD$@"
 457         # by default, expect UNIX standard result codes
 458         UNIX_RES=${UNIX_RES:=1}
 459 
 460         file=$TMPDIR/$rmach.$$.out
 461         file2=$TMPDIR/exec.result
 462         ssh -o "StrictHostKeyChecking no" $rmach -l $ruser "$rcmd; print -u 2 \"returned=(\$?)\"" > $file 2> $file2
 463         ret=$?
 464         if (( ret != 0 )); then
 465                 cat $file2
 466                 return $ret
 467         fi
 468         cat $file
 469         tag=0
 470         # if debug info, ignore error message length criteria
 471         if [[ -n $DEBUG && $DEBUG != 0 ]]; then
 472                 errl=0
 473         else
 474                 errl=$(grep -v 'print -u 2' $file2| grep -v 'returned=('| wc -l)
 475         fi
 476         ret=$(grep -v 'print -u 2' $file2 | grep 'returned=(' | \
 477                 sed 's/^.*returned=(//' | sed 's/).*$//')
 478         # if DEBUG on, mark reason for printing file2
 479         [[ -n $DEBUG && $DEBUG != 0 ]] && tag=2
 480         # if error, overwrite reason for printing file2
 481         [[ $errl != 0 && $DEBUG == 0 ]] || \
 482                 (( UNIX_RES != 0 && ret != 0 )) || \
 483                 [[ $ret == 0 && $errl != 0 && -n $DEBUG && $DEBUG != 0 ]] && tag=1
 484         [[ -n $DEBUG && $DEBUG != 0 ]] || (( errl != 0 )) || \
 485                 (( ret != 0 && UNIX_RES != 0 )) && cat $file2 >&2
 486                 
 487         rm -f $file $file2 > /dev/null 2>&1
 488         return $ret
 489 }
 490 
 491 
 492 # proc to remotely execute one or more commands in the background,
 493 #       using korn shell.
 494 #       Usage: executebg machine user command_string(rest of line)
 495 #       machine         remote machine to execute command
 496 #       user            target user on remote system
 497 #       command_string  any desired command(s) (korn shell)
 498 #       DEBUG           global to enable debugging mode
 499 #       This proc execute remote command in the background
 500 #       getting the return code from rsh. stdout and stderr are directed
 501 #        to files for getting results or diagnostics. But execution
 502 #       tracing (debug) is not enabled on remote system.
 503 #
 504 # note: Take care of not redirection stderr to stdout as that will cause
 505 #       a very messy output in debug mode, and possible test failures.
 506 
 507 function executebg
 508 {
 509         [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
 510 
 511         rmach=$1
 512         ruser=$2
 513         shift; shift
 514         rcmd=$@
 515         file=$TMPDIR/$rmach.$$.out
 516         file2=$TMPDIR/exec.result
 517         ssh -o "StrictHostKeyChecking no" $rmach -l $ruser "/usr/bin/ksh -c $rcmd" >$file  2>$file2 &
 518         ret=$?
 519         sleep 1
 520         [[ -s $file ]] && cat $file 2> /dev/null
 521         [[ -s $file2 ]] && cat $file2 >&2
 522         rm -f $file $file2 > /dev/null 2>&1
 523 
 524         return $ret
 525 }
 526 
 527 
 528 # wrapper proc to mount an NFS file system
 529 #       Usage: mountit server remote_path local_path NFS_version
 530 #we have a local environment variable "MNT_OPT"  to the function
 531 #if you need some extra mount options at the delegation test,
 532 #you may need to export it before the test,for example
 533 #in an RDMA enable system,export MNT_OPT="proto=rdma"
 534 
 535 function mountit
 536 {
 537         [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
 538         server=$1
 539         rpath=$2
 540         lpath=$3
 541         version=$4
 542         options="rw,vers=$version"
 543         export MNT_OPT
 544         [[ -z $MNT_OPT ]] || options="rw,$MNT_OPT,vers=$version"
 545 
 546         is_cipso "vers=$version" $server
 547         if (( $? == CIPSO_NFSV2 )); then
 548                 echo "CIPSO NFSv2 not supported under Trusted Extensions"
 549                 return 1
 550         fi
 551 
 552         mount -F nfs -o $options $server:$rpath $lpath
 553         res=$?
 554         (( res != 0 )) && \
 555                 echo "mount -F nfs -o $options $server:$rpath $lpath FAILED"
 556         return $res
 557 }
 558 
 559 # wrapper proc to mount an NFS file system
 560 #       Usage: umountit local_path [kill_flag]
 561 #       tries to umount path, if unsuccessful, gets and prints PIDs of
 562 #       procs using that NFS file system, and if the kill flag is set
 563 #       and there is any process, tries to kill them and retry the umount
 564 
 565 function umountit
 566 {
 567         [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
 568 
 569         lpath=$1
 570         kflag=0
 571         (( $# > 1 )) && kflag=1
 572         umount $lpath
 573         res=$?
 574         if [ $res != "0" ]; then
 575                 echo "initial umount unsuccessful ..."
 576                 echo "fuser -cu $lpath output:"
 577                 out=$(fuser -cu $lpath 2> /dev/null)
 578                 fuser -cu $lpath
 579                 echo "info for processes involved:"
 580                 pids=$(echo $out|sed 's/^[^0-9]*//')
 581                 pids=$(echo $pids|sed 's/[^0-9]*)//g')
 582                 echo $pids | grep "^[0-9].*" > /dev/null 2>&1
 583                 (( $? != 0 )) && return $res
 584                 ps -fp "$pids"
 585                 if (( kflag != 0 )); then
 586                         echo "killing processes"
 587                         for i in $pids
 588                         do
 589                                 echo "kill -9 $i"
 590                                 kill -9 $i
 591                         done
 592                         # small delay for kills to finish
 593                         sleep 5
 594                         umount $lpath
 595                         res=$?
 596                         (( res != 0 )) && echo "umount $lpath FAILED ($res)"
 597                 fi
 598         fi
 599         return $res
 600 }
 601 
 602 
 603 # proc to convert user names to user ids
 604 #       Usage:  get_uid user_name_string
 605 function get_uid
 606 {
 607         uid=$1
 608         uid=$(id $uid | sed 's/^.*uid=//' | sed 's/(.*$//' 2>/dev/null)
 609         res=$?
 610         (( res != 0 )) && return $res
 611         echo $uid
 612         return $res
 613 }
 614 
 615 
 616 # proc to convert group names to group ids
 617 #       Usage:  get_gid group_name_string
 618 function get_gid
 619 {
 620         uid=$1
 621         gid=$(id $uid | sed 's/^.*gid=//' | sed 's/(.*$//' 2>/dev/null)
 622         res=$?
 623         (( res != 0 )) && return $res
 624         echo $gid
 625         return $res
 626 }
 627 
 628 
 629 # proc to conditionally print a message and the content of an error file,
 630 #       and erase that temporal error file.
 631 #
 632 #       Usage:  dprint  "message" [temp_error_file]
 633 #       message                 Any string surrounded by double (or single)
 634 #                               quote marks.
 635 #       temp_error_file         Optional temporal file with debug information.
 636 function dprint
 637 {
 638         [[ -z $DEBUG || $DEBUG == 0 ]] && return
 639         (( $# < 1 )) && return
 640         msg=$1
 641         echo $msg
 642         if (( $# >= 2 )); then
 643                 efile=$2
 644                 if [[ -f $efile ]]; then
 645                         echo "\tstderr has:\n$(cat $efile)"
 646                         rm -f $efile > /dev/null 2>&1
 647                 fi
 648         fi
 649 }
 650 
 651 function get_del
 652 {
 653         [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
 654         (( $# != 1 )) && echo "USAGE: get_del <SERVER>" >&2 && return $FAIL
 655         SERVER=$1
 656         GET_DEL="sharectl get -p SERVER_DELEGATION nfs"
 657         res=$(execute $SERVER root "$GET_DEL")
 658         if (( $? != 0 )); then
 659                 assertion setup \
 660                 "ERROR: Cannot get delegation policy for $SERVER." \
 661                         "Get to succeed" >&2
 662                 echo "stdout=<$res>" >&2
 663                 return $UNINITIATED
 664         else
 665                 [[ $DEBUG != 0 ]] && echo "stdout=<$res>" >&2
 666                 res=$(echo $res | awk -F= '{print $2}')
 667                 if [[ $res == @(off|OFF) ]]; then
 668                         echo off
 669                 else
 670                         echo on
 671                 fi
 672         fi
 673         return 0
 674 }
 675 
 676 function set_del
 677 {
 678         [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
 679         if (( $# != 2 )); then
 680                 echo "USAGE: set_del <SERVER> <on/off>" >&2
 681                 assertion setup \
 682                 "ERROR: Could not set delegation policy for $SERVER" \
 683                         "Set to succeed" >&2
 684                 echo "\tTest UNINITIATED: Terminating" >&2
 685                 return $UNINITIATED
 686         fi
 687         SERVER=$1
 688         value=$2
 689         echo $value | egrep "on|off" > /dev/null 2>&1
 690         if (( $? != 0 )); then
 691                 assertion setup \
 692                 "ERROR: bad delegation policy value ($value)" \
 693                         "'on' or 'off'" >&2
 694                 echo "\tTest UNINITIATED: Terminating" >&2
 695                 return $UNINITIATED
 696         fi
 697         SET_DEL="sharectl set -p SERVER_DELEGATION=$value nfs"
 698         res=$(execute $SERVER root "$SET_DEL" 2> $TMPDIR/result)
 699         if (( $? != 0 )); then
 700                 assertion setup \
 701                 "ERROR: Cannot set delegation policy for $SERVER." \
 702                         "Set to succeed" >&2
 703                 echo "stdout=<$res>" >&2
 704                 echo "stderr=<$(cat $TMPDIR/result)>" >&2
 705                 echo "\tTest UNINITIATED: Terminating" >&2
 706                 rm -f $TMPDIR/result > /dev/null 2>&1
 707                 return $UNINITIATED
 708         else
 709                 [[ $DEBUG != 0 ]] && cat $TMPDIR/result >&2
 710                 rm -f $TMPDIR/result > /dev/null 2>&1
 711                 wait_now 10 "[[ \$(execute $SERVER root sharectl get -p \
 712                 SERVER_DELEGATION nfs | awk -F= '{print \$2}') == $value ]]"
 713                 if (( $? != 0 )); then
 714                         assertion setup \
 715                         "ERROR: the delegation policy for $SERVER has not been \
 716                                 updated to $value even after 10 seconds." \
 717                                 "Set to succeed" >&2
 718                         return $UNINITIATED
 719                 fi
 720         fi
 721 
 722         # Make sure the server is out of the grace period before moving on.
 723         # Take advantage of nfs client behavior to do it
 724         touch $MNTPTR/wait_for_grace_period
 725         rm -f $MNTPTR/wait_for_grace_period >/dev/null 2>&1
 726         return 0
 727 }
 728 
 729 # proc to convert a return code integer to its equivalent string
 730 #
 731 #       Usage:  rc2str return_code
 732 #       return_code     return code to convert to its equivalent string
 733 
 734 function rc2str
 735 {
 736         [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
 737 
 738         (( $# != 1 )) && echo "USAGE: rc2str return_code" && exit 1
 739 
 740         typeset rc=$1
 741         case $rc in
 742                 0 )     echo "PASS" ;;
 743                 1 )     echo "FAIL" ;;
 744                 2 )     echo "UNRESOLVED" ;;
 745                 3 )     echo "NOTINUSE" ;;
 746                 4 )     echo "UNSUPPORTED" ;;
 747                 5 )     echo "UNTESTED" ;;
 748                 6 )     echo "UNINITIATED" ;;
 749                 7 )     echo "NORESULT" ;;
 750                 8 )     echo "WARNING" ;;
 751                 9 )     echo "TIMED_OUT" ;;
 752                 10 )    echo "OTHER" ;;
 753                 * )     echo "OTHER: (rc=$rc)" ;;
 754         esac
 755 
 756         return 0
 757 }
 758 
 759 # Clean up function
 760 function deleg_cleanit
 761 {
 762         [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
 763 
 764         if [[ $NAMEATTR == ON ]]; then
 765                 runat $OPF "rm -f deleg.* endless*"
 766                 rm -f $OPF
 767                 rm -f $TMPDIR/as_*
 768         fi
 769 
 770         rm -f $TMPDIR/tstres > /dev/null 2>&1
 771         rm -f $TMPDIR/result > /dev/null 2>&1
 772         rm -f $TMPDIR/stat.tmp > /dev/null 2>&1
 773 
 774         rm -f $TESTDIR/deleg.* $TESTDIR/endless_*.*
 775         ls $TESTDIR/deleg.* $TESTDIR/endless_*.* > /dev/null 2>&1
 776         (( $? == 0 )) && echo "WARNING: (Tests CLEANUP) could not remove \
 777                 $TESTDIR/deleg.* $TESTDIR/endless_*.*"
 778 
 779         cd /
 780         umountit $TESTDIR clean
 781         if (( $? != 0 )); then
 782                 umount -f $TESTDIR
 783                 (( $? != 0 )) && echo "WARNING: (Test CLEANUP) could not \
 784                         umount -f $TESTDIR"
 785         fi
 786         rmdir $TESTDIR
 787         (( $? != 0 )) && echo "WARNING: (Test CLEANUP) Cannot rmdir $TESTDIR"
 788 
 789         res=$(execute $CLIENT2 root "umount $TESTDIR")
 790         if (( $? != 0 )); then
 791                 echo "WARNING: Cannot umount $TESTDIR on $CLIENT2.\nres = $res"
 792                 res=$(execute $CLIENT2 root "umount -f $TESTDIR")
 793                 if (( $? != 0 )); then
 794                         echo "\t(Test CLEANUP) Cannot umount -f \
 795                                 $TESTDIR on $CLIENT2."
 796                         echo "res = $res"
 797                 fi
 798         fi
 799         res=$(execute $CLIENT2 root "rmdir $TESTDIR")
 800         (( $? != 0 )) && echo "(Test CLEANUP) WARNING: Cannot rmdir $TESTDIR \
 801                                 on $CLIENT2.\nres = $res"
 802 }
 803 
 804 # Usage: ck_zone [return_flg] [err_msg]
 805 #       return_flg (optional); if provided and not 0, it will returned
 806 #            to the caller when in non-global zone; otherwise
 807 #            it will exit
 808 #       err_msg (optional); if provided, it will be added to the output
 809 #            when in non-global zone
 810 #
 811 # This proc is to verify if the current zone is a non-global zone
 812 #       Yes, it just returns 0 without any messages printed;
 813 #       No, it prints an error message and return/exit 4 (UNSUPPORTED).
 814 #
 815 # The original vesion locates under usr/ontest/util/stc/nfs/nfs-util.ksh
 816 
 817 function ck_zone
 818 {
 819         [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
 820         Return=$1
 821         ErrMsg=$2
 822         [[ -z $ErrMsg ]] && \
 823                 ErrMsg="This test is not supported in non-global zone."
 824         zn=$(/usr/bin/zonename)
 825         if [[ $zn != global ]]; then
 826                 echo "ck_zone: current zonename is <$zn>"
 827                 echo "  $ErrMsg"
 828                 if (( Return == 0 )); then
 829                         echo "\tTest UNSUPPORTED: Terminating"
 830                         exit 4
 831                 else
 832                         return 4
 833                 fi
 834         fi
 835         return 0
 836 }
 837 
 838 # ------------------------------------------------------------------------
 839 # is_cipso
 840 # --------
 841 # Determine whether the connection to be NFS mounted is
 842 # a CIPSO connection and if it is return a value corresponding
 843 # to NFSv2 | NFSv3 | NFSv4.
 844 #
 845 # usage: is_cipso <mount options> <server name>
 846 #
 847 #       Example usage:
 848 #
 849 #               if [[ -n $MNTOPTS ]]; then
 850 #                       is_cipso $MNTOPTS $SERVER
 851 #                       if (( $? == CIPSO_NFSV4 )); then
 852 #                               <setup server exported dir to include   >
 853 #                               <non-global path in its exported dir    >
 854 #                               <setup client mount point dir to include>
 855 #                               <non-global path                        >
 856 #                       fi
 857 #               fi
 858 #
 859 # return:       0: NOT cipso
 860 #               1: IS cipso NFSv2
 861 #               2: IS cipso NFSv3
 862 #               3: IS cipso and NOT NFSv2 or NFSv3
 863 #
 864 # Original version is located in: usr/ontest/util/stc/nfs/common_funcs.shlib
 865 # ------------------------------------------------------------------------
 866 CIPSO_NOT=0
 867 CIPSO_NFSV2=1
 868 CIPSO_NFSV3=2
 869 CIPSO_NFSV4=3
 870 
 871 function is_cipso
 872 {
 873         [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
 874 
 875         if (( $# < 2 )); then
 876                 /bin/echo "is_cipso() wrong number of args!"
 877                 return $CIPSO_NOT
 878         fi
 879 
 880         M_OPTS=$1
 881         ASERVER=$2
 882 
 883         if [[ -x /usr/sbin/tninfo ]]; then
 884                 /usr/sbin/tninfo -h $ASERVER | grep cipso >/dev/null 2>&1
 885                 (( $? != 0 )) && return $CIPSO_NOT
 886 
 887                 echo "$M_OPTS" | grep "vers=2" >/dev/null 2>&1
 888                 (( $? == 0 )) && return $CIPSO_NFSV2
 889 
 890                 echo "$M_OPTS" | grep "vers=3" >/dev/null 2>&1
 891                 (( $? == 0 )) && return $CIPSO_NFSV3
 892                 return $CIPSO_NFSV4
 893         fi
 894         return $CIPSO_NOT
 895 }
 896 
 897 # ------------------------------------------------------------------------
 898 # cipso_check_mntpaths()
 899 # ----------------------
 900 # 1.  Check that any zones exist.
 901 # 2.  Check that at least one non-global zone exists.
 902 # 3.  Check that the server's exported directory contains
 903 #     a path to a non-global zone's directory.
 904 # 4.  Check that the client's mount point dir contains a path
 905 #     to the same non-global zone that's in the server's
 906 #     exported directory path.
 907 #
 908 #       An example of valid paths are:
 909 #       ------------------------------
 910 #       server's exported directory:    /zone/public/root/var/tmp/junk
 911 #       client's mount point directory: /zone/public/mnt
 912 #
 913 #       Then the client can mount it via:
 914 #       ---------------------------------
 915 #       mount -F nfs <server>:/zone/public/root/var/tmp/junk /zone/public/mnt
 916 #
 917 # usage: cipso_check_mntpaths <server's export dir> <client's mnt pnt>
 918 #
 919 # return:       0: Everything is OK
 920 #               1: No non global zones exist
 921 #               2: No non global zone path in server's exported dir
 922 #               3: No non global zone path in client's mount point dir
 923 #
 924 # Original version is located in: usr/ontest/util/stc/nfs/common_funcs.shlib
 925 # ------------------------------------------------------------------------
 926 CIPSO_NO_NG_ZONE=1
 927 CIPSO_NO_EXPORT_ZONEPATH=2
 928 CIPSO_NO_MNTPT_ZONEPATH=3
 929 
 930 function cipso_check_mntpaths
 931 {
 932         [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
 933 
 934         if (( $# < 2 )); then
 935                 /bin/echo "cipso_check_mntpaths() wrong number of args!"
 936                 return $CIPSO_NO_NG_ZONE
 937         fi
 938 
 939         [[ -z $ZONE_PATH ]] && return $CIPSO_NO_NG_ZONE
 940 
 941         srvdir=$1
 942         clntdir=$2
 943 
 944         zlist=$(/usr/sbin/zoneadm list)
 945         [[ -z $zlist ]] && return $CIPSO_NO_NG_ZONE
 946 
 947         [[ $zlist == global ]] && return $CIPSO_NO_NG_ZONE
 948 
 949         fnd=0
 950         for azone in $zlist
 951         do
 952                 [[ $azone == global ]] && continue
 953                 X=$(zoneadm -z $azone list -p | cut -d ":" -f 4)
 954                 [[ -z $X ]] && continue
 955                 X1=$(echo $X | sed -e 's/\// /g' | awk '{print $1}')
 956                 X2=$(echo $X | sed -e 's/\// /g' | awk '{print $2}')
 957                 Y1=$(echo $ZONE_PATH | sed -e 's/\// /g' | awk '{print $1}')
 958                 Y2=$(echo $ZONE_PATH | sed -e 's/\// /g' | awk '{print $2}')
 959                 if [[ $X1 == $Y1 && $X2 == $Y2 ]]; then
 960                         fnd=1
 961                         break
 962                 fi
 963         done
 964 
 965         (( fnd == 0 )) && return $CIPSO_NO_NG_ZONE
 966 
 967         echo $srvdir | /bin/grep "^$ZONE_PATH" >/dev/null 2>&1
 968         (( $? != 0 )) && return $CIPSO_NO_EXPORT_ZONEPATH
 969 
 970         echo $clntdir | /bin/grep "^$ZONE_PATH" >/dev/null 2>&1
 971         (( $? != 0 )) && return $CIPSO_NO_MNTPT_ZONEPATH
 972         return 0
 973 }
 974 
 975 # A wait function to verify a specified condition
 976 # Usage: wait_now max_TIMER the_condition
 977 #      max_TIMER    the maximum timer to wait
 978 #      condition    the condition to break the wait:
 979 #               "true"  wait_now{} returns 0
 980 #               "false" wait_now{} continues until the TIMER
 981 #
 982 
 983 function wait_now
 984 {
 985     [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
 986     (( $# < 2 )) && \
 987         echo "Usage: wait_now max_TIMER the_condition" && \
 988         return -1
 989 
 990     Timer=$1
 991     shift
 992     Wcond=$@
 993 
 994     i=0
 995     while (( i < Timer ))
 996     do
 997         eval $Wcond
 998         (( $? == 0 )) && return 0
 999         sleep 1
1000         i=$((i + 1))
1001     done
1002     echo "wait_now function failed"
1003     return $i
1004 }
1005 
1006 function start_fmri
1007 {
1008         [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
1009         (( $# == 0 )) && \
1010             echo "Usage: start_fmri fmri [host]" &&
1011             return -1
1012         typeset fmri=$1 host=$2
1013         typeset msg cmd ret=0 res
1014         if [[ -z $host ]]; then
1015                 msg="Warning: Failed to start $fmri on $CLIENT"
1016                 smf_fmri_transition_state do $fmri online 10 \
1017                     > $TMPDIR/fmri.out.$$ 2>&1
1018                 ret=$?
1019                 ckreturn $ret "$msg" $TMPDIR/fmri.out.$$
1020                 return $ret
1021         else
1022                 msg="Warning: Failed to start $fmri on $host"
1023                 cmd=". $TMPDIR/libsmf.shlib; \
1024                     smf_fmri_transition_state do $fmri online 10; \
1025                     t=\$?; echo \"ret=\$t\""
1026                 res=$(execute $host root "$cmd")
1027                 ret=$(echo $res | grep "ret=" | sed 's/.*ret=/ret=/' | \
1028                     awk -F= '{print $NF}' | awk '{print $1}')
1029                 ckreturn $ret "$msg"
1030                 return $ret
1031         fi
1032 }